parent
3ae3d1453d
commit
cd691a3c5b
@ -0,0 +1,414 @@ |
||||
---@type Diesal.GUI |
||||
local DiesalGUI = LibStub("DiesalGUI-2.0") |
||||
---@type Diesal.Tools |
||||
local DiesalTools = LibStub("DiesalTools-2.0") |
||||
---@type Diesal.Style |
||||
local DiesalStyle = LibStub("DiesalStyle-2.0") |
||||
-- ~~| Diesal Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
local Colors = DiesalStyle.Colors |
||||
local HSL, ShadeColor, TintColor = DiesalTools.HSL, DiesalTools.ShadeColor, DiesalTools.TintColor |
||||
-- ~~| Lua Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
local tsort = table.sort |
||||
local sub, format, lower, upper, gsub = string.sub, string.format, string.lower, string.upper, string.gsub |
||||
|
||||
-- ~~| WoW Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
||||
-- ~~| Dropdown |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
local Type = "DiesalDropDownPullout" |
||||
local Version = 1 |
||||
|
||||
---@type backdropInfo |
||||
local backdrop = { |
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground", |
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", |
||||
edgeSize = 8, |
||||
tileSize = 8, |
||||
tile = true, |
||||
insets = { left = 2, right = 2, top = 2, bottom = 2 }, |
||||
} |
||||
|
||||
local sliderBackdrop = { |
||||
bgFile = "Interface\\Buttons\\UI-SliderBar-Background", |
||||
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border", |
||||
tile = true, |
||||
tileSize = 8, |
||||
edgeSize = 8, |
||||
insets = { left = 3, right = 3, top = 3, bottom = 3 }, |
||||
} |
||||
|
||||
local Stylesheet = { |
||||
["frame-background"] = { |
||||
type = "texture", |
||||
layer = "BACKGROUND", |
||||
color = Colors.UI_100, |
||||
alpha = 0.95, |
||||
}, |
||||
["frame-inline"] = { |
||||
type = "outline", |
||||
layer = "BORDER", |
||||
color = "ffffff", |
||||
alpha = 0.02, |
||||
position = -1, |
||||
}, |
||||
["frame-shadow"] = { |
||||
type = "shadow", |
||||
}, |
||||
} |
||||
|
||||
local defaultWidth = 200 |
||||
local defaultMaxItems = 20 |
||||
|
||||
local function fixlevels(parent, ...) |
||||
local i = 1 |
||||
local child = select(i, ...) |
||||
while child do |
||||
child:SetFrameLevel(parent:GetFrameLevel() + 1) |
||||
fixlevels(child, child:GetChildren()) |
||||
i = i + 1 |
||||
child = select(i, ...) |
||||
end |
||||
end |
||||
|
||||
local function fixstrata(strata, parent, ...) |
||||
local i = 1 |
||||
local child = select(i, ...) |
||||
parent:SetFrameStrata(strata) |
||||
while child do |
||||
fixstrata(strata, child, child:GetChildren()) |
||||
i = i + 1 |
||||
child = select(i, ...) |
||||
end |
||||
end |
||||
|
||||
-- HACK: This should be no part of the pullout, but there |
||||
-- is no other 'clean' way to response to any item-OnEnter |
||||
-- Used to close Submenus when an other item is entered |
||||
local function OnEnter(item) |
||||
local self = item.pullout |
||||
for k, v in ipairs(self.settings.items) do |
||||
if v.CloseMenu and v ~= item then |
||||
v:CloseMenu() |
||||
end |
||||
end |
||||
end |
||||
|
||||
---@class Diesal.GUI.DropDownPullout.Methods |
||||
local methods = { |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
OnAcquire = function(self) |
||||
self.frame:SetParent(DiesalGUI.UIParent) |
||||
end, |
||||
|
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
OnRelease = function(self) |
||||
self:ClearAllPoints() |
||||
self:Hide() |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
ApplySettings = function(self) end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
GetItemsHeight = function(self) |
||||
local itemHeight = 0 |
||||
for i, item in ipairs(self.settings.items) do |
||||
itemHeight = itemHeight + item.text:GetStringHeight() |
||||
end |
||||
return itemHeight |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
GetMaxHeight = function(self) |
||||
local maxHeight = 0 |
||||
for i, item in ipairs(self.settings.items) do |
||||
if i <= self.maxItems then |
||||
maxHeight = maxHeight + item:GetHeight(false) |
||||
end |
||||
end |
||||
return maxHeight |
||||
--return self:GetMaxItemHeight() * min(self.maxItems, #self.settings.items) |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
---@param item DiesalDropDownItem |
||||
---@param setPoints? boolean |
||||
AddItem = function(self, item, setPoints) |
||||
table.insert(self.settings.items, item) |
||||
local maxWidth = 8 + (item.settings.indent * 6) + (16 * 2) |
||||
if item.text then |
||||
maxWidth = maxWidth + item.text:GetUnboundedStringWidth() |
||||
end |
||||
if item.check then |
||||
maxWidth = maxWidth + item.check:GetWidth() + 4 |
||||
end |
||||
self.settings.maxItemWidth = max(self.settings.maxItemWidth, maxWidth) |
||||
--self.frame:SetHeight(min(self:GetItemsHeight() + 28, self:GetMaxHeight() + 28)) |
||||
if setPoints then |
||||
item:SetPoint("LEFT", self.itemFrame, "LEFT", 20, 0) |
||||
item:SetPoint("RIGHT", self.itemFrame, "RIGHT", 0, 0) |
||||
end |
||||
item:SetPullout(self) |
||||
--item:SetScript("OnEnter", OnEnter) |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
---@param value number |
||||
SetScroll = function(self, value) |
||||
local status = self.scrollStatus |
||||
local scrollFrame, itemFrame = self.scrollFrame, self.itemFrame |
||||
local height, viewheight = scrollFrame:GetHeight(), itemFrame:GetHeight() |
||||
--local minVal, maxVal = self.slider:GetMinMaxValues() |
||||
local minVal, maxVal = height, viewheight |
||||
local offset |
||||
if height > viewheight then |
||||
offset = 0 |
||||
self.slider2:Hide() |
||||
else |
||||
offset = floor(maxVal * value) |
||||
self.slider2:Show() |
||||
end |
||||
itemFrame:ClearAllPoints() |
||||
itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, offset) |
||||
itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", self.slider2:IsShown() and -6 or 0, offset) |
||||
status.offset = offset |
||||
status.scrollvalue = (maxVal * value) |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
---@param value number |
||||
MoveScroll = function(self, value) |
||||
local status = self.scrollStatus |
||||
local frame, child = self.scrollFrame, self.itemFrame |
||||
local height, viewheight = frame:GetHeight(), child:GetHeight() |
||||
--local minVal, maxVal = self.slider:GetMinMaxValues() |
||||
local minVal, maxVal = height, self:GetItemsHeight() |
||||
--child:SetHeight(self:GetItemsHeight()) |
||||
if height > viewheight then |
||||
self.slider2:Hide() |
||||
else |
||||
self.slider2:Show() |
||||
local diff = height - viewheight |
||||
local delta = 1 |
||||
if value < 0 then |
||||
delta = -1 |
||||
end |
||||
local scrollToVal = min(max(status.scrollvalue + delta * (maxVal / (diff / self.settings.itemHeight)), 0), maxVal) |
||||
self.slider2:SetScrollPercentage(scrollToVal/maxVal) |
||||
--self.slider:SetValue(scrollToVal) |
||||
end |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
FixScroll = function(self) |
||||
local status = self.scrollStatus |
||||
local frame, child = self.scrollFrame, self.itemFrame |
||||
local height, viewheight = frame:GetHeight(), child:GetHeight() |
||||
local offset = status.offset or 0 |
||||
local minVal, maxVal = height, viewheight |
||||
if viewheight < height then |
||||
self.slider2:Hide() |
||||
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset) |
||||
self.scrollFrame:SetVerticalScroll(0) |
||||
else |
||||
self.slider2:Show() |
||||
local value = (offset / (viewheight - height) * maxVal) |
||||
--self.slider:SetValue(value) |
||||
self:SetScroll(value) |
||||
if value < maxVal then |
||||
child:ClearAllPoints() |
||||
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset) |
||||
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset) |
||||
status.offset = offset |
||||
end |
||||
end |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
---@param point FramePoint |
||||
---@param relFrame Frame |
||||
---@param relPoint FramePoint |
||||
---@param x number |
||||
---@param y number |
||||
Open = function(self, point, relFrame, relPoint, x, y) |
||||
local items = self.settings.items |
||||
local frame = self.frame |
||||
local itemFrame = self.itemFrame |
||||
|
||||
frame:SetPoint(point, relFrame, relPoint, x, y) |
||||
local maxWidth = self.settings.maxItemWidth + self.slider2:GetWidth() |
||||
if self.dropdown.settings.dropdownWidth then |
||||
if self.dropdown.settings.dropdownWidth > maxWidth then |
||||
frame:SetWidth(self.dropdown.settings.dropdownWidth) |
||||
else |
||||
frame:SetWidth(maxWidth) |
||||
end |
||||
else |
||||
frame:SetWidth(max(maxWidth, self.dropdown.frame:GetWidth())) |
||||
--frame:SetPoint("TOPRIGHT", relFrame, "BOTTOMRIGHT", x, y) |
||||
end |
||||
local height = 0 |
||||
for i, item in ipairs(items) do |
||||
item:SetPoint("TOPLEFT", i == 1 and itemFrame or items[i - 1].frame, i == 1 and "TOPLEFT" or "BOTTOMLEFT", 0, 0) |
||||
item:Show() |
||||
height = height + item.text:GetStringHeight() |
||||
end |
||||
frame:Show() |
||||
frame:SetHeight(self:GetMaxHeight()) |
||||
itemFrame:SetHeight(self:GetItemsHeight()) |
||||
self.scrollFrame:SetScrollChild(itemFrame) |
||||
fixstrata("TOOLTIP", self.scrollFrame, self.scrollFrame:GetChildren()) |
||||
self:FireEvent("OnOpen") |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
Close = function(self) |
||||
self.frame:Hide() |
||||
self:FireEvent("OnClose") |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
Clear = function(self) |
||||
local items = self.settings.items |
||||
for i, item in ipairs(items) do |
||||
items[i] = nil |
||||
end |
||||
for i,item in ipairs(self.itemFrame) do |
||||
end |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
IterateItems = function(self) |
||||
return ipairs(self.settings.items) |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
SetHideOnLeave = function(self, val) |
||||
self.hideOnLeave = val |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
GetRightBorderWidth = function(self) |
||||
return 6 + (self.slider:IsShown() and 12 or 0) |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
GetLeftBorderWidth = function(self) |
||||
return 6 |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
ClearFocus = function(self) |
||||
self:Hide() |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
---@param height? number |
||||
SetItemHeight = function(self, height) |
||||
self.settings.itemHeight = height or self.defaults.itemHeight |
||||
end, |
||||
---@param self Diesal.GUI.Object.DropDownPullout |
||||
SetDropDown = function (self, dropdown) |
||||
self.dropdown = dropdown |
||||
end |
||||
} |
||||
|
||||
---@class Diesal.GUI.Object.DropDownPullout.Settings : Diesal.GUI.ObjectBase.Settings |
||||
---@field width number |
||||
---@field itemHeight number |
||||
---@field sliderWidth number |
||||
---@field hideOnLeave boolean |
||||
---@field items DiesalDropDownItem[] |
||||
---@field maxItemWidth number |
||||
|
||||
---@class DiesalDropDownPullout : Diesal.GUI.Object.DropDownPullout |
||||
|
||||
local function Constructor() |
||||
---@class Diesal.GUI.Object.DropDownPullout : Diesal.GUI.ObjectBase, Diesal.GUI.DropDownPullout.Methods |
||||
---@field settings Diesal.GUI.Object.DropDownPullout.Settings |
||||
---@field items DiesalDropDownItem[] |
||||
---@field dropdown DiesalDropDown |
||||
local self = DiesalGUI:Create(Type, true) |
||||
self:SetMethods(methods) |
||||
local frame = CreateFrame("Frame", nil, DiesalGUI.UIParent, "BackdropTemplate") |
||||
self.frame = frame |
||||
self:SetObj(self.frame) |
||||
|
||||
self.defaults = { |
||||
width = 200, |
||||
itemHeight = 12, |
||||
sliderWidth = 10, |
||||
hideOnLeave = true, |
||||
items = {}, |
||||
maxItemWidth = 0, |
||||
} |
||||
|
||||
self.scrollStatus = { |
||||
scrollvalue = 0, |
||||
} |
||||
self.hideOnLeave = false |
||||
self.maxItems = 20 |
||||
|
||||
frame:SetBackdrop(backdrop) |
||||
frame:SetBackdropColor(0, 0, 0, 1) |
||||
frame:SetBackdropBorderColor(0.2, 0.2, 0.2, 1) |
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG") |
||||
frame:SetClampedToScreen(true) |
||||
frame:SetWidth(self.defaults.width) |
||||
frame:SetHeight(34) |
||||
frame:SetScript("OnHide", function(this) |
||||
self.dropdown.open = nil |
||||
self.dropdown.arrow:SetRotation(0) |
||||
DiesalGUI:ClearFocus() |
||||
end) |
||||
|
||||
self:CreateRegion("Frame", "content", frame) |
||||
|
||||
local scrollFrame = CreateFrame("ScrollFrame", nil, frame, "ScrollFrameTemplate") |
||||
local itemFrame = CreateFrame("Frame", nil, scrollFrame) |
||||
|
||||
self.scrollFrame = scrollFrame |
||||
self.itemFrame = itemFrame |
||||
|
||||
self:SetObj(self.scrollFrame) |
||||
self:SetObj(self.itemFrame) |
||||
|
||||
---@type MinimalScrollBar |
||||
local slider2 = scrollFrame.ScrollBar |
||||
self.slider2 = slider2 |
||||
self.slider2:SetPoint("TOPLEFT", self.scrollFrame, "TOPRIGHT", -20, -2) |
||||
self.slider2:SetPoint("BOTTOMLEFT", self.scrollFrame, "BOTTOMRIGHT", -20, 5) |
||||
self.scrollFrame:SetVerticalScroll(0) |
||||
self.slider2:SetVisibleExtentPercentage(0.25) |
||||
self.slider2:SetThumbExtent(0.25) |
||||
self.slider2:RegisterCallback("OnScroll", function(this, percent) |
||||
self:SetScroll(percent) |
||||
end, self.slider2) |
||||
--local slider = CreateFrame("Slider", nil, scrollFrame, "BackdropTemplate") |
||||
--slider:SetOrientation("VERTICAL") |
||||
--slider:SetHitRectInsets(0, 0, -10, 0) |
||||
--slider:SetBackdrop(sliderBackdrop) |
||||
--slider:SetWidth(8) |
||||
--slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") |
||||
--slider:SetFrameStrata("FULLSCREEN_DIALOG") |
||||
--self.slider = slider |
||||
--self:SetObj(self.slider) |
||||
scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT") |
||||
scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT") |
||||
scrollFrame:EnableMouseWheel(true) |
||||
--[[ scrollFrame:SetScript("OnMouseWheel", function(this, value) |
||||
self:MoveScroll(value) |
||||
self:FireEvent("OnMouseWheel", value) |
||||
end) ]] |
||||
scrollFrame:SetToplevel(true) |
||||
scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG") |
||||
|
||||
itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0) |
||||
itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -6, 0) |
||||
--itemFrame:SetHeight(400) |
||||
itemFrame:SetToplevel(true) |
||||
itemFrame:SetFrameStrata("FULLSCREEN_DIALOG") |
||||
scrollFrame.ItemFrame = itemFrame |
||||
scrollFrame:SetScrollChild(scrollFrame.ItemFrame) |
||||
|
||||
--slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0) |
||||
--slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0) |
||||
--slider:SetScript("OnValueChanged", function(this, value) |
||||
--self:SetScroll(value) |
||||
--end) |
||||
--slider:SetMinMaxValues(0, 1) |
||||
--slider:SetValueStep(1) |
||||
--slider:SetValue(0) |
||||
|
||||
scrollFrame:Show() |
||||
itemFrame:Show() |
||||
--slider:Hide() |
||||
|
||||
self:FixScroll() |
||||
|
||||
return self |
||||
end |
||||
DiesalGUI:RegisterObjectConstructor(Type, Constructor, Version) |
Loading…
Reference in new issue