You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
10 KiB

local _, addon = ...
local API = addon.API;
local MENU_PADDING_V = 8;
local MAX_BUTTON_PER_PAGE = 8;
local MENU_BUTTON_WIDTH = 120;
local MENU_BUTTON_HEIGHT = 24;
local MENU_BUTTON_MAX_WIDTH = 192;
local BUTTON_TEXT_OFFSET_X = 12;
local SCROLLBAR_PADDING = 8;
local SCROLLBAR_WIDTH = 12;
local SCROLLBAR_SIZE = SCROLLBAR_WIDTH + MENU_PADDING_V + SCROLLBAR_PADDING;
local BUTTON_TEXT_FONT = "DUIFont_Quest_Paragraph";
local UNBOUND_MENU_BUTTON_WIDTH = MENU_BUTTON_WIDTH;
local DEFAULT_MENU_WIDTH = MENU_BUTTON_WIDTH + SCROLLBAR_SIZE;
local DEFAULT_MENU_HEIGHT = MENU_BUTTON_HEIGHT * MAX_BUTTON_PER_PAGE;
local DropDownMenu;
local DropDownMenuMixin = {};
local UtilityFontString;
local MenuButtonMixin = {};
function MenuButtonMixin:OnLoad()
self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
self.ButtonText = self:CreateFontString(nil, "OVERLAY", BUTTON_TEXT_FONT);
self.ButtonText:SetPoint("LEFT", self, "LEFT", BUTTON_TEXT_OFFSET_X, 0);
self.ButtonText:SetPoint("RIGHT", self, "RIGHT", -BUTTON_TEXT_OFFSET_X + 1, 0);
self.ButtonText:SetJustifyV("MIDDLE");
self.ButtonText:SetMaxLines(1);
self:SetTextAlignment("LEFT");
end
function MenuButtonMixin:SetButtonText(text)
self.ButtonText:SetText(text);
end
function MenuButtonMixin:SetData(data)
self:SetButtonText(data[1]);
self.ButtonText:SetFont(data[2], 12, "");
self.fontFile = data[2];
end
function MenuButtonMixin:OnClick(button)
if button == "LeftButton" then
addon.FontUtil:SetFontByFile(self.fontFile);
elseif button == "RightButton" then
DropDownMenu:Close();
end
end
function MenuButtonMixin:OnEnter()
DropDownMenu:HighlightButton(self);
end
function MenuButtonMixin:OnLeave()
DropDownMenu:HighlightButton(nil);
end
function MenuButtonMixin:SetTextAlignment(justifyH)
self.ButtonText:SetJustifyH(justifyH);
end
local function CreateMenuButton(parent)
local b = CreateFrame("Button", nil, parent);
API.Mixin(b, MenuButtonMixin);
b:SetScript("OnEnter", b.OnEnter);
b:SetScript("OnLeave", b.OnLeave);
b:SetScript("OnClick", b.OnClick);
b:OnLoad();
b:SetWidth(MENU_BUTTON_WIDTH);
b:SetHeight(MENU_BUTTON_HEIGHT);
return b
end
local ScrollViewDataProvider = {};
do
local OFFSET_PER_SCROLL = MENU_BUTTON_HEIGHT;
ScrollViewDataProvider.content = {};
ScrollViewDataProvider.numEntry = 0;
ScrollViewDataProvider.objects = {};
local function GetTextWidth(text)
if not UtilityFontString then
UtilityFontString = DropDownMenu:CreateFontString(nil, "BACKGROUND", BUTTON_TEXT_FONT);
UtilityFontString:SetJustifyH("LEFT");
UtilityFontString:SetPoint("TOP", DropDownMenu, "TOP", 0, 0);
UtilityFontString:Hide();
end
UtilityFontString:SetText(text);
return UtilityFontString:GetUnboundedStringWidth();
end
function ScrollViewDataProvider:GetSpacing()
return 0
end
function ScrollViewDataProvider:SetContent(content)
self.content = content;
self:CalculateAllExtent();
if self.isVisible then
self:UpdateView();
else
self.isDisplayDirty = true;
end
end
function ScrollViewDataProvider:CalculateAllExtent()
local fromOffset = MENU_PADDING_V;
self.extent = {};
self.extent[0] = 0 + fromOffset;
self.extent[1] = 0 + fromOffset;
local textWidth;
local maxTextWidth = 0;
for i = 1, #self.content do
self.extent[i + 1] = MENU_BUTTON_HEIGHT * i + fromOffset;
textWidth = GetTextWidth(self.content[i][1]);
if textWidth > maxTextWidth then
maxTextWidth = textWidth;
end
end
self.maxTextWidth = API.Round(2*BUTTON_TEXT_OFFSET_X + maxTextWidth);
end
ScrollViewDataProvider:CalculateAllExtent();
function ScrollViewDataProvider:GetExtent()
return self.extent
end
function ScrollViewDataProvider:UpdateView()
self.isDisplayDirty = nil;
self.owner:OnContentChanged();
end
function ScrollViewDataProvider:GetMaxDataIndex()
return #self.content
end
function ScrollViewDataProvider:GetStep()
return OFFSET_PER_SCROLL;
end
function ScrollViewDataProvider:GetMaxExtent()
return self.extent[#self.extent] + MENU_PADDING_V
end
function ScrollViewDataProvider:CreateObject()
local object = CreateMenuButton(DropDownMenu.ScrollView);
table.insert(self.objects, object);
return object
end
function ScrollViewDataProvider:SetObjectData(object, dataIndex)
if dataIndex ~= object.dataIndex then
object.dataIndex = dataIndex;
local data = self.content[dataIndex];
if data then
else
return false
end
object:SetData(data);
end
return true
end
function ScrollViewDataProvider:OnShow(scrollView)
self.isVisible = true;
if self.isDisplayDirty then
self:UpdateView();
end
end
function ScrollViewDataProvider:OnHide(scrollView)
self.isVisible = false;
end
function ScrollViewDataProvider:OnViewUpdated()
end
end
local function DropDown_OnLoad(self)
self:SetSize(8, 8);
self.textures = {};
local bg = self:CreateTexture(nil, "BACKGROUND");
table.insert(self.textures, bg);
self.Background = bg;
local margin = 12;
bg:SetTextureSliceMargins(margin, margin, margin, margin);
bg:SetTextureSliceMode(1);
bg:SetAllPoints(true);
bg:SetTexCoord(0, 0.25, 0, 0.25);
self.ButtonHighlight = CreateFrame("Frame", nil, self);
self.ButtonHighlight:Hide();
local hl = self.ButtonHighlight:CreateTexture(nil, "BACKGROUND", nil, 1);
table.insert(self.textures, hl);
local margin = 8;
hl:SetTextureSliceMargins(margin, margin, margin, margin);
hl:SetTextureSliceMode(1);
hl:SetTexCoord(0.265625, 0.515625, 0, 0.125);
hl:SetAllPoints(true);
local ScrollView = addon.CreateScrollView(self);
self.ScrollView = ScrollView;
ScrollView:SetPoint("TOPLEFT", self, "TOPLEFT", 0, -2);
ScrollView:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 2);
local ScrollBar = addon.CreateScrollBar(self);
self.ScrollBar = ScrollBar;
local inset = SCROLLBAR_PADDING;
ScrollBar:SetPoint("TOPRIGHT", ScrollView, "TOPRIGHT", -inset, -inset);
ScrollBar:SetPoint("BOTTOMRIGHT", ScrollView, "BOTTOMRIGHT", -inset, inset);
ScrollBar:SetOwner(ScrollView);
ScrollBar:SetAlwaysVisible(false);
ScrollBar:ShowScrollToBottomButton(false);
ScrollBar:SetTheme(1);
ScrollBar:Show();
ScrollView:SetScrollBar(ScrollBar);
self:LoadTheme();
end
function DropDownMenuMixin:OnHide()
self:Hide();
end
function DropDownMenuMixin:LoadTheme()
if self.textures then
local file = addon.ThemeUtil:GetTextureFile("DropDown-UI.png");
for _, texture in pairs(self.textures) do
texture:SetTexture(file);
end
if addon.ThemeUtil:IsDarkMode() then
self.ScrollBar:SetTheme(2);
else
self.ScrollBar:SetTheme(1);
end
end
end
function DropDownMenuMixin:HighlightButton(button)
self.ButtonHighlight:Hide();
self.ButtonHighlight:ClearAllPoints();
if button and button:IsEnabled() then
self.ButtonHighlight:SetParent(button);
self.ButtonHighlight:SetPoint("TOPLEFT", button, "TOPLEFT", 2, 0);
self.ButtonHighlight:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -2, 0);
self.ButtonHighlight:SetFrameLevel(button:GetFrameLevel());
self.ButtonHighlight:Show();
end
end
function DropDownMenuMixin:SetContent(content)
ScrollViewDataProvider:SetContent(content);
self.ScrollView:OnContentChanged();
self.ScrollView:ScrollToTop();
self:Layout();
end
function DropDownMenuMixin:Layout()
local height;
local contentHeight = self.ScrollView:GetMaxExtent();
if contentHeight > DEFAULT_MENU_HEIGHT then
height = DEFAULT_MENU_HEIGHT;
else
height = contentHeight;
end
self:SetHeight(height);
self.ScrollView:OnSizeChanged();
self.ScrollBar:OnSizeChanged();
self.ScrollView:UpdateScrollRange();
self.ScrollBar:UpdateThumbSize();
local maxTextWidth = ScrollViewDataProvider.maxTextWidth;
local menuButtonWidth;
if maxTextWidth > MENU_BUTTON_MAX_WIDTH then
menuButtonWidth = MENU_BUTTON_MAX_WIDTH;
else
menuButtonWidth = maxTextWidth;
end
local width;
if self.ScrollView:IsScrollable() then
width = menuButtonWidth + SCROLLBAR_SIZE;
else
width = menuButtonWidth;
end
self:SetWidth(width);
MENU_BUTTON_WIDTH = menuButtonWidth;
for _, object in pairs(ScrollViewDataProvider.objects) do
object:SetWidth(menuButtonWidth)
end
end
function DropDownMenuMixin:Close()
self:Hide();
end
local function GetDropDownMenu(parent)
if not DropDownMenu then
local f = CreateFrame("Frame", nil, parent);
f:EnableMouse(true);
API.Mixin(f, DropDownMenuMixin);
DropDown_OnLoad(f);
f:SetPoint("CENTER", nil, "CENTER", 0, 0);
f:SetSize(DEFAULT_MENU_WIDTH, DEFAULT_MENU_HEIGHT);
f.ScrollView:OnSizeChanged();
f.ScrollBar:OnSizeChanged();
f:SetScript("OnHide", f.OnHide);
f.ScrollView:SetDataProvider(ScrollViewDataProvider);
DropDownMenu = f;
end
return DropDownMenu
end
addon.GetDropDownMenu = GetDropDownMenu;
do
--Debug
local content1 = {
{"Test 1", 1},
{"Test 2", 1},
{"Test 3", 1},
{"Test 4", 1},
{"Test 5", 1},
{"Test 6", 1},
{"Test 7", 1},
{"Test 8", 1},
--{"Test 9", 1},
--{"Test 10", 1},
--{"Test 11", 1},
};
local content2 = {
{"Test 1", 1},
{"Test 2", 1},
{"Test 3", 1},
{"Test 4", 1},
{"Test 5", 1},
{"Test 6", 1},
{"Test 7", 1},
{"Test 8", 1},
{"Test 9", 1},
{"Test 10", 1},
{"Test 11", 1},
{"Test 12", 1},
};
end