initial commit
This commit is contained in:
176
Core/AceWindow.lua
Normal file
176
Core/AceWindow.lua
Normal file
@@ -0,0 +1,176 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = _G[ADDON_NAME]
|
||||
if not HMGT then return end
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI then return end
|
||||
|
||||
local WindowPrototype = {}
|
||||
|
||||
local function ResolveFrame(target)
|
||||
if not target then
|
||||
return nil
|
||||
end
|
||||
if type(target) == "table" and target.frame then
|
||||
return target.frame
|
||||
end
|
||||
return target
|
||||
end
|
||||
|
||||
function WindowPrototype:GetContent()
|
||||
return self.content
|
||||
end
|
||||
|
||||
function WindowPrototype:SetTitle(text)
|
||||
if self.widget and self.widget.SetTitle then
|
||||
self.widget:SetTitle(tostring(text or ""))
|
||||
end
|
||||
end
|
||||
|
||||
function WindowPrototype:SetStatusText(text)
|
||||
if self.widget and self.widget.SetStatusText then
|
||||
self.widget:SetStatusText(tostring(text or ""))
|
||||
end
|
||||
end
|
||||
|
||||
function WindowPrototype:Show()
|
||||
if self.widget and self.widget.Show then
|
||||
self.widget:Show()
|
||||
elseif self.frame then
|
||||
self.frame:Show()
|
||||
end
|
||||
end
|
||||
|
||||
function WindowPrototype:Hide()
|
||||
if self.widget and self.widget.Hide then
|
||||
self.widget:Hide()
|
||||
elseif self.frame then
|
||||
self.frame:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
function WindowPrototype:Raise()
|
||||
if self.frame and self.frame.Raise then
|
||||
self.frame:Raise()
|
||||
end
|
||||
end
|
||||
|
||||
function WindowPrototype:IsShown()
|
||||
return self.frame and self.frame:IsShown() or false
|
||||
end
|
||||
|
||||
function WindowPrototype:RegisterMinimizeTarget(target)
|
||||
self.minimizeTargets = self.minimizeTargets or {}
|
||||
self.minimizeTargets[#self.minimizeTargets + 1] = target
|
||||
end
|
||||
|
||||
function WindowPrototype:SetMinimized(minimized)
|
||||
minimized = minimized and true or false
|
||||
if not self.minimizable then
|
||||
minimized = false
|
||||
end
|
||||
|
||||
self.statusTable = self.statusTable or {}
|
||||
self.statusTable.minimized = minimized
|
||||
if minimized then
|
||||
self.statusTable.restoreHeight = self.statusTable.height or (self.frame and self.frame:GetHeight()) or self.height or 360
|
||||
end
|
||||
|
||||
local targetHeight = minimized
|
||||
and (self.minimizedHeight or 64)
|
||||
or (self.statusTable.restoreHeight or self.statusTable.height or self.height or 360)
|
||||
|
||||
if self.widget and self.widget.EnableResize then
|
||||
self.widget:EnableResize(not minimized)
|
||||
self.widget:SetHeight(targetHeight)
|
||||
elseif self.frame then
|
||||
self.frame:SetHeight(targetHeight)
|
||||
end
|
||||
|
||||
if self.minimizeButton and self.minimizeButton.SetText then
|
||||
self.minimizeButton:SetText(minimized and "+" or "-")
|
||||
end
|
||||
|
||||
for _, target in ipairs(self.minimizeTargets or {}) do
|
||||
local frame = ResolveFrame(target)
|
||||
if frame and frame.SetShown then
|
||||
frame:SetShown(not minimized)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function WindowPrototype:ToggleMinimized()
|
||||
self:SetMinimized(not (self.statusTable and self.statusTable.minimized))
|
||||
end
|
||||
|
||||
function HMGT:CreateAceWindow(key, options)
|
||||
self._aceWindows = self._aceWindows or {}
|
||||
if self._aceWindows[key] then
|
||||
return self._aceWindows[key]
|
||||
end
|
||||
|
||||
if not AceGUI then
|
||||
return nil
|
||||
end
|
||||
|
||||
options = options or {}
|
||||
local statusTable = options.statusTable or {}
|
||||
local widget = AceGUI:Create("Frame")
|
||||
widget:SetTitle(tostring(options.title or ""))
|
||||
widget:SetStatusText(tostring(options.statusText or ""))
|
||||
widget:SetStatusTable(statusTable)
|
||||
widget:SetWidth(tonumber(options.width) or 800)
|
||||
widget:SetHeight(tonumber(options.height) or 360)
|
||||
widget:EnableResize(options.resizable ~= false)
|
||||
widget.frame:SetClampedToScreen(true)
|
||||
widget.frame:SetToplevel(true)
|
||||
widget.frame:SetFrameStrata(options.strata or "FULLSCREEN_DIALOG")
|
||||
widget:Hide()
|
||||
widget:SetCallback("OnClose", function()
|
||||
widget:Hide()
|
||||
end)
|
||||
|
||||
local window = setmetatable({
|
||||
key = key,
|
||||
widget = widget,
|
||||
frame = widget.frame,
|
||||
content = widget.content,
|
||||
statusTable = statusTable,
|
||||
width = tonumber(options.width) or 800,
|
||||
height = tonumber(options.height) or 360,
|
||||
minimizable = options.minimizable == true,
|
||||
minimizedHeight = tonumber(options.minimizedHeight) or 64,
|
||||
minimizeTargets = {},
|
||||
}, { __index = WindowPrototype })
|
||||
|
||||
if options.backgroundTexture then
|
||||
local texture = window.content:CreateTexture(nil, "BACKGROUND")
|
||||
texture:SetPoint("CENTER", window.content, "CENTER", tonumber(options.backgroundOffsetX) or 0, tonumber(options.backgroundOffsetY) or 0)
|
||||
texture:SetSize(tonumber(options.backgroundWidth) or 220, tonumber(options.backgroundHeight) or 120)
|
||||
texture:SetTexture(tostring(options.backgroundTexture))
|
||||
texture:SetAlpha(tonumber(options.backgroundAlpha) or 0.12)
|
||||
window.backgroundTexture = texture
|
||||
end
|
||||
|
||||
if window.minimizable then
|
||||
local minimizeButton = AceGUI:Create("Button")
|
||||
minimizeButton:SetText((statusTable and statusTable.minimized) and "+" or "-")
|
||||
minimizeButton:SetWidth(24)
|
||||
minimizeButton:SetCallback("OnClick", function()
|
||||
window:ToggleMinimized()
|
||||
end)
|
||||
minimizeButton.frame:SetParent(window.frame)
|
||||
minimizeButton.frame:ClearAllPoints()
|
||||
minimizeButton.frame:SetPoint("TOPRIGHT", window.frame, "TOPRIGHT", -34, -4)
|
||||
minimizeButton.frame:SetHeight(20)
|
||||
minimizeButton.frame:Show()
|
||||
window.minimizeButton = minimizeButton
|
||||
end
|
||||
|
||||
self._aceWindows[key] = window
|
||||
if options.onCreate then
|
||||
options.onCreate(window, window.content, widget)
|
||||
end
|
||||
window:SetMinimized(statusTable and statusTable.minimized)
|
||||
return window
|
||||
end
|
||||
486
Core/DebugWindow.lua
Normal file
486
Core/DebugWindow.lua
Normal file
@@ -0,0 +1,486 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = _G[ADDON_NAME]
|
||||
if not HMGT then return end
|
||||
|
||||
local L = HMGT.L or LibStub("AceLocale-3.0"):GetLocale(ADDON_NAME)
|
||||
local AceGUI = LibStub("AceGUI-3.0", true)
|
||||
|
||||
local function GetOrderedDebugLevels()
|
||||
return { "error", "info", "verbose" }
|
||||
end
|
||||
|
||||
local function GetOrderedDebugScopes()
|
||||
local values = HMGT:GetDebugScopeOptions() or {}
|
||||
local names = { "ALL" }
|
||||
for scope in pairs(values) do
|
||||
if scope ~= "ALL" then
|
||||
names[#names + 1] = scope
|
||||
end
|
||||
end
|
||||
table.sort(names, function(a, b)
|
||||
if a == "ALL" then return true end
|
||||
if b == "ALL" then return false end
|
||||
return tostring(values[a] or a) < tostring(values[b] or b)
|
||||
end)
|
||||
return names, values
|
||||
end
|
||||
|
||||
local function SetFilterButtonText(buttonWidget, prefix, valueLabel)
|
||||
if not buttonWidget then
|
||||
return
|
||||
end
|
||||
buttonWidget:SetText(string.format("%s: %s", tostring(prefix or ""), tostring(valueLabel or "")))
|
||||
end
|
||||
|
||||
local function AdvanceDebugLevel(step)
|
||||
local levels = GetOrderedDebugLevels()
|
||||
local current = HMGT:GetConfiguredDebugLevel()
|
||||
local nextIndex = 1
|
||||
for index, value in ipairs(levels) do
|
||||
if value == current then
|
||||
nextIndex = index + (step or 1)
|
||||
break
|
||||
end
|
||||
end
|
||||
if nextIndex < 1 then
|
||||
nextIndex = #levels
|
||||
elseif nextIndex > #levels then
|
||||
nextIndex = 1
|
||||
end
|
||||
HMGT.db.profile.debugLevel = levels[nextIndex]
|
||||
HMGT:RefreshDebugWindow()
|
||||
end
|
||||
|
||||
local function AdvanceDebugScope(step)
|
||||
local scopes, labels = GetOrderedDebugScopes()
|
||||
local current = (HMGT.db and HMGT.db.profile and HMGT.db.profile.debugScope) or "ALL"
|
||||
local nextIndex = 1
|
||||
for index, value in ipairs(scopes) do
|
||||
if value == current then
|
||||
nextIndex = index + (step or 1)
|
||||
break
|
||||
end
|
||||
end
|
||||
if nextIndex < 1 then
|
||||
nextIndex = #scopes
|
||||
elseif nextIndex > #scopes then
|
||||
nextIndex = 1
|
||||
end
|
||||
HMGT.db.profile.debugScope = scopes[nextIndex]
|
||||
HMGT:RefreshDebugWindow()
|
||||
end
|
||||
|
||||
function HMGT:SetDebugWindowMinimized(minimized)
|
||||
local frame = self.debugWindow
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
|
||||
minimized = minimized and true or false
|
||||
self.debugWindowStatus = self.debugWindowStatus or {
|
||||
width = 860,
|
||||
height = 340,
|
||||
}
|
||||
self.debugWindowStatus.minimized = minimized
|
||||
|
||||
local collapsedHeight = 64
|
||||
if minimized then
|
||||
self.debugWindowStatus.restoreHeight = self.debugWindowStatus.height or frame:GetHeight() or 340
|
||||
end
|
||||
|
||||
local targetHeight = minimized
|
||||
and collapsedHeight
|
||||
or (self.debugWindowStatus.restoreHeight or self.debugWindowStatus.height or 340)
|
||||
|
||||
if frame.aceWidget then
|
||||
frame.aceWidget:EnableResize(not minimized)
|
||||
frame.aceWidget:SetHeight(targetHeight)
|
||||
else
|
||||
frame:SetHeight(targetHeight)
|
||||
end
|
||||
|
||||
if frame.minimizeButton then
|
||||
frame.minimizeButton:SetText(minimized and "+" or "-")
|
||||
end
|
||||
if frame.clearButton then
|
||||
local buttonFrame = frame.clearButton.frame or frame.clearButton
|
||||
buttonFrame:SetShown(not minimized)
|
||||
end
|
||||
if frame.selectButton then
|
||||
local buttonFrame = frame.selectButton.frame or frame.selectButton
|
||||
buttonFrame:SetShown(not minimized)
|
||||
end
|
||||
if frame.levelFilter then
|
||||
local filterFrame = frame.levelFilter.frame or frame.levelFilter
|
||||
filterFrame:SetShown(not minimized)
|
||||
end
|
||||
if frame.scopeFilter then
|
||||
local filterFrame = frame.scopeFilter.frame or frame.scopeFilter
|
||||
filterFrame:SetShown(not minimized)
|
||||
end
|
||||
if frame.logWidget then
|
||||
frame.logWidget.frame:SetShown(not minimized)
|
||||
end
|
||||
if frame.scrollBG then
|
||||
frame.scrollBG:SetShown(not minimized)
|
||||
end
|
||||
|
||||
if not minimized then
|
||||
self:RefreshDebugWindow()
|
||||
end
|
||||
end
|
||||
|
||||
function HMGT:ToggleDebugWindowMinimized()
|
||||
self:SetDebugWindowMinimized(not (self.debugWindowStatus and self.debugWindowStatus.minimized))
|
||||
end
|
||||
|
||||
function HMGT:EnsureDebugWindow()
|
||||
if self.debugWindow then
|
||||
return self.debugWindow
|
||||
end
|
||||
|
||||
local frameWidget
|
||||
if AceGUI then
|
||||
frameWidget = AceGUI:Create("Frame")
|
||||
self.debugWindowStatus = self.debugWindowStatus or {
|
||||
width = 860,
|
||||
height = 340,
|
||||
}
|
||||
frameWidget:SetTitle(L["DEBUG_WINDOW_TITLE"] or "HMGT Debug Console")
|
||||
frameWidget:SetStatusText(L["DEBUG_WINDOW_HINT"] or "Mouse wheel scrolls, Ctrl+A selects all, Ctrl+C copies selected text")
|
||||
frameWidget:SetStatusTable(self.debugWindowStatus)
|
||||
frameWidget:SetWidth(self.debugWindowStatus.width or 860)
|
||||
frameWidget:SetHeight(self.debugWindowStatus.height or 340)
|
||||
frameWidget:EnableResize(true)
|
||||
frameWidget.frame:SetClampedToScreen(true)
|
||||
frameWidget.frame:SetToplevel(true)
|
||||
frameWidget.frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
frameWidget:Hide()
|
||||
end
|
||||
|
||||
local frame = frameWidget and frameWidget.frame or CreateFrame("Frame", "HMGT_DebugWindow", UIParent, "BackdropTemplate")
|
||||
if not frameWidget then
|
||||
frame:SetSize(860, 340)
|
||||
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
|
||||
frame:SetFrameStrata("DIALOG")
|
||||
frame:SetClampedToScreen(true)
|
||||
frame:SetMovable(true)
|
||||
frame:EnableMouse(true)
|
||||
frame:RegisterForDrag("LeftButton")
|
||||
frame:SetScript("OnDragStart", function(selfFrame) selfFrame:StartMoving() end)
|
||||
frame:SetScript("OnDragStop", function(selfFrame) selfFrame:StopMovingOrSizing() end)
|
||||
frame:SetBackdrop({
|
||||
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
edgeSize = 12,
|
||||
insets = { left = 3, right = 3, top = 3, bottom = 3 },
|
||||
})
|
||||
frame:SetBackdropColor(0.05, 0.05, 0.06, 0.95)
|
||||
frame:SetBackdropBorderColor(0.35, 0.55, 0.85, 1)
|
||||
frame:Hide()
|
||||
|
||||
local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
||||
title:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -12)
|
||||
title:SetText(L["DEBUG_WINDOW_TITLE"] or "HMGT Debug Console")
|
||||
frame.title = title
|
||||
|
||||
local closeButton = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
|
||||
closeButton:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -5, -5)
|
||||
frame.closeButton = closeButton
|
||||
|
||||
local minimizeButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
||||
minimizeButton:SetSize(22, 20)
|
||||
minimizeButton:SetPoint("TOPRIGHT", closeButton, "TOPLEFT", -2, 0)
|
||||
minimizeButton:SetText((self.debugWindowStatus and self.debugWindowStatus.minimized) and "+" or "-")
|
||||
minimizeButton:SetScript("OnClick", function()
|
||||
HMGT:ToggleDebugWindowMinimized()
|
||||
end)
|
||||
frame.minimizeButton = minimizeButton
|
||||
end
|
||||
|
||||
frame.aceWidget = frameWidget
|
||||
|
||||
if frameWidget and AceGUI then
|
||||
local content = frameWidget.content
|
||||
|
||||
local minimizeButton = AceGUI:Create("Button")
|
||||
minimizeButton:SetText((self.debugWindowStatus and self.debugWindowStatus.minimized) and "+" or "-")
|
||||
minimizeButton:SetWidth(24)
|
||||
minimizeButton:SetCallback("OnClick", function()
|
||||
HMGT:ToggleDebugWindowMinimized()
|
||||
end)
|
||||
minimizeButton.frame:SetParent(frame)
|
||||
minimizeButton.frame:ClearAllPoints()
|
||||
minimizeButton.frame:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -34, -4)
|
||||
minimizeButton.frame:SetHeight(20)
|
||||
minimizeButton.frame:Show()
|
||||
frame.minimizeButton = minimizeButton
|
||||
|
||||
local clearButton = AceGUI:Create("Button")
|
||||
clearButton:SetText(L["OPT_DEBUG_CLEAR"] or "Clear log")
|
||||
clearButton:SetWidth(120)
|
||||
clearButton:SetCallback("OnClick", function()
|
||||
HMGT:ClearDebugLog()
|
||||
end)
|
||||
clearButton.frame:SetParent(content)
|
||||
clearButton.frame:ClearAllPoints()
|
||||
clearButton.frame:SetPoint("TOPRIGHT", content, "TOPRIGHT", 0, -2)
|
||||
clearButton.frame:Show()
|
||||
frame.clearButton = clearButton
|
||||
|
||||
local selectButton = AceGUI:Create("Button")
|
||||
selectButton:SetText(L["OPT_DEBUG_SELECT_ALL"] or "Select all")
|
||||
selectButton:SetWidth(120)
|
||||
selectButton:SetCallback("OnClick", function()
|
||||
if frame.editBox then
|
||||
frame.editBox:SetFocus()
|
||||
frame.editBox:HighlightText(0)
|
||||
end
|
||||
end)
|
||||
selectButton.frame:SetParent(content)
|
||||
selectButton.frame:ClearAllPoints()
|
||||
selectButton.frame:SetPoint("TOPRIGHT", clearButton.frame, "TOPLEFT", -6, 0)
|
||||
selectButton.frame:Show()
|
||||
frame.selectButton = selectButton
|
||||
|
||||
local levelFilter = AceGUI:Create("Button")
|
||||
levelFilter:SetWidth(150)
|
||||
levelFilter:SetCallback("OnClick", function()
|
||||
AdvanceDebugLevel(1)
|
||||
end)
|
||||
levelFilter.frame:SetParent(content)
|
||||
levelFilter.frame:ClearAllPoints()
|
||||
levelFilter.frame:SetPoint("TOPLEFT", content, "TOPLEFT", 0, 0)
|
||||
levelFilter.frame:Show()
|
||||
frame.levelFilter = levelFilter
|
||||
|
||||
local scopeFilter = AceGUI:Create("Button")
|
||||
scopeFilter:SetWidth(180)
|
||||
scopeFilter:SetCallback("OnClick", function()
|
||||
AdvanceDebugScope(1)
|
||||
end)
|
||||
scopeFilter.frame:SetParent(content)
|
||||
scopeFilter.frame:ClearAllPoints()
|
||||
scopeFilter.frame:SetPoint("TOPLEFT", levelFilter.frame, "TOPRIGHT", 8, 0)
|
||||
scopeFilter.frame:Show()
|
||||
frame.scopeFilter = scopeFilter
|
||||
|
||||
local logWidget = AceGUI:Create("MultiLineEditBox")
|
||||
logWidget:SetLabel("")
|
||||
logWidget:DisableButton(true)
|
||||
logWidget:SetNumLines(18)
|
||||
logWidget:SetText("")
|
||||
logWidget.frame:SetParent(content)
|
||||
logWidget.frame:ClearAllPoints()
|
||||
logWidget.frame:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -54)
|
||||
logWidget.frame:SetPoint("BOTTOMRIGHT", content, "BOTTOMRIGHT", 0, 0)
|
||||
logWidget.frame:Show()
|
||||
logWidget:SetCallback("OnTextChanged", function()
|
||||
HMGT:RefreshDebugWindow()
|
||||
end)
|
||||
logWidget.editBox:SetScript("OnKeyDown", function(selfBox, key)
|
||||
if IsControlKeyDown() and (key == "A" or key == "a") then
|
||||
selfBox:HighlightText(0)
|
||||
end
|
||||
end)
|
||||
frame.logWidget = logWidget
|
||||
frame.editBox = logWidget.editBox
|
||||
frame.scrollFrame = logWidget.scrollFrame
|
||||
|
||||
self.debugWindow = frame
|
||||
self:SetDebugWindowMinimized(self.debugWindowStatus and self.debugWindowStatus.minimized)
|
||||
return frame
|
||||
end
|
||||
|
||||
local clearButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
||||
clearButton:SetSize(90, 22)
|
||||
clearButton:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -30, -6)
|
||||
clearButton:SetText(L["OPT_DEBUG_CLEAR"] or "Clear log")
|
||||
clearButton:SetScript("OnClick", function()
|
||||
HMGT:ClearDebugLog()
|
||||
end)
|
||||
frame.clearButton = clearButton
|
||||
|
||||
local selectButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
||||
selectButton:SetSize(90, 22)
|
||||
selectButton:SetPoint("TOPRIGHT", clearButton, "TOPLEFT", -6, 0)
|
||||
selectButton:SetText(L["OPT_DEBUG_SELECT_ALL"] or "Select all")
|
||||
selectButton:SetScript("OnClick", function()
|
||||
if frame.editBox then
|
||||
frame.editBox:SetFocus()
|
||||
frame.editBox:HighlightText(0)
|
||||
end
|
||||
end)
|
||||
frame.selectButton = selectButton
|
||||
|
||||
local scopeFilter = CreateFrame("Frame", nil, frame)
|
||||
scopeFilter:SetSize(170, 22)
|
||||
scopeFilter:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -8)
|
||||
frame.scopeFilter = scopeFilter
|
||||
|
||||
local scrollBG = CreateFrame("Frame", nil, frame, "BackdropTemplate")
|
||||
scrollBG:SetBackdrop({
|
||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
edgeSize = 16,
|
||||
insets = { left = 4, right = 3, top = 4, bottom = 3 },
|
||||
})
|
||||
scrollBG:SetBackdropColor(0, 0, 0, 0.95)
|
||||
scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
|
||||
scrollBG:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -36)
|
||||
scrollBG:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -30, 14)
|
||||
frame.scrollBG = scrollBG
|
||||
|
||||
local scrollFrame = CreateFrame("ScrollFrame", nil, scrollBG, "UIPanelScrollFrameTemplate")
|
||||
scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 6, -6)
|
||||
scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -27, 4)
|
||||
scrollFrame:EnableMouseWheel(true)
|
||||
scrollFrame:SetScript("OnMouseWheel", function(selfMsg, delta)
|
||||
if delta > 0 then
|
||||
selfMsg:SetVerticalScroll(math.max(0, selfMsg:GetVerticalScroll() - 42))
|
||||
else
|
||||
selfMsg:SetVerticalScroll(selfMsg:GetVerticalScroll() + 42)
|
||||
end
|
||||
end)
|
||||
frame.scrollFrame = scrollFrame
|
||||
|
||||
local editBox = CreateFrame("EditBox", nil, scrollFrame)
|
||||
editBox:SetMultiLine(true)
|
||||
editBox:SetAutoFocus(false)
|
||||
editBox:SetFontObject(ChatFontNormal)
|
||||
editBox:SetWidth(780)
|
||||
editBox:SetTextInsets(6, 6, 6, 6)
|
||||
editBox:EnableMouse(true)
|
||||
editBox:SetScript("OnEscapePressed", function(selfBox)
|
||||
selfBox:ClearFocus()
|
||||
end)
|
||||
editBox:SetScript("OnKeyDown", function(selfBox, key)
|
||||
if IsControlKeyDown() and (key == "A" or key == "a") then
|
||||
selfBox:HighlightText(0)
|
||||
end
|
||||
end)
|
||||
editBox:SetScript("OnTextChanged", function(selfBox, userInput)
|
||||
if userInput then
|
||||
HMGT:RefreshDebugWindow()
|
||||
else
|
||||
selfBox:SetCursorPosition(selfBox:GetNumLetters())
|
||||
selfBox:SetHeight(math.max(scrollFrame:GetHeight(), HMGT:GetDebugWindowTextHeight(frame, selfBox:GetText()) + 16))
|
||||
scrollFrame:UpdateScrollChildRect()
|
||||
end
|
||||
end)
|
||||
editBox:SetScript("OnMouseUp", function(selfBox)
|
||||
selfBox:SetFocus()
|
||||
end)
|
||||
scrollFrame:SetScrollChild(editBox)
|
||||
frame.editBox = editBox
|
||||
|
||||
local measureText = frame:CreateFontString(nil, "ARTWORK", "ChatFontNormal")
|
||||
measureText:SetJustifyH("LEFT")
|
||||
measureText:SetJustifyV("TOP")
|
||||
if measureText.SetSpacing then
|
||||
measureText:SetSpacing(2)
|
||||
end
|
||||
measureText:SetWidth(768)
|
||||
frame.measureText = measureText
|
||||
|
||||
self.debugWindow = frame
|
||||
self:SetDebugWindowMinimized(self.debugWindowStatus and self.debugWindowStatus.minimized)
|
||||
return frame
|
||||
end
|
||||
|
||||
function HMGT:GetDebugWindowTextHeight(frame, text)
|
||||
if not frame or not frame.measureText then
|
||||
return 0
|
||||
end
|
||||
|
||||
local width = 768
|
||||
if frame.editBox then
|
||||
width = math.max(1, (frame.editBox:GetWidth() or width) - 12)
|
||||
end
|
||||
frame.measureText:SetWidth(width)
|
||||
frame.measureText:SetText(text or "")
|
||||
return frame.measureText:GetStringHeight()
|
||||
end
|
||||
|
||||
function HMGT:RefreshDebugWindow()
|
||||
local frame = self:EnsureDebugWindow()
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
|
||||
local filtered = self:GetFilteredDebugBuffer() or self.debugBuffer or {}
|
||||
local text = table.concat(filtered, "\n")
|
||||
if frame.logWidget and frame.editBox then
|
||||
if frame.levelFilter then
|
||||
local levelOptions = self:GetDebugLevelOptions()
|
||||
SetFilterButtonText(frame.levelFilter, L["OPT_DEBUG_LEVEL"] or "Level", levelOptions[self:GetConfiguredDebugLevel()])
|
||||
end
|
||||
if frame.scopeFilter then
|
||||
local scopeOptions = self:GetDebugScopeOptions()
|
||||
local currentScope = (self.db and self.db.profile and self.db.profile.debugScope) or "ALL"
|
||||
SetFilterButtonText(frame.scopeFilter, L["OPT_DEBUG_SCOPE"] or "Module", scopeOptions[currentScope] or currentScope)
|
||||
end
|
||||
frame.logWidget:SetText(text)
|
||||
frame.editBox:SetCursorPosition(frame.editBox:GetNumLetters())
|
||||
return
|
||||
end
|
||||
|
||||
if not frame.editBox then
|
||||
return
|
||||
end
|
||||
|
||||
frame.editBox:SetText(text)
|
||||
frame.editBox:SetCursorPosition(#text)
|
||||
frame.editBox:SetHeight(math.max(frame.scrollFrame:GetHeight(), self:GetDebugWindowTextHeight(frame, text) + 16))
|
||||
frame.scrollFrame:SetVerticalScroll(math.max(0, frame.editBox:GetHeight() - frame.scrollFrame:GetHeight()))
|
||||
end
|
||||
|
||||
function HMGT:UpdateDebugWindowVisibility()
|
||||
if self.db and self.db.profile then
|
||||
self.db.profile.debug = false
|
||||
end
|
||||
local frame = self.debugWindow
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
local widget = frame.aceWidget
|
||||
if widget then
|
||||
widget:Hide()
|
||||
else
|
||||
frame:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
function HMGT:ClearDebugLog()
|
||||
wipe(self.debugBuffer)
|
||||
if self.debugWindow and self.debugWindow.logWidget then
|
||||
self.debugWindow.logWidget:SetText("")
|
||||
self.debugWindow.editBox:SetCursorPosition(0)
|
||||
self.debugWindow.scrollFrame:SetVerticalScroll(0)
|
||||
return
|
||||
end
|
||||
if self.debugWindow and self.debugWindow.editBox then
|
||||
self.debugWindow.editBox:SetText("")
|
||||
self.debugWindow.scrollFrame:SetVerticalScroll(0)
|
||||
end
|
||||
end
|
||||
|
||||
function HMGT:ToggleDebugWindowShortcut()
|
||||
if self.db and self.db.profile then
|
||||
self.db.profile.debug = false
|
||||
end
|
||||
local frame = self.debugWindow
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
local widget = frame.aceWidget
|
||||
if widget then
|
||||
widget:Hide()
|
||||
else
|
||||
frame:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
function HMGT:DumpDebugLog(maxLines)
|
||||
return
|
||||
end
|
||||
227
Core/DevTools.lua
Normal file
227
Core/DevTools.lua
Normal file
@@ -0,0 +1,227 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = _G[ADDON_NAME]
|
||||
if not HMGT then return end
|
||||
|
||||
local L = HMGT.L or LibStub("AceLocale-3.0"):GetLocale(ADDON_NAME)
|
||||
|
||||
HMGT.devToolsBuffer = HMGT.devToolsBuffer or {}
|
||||
HMGT.devToolsBufferMax = HMGT.devToolsBufferMax or 300
|
||||
|
||||
local DEVTOOLS_SCOPE_ALL = "ALL"
|
||||
local DEVTOOLS_SCOPE_LABELS = {
|
||||
System = "System",
|
||||
Version = "Version",
|
||||
Options = "Options",
|
||||
Comm = "Communication",
|
||||
Tracker = "Tracker",
|
||||
RaidTimeline = "Raid Timeline",
|
||||
Notes = "Notes",
|
||||
}
|
||||
|
||||
local DEVTOOLS_LEVELS = {
|
||||
error = 1,
|
||||
trace = 2,
|
||||
}
|
||||
|
||||
local function TrimText(value)
|
||||
return tostring(value or ""):gsub("^%s+", ""):gsub("%s+$", "")
|
||||
end
|
||||
|
||||
local function SortKeys(tbl)
|
||||
local keys = {}
|
||||
for key in pairs(tbl or {}) do
|
||||
keys[#keys + 1] = key
|
||||
end
|
||||
table.sort(keys, function(a, b)
|
||||
return tostring(a) < tostring(b)
|
||||
end)
|
||||
return keys
|
||||
end
|
||||
|
||||
local function EncodePayloadValue(value, depth)
|
||||
depth = tonumber(depth) or 0
|
||||
local valueType = type(value)
|
||||
if valueType == "nil" then
|
||||
return "nil"
|
||||
end
|
||||
if valueType == "string" then
|
||||
return value
|
||||
end
|
||||
if valueType == "number" or valueType == "boolean" then
|
||||
return tostring(value)
|
||||
end
|
||||
if valueType == "table" then
|
||||
if depth >= 1 then
|
||||
return "{...}"
|
||||
end
|
||||
local parts = {}
|
||||
for _, key in ipairs(SortKeys(value)) do
|
||||
parts[#parts + 1] = string.format("%s=%s", tostring(key), EncodePayloadValue(value[key], depth + 1))
|
||||
end
|
||||
return table.concat(parts, ", ")
|
||||
end
|
||||
return tostring(value)
|
||||
end
|
||||
|
||||
function HMGT:GetDevToolsSettings()
|
||||
local profile = self.db and self.db.profile
|
||||
if not profile then
|
||||
return {
|
||||
enabled = false,
|
||||
level = "error",
|
||||
scope = DEVTOOLS_SCOPE_ALL,
|
||||
window = { width = 920, height = 420, minimized = false },
|
||||
}
|
||||
end
|
||||
profile.devTools = type(profile.devTools) == "table" and profile.devTools or {}
|
||||
local settings = profile.devTools
|
||||
settings.enabled = settings.enabled == true
|
||||
if settings.level ~= "error" and settings.level ~= "trace" then
|
||||
settings.level = "error"
|
||||
end
|
||||
if type(settings.scope) ~= "string" or settings.scope == "" then
|
||||
settings.scope = DEVTOOLS_SCOPE_ALL
|
||||
end
|
||||
settings.window = type(settings.window) == "table" and settings.window or {}
|
||||
settings.window.width = math.max(720, tonumber(settings.window.width) or 920)
|
||||
settings.window.height = math.max(260, tonumber(settings.window.height) or 420)
|
||||
settings.window.minimized = settings.window.minimized == true
|
||||
return settings
|
||||
end
|
||||
|
||||
function HMGT:IsDevToolsEnabled()
|
||||
return self:GetDevToolsSettings().enabled == true
|
||||
end
|
||||
|
||||
function HMGT:GetDevToolsLevelOptions()
|
||||
return {
|
||||
error = L["OPT_DEVTOOLS_LEVEL_ERROR"] or "Errors",
|
||||
trace = L["OPT_DEVTOOLS_LEVEL_TRACE"] or "Trace",
|
||||
}
|
||||
end
|
||||
|
||||
function HMGT:GetConfiguredDevToolsLevel()
|
||||
return self:GetDevToolsSettings().level or "error"
|
||||
end
|
||||
|
||||
function HMGT:ShouldIncludeDevToolsLevel(level)
|
||||
local configured = self:GetConfiguredDevToolsLevel()
|
||||
return (DEVTOOLS_LEVELS[tostring(level or "error")] or DEVTOOLS_LEVELS.error)
|
||||
<= (DEVTOOLS_LEVELS[configured] or DEVTOOLS_LEVELS.error)
|
||||
end
|
||||
|
||||
function HMGT:GetDevToolsScopeOptions()
|
||||
local values = {
|
||||
[DEVTOOLS_SCOPE_ALL] = L["OPT_DEVTOOLS_SCOPE_ALL"] or "All scopes",
|
||||
}
|
||||
for scope, label in pairs(DEVTOOLS_SCOPE_LABELS) do
|
||||
values[scope] = label
|
||||
end
|
||||
for _, entry in ipairs(self.devToolsBuffer or {}) do
|
||||
local scope = TrimText(entry and entry.scope or "")
|
||||
if scope ~= "" and scope ~= DEVTOOLS_SCOPE_ALL then
|
||||
values[scope] = values[scope] or scope
|
||||
end
|
||||
end
|
||||
return values
|
||||
end
|
||||
|
||||
function HMGT:FormatDevToolsEntry(entry)
|
||||
local stamp = tostring(entry and entry.stamp or date("%H:%M:%S"))
|
||||
local level = string.upper(tostring(entry and entry.level or "error"))
|
||||
local scope = tostring(entry and entry.scope or "System")
|
||||
local eventName = tostring(entry and entry.event or "")
|
||||
local payload = TrimText(entry and entry.payload or "")
|
||||
if payload ~= "" then
|
||||
return string.format("%s [%s][%s] %s | %s", stamp, level, scope, eventName, payload)
|
||||
end
|
||||
return string.format("%s [%s][%s] %s", stamp, level, scope, eventName)
|
||||
end
|
||||
|
||||
function HMGT:GetFilteredDevToolsEntries()
|
||||
local filtered = {}
|
||||
local settings = self:GetDevToolsSettings()
|
||||
for _, entry in ipairs(self.devToolsBuffer or {}) do
|
||||
local scopeMatches = settings.scope == DEVTOOLS_SCOPE_ALL or settings.scope == tostring(entry.scope or "")
|
||||
if scopeMatches and self:ShouldIncludeDevToolsLevel(entry.level) then
|
||||
filtered[#filtered + 1] = entry
|
||||
end
|
||||
end
|
||||
return filtered
|
||||
end
|
||||
|
||||
function HMGT:GetFilteredDevToolsLines()
|
||||
local lines = {}
|
||||
for _, entry in ipairs(self:GetFilteredDevToolsEntries()) do
|
||||
lines[#lines + 1] = self:FormatDevToolsEntry(entry)
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
function HMGT:RecordDevEvent(level, scope, eventName, payload)
|
||||
if not self:IsDevToolsEnabled() then
|
||||
return
|
||||
end
|
||||
|
||||
local normalizedLevel = tostring(level or "error")
|
||||
if normalizedLevel ~= "error" and normalizedLevel ~= "trace" then
|
||||
normalizedLevel = "trace"
|
||||
end
|
||||
if not self:ShouldIncludeDevToolsLevel(normalizedLevel) then
|
||||
return
|
||||
end
|
||||
|
||||
local normalizedScope = TrimText(scope or "System")
|
||||
if normalizedScope == "" then
|
||||
normalizedScope = "System"
|
||||
end
|
||||
|
||||
local entry = {
|
||||
stamp = date("%H:%M:%S"),
|
||||
level = normalizedLevel,
|
||||
scope = normalizedScope,
|
||||
event = TrimText(eventName or "event"),
|
||||
payload = EncodePayloadValue(payload, 0),
|
||||
}
|
||||
|
||||
table.insert(self.devToolsBuffer, entry)
|
||||
if #self.devToolsBuffer > (tonumber(self.devToolsBufferMax) or 300) then
|
||||
table.remove(self.devToolsBuffer, 1)
|
||||
end
|
||||
|
||||
if self.devToolsWindow and self.devToolsWindow:IsShown() and self.RefreshDevToolsWindow then
|
||||
self:RefreshDevToolsWindow()
|
||||
end
|
||||
end
|
||||
|
||||
function HMGT:DevError(scope, eventName, payload)
|
||||
self:RecordDevEvent("error", scope, eventName, payload)
|
||||
end
|
||||
|
||||
function HMGT:DevTrace(scope, eventName, payload)
|
||||
self:RecordDevEvent("trace", scope, eventName, payload)
|
||||
end
|
||||
|
||||
function HMGT:ClearDevToolsLog()
|
||||
wipe(self.devToolsBuffer)
|
||||
if self.devToolsWindow and self.devToolsWindow.editBox then
|
||||
self.devToolsWindow.editBox:SetText("")
|
||||
self.devToolsWindow.editBox:SetCursorPosition(0)
|
||||
end
|
||||
end
|
||||
|
||||
function HMGT:DumpDevToolsLog(maxLines)
|
||||
if self:IsDevToolsEnabled() and self.OpenDevToolsWindow then
|
||||
self:OpenDevToolsWindow()
|
||||
return
|
||||
end
|
||||
|
||||
local lines = tonumber(maxLines) or 40
|
||||
if lines < 1 then
|
||||
lines = 1
|
||||
end
|
||||
local startIndex = math.max(1, #self.devToolsBuffer - lines + 1)
|
||||
for i = startIndex, #self.devToolsBuffer do
|
||||
self:Print(self:FormatDevToolsEntry(self.devToolsBuffer[i]))
|
||||
end
|
||||
end
|
||||
254
Core/DevToolsWindow.lua
Normal file
254
Core/DevToolsWindow.lua
Normal file
@@ -0,0 +1,254 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = _G[ADDON_NAME]
|
||||
if not HMGT then return end
|
||||
|
||||
local L = HMGT.L or LibStub("AceLocale-3.0"):GetLocale(ADDON_NAME)
|
||||
local AceGUI = LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI then return end
|
||||
|
||||
local function GetOrderedLevels()
|
||||
return { "error", "trace" }
|
||||
end
|
||||
|
||||
local function GetOrderedScopes()
|
||||
local values = HMGT:GetDevToolsScopeOptions() or {}
|
||||
local scopes = { "ALL" }
|
||||
for scope in pairs(values) do
|
||||
if scope ~= "ALL" then
|
||||
scopes[#scopes + 1] = scope
|
||||
end
|
||||
end
|
||||
table.sort(scopes, function(a, b)
|
||||
if a == "ALL" then return true end
|
||||
if b == "ALL" then return false end
|
||||
return tostring(values[a] or a) < tostring(values[b] or b)
|
||||
end)
|
||||
return scopes, values
|
||||
end
|
||||
|
||||
local function SetFilterButtonText(buttonWidget, prefix, valueLabel)
|
||||
if not buttonWidget then
|
||||
return
|
||||
end
|
||||
buttonWidget:SetText(string.format("%s: %s", tostring(prefix or ""), tostring(valueLabel or "")))
|
||||
end
|
||||
|
||||
local function AdvanceLevel(step)
|
||||
local levels = GetOrderedLevels()
|
||||
local current = HMGT:GetConfiguredDevToolsLevel()
|
||||
local nextIndex = 1
|
||||
for index, value in ipairs(levels) do
|
||||
if value == current then
|
||||
nextIndex = index + (step or 1)
|
||||
break
|
||||
end
|
||||
end
|
||||
if nextIndex < 1 then
|
||||
nextIndex = #levels
|
||||
elseif nextIndex > #levels then
|
||||
nextIndex = 1
|
||||
end
|
||||
HMGT:GetDevToolsSettings().level = levels[nextIndex]
|
||||
HMGT:RefreshDevToolsWindow()
|
||||
end
|
||||
|
||||
local function AdvanceScope(step)
|
||||
local scopes = GetOrderedScopes()
|
||||
local current = HMGT:GetDevToolsSettings().scope or "ALL"
|
||||
local nextIndex = 1
|
||||
for index, value in ipairs(scopes) do
|
||||
if value == current then
|
||||
nextIndex = index + (step or 1)
|
||||
break
|
||||
end
|
||||
end
|
||||
if nextIndex < 1 then
|
||||
nextIndex = #scopes
|
||||
elseif nextIndex > #scopes then
|
||||
nextIndex = 1
|
||||
end
|
||||
HMGT:GetDevToolsSettings().scope = scopes[nextIndex]
|
||||
HMGT:RefreshDevToolsWindow()
|
||||
end
|
||||
|
||||
function HMGT:EnsureDevToolsWindow()
|
||||
if self.devToolsWindow then
|
||||
return self.devToolsWindow
|
||||
end
|
||||
|
||||
local settings = self:GetDevToolsSettings()
|
||||
local window = self:CreateAceWindow("devTools", {
|
||||
title = L["DEVTOOLS_WINDOW_TITLE"] or "HMGT Developer Tools",
|
||||
statusText = L["DEVTOOLS_WINDOW_HINT"] or "Structured developer events for the current session",
|
||||
statusTable = settings.window,
|
||||
width = settings.window.width or 920,
|
||||
height = settings.window.height or 420,
|
||||
minimizable = true,
|
||||
minimizedHeight = 64,
|
||||
})
|
||||
if not window then
|
||||
return nil
|
||||
end
|
||||
|
||||
local content = window:GetContent()
|
||||
|
||||
local clearButton = AceGUI:Create("Button")
|
||||
clearButton:SetText(L["OPT_DEVTOOLS_CLEAR"] or "Clear developer log")
|
||||
clearButton:SetWidth(140)
|
||||
clearButton:SetCallback("OnClick", function()
|
||||
HMGT:ClearDevToolsLog()
|
||||
end)
|
||||
clearButton.frame:SetParent(content)
|
||||
clearButton.frame:ClearAllPoints()
|
||||
clearButton.frame:SetPoint("TOPRIGHT", content, "TOPRIGHT", 0, -2)
|
||||
clearButton.frame:Show()
|
||||
window.clearButton = clearButton
|
||||
window:RegisterMinimizeTarget(clearButton)
|
||||
|
||||
local selectButton = AceGUI:Create("Button")
|
||||
selectButton:SetText(L["OPT_DEVTOOLS_SELECT_ALL"] or "Select all")
|
||||
selectButton:SetWidth(120)
|
||||
selectButton:SetCallback("OnClick", function()
|
||||
if window.editBox then
|
||||
window.editBox:SetFocus()
|
||||
window.editBox:HighlightText(0)
|
||||
end
|
||||
end)
|
||||
selectButton.frame:SetParent(content)
|
||||
selectButton.frame:ClearAllPoints()
|
||||
selectButton.frame:SetPoint("TOPRIGHT", clearButton.frame, "TOPLEFT", -6, 0)
|
||||
selectButton.frame:Show()
|
||||
window.selectButton = selectButton
|
||||
window:RegisterMinimizeTarget(selectButton)
|
||||
|
||||
local levelFilter = AceGUI:Create("Button")
|
||||
levelFilter:SetWidth(150)
|
||||
levelFilter:SetCallback("OnClick", function()
|
||||
AdvanceLevel(1)
|
||||
end)
|
||||
levelFilter.frame:SetParent(content)
|
||||
levelFilter.frame:ClearAllPoints()
|
||||
levelFilter.frame:SetPoint("TOPLEFT", content, "TOPLEFT", 0, 0)
|
||||
levelFilter.frame:Show()
|
||||
window.levelFilter = levelFilter
|
||||
window:RegisterMinimizeTarget(levelFilter)
|
||||
|
||||
local scopeFilter = AceGUI:Create("Button")
|
||||
scopeFilter:SetWidth(200)
|
||||
scopeFilter:SetCallback("OnClick", function()
|
||||
AdvanceScope(1)
|
||||
end)
|
||||
scopeFilter.frame:SetParent(content)
|
||||
scopeFilter.frame:ClearAllPoints()
|
||||
scopeFilter.frame:SetPoint("TOPLEFT", levelFilter.frame, "TOPRIGHT", 8, 0)
|
||||
scopeFilter.frame:Show()
|
||||
window.scopeFilter = scopeFilter
|
||||
window:RegisterMinimizeTarget(scopeFilter)
|
||||
|
||||
local logWidget = AceGUI:Create("MultiLineEditBox")
|
||||
logWidget:SetLabel("")
|
||||
logWidget:DisableButton(true)
|
||||
logWidget:SetNumLines(20)
|
||||
logWidget:SetText("")
|
||||
logWidget.frame:SetParent(content)
|
||||
logWidget.frame:ClearAllPoints()
|
||||
logWidget.frame:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -54)
|
||||
logWidget.frame:SetPoint("BOTTOMRIGHT", content, "BOTTOMRIGHT", 0, 0)
|
||||
logWidget.frame:Show()
|
||||
logWidget.editBox:SetScript("OnKeyDown", function(selfBox, key)
|
||||
if IsControlKeyDown() and (key == "A" or key == "a") then
|
||||
selfBox:HighlightText(0)
|
||||
end
|
||||
end)
|
||||
window.logWidget = logWidget
|
||||
window.editBox = logWidget.editBox
|
||||
window:RegisterMinimizeTarget(logWidget)
|
||||
|
||||
self.devToolsWindow = window
|
||||
window:SetMinimized(settings.window.minimized)
|
||||
return window
|
||||
end
|
||||
|
||||
function HMGT:RefreshDevToolsWindow()
|
||||
local window = self:EnsureDevToolsWindow()
|
||||
if not window or not window.editBox or not window.logWidget then
|
||||
return
|
||||
end
|
||||
|
||||
local levelOptions = self:GetDevToolsLevelOptions()
|
||||
SetFilterButtonText(window.levelFilter, L["OPT_DEVTOOLS_LEVEL"] or "Capture level", levelOptions[self:GetConfiguredDevToolsLevel()])
|
||||
|
||||
local scopeValues = self:GetDevToolsScopeOptions()
|
||||
local currentScope = self:GetDevToolsSettings().scope or "ALL"
|
||||
SetFilterButtonText(window.scopeFilter, L["OPT_DEVTOOLS_SCOPE"] or "Scope", scopeValues[currentScope] or currentScope)
|
||||
|
||||
local text = table.concat(self:GetFilteredDevToolsLines(), "\n")
|
||||
window.logWidget:SetText(text)
|
||||
window.editBox:SetCursorPosition(window.editBox:GetNumLetters())
|
||||
end
|
||||
|
||||
function HMGT:OpenDevToolsWindow()
|
||||
if not self:IsDevToolsEnabled() then
|
||||
self:Print(L["OPT_DEVTOOLS_DISABLED"] or "HMGT: developer tools are not enabled.")
|
||||
return
|
||||
end
|
||||
local window = self:EnsureDevToolsWindow()
|
||||
if not window then
|
||||
return
|
||||
end
|
||||
window:Show()
|
||||
window:Raise()
|
||||
self:RefreshDevToolsWindow()
|
||||
end
|
||||
|
||||
function HMGT:ToggleDevToolsWindow()
|
||||
if not self:IsDevToolsEnabled() then
|
||||
self:Print(L["OPT_DEVTOOLS_DISABLED"] or "HMGT: developer tools are not enabled.")
|
||||
return
|
||||
end
|
||||
local window = self:EnsureDevToolsWindow()
|
||||
if not window then
|
||||
return
|
||||
end
|
||||
if window:IsShown() then
|
||||
window:Hide()
|
||||
return
|
||||
end
|
||||
window:Show()
|
||||
window:Raise()
|
||||
self:RefreshDevToolsWindow()
|
||||
end
|
||||
|
||||
function HMGT:UpdateDevToolsWindowVisibility()
|
||||
local window = self.devToolsWindow
|
||||
if not window then
|
||||
return
|
||||
end
|
||||
if not self:IsDevToolsEnabled() then
|
||||
window:Hide()
|
||||
return
|
||||
end
|
||||
if window:IsShown() then
|
||||
self:RefreshDevToolsWindow()
|
||||
end
|
||||
end
|
||||
|
||||
function HMGT:RefreshDebugWindow()
|
||||
self:RefreshDevToolsWindow()
|
||||
end
|
||||
|
||||
function HMGT:UpdateDebugWindowVisibility()
|
||||
self:UpdateDevToolsWindowVisibility()
|
||||
end
|
||||
|
||||
function HMGT:ClearDebugLog()
|
||||
self:ClearDevToolsLog()
|
||||
end
|
||||
|
||||
function HMGT:ToggleDebugWindowShortcut()
|
||||
self:ToggleDevToolsWindow()
|
||||
end
|
||||
|
||||
function HMGT:DumpDebugLog(maxLines)
|
||||
self:DumpDevToolsLog(maxLines)
|
||||
end
|
||||
103
Core/VersionNoticeWindow.lua
Normal file
103
Core/VersionNoticeWindow.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
local ADDON_NAME = "HailMaryGuildTools"
|
||||
local HMGT = _G[ADDON_NAME]
|
||||
if not HMGT then return end
|
||||
|
||||
local L = HMGT.L or LibStub("AceLocale-3.0"):GetLocale(ADDON_NAME)
|
||||
|
||||
function HMGT:EnsureVersionNoticeWindow()
|
||||
if self.versionNoticeWindow then
|
||||
return self.versionNoticeWindow
|
||||
end
|
||||
|
||||
self.versionNoticeWindowStatus = self.versionNoticeWindowStatus or {
|
||||
width = 560,
|
||||
height = 240,
|
||||
}
|
||||
|
||||
local window = self:CreateAceWindow("versionNotice", {
|
||||
title = L["VERSION_WINDOW_TITLE"] or "HMGT Version Check",
|
||||
statusText = "",
|
||||
statusTable = self.versionNoticeWindowStatus,
|
||||
width = self.versionNoticeWindowStatus.width or 560,
|
||||
height = self.versionNoticeWindowStatus.height or 240,
|
||||
backgroundTexture = "Interface\\AddOns\\HailMaryGuildTools\\Media\\HailMaryLogo.png",
|
||||
backgroundWidth = 220,
|
||||
backgroundHeight = 120,
|
||||
backgroundOffsetY = -8,
|
||||
backgroundAlpha = 0.12,
|
||||
strata = "FULLSCREEN_DIALOG",
|
||||
})
|
||||
if not window then
|
||||
return nil
|
||||
end
|
||||
|
||||
local content = window:GetContent()
|
||||
local messageText = content:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
|
||||
messageText:SetPoint("TOPLEFT", content, "TOPLEFT", 28, -28)
|
||||
messageText:SetPoint("TOPRIGHT", content, "TOPRIGHT", -28, -28)
|
||||
messageText:SetJustifyH("CENTER")
|
||||
messageText:SetJustifyV("MIDDLE")
|
||||
messageText:SetTextColor(1, 0.82, 0.1, 1)
|
||||
messageText:SetText(L["VERSION_WINDOW_MESSAGE"] or "A new version of Hail Mary Guild Tools is available.")
|
||||
window.messageText = messageText
|
||||
|
||||
local detailText = content:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
||||
detailText:SetPoint("TOPLEFT", messageText, "BOTTOMLEFT", 0, -18)
|
||||
detailText:SetPoint("TOPRIGHT", messageText, "BOTTOMRIGHT", 0, -18)
|
||||
detailText:SetJustifyH("CENTER")
|
||||
detailText:SetJustifyV("TOP")
|
||||
if detailText.SetSpacing then
|
||||
detailText:SetSpacing(2)
|
||||
end
|
||||
detailText:SetTextColor(0.9, 0.9, 0.9, 1)
|
||||
window.detailText = detailText
|
||||
|
||||
self.versionNoticeWindow = window
|
||||
return window
|
||||
end
|
||||
|
||||
function HMGT:ShowVersionMismatchPopup(playerName, detail, sourceTag, opts)
|
||||
opts = opts or {}
|
||||
|
||||
if playerName or detail or sourceTag then
|
||||
self.latestVersionMismatch = {
|
||||
playerName = playerName,
|
||||
detail = detail,
|
||||
sourceTag = sourceTag,
|
||||
}
|
||||
end
|
||||
|
||||
local info = self.latestVersionMismatch or {}
|
||||
local window = self:EnsureVersionNoticeWindow()
|
||||
if not window then
|
||||
return
|
||||
end
|
||||
local hasMismatch = info.playerName or info.detail
|
||||
|
||||
window:SetTitle(L["VERSION_WINDOW_TITLE"] or "HMGT Version Check")
|
||||
|
||||
if hasMismatch then
|
||||
window.messageText:SetText(L["VERSION_WINDOW_MESSAGE"] or "A new version of Hail Mary Guild Tools is available.")
|
||||
window.detailText:SetText(string.format(
|
||||
L["VERSION_WINDOW_DETAIL"] or "Detected via %s from %s.\n%s",
|
||||
tostring(info.sourceTag or "?"),
|
||||
tostring(info.playerName or UNKNOWN),
|
||||
tostring(info.detail or "")
|
||||
))
|
||||
else
|
||||
window.messageText:SetText(L["VERSION_WINDOW_NO_MISMATCH"] or "No newer HMGT version has been detected in your current group.")
|
||||
window.detailText:SetText(string.format(
|
||||
L["VERSION_WINDOW_CURRENT"] or "Current version: %s | Protocol: %s",
|
||||
tostring(HMGT.ADDON_VERSION or "dev"),
|
||||
tostring(HMGT.PROTOCOL_VERSION or "?")
|
||||
))
|
||||
end
|
||||
|
||||
self:DevTrace("Version", hasMismatch and "window_show_mismatch" or "window_show_current", {
|
||||
player = info.playerName,
|
||||
source = info.sourceTag,
|
||||
detail = info.detail,
|
||||
})
|
||||
window:Show()
|
||||
window:Raise()
|
||||
end
|
||||
Reference in New Issue
Block a user