diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..427eb54 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,43 @@ +on: + push: + branches: + - "master" + +name: Generate Release With Zip Asset + +jobs: + build: + name: Upload Release Asset + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Get current time + uses: srfrnk/current-time@master + id: current-time + with: + format: YYYY.MM.DD.HH.mm + - name: Zip project + run: | + rsync -a "$PWD" . + zip -r Mappy.${{ steps.current-time.outputs.formattedTime }}.zip `basename "$PWD"` + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ steps.current-time.outputs.formattedTime }} + release_name: v${{ steps.current-time.outputs.formattedTime }} + draft: false + prerelease: false + - name: Upload Release Asset + id: upload-release-asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./Mappy.${{ steps.current-time.outputs.formattedTime }}.zip + asset_name: Mappy.${{ steps.current-time.outputs.formattedTime }}.zip + asset_content_type: application/zip diff --git a/Libraries/LibDropdown-1.0.lua b/Libraries/LibDropdown-1.0.lua old mode 100755 new mode 100644 index ca5360d..c85be53 --- a/Libraries/LibDropdown-1.0.lua +++ b/Libraries/LibDropdown-1.0.lua @@ -1,1203 +1,1203 @@ --- This library has been modified and so I've changed the major name to use an MC suffix. Changes are: --- * Added support for a color parameter on items to tint the text --- * Added an optional cleanup function to menus so their owner can be notified if they're released --- * Added support for items with an icon - -local MAJOR = "LibDropdownMC-1.0" -local MINOR = 2 - -local lib = LibStub:NewLibrary(MAJOR, MINOR) -if not lib then return end - -local assert = assert -local ipairs = ipairs -local math = math -local max = max -local min = min -local next = next -local pairs = pairs -local select = select -local table = table -local setmetatable = setmetatable -local tinsert = tinsert -local tostring = tostring -local tremove = tremove -local type = type -local wipe = wipe - -local CreateFrame = CreateFrame -local PlaySound = PlaySound -local ShowUIPanel = ShowUIPanel -local GetMouseFocus = GetMouseFocus -local UISpecialFrames = UISpecialFrames - -local ChatFrame1 = ChatFrame1 -local ColorPickerFrame = ColorPickerFrame -local GameTooltip = GameTooltip - -local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor - -local HIGHLIGHT_FONT_COLOR = HIGHLIGHT_FONT_COLOR -local NORMAL_FONT_COLOR = NORMAL_FONT_COLOR - -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, Refresh, GetRoot, SetChecked, HideRecursive, 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(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) - 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() - local 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("") - - 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 - - if f.cleanup then - f.cleanup() - 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 - - -- Tint with a color (mundocani) - if v.color then - b.text:SetTextColor(v.color.r, v.color.g, v.color.b, v.color.a) - end - 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 - if self.data.icon then - self.swatch:Show() - self.swatch.tex:Hide() - self.swatch:SetNormalTexture(self.data.icon) - else - self.swatch:Hide() - self.swatch.tex:Show() - self.swatch:SetNormalTexture([[Interface\ChatFrame\ChatFrameColorSwatch]]) - 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 testlibdropdown() - LibStub("LibDropdown-1.0"):OpenAce3Menu(t) -end]] - -WorldFrame:HookScript("OnMouseDown", function() - if openMenu then - openMenu = openMenu:Release() - end -end) +-- This library has been modified and so I've changed the major name to use an MC suffix. Changes are: +-- * Added support for a color parameter on items to tint the text +-- * Added an optional cleanup function to menus so their owner can be notified if they're released +-- * Added support for items with an icon + +local MAJOR = "LibDropdownMC-1.0" +local MINOR = 2 + +local lib = LibStub:NewLibrary(MAJOR, MINOR) +if not lib then return end + +local assert = assert +local ipairs = ipairs +local math = math +local max = max +local min = min +local next = next +local pairs = pairs +local select = select +local table = table +local setmetatable = setmetatable +local tinsert = tinsert +local tostring = tostring +local tremove = tremove +local type = type +local wipe = wipe + +local CreateFrame = CreateFrame +local PlaySound = PlaySound +local ShowUIPanel = ShowUIPanel +local GetMouseFocus = GetMouseFocus +local UISpecialFrames = UISpecialFrames + +local ChatFrame1 = ChatFrame1 +local ColorPickerFrame = ColorPickerFrame +local GameTooltip = GameTooltip + +local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor + +local HIGHLIGHT_FONT_COLOR = HIGHLIGHT_FONT_COLOR +local NORMAL_FONT_COLOR = NORMAL_FONT_COLOR + +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, Refresh, GetRoot, SetChecked, HideRecursive, 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(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) + 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() + local 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("") + + 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 + + if f.cleanup then + f.cleanup() + 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 + + -- Tint with a color (mundocani) + if v.color then + b.text:SetTextColor(v.color.r, v.color.g, v.color.b, v.color.a) + end + 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 + if self.data.icon then + self.swatch:Show() + self.swatch.tex:Hide() + self.swatch:SetNormalTexture(self.data.icon) + else + self.swatch:Hide() + self.swatch.tex:Show() + self.swatch:SetNormalTexture([[Interface\ChatFrame\ChatFrameColorSwatch]]) + 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 testlibdropdown() + LibStub("LibDropdown-1.0"):OpenAce3Menu(t) +end]] + +WorldFrame:HookScript("OnMouseDown", function() + if openMenu then + openMenu = openMenu:Release() + end +end) diff --git a/Libraries/LibStub.lua b/Libraries/LibStub.lua old mode 100755 new mode 100644 index cfc97de..0a41ac0 --- a/Libraries/LibStub.lua +++ b/Libraries/LibStub.lua @@ -1,30 +1,30 @@ --- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info --- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! -local LibStub = _G[LIBSTUB_MAJOR] - -if not LibStub or LibStub.minor < LIBSTUB_MINOR then - LibStub = LibStub or {libs = {}, minors = {} } - _G[LIBSTUB_MAJOR] = LibStub - LibStub.minor = LIBSTUB_MINOR - - function LibStub:NewLibrary(major, minor) - assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") - minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") - - local oldminor = self.minors[major] - if oldminor and oldminor >= minor then return nil end - self.minors[major], self.libs[major] = minor, self.libs[major] or {} - return self.libs[major], oldminor - end - - function LibStub:GetLibrary(major, silent) - if not self.libs[major] and not silent then - error(("Cannot find a library instance of %q."):format(tostring(major)), 2) - end - return self.libs[major], self.minors[major] - end - - function LibStub:IterateLibraries() return pairs(self.libs) end - setmetatable(LibStub, { __call = LibStub.GetLibrary }) -end +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! +local LibStub = _G[LIBSTUB_MAJOR] + +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end diff --git a/Libraries/MC2AddonLib b/Libraries/MC2AddonLib deleted file mode 160000 index bc94dee..0000000 --- a/Libraries/MC2AddonLib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bc94dee545babee55d9889f88d052af6f6e40422 diff --git a/Libraries/MC2AddonLib/LICENSE b/Libraries/MC2AddonLib/LICENSE new file mode 100644 index 0000000..0e658b9 --- /dev/null +++ b/Libraries/MC2AddonLib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 John Stephen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Libraries/MC2AddonLib/MC2AddonLib.lua b/Libraries/MC2AddonLib/MC2AddonLib.lua new file mode 100644 index 0000000..0ad58dd --- /dev/null +++ b/Libraries/MC2AddonLib/MC2AddonLib.lua @@ -0,0 +1,178 @@ +---------------------------------------- +local AddonName, Addon = ... +Addon.AddonPath = "Interface\\Addons\\"..AddonName.."\\" +---------------------------------------- + +function Addon:new(methodTable, ...) + local object + + if methodTable.New then + object = methodTable:New(...) + else + object = {} + end + + self:initObject(object, methodTable, ...) + + return object +end + +function Addon:initObject(object, class, ...) + assert(type(class) == "table", "table expected") + + local methodTable = class + if methodTable._class_meta then + methodTable = methodTable._class_meta + end + + if methodTable.__index then + setmetatable(object, methodTable) + + if object.construct then + object:construct(...) + elseif object.Construct then + object:Construct(...) + end + else + for k, v in pairs(self.Object) do + object[k] = v + end + + object:inheritOver(methodTable, ...) + end + + return object +end + +function Addon:duplicateTable(table, recurse, destTable) + if not table then + return nil + end + + local result + + if destTable then + assert(type(destTable) == "table", "table expected for destTable") + result = destTable + else + result = {} + end + + if recurse then + for key, value in pairs(table) do + if type(value) == "table" then + result[key] = self:duplicateTable(value, true) + else + result[key] = value + end + end + else + self:copyTable(result, table) + end + + return result +end + +function Addon:copyTable(destTable, table) + for key, value in pairs(table) do + destTable[key] = value + end +end + +function Addon:eraseTable(table) + return wipe(table) +end + +function Addon:recycleTable(table) + if table then + return wipe(table) + else + return {} + end +end + +function Addon:hookScript(frame, scriptID, func) + if not frame:GetScript(scriptID) then + frame:SetScript(scriptID, func) + else + frame:HookScript(scriptID, func) + end +end + +function Addon:newClass(inherits) + local class = {} + setmetatable(class, inherits or Addon.ObjectMetaTable) + + local classMeta = { + __index = class + } + + class._class_meta = classMeta + + return class +end + +-- Old name compatibility +Addon.New = Addon.new +Addon.DuplicateTable = Addon.duplicateTable +Addon.CopyTable = Addon.copyTable +Addon.EraseTable = Addon.eraseTable +Addon.RecycleTable = Addon.recycleTable +Addon.HookScript = Addon.hookScript + +---------------------------------------- +Addon.Object = {} +Addon.ObjectMetaTable = {__index = Addon.Object} +---------------------------------------- + +function Addon.Object:inheritOver(methodTable, ...) + for key, value in pairs(methodTable) do + if self[key] then + if not self.inherited then + self.inherited = {} + self.Inherited = self.inherited + end + + self.inherited[key] = self[key] + end + + self[key] = value + end + + if methodTable.construct then + methodTable.construct(self, ...) + elseif methodTable.Construct then + methodTable.Construct(self, ...) + end +end + +function Addon.Object:inherit(methodTable, ...) + for key, value in pairs(methodTable) do + if self[key] then + if not self.inherited then + self.inherited = {} + self.Inherited = self.inherited + end + + if not self.inherited[key] then + self.inherited[key] = value + end + else + self[key] = value + end + end + + if methodTable.construct then + methodTable.construct(self, ...) + elseif methodTable.Construct then + methodTable.Construct(self, ...) + end +end + +Addon.Object.Inherit = Addon.Object.inherit +Addon.Object.InheritOver = Addon.Object.inheritOver + +Addon.Inherit = Addon.Object.Inherit +Addon.InheritOver = Addon.Object.InheritOver +Addon.inherit = Addon.Object.inherit +Addon.inheritOver = Addon.Object.inheritOver diff --git a/Libraries/MC2DebugLib b/Libraries/MC2DebugLib deleted file mode 160000 index 48caa47..0000000 --- a/Libraries/MC2DebugLib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 48caa476753157c6ef2d0db216fff30c16905cb3 diff --git a/Libraries/MC2DebugLib/LICENSE b/Libraries/MC2DebugLib/LICENSE new file mode 100644 index 0000000..0e658b9 --- /dev/null +++ b/Libraries/MC2DebugLib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 John Stephen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Libraries/MC2DebugLib/MC2DebugLib.lua b/Libraries/MC2DebugLib/MC2DebugLib.lua new file mode 100644 index 0000000..52c909b --- /dev/null +++ b/Libraries/MC2DebugLib/MC2DebugLib.lua @@ -0,0 +1,482 @@ +local AddonName, Addon = ... +local _ + +Addon.DebugLib = +{ + Version = 1, +} + +if not Addon.DebugColorCode then + Addon.DebugColorCode = GREEN_FONT_COLOR_CODE +end + +if not tern then + function tern(a, b, c) + if a then return b else return c end + end +end + +function Addon.DebugLib:Initialize() + if self.Initialized then + return + end + + self.Initialized = true + + hooksecurefunc( + "ChatFrame_ConfigEventHandler", + function (event) + if event == "UPDATE_CHAT_WINDOWS" + and not self.DebugFrame then + self:FindDebugFrame() + end + end) + + self:FindDebugFrame() +end + +function Addon.DebugLib:FindDebugFrame() + if self.DebugFrame then + return + end + + for vChatIndex = 1, NUM_CHAT_WINDOWS do + local vChatFrame = _G["ChatFrame"..vChatIndex] + + if vChatFrame + and (vChatFrame:IsVisible() or vChatFrame.isDocked) then + local vTab = _G["ChatFrame"..vChatIndex.."Tab"] + local vName = vTab:GetText() + + if vName == "Debug" then + self.DebugFrame = vChatFrame + + if self.DebugFrame:GetMaxLines() < 1000 then + self.DebugFrame:SetMaxLines(1000) + end + + self.DebugFrame:SetFading(false) + self.DebugFrame:SetMaxResize(1200, 1000) + end + end + end + + if self.DebugFrame then + Addon:NoteMessage("Found debugging chat frame") + end +end + +function Addon.DebugLib:ClearDebugLog() + if not self.Initialized then + self:Initialize() + end + + if not self.DebugFrame then + return + end + + self.DebugFrame:Clear() +end + +function Addon.DebugLib:AddDebugMessage(pPrefix, pMessage, ...) + if not self.Initialized then + self:Initialize() + end + + local vMessage = (pPrefix or "")..Addon.DebugColorCode..string.format("[%s] ", AddonName)..FONT_COLOR_CODE_CLOSE..HIGHLIGHT_FONT_COLOR_CODE..pMessage..FONT_COLOR_CODE_CLOSE + + if true then -- set to false to diagnose debug message problems + if select("#", ...) > 0 then + if type(select(1, ...)) == "table" then + vMessage = string.gsub(vMessage, "%$(%w+)", ...) + else + vMessage = string.format(vMessage, ...) + end + end + else + local vSucceeded + + if select("#", ...) > 0 then + if type(select(1, ...)) == "table" then + vSucceeded, vMessage = pcall(string.gsub, vMessage, "%$(%w+)", ...) + else + vSucceeded, vMessage = pcall(string.format, vMessage, ...) + end + end + end + + if self.DebugFrame then + self.DebugFrame:AddMessage(vMessage) + + local vTabFlash = _G[self.DebugFrame:GetName().."TabFlash"] + + vTabFlash:Show() + --UIFrameFlash(vTabFlash, 0.25, 0.25, 60, nil, 0.5, 0.5) + end + + return vMessage +end + +function Addon:DebugMessage(pMessage, ...) + if not self.DebugLib.Initialized then + self.DebugLib:Initialize() + end + + if not self.DebugLib.DebugFrame then + return + end + + self.DebugLib:AddDebugMessage(NORMAL_FONT_COLOR_CODE.."[DEBUG] "..FONT_COLOR_CODE_CLOSE, pMessage, ...) +end + +function Addon:TestMessage(pMessage, ...) + local vMessage = self.DebugLib:AddDebugMessage(GREEN_FONT_COLOR_CODE.."[ TEST] "..FONT_COLOR_CODE_CLOSE, pMessage, ...) + DEFAULT_CHAT_FRAME:AddMessage(vMessage) +end + +function Addon:ErrorMessage(pMessage, ...) + local vMessage = self.DebugLib:AddDebugMessage(RED_FONT_COLOR_CODE.."[ERROR] "..FONT_COLOR_CODE_CLOSE, pMessage, ...) + DEFAULT_CHAT_FRAME:AddMessage(vMessage) +end + +function Addon:NoteMessage(pMessage, ...) + local vMessage = self.DebugLib:AddDebugMessage("", pMessage, ...) + DEFAULT_CHAT_FRAME:AddMessage(vMessage) +end + +function Addon:DebugTable(pValue, pValuePath, pMaxDepth, pMode) + if not pValuePath then + pValuePath = "table" + end + + if not pValue then + self:DebugMessage(pValuePath.." = nil") + return + end + + local vType = type(pValue) + + if vType == "number" then + self:DebugMessage(pValuePath.." = "..pValue) + elseif vType == "string" then + self:DebugMessage(pValuePath.." = \""..pValue.."\"") + elseif vType == "boolean" then + if pValue then + self:DebugMessage(pValuePath.." = true") + else + self:DebugMessage(pValuePath.." = false") + end + elseif vType == "table" then + local vMaxDepth + + if pMaxDepth then + vMaxDepth = pMaxDepth + else + vMaxDepth = 5 + end + + if vMaxDepth == 0 then + self:DebugMessage(pValuePath.." = {...}") + else + local vFoundElement = false + + for vIndex, vElement in pairs(pValue) do + local vValuePath + + if not vFoundElement then + vValuePath = pValuePath + elseif string.sub(pValuePath, 1, 10) == "|cff888888" then + vValuePath = string.gsub(pValuePath, "|cffffffff", "") + else + vValuePath = "|cff888888"..string.gsub(pValuePath, "|cffffffff", "") + end + + if type(vIndex) ~= "string" then + vValuePath = vValuePath.."|cffffffff["..tostring(vIndex).."]" + else + vValuePath = vValuePath.."|cffffffff."..vIndex + end + + self:DebugTable(vElement, vValuePath, vMaxDepth - 1, pMode) + + vFoundElement = true + end + + if not vFoundElement then + self:DebugMessage(pValuePath.." = {}") + end + end + elseif vType == "function" then + if pMode ~= "NO_FUNCTIONS" then + self:DebugMessage(pValuePath.." "..vType) + end + else + self:DebugMessage(pValuePath.." "..vType) + end +end + +function Addon:DebugStack(pPrefix, pDepth) + local vCallStack = self.DebugLib:GetCallStack(pPrefix, pDepth, 1) + + for vIndex, vMessage in ipairs(vCallStack) do + self:DebugMessage(vMessage) + end +end + +function Addon:ErrorStack(pPrefix, pDepth) + local vCallStack = self.DebugLib:GetCallStack(pPrefix, pDepth, 1) + + for vIndex, vMessage in ipairs(vCallStack) do + self:ErrorMessage(vMessage) + end +end + +function Addon:DebugMark() + self:DebugMessage("————————————————————————————————————————") +end + +function Addon.DebugLib:ReduceAddonPath(pPath) + return string.gsub(pPath, "^Interface\\AddOns\\[^\\]*\\", "") +end + +function Addon.DebugLib:GetCallStack(pPrefix, pDepth, pDepthOffset) + local vCallStack = {} + + if not pPrefix then + pPrefix = " " + end + + if not pDepth then + pDepth = 18 + end + + local vStackString = debugstack((pDepthOffset or 0) + 2, pDepth, 0) + + for vMessageLine in string.gmatch(vStackString, "(.-)\n") do + --table.insert(vCallStack, pPrefix.."LINE: "..vMessageLine) + + local _, _, vFile, vLine, vFunction = string.find(vMessageLine, "([%w%.]+):(%d+): in function .(.*)'") + + if not vFunction then + _, _, vFunction, vLine, vFile = string.find(vMessageLine, "%[string \"(.*)\"%]:(%d+): in (.*)") + end + + if not vFunction then + _, _, vFile, vLine, vFunctionFile, vFunctionLine = string.find(vMessageLine, "([^:]+):(%d+): in function <([^:]+):(%d+)>") + + if vFunctionLine then + vFunctionFile = self:ReduceAddonPath(vFunctionFile) + vFunction = vFunctionFile..", "..vFunctionLine + end + end + + if not vFunction then + _, _, vFunction = string.find(vMessageLine, "(tail call.*)") + end + + if not vFunction then + _, _, _, vFunction = string.find(vMessageLine, "(%[C%]): in function .(.*)'") + + if vFunction then + vFunction = "[C] "..vFunction + vFile = nil + vLine = nil + end + end + + if vFunction then + if vFile then + if not vLine then + vLine = 0 + end + + vFile = self:ReduceAddonPath(vFile) + + table.insert(vCallStack, pPrefix..vFile..", "..vLine..": "..vFunction) + else + table.insert(vCallStack, pPrefix..vFunction) + end + else + table.insert(vCallStack, pPrefix.."Unknown function: "..vMessageLine) + end + end + + return vCallStack +end + +function Addon.DebugLib:NewBuckets(pInterval) + local vBuckets = + { + Interval = pInterval, + BucketStartTime = GetTime(), + BucketIndex = 1, + NumBuckets = math.floor(pInterval), + Buckets = {[1] = {Value = 0, Time = 0}}, + + AddSample = self.BucketsAddSample, + GetValue = self.BucketsGetValue, + } + + return vBuckets +end + +function Addon.DebugLib:BucketsAddSample(pValue, pTime) + local vBucket = self.Buckets[self.BucketIndex] + + vBucket.Value = vBucket.Value + pValue + + local vElapsed = pTime - self.BucketStartTime + + if vElapsed > 1 then + vBucket.Time = vElapsed + + self.BucketStartTime = pTime + self.BucketIndex = self.BucketIndex + 1 + + if self.BucketIndex > self.NumBuckets then + self.BucketIndex = 1 + end + + vBucket = self.Buckets[self.BucketIndex] + + if not vBucket then + vBucket = {} + self.Buckets[self.BucketIndex] = vBucket + end + + vBucket.Value = 0 + vBucket.Time = 0 + end +end + +function Addon.DebugLib:BucketsGetValue() + local vTotalElapsed = 0 + local vTotalValue = 0 + + for vIndex, vBucket in ipairs(self.Buckets) do + if vBucket.Time > 0 then + vTotalElapsed = vTotalElapsed + vBucket.Time + vTotalValue = vTotalValue + vBucket.Value + end + end + + if vTotalElapsed == 0 then + return 0, 0 + end + + return vTotalValue / vTotalElapsed, vTotalElapsed +end + +function Addon.DebugLib:NewPerfMonitor(pLabel) + local vPerfMonitor = + { + Label = pLabel, + CPUBuckets = self:NewBuckets(10), + MemBuckets = self:NewBuckets(10), + + FunctionEnter = self.PerfMonitorFunctionEnter, + FunctionExit = self.PerfMonitorFunctionExit, + DumpValue = self.PerfMonitorDumpValue, + } + + return vPerfMonitor +end + +function Addon.DebugLib:PerfMonitorFunctionEnter(pTime) + self.StartTime = pTime + self.StartMem = gcinfo() +end + +function Addon.DebugLib:PerfMonitorFunctionExit(pTime) + local vEndMem = gcinfo() + + self.CPUBuckets:AddSample(pTime - self.StartTime, pTime) + self.MemBuckets:AddSample(vEndMem - self.StartMem, pTime) +end + +function Addon.DebugLib:PerfMonitorDumpValue() + local vCPUTime, vTotalTime = self.CPUBuckets:GetValue() + local vMemRate = self.MemBuckets:GetValue() + local vCPUPercent + + if vTotalTime > 0 then + vCPUPercent = 100 * vCPUTime / vTotalTime + else + vCPUPercent = 0 + end + + self:DebugMessage("%s: CPU: %.1f%% Mem: %dKB/sec", self.Label, vCPUPercent, vMemRate) +end + +function Addon.DebugLib.BoolToString(pValue) + if pValue then + return "true" + else + return "false" + end +end + +function Addon.DebugLib:ShowFrameStatus(pFrame, pPrefix) + self:DebugMessage("%sVisible: %s Protected: %s Width: %d Height: %d Level: %d", pPrefix or pFrame:GetName(), self.BoolToString(pFrame:IsVisible()), self.BoolToString(pFrame:IsProtected()), pFrame:GetWidth(), pFrame:GetHeight(), pFrame:GetFrameLevel()) +end + +function Addon.DebugLib:ShowParentTree(pFrame, pPrefix) + if not pPrefix then + pPrefix = "" + end + + local vParent = pFrame:GetParent() + + if vParent then + self:DebugMessage(pPrefix.."Parent: "..vParent:GetName()) + + if vParent ~= UIParent then + self:ShowFrameStatus(vParent, pPrefix.." ") + self:ShowParentTree(vParent, pPrefix.." ") + end + end +end + +function Addon.DebugLib:ShowAnchorTree(pFrame, pPrefix) + if not pPrefix then + pPrefix = "" + end + + local vIndex = 1 + local vDidAnchor = {} + + local vIndex = 1 + + while true do + local vPoint, vRelativeTo, vRelativePoint, vOffsetX, vOffsetY = pFrame:GetPoint(vIndex) + + if not vPoint + or not vRelativeTo then + break + end + + self:DebugMessage("%sAnchor %d: %s, %s, %s, %d, %d", pPrefix, vIndex, vPoint, vRelativeTo:GetName(), vRelativePoint, vOffsetX, vOffsetY) + + if vRelativeTo ~= UIParent + and not vDidAnchor[vRelativeTo] then + vDidAnchor[vRelativeTo] = true + + self:DebugMessage(pPrefix.."RelativeTo: "..vRelativeTo:GetName()) + self:ShowFrameStatus(vRelativeTo, pPrefix.." ") + self:ShowAnchorTree(vRelativeTo, pPrefix.." ") + end + + vIndex = vIndex + 1 + end + + if vIndex == 1 then + self:DebugMessage(pPrefix.." No Anchors") + end +end + +function Addon.DebugLib:ShowFrameTree(pFrame) + self:DebugMessage("ShowFrameTree: "..pFrame:GetName()) + self:ShowFrameStatus(pFrame, " ") + self:ShowParentTree(pFrame, " ") + self:ShowAnchorTree(pFrame, " ") +end diff --git a/Libraries/MC2EventLib b/Libraries/MC2EventLib deleted file mode 160000 index cd82f5d..0000000 --- a/Libraries/MC2EventLib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cd82f5d135438bc6c73b73a13bc5161d3829bd3f diff --git a/Libraries/MC2EventLib/LICENSE b/Libraries/MC2EventLib/LICENSE new file mode 100644 index 0000000..0e658b9 --- /dev/null +++ b/Libraries/MC2EventLib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 John Stephen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Libraries/MC2EventLib/MC2EventLib.lua b/Libraries/MC2EventLib/MC2EventLib.lua new file mode 100644 index 0000000..24a5749 --- /dev/null +++ b/Libraries/MC2EventLib/MC2EventLib.lua @@ -0,0 +1,171 @@ +local _, Addon = ... + +Addon.EventLib = +{ + Version = 2, + Events = {}, + Iterators = {}, + EventFrame = CreateFrame("FRAME", nil, UIParent), +} + +function Addon.EventLib:DispatchEvent(eventID, ...) + local event = self.Events[eventID] + if not event then + return + end + + local iterator = self.Iterators[eventID] + if iterator then + return + end + + -- Addon:DebugMessage("Dispatching event %s", eventID) + + local handlers = event.Handlers + + iterator = {Index = 1, Count = #handlers} + self.Iterators[eventID] = iterator + while iterator.Index <= iterator.Count do + local handler = handlers[iterator.Index] + + if handler.Blind then + if handler.RefParam ~= nil then + handler.Function(handler.RefParam, ...) + else + handler.Function(...) + end + else + if handler.RefParam ~= nil then + handler.Function(handler.RefParam, eventID, ...) + else + handler.Function(eventID, ...) + end + end + + iterator.Index = iterator.Index + 1 + end + + self.Iterators[eventID] = nil + + if self.PerfMonitor then + local endTime = GetTime() + + self.PerfMonitor:FunctionExit(endTime) + + if not self.LastDumpTime + or endTime - self.LastDumpTime > 2 then + self.LastDumpTime = endTime + + self.PerfMonitor:DumpValue() + end + end +end + +function Addon.EventLib:RegisterCustomEvent(eventID, handlerFunction, refParam, blind) + self:RegisterEvent(eventID, handlerFunction, refParam, blind, true) +end + +function Addon.EventLib:RegisterEvent(eventID, handlerFunction, refParam, blind, isCustomEvent) + if not handlerFunction then + error(string.format("Attempted to register a nil function pointer for event %s", eventID or "unknown")) + end + + local isRegistered, index = self:EventIsRegistered(eventID, handlerFunction, refParam) + + if isRegistered then + error(string.format("Attempted to register a handler twice for %s", eventID)) + end + + local event = self.Events[eventID] + if not event then + event = {} + event.IsCustomEvent = isCustomEvent + event.Handlers = {} + + self.Events[eventID] = event + + if self.EventFrame and not isCustomEvent then + self.EventFrame:RegisterEvent(eventID) + end + end + + local handler = + { + Function = handlerFunction, + RefParam = refParam, + Blind = blind, + IsCustomEvent = isCustomEvent + } + table.insert(event.Handlers, handler) +end + +function Addon.EventLib:EventIsRegistered(eventID, handlerFunction, refParam) + local event = self.Events[eventID] + if not event then + return false + end + + for index, handler in ipairs(event.Handlers) do + if (not handlerFunction or handler.Function == handlerFunction) + and (not refParam or handler.RefParam == refParam) then + return true, index + end + end + + return false +end + +function Addon.EventLib:UnregisterCustomEvent(eventID, handlerFunction, refParam) + self:UnregisterEvent(eventID, handlerFunction, refParam) +end + +function Addon.EventLib:UnregisterEvent(eventID, handlerFunction, refParam) + local isRegistered, index = self:EventIsRegistered(eventID, handlerFunction, refParam) + if not isRegistered then + return + end + + local event = self.Events[eventID] + local handlers = event.Handlers + + table.remove(handlers, index) + + if #handlers == 0 then + self.Events[eventID] = nil + + if self.EventFrame and not event.IsCustomEvent then + self.EventFrame:UnregisterEvent(eventID) + end + end + + local iterator = self.Iterators[eventID] + + if iterator then + if index <= iterator.Index then + iterator.Index = iterator.Index - 1 + end + + iterator.Count = iterator.Count - 1 + end +end + +function Addon.EventLib:UnregisterAllEvents(handlerFunction, refParam) + for eventID, event in pairs(self.Events) do + self:UnregisterEvent(eventID, handlerFunction, refParam) + end +end + +Addon.EventLib.EventFrame.EventLib = Addon.EventLib + +Addon.EventLib.HardwareEvents = +{ + ["TRADE_SKILL_SHOW"] = true, + ["TRADE_SKILL_CLOSE"] = true, +} + +Addon.EventLib.EventFrame:SetScript("OnEvent", function (frame, eventID, ...) + local hadHardwareEvent = Addon.HasHWEvent + Addon.HasHWEvent = Addon.HasHWEvent or Addon.EventLib.HardwareEvents[eventID] + frame.EventLib:DispatchEvent(eventID, ...) + Addon.HasHWEvent = hadHardwareEvent +end) diff --git a/Libraries/MC2SchedulerLib b/Libraries/MC2SchedulerLib deleted file mode 160000 index c4d4be5..0000000 --- a/Libraries/MC2SchedulerLib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c4d4be5baacd7a8974b48804421d724d2566cf17 diff --git a/Libraries/MC2SchedulerLib/LICENSE b/Libraries/MC2SchedulerLib/LICENSE new file mode 100644 index 0000000..0e658b9 --- /dev/null +++ b/Libraries/MC2SchedulerLib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 John Stephen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Libraries/MC2SchedulerLib/MC2SchedulerLib.lua b/Libraries/MC2SchedulerLib/MC2SchedulerLib.lua new file mode 100644 index 0000000..b0a4d11 --- /dev/null +++ b/Libraries/MC2SchedulerLib/MC2SchedulerLib.lua @@ -0,0 +1,273 @@ +local _, Addon = ... + +---------------------------------------- +Addon.SchedulerLib = +---------------------------------------- +{ + Version = 1, + + EventFrame = CreateFrame("Frame", nil, UIParent), + + HasTasks = false, + NeedSorted = false, + Tasks = {}, + + IteratorIndex = nil, + IteratorCount = nil, +} + +Addon.SchedulerLib.EventFrame.SchedulerLib = Addon.SchedulerLib +Addon.SchedulerLib.EventFrame:SetScript("OnUpdate", function (self, elapsed) self.SchedulerLib:OnUpdate(elapsed) end) + +function Addon.SchedulerLib:ScheduleTask(pDelay, pFunction, pParam, pTaskName) + if type(pFunction) ~= "function" then + error("Attempt to schedule an invalid function (passed "..type(pFunction).." instead)") + end + + local vTask = + { + Time = GetTime() + pDelay, + Function = pFunction, + Param = pParam, + Name = pTaskName, + } + + self:InsertTask(vTask) +end + +function Addon.SchedulerLib:RescheduleTask(pDelay, pFunction, pParam, pTaskName) + self:UnscheduleTask(pFunction, pParam) + self:ScheduleTask(pDelay, pFunction, pParam, pTaskName) +end + +function Addon.SchedulerLib:ScheduleUniqueTask(pDelay, pFunction, pParam, pTaskName) + if self:FindTask(pFunction, pParam) then + return + end + + self:ScheduleTask(pDelay, pFunction, pParam, pTaskName) +end + +function Addon.SchedulerLib:ScheduleRepeatingTask(pInterval, pFunction, pParam, pInitialDelay, pTaskName) + local vTask = + { + Interval = pInterval, + Function = pFunction, + Param = pParam, + Name = pTaskName, + } + + if pInitialDelay then + vTask.Time = GetTime() + pInitialDelay + else + vTask.Time = GetTime() + pInterval + end + + self:InsertTask(vTask) +end + +function Addon.SchedulerLib:ScheduleUniqueRepeatingTask(pInterval, pFunction, pParam, pInitialDelay, pTaskName) + if self:FindTask(pFunction, pParam) then + return + end + + self:ScheduleRepeatingTask(pInterval, pFunction, pParam, pInitialDelay, pTaskName) +end + +function Addon.SchedulerLib:SetTaskInterval(pInterval, pFunction, pParam) + local vTask, vIndex = self:FindTask(pFunction, pParam) + + if not vTask then + return + end + + if vTask.Interval == pInterval then + return + end + + if vTask.Interval then + vTask.Time = vTask.Time - vTask.Interval + end + + vTask.Interval = pInterval + + if vTask.Interval then + vTask.Time = vTask.Time + vTask.Interval + end + + self.NeedSorted = true +end + +function Addon.SchedulerLib:SetTaskDelay(pDelay, pFunction, pParam) + local vTask, vIndex = self:FindTask(pFunction, pParam) + + if not vTask then + return + end + + vTask.Time = GetTime() + pDelay + + self.NeedSorted = true +end + +function Addon.SchedulerLib:InsertTask(pTask) + if not pTask then + error("Inserting a nil task") + end + + table.insert(self.Tasks, pTask) + + self.NeedSorted = true + + if not self.HasTasks then + self.EventFrame:Show() + self.HasTasks = true + end +end + +function Addon.SchedulerLib:UnscheduleAllTasks(pFunction, pParam) + while self:UnscheduleTask(pFunction, pParam) do + end +end + +function Addon.SchedulerLib:UnscheduleTask(pFunction, pParam) + local vTask, vIndex = self:FindTask(pFunction, pParam) + + if not vTask then + return false + end + + table.remove(self.Tasks, vIndex) + + if self.IteratorIndex + and vIndex < self.IteratorIndex then + self.IteratorIndex = self.IteratorIndex - 1 + end + + if #self.Tasks == 0 then + self.HasTasks = false + self.EventFrame:Hide() + end + + return true +end + +function Addon.SchedulerLib:FindTask(pFunction, pParam) + for vIndex, vTask in ipairs(self.Tasks) do + if (pFunction == nil or vTask.Function == pFunction) + and (pParam == nil or vTask.Param == pParam) then + return vTask, vIndex + end + end -- for +end + +function Addon.SchedulerLib:OnUpdate(pElapsed) + -- Prevent from re-entering + + if self.OnUpdateRunning then + -- self:TestMessage("OnUpdate already running") + return + end + + self.OnUpdateRunning = true + + for vIndex, vTask in ipairs(self.Tasks) do + vTask.DidRun = false + end + + self:OnUpdate2(pElapsed) + + self.OnUpdateRunning = false +end + +function Addon.SchedulerLib:OnUpdate2(pElapsed) + local vTime = GetTime() + + if self.PerfMonitor then + self.PerfMonitor:FunctionEnter(vTime) + end + + -- + + if self.NeedSorted then + self.NeedSorted = false + table.sort(self.Tasks, self.CompareTasks) + end + + self.IteratorIndex = 1 + + while self.IteratorIndex <= #self.Tasks do + local vTask = self.Tasks[self.IteratorIndex] + + if not vTask then + Addon:ErrorMessage("nil task at index "..self.IteratorIndex) + table.remove(self.Tasks, self.IteratorIndex) + elseif vTask.DidRun then + -- Ignore it + + self.IteratorIndex = self.IteratorIndex + 1 + else + if vTask.Time > vTime then + break + end + + -- Re-schedule or remove one-shot tasks before calling their function + -- in case the function decides it wants to remove the task too + + if vTask.Interval == nil then + table.remove(self.Tasks, self.IteratorIndex) + + -- Repeat tasks just need a new time calculated + + else + vTask.Time = vTime + vTask.Interval + + if vTask.Interval > 0 then + self.NeedSorted = true + end + + self.IteratorIndex = self.IteratorIndex + 1 + end + + -- Call the function + + -- Addon:DebugMessage("Calling task %s", vTask.Name or "anonymous") + + if not vTask.Disabled then + local vResult, vMessage + + vTask.DidRun = true + + if vTask.Param ~= nil then + vTask.Function(vTask.Param, vTime) + else + vTask.Function(vTime) + end + end + end + end -- while + + self.IteratorIndex = nil + + if #self.Tasks == 0 then + self.HasTasks = false + self.EventFrame:Hide() + end + + if self.PerfMonitor then + local vEndTime = GetTime() + + self.PerfMonitor:FunctionExit(vEndTime) + + if not self.LastDumpTime + or vEndTime - self.LastDumpTime > 2 then + self.LastDumpTime = vEndTime + + self.PerfMonitor:DumpValue() + end + end +end + +function Addon.SchedulerLib.CompareTasks(pTask1, pTask2) + return pTask1.Time < pTask2.Time +end diff --git a/Libraries/MC2UIElementsLib b/Libraries/MC2UIElementsLib deleted file mode 160000 index 5256085..0000000 --- a/Libraries/MC2UIElementsLib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5256085c107e2e90b32b72a1fc720c45d609c90f diff --git a/Libraries/MC2UIElementsLib/LICENSE b/Libraries/MC2UIElementsLib/LICENSE new file mode 100644 index 0000000..0e658b9 --- /dev/null +++ b/Libraries/MC2UIElementsLib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 John Stephen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Libraries/MC2UIElementsLib/MC2UIElementsLib.lua b/Libraries/MC2UIElementsLib/MC2UIElementsLib.lua new file mode 100644 index 0000000..caff376 --- /dev/null +++ b/Libraries/MC2UIElementsLib/MC2UIElementsLib.lua @@ -0,0 +1,2735 @@ +local _, Addon = ... + +Addon.UIElementsLib = +{ + Version = 1, + Addon = Addon, +} + +if not MC2UIElementsLib then + MC2UIElementsLib = {} +end + +if not Addon.UIElementsLibTexturePath then + Addon.UIElementsLibTexturePath = Addon.AddonPath +end + +---------------------------------------- +-- Escape key handling for dialogs +---------------------------------------- + +function Addon.UIElementsLib:BeginDialog(pDialog) + if not self.OpenDialogs then + self.OpenDialogs = {} + + self.OrigStaticPopup_EscapePressed = StaticPopup_EscapePressed + StaticPopup_EscapePressed = function (...) return self:StaticPopup_EscapePressed(...) end + end + + table.insert(self.OpenDialogs, pDialog) +end + +function Addon.UIElementsLib:EndDialog(pDialog) + for vIndex, vDialog in ipairs(self.OpenDialogs) do + if vDialog == pDialog then + table.remove(self.OpenDialogs, vIndex) + return + end + end + + Addon:ErrorMessage("DialogClosed called on an unknown dialog: %s", tostring(pDialog:GetName())) +end + +function Addon.UIElementsLib:StaticPopup_EscapePressed(...) + local vClosed = self.OrigStaticPopup_EscapePressed(...) + local vNumDialogs = #self.OpenDialogs + + for vIndex = 1, vNumDialogs do + local vDialog = self.OpenDialogs[1] + vDialog:Cancel() + vClosed = 1 + end + + return vClosed +end + + +---------------------------------------- +Addon.UIElementsLib._StretchTextures = {} +---------------------------------------- + +function Addon.UIElementsLib._StretchTextures:Construct(pTextureInfo, pFrame, pLayer) + for vName, vInfo in pairs(pTextureInfo) do + local vTexture = pFrame:CreateTexture(nil, pLayer) + + if vInfo.Width then + vTexture:SetWidth(vInfo.Width) + end + + if vInfo.Height then + vTexture:SetHeight(vInfo.Height) + end + + vTexture:SetTexture(vInfo.Path) + vTexture:SetTexCoord(vInfo.Coords.Left, vInfo.Coords.Right, vInfo.Coords.Top, vInfo.Coords.Bottom) + + self[vName] = vTexture + end + + self.TopLeft:SetPoint("TOPLEFT", pFrame, "TOPLEFT") + self.TopRight:SetPoint("TOPRIGHT", pFrame, "TOPRIGHT") + self.BottomLeft:SetPoint("BOTTOMLEFT", pFrame, "BOTTOMLEFT") + self.BottomRight:SetPoint("BOTTOMRIGHT", pFrame, "BOTTOMRIGHT") + + self.TopCenter:SetPoint("TOPLEFT", self.TopLeft, "TOPRIGHT") + self.TopCenter:SetPoint("TOPRIGHT", self.TopRight, "TOPLEFT") + + self.MiddleLeft:SetPoint("TOPLEFT", self.TopLeft, "BOTTOMLEFT") + self.MiddleLeft:SetPoint("BOTTOMLEFT", self.BottomLeft, "TOPLEFT") + + self.MiddleRight:SetPoint("TOPRIGHT", self.TopRight, "BOTTOMRIGHT") + self.MiddleRight:SetPoint("BOTTOMRIGHT", self.BottomRight, "TOPRIGHT") + + self.BottomCenter:SetPoint("BOTTOMLEFT", self.BottomLeft, "BOTTOMRIGHT") + self.BottomCenter:SetPoint("BOTTOMRIGHT", self.BottomRight, "BOTTOMLEFT") + + self.MiddleCenter:SetPoint("TOPLEFT", self.TopLeft, "BOTTOMRIGHT") + self.MiddleCenter:SetPoint("BOTTOMLEFT", self.BottomLeft, "TOPRIGHT") + self.MiddleCenter:SetPoint("TOPRIGHT", self.TopRight, "BOTTOMLEFT") + self.MiddleCenter:SetPoint("BOTTOMRIGHT", self.BottomRight, "TOPLEFT") +end + +---------------------------------------- +if Addon.UIElementsLibTexturePath then +Addon.UIElementsLib._PortaitWindow = {} +---------------------------------------- + +Addon.UIElementsLib._PortaitWindow.BackgroundTextureInfo = +{ + TopLeft = {Width = 100, Height = 100, Path = "Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft", Coords = {Left = 0, Right = 0.390625, Top = 0, Bottom = 0.390625}}, + TopCenter = {Width = 156, Height = 100, Path = "Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft", Coords = {Left = 0.390625, Right = 1, Top = 0, Bottom = 0.390625}}, + TopRight = {Width = 93, Height = 100, Path = "Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight", Coords = {Left = 0, Right = 0.7265625, Top = 0, Bottom = 0.390625}}, + MiddleLeft = {Width = 100, Height = 156, Path = "Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft", Coords = {Left = 0, Right = 0.390625, Top = 0.390625, Bottom = 1}}, + MiddleCenter = {Width = 156, Height = 156, Path = "Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft", Coords = {Left = 0.390625, Right = 1, Top = 0.390625, Bottom = 1}}, + MiddleRight = {Width = 93, Height = 156, Path = "Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight", Coords = {Left = 0, Right = 0.7265625, Top = 0.390625, Bottom = 1}}, + BottomLeft = {Width = 100, Height = 120, Path = Addon.UIElementsLibTexturePath.."Textures\\CalendarFrame-BottomLeft", Coords = {Left = 0, Right = 0.390625, Top = 0, Bottom = 0.9375}}, + BottomCenter = {Width = 156, Height = 120, Path = Addon.UIElementsLibTexturePath.."Textures\\CalendarFrame-BottomLeft", Coords = {Left = 0.390625, Right = 1, Top = 0, Bottom = 0.9375}}, + BottomRight = {Width = 93, Height = 120, Path = Addon.UIElementsLibTexturePath.."Textures\\CalendarFrame-BottomRight", Coords = {Left = 0, Right = 0.7265625, Top = 0, Bottom = 0.9375}}, +} + +function Addon.UIElementsLib._PortaitWindow:New(pTitle, pWidth, pHeight, pName) + return CreateFrame("Frame", pName, UIParent) +end + +function Addon.UIElementsLib._PortaitWindow:Construct(pTitle, pWidth, pHeight, pName) + self:EnableMouse(true) + self:SetMovable(true) + self:SetWidth(pWidth) + self:SetHeight(pHeight) + + self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 0, -104) + + self.BackgroundTextures = Addon:New(Addon.UIElementsLib._StretchTextures, self.BackgroundTextureInfo, self, "BORDER") + + self:SetScript("OnDragStart", function (self, pButton) self:StartMoving() end) + self:SetScript("OnDragStop", function (self) self:StopMovingOrSizing() end) + + self.TitleText = self:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + self.TitleText:SetPoint("TOP", self, "TOP", 17, -18) + self.TitleText:SetText(pTitle) + + self.CloseButton = CreateFrame("Button", nil, self, "UIPanelCloseButton") + self.CloseButton:SetPoint("TOPRIGHT", self, "TOPRIGHT", 5, -8) +end + +---------------------------------------- +Addon.UIElementsLib._PanelSectionBackgroundInfo = +---------------------------------------- +{ + TopLeft = {Width = 4, Height = 4, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0, Right = 0.015625, Top = 0, Bottom = 0.0625}}, + TopCenter = {Width = 248, Height = 4, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0.015625, Right = 0.984375, Top = 0, Bottom = 0.0625}}, + TopRight = {Width = 4, Height = 4, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0.984375, Right = 1, Top = 0, Bottom = 0.0625}}, + MiddleLeft = {Width = 4, Height = 56, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0, Right = 0.015625, Top = 0.0625, Bottom = 0.9375}}, + MiddleCenter = {Width = 248, Height = 56, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0.015625, Right = 0.984375, Top = 0.0625, Bottom = 0.9375}}, + MiddleRight = {Width = 4, Height = 56, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0.984375, Right = 1, Top = 0.0625, Bottom = 0.9375}}, + BottomLeft = {Width = 4, Height = 4, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0, Right = 0.015625, Top = 0.9375, Bottom = 1}}, + BottomCenter = {Width = 248, Height = 4, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0.015625, Right = 0.984375, Top = 0.9375, Bottom = 1}}, + BottomRight = {Width = 4, Height = 4, Path = Addon.UIElementsLibTexturePath.."Textures\\PanelSectionBackground", Coords = {Left = 0.984375, Right = 1, Top = 0.9375, Bottom = 1}}, +} + +end -- if UIElementsLibTexturePath + +---------------------------------------- +function Addon.UIElementsLib:SetDialogBackdrop(pFrame) +---------------------------------------- + pFrame:SetBackdrop( + { + bgFile = "Interface\\RAIDFRAME\\UI-RaidFrame-GroupBg", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + tileSize = 512, + edgeSize = 32, + insets = {left = 11, right = 11, top = 11, bottom = 10} + }) + + pFrame:SetBackdropBorderColor(1, 1, 1) + pFrame:SetBackdropColor(0.8, 0.8, 0.8, 1) +end + +---------------------------------------- +Addon.UIElementsLib._ModalDialogFrame = {} +---------------------------------------- + +function Addon.UIElementsLib._ModalDialogFrame:New(pParent, pTitle, pWidth, pHeight) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._ModalDialogFrame:Construct(pParent, pTitle, pWidth, pHeight) + Addon.UIElementsLib:SetDialogBackdrop(self) + + self:SetWidth(pWidth) + self:SetHeight(pHeight) + + self.Title = self:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + self.Title:SetPoint("TOP", self, "TOP", 0, 0) + self.Title:SetText(pTitle) + + self.TitleBackground = self:CreateTexture(nil, "ARTWORK") + self.TitleBackground:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header") + self.TitleBackground:SetTexCoord(0.234375, 0.7578125, 0, 0.625) + self.TitleBackground:SetHeight(40) + self.TitleBackground:SetPoint("LEFT", self.Title, "LEFT", -20, 0) + self.TitleBackground:SetPoint("RIGHT", self.Title, "RIGHT", 20, 0) + + self.CancelButton = Addon:New(Addon.UIElementsLib._PushButton, self, CANCEL, 80) + self.CancelButton:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -15, 20) + self.CancelButton:SetScript("OnClick", function () + PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) + self:Cancel() + end) + + self.DoneButton = Addon:New(Addon.UIElementsLib._PushButton, self, OKAY, 80) + self.DoneButton:SetPoint("RIGHT", self.CancelButton, "LEFT", -7, 0) + self.DoneButton:SetScript("OnClick", function () + PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) + self:Done() + end) +end + +---------------------------------------- +Addon.UIElementsLib._SidebarWindowFrame = {} +---------------------------------------- + +function Addon.UIElementsLib._SidebarWindowFrame:New(pParent) + return CreateFrame("Frame", nil, pParent or UIParent) +end + +function Addon.UIElementsLib._SidebarWindowFrame:Construct() + self:EnableMouse(true) + + self.CloseButton = CreateFrame("Button", nil, self, "UIPanelCloseButton") + self.CloseButton:SetPoint("TOPRIGHT", self, "TOPRIGHT", 5, 5) + + self.Title = self:CreateFontString(nil, "ARTWORK", "GameFontNormal") + self.Title:SetPoint("CENTER", self, "TOP", 0, -10) + + -- Create the textures + + self.TopHeight = 80 + self.LeftWidth = 80 + self.BottomHeight = 183 + self.RightWidth = 94 + + self.TopMargin = 13 + self.LeftMargin = 0 + self.BottomMargin = 3 + self.RightMargin = 1 + + self.TextureWidth1 = 256 + self.TextureWidth2 = 128 + self.TextureUsedWidth2 = 94 + + self.TextureHeight1 = 256 + self.TextureHeight2 = 256 + self.TextureUsedHeight2 = 183 + + self.MiddleWidth1 = self.TextureWidth1 - self.LeftWidth + self.MiddleWidth2 = 60 + + self.TexCoordX1 = self.LeftWidth / self.TextureWidth1 + self.TexCoordX2 = (self.TextureUsedWidth2 - self.RightWidth) / self.TextureWidth2 + self.TexCoordX3 = self.TextureUsedWidth2 / self.TextureWidth2 + + self.TexCoordY1 = self.TopHeight / self.TextureHeight1 + self.TexCoordY2 = (self.TextureUsedHeight2 - self.BottomHeight) / self.TextureHeight2 + self.TexCoordY3 = self.TextureUsedHeight2 / self.TextureHeight2 + + self.Background = {} + + self.Background.TopRight = self:CreateTexture(nil, "BORDER") + self.Background.TopRight:SetWidth(self.RightWidth) + self.Background.TopRight:SetHeight(self.TopHeight) + self.Background.TopRight:SetPoint("TOPRIGHT", self, "TOPRIGHT", self.RightMargin, self.TopMargin) + self.Background.TopRight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight") + self.Background.TopRight:SetTexCoord(self.TexCoordX2, self.TexCoordX3, 0, self.TexCoordY1) + + self.Background.TopLeft = self:CreateTexture(nil, "BORDER") + self.Background.TopLeft:SetHeight(self.TopHeight) + self.Background.TopLeft:SetPoint("TOPLEFT", self, "TOPLEFT", -self.LeftMargin, self.TopMargin) + self.Background.TopLeft:SetPoint("TOPRIGHT", self.Background.TopRight, "TOPLEFT") + self.Background.TopLeft:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft") + self.Background.TopLeft:SetTexCoord(self.TexCoordX1, 1, 0, self.TexCoordY1) + + self.Background.BottomRight = self:CreateTexture(nil, "BORDER") + self.Background.BottomRight:SetWidth(self.RightWidth) + self.Background.BottomRight:SetHeight(self.BottomHeight) + self.Background.BottomRight:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", self.RightMargin, -self.BottomMargin) + self.Background.BottomRight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomRight") + self.Background.BottomRight:SetTexCoord(self.TexCoordX2, self.TexCoordX3, self.TexCoordY2, self.TexCoordY3) + + self.Background.BottomLeft = self:CreateTexture(nil, "BORDER") + self.Background.BottomLeft:SetHeight(self.BottomHeight) + self.Background.BottomLeft:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", -self.LeftMargin, -self.BottomMargin) + self.Background.BottomLeft:SetPoint("BOTTOMRIGHT", self.Background.BottomRight, "BOTTOMLEFT") + self.Background.BottomLeft:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomLeft") + self.Background.BottomLeft:SetTexCoord(self.TexCoordX1, 1, self.TexCoordY2, self.TexCoordY3) + + self.Background.RightMiddle = self:CreateTexture(nil, "BORDER") + self.Background.RightMiddle:SetWidth(self.RightWidth) + self.Background.RightMiddle:SetPoint("TOPRIGHT", self.Background.TopRight, "BOTTOMRIGHT") + self.Background.RightMiddle:SetPoint("BOTTOMRIGHT", self.Background.BottomRight, "TOPRIGHT") + self.Background.RightMiddle:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight") + self.Background.RightMiddle:SetTexCoord(self.TexCoordX2, self.TexCoordX3, self.TexCoordY1, 1) + + self.Background.LeftMiddle = self:CreateTexture(nil, "BORDER") + self.Background.LeftMiddle:SetPoint("TOPLEFT", self.Background.TopLeft, "BOTTOMLEFT") + self.Background.LeftMiddle:SetPoint("BOTTOMLEFT", self.Background.BottomLeft, "TOPLEFT") + self.Background.LeftMiddle:SetPoint("TOPRIGHT", self.Background.TopRight, "BOTTOMLEFT") + self.Background.LeftMiddle:SetPoint("BOTTOMRIGHT", self.Background.BottomRight, "TOPLEFT") + self.Background.LeftMiddle:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft") + self.Background.LeftMiddle:SetTexCoord(self.TexCoordX1, 1, self.TexCoordY1, 1) + + self.Foreground = CreateFrame("Frame", nil, self) + self.Foreground:SetAllPoints() + self.Foreground:SetFrameLevel(self:GetFrameLevel() + 20) + + self.Foreground.Shadow = self.Foreground:CreateTexture(nil, "OVERLAY") + self.Foreground.Shadow:SetWidth(18) + self.Foreground.Shadow:SetPoint("TOPLEFT", self.Foreground, "TOPLEFT") + self.Foreground.Shadow:SetPoint("BOTTOMLEFT", self.Foreground, "BOTTOMLEFT") + self.Foreground.Shadow:SetTexture("Interface\\AchievementFrame\\UI-Achievement-HorizontalShadow") + self.Foreground.Shadow:SetVertexColor(0, 0, 0) +end + +---------------------------------------- +Addon.UIElementsLib._Tabs = {} +---------------------------------------- + +if not MC2UIElementsLib.TabNameIndex then + MC2UIElementsLib.TabNameIndex = 1 +end + +function Addon.UIElementsLib._Tabs:Construct(pFrame, pXOffset, pYOffset) + self.ParentFrame = pFrame + self.Tabs = {} + self.SelectedTab = nil + + self.XOffset = (pXOffset or 0) + 18 + self.YOffset = (pYOffset or 0) + 3 +end + +function Addon.UIElementsLib._Tabs:NewTab(title, value) + local name = "MC2UIElementsLibTab"..MC2UIElementsLib.TabNameIndex + + MC2UIElementsLib.TabNameIndex = MC2UIElementsLib.TabNameIndex + 1 + + local tab = CreateFrame("Button", name, self.ParentFrame, "CharacterFrameTabButtonTemplate") + + tab:SetText(title) + tab.Value = value + tab:SetScript("OnClick", function(...) self:Tab_OnClick(...) end) + + PanelTemplates_DeselectTab(tab) + + table.insert(self.Tabs, tab) + + self:UpdateTabs() +end + +function Addon.UIElementsLib._Tabs:UpdateTabs() + local previousTab + + for _, tab in ipairs(self.Tabs) do + -- Remove existing anchors + tab:ClearAllPoints() + + -- Anchor to the previous tab if shown, or the parent if this is the first visible tab + if not tab.Hidden then + if not previousTab then + tab:SetPoint("TOPLEFT", self.ParentFrame, "TOPLEFT", self.XOffset, self.YOffset) + else + tab:SetPoint("TOPLEFT", previousTab, "TOPRIGHT", -14, 0) + end + + previousTab = tab + end + end +end + +function Addon.UIElementsLib._Tabs:SelectTabByValue(pValue) + self:SelectTab(self:GetTabByValue(pValue)) +end + +function Addon.UIElementsLib._Tabs:ShowTabByValue(pValue) + self:ShowTab(self:GetTabByValue(pValue)) +end + +function Addon.UIElementsLib._Tabs:HideTabByValue(pValue) + self:HideTab(self:GetTabByValue(pValue)) +end + +function Addon.UIElementsLib._Tabs:SelectTab(pTab) + if pTab == self.SelectedTab then + return + end + + if self.SelectedTab then + PanelTemplates_DeselectTab(self.SelectedTab) + + if self.OnDeselect then + self:OnSelect(self.SelectedTab) + end + end + + self.SelectedTab = pTab + + if self.SelectedTab then + PanelTemplates_SelectTab(self.SelectedTab) + + if self.OnSelect then + self:OnSelect(self.SelectedTab) + end + end +end + +function Addon.UIElementsLib._Tabs:ShowTab(pTab) + if not pTab.Hidden then + return + end + + pTab.Hidden = false + pTab:Show() + self:UpdateTabs() +end + +function Addon.UIElementsLib._Tabs:HideTab(pTab) + if pTab.Hidden then + return + end + + pTab.Hidden = true + pTab:Hide() + self:UpdateTabs() +end + +function Addon.UIElementsLib._Tabs:GetTabByValue(pValue) + for vIndex, vTab in ipairs(self.Tabs) do + if vTab.Value == pValue then + return vTab, vIndex + end + end +end + +function Addon.UIElementsLib._Tabs:Tab_OnClick(pTab, pButton) + PlaySound(SOUNDKIT.IG_MAINMENU_OPEN) + self:SelectTabByValue(pTab.Value) +end + +---------------------------------------- +Addon.UIElementsLib._TabbedView = {} +---------------------------------------- + +function Addon.UIElementsLib._TabbedView:New(parent, horizOffset, vertOffset) + return CreateFrame("Frame", nil, parent or UIParent) +end + +function Addon.UIElementsLib._TabbedView:Construct(parent, horizOffset, vertOffset) + self.Views = {} + self.CurrentFrame = nil + + self:SetWidth(1) + self:SetHeight(1) + + self:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", horizOffset, vertOffset) + + self.Tabs = Addon:New(Addon.UIElementsLib._Tabs, self) + self.Tabs.OnSelect = function (tabs, tab) + self:SelectView(tab.Value) + end +end + +function Addon.UIElementsLib._TabbedView:AddView(frame, title) + -- Add the tab + local tab = self.Tabs:NewTab(title, frame) + + -- Create the view + local view = { + Title = title, + Frame = frame, + Tab = tab, + } + table.insert(self.Views, view) + + -- Initially hidden + frame:Hide() + + -- Done + return view +end + +function Addon.UIElementsLib._TabbedView:SelectView(pFrame) + if self.CurrentFrame == pFrame then + return + end + + if self.CurrentFrame then + self:DeactivateView(self.CurrentFrame) + self.CurrentFrame:Hide() + end + + self.CurrentFrame = pFrame + + if self.CurrentFrame then + self.CurrentFrame:Show() + self:ActivateView(self.CurrentFrame) + end + + self.Tabs:SelectTabByValue(self.CurrentFrame) +end + +function Addon.UIElementsLib._TabbedView:GetViewByFrame(pFrame) + for _, vView in ipairs(self.Views) do + if vView.Frame == pFrame then + return vView + end + end +end + +function Addon.UIElementsLib._TabbedView:ShowView(pFrame) + self.Tabs:ShowTabByValue(pFrame) +end + +function Addon.UIElementsLib._TabbedView:HideView(pFrame) + self.Tabs:HideTabByValue(pFrame) +end + +function Addon.UIElementsLib._TabbedView:ActivateView(pView) + if pView.ViewActivated then + pView:ViewActivated() + end +end + +function Addon.UIElementsLib._TabbedView:DeactivateView(pView) + if pView.ViewDeactivated then + pView:ViewDeactivated() + end +end + +---------------------------------------- +if Addon.UIElementsLibTexturePath then +Addon.UIElementsLib._ScrollbarTrench = {} +---------------------------------------- + +function Addon.UIElementsLib._ScrollbarTrench:New(pParent) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._ScrollbarTrench:Construct(pParent) + self:SetWidth(27) + + self.TopTexture = self:CreateTexture(nil, "OVERLAY") + self.TopTexture:SetHeight(26) + self.TopTexture:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 2) + self.TopTexture:SetPoint("TOPRIGHT", self, "TOPRIGHT", 0, 2) + self.TopTexture:SetTexture(Addon.UIElementsLibTexturePath.."Textures\\ScrollbarTrench") + self.TopTexture:SetTexCoord(0, 0.84375, 0, 0.1015625) + + self.BottomTexture = self:CreateTexture(nil, "OVERLAY") + self.BottomTexture:SetHeight(26) + self.BottomTexture:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 0, -1) + self.BottomTexture:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, -1) + self.BottomTexture:SetTexture(Addon.UIElementsLibTexturePath.."Textures\\ScrollbarTrench") + self.BottomTexture:SetTexCoord(0, 0.84375, 0.90234375, 1) + + self.MiddleTexture = self:CreateTexture(nil, "OVERLAY") + self.MiddleTexture:SetPoint("TOPLEFT", self.TopTexture, "BOTTOMLEFT") + self.MiddleTexture:SetPoint("BOTTOMRIGHT", self.BottomTexture, "TOPRIGHT") + self.MiddleTexture:SetTexture(Addon.UIElementsLibTexturePath.."Textures\\ScrollbarTrench") + self.MiddleTexture:SetTexCoord(0, 0.84375, 0.1015625, 0.90234375) +end + +---------------------------------------- +Addon.UIElementsLib._Scrollbar = {} +---------------------------------------- + +function Addon.UIElementsLib._Scrollbar:New(pParent) + return CreateFrame("Slider", nil, pParent) +end + +function Addon.UIElementsLib._Scrollbar:Construct(pParent) + self:SetWidth(16) + + self.UpButton = CreateFrame("Button", nil, self) + self.UpButton:SetWidth(16) + self.UpButton:SetHeight(16) + self.UpButton:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Up") + self.UpButton:GetNormalTexture():SetTexCoord(0.25, 0.75, 0.25, 0.75) + self.UpButton:SetPushedTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Down") + self.UpButton:GetPushedTexture():SetTexCoord(0.25, 0.75, 0.25, 0.75) + self.UpButton:SetDisabledTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Disabled") + self.UpButton:GetDisabledTexture():SetTexCoord(0.25, 0.75, 0.25, 0.75) + self.UpButton:SetHighlightTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Highlight") + self.UpButton:GetHighlightTexture():SetTexCoord(0.25, 0.75, 0.25, 0.75) + self.UpButton:GetHighlightTexture():SetBlendMode("ADD") + self.UpButton:SetPoint("BOTTOM", self, "TOP") + self.UpButton:SetScript("OnClick", function (pButtonFrame, pButton) + self:SetValue(self:GetValue() - self:GetHeight() * 0.5) + PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) + end) + + self.DownButton = CreateFrame("Button", nil, self) + self.DownButton:SetWidth(16) + self.DownButton:SetHeight(16) + self.DownButton:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Up") + self.DownButton:GetNormalTexture():SetTexCoord(0.25, 0.75, 0.25, 0.75) + self.DownButton:SetPushedTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Down") + self.DownButton:GetPushedTexture():SetTexCoord(0.25, 0.75, 0.25, 0.75) + self.DownButton:SetDisabledTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Disabled") + self.DownButton:GetDisabledTexture():SetTexCoord(0.25, 0.75, 0.25, 0.75) + self.DownButton:SetHighlightTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Highlight") + self.DownButton:GetHighlightTexture():SetTexCoord(0.25, 0.75, 0.25, 0.75) + self.DownButton:GetHighlightTexture():SetBlendMode("ADD") + self.DownButton:SetPoint("TOP", self, "BOTTOM") + self.DownButton:SetScript("OnClick", function (pButtonFrame, pButton) + self:SetValue(self:GetValue() + self:GetHeight() * 0.5) + PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) + end) + + local vThumbTexture = self:CreateTexture(nil, "OVERLAY") + + vThumbTexture:SetTexture("Interface\\Buttons\\UI-ScrollBar-Knob") + vThumbTexture:SetWidth(16) + vThumbTexture:SetHeight(24) + vThumbTexture:SetTexCoord(0.25, 0.75, 0.125, 0.875) + + self:SetThumbTexture(vThumbTexture) +end + +function Addon.UIElementsLib._Scrollbar:SetValue(...) + self.Inherited.SetValue(self, ...) + self:AdjustButtons() +end + +function Addon.UIElementsLib._Scrollbar:SetMinMaxValues(...) + self.Inherited.SetMinMaxValues(self, ...) + self:AdjustButtons() +end + +function Addon.UIElementsLib._Scrollbar:AdjustButtons() + local vMin, vMax = self:GetMinMaxValues() + local vValue = self:GetValue() + + if math.floor(vValue) <= vMin then + self.UpButton:Disable() + else + self.UpButton:Enable() + end + + if math.ceil(vValue) >= vMax then + self.DownButton:Disable() + else + self.DownButton:Enable() + end +end + +---------------------------------------- +Addon.UIElementsLib._ScrollingList = {} +---------------------------------------- + +if not MC2UIElementsLib.ScrollFrameIndex then + MC2UIElementsLib.ScrollFrameIndex = 1 +end + +function Addon.UIElementsLib._ScrollingList:New(pParent, pItemHeight) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._ScrollingList:Construct(pParent, pItemHeight) + self.ItemHeight = pItemHeight or 27 + + self.ScrollbarTrench = Addon:New(Addon.UIElementsLib._ScrollbarTrench, self) + self.ScrollbarTrench:SetPoint("TOPRIGHT", self, "TOPRIGHT", 0, 0) + self.ScrollbarTrench:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0) + + local vScrollFrameName = "MC2UIElementsLibScrollFrame"..MC2UIElementsLib.ScrollFrameIndex + MC2UIElementsLib.ScrollFrameIndex = MC2UIElementsLib.ScrollFrameIndex + 1 + + self.ScrollFrame = CreateFrame("ScrollFrame", vScrollFrameName, self, "FauxScrollFrameTemplate") + self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT") + self.ScrollFrame:SetPoint("BOTTOMRIGHT", self.ScrollbarTrench, "BOTTOMLEFT", 0, 0) + self.ScrollFrame:SetScript("OnVerticalScroll", function (frame, offset) + FauxScrollFrame_OnVerticalScroll(frame, offset, self.ItemHeight, function () + if self.DrawingFunc then + self:DrawingFunc() + end + end) + end) + + self.ScrollFrame:SetFrameLevel(self:GetFrameLevel() + 1) -- Ensure it's above the parent + self.ScrollFrame:Show() -- Ensure it's visible +end + +function Addon.UIElementsLib._ScrollingList:GetOffset() + return FauxScrollFrame_GetOffset(self.ScrollFrame) +end + +function Addon.UIElementsLib._ScrollingList:GetNumVisibleItems() + local vHeight = self:GetHeight() or 0 + return math.floor(vHeight / self.ItemHeight) +end + +function Addon.UIElementsLib._ScrollingList:SetNumItems(pNumItems) + local vWidth, vHeight = self:GetWidth(), self:GetHeight() + local vNumVisibleItems = self:GetNumVisibleItems() + + FauxScrollFrame_Update( + self.ScrollFrame, + pNumItems, + vNumVisibleItems, + self.ItemHeight, + nil, + nil, + nil, + nil, + vWidth, vHeight) +end + +---------------------------------------- +Addon.UIElementsLib._ScrollingItemList = {} +---------------------------------------- + +function Addon.UIElementsLib._ScrollingItemList:New(pParent, pItemMethods, pItemHeight) + return Addon:New(Addon.UIElementsLib._ScrollingList, pParent, pItemHeight) +end + +function Addon.UIElementsLib._ScrollingItemList:Construct(pParent, pItemMethods, pItemHeight) + self.ItemMethods = pItemMethods + self.ItemFrames = {} +end + +function Addon.UIElementsLib._ScrollingItemList:GetNumVisibleItems() + local vNumVisibleItems = self.Inherited.GetNumVisibleItems(self) + + while #self.ItemFrames < vNumVisibleItems do + local vListItem = Addon:New(self.ItemMethods, self) + + if #self.ItemFrames == 0 then + vListItem:SetPoint("TOPLEFT", self.ScrollFrame, "TOPLEFT") + vListItem:SetPoint("TOPRIGHT", self.ScrollFrame, "TOPRIGHT") + else + local vPreviousListItem = self.ItemFrames[#self.ItemFrames] + + vListItem:SetPoint("TOPLEFT", vPreviousListItem, "BOTTOMLEFT") + vListItem:SetPoint("TOPRIGHT", vPreviousListItem, "BOTTOMRIGHT") + end + + table.insert(self.ItemFrames, vListItem) + end + + return vNumVisibleItems +end + +function Addon.UIElementsLib._ScrollingItemList:SetNumItems(pNumItems) + self.Inherited.SetNumItems(self, pNumItems) + + -- Adjust visibility + + local vNumVisibleItems = self:GetNumVisibleItems() -- This will allocate the item frames + + if pNumItems < vNumVisibleItems then + vNumVisibleItems = pNumItems + end + + for vItemIndex = 1, vNumVisibleItems do + self.ItemFrames[vItemIndex]:Show() + end + + for vItemIndex = vNumVisibleItems + 1, #self.ItemFrames do + self.ItemFrames[vItemIndex]:Hide() + end +end + +end -- if Addon.UIElementsLibTexturePath then + +---------------------------------------- +Addon.UIElementsLib._CheckButton = {} +---------------------------------------- + +function Addon.UIElementsLib._CheckButton:New(pParent, pTitle, pSmall) + return CreateFrame("CheckButton", nil, pParent) +end + +function Addon.UIElementsLib._CheckButton:Construct(pParent, pTitle, pSmall) + self.Enabled = true + + self.Small = pSmall + + self:SetWidth(self.Small and 18 or 23) + self:SetHeight(self.Small and 16 or 21) + + self.Title = self:CreateFontString(nil, "ARTWORK", self.Small and "GameFontNormalSmall" or "GameFontNormal") + self.Title:SetPoint("LEFT", self, "RIGHT", 2, 0) + self.Title:SetJustifyH("LEFT") + self.Title:SetText(pTitle or "") + + --self:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled") + --self:GetDisabledCheckedTexture():SetTexCoord(0.125, 0.84375, 0.15625, 0.8125) + + self:SetDisplayMode("CHECKBOX") +end + +function Addon.UIElementsLib._CheckButton:SetEnabled(pEnabled) + self.Enabled = pEnabled + + if pEnabled then + self:Enable() + else + self:Disable() + end + + self:SetAlpha(pEnabled and 1 or 0.5) +end + +function Addon.UIElementsLib._CheckButton:SetAnchorMode(pMode) + self.Title:ClearAllPoints() + self:ClearAllPoints() + + if pMode == "TITLE" then + self:SetPoint("RIGHT", self.Title, "LEFT", -2, 0) + else + self.Title:SetPoint("LEFT", self, "RIGHT", 2, 0) + end +end + +function Addon.UIElementsLib._CheckButton:SetDisplayMode(pMode) + self.DisplayMode = pMode + + if pMode == "LEADER" + or pMode == "ASSIST" then + self:UpdateLeaderModeTexture() + + self:SetHighlightTexture("Interface\\Buttons\\UI-PlusButton-Hilight") + self:GetHighlightTexture():SetTexCoord(0, 1, 0, 1) + self:GetHighlightTexture():SetBlendMode("ADD") + + if self.DisplayMode == "ASSIST" then + self:SetNormalTexture("Interface\\GroupFrame\\UI-Group-AssistantIcon") + self:SetPushedTexture("Interface\\GroupFrame\\UI-Group-AssistantIcon") + self:SetCheckedTexture("Interface\\GroupFrame\\UI-Group-AssistantIcon") + else + self:SetNormalTexture("Interface\\GroupFrame\\UI-Group-LeaderIcon") + self:SetCheckedTexture("Interface\\GroupFrame\\UI-Group-LeaderIcon") + self:SetPushedTexture("Interface\\GroupFrame\\UI-Group-LeaderIcon") + end + + if self.MultiSelect then + self:GetCheckedTexture():SetDesaturated(true) + self:GetCheckedTexture():SetVertexColor(1, 1, 1, 0.6) + else + self:GetCheckedTexture():SetDesaturated(false) + self:GetCheckedTexture():SetVertexColor(1, 1, 1, 1) + end + + local vNormalTexture = self:GetNormalTexture() + + vNormalTexture:SetDesaturated(true) + vNormalTexture:SetVertexColor(1, 1, 1, 0.33) + + elseif pMode == "EXPAND" then + self:UpdateExpandModeTexture() + + self:SetHighlightTexture("Interface\\Buttons\\UI-PlusButton-Hilight") + self:GetHighlightTexture():SetTexCoord(0, 1, 0, 1) + self:GetHighlightTexture():SetBlendMode("ADD") + + self:SetCheckedTexture("") + else + if pMode == "BUSY" then + self:SetNormalTexture(Addon.UIElementsLibTexturePath.."Textures\\Gear") + self:GetNormalTexture():SetTexCoord(0, 1, 0, 1) + self:SetCheckedTexture("") + else -- CHECKBOX + self:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up") + self:GetNormalTexture():SetTexCoord(0.125, 0.84375, 0.15625, 0.8125) + + if self.MultiSelect then + self:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled") + else + self:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check") + end + + self:GetCheckedTexture():SetTexCoord(0.125, 0.84375, 0.15625, 0.8125) + end + + self:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down") + self:GetPushedTexture():SetTexCoord(0.125, 0.84375, 0.15625, 0.8125) + + self:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight") + self:GetHighlightTexture():SetTexCoord(0.125, 0.84375, 0.15625, 0.8125) + self:GetHighlightTexture():SetBlendMode("ADD") + end +end + +function Addon.UIElementsLib._CheckButton:SetChecked(pChecked) + self.Inherited.SetChecked(self, pChecked) + + if self.DisplayMode == "LEADER" + or self.DisplayMode == "ASSIST" then + self:UpdateLeaderModeTexture() + elseif self.DisplayMode == "EXPAND" then + self:UpdateExpandModeTexture() + end +end + +function Addon.UIElementsLib._CheckButton:UpdateExpandModeTexture() + if self:GetChecked() then + self:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up") + self:GetNormalTexture():SetTexCoord(0, 1, 0, 1) + + self:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-Down") + self:GetPushedTexture():SetTexCoord(0, 1, 0, 1) + else + self:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up") + self:GetNormalTexture():SetTexCoord(0, 1, 0, 1) + + self:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-Down") + self:GetPushedTexture():SetTexCoord(0, 1, 0, 1) + end +end + +function Addon.UIElementsLib._CheckButton:UpdateLeaderModeTexture() +end + +function Addon.UIElementsLib._CheckButton:SetTitle(pTitle) + self.Title:SetText(pTitle) +end + +function Addon.UIElementsLib._CheckButton:SetMultiSelect(pMultiSelect) + self.MultiSelect = pMultiSelect + self:SetDisplayMode(self.DisplayMode) +end + +---------------------------------------- +Addon.UIElementsLib._ExpandAllButton = {} +---------------------------------------- + +function Addon.UIElementsLib._ExpandAllButton:New(pParent) + return Addon:New(Addon.UIElementsLib._CheckButton, pParent, ALL) +end + +function Addon.UIElementsLib._ExpandAllButton:Construct(pParent) + self:SetWidth(20) + self:SetHeight(20) + + self.TabLeft = self:CreateTexture(nil, "BACKGROUND") + self.TabLeft:SetWidth(8) + self.TabLeft:SetHeight(32) + self.TabLeft:SetPoint("RIGHT", self, "LEFT", 3, 3) + self.TabLeft:SetTexture("Interface\\QuestFrame\\UI-QuestLogSortTab-Left") + + self.TabMiddle = self:CreateTexture(nil, "BACKGROUND") + self.TabMiddle:SetHeight(32) + self.TabMiddle:SetPoint("LEFT", self.TabLeft, "RIGHT") + self.TabMiddle:SetPoint("RIGHT", self.Title, "RIGHT", 5, 0) + self.TabMiddle:SetTexture("Interface\\QuestFrame\\UI-QuestLogSortTab-Middle") + + self.TabRight = self:CreateTexture(nil, "BACKGROUND") + self.TabRight:SetWidth(8) + self.TabRight:SetHeight(32) + self.TabRight:SetPoint("LEFT", self.TabMiddle, "RIGHT") + self.TabRight:SetTexture("Interface\\QuestFrame\\UI-QuestLogSortTab-Right") + + self:SetDisplayMode("EXPAND") +end + +---------------------------------------- +Addon.UIElementsLib._Window = {} +---------------------------------------- + +function Addon.UIElementsLib._Window:New() + return CreateFrame("Frame", nil, UIParent) +end + +function Addon.UIElementsLib._Window:Construct() + self:SetMovable(true) + self:SetScript("OnDragStart", self.OnDragStart) + self:SetScript("OnDragStop", self.OnDragStop) +end + +function Addon.UIElementsLib._Window:OnDragStart() + self:StartMoving() +end + +function Addon.UIElementsLib._Window:OnDragStop() + self:StopMovingOrSizing() +end + +function Addon.UIElementsLib._Window:Close() + self:Hide() +end + +---------------------------------------- +Addon.UIElementsLib._FloatingWindow = {} +---------------------------------------- + +function Addon.UIElementsLib._FloatingWindow:New() + return Addon:New(Addon.UIElementsLib._Window) +end + +function Addon.UIElementsLib._FloatingWindow:Construct() + self.ContentFrame = Addon:New(Addon.UIElementsLib._PlainBorderedFrame, self) + self.ContentFrame:SetAllPoints() + + self.TitleBar = Addon:New(Addon.UIElementsLib._FadingTitleBar, self) +end + +function Addon.UIElementsLib._FloatingWindow:SetTitle(pTitle) + self.TitleBar:SetTitle(pTitle) +end + +function Addon.UIElementsLib._FloatingWindow:OnDragStart() + self.Inherited.OnDragStart(self) + self.TitleBar:SetForceFullBar(true) +end + +function Addon.UIElementsLib._FloatingWindow:OnDragStop() + self.Inherited.OnDragStop(self) + self.TitleBar:SetForceFullBar(false) +end + +---------------------------------------- +Addon.UIElementsLib._PlainBorderedFrame = {} +---------------------------------------- + +function Addon.UIElementsLib._PlainBorderedFrame:New(pParent) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._PlainBorderedFrame:Construct(pParent) + self:SetBackdrop( + { + bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", + edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", + tile = true, + tileSize = 16, + edgeSize = 16, + insets = {left = 3, right = 3, top = 3, bottom = 3} + }) + + self:SetBackdropBorderColor(0.75, 0.75, 0.75) + self:SetBackdropColor(0.15, 0.15, 0.15) + self:SetAlpha(1.0) +end + +---------------------------------------- +Addon.UIElementsLib._CloseButton = {} +---------------------------------------- + +function Addon.UIElementsLib._CloseButton:New(pParent) + return CreateFrame("Button", nil, pParent) +end + +function Addon.UIElementsLib._CloseButton:Construct(pParent) + local vTexture + + self:SetWidth(16) + self:SetHeight(15) + + local vTexture = self:CreateTexture(nil, "ARTWORK") + + self:SetNormalTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Up") + vTexture = self:GetNormalTexture() + vTexture:SetTexCoord(0.1875, 0.78125, 0.21875, 0.78125) + + self:SetPushedTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Down") + vTexture = self:GetPushedTexture() + vTexture:SetTexCoord(0.1875, 0.78125, 0.21875, 0.78125) + + self:SetHighlightTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Highlight") + vTexture = self:GetHighlightTexture() + vTexture:SetTexCoord(0.1875, 0.78125, 0.21875, 0.78125) + vTexture:SetBlendMode("ADD") +end + +---------------------------------------- +Addon.UIElementsLib._FadingTitleBar = {} +---------------------------------------- + +function Addon.UIElementsLib._FadingTitleBar:New(pParent) + return CreateFrame("Button", nil, pParent) +end + +function Addon.UIElementsLib._FadingTitleBar:Construct(pParent) + self:SetHeight(15) + self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", 0, 0) + self:SetPoint("BOTTOMRIGHT", self:GetParent(), "TOPRIGHT", 0, 0) + + self.FullBar = CreateFrame("Frame", nil, self) + self.FullBar:SetAllPoints() + + self.FullBar.BarLeft = self.FullBar:CreateTexture(nil, "BACKGROUND") + self.FullBar.BarLeft:SetWidth(12) + self.FullBar.BarLeft:SetHeight(22) + self.FullBar.BarLeft:SetPoint("TOPLEFT", self, "TOPLEFT") + self.FullBar.BarLeft:SetTexture("Interface\\Addons\\ForgeWay\\Textures\\GroupTitleBar") + self.FullBar.BarLeft:SetTexCoord(0, 0.09375, 0.3125, 1) + + self.FullBar.BarRight = self.FullBar:CreateTexture(nil, "BACKGROUND") + self.FullBar.BarRight:SetWidth(32) + self.FullBar.BarRight:SetHeight(22) + self.FullBar.BarRight:SetPoint("TOPRIGHT", self, "TOPRIGHT", 1, 0) + self.FullBar.BarRight:SetTexture("Interface\\Addons\\ForgeWay\\Textures\\GroupTitleBar") + self.FullBar.BarRight:SetTexCoord(0.75, 1, 0.3125, 1) + + self.FullBar.BarMiddle = self.FullBar:CreateTexture(nil, "BACKGROUND") + self.FullBar.BarMiddle:SetHeight(22) + self.FullBar.BarMiddle:SetPoint("TOPLEFT", self.FullBar.BarLeft, "TOPRIGHT") + self.FullBar.BarMiddle:SetPoint("TOPRIGHT", self.FullBar.BarRight, "TOPLEFT") + self.FullBar.BarMiddle:SetTexture("Interface\\Addons\\ForgeWay\\Textures\\GroupTitleBar") + self.FullBar.BarMiddle:SetTexCoord(0.09375, 0.75, 0.3125, 1) + + self.FullBar.Title = self.FullBar:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") + self.FullBar.Title:SetPoint("LEFT", self.FullBar.BarLeft, "RIGHT", -4, 2) + self.FullBar.Title:SetPoint("RIGHT", self.FullBar.BarRight, "LEFT", 0, 2) + + self.FullBar.CloseButton = Addon:New(Addon.UIElementsLib._CloseButton, self.FullBar) + self.FullBar.CloseButton:SetPoint("RIGHT", self.FullBar.BarRight, "RIGHT", -5, 1) + self.FullBar.CloseButton:SetScript("OnEnter", function (self) self:GetParent():GetParent():ShowFullBar(true) end) + self.FullBar.CloseButton:SetScript("OnLeave", function (self) self:GetParent():GetParent():ShowFullBar(false) end) + self.FullBar.CloseButton:Hide() + + -- Create the compact version (shown when the mouse isn't over the bar) + + self.CompactBar = CreateFrame("Frame", nil, self) + self.CompactBar:SetAllPoints() + + self.CompactBar.Title = self.CompactBar:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") + self.CompactBar.Title:SetPoint("LEFT", self.CompactBar, "LEFT", 0, -1) + self.CompactBar.Title:SetPoint("RIGHT", self.CompactBar, "RIGHT", 0, -1) + + self:SetScript("OnEnter", function (self) self:ShowFullBar(true) end) + self:SetScript("OnLeave", function (self) self:ShowFullBar(false) end) + self:SetScript("OnMouseDown", function (self) self:GetParent():OnDragStart() end) + self:SetScript("OnMouseUp", function (self) self:GetParent():OnDragStop() end) + + -- Start out with the full bar hidden + + self.FullBar:SetAlpha(0) + self.CompactBar:SetAlpha(1) + + self.FullBarShown = false + self.FullBarForced = false + + -- + + self:RegisterForDrag("LeftButton") + self:RegisterForClicks("RightButtonUp") +end + +function Addon.UIElementsLib._FadingTitleBar:SetForceFullBar(pForce) + if self.FullBarForced == pForce then + return + end + + self.FullBarForced = pForce + self:UpdateFullBarVisibility() +end + +function Addon.UIElementsLib._FadingTitleBar:ShowFullBar(pShow) + if self.FullBarShown == pShow then + return + end + + self.FullBarShown = pShow + self:UpdateFullBarVisibility() +end + +function Addon.UIElementsLib._FadingTitleBar:UpdateFullBarVisibility() + if self.FullBarShown or self.FullBarForced then + UIFrameFadeRemoveFrame(self.FullBar) + UIFrameFadeRemoveFrame(self.CompactBar) + + self.FullBar:SetAlpha(1) + self.CompactBar:SetAlpha(0) + else + if pForceState then + UIFrameFadeRemoveFrame(self.FullBar) + UIFrameFadeRemoveFrame(self.CompactBar) + self.FullBar:SetAlpha(0) + self.CompactBar:SetAlpha(1) + else + UIFrameFadeOut(self.FullBar, 0.5, 1, 0) + UIFrameFadeIn(self.CompactBar, 0.5, 0, 1) + end + end +end + +function Addon.UIElementsLib._FadingTitleBar:SetTitle(pTitle) + self.FullBar.Title:SetText(pTitle) + self.CompactBar.Title:SetText(pTitle) +end + +function Addon.UIElementsLib._FadingTitleBar:SetCloseFunc(pCloseFunc) + self.FullBar.CloseButton:SetScript("OnClick", pCloseFunc) + self.FullBar.CloseButton:Show() +end + +---------------------------------------- +Addon.UIElementsLib._ExpandButton = {} +---------------------------------------- + +function Addon.UIElementsLib._ExpandButton:New(pParent) + return CreateFrame("Button", nil, pParent) +end + +function Addon.UIElementsLib._ExpandButton:Construct(pParent) + self:SetWidth(16) + self:SetHeight(16) + + self:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP") + + local vHighlight = self:CreateTexture(nil, "HIGHLIGHT") + vHighlight:SetTexture("Interface\\Buttons\\UI-PlusButton-Hilight") + vHighlight:SetBlendMode("ADD") + vHighlight:SetAllPoints() + + self:SetHighlightTexture(vHighlight) +end + +function Addon.UIElementsLib._ExpandButton:SetExpanded(pExpanded) + if pExpanded then + self:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP") + else + self:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-UP") + end +end + +---------------------------------------- +Addon.UIElementsLib._DropDownMenuItems = {} +---------------------------------------- + +function Addon.UIElementsLib._DropDownMenuItems:Construct(closeFunc) + self.type = "group" + self.args = {} + self.closeFunc = closeFunc +end + +function Addon.UIElementsLib._DropDownMenuItems:AddItem(item, options) + -- Convert to a table if the item is just a string + if type(item) ~= "table" then + item = {name = tostring(item)} + end + + -- Copy the options table over if it's provided + if options then + assert(type(options) == "table", "AddItem second parameter must be a table") + + for k, v in pairs(options) do + item[k] = v + end + end + + item.order = #self.args + 1 + table.insert(self.args, item) +end + +function Addon.UIElementsLib._DropDownMenuItems:AddFunction(title, func, disabled, options) + self:AddItem({ + name = title, + type = "execute", + func = function (...) + func(...) + if self.closeFunc then + self.closeFunc() + end + end, + disabled = disabled, + }, options) +end + +function Addon.UIElementsLib._DropDownMenuItems:AddCategoryTitle(title) + if not title then + Addon:ErrorMessage("Category must have title") + return + end + + self:AddItem({ + name = title, + type = "header", + }) +end + +function Addon.UIElementsLib._DropDownMenuItems:AddSelect(title, values, get, set) + assert(title, "Category must have title") + + if type(values) == "function" then + values = values() + end + + self:AddItem({ + name = title, + type = "select", + values = values, + get = get, + set = function (...) + set(...) + if self.closeFunc then + self.closeFunc() + end + end, + }) +end + +function Addon.UIElementsLib._DropDownMenuItems:AddChildMenu(title, func) + assert(type(title) == "string", "AddChildMenu: First parameter must be a string") + assert(type(func) == "function", "AddChildMenu: Second parameter must be a function") + + local items = Addon:New(Addon.UIElementsLib._DropDownMenuItems, self.closeFunc) + items.name = title + items.type = "group" + func(items) + + self:AddItem(items) +end + +function Addon.UIElementsLib._DropDownMenuItems:AddDivider() + self:AddCategoryTitle(" ") +end + +function Addon.UIElementsLib._DropDownMenuItems:AddToggle(title, get, set, disabled, options) + local item = { + name = title, + type = "toggle", + get = get, + set = function (item, ...) + if set then + set(item, ...) + end + if self.closeFunc then + self.closeFunc() + end + end, + disabled = disabled, + } + self:AddItem(item, options) + return item +end + +function Addon.UIElementsLib._DropDownMenuItems:AddToggleWithIcon(title, icon, color, get, set, disabled, options) + local item = self:AddToggle(title, get, set, disabled, options) + item.icon = icon + item.color = color + return item +end + +function Addon.UIElementsLib._DropDownMenuItems:AddItemWithValue(title, value, options) + local item = self:AddToggle( + title, + + -- get + function (item) + return self.selectedValue == value + end, + + -- set + function (item) + self:DidSelectItemWithValue(value) + end, + + nil, -- disabled + options + ) + + item.value = value + return item +end + +function Addon.UIElementsLib._DropDownMenuItems:GetItemWithValue(value) + for index, item in ipairs(self.args) do + if item.value == value then + return item, index + elseif item.type == "group" then + local item, index2 = item:GetItemWithValue(value) + if item then + return item, index, index2 + end + end + end +end + +function Addon.UIElementsLib._DropDownMenuItems:GetTitleForValue(value) + local item = self:GetItemWithValue(value) + if item then + return item.name + end +end + +function Addon.UIElementsLib._DropDownMenuItems:AddSingleChoiceGroup(title, items, get, set, disable) + if title then + self:AddCategoryTitle(title) + end + for index, item in ipairs(items) do + local menuItem = self:AddToggle( + item.title, + -- get + function () + return get() == item.value + end, + -- set + function (menu, value) + set(item.value) + end, + disable) + menuItem.value = item.value + end +end + +---------------------------------------- +Addon.UIElementsLib._DropDownMenu = {} +---------------------------------------- + +function Addon.UIElementsLib._DropDownMenu:Show(items, point, relativeTo, relativePoint, xOffset, yOffset) + -- Fail if it's already up + assert(not self.menuFrame, "DropDownMenu can't call Show if already shown") + assert(items and items.args, "DropDownMenu items must be DropDownMenuItems") + + -- Play a sound + PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) + + -- Show the menu + self.menuFrame = LibStub("LibDropdownMC-1.0"):OpenAce3Menu(items) + self.menuFrame:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset) + self.menuFrame.cleanup = function () + if self.cleanup then + self.cleanup() + end + end +end + +function Addon.UIElementsLib._DropDownMenu:Hide() + -- Fail if it's not up + assert(self.menuFrame, "DropDownMenu can't call Hide if not shown") + + -- Play a sound + PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) + + -- Hide the menu and leave if it's currently up + self.menuFrame:Hide() + self.menuFrame = nil +end + +function Addon.UIElementsLib._DropDownMenu:Toggle() + if self.menuFrame then + self:Hide() + else + self:Show() + end +end + +---------------------------------------- +Addon.UIElementsLib._DropDownMenuButton = {} +---------------------------------------- + +if not MC2UIElementsLib_Globals then + MC2UIElementsLib_Globals = + { + NumDropDownMenuButtons = 0, + } +end + +function Addon.UIElementsLib._DropDownMenuButton:New(parent, menuFunc, width) + MC2UIElementsLib_Globals.NumDropDownMenuButtons = MC2UIElementsLib_Globals.NumDropDownMenuButtons + 1 + local name = "MC2UIElementsLib_DropDownMenuButton"..MC2UIElementsLib_Globals.NumDropDownMenuButtons + + return CreateFrame("Frame", name, parent) +end + +function Addon.UIElementsLib._DropDownMenuButton:Construct(pParent, pMenuFunc, pWidth) + local buttonSize = 24 + + if not pWidth then + pWidth = buttonSize + end + + if pWidth < buttonSize then + buttonSize = pWidth + end + + self.AutoSelectValue = true -- calls SetSelectedValue on item selection automatically + + self:SetWidth(pWidth) + self:SetHeight(buttonSize) + + self.Button = CreateFrame("Button", nil, self) + self.Button:SetWidth(buttonSize) + self.Button:SetHeight(buttonSize) + self.Button:SetPoint("RIGHT", self, "RIGHT", 1, 0) + + self.Button:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up") + self.Button:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down") + self.Button:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled") + + self.Button.HighlightTexture = self.Button:CreateTexture(nil, "HIGHLIGHT") + self.Button.HighlightTexture:SetTexture("Interface\\Buttons\\UI-Common-MouseHilight") + self.Button.HighlightTexture:SetBlendMode("ADD") + self.Button.HighlightTexture:SetAllPoints() + + self.Icon = self:CreateTexture(self:GetName().."Icon", "ARTWORK") + self.Icon:SetWidth(1) + self.Icon:SetHeight(1) + self.Icon:SetPoint("TOPLEFT", self.LeftTexture, "TOPLEFT", 0, 0) + + self.Button:SetScript("OnClick", function (frame, button) + self:ToggleMenu() + PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) + end) + + self.MenuFunc = pMenuFunc + + self.initialize = self.WoWMenuInitFunction + self.currentLevelItems = self.items + + self:SetScript("OnHide", function () + if self.dropDownMenu then + self.dropDownMenu:Hide() + self.dropDownMenu = nil + end + end) +end + +function Addon.UIElementsLib._DropDownMenuButton:SetMenuFunc(menuFunc) + self.menuFunc = menuFunc +end + +function Addon.UIElementsLib._DropDownMenuButton:RefreshItems() + self.items = Addon:New(Addon.UIElementsLib._DropDownMenuItems, function () + Addon.SchedulerLib:ScheduleTask(0.1, function () + self.dropDownMenu:Hide() + self.dropDownMenu = nil + end) + end) + self.MenuFunc(self.items) +end + +function Addon.UIElementsLib._DropDownMenuButton:ToggleMenu() + PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) + + -- Hide the menu and leave if it's currently up + if self.dropDownMenu then + self.dropDownMenu:Hide() + self.dropDownMenu = nil + return + end + + -- Position the menu + self.relativeTo = self + self.point = self.AnchorPoint or "TOPRIGHT" + self.relativePoint = self.AnchorRelativePoint or "BOTTOMRIGHT" + self.xOffset = self.AnchorXOffset or 0 + self.yOffset = self.AnchorYOffset or 3 + + -- Get the items + self:RefreshItems() + + -- Show the menu + self.dropDownMenu = Addon:New(Addon.UIElementsLib._DropDownMenu) + self.items.selectedValue = self.selectedValue + self.dropDownMenu:Show(self.items, self.point, self.relativeTo, self.relativePoint, self.xOffset, self.yOffset) + + -- Propagate value change messages for those menus using the stateful idiom + self.items.DidSelectItemWithValue = function (menu, value) + self:DidSelectItemWithValue(value) + end +end + +function Addon.UIElementsLib._DropDownMenuButton:ItemClicked(value) + if self.AutoSelectValue then + self:SetSelectedValue(value) + end + + if self.ItemClickedFunc then + self:ItemClickedFunc(value) + end + + CloseDropDownMenus() +end + +function Addon.UIElementsLib._DropDownMenuButton:SetSelectedValue(value) + self.selectedValue = value + + if self.items then + self.items.selectedValue = value + end +end + +function Addon.UIElementsLib._DropDownMenuButton:GetSelectedValue() + return self.selectedValue +end + +function Addon.UIElementsLib._DropDownMenuButton:SetCurrentValueText(pText) + -- Not applicable for a menu button +end + +function Addon.UIElementsLib._DropDownMenuButton:SetEnabled(pEnabled) + if pEnabled then + self.Button:Enable() + self:SetAlpha(1) + else + self.Button:Disable() + self:SetAlpha(0.5) + end +end + +---------------------------------------- +Addon.UIElementsLib._TitledDropDownMenuButton = {} +---------------------------------------- + +Addon.UIElementsLib._TitledDropDownMenuButton.New = Addon.UIElementsLib._DropDownMenuButton.New + +function Addon.UIElementsLib._TitledDropDownMenuButton:Construct(pParent, pMenuFunc, pWidth) + self:Inherit(Addon.UIElementsLib._DropDownMenuButton, pParent, pMenuFunc, pWidth or 150) + + self.LeftTexture = self:CreateTexture(nil, "ARTWORK") + self.LeftTexture:SetWidth(25) + self.LeftTexture:SetHeight(64) + self.LeftTexture:SetPoint("TOPRIGHT", self, "TOPLEFT", 1, 19) + self.LeftTexture:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame") + self.LeftTexture:SetTexCoord(0, 0.1953125, 0, 1) + + self.RightTexture = self:CreateTexture(nil, "ARTWORK") + self.RightTexture:SetWidth(25) + self.RightTexture:SetHeight(64) + self.RightTexture:SetPoint("TOP", self.LeftTexture, "TOP") + self.RightTexture:SetPoint("LEFT", self, "RIGHT", -9, 0) + self.RightTexture:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame") + self.RightTexture:SetTexCoord(0.8046875, 1, 0, 1) + + self.MiddleTexture = self:CreateTexture(nil, "ARTWORK") + self.MiddleTexture:SetPoint("TOPLEFT", self.LeftTexture, "TOPRIGHT") + self.MiddleTexture:SetPoint("BOTTOMRIGHT", self.RightTexture, "BOTTOMLEFT") + self.MiddleTexture:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame") + self.MiddleTexture:SetTexCoord(0.1953125, 0.8046875, 0, 1) + + self.Text = self:CreateFontString(self:GetName().."Text", "ARTWORK", "GameFontHighlightSmall") + self.Text:SetJustifyH("RIGHT") + self.Text:SetHeight(18) + self.Text:SetPoint("RIGHT", self.MiddleTexture, "RIGHT", -18, 1) + self.Text:SetPoint("LEFT", self.MiddleTexture, "LEFT", 0, 1) + + self.Title = self:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall") + self.Title:SetPoint("RIGHT", self.MiddleTexture, "LEFT", -11, 1) +end + +function Addon.UIElementsLib._TitledDropDownMenuButton:SetTitle(pTitle) + self.Title:SetText(pTitle) +end + +function Addon.UIElementsLib._TitledDropDownMenuButton:SetCurrentValueText(pText) + self.Text:SetText(pText) +end + +function Addon.UIElementsLib._TitledDropDownMenuButton:SetSelectedValue(value) + if self.selectedValue == value then + return + end + + self.Inherited.SetSelectedValue(self, value) + + self:RefreshItems() + + local text = self.items:GetTitleForValue(value) or "" + self:SetCurrentValueText(text) +end + +---------------------------------------- +Addon.UIElementsLib._Section = {} +---------------------------------------- + +function Addon.UIElementsLib._Section:New(pParent, pTitle) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._Section:Construct(pParent, pTitle) + self:SetBackdrop({ + bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", + edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", + tile = true, tileSize = 16, edgeSize = 16, + insets = {left = 3, right = 3, top = 3, bottom = 3}}) + + self:SetBackdropColor(1, 1, 1, 0.2) + + self.Title = self:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") + self.Title:SetPoint("TOPLEFT", self, "TOPLEFT", 10, -7) + self.Title:SetText(pTitle) +end + +---------------------------------------- +Addon.UIElementsLib._ContextMenu = {} +---------------------------------------- + +function Addon.UIElementsLib._ContextMenu:ToggleMenu(frame) + PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON) + + -- Hide the menu and leave if it's currently up + if self.dropDownMenu then + self.dropDownMenu:Hide() + self.dropDownMenu = nil + return + end + + -- Position the menu + self.relativeTo = frame + self.point = "TOPLEFT" + self.relativePoint = self.AnchorRelativePoint or "BOTTOMLEFT" + self.xOffset = 0 + self.yOffset = 0 + + -- Get the items + self.items = Addon:New(Addon.UIElementsLib._DropDownMenuItems, function () + Addon.SchedulerLib:ScheduleTask(0.1, function () + self.dropDownMenu:Hide() + self.dropDownMenu = nil + end) + end) + self:AddItems(self.items) + + -- Show the menu + self.dropDownMenu = Addon:New(Addon.UIElementsLib._DropDownMenu) + self.items.selectedValue = self.selectedValue + self.dropDownMenu:Show(self.items, self.point, self.relativeTo, self.relativePoint, self.xOffset, self.yOffset) + + -- Propagate value change messages for those menus using the stateful idiom + self.items.DidSelectItemWithValue = function (menu, value) + self:DidSelectItemWithValue(value) + end +end + +function Addon.UIElementsLib._ContextMenu:AddItems(menu) + menu:AddItemWithValue("Test 1", "TEST1") + menu:AddItemWithValue("Test 2", "TEST2") + menu:AddItemWithValue("Test 3", "TEST3") +end + +---------------------------------------- +Addon.UIElementsLib._EditBox = {} +---------------------------------------- + +function Addon.UIElementsLib._EditBox:New(pParent, pLabel, pMaxLetters, pWidth, pPlain) + return CreateFrame("EditBox", nil, pParent) +end + +function Addon.UIElementsLib._EditBox:Construct(pParent, pLabel, pMaxLetters, pWidth, pPlain) + self.Enabled = true + + self.cursorOffset = 0 + self.cursorHeight = 0 + + self:SetWidth(pWidth or 150) + self:SetHeight(25) + + self:SetFontObject(ChatFontNormal) + + self:SetMultiLine(false) + self:EnableMouse(true) + self:SetAutoFocus(false) + self:SetMaxLetters(pMaxLetters or 200) + + if not pPlain then + self.LeftTexture = self:CreateTexture(nil, "BACKGROUND") + self.LeftTexture:SetTexture("Interface\\Common\\Common-Input-Border") + self.LeftTexture:SetWidth(8) + self.LeftTexture:SetHeight(20) + self.LeftTexture:SetPoint("LEFT", self, "LEFT", -5, 0) + self.LeftTexture:SetTexCoord(0, 0.0625, 0, 0.625) + + self.RightTexture = self:CreateTexture(nil, "BACKGROUND") + self.RightTexture:SetTexture("Interface\\Common\\Common-Input-Border") + self.RightTexture:SetWidth(8) + self.RightTexture:SetHeight(20) + self.RightTexture:SetPoint("RIGHT", self, "RIGHT", 0, 0) + self.RightTexture:SetTexCoord(0.9375, 1, 0, 0.625) + + self.MiddleTexture = self:CreateTexture(nil, "BACKGROUND") + self.MiddleTexture:SetHeight(20) + self.MiddleTexture:SetTexture("Interface\\Common\\Common-Input-Border") + self.MiddleTexture:SetPoint("LEFT", self.LeftTexture, "RIGHT") + self.MiddleTexture:SetPoint("RIGHT", self.RightTexture, "LEFT") + self.MiddleTexture:SetTexCoord(0.0625, 0.9375, 0, 0.625) + + self.Title = self:CreateFontString(nil, "BACKGROUND", "GameFontNormalSmall") + self.Title:SetJustifyH("RIGHT") + self.Title:SetPoint("RIGHT", self, "TOPLEFT", -10, -13) + self.Title:SetText(pLabel or "") + end + + self:SetScript("OnEscapePressed", function (self) self:ClearFocus() end) + self:SetScript("OnEditFocusLost", self.EditFocusLost) + self:SetScript("OnEditFocusGained", self.EditFocusGained) + self:SetScript("OnTabPressed", self.OnTabPressed) + self:SetScript("OnChar", self.OnChar) + self:SetScript("OnCharComposition", self.OnCharComposition) + self:SetScript("OnTextChanged", self.OnTextChanged) + + self:LinkIntoTabChain(pParent) +end + +function Addon.UIElementsLib._EditBox:SetEnabled(pEnabled) + self.Enabled = pEnabled + + if not pEnabled then + self:ClearFocus() + end + + self:EnableMouse(pEnabled) + self:SetAlpha(pEnabled and 1.0 or 0.5) +end + +function Addon.UIElementsLib._EditBox:SetAnchorMode(pMode) + self.Title:ClearAllPoints() + self:ClearAllPoints() + + if pMode == "TITLE" then + self:SetPoint("TOPLEFT", self.Title, "RIGHT", 10, 12) + else + self.Title:SetPoint("RIGHT", self, "TOPLEFT", -10, -13) + end +end + +function Addon.UIElementsLib._EditBox:EditFocusLost() + self.HaveKeyboardFocus = nil + self.TextHasChanged = nil + self:HighlightText(0, 0) +end + +function Addon.UIElementsLib._EditBox:EditFocusGained() + self.HaveKeyboardFocus = true + self.TextHasChanged = nil + self:HighlightText() +end + +function Addon.UIElementsLib._EditBox:SetAutoCompleteFunc(pFunction) + self.AutoCompleteFunc = pFunction +end + +function Addon.UIElementsLib._EditBox:OnChar() + if not self:IsInIMECompositionMode() then + self:OnCharComposition() + end + self.TextHasChanged = self:GetText() ~= self.OrigText +end + +function Addon.UIElementsLib._EditBox:OnCharComposition() + if self.AutoCompleteFunc then + self:AutoCompleteFunc() + end + self.TextHasChanged = self:GetText() ~= self.OrigText +end + +function Addon.UIElementsLib._EditBox:SetText(pText, ...) + self.TextHasChanged = nil + self.OrigText = tostring(pText) + + self.Inherited.SetText(self, pText, ...) +end + +function Addon.UIElementsLib._EditBox:OnTextChanged() + local vText = self:GetText() + + self.TextHasChanged = vText ~= self.OrigText + + if self.EmptyText then + if string.trim(vText) == "" then + self.EmptyText:Show() + else + self.EmptyText:Hide() + end + end +end + +function Addon.UIElementsLib._EditBox:LinkIntoTabChain(pParent) + local vTabParent = pParent + + while vTabParent.TabParent do + vTabParent = vTabParent.TabParent + end + + self.NextEditBox = vTabParent.FirstEditBox + self.PrevEditBox = vTabParent.LastEditBox + + if vTabParent.LastEditBox then + vTabParent.LastEditBox.NextEditBox = self + end + + vTabParent.LastEditBox = self + + if vTabParent.FirstEditBox then + vTabParent.FirstEditBox.PrevEditBox = self + else + vTabParent.FirstEditBox = self + end +end + +function Addon.UIElementsLib._EditBox:OnTabPressed() + local vReverse = IsShiftKeyDown() + local vEditBox = self + + for vIndex = 1, 50 do + local vNextEditBox + + if vReverse then + vNextEditBox = vEditBox.PrevEditBox + else + vNextEditBox = vEditBox.NextEditBox + end + + if not vNextEditBox then + self:SetFocus() + return + end + + if vNextEditBox:IsVisible() + and not vNextEditBox.isDisabled then + vNextEditBox:SetFocus() + return + end + + vEditBox = vNextEditBox + end +end + +function Addon.UIElementsLib._EditBox:SetVertexColor(pRed, pGreen, pBlue, pAlpha) + self.LeftTexture:SetVertexColor(pRed, pGreen, pBlue, pAlpha) + self.MiddleTexture:SetVertexColor(pRed, pGreen, pBlue, pAlpha) + self.RightTexture:SetVertexColor(pRed, pGreen, pBlue, pAlpha) +end + +function Addon.UIElementsLib._EditBox:SetEmptyText(pText) + if not self.EmptyText then + self.EmptyText = self:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + self.EmptyText:SetPoint("LEFT", self, "LEFT") + self.EmptyText:SetPoint("RIGHT", self, "RIGHT") + self.EmptyText:SetJustifyH("LEFT") + self.EmptyText:SetTextColor(1, 1, 1, 0.5) + end + + self.EmptyText:SetText(pText) +end + +---------------------------------------- +Addon.UIElementsLib._DatePicker = {} +---------------------------------------- + +function Addon.UIElementsLib._DatePicker:New(parent, title) + return CreateFrame("Frame", nil, parent) +end + +function Addon.UIElementsLib._DatePicker:Construct(parent, title) + self.Enabled = true + + -- Month menu + self.MonthMenu = Addon:New(Addon.UIElementsLib._TitledDropDownMenuButton, self, + function (menu) + menu:AddSingleChoiceGroup(nil, + { + {title = Addon.CALENDAR_MONTH_NAMES[1], value = 1}, + {title = Addon.CALENDAR_MONTH_NAMES[2], value = 2}, + {title = Addon.CALENDAR_MONTH_NAMES[3], value = 3}, + {title = Addon.CALENDAR_MONTH_NAMES[4], value = 4}, + {title = Addon.CALENDAR_MONTH_NAMES[5], value = 5}, + {title = Addon.CALENDAR_MONTH_NAMES[6], value = 6}, + {title = Addon.CALENDAR_MONTH_NAMES[7], value = 7}, + {title = Addon.CALENDAR_MONTH_NAMES[8], value = 8}, + {title = Addon.CALENDAR_MONTH_NAMES[9], value = 9}, + {title = Addon.CALENDAR_MONTH_NAMES[10], value = 10}, + {title = Addon.CALENDAR_MONTH_NAMES[11], value = 11}, + {title = Addon.CALENDAR_MONTH_NAMES[12], value = 12}, + }, + function () + return self.month + end, + function (value) + self.month = value + self.MonthMenu:SetSelectedValue(value) + self:ValidateDay() + self:DateValueChanged() + end + ) + end) + self.MonthMenu:SetWidth(120) + + -- Year menu + self.YearMenu = Addon:New(Addon.UIElementsLib._TitledDropDownMenuButton, self, + function (menu) + local currentDate = C_Calendar.GetDate() + menu:AddSingleChoiceGroup(nil, + { + {title = currentDate.year, value = currentDate.year}, + {title = currentDate.year + 1, value = currentDate.year + 1} + }, + function () + return self.year + end, + function (value) + self.year = value + self.YearMenu:SetSelectedValue(value) + self:ValidateDay() + self:DateValueChanged() + end + ) + end) + self.YearMenu:SetWidth(75) + + -- Day menu + self.DayMenu = Addon:New(Addon.UIElementsLib._TitledDropDownMenuButton, self, + function (menu) + local numDays = Addon.DateLib:GetDaysInMonth(self.month, self.year) + if not numDays then + return + end + + for day = 1, numDays do + local item = menu:AddToggle(day, + function () + return self.day == day + end, + function () + self.day = day + self.DayMenu:SetSelectedValue(day) + self:DateValueChanged() + end + ) + item.value = day + end + end) + self.DayMenu:SetWidth(55) + + -- Layout the menus based on locale + + if string.sub(GetLocale(), -2) == "US" then + self.MonthMenu:SetPoint("LEFT", self, "LEFT") + self.DayMenu:SetPoint("LEFT", self.MonthMenu, "RIGHT", 8, 0) + self.YearMenu:SetPoint("LEFT", self.DayMenu, "RIGHT", 8, 0) + + self.LeftMenu = self.MonthMenu + else + self.DayMenu:SetPoint("LEFT", self, "LEFT") + self.MonthMenu:SetPoint("LEFT", self.DayMenu, "RIGHT", 8, 0) + self.YearMenu:SetPoint("LEFT", self.MonthMenu, "RIGHT", 8, 0) + + self.LeftMenu = self.DayMenu + end + + self:SetWidth(self.MonthMenu:GetWidth() + self.DayMenu:GetWidth() + self.YearMenu:GetWidth() + 16) + self:SetHeight(self.MonthMenu:GetHeight()) + + -- + + self:SetLabel(title or "") +end + +function Addon.UIElementsLib._DatePicker:SetEnabled(pEnabled) + self.Enabled = pEnabled + + self.MonthMenu:SetEnabled(pEnabled) + self.DayMenu:SetEnabled(pEnabled) + self.YearMenu:SetEnabled(pEnabled) +end + +function Addon.UIElementsLib._DatePicker:SetDate(month, day, year) + self.month = month + self.day = day + self.year = year + + if not month then + self.YearMenu:SetSelectedValue(nil) + self.MonthMenu:SetSelectedValue(nil) + self.DayMenu:SetSelectedValue(nil) + return + end + + -- Set DayMenu last so that month and year will be available for calculating + -- the number of days in the month + self.YearMenu:SetSelectedValue(year) + self.MonthMenu:SetSelectedValue(month) + self.DayMenu:SetSelectedValue(day) +end + +function Addon.UIElementsLib._DatePicker:DateValueChanged() + if self.ValueChangedFunc then + self:ValueChangedFunc() + end +end + +function Addon.UIElementsLib._DatePicker:ValidateDay() + local numDays = Addon.DateLib:GetDaysInMonth(self.MonthMenu:GetSelectedValue(), self.YearMenu:GetSelectedValue()) + + if self.DayMenu:GetSelectedValue() > numDays then + self.DayMenu:SetSelectedValue(numDays) + end +end + +function Addon.UIElementsLib._DatePicker:GetDate() + return self.month, self.day, self.year +end + +function Addon.UIElementsLib._DatePicker:SetLabel(pLabel) + self.LeftMenu:SetTitle(pLabel) +end + +---------------------------------------- +Addon.UIElementsLib._TimePicker = {} +---------------------------------------- + +function Addon.UIElementsLib._TimePicker:New(pParent, pTitle) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._TimePicker:Construct(pParent, pLabel) + self.Enabled = true + + self:SetWidth(185) + self:SetHeight(24) + + self.HourMenu = Addon:New(Addon.UIElementsLib._TitledDropDownMenuButton, self, function (menu) + if self.Use24HTime then + for hour = 0, 23 do + menu:AddItemWithValue(hour, hour) + end + else + for hour = 1, 12 do + menu:AddItemWithValue(hour, hour) + end + end + end) + self.HourMenu:SetWidth(55) + self.HourMenu:SetPoint("LEFT", self, "LEFT") + self.HourMenu.DidSelectItemWithValue = function (menu, value) + self.HourMenu:SetSelectedValue(value) + self:TimeValueChanged() + end + + self.MinuteMenu = Addon:New(Addon.UIElementsLib._TitledDropDownMenuButton, self, function (menu) + for minute = 0, 59, 5 do + menu:AddItemWithValue(string.format("%02d", minute), minute) + end + end) + self.MinuteMenu:SetWidth(55) + self.MinuteMenu:SetPoint("LEFT", self.HourMenu, "RIGHT", 8, 0) + self.MinuteMenu.DidSelectItemWithValue = function (menu, value) + self.MinuteMenu:SetSelectedValue(value) + self:TimeValueChanged() + end + + self.AMPMMenu = Addon:New(Addon.UIElementsLib._TitledDropDownMenuButton, self, function (menu) + menu:AddItemWithValue("AM", "AM") + menu:AddItemWithValue("PM", "PM") + end) + self.AMPMMenu:SetWidth(55) + self.AMPMMenu:SetPoint("LEFT", self.MinuteMenu, "RIGHT", 8, 0) + self.AMPMMenu.DidSelectItemWithValue = function (menu, value) + self.AMPMMenu:SetSelectedValue(value) + self:TimeValueChanged() + end + + self:SetLabel(pLabel or "") +end + +function Addon.UIElementsLib._TimePicker:SetEnabled(enabled) + self.Enabled = enabled + + self.HourMenu:SetEnabled(enabled) + self.MinuteMenu:SetEnabled(enabled) + self.AMPMMenu:SetEnabled(enabled) +end + +function Addon.UIElementsLib._TimePicker:SetTime(hour, minute) + self.hour = hour + self.minute = minute + + if not hour then + self.HourMenu:SetSelectedValue(nil) + self.MinuteMenu:SetSelectedValue(nil) + self.AMPMMenu:SetSelectedValue(nil) + return + end + + local displayHour = hour + + if GetCVarBool("timeMgrUseMilitaryTime") then + self.AMPMMenu:Hide() + self.Use24HTime = true + else + local ampm = "AM" + if hour == 0 then + displayHour = 12 + elseif hour == 12 then + displayHour = hour + ampm = "PM" + elseif hour > 12 then + displayHour = hour - 12 + ampm = "PM" + else + displayHour = hour + end + + if ampm == "PM" and displayHour > 12 then + displayHour = displayHour - 12 + end + + if displayHour == 0 then + displayHour = 12 + end + + self.AMPMMenu:SetSelectedValue(ampm) + self.AMPMMenu:Show() + + self.Use24HTime = false + end + + self.HourMenu:SetSelectedValue(displayHour) + self.MinuteMenu:SetSelectedValue(minute) +end + +function Addon.UIElementsLib._TimePicker:TimeValueChanged() + if self.ValueChangedFunc then + self:ValueChangedFunc() + end +end + +function Addon.UIElementsLib._TimePicker:GetTime() + local vHour, vMinute + + vHour = self.HourMenu:GetSelectedValue() + vMinute = self.MinuteMenu:GetSelectedValue() + + if not vHour or not vMinute then + return + end + + if not self.Use24HTime then + if self.AMPMMenu:GetSelectedValue() == "AM" then + if vHour == 12 then + vHour = 0 + end + else + if vHour ~= 12 then + vHour = vHour + 12 + end + end + end + + return vHour, vMinute +end + +function Addon.UIElementsLib._TimePicker:SetLabel(pLabel) + self.HourMenu:SetTitle(pLabel) +end + +---------------------------------------- +Addon.UIElementsLib._LevelRangePicker = {} +---------------------------------------- + +function Addon.UIElementsLib._LevelRangePicker:New(pParent, pLabel) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._LevelRangePicker:Construct(pParent, pLabel) + self.Enabled = true + + self.TabParent = pParent + + self:SetWidth(80) + self:SetHeight(24) + + self.MinLevel = Addon:New(Addon.UIElementsLib._EditBox, self, pLabel, 3) + self.MinLevel:SetWidth(30) + self.MinLevel:SetPoint("LEFT", self, "LEFT") + + self.MaxLevel = Addon:New(Addon.UIElementsLib._EditBox, self, Addon.cLevelRangeSeparator, 3) + self.MaxLevel:SetWidth(30) + self.MaxLevel:SetAnchorMode("TITLE") + self.MaxLevel.Title:SetPoint("LEFT", self.MinLevel, "RIGHT", 5, 0) +end + +function Addon.UIElementsLib._LevelRangePicker:SetEnabled(pEnabled) + self.Enabled = pEnabled + + self.MinLevel:SetEnabled(pEnabled) + self.MaxLevel:SetEnabled(pEnabled) +end + +function Addon.UIElementsLib._LevelRangePicker:SetLabel(pLabel) + self.MinLevel:SetTitle(pLabel) +end + +function Addon.UIElementsLib._LevelRangePicker:SetLevelRange(pMinLevel, pMaxLevel) + self.MinLevel:SetText(pMinLevel or "") + self.MaxLevel:SetText(pMaxLevel or "") +end + +function Addon.UIElementsLib._LevelRangePicker:GetLevelRange() + return tonumber(self.MinLevel:GetText()), tonumber(self.MaxLevel:GetText()) +end + +function Addon.UIElementsLib._LevelRangePicker:ClearFocus() + self.MinLevel:ClearFocus() + self.MaxLevel:ClearFocus() +end + +---------------------------------------- +Addon.UIElementsLib._PushButton = {} +---------------------------------------- + +function Addon.UIElementsLib._PushButton:New(pParent, pTitle, pWidth) + return CreateFrame("Button", nil, pParent) +end + +function Addon.UIElementsLib._PushButton:Construct(pParent, pTitle, pWidth) + self:SetWidth(pWidth or 100) + self:SetHeight(22) + + self.Text = self:CreateFontString(nil, "OVERLAY", "GameFontNormal") + self.Text:SetPoint("LEFT", self, "LEFT") + self.Text:SetPoint("RIGHT", self, "RIGHT") + self.Text:SetHeight(20) + self.Text:SetText(pTitle) + + self.LeftTexture = self:CreateTexture(nil, "BACKGROUND") + self.LeftTexture:SetWidth(12) + self.LeftTexture:SetPoint("TOPLEFT", self, "TOPLEFT") + self.LeftTexture:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT") + self.LeftTexture:SetTexCoord(0, 0.09375, 0, 0.6875) + + self.RightTexture = self:CreateTexture(nil, "BACKGROUND") + self.RightTexture:SetWidth(12) + self.RightTexture:SetPoint("TOPRIGHT", self, "TOPRIGHT") + self.RightTexture:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT") + self.RightTexture:SetTexCoord(0.53125, 0.625, 0, 0.6875) + + self.MiddleTexture = self:CreateTexture(nil, "BACKGROUND") + self.MiddleTexture:SetPoint("TOPLEFT", self.LeftTexture, "TOPRIGHT") + self.MiddleTexture:SetPoint("BOTTOMLEFT", self.LeftTexture, "BOTTOMRIGHT") + self.MiddleTexture:SetPoint("TOPRIGHT", self.RightTexture, "TOPLEFT") + self.MiddleTexture:SetPoint("BOTTOMRIGHT", self.RightTexture, "BOTTOMLEFT") + self.MiddleTexture:SetTexCoord(0.09375, 0.53125, 0, 0.6875) + + self.HighlightTexture = self:CreateTexture(nil, "HIGHLIGHT") + self.HighlightTexture:SetAllPoints() + self.HighlightTexture:SetTexCoord(0, 0.625, 0, 0.6875) + self.HighlightTexture:SetBlendMode("ADD") + + self.Down = false + self:UpdateButtonTexture() + + self:SetScript("OnMouseDown", function () + self.Down = true + self:UpdateButtonTexture() + end) + + self:SetScript("OnMouseUp", function () + self.Down = false + self:UpdateButtonTexture() + end) +end + +function Addon.UIElementsLib._PushButton:SetEnabled(pEnabled) + if pEnabled == self:IsEnabled() then + return + end + + if pEnabled then + self:Enable() + else + self:Disable() + end +end + +function Addon.UIElementsLib._PushButton:SetTitle(pTitle) + self.Text:SetText(pTitle) +end + +function Addon.UIElementsLib._PushButton:Enable() + self.Inherited.Enable(self) + self:UpdateButtonTexture() +end + +function Addon.UIElementsLib._PushButton:Disable() + self.Inherited.Disable(self) + self:UpdateButtonTexture() +end + +function Addon.UIElementsLib._PushButton:IsEnabled() + return self.Inherited.IsEnabled(self) +end + +function Addon.UIElementsLib._PushButton:UpdateButtonTexture() + if self:IsEnabled() then + self:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b) + self.HighlightTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Highlight") + + if self.Down then + self.LeftTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Down") + self.MiddleTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Down") + self.RightTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Down") + else + self.LeftTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up") + self.MiddleTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up") + self.RightTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up") + end + else + self:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b) + self.HighlightTexture:SetTexture() + + if self.Down then + self.LeftTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled-Down") + self.MiddleTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled-Down") + self.RightTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled-Down") + else + self.LeftTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled") + self.MiddleTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled") + self.RightTexture:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled") + end + end +end + +function Addon.UIElementsLib._PushButton:SetTextColor(pRed, pGreen, pBlue, pAlpha) + self.Text:SetTextColor(pRed, pGreen, pBlue, pAlpha) +end + +---------------------------------------- +Addon.UIElementsLib._ScrollingEditBox = {} +---------------------------------------- + +function Addon.UIElementsLib._ScrollingEditBox:New(pParent, pLabel, pMaxLetters, pWidth, pHeight) + return CreateFrame("Frame", nil, pParent) +end + +Addon.UIElementsLib._ScrollingEditBox.InputFieldTextureInfo = +{ + TopLeft = {Width = 5, Height = 5, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0, Right = 0.0390625, Top = 0, Bottom = 0.15625}}, + TopCenter = {Width = 118, Height = 5, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0.0390625, Right = 0.9609375, Top = 0, Bottom = 0.15625}}, + TopRight = {Width = 5, Height = 5, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0.9609375, Right = 1, Top = 0, Bottom = 0.15625}}, + MiddleLeft = {Width = 5, Height = 10, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0, Right = 0.0390625, Top = 0.15625, Bottom = 0.46875}}, + MiddleCenter = {Width = 118, Height = 10, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0.0390625, Right = 0.9609375, Top = 0.15625, Bottom = 0.46875}}, + MiddleRight = {Width = 5, Height = 10, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0.9609375, Right = 1, Top = 0.15625, Bottom = 0.46875}}, + BottomLeft = {Width = 5, Height = 5, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0, Right = 0.0390625, Top = 0.46875, Bottom = 0.625}}, + BottomCenter = {Width = 118, Height = 5, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0.0390625, Right = 0.9609375, Top = 0.46875, Bottom = 0.625}}, + BottomRight = {Width = 5, Height = 5, Path = "Interface\\Common\\Common-Input-Border", Coords = {Left = 0.9609375, Right = 1, Top = 0.46875, Bottom = 0.625}}, +} + +function Addon.UIElementsLib._ScrollingEditBox:Construct(pParent, pLabel, pMaxLetters, pWidth, pHeight) + self.Enabled = true + + self:SetWidth(pWidth or 150) + self:SetHeight(pHeight or 60) + + self.Title = self:CreateFontString(nil, "BACKGROUND", "GameFontNormalSmall") + self.Title:SetJustifyH("RIGHT") + self.Title:SetPoint("RIGHT", self, "TOPLEFT", -10, -9) + self.Title:SetText(pLabel or "") + + self.BackgroundTextures = CreateFrame("Frame", nil, self) + self.BackgroundTextures:SetPoint("TOPLEFT", self, "TOPLEFT", -4, 4) + self.BackgroundTextures:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, -4) + Addon.Inherit(self.BackgroundTextures, Addon.UIElementsLib._StretchTextures, self.InputFieldTextureInfo, self.BackgroundTextures, "BORDER") + + self.ScrollbarTrench = Addon:New(Addon.UIElementsLib._ScrollbarTrench, self) + self.ScrollbarTrench:SetPoint("TOPRIGHT", self, "TOPRIGHT", 0, 1) + self.ScrollbarTrench:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, -2) + + self.Scrollbar = Addon:New(Addon.UIElementsLib._Scrollbar, self) + self.Scrollbar:SetPoint("TOP", self.ScrollbarTrench, "TOP", 0, -19) + self.Scrollbar:SetPoint("BOTTOM", self.ScrollbarTrench, "BOTTOM", 0, 17) + self.Scrollbar:SetFrameLevel(self.ScrollbarTrench:GetFrameLevel() + 1) + self.Scrollbar:SetScript("OnValueChanged", function (pScrollbar, pValue) + self.ScrollFrame:SetVerticalScroll(pValue) + end) + + -- + + local vScrollFrameName = "MC2UIElementsLibScrollFrame"..MC2UIElementsLib.ScrollFrameIndex + MC2UIElementsLib.ScrollFrameIndex = MC2UIElementsLib.ScrollFrameIndex + 1 + + self.ScrollFrame = CreateFrame("ScrollFrame", vScrollFrameName, self) + self.ScrollFrame:SetWidth(self:GetWidth() - self.ScrollbarTrench:GetWidth()) + self.ScrollFrame:SetHeight(self:GetHeight()) + self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT") + self.ScrollFrame:EnableMouseWheel(1) + self.ScrollFrame:SetScript("OnVerticalScroll", function (pScrollFrame, pOffset) + self.Scrollbar:SetValue(pOffset) + end) + self.ScrollFrame:SetScript("OnScrollRangeChanged", function (pScrollFrame, pHorizRange, pVertRange) + if not pVertRange then + pVertRange = self:GetVerticalScrollRange() + end + + self.Scrollbar:SetMinMaxValues(0, pVertRange) + + local vValue = self.Scrollbar:GetValue() + + if vValue > pVertRange then + vValue = pVertRange + self.Scrollbar:SetValue(vValue) + end + end) + self.ScrollFrame:SetScript("OnMouseWheel", function (pScrollFrame, pDelta) + local vDistance = pScrollFrame:GetHeight() * 0.5 + local vValue = self.Scrollbar:GetValue() + + if pDelta > 0 then -- Scroll up + self.Scrollbar:SetValue(vValue - vDistance) + else + self.Scrollbar:SetValue(vValue + vDistance) + end + end) + + -- + + self.ScrollChildFrame = CreateFrame("Frame", nil, self.ScrollFrame) + self.ScrollChildFrame:SetWidth(self.ScrollFrame:GetWidth()) + self.ScrollChildFrame:SetHeight(self.ScrollFrame:GetHeight()) + self.ScrollChildFrame:SetPoint("TOPLEFT", self.ScrollFrame, "TOPLEFT") + self.ScrollChildFrame.TabParent = pParent + + self.EditBox = Addon:New(Addon.UIElementsLib._EditBox, self.ScrollChildFrame, nil, pMaxLetters or 200, self.ScrollChildFrame:GetWidth(), true) + self.EditBox:SetHeight(self.ScrollChildFrame:GetHeight()) + self.EditBox:SetPoint("TOPLEFT", self.ScrollChildFrame, "TOPLEFT", 0, 0) + self.EditBox:SetPoint("TOPRIGHT", self.ScrollChildFrame, "TOPRIGHT", 0, 0) + self.EditBox:SetFontObject(ChatFontNormal) + self.EditBox:SetMultiLine(true) + self.EditBox:EnableMouse(true) + self.EditBox:SetAutoFocus(false) + Addon:HookScript(self.EditBox, "OnTextChanged", function (pEditBox) + self:UpdateLimitText() + ScrollingEdit_OnTextChanged(pEditBox, self.ScrollFrame) + end) + Addon:HookScript(self.EditBox, "OnCursorChanged", function (pEditBox, pCol, pRow, pWidth, pHeight) + ScrollingEdit_OnCursorChanged(pEditBox, pCol, pRow - 10, pWidth, pHeight) + end) + Addon:HookScript(self.EditBox, "OnUpdate", function (pEditBox, pElapsed) + ScrollingEdit_OnUpdate(pEditBox, pElapsed, self.ScrollFrame) + end) + + self.ScrollFrame:SetScrollChild(self.ScrollChildFrame) + + self:EnableMouse(true) + self:SetScript("OnMouseDown", function () if self.EditBox.Enabled then self.EditBox:SetFocus() end end) +end + +function Addon.UIElementsLib._ScrollingEditBox:SetEnabled(pEnabled) + self.Enabled = pEnabled + self.EditBox:SetEnabled(pEnabled) + + self:SetAlpha(pEnabled and 1 or 0.5) +end + +function Addon.UIElementsLib._ScrollingEditBox:GetText() + return self.EditBox:GetText() +end + +function Addon.UIElementsLib._ScrollingEditBox:SetText(pText) + self.EditBox:SetText(pText) +end + +function Addon.UIElementsLib._ScrollingEditBox:ShowLimitText() + if self.LimitText then + return + end + + self.LimitText = self:CreateFontString(nil, "BACKGROUND", "GameFontNormalSmall") + self.LimitText:SetJustifyH("RIGHT") + self.LimitText:SetPoint("TOPRIGHT", self.Title, "BOTTOMRIGHT") + + self:UpdateLimitText() +end + +function Addon.UIElementsLib._ScrollingEditBox:UpdateLimitText() + if not self.LimitText then + return + end + + local vCurLength = self:GetText():len() + local vMaxLength = self.EditBox:GetMaxLetters() + + self.LimitText:SetText(vCurLength.."/"..vMaxLength) + + -- Figure out the amount used in the description and color progress based on percentage + + local vPercentUsed = vCurLength / vMaxLength + + if vPercentUsed <= 0.75 then + self.LimitText:SetVertexColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b) + elseif vCurLength < vMaxLength then + self.LimitText:SetVertexColor(0.9, 0.9, 0.05) -- Yellow + else + self.LimitText:SetVertexColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b) + end +end + +function Addon.UIElementsLib._ScrollingEditBox:ClearFocus() + self.EditBox:ClearFocus() +end + +---------------------------------------- +Addon.UIElementsLib._ProgressBar = {} +---------------------------------------- + +function Addon.UIElementsLib._ProgressBar:New(pParent) + return CreateFrame("StatusBar", nil, pParent) +end + +function Addon.UIElementsLib._ProgressBar:Construct() + self:SetHeight(20) + + self.LabelText = self:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") + self.LabelText:SetPoint("TOPLEFT", self, "TOPLEFT") + self.LabelText:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT") + self.LabelText:SetJustifyH("LEFT") + self.LabelText:SetJustifyV("MIDDLE") + + self:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar") + self:SetStatusBarColor(1, 0.7, 0) + + self:SetMinMaxValues(0, 1) + self:SetValue(0) +end + +function Addon.UIElementsLib._ProgressBar:SetText(pText) + self.LabelText:SetText(pText) +end + +function Addon.UIElementsLib._ProgressBar:SetProgress(pProgress) + if pProgress then + self:SetValue(pProgress) + else + self:SetValue(0) + end +end + +---------------------------------------- +Addon.UIElementsLib._PowerDot = {} +---------------------------------------- + +function Addon.UIElementsLib._PowerDot:New(pParent) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._PowerDot:Construct(pParent) + local vAlphaAnimation + + self.Value = nil + + self:SetWidth(21) + self:SetHeight(21) + + self.BackgroundTexture = self:CreateTexture(nil, "BACKGROUND") + self.BackgroundTexture:SetTexture("Interface\\PlayerFrame\\MonkUI") + self.BackgroundTexture:SetTexCoord(0.09375000, 0.17578125, 0.71093750, 0.87500000) + self.BackgroundTexture:SetWidth(21) + self.BackgroundTexture:SetHeight(21) + self.BackgroundTexture:SetPoint("CENTER", self, "CENTER", 0, 0) + + self.OnTexture = self:CreateTexture(nil, "ARTWORK") + self.OnTexture:SetTexture("Interface\\PlayerFrame\\MonkUI") + self.OnTexture:SetTexCoord(0.00390625, 0.08593750, 0.71093750, 0.87500000) + self.OnTexture:SetWidth(21) + self.OnTexture:SetHeight(21) + self.OnTexture:SetPoint("CENTER", self, "CENTER", 0, 0) + self.OnTexture:SetAlpha(0) -- initially off + + -- Fade in + self.activate = self.OnTexture:CreateAnimationGroup("activate") + vAlphaAnimation = self.activate:CreateAnimation("Alpha") + vAlphaAnimation:SetFromAlpha(0) + vAlphaAnimation:SetToAlpha(1) + vAlphaAnimation:SetDuration(0.2) + vAlphaAnimation:SetOrder(1) + + -- Fade out + self.deactivate = self.OnTexture:CreateAnimationGroup("deactivate") + vAlphaAnimation = self.deactivate:CreateAnimation("Alpha") + vAlphaAnimation:SetFromAlpha(1) + vAlphaAnimation:SetToAlpha(0) + vAlphaAnimation:SetDuration(0.3) + vAlphaAnimation:SetOrder(2) +end + +function Addon.UIElementsLib._PowerDot:SetValue(pValue) + -- normalize the value + pValue = pValue and true or nil + + -- return if the value isn't changing + if pValue == self.Value then return end + + if pValue then + if self.deactivate:IsPlaying() then self.deactivate:Stop() end + if not self.activate:IsPlaying() then self.activate:Play() end + else + if self.activate:IsPlaying() then self.activate:Stop() end + if not self.deactivate:IsPlaying() then self.deactivate:Play() end + end +end + +---------------------------------------- +Addon.UIElementsLib._PowerDots = {} +---------------------------------------- + +function Addon.UIElementsLib._PowerDots:New(pParent) + return CreateFrame("Frame", nil, pParent) +end + +function Addon.UIElementsLib._PowerDots:Construct() + self.MaxValue = 0 + self.Dots = {} +end + +function Addon.UIElementsLib._PowerDots:SetMax(pMax) + self.MaxValue = pMax + while #self.Dots < self.MaxValue do + table.insert(self.Dots, Addon:New(Addon.UIElementsLib._PowerDot, self)) + end + self:LayoutDots() +end + +function Addon.UIElementsLib._PowerDots:LayoutDots() + local vLeft = 0 + local vSpacing = 5 + for vIndex = 1, self.MaxValue do + local vDot = self.Dots[vIndex] + vDot:ClearAllPoints() + vDot:SetPoint("LEFT", self, "LEFT", vLeft, 0) + vDot:Show() + vLeft = vLeft + vDot:GetWidth() + vSpacing + end + -- Hide unused dots + for vIndex = self.MaxValue + 1, #self.Dots do + self.Dots[vIndex]:Hide() + end +end + +function Addon.UIElementsLib._PowerDots:SetValue(pValue) + for vIndex = 1, self.MaxValue do + local vDot = self.Dots[vIndex] + vDot:SetValue(vIndex <= pValue) + end +end diff --git a/Mappy.lua b/Mappy.lua index 5d5422a..9d1d0e4 100755 --- a/Mappy.lua +++ b/Mappy.lua @@ -340,7 +340,7 @@ function Mappy:InitializeMinimap() end function Mappy:InitializeAttachedFrames() - local attachmenFrame = CreateFrame("Frame", "MappyAttachmentFrame", UIParent, "SecureFrameTemplate") + local attachmenFrame = CreateFrame("Frame", "MappyAttachmentFrame", UIParent, "SecureFrameTemplate", BackdropTemplateMixin and "BackdropTemplate") self.AttachmentFrame = attachmenFrame -- Give it an initial position @@ -723,6 +723,9 @@ function Mappy:InitializeDragging() end function Mappy:AdjustBackgroundStyle() + if not MinimapBackdrop.SetBackdrop then + Mixin(MinimapBackdrop, BackdropTemplateMixin) + end if self.CurrentProfile.HideBorder then MinimapBackdrop:SetBackdropBorderColor(0.75, 0.75, 0.75, 0.0) MinimapBackdrop:SetBackdropColor(0.15, 0.15, 0.15, 0.0, 0.0) @@ -736,6 +739,9 @@ function Mappy:InitializeSquareShape() Minimap:SetMaskTexture("Interface\\Addons\\Mappy\\Textures\\MinimapMask") MinimapBorder:SetTexture(nil) + if not MinimapBackdrop.SetBackdrop then + Mixin(MinimapBackdrop, BackdropTemplateMixin) + end MinimapBackdrop:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", @@ -2398,7 +2404,7 @@ Mappy._OptionsPanel = {} ---------------------------------------- function Mappy._OptionsPanel:New(pParent) - return CreateFrame("Frame", nil, pParent) + return CreateFrame("Frame", nil, pParent, BackdropTemplateMixin and "BackdropTemplate") end function Mappy._OptionsPanel:Construct(pParent) @@ -2413,7 +2419,7 @@ function Mappy._OptionsPanel:Construct(pParent) -- Size slider - self.SizeSlider = CreateFrame("Slider", "MappySizeSlider", self, "OptionsSliderTemplate") + self.SizeSlider = CreateFrame("Slider", "MappySizeSlider", self, "OptionsSliderTemplate", BackdropTemplateMixin and "BackdropTemplate") self.SizeSlider:SetWidth(380) self.SizeSlider:SetPoint("TOPLEFT", self.Title, "BOTTOMLEFT", 0, -15) self.SizeSlider:SetMinMaxValues(80, 1000) @@ -2424,7 +2430,7 @@ function Mappy._OptionsPanel:Construct(pParent) -- Alpha slider - self.AlphaSlider = CreateFrame("Slider", "MappyAlphaSlider", self, "OptionsSliderTemplate") + self.AlphaSlider = CreateFrame("Slider", "MappyAlphaSlider", self, "OptionsSliderTemplate", BackdropTemplateMixin and "BackdropTemplate") self.AlphaSlider:SetWidth(180) self.AlphaSlider:SetPoint("TOPLEFT", self.SizeSlider, "BOTTOMLEFT", 0, -30) self.AlphaSlider:SetScript("OnValueChanged", function (self) Mappy:SetMinimapAlpha(self:GetValue()) end) @@ -2433,7 +2439,7 @@ function Mappy._OptionsPanel:Construct(pParent) -- Combat alpha slider - self.CombatAlphaSlider = CreateFrame("Slider", "MappyCombatAlphaSlider", self, "OptionsSliderTemplate") + self.CombatAlphaSlider = CreateFrame("Slider", "MappyCombatAlphaSlider", self, "OptionsSliderTemplate", BackdropTemplateMixin and "BackdropTemplate") self.CombatAlphaSlider:SetWidth(180) self.CombatAlphaSlider:SetPoint("TOPLEFT", self.AlphaSlider, "TOPRIGHT", 20, 0) self.CombatAlphaSlider:SetScript("OnValueChanged", function (self) Mappy:SetMinimapCombatAlpha(self:GetValue()) end) @@ -2442,7 +2448,7 @@ function Mappy._OptionsPanel:Construct(pParent) -- Movement alpha slider - self.MovingAlphaSlider = CreateFrame("Slider", "MappyMovingAlphaSlider", self, "OptionsSliderTemplate") + self.MovingAlphaSlider = CreateFrame("Slider", "MappyMovingAlphaSlider", self, "OptionsSliderTemplate", BackdropTemplateMixin and "BackdropTemplate") self.MovingAlphaSlider:SetWidth(180) self.MovingAlphaSlider:SetPoint("TOPLEFT", self.CombatAlphaSlider, "TOPRIGHT", 20, 0) self.MovingAlphaSlider:SetScript("OnValueChanged", function (self) Mappy:SetMinimapMovingAlpha(self:GetValue()) end) @@ -2451,67 +2457,67 @@ function Mappy._OptionsPanel:Construct(pParent) -- Hide coordinates - self.HideCoordinatesCheckbutton = CreateFrame("Checkbutton", "MappyHideCoordinatesCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideCoordinatesCheckbutton = CreateFrame("Checkbutton", "MappyHideCoordinatesCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideCoordinatesCheckbutton:SetPoint("TOPLEFT", self.AlphaSlider, "TOPLEFT", -5, -45) self.HideCoordinatesCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideCoordinates(self:GetChecked()) end) MappyHideCoordinatesCheckbuttonText:SetText("Hide coordinates") -- Hide zone name - self.HideZoneNameCheckbutton = CreateFrame("Checkbutton", "MappyHideZoneNameCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideZoneNameCheckbutton = CreateFrame("Checkbutton", "MappyHideZoneNameCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideZoneNameCheckbutton:SetPoint("TOPLEFT", self.HideCoordinatesCheckbutton, "TOPLEFT", 0, -25) self.HideZoneNameCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideZoneName(self:GetChecked()) end) MappyHideZoneNameCheckbuttonText:SetText("Hide zone name") -- Hide North arrow - self.HideNorthLabelCheckbutton = CreateFrame("Checkbutton", "MappyHideNorthLabelCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideNorthLabelCheckbutton = CreateFrame("Checkbutton", "MappyHideNorthLabelCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideNorthLabelCheckbutton:SetPoint("TOPLEFT", self.HideZoneNameCheckbutton, "TOPLEFT", 0, -25) self.HideNorthLabelCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideNorthLabel(self:GetChecked()) end) MappyHideNorthLabelCheckbuttonText:SetText("Hide North label") -- Hide background - self.HideBorderCheckbutton = CreateFrame("Checkbutton", "MappyHideBorderCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideBorderCheckbutton = CreateFrame("Checkbutton", "MappyHideBorderCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideBorderCheckbutton:SetPoint("TOPLEFT", self.HideNorthLabelCheckbutton, "TOPLEFT", 0, -25) self.HideBorderCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideBorder(self:GetChecked()) end) MappyHideBorderCheckbuttonText:SetText("Hide border") -- Flash gathering nodes - self.FlashGatherNodesCheckbutton = CreateFrame("Checkbutton", "MappyFlashGatherNodesCheckbutton", self, "OptionsCheckButtonTemplate") + self.FlashGatherNodesCheckbutton = CreateFrame("Checkbutton", "MappyFlashGatherNodesCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.FlashGatherNodesCheckbutton:SetPoint("TOPLEFT", self.HideBorderCheckbutton, "TOPLEFT", 0, -40) self.FlashGatherNodesCheckbutton:SetScript("OnClick", function (self) Mappy:SetFlashGatherNodes(self:GetChecked()) end) MappyFlashGatherNodesCheckbuttonText:SetText("Flash gathering nodes") -- Large gathering nodes - self.LargeGatherNodesCheckbutton = CreateFrame("Checkbutton", "MappyLargeGatherNodesCheckbutton", self, "OptionsCheckButtonTemplate") + self.LargeGatherNodesCheckbutton = CreateFrame("Checkbutton", "MappyLargeGatherNodesCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.LargeGatherNodesCheckbutton:SetPoint("TOPLEFT", self.FlashGatherNodesCheckbutton, "TOPLEFT", 0, -25) self.LargeGatherNodesCheckbutton:SetScript("OnClick", function (self) Mappy:SetLargeGatherNodes(self:GetChecked()) end) MappyLargeGatherNodesCheckbuttonText:SetText("Large gathering nodes") -- Lock position - self.LockPositionCheckbutton = CreateFrame("Checkbutton", "MappyLockPositionCheckbutton", self, "OptionsCheckButtonTemplate") + self.LockPositionCheckbutton = CreateFrame("Checkbutton", "MappyLockPositionCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.LockPositionCheckbutton:SetPoint("TOPLEFT", self.LargeGatherNodesCheckbutton, "TOPLEFT", 0, -40) self.LockPositionCheckbutton:SetScript("OnClick", function (self) Mappy:SetLockPosition(self:GetChecked()) end) MappyLockPositionCheckbuttonText:SetText("Lock position") -- Ghost - self.GhostCheckbutton = CreateFrame("Checkbutton", "MappyGhostCheckbutton", self, "OptionsCheckButtonTemplate") + self.GhostCheckbutton = CreateFrame("Checkbutton", "MappyGhostCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.GhostCheckbutton:SetPoint("TOPLEFT", self.LockPositionCheckbutton, "TOPLEFT", 0, -25) self.GhostCheckbutton:SetScript("OnClick", function (self) Mappy:SetGhost(self:GetChecked()) end) MappyGhostCheckbuttonText:SetText("Pass clicks through") -- Attached frames - self.DetachManagedFramesCheckbutton = CreateFrame("Checkbutton", "MappyDetachManagedFramesCheckbutton", self, "OptionsCheckButtonTemplate") + self.DetachManagedFramesCheckbutton = CreateFrame("Checkbutton", "MappyDetachManagedFramesCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.DetachManagedFramesCheckbutton:SetPoint("TOPLEFT", self.GhostCheckbutton, "TOPLEFT", 0, -40) self.DetachManagedFramesCheckbutton:SetScript("OnClick", function (button) Mappy:SetDetachManagedFrames(button:GetChecked()) self:OnShow() end) MappyDetachManagedFramesCheckbuttonText:SetText("Detach UI frames (quest watch, durability, etc.)") - self.LockManagedFramesCheckbutton = CreateFrame("Checkbutton", "MappyLockManagedFramesCheckbutton", self, "OptionsCheckButtonTemplate") + self.LockManagedFramesCheckbutton = CreateFrame("Checkbutton", "MappyLockManagedFramesCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.LockManagedFramesCheckbutton:SetPoint("TOPLEFT", self.DetachManagedFramesCheckbutton, "TOPLEFT", 0, -25) self.LockManagedFramesCheckbutton:SetScript("OnClick", function (button) Mappy:SetLockManagedFrames(button:GetChecked()) end) MappyLockManagedFramesCheckbuttonText:SetText("Lock UI frames position") @@ -2556,7 +2562,7 @@ Mappy._ButtonOptionsPanel = {} ---------------------------------------- function Mappy._ButtonOptionsPanel:New(pParent) - return CreateFrame("Frame", nil, pParent) + return CreateFrame("Frame", nil, pParent, BackdropTemplateMixin and "BackdropTemplate") end function Mappy._ButtonOptionsPanel:Construct(pParent) @@ -2573,78 +2579,78 @@ function Mappy._ButtonOptionsPanel:Construct(pParent) -- Hide time-of-day - self.HideTimeOfDayCheckbutton = CreateFrame("Checkbutton", "MappyHideTimeOfDayCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideTimeOfDayCheckbutton = CreateFrame("Checkbutton", "MappyHideTimeOfDayCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideTimeOfDayCheckbutton:SetPoint("TOPLEFT", self.Title, "BOTTOMLEFT", 0, -15) self.HideTimeOfDayCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideTimeOfDay(self:GetChecked()) end) MappyHideTimeOfDayCheckbuttonText:SetText("Hide calendar button") -- Hide zoom in/out - self.HideZoomCheckbutton = CreateFrame("Checkbutton", "MappyHideZoomCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideZoomCheckbutton = CreateFrame("Checkbutton", "MappyHideZoomCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideZoomCheckbutton:SetPoint("TOPLEFT", self.HideTimeOfDayCheckbutton, "TOPLEFT", 0, -25) self.HideZoomCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideZoom(self:GetChecked()) end) MappyHideZoomCheckbuttonText:SetText("Hide zoom buttons") -- Hide world map button - self.HideWorldMapCheckbutton = CreateFrame("Checkbutton", "MappyHideWorldMapCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideWorldMapCheckbutton = CreateFrame("Checkbutton", "MappyHideWorldMapCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideWorldMapCheckbutton:SetPoint("TOPLEFT", self.HideZoomCheckbutton, "TOPLEFT", 0, -25) self.HideWorldMapCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideWorldMap(self:GetChecked()) end) MappyHideWorldMapCheckbuttonText:SetText("Hide world map button") -- Hide Tracking Icon - self.HideMiniMapTrackingCheckbutton = CreateFrame("Checkbutton", "MappyHideMiniMapTrackingCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideMiniMapTrackingCheckbutton = CreateFrame("Checkbutton", "MappyHideMiniMapTrackingCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideMiniMapTrackingCheckbutton:SetPoint("TOPLEFT", self.HideWorldMapCheckbutton, "TOPLEFT", 0, -25) self.HideMiniMapTrackingCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideTracking(self:GetChecked()) end) MappyHideMiniMapTrackingCheckbuttonText:SetText("Hide Tracking icon") -- Hide Time Manager Clock - self.HideTimeManagerClockCheckbutton = CreateFrame("Checkbutton", "MappyHideTimeManagerClockCheckbutton", self, "OptionsCheckButtonTemplate") + self.HideTimeManagerClockCheckbutton = CreateFrame("Checkbutton", "MappyHideTimeManagerClockCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.HideTimeManagerClockCheckbutton:SetPoint("TOPLEFT", self.HideMiniMapTrackingCheckbutton, "TOPLEFT", 0, -25) self.HideTimeManagerClockCheckbutton:SetScript("OnClick", function (self) Mappy:SetHideTimeManagerClock(self:GetChecked()) end) MappyHideTimeManagerClockCheckbuttonText:SetText("Hide clock") -- Addon button stacking - self.AutoStackCheckbutton = CreateFrame("Checkbutton", "MappyAutoStackCheckbutton", self, "OptionsCheckButtonTemplate") + self.AutoStackCheckbutton = CreateFrame("Checkbutton", "MappyAutoStackCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.AutoStackCheckbutton:SetPoint("TOPLEFT", self.HideTimeManagerClockCheckbutton, "TOPLEFT", 0, -40) self.AutoStackCheckbutton:SetScript("OnClick", function (self) Mappy:SetAutoArrangeButtons(self:GetChecked()) end) MappyAutoStackCheckbuttonText:SetText("Auto-arrange addon buttons") -- Starting corner - self.TopLeftCheckbutton = CreateFrame("Checkbutton", "MappyTopLeftCheckbutton", self, "OptionsCheckButtonTemplate") + self.TopLeftCheckbutton = CreateFrame("Checkbutton", "MappyTopLeftCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.TopLeftCheckbutton:SetPoint("TOPLEFT", self.AutoStackCheckbutton, "TOPLEFT", 30, -25) self.TopLeftCheckbutton:SetScript("OnClick", function (button) Mappy:corner("TOPLEFT") self:OnShow() end) MappyTopLeftCheckbuttonText:SetText("Top-left") - self.TopRightCheckbutton = CreateFrame("Checkbutton", "MappyTopRightCheckbutton", self, "OptionsCheckButtonTemplate") + self.TopRightCheckbutton = CreateFrame("Checkbutton", "MappyTopRightCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.TopRightCheckbutton:SetPoint("TOPLEFT", self.TopLeftCheckbutton, "TOPLEFT", 120, 0) self.TopRightCheckbutton:SetScript("OnClick", function (button) Mappy:corner("TOPRIGHT") self:OnShow() end) MappyTopRightCheckbuttonText:SetText("Top-right") - self.BottomLeftCheckbutton = CreateFrame("Checkbutton", "MappyBottomLeftCheckbutton", self, "OptionsCheckButtonTemplate") + self.BottomLeftCheckbutton = CreateFrame("Checkbutton", "MappyBottomLeftCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.BottomLeftCheckbutton:SetPoint("TOPLEFT", self.TopLeftCheckbutton, "TOPLEFT", 0, -25) self.BottomLeftCheckbutton:SetScript("OnClick", function (button) Mappy:corner("BOTTOMLEFT") self:OnShow() end) MappyBottomLeftCheckbuttonText:SetText("Bottom-left") - self.BottomRightCheckbutton = CreateFrame("Checkbutton", "MappyBottomRightCheckbutton", self, "OptionsCheckButtonTemplate") + self.BottomRightCheckbutton = CreateFrame("Checkbutton", "MappyBottomRightCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.BottomRightCheckbutton:SetPoint("TOPLEFT", self.TopRightCheckbutton, "TOPLEFT", 0, -25) self.BottomRightCheckbutton:SetScript("OnClick", function (button) Mappy:corner("BOTTOMRIGHT") self:OnShow() end) MappyBottomRightCheckbuttonText:SetText("Bottom-right") -- Direction - self.CCWCheckbutton = CreateFrame("Checkbutton", "MappyCCWCheckbutton", self, "OptionsCheckButtonTemplate") + self.CCWCheckbutton = CreateFrame("Checkbutton", "MappyCCWCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.CCWCheckbutton:SetPoint("TOPLEFT", self.BottomLeftCheckbutton, "TOPLEFT", 0, -25) self.CCWCheckbutton:SetScript("OnClick", function (self) Mappy:SetCounterClockwise(self:GetChecked()) end) MappyCCWCheckbuttonText:SetText("Counter-clockwise") -- Stacking parent - self.StackToScreenCheckbutton = CreateFrame("Checkbutton", "MappyStackToScreenCheckbutton", self, "OptionsCheckButtonTemplate") + self.StackToScreenCheckbutton = CreateFrame("Checkbutton", "MappyStackToScreenCheckbutton", self, "OptionsCheckButtonTemplate", BackdropTemplateMixin and "BackdropTemplate") self.StackToScreenCheckbutton:SetPoint("TOPLEFT", self.CCWCheckbutton, "TOPLEFT", 0, -25) self.StackToScreenCheckbutton:SetScript("OnClick", function (self) Mappy:SetStackToScreen(self:GetChecked()) end) MappyStackToScreenCheckbuttonText:SetText("Stack around screen") @@ -2680,7 +2686,7 @@ Mappy._ProfilesPanel = {} ---------------------------------------- function Mappy._ProfilesPanel:New(pParent) - return CreateFrame("Frame", nil, pParent) + return CreateFrame("Frame", nil, pParent, BackdropTemplateMixin and "BackdropTemplate") end function Mappy._ProfilesPanel:Construct(pParent)