local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB local S = E:GetModule('Skins') local _G = _G local unpack, sort, gsub, wipe = unpack, sort, gsub, wipe local strupper, ipairs, tonumber = strupper, ipairs, tonumber local floor, select, type, min = floor, select, type, min local pairs, tinsert, tContains = pairs, tinsert, tContains local strsplit = strsplit local hooksecurefunc = hooksecurefunc local EnableAddOn = EnableAddOn local LoadAddOn = LoadAddOn local GetAddOnMetadata = GetAddOnMetadata local GetAddOnInfo = GetAddOnInfo local CreateFrame = CreateFrame local IsAddOnLoaded = IsAddOnLoaded local InCombatLockdown = InCombatLockdown local IsControlKeyDown = IsControlKeyDown local IsAltKeyDown = IsAltKeyDown local EditBox_ClearFocus = EditBox_ClearFocus local ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT local RESET = RESET -- GLOBALS: ElvUIMoverPopupWindow, ElvUIMoverNudgeWindow, ElvUIMoverPopupWindowDropDown local ConfigTooltip = CreateFrame('GameTooltip', 'ElvUIConfigTooltip', E.UIParent, 'GameTooltipTemplate, BackdropTemplate') local grid E.ConfigModeLayouts = { 'ALL', 'GENERAL', 'SOLO', 'PARTY', 'ARENA', 'RAID', 'ACTIONBARS' } E.ConfigModeLocalizedStrings = { ALL = _G.ALL, GENERAL = _G.GENERAL, SOLO = _G.SOLO, PARTY = _G.PARTY, ARENA = _G.ARENA, RAID = _G.RAID, ACTIONBARS = _G.ACTIONBARS_LABEL } function E:Grid_Show() if not grid then E:Grid_Create() elseif grid.boxSize ~= E.db.gridSize then grid:Hide() E:Grid_Create() else grid:Show() end end function E:Grid_Hide() if grid then grid:Hide() end end function E:ToggleMoveMode(which) if InCombatLockdown() then return end local mode = not E.ConfigurationMode if not which or which == '' then E.ConfigurationMode = mode which = 'all' else E.ConfigurationMode = true mode = true end self:ToggleMovers(mode, which) if mode then E:Grid_Show() _G.ElvUIGrid:SetAlpha(0.4) if not ElvUIMoverPopupWindow then E:CreateMoverPopup() end ElvUIMoverPopupWindow:Show() _G.UIDropDownMenu_SetSelectedValue(ElvUIMoverPopupWindowDropDown, strupper(which)) if IsAddOnLoaded('ElvUI_OptionsUI') then E:Config_CloseWindow() end else E:Grid_Hide() _G.ElvUIGrid:SetAlpha(1) if ElvUIMoverPopupWindow then ElvUIMoverPopupWindow:Hide() end end end function E:Grid_GetRegion() if grid then if grid.regionCount and grid.regionCount > 0 then local line = select(grid.regionCount, grid:GetRegions()) grid.regionCount = grid.regionCount - 1 line:SetAlpha(1) return line else return grid:CreateTexture() end end end function E:Grid_Create() if not grid then grid = CreateFrame('Frame', 'ElvUIGrid', E.UIParent) grid:SetFrameStrata('BACKGROUND') else grid.regionCount = 0 local numRegions = grid:GetNumRegions() for i = 1, numRegions do local region = select(i, grid:GetRegions()) if region and region.IsObjectType and region:IsObjectType('Texture') then grid.regionCount = grid.regionCount + 1 region:SetAlpha(0) end end end local width, height = E.UIParent:GetSize() local size, half = E.mult / 2, height / 2 local gSize = E.db.gridSize local gHalf = gSize / 2 local ratio = width / height local hHeight = height * ratio local wStep = width / gSize local hStep = hHeight / gSize grid.boxSize = gSize grid:SetPoint('CENTER', E.UIParent) grid:Size(width, height) grid:Show() for i = 0, gSize do local tx = E:Grid_GetRegion() if i == gHalf then tx:SetColorTexture(1, 0, 0) tx:SetDrawLayer('BACKGROUND', 1) else tx:SetColorTexture(0, 0, 0) tx:SetDrawLayer('BACKGROUND', 0) end local iwStep = i*wStep tx:ClearAllPoints() tx:SetPoint('TOPLEFT', grid, 'TOPLEFT', iwStep - size, 0) tx:SetPoint('BOTTOMRIGHT', grid, 'BOTTOMLEFT', iwStep + size, 0) end do local tx = E:Grid_GetRegion() tx:SetColorTexture(1, 0, 0) tx:SetDrawLayer('BACKGROUND', 1) tx:ClearAllPoints() tx:SetPoint('TOPLEFT', grid, 'TOPLEFT', 0, -half + size) tx:SetPoint('BOTTOMRIGHT', grid, 'TOPRIGHT', 0, -(half + size)) end local hSteps = floor((height/2)/hStep) for i = 1, hSteps do local ihStep = i*hStep local tx = E:Grid_GetRegion() tx:SetColorTexture(0, 0, 0) tx:SetDrawLayer('BACKGROUND', 0) tx:ClearAllPoints() tx:SetPoint('TOPLEFT', grid, 'TOPLEFT', 0, -(half+ihStep) + size) tx:SetPoint('BOTTOMRIGHT', grid, 'TOPRIGHT', 0, -(half+ihStep + size)) tx = E:Grid_GetRegion() tx:SetColorTexture(0, 0, 0) tx:SetDrawLayer('BACKGROUND', 0) tx:ClearAllPoints() tx:SetPoint('TOPLEFT', grid, 'TOPLEFT', 0, -(half-ihStep) + size) tx:SetPoint('BOTTOMRIGHT', grid, 'TOPRIGHT', 0, -(half-ihStep + size)) end end local function ConfigMode_OnClick(self) E:ToggleMoveMode(self.value) end local function ConfigMode_Initialize() local info = _G.UIDropDownMenu_CreateInfo() info.func = ConfigMode_OnClick for _, configMode in ipairs(E.ConfigModeLayouts) do info.text = E.ConfigModeLocalizedStrings[configMode] info.value = configMode _G.UIDropDownMenu_AddButton(info) end local dd = ElvUIMoverPopupWindowDropDown _G.UIDropDownMenu_SetSelectedValue(dd, dd.selectedValue or 'ALL') end function E:NudgeMover(nudgeX, nudgeY) local mover = ElvUIMoverNudgeWindow.child local x, y, point = E:CalculateMoverPoints(mover, nudgeX, nudgeY) mover:ClearAllPoints() mover:SetPoint(point, E.UIParent, point, x, y) E:SaveMoverPosition(mover.name) --Update coordinates in Nudge Window E:UpdateNudgeFrame(mover, x, y) end function E:UpdateNudgeFrame(mover, x, y) if not (x and y) then x, y = E:CalculateMoverPoints(mover) end x = E:Round(x) y = E:Round(y) local ElvUIMoverNudgeWindow = ElvUIMoverNudgeWindow ElvUIMoverNudgeWindow.xOffset:SetText(x) ElvUIMoverNudgeWindow.yOffset:SetText(y) ElvUIMoverNudgeWindow.xOffset.currentValue = x ElvUIMoverNudgeWindow.yOffset.currentValue = y ElvUIMoverNudgeWindow.title:SetText(mover.textString) end function E:AssignFrameToNudge() ElvUIMoverNudgeWindow.child = self E:UpdateNudgeFrame(self) end function E:CreateMoverPopup() local r, g, b = unpack(E.media.rgbvaluecolor) local f = CreateFrame('Frame', 'ElvUIMoverPopupWindow', _G.UIParent, 'BackdropTemplate') f:SetFrameStrata('DIALOG') f:SetToplevel(true) f:EnableMouse(true) f:SetMovable(true) f:SetFrameLevel(99) f:SetClampedToScreen(true) f:Size(370, 190) f:SetTemplate('Transparent') f:Point('BOTTOM', _G.UIParent, 'CENTER', 0, 100) f:Hide() local header = CreateFrame('Button', nil, f, 'BackdropTemplate') header:SetTemplate(nil, true) header:Size(100, 25) header:SetPoint('CENTER', f, 'TOP') header:SetFrameLevel(header:GetFrameLevel() + 2) header:EnableMouse(true) header:RegisterForClicks('AnyUp', 'AnyDown') header:SetScript('OnMouseDown', function() f:StartMoving() end) header:SetScript('OnMouseUp', function() f:StopMovingOrSizing() end) f.header = header local title = header:CreateFontString(nil, 'OVERLAY') title:FontTemplate() title:Point('CENTER', header, 'CENTER') title:SetText('ElvUI') f.title = title local desc = f:CreateFontString(nil, 'ARTWORK') desc:SetFontObject('GameFontHighlight') desc:SetJustifyV('TOP') desc:SetJustifyH('LEFT') desc:Point('TOPLEFT', 18, -20) desc:Point('BOTTOMRIGHT', -18, 48) desc:SetText(L["DESC_MOVERCONFIG"]) f.desc = desc local snapName = f:GetName()..'CheckButton' local snapping = CreateFrame('CheckButton', snapName, f, 'OptionsCheckButtonTemplate') snapping:SetScript('OnShow', function(cb) cb:SetChecked(E.db.general.stickyFrames) end) snapping:SetScript('OnClick', function(cb) E.db.general.stickyFrames = cb:GetChecked() end) snapping.text = _G[snapName..'Text'] snapping.text:SetText(L["Sticky Frames"]) f.snapping = snapping local lock = CreateFrame('Button', f:GetName()..'CloseButton', f, 'OptionsButtonTemplate, BackdropTemplate') lock.Text:SetText(L["Lock"]) lock:SetScript('OnClick', function() E:ToggleMoveMode() if E.ConfigurationToggled then E.ConfigurationToggled = nil if IsAddOnLoaded('ElvUI_OptionsUI') then E:Config_OpenWindow() end end end) f.lock = lock local align = CreateFrame('EditBox', f:GetName()..'EditBox', f, 'InputBoxTemplate, BackdropTemplate') align:Size(24, 17) align:SetAutoFocus(false) align:SetScript('OnEscapePressed', function(eb) eb:SetText(E.db.gridSize) EditBox_ClearFocus(eb) end) align:SetScript('OnEnterPressed', function(eb) local text = eb:GetText() if tonumber(text) then if tonumber(text) <= 256 and tonumber(text) >= 4 then E.db.gridSize = tonumber(text) else eb:SetText(E.db.gridSize) end else eb:SetText(E.db.gridSize) end E:Grid_Show() EditBox_ClearFocus(eb) end) align:SetScript('OnEditFocusLost', function(eb) eb:SetText(E.db.gridSize) end) align:SetScript('OnEditFocusGained', align.HighlightText) align:SetScript('OnShow', function(eb) EditBox_ClearFocus(eb) eb:SetText(E.db.gridSize) end) align.text = align:CreateFontString(nil, 'OVERLAY', 'GameFontNormal') align.text:Point('RIGHT', align, 'LEFT', -4, 0) align.text:SetText(L["Grid Size:"]) f.align = align --position buttons snapping:Point('BOTTOMLEFT', 14, 10) lock:Point('BOTTOMRIGHT', -14, 14) align:Point('TOPRIGHT', lock, 'TOPLEFT', -4, -2) S:HandleCheckBox(snapping) S:HandleButton(lock) S:HandleEditBox(align) f:RegisterEvent('PLAYER_REGEN_DISABLED') f:SetScript('OnEvent', function(mover) if mover:IsShown() then mover:Hide() E:Grid_Hide() E:ToggleMoveMode() end end) local dropDown = CreateFrame('Frame', f:GetName()..'DropDown', f, 'UIDropDownMenuTemplate') dropDown:Point('BOTTOMRIGHT', lock, 'TOPRIGHT', 8, -5) S:HandleDropDownBox(dropDown, 165) dropDown.text = dropDown:CreateFontString(nil, 'OVERLAY', 'GameFontNormal') dropDown.text:Point('RIGHT', dropDown.backdrop, 'LEFT', -2, 0) dropDown.text:SetText(L["Config Mode:"]) f.dropDown = dropDown _G.UIDropDownMenu_Initialize(dropDown, ConfigMode_Initialize) local nudgeFrame = CreateFrame('Frame', 'ElvUIMoverNudgeWindow', E.UIParent, 'BackdropTemplate') nudgeFrame:SetFrameStrata('DIALOG') nudgeFrame:Size(200, 110) nudgeFrame:SetTemplate('Transparent') nudgeFrame:CreateShadow(5) nudgeFrame.shadow:SetBackdropBorderColor(r, g, b, 0.9) nudgeFrame:SetFrameLevel(500) nudgeFrame:EnableMouse(true) nudgeFrame:SetClampedToScreen(true) nudgeFrame:SetPropagateKeyboardInput(true) nudgeFrame:SetScript('OnKeyDown', function(_, btn) local Mod = IsAltKeyDown() or IsControlKeyDown() if btn == 'NUMPAD4' then E:NudgeMover(-1 * (Mod and 10 or 1)) elseif btn == 'NUMPAD6' then E:NudgeMover(1 * (Mod and 10 or 1)) elseif btn == 'NUMPAD8' then E:NudgeMover(nil, 1 * (Mod and 10 or 1)) elseif btn == 'NUMPAD2' then E:NudgeMover(nil, -1 * (Mod and 10 or 1)) end end) ElvUIMoverPopupWindow:HookScript('OnHide', function() ElvUIMoverNudgeWindow:Hide() end) desc = nudgeFrame:CreateFontString(nil, 'ARTWORK') desc:SetFontObject('GameFontHighlight') desc:SetJustifyV('TOP') desc:SetJustifyH('LEFT') desc:Point('TOPLEFT', 18, -15) desc:Point('BOTTOMRIGHT', -18, 28) desc:SetJustifyH('CENTER') nudgeFrame.desc = desc header = CreateFrame('Button', nil, nudgeFrame, 'BackdropTemplate') header:SetTemplate(nil, true) header:Size(100, 25) header:SetPoint('CENTER', nudgeFrame, 'TOP') header:SetFrameLevel(header:GetFrameLevel() + 2) nudgeFrame.header = header title = header:CreateFontString(nil, 'OVERLAY') title:FontTemplate() title:Point('CENTER', header, 'CENTER') title:SetText(L["Nudge"]) nudgeFrame.title = title local xOffset = CreateFrame('EditBox', nudgeFrame:GetName()..'XEditBox', nudgeFrame, 'InputBoxTemplate') xOffset:Size(50, 17) xOffset:SetAutoFocus(false) xOffset.currentValue = 0 xOffset:SetScript('OnEscapePressed', function(eb) eb:SetText(E:Round(xOffset.currentValue)) EditBox_ClearFocus(eb) end) xOffset:SetScript('OnEnterPressed', function(eb) local num = eb:GetText() if tonumber(num) then local diff = num - xOffset.currentValue xOffset.currentValue = num E:NudgeMover(diff) end eb:SetText(E:Round(xOffset.currentValue)) EditBox_ClearFocus(eb) end) xOffset:SetScript('OnEditFocusLost', function(eb) eb:SetText(E:Round(xOffset.currentValue)) end) xOffset:SetScript('OnEditFocusGained', xOffset.HighlightText) xOffset:SetScript('OnShow', function(eb) EditBox_ClearFocus(eb) eb:SetText(E:Round(xOffset.currentValue)) end) xOffset.text = xOffset:CreateFontString(nil, 'OVERLAY', 'GameFontNormal') xOffset.text:Point('RIGHT', xOffset, 'LEFT', -4, 0) xOffset.text:SetText('X:') xOffset:Point('BOTTOMRIGHT', nudgeFrame, 'CENTER', -6, 8) S:HandleEditBox(xOffset) nudgeFrame.xOffset = xOffset local yOffset = CreateFrame('EditBox', nudgeFrame:GetName()..'YEditBox', nudgeFrame, 'InputBoxTemplate') yOffset:Size(50, 17) yOffset:SetAutoFocus(false) yOffset.currentValue = 0 yOffset:SetScript('OnEscapePressed', function(eb) eb:SetText(E:Round(yOffset.currentValue)) EditBox_ClearFocus(eb) end) yOffset:SetScript('OnEnterPressed', function(eb) local num = eb:GetText() if tonumber(num) then local diff = num - yOffset.currentValue yOffset.currentValue = num E:NudgeMover(nil, diff) end eb:SetText(E:Round(yOffset.currentValue)) EditBox_ClearFocus(eb) end) yOffset:SetScript('OnEditFocusLost', function(eb) eb:SetText(E:Round(yOffset.currentValue)) end) yOffset:SetScript('OnEditFocusGained', yOffset.HighlightText) yOffset:SetScript('OnShow', function(eb) EditBox_ClearFocus(eb) eb:SetText(E:Round(yOffset.currentValue)) end) yOffset.text = yOffset:CreateFontString(nil, 'OVERLAY', 'GameFontNormal') yOffset.text:Point('RIGHT', yOffset, 'LEFT', -4, 0) yOffset.text:SetText('Y:') yOffset:Point('BOTTOMLEFT', nudgeFrame, 'CENTER', 16, 8) S:HandleEditBox(yOffset) nudgeFrame.yOffset = yOffset local resetButton = CreateFrame('Button', nudgeFrame:GetName()..'ResetButton', nudgeFrame, 'UIPanelButtonTemplate, BackdropTemplate') resetButton:SetText(RESET) resetButton:Point('TOP', nudgeFrame, 'CENTER', 0, 2) resetButton:Size(100, 25) resetButton:SetScript('OnClick', function() if ElvUIMoverNudgeWindow.child.textString then E:ResetMovers(ElvUIMoverNudgeWindow.child.textString) end end) S:HandleButton(resetButton) nudgeFrame.resetButton = resetButton local upButton = CreateFrame('Button', nudgeFrame:GetName()..'UpButton', nudgeFrame, 'BackdropTemplate') upButton:Point('BOTTOMRIGHT', nudgeFrame, 'BOTTOM', -6, 4) upButton:SetScript('OnClick', function() E:NudgeMover(nil, 1) end) S:HandleNextPrevButton(upButton) S:HandleButton(upButton) upButton:Size(22) nudgeFrame.upButton = upButton local downButton = CreateFrame('Button', nudgeFrame:GetName()..'DownButton', nudgeFrame, 'BackdropTemplate') downButton:Point('BOTTOMLEFT', nudgeFrame, 'BOTTOM', 6, 4) downButton:SetScript('OnClick', function() E:NudgeMover(nil, -1) end) S:HandleNextPrevButton(downButton) S:HandleButton(downButton) downButton:Size(22) nudgeFrame.downButton = downButton local leftButton = CreateFrame('Button', nudgeFrame:GetName()..'LeftButton', nudgeFrame, 'BackdropTemplate') leftButton:Point('RIGHT', upButton, 'LEFT', -6, 0) leftButton:SetScript('OnClick', function() E:NudgeMover(-1) end) S:HandleNextPrevButton(leftButton) S:HandleButton(leftButton) leftButton:Size(22) nudgeFrame.leftButton = leftButton local rightButton = CreateFrame('Button', nudgeFrame:GetName()..'RightButton', nudgeFrame, 'BackdropTemplate') rightButton:Point('LEFT', downButton, 'RIGHT', 6, 0) rightButton:SetScript('OnClick', function() E:NudgeMover(1) end) S:HandleNextPrevButton(rightButton) S:HandleButton(rightButton) rightButton:Size(22) nudgeFrame.rightButton = rightButton end function E:Config_ResetSettings() E.configSavedPositionTop, E.configSavedPositionLeft = nil, nil E.global.general.AceGUI = E:CopyTable({}, E.DF.global.general.AceGUI) end function E:Config_GetPosition() return E.configSavedPositionTop, E.configSavedPositionLeft end function E:Config_GetSize() return E.global.general.AceGUI.width, E.global.general.AceGUI.height end function E:Config_UpdateSize(reset) local frame = E:Config_GetWindow() if not frame then return end local maxWidth, maxHeight = self.UIParent:GetSize() frame:SetMinResize(800, 600) frame:SetMaxResize(maxWidth-50, maxHeight-50) self.Libs.AceConfigDialog:SetDefaultSize(E.name, E:Config_GetDefaultSize()) local status = frame.obj and frame.obj.status if status then if reset then E:Config_ResetSettings() status.top, status.left = E:Config_GetPosition() status.width, status.height = E:Config_GetDefaultSize() frame.obj:ApplyStatus() else local top, left = E:Config_GetPosition() if top and left then status.top, status.left = top, left frame.obj:ApplyStatus() end end E:Config_UpdateLeftScroller(frame) end end function E:Config_GetDefaultSize() local width, height = E:Config_GetSize() local maxWidth, maxHeight = E.UIParent:GetSize() width, height = min(maxWidth-50, width), min(maxHeight-50, height) return width, height end function E:Config_StopMoving() local frame = self and self.GetParent and self:GetParent() if frame and frame.obj and frame.obj.status then E.configSavedPositionTop, E.configSavedPositionLeft = E:Round(frame:GetTop(), 2), E:Round(frame:GetLeft(), 2) E.global.general.AceGUI.width, E.global.general.AceGUI.height = E:Round(frame:GetWidth(), 2), E:Round(frame:GetHeight(), 2) E:Config_UpdateLeftScroller(frame) end end local function Config_ButtonOnEnter(self) if ConfigTooltip:IsForbidden() or not self.desc then return end ConfigTooltip:SetOwner(self, 'ANCHOR_TOPRIGHT', 0, 2) ConfigTooltip:AddLine(self.desc, 1, 1, 1, true) ConfigTooltip:Show() end local function Config_ButtonOnLeave() if ConfigTooltip:IsForbidden() then return end ConfigTooltip:Hide() end local function Config_StripNameColor(name) if type(name) == 'function' then name = name() end return E:StripString(name) end local function Config_SortButtons(a,b) local A1, B1 = a[1], b[1] if A1 and B1 then if A1 == B1 then local A3, B3 = a[3], b[3] if A3 and B3 and (A3.name and B3.name) then return Config_StripNameColor(A3.name) < Config_StripNameColor(B3.name) end end return A1 < B1 end end local function ConfigSliderOnMouseWheel(self, offset) local _, maxValue = self:GetMinMaxValues() if maxValue == 0 then return end local newValue = self:GetValue() - offset if newValue < 0 then newValue = 0 end if newValue > maxValue then return end self:SetValue(newValue) self.buttons:Point('TOPLEFT', 0, newValue * 36) end local function ConfigSliderOnValueChanged(self, value) self:SetValue(value) self.buttons:Point('TOPLEFT', 0, value * 36) end function E:Config_SetButtonText(btn, noColor) local name = btn.info.name if type(name) == 'function' then name = name() end if noColor then btn:SetText(name:gsub('|c[fF][fF]%x%x%x%x%x%x',''):gsub('|r','')) else btn:SetText(name) end end function E:Config_CreateSeparatorLine(frame, lastButton) local line = frame.leftHolder.buttons:CreateTexture() line:SetTexture(E.Media.Textures.White8x8) line:SetVertexColor(1, .82, 0, .4) line:Size(179, 2) line:Point('TOP', lastButton, 'BOTTOM', 0, -6) line.separator = true return line end function E:Config_SetButtonColor(btn, disabled) if disabled then btn:Disable() btn:SetBackdropBorderColor(1, .82, 0, 1) btn:SetBackdropColor(1, .82, 0, 0.4) btn.Text:SetTextColor(1, 1, 1) E:Config_SetButtonText(btn, true) else btn:Enable() local r, g, b = unpack(E.media.bordercolor) btn:SetBackdropBorderColor(r, g, b, 1) r, g, b = unpack(E.media.backdropcolor) btn:SetBackdropColor(r, g, b, 1) btn.Text:SetTextColor(1, .82, 0) E:Config_SetButtonText(btn) end end function E:Config_UpdateSliderPosition(btn) local left = btn and btn.frame and btn.frame.leftHolder if left and left.slider then ConfigSliderOnValueChanged(left.slider, btn.sliderValue or 0) end end function E:Config_CreateButton(info, frame, unskinned, ...) local btn = CreateFrame(...) btn.frame = frame btn.desc = info.desc btn.info = info if not unskinned then E.Skins:HandleButton(btn, nil, nil, nil, true) end E:Config_SetButtonText(btn) E:Config_SetButtonColor(btn, btn.info.key == 'general') btn:HookScript('OnEnter', Config_ButtonOnEnter) btn:HookScript('OnLeave', Config_ButtonOnLeave) btn:SetScript('OnClick', info.func) btn:Width(btn:GetTextWidth() + 40) return btn end function E:Config_DialogOpened(name) if name ~= 'ElvUI' then return end local frame = E:Config_GetWindow() if frame and frame.leftHolder then E:Config_WindowOpened(frame) end end function E:Config_UpdateLeftButtons() local frame = E:Config_GetWindow() if not (frame and frame.leftHolder) then return end local status = frame.obj.status local selected = status and status.groups.selected for _, btn in ipairs(frame.leftHolder.buttons) do if type(btn) == 'table' and btn.IsObjectType and btn:IsObjectType('Button') then local enabled = btn.info.key == selected E:Config_SetButtonColor(btn, enabled) if enabled then E:Config_UpdateSliderPosition(btn) end end end end function E:Config_UpdateLeftScroller(frame) local left = frame and frame.leftHolder if not left then return end local btns = left.buttons local bottom = btns:GetBottom() if not bottom then return end btns:Point('TOPLEFT', 0, 0) local max = 0 for _, btn in ipairs(btns) do local button = type(btn) == 'table' and btn.IsObjectType and btn:IsObjectType('Button') if button then btn.sliderValue = nil local btm = btn:GetBottom() if btm then if bottom > btm then max = max + 1 btn.sliderValue = max end end end end local slider = left.slider slider:SetMinMaxValues(0, max) slider:SetValue(0) if max == 0 then slider.thumb:Hide() else slider.thumb:Show() end end function E:Config_SaveOldPosition(frame) if frame.GetNumPoints and not frame.oldPosition then frame.oldPosition = {} for i = 1, frame:GetNumPoints() do tinsert(frame.oldPosition, {frame:GetPoint(i)}) end end end function E:Config_RestoreOldPosition(frame) local position = frame.oldPosition if position then frame:ClearAllPoints() for i = 1, #position do frame:Point(unpack(position[i])) end end end function E:Config_CreateLeftButtons(frame, unskinned, options) local opts = {} for key, info in pairs(options) do if (not info.order or info.order < 6) and not tContains(E.OriginalOptions, key) then info.order = 6 end if key == 'profiles' then info.desc = nil end tinsert(opts, {info.order, key, info}) end sort(opts, Config_SortButtons) local buttons, last, order = frame.leftHolder.buttons for index, opt in ipairs(opts) do local info = opt[3] local key = opt[2] if (order == 2 or order == 5) and order < opt[1] then last = E:Config_CreateSeparatorLine(frame, last) end order = opt[1] info.key = key info.func = function() local ACD = E.Libs.AceConfigDialog if ACD then ACD:SelectGroup('ElvUI', key) end end local btn = E:Config_CreateButton(info, frame, unskinned, 'Button', nil, buttons, 'UIPanelButtonTemplate, BackdropTemplate') btn:Width(177) if not last then btn:Point('TOP', buttons, 'TOP', 0, 0) else btn:Point('TOP', last, 'BOTTOM', 0, (last.separator and -6) or -4) end buttons[index] = btn last = btn end end function E:Config_CloseClicked() if self.originalClose then self.originalClose:Click() end end function E:Config_CloseWindow() local ACD = E.Libs.AceConfigDialog if ACD then ACD:Close('ElvUI') end if not ConfigTooltip:IsForbidden() then ConfigTooltip:Hide() end end function E:Config_OpenWindow() local ACD = E.Libs.AceConfigDialog if ACD then ACD:Open('ElvUI') end if not ConfigTooltip:IsForbidden() then ConfigTooltip:Hide() end end function E:Config_GetWindow() local ACD = E.Libs.AceConfigDialog local ConfigOpen = ACD and ACD.OpenFrames and ACD.OpenFrames[E.name] return ConfigOpen and ConfigOpen.frame end local ConfigLogoTop E.valueColorUpdateFuncs[function(_, r, g, b) if ConfigLogoTop then ConfigLogoTop:SetVertexColor(r, g, b) end if ElvUIMoverNudgeWindow and ElvUIMoverNudgeWindow.shadow then ElvUIMoverNudgeWindow.shadow:SetBackdropBorderColor(r, g, b, 0.9) end end] = true function E:Config_WindowClosed() if not self.bottomHolder then return end local frame = E:Config_GetWindow() if not frame or frame ~= self then self.bottomHolder:Hide() self.leftHolder:Hide() self.topHolder:Hide() self.leftHolder.slider:Hide() self.closeButton:Hide() self.originalClose:Show() ConfigLogoTop = nil E:StopElasticize(self.leftHolder.LogoTop) E:StopElasticize(self.leftHolder.LogoBottom) E:Config_RestoreOldPosition(self.topHolder.version) E:Config_RestoreOldPosition(self.obj.content) E:Config_RestoreOldPosition(self.obj.titlebg) end end function E:Config_WindowOpened(frame) if frame and frame.bottomHolder and not ConfigLogoTop then frame.bottomHolder:Show() frame.leftHolder:Show() frame.topHolder:Show() frame.leftHolder.slider:Show() frame.closeButton:Show() frame.originalClose:Hide() frame.leftHolder.LogoTop:SetVertexColor(unpack(E.media.rgbvaluecolor)) ConfigLogoTop = frame.leftHolder.LogoTop E:Elasticize(frame.leftHolder.LogoTop, 128, 64) E:Elasticize(frame.leftHolder.LogoBottom, 128, 64) local unskinned = not E.private.skins.ace3Enable local offset = unskinned and 14 or 8 local version = frame.topHolder.version E:Config_SaveOldPosition(version) version:ClearAllPoints() version:Point('LEFT', frame.topHolder, 'LEFT', unskinned and 8 or 6, unskinned and -4 or 0) local holderHeight = frame.bottomHolder:GetHeight() local content = frame.obj.content E:Config_SaveOldPosition(content) content:ClearAllPoints() content:Point('TOPLEFT', frame, 'TOPLEFT', offset, -(unskinned and 50 or 40)) content:Point('BOTTOMRIGHT', frame, 'BOTTOMRIGHT', -offset, holderHeight + 3) local titlebg = frame.obj.titlebg E:Config_SaveOldPosition(titlebg) titlebg:ClearAllPoints() titlebg:SetPoint('TOPLEFT', frame) titlebg:SetPoint('TOPRIGHT', frame) end end function E:Config_CreateBottomButtons(frame, unskinned) local L = E.Libs.ACL:GetLocale('ElvUI', E.global.general.locale or 'enUS') local last for _, info in ipairs({ { var = 'ToggleAnchors', name = L["Toggle Anchors"], desc = L["Unlock various elements of the UI to be repositioned."], func = function() E:ToggleMoveMode() E.ConfigurationToggled = true end }, { var = 'ResetAnchors', name = L["Reset Anchors"], desc = L["Reset all frames to their original positions."], func = function() E:ResetUI() end }, { var = 'RepositionWindow', name = L["Reposition Window"], desc = L["Reset the size and position of this frame."], func = function() E:Config_UpdateSize(true) end }, { var = 'Install', name = L["Install"], desc = L["Run the installation process."], func = function() E:Install() E:ToggleOptionsUI() end }, { var = 'ToggleTutorials', name = L["Toggle Tutorials"], func = function() E:Tutorials(true) E:ToggleOptionsUI() end }, { var = 'ShowStatusReport', name = L["ElvUI Status"], desc = L["Shows a frame with needed info for support."], func = function() E:ShowStatusReport() E:ToggleOptionsUI() E.StatusReportToggled = true end } }) do local btn = E:Config_CreateButton(info, frame, unskinned, 'Button', nil, frame.bottomHolder, 'UIPanelButtonTemplate, BackdropTemplate') local offset = unskinned and 14 or 8 if not last then btn:Point('BOTTOMLEFT', frame.bottomHolder, 'BOTTOMLEFT', unskinned and 24 or offset, offset) last = btn else btn:Point('LEFT', last, 'RIGHT', 4, 0) last = btn end frame.bottomHolder[info.var] = btn end end local pageNodes = {} function E:Config_GetToggleMode(frame, msg) local pages, msgStr if msg and msg ~= '' then pages = {strsplit(',', msg)} msgStr = gsub(msg, ',', '\001') end local empty = pages ~= nil if not frame or empty then if empty then local ACD = E.Libs.AceConfigDialog local pageCount, index, mainSel = #pages if pageCount > 1 then wipe(pageNodes) index = 0 local main, mainNode, mainSelStr, sub, subNode, subSel for i = 1, pageCount do if i == 1 then main = pages[i] and ACD and ACD.Status and ACD.Status.ElvUI mainSel = main and main.status and main.status.groups and main.status.groups.selected mainSelStr = mainSel and ('^'..E:EscapeString(mainSel)..'\001') mainNode = main and main.children and main.children[pages[i]] pageNodes[index+1], pageNodes[index+2] = main, mainNode else sub = pages[i] and pageNodes[i] and ((i == pageCount and pageNodes[i]) or pageNodes[i].children[pages[i]]) subSel = sub and sub.status and sub.status.groups and sub.status.groups.selected subNode = (mainSelStr and msgStr:match(mainSelStr..E:EscapeString(pages[i])..'$') and (subSel and subSel == pages[i])) or ((i == pageCount and not subSel) and mainSel and mainSel == msgStr) pageNodes[index+1], pageNodes[index+2] = sub, subNode end index = index + 2 end else local main = pages[1] and ACD and ACD.Status and ACD.Status.ElvUI mainSel = main and main.status and main.status.groups and main.status.groups.selected end if frame and ((not index and mainSel and mainSel == msg) or (index and pageNodes and pageNodes[index])) then return 'Close' else return 'Open', pages end else return 'Open' end else return 'Close' end end function E:ToggleOptionsUI(msg) if InCombatLockdown() then self:Print(ERR_NOT_IN_COMBAT) self.ShowOptionsUI = true return end if not IsAddOnLoaded('ElvUI_OptionsUI') then local noConfig local _, _, _, _, reason = GetAddOnInfo('ElvUI_OptionsUI') if reason ~= 'MISSING' then EnableAddOn('ElvUI_OptionsUI') LoadAddOn('ElvUI_OptionsUI') -- version check elvui options if it's actually enabled if GetAddOnMetadata('ElvUI_OptionsUI', 'Version') ~= '1.07' then self:StaticPopup_Show('CLIENT_UPDATE_REQUEST') end else noConfig = true end if noConfig then self:Print('|cffff0000Error -- Addon "ElvUI_OptionsUI" not found.|r') return end end local frame = E:Config_GetWindow() local mode, pages = E:Config_GetToggleMode(frame, msg) local ACD = E.Libs.AceConfigDialog if ACD then if not ACD.OpenHookedElvUI then hooksecurefunc(E.Libs.AceConfigDialog, 'Open', E.Config_DialogOpened) ACD.OpenHookedElvUI = true end ACD[mode](ACD, E.name) end if not frame then frame = E:Config_GetWindow() end if mode == 'Open' and frame then local ACR = E.Libs.AceConfigRegistry if ACR and not ACR.NotifyHookedElvUI then hooksecurefunc(E.Libs.AceConfigRegistry, 'NotifyChange', E.Config_UpdateLeftButtons) ACR.NotifyHookedElvUI = true E:Config_UpdateSize() end if not frame.bottomHolder then -- window was released or never opened frame:HookScript('OnHide', E.Config_WindowClosed) for i=1, frame:GetNumChildren() do local child = select(i, frame:GetChildren()) if child:IsObjectType('Button') and child:GetText() == _G.CLOSE then frame.originalClose = child child:Hide() elseif child:IsObjectType('Frame') or child:IsObjectType('Button') then if child:HasScript('OnMouseUp') then child:HookScript('OnMouseUp', E.Config_StopMoving) end end end local unskinned = not E.private.skins.ace3Enable if unskinned then for i=1, frame:GetNumRegions() do local region = select(i, frame:GetRegions()) if region:IsObjectType('Texture') and region:GetTexture() == 131080 then region:SetAlpha(0) end end end local bottom = CreateFrame('Frame', nil, frame, 'BackdropTemplate') bottom:Point('BOTTOMLEFT', 2, 2) bottom:Point('BOTTOMRIGHT', -2, 2) bottom:Height(37) frame.bottomHolder = bottom local close = CreateFrame('Button', nil, frame, 'UIPanelCloseButton, BackdropTemplate') close:SetScript('OnClick', E.Config_CloseClicked) close:SetFrameLevel(1000) close:Point('TOPRIGHT', unskinned and -8 or 1, unskinned and -8 or 2) close:Size(32, 32) close.originalClose = frame.originalClose frame.closeButton = close local left = CreateFrame('Frame', nil, frame, 'BackdropTemplate') left:Point('BOTTOMRIGHT', bottom, 'BOTTOMLEFT', 181, 0) left:Point('BOTTOMLEFT', bottom, 'TOPLEFT', 0, 1) left:Point('TOPLEFT', unskinned and 10 or 2, unskinned and -6 or -2) frame.leftHolder = left local top = CreateFrame('Frame', nil, frame, 'BackdropTemplate') top.version = frame.obj.titletext top:Point('TOPRIGHT', frame, -2, 0) top:Point('TOPLEFT', left, 'TOPRIGHT', 1, 0) top:Height(24) frame.topHolder = top local LogoBottom = left:CreateTexture() LogoBottom:SetTexture(E.Media.Textures.LogoBottomSmall) LogoBottom:Point('CENTER', left, 'TOP', unskinned and 10 or 0, unskinned and -40 or -36) LogoBottom:Size(128, 64) left.LogoBottom = LogoBottom local LogoTop = left:CreateTexture() LogoTop:SetTexture(E.Media.Textures.LogoTopSmall) LogoTop:Point('CENTER', left, 'TOP', unskinned and 10 or 0, unskinned and -40 or -36) LogoTop:Size(128, 64) left.LogoTop = LogoTop local buttonsHolder = CreateFrame('Frame', nil, left) buttonsHolder:Point('BOTTOMLEFT', bottom, 'TOPLEFT', 0, 1) buttonsHolder:Point('TOPLEFT', left, 'TOPLEFT', 0, -70) buttonsHolder:Point('BOTTOMRIGHT') buttonsHolder:SetFrameLevel(5) buttonsHolder:SetClipsChildren(true) left.buttonsHolder = buttonsHolder local buttons = CreateFrame('Frame', nil, buttonsHolder, 'BackdropTemplate') buttons:Point('BOTTOMLEFT', bottom, 'TOPLEFT', 0, 1) buttons:Point('BOTTOMRIGHT') buttons:Point('TOPLEFT', 0, 0) left.buttons = buttons local slider = CreateFrame('Slider', nil, frame, 'BackdropTemplate') slider:SetThumbTexture(E.Media.Textures.White8x8) slider:SetScript('OnMouseWheel', ConfigSliderOnMouseWheel) slider:SetScript('OnValueChanged', ConfigSliderOnValueChanged) slider:SetOrientation('VERTICAL') slider:SetObeyStepOnDrag(true) slider:SetFrameLevel(4) slider:SetValueStep(1) slider:SetValue(0) slider:Width(192) slider:Point('BOTTOMLEFT', bottom, 'TOPLEFT', 0, 1) slider:Point('TOPLEFT', buttons, 'TOPLEFT', 0, 0) slider.buttons = buttons left.slider = slider local thumb = slider:GetThumbTexture() thumb:Point('LEFT', left, 'RIGHT', 2, 0) thumb:SetVertexColor(1, 1, 1, 0.5) thumb:Size(8, 12) left.slider.thumb = thumb if not unskinned then bottom:SetTemplate('Transparent') left:SetTemplate('Transparent') top:SetTemplate('Transparent') E.Skins:HandleCloseButton(close) end E:Config_CreateLeftButtons(frame, unskinned, E.Options.args) E:Config_CreateBottomButtons(frame, unskinned) E:Config_UpdateLeftScroller(frame) E:Config_WindowOpened(frame) end if ACD and pages then ACD:SelectGroup(E.name, unpack(pages)) end end end