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