diff --git a/XanReputation.lua b/XanReputation.lua index 9240931..16394f0 100644 --- a/XanReputation.lua +++ b/XanReputation.lua @@ -99,11 +99,12 @@ function f:CreateREP_Frame() g:SetText("?") f:SetScript("OnMouseDown",function(self, button) + if not button then return end if button == "LeftButton" and IsShiftKeyDown() then self.isMoving = true self:StartMoving(); elseif button == "RightButton" then - ToggleDropDownMenu(1, nil, self.DD, self, 0, 0) + self:ShowDropDown(self) end end) f:SetScript("OnMouseUp",function() @@ -273,90 +274,152 @@ end -- DropDown -- ------------------------------ -function f:SetupDropDown() +local function Faded(self) + self:Release() +end - --close the dropdown menu if shown - if f.DD and f.DD:IsShown() then - CloseDropDownMenus() - end +local function FadeMenu(self) + local fadeInfo = {} + fadeInfo.mode = "OUT" + fadeInfo.timeToFade = 0.1 + fadeInfo.finishedFunc = Faded + fadeInfo.finishedArg1 = self + UIFrameFade(self, fadeInfo) +end - local dd1 = LibStub('LibXMenu-1.0'):New("xanReputation_DD", XanREP_DB) - dd1.initialize = function(self, lvl) - if lvl == 1 then - self:AddList(lvl, "Reputation", "rep") - self:AddList(lvl, "Settings", "settings") - self:AddCloseButton(lvl, "Close") - elseif lvl and lvl > 1 then - local sub = UIDROPDOWNMENU_MENU_VALUE - if sub == "rep" then - for i = 1, GetNumFactions() do - local name, showValue, level, minVal, maxVal, value, atWar, canBeAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(i) - if isHeader then - self:AddList(lvl, name, "rep2|"..name) - end +function f:ShowDropDown(sFrame) + + local dd1 = LibStub("LibDropdown-1.0") + + local t = { + type = "group", + name = "group", + desc = "group", + args = { + reputation = { + type = "group", + name = "Reputation", + desc = "Select a reputation", + args = { + --to be filled by loop below + }, + order = 10 + }, + settings = { + type = "group", + name = "Settings", + desc = "xanReputation settings", + args = { + range = { + type = "range", + name = "Scale", + desc = "Change the scale size of xanReputation", + min = 1, + max = 2.6, + bigStep = 0.1, + get = function(info) return XanREP_DB.scale end, + set = function(info, v) + XanREP_DB.scale = v + xanReputation:SetScale(v) + end, + order = 10 + }, + toggleBG = { + type = "toggle", + name = "Toggle background", + desc = "Toggle the xanReputation background", + get = function() return XanREP_DB.bgShown end, + set = function(info, v) + XanREP_DB.bgShown = v + f:BackgroundToggle(true) + end, + order = 20 + }, + autoSwitchBG = { + type = "toggle", + name = "Auto Switch", + desc = "Auto switch reputation", + get = function() return XanREP_DB.autoSwitch end, + set = function(info, v) XanREP_DB.autoSwitch = v end, + order = 30 + }, + }, + order = 20 + }, + close = { + type = "execute", + name = "Close", + desc = "Close this menu", + func = function(self) FadeMenu(f.DD) end, + order = 1000 + } + } + } + + --fill the reputation list + local parentOrder = 1 + for i = 1, GetNumFactions() do + local name, showValue, level, minVal, maxVal, value, atWar, canBeAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(i) + if isHeader then + --check if we have something first + local processChk = false + for q = 1, GetNumFactions() do + local nameSub, _, _, _, _, _, _, _, isHeaderSub = GetFactionInfo(q) + if isHeaderSub and nameSub == name then + boolD = true + elseif isHeaderSub and nameSub ~= name then + boolD = false + end + if boolD and not isHeaderSub then + processChk = true + break end - elseif strmatch(sub, "(%w+)|(.+)") == "rep2" then - - local _, cHeader = strmatch(sub, "(%w+)|(.+)") - local t = {} - local q = {} - - for i = 1, GetNumFactions() do - local name, showValue, level, minVal, maxVal, value, atWar, canBeAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(i) - if isHeader and name == cHeader then + end + + if processChk then + --do the child rep names for the reputation parent + local boolD = false + local tableValues = {} + for q = 1, GetNumFactions() do + local nameSub, _, _, _, _, _, _, _, isHeaderSub = GetFactionInfo(q) + if isHeaderSub and nameSub == name then boolD = true - elseif isHeader and name ~= cHeader then + elseif isHeaderSub and nameSub ~= name then boolD = false end - if boolD and not isHeader then - table.insert(t, name) - q[name] = level + if boolD and not isHeaderSub then + table.insert(tableValues,nameSub) end end - - table.sort(t, function(a,b) return a < b end) - if #t > 0 then - local starti = (30 * (lvl - 3)) + 1 - local endi = (30 * (lvl - 2)) - 1 - - for i = starti, endi, 1 do - if not t[i] then break end - local status = "??" - if q[t[i]] then - status = string.format("|cFF%s%s|r", colors[q[t[i]]], levels[q[t[i]]]) - end - self:AddSelect(lvl, string.format("%s (%s)", t[i], status), t[i], "factionWatched") - if i == endi and t[i + 1] then - self:AddList(lvl, "More", sub) - break - end - end - end - elseif sub == "settings" then - self:AddList(lvl, "Scale", "scale") - self:AddToggle(lvl, "Toggle background", "bgShown", nil, nil, nil, 1) - self:AddToggle(lvl, "Auto switch reputation", "autoSwitch") - elseif sub == "scale" then - for i = 1, 2.6, 0.1 do - self:AddSelect(lvl, i, i, "scale", nil, nil, 2) - end - end - end - end - - dd1.doUpdate = function(bOpt) - if bOpt and bOpt == 1 then - self:BackgroundToggle(true) - return - elseif bOpt and bOpt == 2 then - xanReputation:SetScale(XanREP_DB.scale) - return + --add to reputation parent + t.args.reputation.args[name] = + { + type = "select", + name = name, + desc = name, + values = tableValues, + order = parentOrder*10, + get = function(info) return optIndex end, + set = function(info, v) optIndex = v end + --XanREP_DB.factionWatched = nameSub + --f:GetFactionWatched(true) + } + + parentOrder = parentOrder + 1 + + end end - self:GetFactionWatched(true) end - - f.DD = dd1 + + + f.DD = dd1:OpenAce3Menu(t) + f.DD:SetClampedToScreen(true) + f.DD:SetAlpha(1.0) + f.DD:Show() + + f:GetFactionWatched(true) + end ------------------------------ @@ -388,7 +451,6 @@ function f:CHAT_MSG_COMBAT_FACTION_CHANGE(event, msg) if XanREP_DB.factionCount ~= GetNumFactions() then --a new faction was added so lets update the display XanREP_DB.factionCount = GetNumFactions() - f:SetupDropDown() end if not decrease and XanREP_DB.autoSwitch then @@ -410,7 +472,6 @@ function f:CHAT_MSG_SYSTEM(event, msg) if XanREP_DB.factionCount ~= GetNumFactions() then --a new faction was added so lets update the display XanREP_DB.factionCount = GetNumFactions() - f:SetupDropDown() end end @@ -420,9 +481,6 @@ function f:UPDATE_FACTION() --setup startup faction information self:GetFactionWatched(true) - --do the dropdown - self:SetupDropDown() - --do rep frame update self:UpdateREP_Frame() diff --git a/XanReputation.toc b/XanReputation.toc index 6db0261..76e338f 100644 --- a/XanReputation.toc +++ b/XanReputation.toc @@ -1,11 +1,11 @@ -## Interface: 40200 +## Interface: 50001 ## Title: xanReputation ## Notes: A small window display current reputation xp ## Author: Xruptor -## Version: 1.9.2 +## Version: 2.0 ## SavedVariablesPerCharacter: XanREP_DB libs\LibStub.lua -libs\LibXMenu-1.0.lua +libs\LibDropdown-1.0.lua xanReputation.lua diff --git a/libs/LibDropdown-1.0.lua b/libs/LibDropdown-1.0.lua new file mode 100644 index 0000000..161ae20 --- /dev/null +++ b/libs/LibDropdown-1.0.lua @@ -0,0 +1,1155 @@ +local MAJOR = "LibDropdown-1.0" +local MINOR = 1 + +local lib = LibStub:NewLibrary(MAJOR, MINOR) +if not lib then return end + +local math_max = _G.math.max + +local framePool = lib.framePool or {} +lib.framePool = framePool + +local buttonPool = lib.buttonPool or {} +lib.buttonPool = buttonPool + +local inputPool = lib.inputPool or {} +lib.inputPool = inputPool + +local frameHideQueue = lib.frameHideQueue or {} +lib.frameHideQueue = frameHideQueue + +local sliderPool = lib.sliderPool or {} +lib.sliderPool = sliderPool + +local AddButton, ShowGroup, HideGroup, SetGroup, NewDropdownFrame, NewDropdownButton, ReleaseFrame, AcquireButton, ReleaseButton, AcquireFrame +local UIParent = _G.UIParent + +local openMenu + +local noop = lib.noop or function() end +lib.noop = noop + +local new, newHash, newSet, del +if not lib.new then + local list = setmetatable({}, {__mode='k'}) + function new(...) + local t = next(list) + if t then + list[t] = nil + for i = 1, select('#', ...) do + t[i] = select(i, ...) + end + return t + else + return {...} + end + end + function del(t) + setmetatable(t, nil) + for k in pairs(t) do + t[k] = nil + end + t[''] = true + t[''] = nil + list[t] = true + return nil + end + lib.new, lib.del = new, del +end + +-- Make the frame match the tooltip +local function InitializeFrame(frame) + local backdrop = GameTooltip:GetBackdrop() + + frame:SetBackdrop(backdrop) + + if backdrop then + frame:SetBackdropColor(GameTooltip:GetBackdropColor()) + frame:SetBackdropBorderColor(GameTooltip:GetBackdropBorderColor()) + end + frame:SetScale(GameTooltip:GetScale()) +end + +local editBoxCount = 1 +local function AcquireInput() + local frame = tremove(inputPool) + + if frame then + frame.released = false + return frame + end + + frame = CreateFrame("EditBox", "LibDropDownEditBox"..editBoxCount, UIParent, "InputBoxTemplate") + frame:SetAutoFocus(false) + editBoxCount = editBoxCount + 1 + frame:SetScript("OnEscapePressed", + function(self) + self:ClearFocus() + self:GetParent():GetRoot():Refresh() + end) + + frame:SetScript("OnEnterPressed", + function(self) + if self.ValueChanged then + self:ValueChanged(self:GetText()) + end + end) + frame.refresh = noop + return frame +end + +local function AcquireSlider() + local frame = tremove(sliderPool) + if frame then + frame.released = false + return frame + end + + local frame = CreateFrame("Slider", nil, UIParent) + frame:SetWidth(10) + frame:SetHeight(150) + frame:SetOrientation("VERTICAL") + frame:SetBackdrop({ + bgFile = [[Interface\Buttons\UI-SliderBar-Background]], + edgeFile = [[Interface\Buttons\UI-SliderBar-Border]], + tile = true, + tileSize = 8, + edgeSize = 8, + insets = {left = 3, right = 3, top = 6, bottom = 6} + }) + frame:SetThumbTexture([[Interface\Buttons\UI-SliderBar-Button-Vertical]]) + frame:EnableMouseWheel() + frame:Show() + + local text = frame:CreateFontString(nil, nil, "GameFontNormalSmall") + text:SetPoint("TOP", frame, "BOTTOM") + text:SetTextColor(1,1,1,1) + frame.text = text + + frame:SetScript("OnMouseWheel", function(self, direction, ...) + if not direction then return end -- huh? + local mn, mx = self:GetMinMaxValues() + local nv = min(mx, max(mn, self:GetValue() + ((self.step or 1) * direction * -1))) + self:SetValue(nv) + end) + + frame:SetScript("OnValueChanged", function(self) + local mn, mx = self:GetMinMaxValues() + local nv = min(mx, max(mn, self:GetValue())) + if nv ~= self:GetValue() then + self:SetValue(nv) + return + end + local n, x = self:GetMinMaxValues() + local ev = x - nv + frame.text:SetText(ev) + + if self.ValueChanged then + self:ValueChanged(self:GetValue()) + end + end) + frame.refresh = noop + return frame +end + +local function ReleaseSlider(slider) + if slider.released then return end + slider.released = true + slider:Hide() + slider:SetParent(UIParent) + tinsert(sliderPool, slider) + return nil +end + +local function ReleaseInput(input) + if input.released then return end + input.released = true + input:Hide() + input:SetParent(UIParent) + tinsert(inputPool, input) + return nil +end + +local function MouseOver(frame) + local f = GetMouseFocus() + while f and f ~= UIParent do + if f == frame then return true end + f = f:GetParent() + end + return false +end + +-- Frame methods +function AddButton(self, b) + b:ClearAllPoints() + b:SetParent(self) + b:Show() + if #self.buttons == 0 then + b:SetPoint("TOPLEFT", self, "TOPLEFT", 0, -4) + b:SetPoint("TOPRIGHT", self, "TOPRIGHT", 0, -4) + else + b:SetPoint("TOPLEFT", self.buttons[#self.buttons], "BOTTOMLEFT") + b:SetPoint("TOPRIGHT", self.buttons[#self.buttons], "BOTTOMRIGHT") + end + tinsert(self.buttons, b) + self:SetHeight(#self.buttons * b:GetHeight() + 8) +end + +function Refresh(self) + if not self:IsVisible() then return end + local maxWidth = 1 + for i = 1, #self.buttons do + self.buttons[i]:refresh() + maxWidth = math_max(maxWidth, self.buttons[i].text:GetStringWidth() + 60) + end + self:SetWidth(maxWidth) +end + +function GetRoot(self) + local parent = self:GetParent() + if parent and parent.GetRoot then + return parent:GetRoot() + else + return self + end +end + +-- Button methods +function ShowGroup(self) + if not self.enabled then return end + if not self.groupFrame then + self.groupFrame = self:AcquireFrame() + end + if not self.handled then + self.handler(lib, self.group, self.groupFrame) + self.handled = true + end + self.groupFrame:SetPoint("TOPLEFT", self, "TOPRIGHT", 0, 4) + self.groupFrame:Show() + self.groupFrame:Refresh() + self:LockHighlight() + self:enter() + if self.groupFrame.Showing then + self.groupFrame:Showing() + end +end + +function HideGroup(self) + if not self then return end + if MouseOver(self) then return end + if self.groupFrame then + self.groupFrame:Hide() + end + self:UnlockHighlight() + self:leave() + if self.groupFrame.Hiding then + self.groupFrame:Hiding() + end +end + +function SetChecked(self, val) + self.checked = val + if val then + self.check:Show() + self.check:SetDesaturated(false) + elseif val == false or not self.tristate then + self.check:Hide() + elseif val == nil then + self.check:Show() + self.check:SetDesaturated(true) + end +end + +function HideRecursive(self) + HideGroup(self:GetParent()) +end + +function SetGroup(self, t, handler) + if t then + self.expand:Show() + self:SetScript("OnEnter", ShowGroup) + self:SetScript("OnLeave", HideGroup) + self.group = t + self.handler = handler + else + self.expand:Hide() + self:SetScript("OnEnter", nil) + self:SetScript("OnLeave", nil) + self.group = nil + self.handler = nil + end + self.clickable = t == nil +end + +-- Pool methods +local frameCount = 0 +function NewDropdownFrame() + local frame = CreateFrame("Frame", "LibDropdownFrame" .. frameCount, UIParent) + frameCount = frameCount + 1 + frame:SetPoint("CENTER", UIParent, "CENTER") + frame:SetWidth(10) + frame:SetHeight(24) + frame:EnableMouse(true) + frame.AddButton = AddButton + frame.Refresh = Refresh + frame.GetRoot = GetRoot + frame.isDropdownFrame = true + frame.Release = ReleaseFrame + frame.AcquireButton = AcquireButton + -- make it close on escape + tinsert(UISpecialFrames, frame:GetName()) + return frame +end + +do + local function enterButton(self) + GameTooltip_SetDefaultAnchor(GameTooltip, self) + GameTooltip:ClearLines() + GameTooltip:AddLine(self.text:GetText()) + if self.desc then + GameTooltip:AddLine("|cffffffff" .. self.desc .. "|r") + end + GameTooltip:Show() + end + + local function leaveButton(self) + GameTooltip:Hide() + local p = self:GetParent() + if p then + local f = p:GetScript("OnLeave") + if f then + f(p) + end + end + end + + local function pushText(self) + if not self.clickable then return end + self.text:SetPoint("TOP", self, "TOP", 0, -2) + self.text:SetPoint("LEFT", self.check, "RIGHT", 6, 0) + end + + local function unpushText(self) + if not self.clickable then return end + self.text:SetPoint("TOP", self, "TOP", 0, 0) + self.text:SetPoint("LEFT", self.check, "RIGHT", 4, 0) + end + + local function click(self) + if self.OnClick and self.clickable then + self.OnClick(self) + PlaySound("igMainMenuOptionCheckBoxOn"); + self:GetParent():GetRoot():Refresh() + end + end + + local function settext(self, t) + self.text:SetText(t) + end + + local function disable(self) + self.enabled = false + self:SetScript("OnMouseDown", nil) + self:SetScript("OnMouseUp", nil) + self.text:SetTextColor(0.5, 0.5, 0.5, 1) + self.check:SetDesaturated(true) + self.expand:SetDesaturated(true) + self:oldDisable() + end + + local function enable(self) + self.enabled = true + self:SetScript("OnMouseDown", pushText) + self:SetScript("OnMouseUp", unpushText) + self.text:SetTextColor(1, 1, 1, 1) + -- self.text:SetTextColor(self:GetTextColor()) -- Removed in 3.0 + self.check:SetDesaturated(false) + self.expand:SetDesaturated(false) + self:oldEnable() + end + + local function revert() + --ColorPickerFrame.previousValues.frame + end + + local function setColor() + local r,g,b = ColorPickerFrame:GetColorRGB() + local a = ColorPickerFrame.opacity or 1 + local f = ColorPickerFrame.previousValues.frame + f:GetNormalTexture():SetVertexColor(r, g, b, a) + if f:GetParent().OnClick then + f:GetParent():OnClick(r,g,b,a) + end + end + + local function revert() + p = ColorPickerFrame.previousValues + ColorPickerFrame:SetColorRGB(p.r, p.g, p.b) + ColorPickerFrame.opacity = p.opacity + setColor() + end + + local function openColorPicker(self) + local p = self:GetParent() + p.r, p.g, p.b, p.a = self:GetNormalTexture():GetVertexColor() + + ColorPickerFrame.hasOpacity = p.hasOpacity + ColorPickerFrame.opacityFunc = p.opacityFunc + ColorPickerFrame.opacity = p.a + ColorPickerFrame:SetColorRGB(p.r, p.g, p.b) + ColorPickerFrame.previousValues = ColorPickerFrame.previousValues or {} + ColorPickerFrame.previousValues.r = p.r + ColorPickerFrame.previousValues.g = p.g + ColorPickerFrame.previousValues.b = p.b + ColorPickerFrame.previousValues.opacity = p.a + ColorPickerFrame.previousValues.frame = self + ColorPickerFrame.cancelFunc = revert + ColorPickerFrame.func = setColor + + ShowUIPanel(ColorPickerFrame) + end + + local function highlightSwatch(self) + self.tex:SetTexture(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); + end + + local function unhighlightSwatch(self) + self.tex:SetTexture(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); + end + + local function makeTitle(self, t) + -- self.text:SetJustifyH("CENTER") + self.text:ClearAllPoints() + self.text:SetPoint("LEFT", self, "LEFT", 16, 0) + self.text:SetPoint("RIGHT", self, "RIGHT", -16, 0) + self.text:SetTextColor(1, 0.8, 0, 1) + self.clickable = false + if t then self.text:SetText(t) end + end + + local function makeButton(self, t) + local text, frame, check, expand = self.text, self, self.check, self.expand + text:ClearAllPoints() + text:SetPoint("TOP", frame, "TOP") + text:SetPoint("LEFT", check, "RIGHT", 4, 0) + text:SetPoint("BOTTOM", frame, "BOTTOM") + text:SetPoint("RIGHT", expand, "LEFT", -4, 0) + text:SetJustifyH("LEFT") + self.text:SetTextColor(1, 1,1,1) + self.clickable = true + if t then text:SetText(t) end + end + + function NewDropdownButton(f) + local frame = f or CreateFrame("Button", nil, UIParent) + frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]]) + frame:GetHighlightTexture():SetBlendMode("ADD") + -- frame:SetDisabledTextColor(0.5, 0.5, 0.5, 1) -- Removed in 3.0 + frame:SetPushedTextOffset(3,-3) + frame:SetHeight(18) + + local check = frame.check or frame:CreateTexture() + check:SetTexture([[Interface\Buttons\UI-CheckBox-Check]]) + check:SetWidth(18) + check:SetHeight(18) + check:SetPoint("LEFT", frame, "LEFT", 4, 0) + check:Hide() + frame.check = check + + local expand = frame.expand or frame:CreateTexture() + expand:SetTexture([[Interface\ChatFrame\ChatFrameExpandArrow]]) + expand:SetWidth(16) + expand:SetHeight(16) + expand:SetPoint("RIGHT", frame, "RIGHT", -4, 0) + expand:Hide() + frame.expand = expand + + local text = frame.text or frame:CreateFontString(nil, nil, "GameFontHighlightSmall") + frame.text = text + frame.SetText = settext + frame.MakeButton = makeButton + frame.MakeTitle = makeTitle + frame:MakeButton("<not set>") + + local swatch = frame.swatch or CreateFrame("Button", nil, frame) + swatch:SetWidth(18) + swatch:SetHeight(18) + swatch.tex = swatch.text or swatch:CreateTexture(nil, "BACKGROUND") + swatch.tex:SetPoint("CENTER", swatch, "CENTER") + swatch.tex:SetWidth(swatch:GetWidth()-2) + swatch.tex:SetHeight(swatch:GetHeight()-2) + -- swatch.tex:SetTexture([[Interface\ChatFrame\ChatFrameColorSwatch]]) + swatch:SetNormalTexture([[Interface\ChatFrame\ChatFrameColorSwatch]]) + swatch:SetPoint("RIGHT", frame, "RIGHT", -4, 0) + swatch:SetScript("OnClick", openColorPicker) + swatch:SetFrameLevel(frame:GetFrameLevel() + 100) + swatch:SetScript("OnEnter", highlightSwatch) + swatch:SetScript("OnLeave", unhighlightSwatch) + swatch:Hide() + frame.swatch = swatch + unhighlightSwatch(swatch) + + frame:SetScript("OnEnter", enterButton) + frame:SetScript("OnLeave", leaveButton) + frame.enter, frame.leave = enterButton, leaveButton + + frame:SetScript("OnMouseDown", pushText) + frame:SetScript("OnMouseUp", unpushText) + frame:SetScript("OnClick", click) + frame.SetGroup = SetGroup + frame.SetChecked = SetChecked + frame.AcquireFrame = AcquireFrame + frame.GetRoot = GetRoot + frame.oldDisable, frame.Disable = frame.Disable, disable + frame.oldEnable, frame.Enable = frame.Enable, enable + frame.Release = ReleaseButton + + frame.clickable = true + frame.enabled = true + frame:Enable() + + return frame + end +end + +function ReleaseFrame(f) + if f.rootMenu then + openMenu = nil + end + if f.released then return end + f.released = true + f.data = nil + f.dataname = nil + f.rootMenu = nil + + f:Hide() + f:SetParent(UIParent) + f:ClearAllPoints() + + tinsert(framePool, f) + for i = 1, #f.buttons do + local button = tremove(f.buttons) + button:Release() + end + return nil +end + +function AcquireButton(p) + local b = NewDropdownButton(tremove(buttonPool)) + b.released = false + b:EnableMouse(true) + b:Show() + p:AddButton(b) + return b +end + +function ReleaseButton(b) + if b.released then return end + tinsert(buttonPool, b) + b.desc = nil + b.released = true + b.Enable = b.oldEnable + b.Disable = b.oldDisable + b.handled = false + b:SetParent(UIParent) + b:Hide() + if b.slider then + b.slider = ReleaseSlider(b.slider) + end + if b.input then + b.input = ReleaseInput(b.input) + end + b:ClearAllPoints() + b:MakeButton("(released)") + if b.groupFrame then + b.groupFrame.Showing = nil + b.groupFrame = b.groupFrame:Release() + end + +end + +local function frameReleaseOnHide(self) + self:SetScript("OnHide", nil) + self:Release() +end + +function AcquireFrame(parent, toplevel) + local f = tremove(framePool) or NewDropdownFrame() + InitializeFrame(f) -- set the look of the frame + f.released = false + f.buttons = f.buttons or {} + f:SetParent(parent or UIParent) + if parent then + f:SetScript("OnLeave", HideRecursive) + else + f:SetScript("OnLeave", nil) + end + if toplevel then + f:SetScript("OnHide", frameReleaseOnHide) + else + f:SetScript("OnHide", nil) + end + f:ClearAllPoints() + f:Show() + return f +end + +---------------------------------------------------------------------- +---------------------------------------------------------------------- +do + local Ace3 = {} + local grefresh + local info = {} + local options + local currentOptionData + local function setup(k, v, parent) + local b = parent:AcquireButton() + b.data = v + b.option = v + b.dataname = k + b.refresh = grefresh + return b + end + + local function setInfoOptions() + local option = options + for _, key in ipairs(info) do + if option.args and option.args[key] then + option = option.args[key] + else + return + end + end + info.option = option + info.type = option.type + end + + local function initInfo(type) + info.options = options + info.appName = options.name + info.type = type + info.uiType = "dropdown" + info.uiName = "LibDropdown-1.0" + end + + local function wipeInfo() + local type = info.type + wipe(info) + initInfo(type) + end + + local function runHandler(button, handler, ...) + info.handler = handler + info.option = button.data + if not button.rootMenu then + tinsert(info, 1, button.dataname) + end + local v = button.data + if v and v[handler] then + local ht = type(v[handler]) + if ht == "function" then + setInfoOptions() + local ret, r1, r2, r3 = v[handler](info, ...) + wipeInfo() + return ret, r1, r2, r3 + elseif ht == "table" then + return v[handler] + elseif ht == "string" then + local t = runHandler(button, "handler", ...) + if type(t) == "table" then + setInfoOptions() + local ret, r1, r2, r3 = t[v[handler]](t, info, ...) + wipeInfo() + return ret, r1, r2, r3 + end + end + elseif v and v[handler] == false then + return nil -- Is this right? + else + if button.GetParent then + local pp = button:GetParent() and button:GetParent():GetParent() + if not pp or not pp.data then + pp = button:GetParent() + end + if pp and pp.data then + return runHandler(pp, handler, ...) + end + end + end + wipeInfo() + return nil + end + + function grefresh(self) + local isDisabled = false + self:SetText(self.data.name) + self.desc = self.data.desc + if type(self.data.disabled) == "function" then + if self.data.disabled() then + self:Disable() + isDisabled = true + else + self:Enable() + end + elseif type(self.data.disabled) == "boolean" then + if self.data.disabled then + self:Disable() + isDisabled = true + else + self:Enable() + end + end + return isDisabled + end + + -- group + do + local function refresh(self) + grefresh(self) + if not self.groupFrame or self.groupFrame == self:GetParent() then return end + self.groupFrame:Refresh() + end + function Ace3.group(k, v, parent) + local b = setup(k, v, parent) + if v.inline then + -- TODO: Add heading + local b2 = parent:AcquireButton() + b:MakeTitle(k) + b2.refresh = noop + lib:OpenAce3Menu(v.args, parent) + else + b:SetGroup(v.args, lib.OpenAce3Menu) + end + b.refresh = refresh + end + end + + -- execute + function Ace3.execute(k, v, parent) + local b = setup(k, v, parent) + b:SetText(v.name) + b.desc = v.desc + b.OnClick = function(self) + initInfo('execute') + runHandler(self, "func") + self:GetRoot():Refresh() + end + end + + -- input + do + local function refresh(self) + grefresh(self) + self.input:SetText(runHandler(self, "get") or "") + end + + local function inputValueChanged(self, val) + initInfo('input') + runHandler(self:GetParent():GetParent(), "set", val) + self:GetParent():GetRoot():Refresh() + end + + function Ace3.input(k, v, parent) + local b = setup(k, v, parent) + b:SetGroup(v, lib.Ace3InputShow) + b.input = AcquireInput() + b.refresh = refresh + end + + local function showInput(frame) + local data = frame.data + local input = frame:GetParent().input + input:SetParent(frame) + input:ClearAllPoints() + input:SetPoint("LEFT", frame, "LEFT", 10, 0) + frame:SetWidth(185) + input:SetWidth(170) + input:SetHeight(34) + frame:SetHeight(34) + input.ValueChanged = inputValueChanged + input:Show() + refresh(frame:GetParent()) + end + + function lib:Ace3InputShow(t, parent) + parent.data = t + parent.Showing = showInput + end + end + + -- toggle + do + local function refresh(self) + local disabled = grefresh(self) + initInfo('toggle') + local actual = runHandler(self, "get") + if disabled then + self:SetChecked(false) + else + self:SetChecked(actual) + end + end + local function onClick(self) + initInfo('toggle') + if self.data.tristate then + local val = runHandler(self, "get") + local sv + if val == nil then sv = true + elseif val == true then sv = false + else sv = nil end + runHandler(self, "set", sv) + else + local val = not runHandler(self, "get") + runHandler(self, "set", val) + end + self:GetRoot():Refresh() + end + + function Ace3.toggle(k, v, parent) + local b = setup(k, v, parent) + b.OnClick = onClick + b.tristate = v.tristate + b.refresh = refresh + end + end + + -- header + do + local function refresh(self) + grefresh(self) + end + + function Ace3.header(k, v, parent) + local b = setup(k, v, parent) + b:MakeTitle(k) + b:EnableMouse(false) + b.tristate = nil + b.refresh = refresh + end + end + + -- color + do + local function refresh(self) + grefresh(self) + initInfo('color') + self.swatch:GetNormalTexture():SetVertexColor(runHandler(self, "get")) + end + function Ace3.color(k, v, parent) + local b = setup(k, v, parent) + b.swatch:Show() + b.clickable = false + b.refresh = refresh + b.OnClick = function(self, r, g, b, a) + runHandler(self, "set", r, g, b, a); + self:GetRoot():Refresh() + end + end + end + + -- select + do + local function refresh(self) + grefresh(self) + if self.groupFrame then + self.groupFrame:Refresh() + end + end + function Ace3.select(k, v, parent) + local b = setup(k, v, parent) + b.parentTree = v + b:SetGroup(v.values, lib.Ace3MenuSelect) + b.refresh = refresh + end + + local function buttonRefresh(self) + initInfo('select') + self:SetChecked( runHandler(self:GetParent():GetParent(), "get") == self.value ) + end + function lib:Ace3MenuSelect(t, parent) + initInfo('select') + if type(t) == "string" or type(t) == "function" then + t = runHandler(parent, "values") + end + if type(t) == "table" then + for k, v in pairs(t) do + local b = parent:AcquireButton() + b:SetText(v) + b.value = k + b.OnClick = function(self) + initInfo('select') + runHandler(self:GetParent():GetParent(), "set", self.value) + self:GetParent():GetRoot():Refresh() + end + b.refresh = buttonRefresh + end + end + end + end + + -- range + -- Some extra tricksery for mousewheel on the containing frame. A bit more user friendly. + do + local function refresh(self) + grefresh(self) + initInfo('range') + self.slider:SetValue(runHandler(self, "get") or self.slider:GetMinMaxValues()) + initInfo('range') + self.slider.text:SetText(runHandler(self, "get")) + end + + function Ace3.range(k, v, parent) + local b = setup(k, v, parent) + b:SetGroup(v, lib.Ace3SliderShow) + b.slider = AcquireSlider() + b.refresh = refresh + end + + local function onWheel(f) + f:GetParent().slider:GetScript("OnMouseWheel")(f:GetParent().slider) + end + + local function removeMousewheelFuncs(f) + tremove(f.buttons) + f:EnableMouseWheel(false) + f:SetScript("OnMouseWheel", nil) + f.Hiding = nil + end + + local function sliderValueChanged(self, val) + initInfo('range') + runHandler(self:GetParent():GetParent(), "set", val) + self:GetParent():GetRoot():Refresh() + end + + local function showSlider(frame) + local data = frame.data + local slider = frame:GetParent().slider + + slider:SetParent(frame) + slider:ClearAllPoints() + slider:SetPoint("CENTER", frame, "CENTER") + slider:SetPoint("TOP", frame, "TOP", 0, -8) + slider:SetHeight(150) + slider.text:ClearAllPoints() + slider.text:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 0, 8) + slider.text:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 8) + + slider.text:SetText(data.max) + frame:SetWidth(max(60, slider.text:GetStringWidth() + 10)) + + slider.step = data.bigStep + slider:SetMinMaxValues(data.min or 0, data.max or 100) + slider:SetValueStep(data.bigStep or data.step or 1) + slider.ValueChanged = sliderValueChanged + + frame:EnableMouseWheel(true) + frame:SetScript("OnMouseWheel", onWheel) + frame.Hiding = removeMousewheelFuncs + frame:SetHeight(180) + + slider:Show() + refresh(frame:GetParent()) + end + + function lib:Ace3SliderShow(t, parent) + parent.data = t + parent.Showing = showSlider + end + end + + do + local sortOptions = function(a,b) + if (b.order or 100) > (a.order or 100) then return true + elseif (b.order or 100) < (a.order or 100) then return false + elseif b.name:lower() > a.name:lower() then return true + else return false + end + end + + function lib:OpenAce3Menu(t, parent) + assert(t and type(t) == "table", "Expected table, got "..type(t)) + if parent == nil and t.args then + if openMenu then + openMenu:Release() + end + options = t + openMenu = AcquireFrame(nil, true) + openMenu:Show() + openMenu.data = t + openMenu.dataname = "Root menu" + openMenu.rootMenu = true + openMenu:SetPoint("CENTER", UIParent, "CENTER") + self:OpenAce3Menu(t.args, openMenu) + openMenu:Refresh() + openMenu:SetFrameStrata("TOOLTIP") + return openMenu + else + local sortedOpts = new() + local lookup = new() + for i = 1, #sortedOpts do + tremove(sortedOpts) + end + for k, v in pairs(t) do + lookup[v] = k + tinsert(sortedOpts, v) + end + table.sort(sortedOpts, sortOptions) + for _, v in ipairs(sortedOpts) do + if Ace3[v.type] and not v.dropdownHidden and not v.hidden then + Ace3[v.type](lookup[v], v, parent) + end + end + sortedOpts = del(sortedOpts) + lookup = del(lookup) + end + end + end +end + +------------------------------------------------------ +------------------------------------------------------ + +local toggled = true +local r,g,b,a = 1,0,1,1 +local options = {"foo", "bar", "foobar"} +local optIndex = 1 +local rangeVal, rangeVal2 = 100, 10 +local inherits = {["inherittoggle"] = true} + +local t = { + type = "group", + name = "group", + desc = "group", + args = { + foo = { + type = "input", + name = "text", + desc = "text desc", + get = function(info) return "texting!" end, + set = function(info, v) end + }, + inherit = { + type = "group", + name = "inheritance test", + desc = "inheritance test", + get = function(info) ChatFrame1:AddMessage(("Got getter, getting %s (%s)"):format(tostring(info[#info]), tostring(inherits[info[#info]]))); return inherits[info[#info]] end, + set = function(info, v) ChatFrame1:AddMessage("Got setter:" .. tostring(v)); inherits[info[#info]] = v end, + args = { + inherittoggle = { + type = "toggle", + name = "inherit toggle", + desc = "inherit toggle" + }, + } + }, + exec = { + type = "execute", + name = "Say hi", + desc = "Execute, says hi", + func = function() ChatFrame1:AddMessage("Hi!") end + }, + range = { + type = "range", + name = "Range slider", + desc = "Range slider", + min = 0, + max = 800, + bigStep = 50, + get = function(info) return rangeVal end, + set = function(info, v) rangeVal = v end, + }, + range2 = { + type = "range", + name = "Range slider 2", + desc = "Range slider 2", + min = 0, + max = 80, + bigStep = 5, + get = function(info) return rangeVal2 end, + set = function(info, v) rangeVal2 = v end, + }, + toggle = { + type = "toggle", + name = "Toggle", + desc = "Toggle", + get = function() return toggled end, + set = function(info, v) toggled = v end, + disabled = function(info) return not toggled end + }, + toggle3 = { + type = "toggle", + name = "Tristate Toggle Tristate Toggle Tristate Toggle", + desc = "Tristate Toggle", + tristate = true, + get = function() return toggled end, + set = function(info, v) toggled = v end + }, + select = { + type = "select", + name = "select", + desc = "select desc", + values = options, + get = function(info) return optIndex end, + set = function(info, v) optIndex = v end + }, + color = { + type = "color", + name = "color swatch", + desc = "color swatch desc", + get = function(info) return r,g,b,a end, + set = function(info, _r,_g,_b,_a) r,g,b,a = _r,_g,_b,_a end + }, + foo3 = { + type = "group", + name = "group!", + desc = "group desc", + args = { + toggle3 = { + type = "toggle", + name = "Tristate Toggle Tristate Toggle Tristate Toggle", + desc = "Tristate Toggle", + tristate = true, + get = function() return toggled end, + set = function(info, v) toggled = v end + }, + } + }, + foo4 = { + type = "group", + name = "inline group!", + desc = "inline group desc", + inline = "true", + args = { + foo2 = { + type = "input", + name = "text3", + desc = "text3 desc", + get = function(info) return "texting!" end, + set = function(info, v) end + } + }, + order = 500 + }, + close = { + type = "execute", + name = "Close", + desc = "Close this menu", + func = function(self) end, + order = 1000 + } + } +} + +function testdropdown() + LibStub("LibDropdown-1.0"):OpenAce3Menu(t) +end + + +---- + +WorldFrame:HookScript("OnMouseDown", function() + if openMenu then + openMenu = openMenu:Release() + end + end) diff --git a/libs/LibXMenu-1.0.lua b/libs/LibXMenu-1.0.lua deleted file mode 100644 index 249fc63..0000000 --- a/libs/LibXMenu-1.0.lua +++ /dev/null @@ -1,312 +0,0 @@ ---[[ - LibXMenu-1.0.lua - Created By: Xruptor - - A simple DropDown library for creating interactive menus. - - Example using each available option: - - local dd1 = LibStub('LibXMenu-1.0'):New("DropDownName", database) - dd1.db.color1val = { r = 0, g = 0, b = 0, a = 1, } - dd1.initialize = function(self, lvl) - if lvl == 1 then - self:AddTitle(lvl, "My DropDown") - self:AddList(lvl, "Font Size", "fontsize") - self:AddList(lvl, "Advance List", "advancelist") - self:AddColor(lvl, "Color 1", "color1val") - self:AddToggle(lvl, "Switch", "switch") - self:AddToggle(lvl, "Switch2", "switch2", otherdb, "otherdboption2") - elseif lvl and lvl > 1 then - local sub = UIDROPDOWNMENU_MENU_VALUE - if sub == "fontsize" then - --loop selection add - for i = 5, 12, 1 do - self:AddSelect(lvl, i, i, "fontsize", nil) - end - elseif sub == "advancelist" then - --several different ways of adding selects - self:AddSelect(lvl, "This button 1", "button1", db, "dboption1", nil, 1) - self:AddSelect(lvl, "This button 2", "button2", "dboption2", nil, nil, 2) - end - end - end - dd1.doUpdate = function(bOpt) - --fired after every menu selection click - doDisplayUpdates(); - if bOpt == 1 then - --do something, bOpt is optional tag attached to a button - end - end - - ToggleDropDownMenu(1, nil, dd1, "cursor") - ---]] - -local MAJOR, MINOR = "LibXMenu-1.0", 5 -local lib = LibStub:NewLibrary(MAJOR, MINOR) -if not lib then return end - ---DO NOT MODIFY ---Used to prevent checks from displaying on Menulist title options -local function HideCheck(item) - if item and item.GetName and _G[item:GetName().."Check"] then - _G[item:GetName().."Check"]:Hide() - end -end - ---[[ - lib:AddButton - (NOTE:) This function is automatically called by each menu item insertion. - You should only use this function if your going to use your own custom button. - lvl - menu level 1,2,3 etc... - text - name of the menu item - keepShownOnClick - (optional) toggle if the menu item should be shown or not on click (true/false) ---]] - -local function AddButton(self, lvl, text, keepshown) - if not lvl then return end - if not text then return end - self.info.text = text - self.info.keepShownOnClick = keepshown - self.info.owner = self - UIDropDownMenu_AddButton(self.info, lvl) - wipe(self.info) -end - ---[[ - lib:AddToggle - lvl - menu level 1,2,3 etc... - text - name of the menu item - value - element in the database table, used when arg1 and arg2 are both nil. Example: db[value] - NOTE: Value of the database element must be a boolean value. TRUE/FALSE. Example: db[value] = true - arg1 - custom database variable, if arg2 is nil then value is used as element. Example: arg1[value] - arg2 - custom database element for arg1. Example: arg1[arg2] - func - override with custom function - bOpt - define an optional variable to be passed to doUpdate. Example: button name or button ID. ---]] - -local function AddToggle(self, lvl, text, value, arg1, arg2, func, bOpt) - if not lvl then return end - if not text then return end - if not value then return end - - value = tonumber(value) or value - self.info.arg1 = arg1 - self.info.arg2 = arg2 - self.info.value = value - self.info.func = func or function(item, arg1, arg2) - if arg1 and arg2 then - arg1[arg2] = not arg1[arg2] - elseif arg1 then - arg1[item.value] = not arg1[item.value] - else - item.owner.db[item.value] = not item.owner.db[item.value] - end - if item.owner.doUpdate then item.owner.doUpdate(bOpt) end - end - if arg1 and arg2 then - self.info.checked = arg1[arg2] - elseif arg1 then - self.info.checked = arg1[value] - else - self.info.checked = self.db[value] - end - AddButton(self, lvl, text, 1) -end - ---[[ - lib:AddList - lvl - menu level 1,2,3 etc... - text - name of the menu item - value - menuList value, used in UIDROPDOWNMENU_MENU_VALUE when lvl > 1. ---]] - -local function AddList(self, lvl, text, value, notCheckable) - if not lvl then return end - if not text then return end - if not value then return end - - self.info.value = value - self.info.hasArrow = true - self.info.func = HideCheck - if notCheckable ~= nil then - self.info.notCheckable = notCheckable - else - self.info.notCheckable = true - end - self.info.notCheckable = notCheckable or true - AddButton(self, lvl, text, 1) -end - ---[[ - lib:AddSelect - lvl - menu level 1,2,3 etc... - text - name of the menu item - value - Value in database to compare and store. - If arg1 and arg2 then value is stored in the arg1[arg2] table. - If arg1 and not arg2 then value is stored in db[arg1] table. - arg1 - REQUIRED: database variable, if arg2 then acts as primary database. Example: arg1[arg2] - if not arg2 then arg1 is used as an element of the database table. Example: db[arg1] - arg2 - custom database variable, if arg1 then acts as an element in arg1 table. Example: arg1[arg2] - func - override with custom function - bOpt - define an optional variable to be passed to doUpdate. Example: button name or button ID. ---]] - -local function AddSelect(self, lvl, text, value, arg1, arg2, func, bOpt) - if not lvl then return end - if not text then return end - if not value then return end - if not arg1 and not arg2 then assert(false, "LibXMenu-1.0: Error, AddSelect() requires arg1") return end - - value = tonumber(value) or value - self.info.arg1 = arg1 - self.info.arg2 = arg2 - self.info.value = value - self.info.func = func or function(item, arg1, arg2) - local val = tonumber(item.value) or item.value - if arg1 and arg2 then - arg1[arg2] = val - elseif arg1 then - item.owner.db[arg1] = val - end - local level, num = strmatch(item:GetName(), "DropDownList(%d+)Button(%d+)") - level, num = tonumber(level) or 0, tonumber(num) or 0 - for i = 1, level, 1 do - for j = 1, UIDROPDOWNMENU_MAXBUTTONS, 1 do - local check = _G["DropDownList"..i.."Button"..j.."Check"] - local iObjChk = _G["DropDownList"..i.."Button"..j] - --make sure it's a pair in the same selection field - if iObjChk then - local passChk = false - if iObjChk.arg1 and iObjChk.arg2 then - passChk = iObjChk.arg1 == arg1 and iObjChk.arg2 == arg2 - elseif iObjChk.arg1 then - passChk = iObjChk.arg1 == arg1 - end - if passChk then - if check and i == level and j == num then - check:Show() - elseif item then - check:Hide() - end - end - end - end - end - if item.owner.doUpdate then item.owner.doUpdate(bOpt) end - end - if arg1 and arg2 then - self.info.checked = arg1[arg2] == value - elseif arg1 then - self.info.checked = self.db[arg1] == value - else - self.info.checked = false - end - AddButton(self, lvl, text, 1) -end - ---[[ - lib:AddColor - (NOTE:) A color table must be first established before using this function - lvl - menu level 1,2,3 etc... - text - name of the menu item - value - database element value or name. Example: db[value] - arg1 - (optional) use a secondary database, value is used as key. Example: arg1[value] - bOpt - define an optional variable to be passed to doUpdate. Example: button name or button ID. - func - override with custom function - swatchFunc - override with custom function - opacityFunc - override with custom function - cancelFunc - override with custom function ---]] - -local function AddColor(self, lvl, text, value, arg1, bOpt, func, swatchFunc, opacityFunc, cancelFunc) - if not lvl then return end - if not text then return end - if not value then return end - - local db - if arg1 then - db = arg1[value] - else - db = self.db[value] - end - if not db then return end - local SetColor = function(item) - local colDB = _G[self:GetName()].db[UIDROPDOWNMENU_MENU_VALUE] - if not colDB then return end - local r, g, b, a - if item then - local pv = ColorPickerFrame.previousValues - r, g, b, a = pv.r, pv.g, pv.b, 1 - pv.opacity - else - r, g, b = ColorPickerFrame:GetColorRGB() - a = 1 - OpacitySliderFrame:GetValue() - end - colDB.r, colDB.g, colDB.b, colDB.a = r, g, b, a - if _G[self:GetName()].doUpdate then _G[self:GetName()].doUpdate(bOpt) end - end - self.info.hasColorSwatch = true - self.info.hasOpacity = 1 - self.info.r, self.info.g, self.info.b, self.info.opacity = db.r, db.g, db.b, 1 - db.a - self.info.swatchFunc = swatchFunc or SetColor - self.info.opacityFunc = opacityFunc or SetColor - self.info.cancelFunc = cancelFunc or SetColor - self.info.value = value - self.info.func = func or UIDropDownMenuButton_OpenColorPicker - AddButton(self, lvl, text, nil) -end - ---[[ - lib:AddTitle - lvl - menu level 1,2,3 etc... - text - name of the menu item ---]] - -local function AddTitle(self, lvl, text) - if not lvl then return end - if not text then return end - self.info.isTitle = true - self.info.notCheckable = true - AddButton(self, lvl, text) -end - ---[[ - lib:AddCloseButton - lvl - menu level 1,2,3 etc... - text - name of the menu item ---]] - -local function AddCloseButton(self, lvl, text) - if not lvl then return end - if not text then return end - self.info.notCheckable = true - self.info.func = function() CloseDropDownMenus() end - AddButton(self, lvl, text) -end - ---[[ - lib:New - selfName - name of the dropdown menu - db - database for the dropdown menu to use ---]] - -function lib:New(selfName, db) - if not selfName then assert(false, "LibXMenu-1.0: Error, DropDown requires a name") return end - if not db then assert(false, "LibXMenu-1.0: Error, DropDown requires a Database.") return end - --Note: If you don't want to use a database, just use an empty table {}. - --Ex. local dd1 = LibStub('LibXMenu-1.0'):New("DropDownName", {}) - - local dd = CreateFrame("Frame", selfName, UIParent) - dd.db = db - dd.info = {} - dd.displayMode = "MENU" - dd.AddButton = AddButton - dd.AddToggle = AddToggle - dd.AddList = AddList - dd.AddSelect = AddSelect - dd.AddColor = AddColor - dd.AddTitle = AddTitle - dd.AddCloseButton = AddCloseButton - dd.doUpdate = function() end - return dd -end