Dateien nach "UI" hochladen
This commit is contained in:
+1039
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,127 @@
|
||||
-- Freewood-OctoWoW-Core: Aufbau des Hauptfensters (OctoWoW)
|
||||
--
|
||||
-- Ersetzt MainWindow.xml. OctoWoW (1.12.1) bricht beim Laden ab, sobald ein <Size> nur x ODER y hat
|
||||
-- ("No x or y attributes in element: Size"); dann entstehen keine Unterframes und das ganze Fenster fehlt.
|
||||
-- Der Aufbau in Lua ist unabhaengig vom XML-Parser des Clients. Die Struktur ist dieselbe wie vorher:
|
||||
-- FreewoodMainFrame.Header (Bg, Accent, Logo, Title, Subtitle)
|
||||
-- FreewoodMainFrame.TabBar (Bg, Line)
|
||||
-- FreewoodMainFrame.Footer (Bg, Left)
|
||||
-- FreewoodMainFrame.Content
|
||||
-- Farben: Hintergrund #0f131f, Kopfzeile #0c0e14, Leiste #141824, Gold #c89b3c, Bronze #9d7826.
|
||||
|
||||
local ADDON, FW = ...
|
||||
|
||||
if _G.FreewoodMainFrame then
|
||||
return
|
||||
end
|
||||
|
||||
local function Solid(tex, r, g, b, a)
|
||||
tex:SetTexture(r, g, b, a)
|
||||
end
|
||||
|
||||
local function NewTexture(parent, layer, r, g, b, a)
|
||||
local t = parent:CreateTexture(nil, layer)
|
||||
Solid(t, r, g, b, a)
|
||||
return t
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame", "FreewoodMainFrame", UIParent)
|
||||
frame:SetFrameStrata("HIGH")
|
||||
frame:SetToplevel(true)
|
||||
frame:SetMovable(true)
|
||||
frame:SetClampedToScreen(true)
|
||||
frame:EnableMouse(true)
|
||||
frame:SetWidth(960)
|
||||
frame:SetHeight(760)
|
||||
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
|
||||
frame:Hide()
|
||||
|
||||
-- Hintergrund und Rahmen
|
||||
frame.Bg = NewTexture(frame, "BACKGROUND", 0.059, 0.075, 0.122, 0.97)
|
||||
frame.Bg:SetAllPoints(frame)
|
||||
|
||||
local gold = { 0.616, 0.471, 0.149, 1 }
|
||||
|
||||
frame.BorderTop = NewTexture(frame, "BORDER", gold[1], gold[2], gold[3], gold[4])
|
||||
frame.BorderTop:SetHeight(1)
|
||||
frame.BorderTop:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
|
||||
frame.BorderTop:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 0)
|
||||
|
||||
frame.BorderBottom = NewTexture(frame, "BORDER", gold[1], gold[2], gold[3], gold[4])
|
||||
frame.BorderBottom:SetHeight(1)
|
||||
frame.BorderBottom:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 0, 0)
|
||||
frame.BorderBottom:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 0)
|
||||
|
||||
frame.BorderLeft = NewTexture(frame, "BORDER", gold[1], gold[2], gold[3], gold[4])
|
||||
frame.BorderLeft:SetWidth(1)
|
||||
frame.BorderLeft:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
|
||||
frame.BorderLeft:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 0, 0)
|
||||
|
||||
frame.BorderRight = NewTexture(frame, "BORDER", gold[1], gold[2], gold[3], gold[4])
|
||||
frame.BorderRight:SetWidth(1)
|
||||
frame.BorderRight:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 0)
|
||||
frame.BorderRight:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 0)
|
||||
|
||||
-- Kopfzeile mit Titel
|
||||
local header = CreateFrame("Frame", nil, frame)
|
||||
header:SetHeight(48)
|
||||
header:SetPoint("TOPLEFT", frame, "TOPLEFT", 1, -1)
|
||||
header:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -1, -1)
|
||||
frame.Header = header
|
||||
|
||||
header.Bg = NewTexture(header, "BACKGROUND", 0.047, 0.055, 0.078, 1)
|
||||
header.Bg:SetAllPoints(header)
|
||||
|
||||
header.Accent = NewTexture(header, "ARTWORK", 0.784, 0.608, 0.235, 0.55)
|
||||
header.Accent:SetHeight(1)
|
||||
header.Accent:SetPoint("BOTTOMLEFT", header, "BOTTOMLEFT", 0, 0)
|
||||
header.Accent:SetPoint("BOTTOMRIGHT", header, "BOTTOMRIGHT", 0, 0)
|
||||
|
||||
header.Logo = header:CreateTexture(nil, "ARTWORK")
|
||||
header.Logo:SetTexture("Interface\\AddOns\\Freewood-OctoWoW-Core\\Media\\FreeWood_Logo")
|
||||
header.Logo:SetWidth(40)
|
||||
header.Logo:SetHeight(40)
|
||||
header.Logo:SetPoint("LEFT", header, "LEFT", 14, 0)
|
||||
|
||||
header.Title = header:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
|
||||
header.Title:SetJustifyH("LEFT")
|
||||
header.Title:SetPoint("LEFT", header.Logo, "RIGHT", 10, 0)
|
||||
|
||||
header.Subtitle = header:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
header.Subtitle:SetJustifyH("LEFT")
|
||||
header.Subtitle:SetPoint("LEFT", header.Title, "RIGHT", 12, -2)
|
||||
|
||||
-- Leiste fuer die Tabs
|
||||
local tabBar = CreateFrame("Frame", nil, frame)
|
||||
tabBar:SetHeight(36)
|
||||
tabBar:SetPoint("TOPLEFT", header, "BOTTOMLEFT", 0, 0)
|
||||
tabBar:SetPoint("TOPRIGHT", header, "BOTTOMRIGHT", 0, 0)
|
||||
frame.TabBar = tabBar
|
||||
|
||||
tabBar.Bg = NewTexture(tabBar, "BACKGROUND", 0.078, 0.094, 0.141, 1)
|
||||
tabBar.Bg:SetAllPoints(tabBar)
|
||||
|
||||
tabBar.Line = NewTexture(tabBar, "ARTWORK", 0.616, 0.471, 0.149, 0.5)
|
||||
tabBar.Line:SetHeight(1)
|
||||
tabBar.Line:SetPoint("BOTTOMLEFT", tabBar, "BOTTOMLEFT", 0, 0)
|
||||
tabBar.Line:SetPoint("BOTTOMRIGHT", tabBar, "BOTTOMRIGHT", 0, 0)
|
||||
|
||||
-- Fusszeile
|
||||
local footer = CreateFrame("Frame", nil, frame)
|
||||
footer:SetHeight(26)
|
||||
footer:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 1, 1)
|
||||
footer:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -1, 1)
|
||||
frame.Footer = footer
|
||||
|
||||
footer.Bg = NewTexture(footer, "BACKGROUND", 0.047, 0.055, 0.078, 1)
|
||||
footer.Bg:SetAllPoints(footer)
|
||||
|
||||
footer.Left = footer:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
footer.Left:SetJustifyH("LEFT")
|
||||
footer.Left:SetPoint("LEFT", footer, "LEFT", 16, 0)
|
||||
|
||||
-- Inhaltsbereich (hier setzen die Tabs ihre Frames ein)
|
||||
local content = CreateFrame("Frame", nil, frame)
|
||||
content:SetPoint("TOPLEFT", tabBar, "BOTTOMLEFT", 20, -18)
|
||||
content:SetPoint("BOTTOMRIGHT", footer, "TOPRIGHT", -20, 12)
|
||||
frame.Content = content
|
||||
@@ -0,0 +1,353 @@
|
||||
-- Freewood-OctoWoW-Core: Verhalten des Hauptfensters
|
||||
-- Aufbau und Farben stehen in MainWindow.xml. Hier: Ziehen, Position merken,
|
||||
-- Tabs registrieren und umschalten, Oeffnen/Schliessen.
|
||||
|
||||
local ADDON, FW = ...
|
||||
|
||||
local UI = FW.UI
|
||||
local frame = _G.FreewoodMainFrame
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
|
||||
UI.window = frame
|
||||
table.insert(UISpecialFrames, "FreewoodMainFrame") -- Escape schliesst das Fenster
|
||||
|
||||
local tabs = {} -- Reihenfolge der Tabs
|
||||
local tabsById = {}
|
||||
local activeId
|
||||
local built = false
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Kopf, Ziehen, Position
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local header = frame.Header
|
||||
|
||||
UI.SetFont(header.Title, "heading", 20)
|
||||
header.Title:SetTextColor(UI.Color("goldLight"))
|
||||
header.Title:SetText("Freewood")
|
||||
|
||||
UI.SetFont(header.Subtitle, "body", 11)
|
||||
header.Subtitle:SetTextColor(UI.Color("textDim"))
|
||||
|
||||
UI.SetFont(frame.Footer.Left, "body", 11)
|
||||
frame.Footer.Left:SetTextColor(UI.Color("textDim"))
|
||||
|
||||
local closeButton = UI.CreateButton(header, "X", 30, 30, function()
|
||||
frame:Hide()
|
||||
end, "ghost")
|
||||
closeButton:SetPoint("RIGHT", header, "RIGHT", -10, 0)
|
||||
|
||||
-- Regler fuer die Fenstergroesse (50 bis 150 Prozent) in der Kopfzeile
|
||||
local scaleText = UI.CreateLabel(header, "100%", { size = 11, color = "textDim", justify = "RIGHT" })
|
||||
scaleText:SetWidth(40)
|
||||
scaleText:SetPoint("RIGHT", closeButton, "LEFT", -12, 0)
|
||||
local scaleSlider = UI.CreateSlider(header, 150, {
|
||||
min = 50, max = 150, step = 5,
|
||||
get = function() return math.floor(UI:GetScale() * 100 + 0.5) end,
|
||||
set = function(v) UI:SetScale(v / 100) end,
|
||||
})
|
||||
scaleSlider:SetPoint("RIGHT", scaleText, "LEFT", -8, 0)
|
||||
scaleSlider.onText = function(v) scaleText:SetText(string.format("%d%%", v)) end
|
||||
UI.AttachTooltip(scaleSlider, function() return FW.L.WINDOW_SCALE end, function() return FW.L.WINDOW_SCALE_TIP end)
|
||||
UI.scaleSlider = scaleSlider
|
||||
|
||||
local scaleListeners = {}
|
||||
-- Andere Bedienelemente (Einstellungen: - / +) melden sich an, um bei einer Aenderung nachzuziehen
|
||||
function UI:OnScaleChanged(fn)
|
||||
scaleListeners[#scaleListeners + 1] = fn
|
||||
end
|
||||
|
||||
header:EnableMouse(true)
|
||||
header:RegisterForDrag("LeftButton")
|
||||
header:SetScript("OnDragStart", function()
|
||||
frame:StartMoving()
|
||||
end)
|
||||
header:SetScript("OnDragStop", function()
|
||||
frame:StopMovingOrSizing()
|
||||
local point, _, relativePoint, x, y = frame:GetPoint(1)
|
||||
if point and FW.settings then
|
||||
FW.settings.windowPos = { point = point, relativePoint = relativePoint, x = x, y = y }
|
||||
end
|
||||
end)
|
||||
|
||||
function UI:ApplyPosition()
|
||||
local pos = FW.settings and FW.settings.windowPos
|
||||
frame:ClearAllPoints()
|
||||
if type(pos) == "table" and pos.point then
|
||||
frame:SetPoint(pos.point, UIParent, pos.relativePoint or pos.point, pos.x or 0, pos.y or 0)
|
||||
else
|
||||
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Groesse: Standard, Grenzen, Ziehgriff unten rechts
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local DEFAULT_W, DEFAULT_H = 1240, 840
|
||||
local MIN_W, MIN_H = 1240, 840 -- so gross, dass die Einstellungen komplett passen
|
||||
local MAX_W, MAX_H = 1500, 1100
|
||||
|
||||
-- Grenzen passend zum Bildschirm (Fenster soll nicht groesser als der Bildschirm werden)
|
||||
local function SizeLimits()
|
||||
local scale = frame:GetScale() or 1
|
||||
local sw = ((UIParent and UIParent:GetWidth()) or 1920) / scale
|
||||
local sh = ((UIParent and UIParent:GetHeight()) or 1080) / scale
|
||||
local maxW = math.max(MIN_W, math.min(MAX_W, sw - 20))
|
||||
local maxH = math.max(MIN_H, math.min(MAX_H, sh - 20))
|
||||
return maxW, maxH
|
||||
end
|
||||
|
||||
local function ClampSize(w, h)
|
||||
local maxW, maxH = SizeLimits()
|
||||
w = math.min(math.max(tonumber(w) or DEFAULT_W, MIN_W), maxW)
|
||||
h = math.min(math.max(tonumber(h) or DEFAULT_H, MIN_H), maxH)
|
||||
return w, h
|
||||
end
|
||||
|
||||
function UI:ApplySize()
|
||||
local saved = FW.settings and FW.settings.windowSize
|
||||
local w, h = DEFAULT_W, DEFAULT_H
|
||||
if type(saved) == "table" then
|
||||
w, h = saved.w or w, saved.h or h
|
||||
end
|
||||
frame:SetSize(ClampSize(w, h))
|
||||
end
|
||||
|
||||
local function SetupResize()
|
||||
if frame.SetResizable then
|
||||
frame:SetResizable(true)
|
||||
end
|
||||
local maxW, maxH = SizeLimits()
|
||||
if frame.SetResizeBounds then
|
||||
frame:SetResizeBounds(MIN_W, MIN_H, maxW, maxH)
|
||||
else
|
||||
if frame.SetMinResize then frame:SetMinResize(MIN_W, MIN_H) end
|
||||
if frame.SetMaxResize then frame:SetMaxResize(maxW, maxH) end
|
||||
end
|
||||
|
||||
local grip = CreateFrame("Button", nil, frame)
|
||||
grip:SetSize(18, 18)
|
||||
grip:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -3, 3)
|
||||
grip:SetFrameLevel((frame:GetFrameLevel() or 1) + 30)
|
||||
grip:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
|
||||
grip:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
|
||||
grip:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
|
||||
grip:SetScript("OnMouseDown", function()
|
||||
local mw, mh = SizeLimits()
|
||||
if frame.SetResizeBounds then
|
||||
frame:SetResizeBounds(MIN_W, MIN_H, mw, mh)
|
||||
end
|
||||
frame:StartSizing("BOTTOMRIGHT")
|
||||
end)
|
||||
grip:SetScript("OnMouseUp", function()
|
||||
frame:StopMovingOrSizing()
|
||||
local w, h = ClampSize(frame:GetWidth(), frame:GetHeight())
|
||||
frame:SetSize(w, h)
|
||||
if FW.settings then
|
||||
FW.settings.windowSize = { w = math.floor(w + 0.5), h = math.floor(h + 0.5) }
|
||||
end
|
||||
local point, _, relativePoint, x, y = frame:GetPoint(1)
|
||||
if point and FW.settings then
|
||||
FW.settings.windowPos = { point = point, relativePoint = relativePoint, x = x, y = y }
|
||||
end
|
||||
end)
|
||||
UI.AttachTooltip(grip, function() return FW.L.WINDOW_RESIZE end, function() return FW.L.WINDOW_RESIZE_TIP end)
|
||||
frame.resizeGrip = grip
|
||||
end
|
||||
|
||||
function UI:ResetPosition()
|
||||
if FW.settings then
|
||||
FW.settings.windowPos = false
|
||||
FW.settings.windowSize = false
|
||||
end
|
||||
self:ApplySize()
|
||||
self:ApplyPosition()
|
||||
end
|
||||
|
||||
function UI:SetScale(scale)
|
||||
scale = FW.Util.Clamp(math.floor(scale * 20 + 0.5) / 20, 0.5, 1.5)
|
||||
if FW.settings then
|
||||
FW.settings.scale = scale
|
||||
end
|
||||
frame:SetScale(scale)
|
||||
self:ApplySize()
|
||||
scaleSlider:Refresh()
|
||||
for _, fn in ipairs(scaleListeners) do
|
||||
pcall(fn, scale)
|
||||
end
|
||||
end
|
||||
|
||||
function UI:GetScale()
|
||||
return (FW.settings and FW.settings.scale) or 1
|
||||
end
|
||||
|
||||
FW:On("FW_DB_READY", function()
|
||||
frame:SetScale(UI:GetScale())
|
||||
scaleSlider:Refresh()
|
||||
SetupResize()
|
||||
UI:ApplySize()
|
||||
UI:ApplyPosition()
|
||||
header.Subtitle:SetText("v" .. FW.version)
|
||||
end)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Tabs
|
||||
-- def.label Text oder Funktion, die den Text liefert
|
||||
-- def.order Reihenfolge (kleiner = weiter links)
|
||||
-- def.build function(content) -> Frame (wird beim ersten Anzeigen aufgerufen)
|
||||
-- def.onShow function(tabFrame) (bei jedem Anzeigen)
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local function ResolveLabel(def)
|
||||
local label = def.label
|
||||
if type(label) == "function" then
|
||||
label = label()
|
||||
end
|
||||
return label or "?"
|
||||
end
|
||||
|
||||
local TAB_ROW_H = 34
|
||||
|
||||
-- Tabs in Zeilen umbrechen, wenn sie nicht in eine Zeile passen; die Leiste waechst mit,
|
||||
-- der Inhaltsbereich haengt an ihrem unteren Rand und rutscht mit.
|
||||
local function LayoutTabs()
|
||||
table.sort(tabs, function(a, b)
|
||||
if a.order ~= b.order then
|
||||
return a.order < b.order
|
||||
end
|
||||
return a.seq < b.seq
|
||||
end)
|
||||
local barW = frame.TabBar:GetWidth()
|
||||
if not barW or barW < 100 then
|
||||
barW = (frame:GetWidth() or 1000) - 2
|
||||
end
|
||||
local limit = barW - 12
|
||||
local x, row = 12, 0
|
||||
local rowOf = {}
|
||||
for _, tab in ipairs(tabs) do
|
||||
if tab.button then
|
||||
local w = tab.button:GetWidth()
|
||||
if x + w > limit and x > 12 then
|
||||
row = row + 1
|
||||
x = 12
|
||||
end
|
||||
rowOf[tab] = { row = row, x = x }
|
||||
x = x + w + 4
|
||||
end
|
||||
end
|
||||
local rows = row + 1
|
||||
frame.TabBar:SetHeight(rows * TAB_ROW_H + 2)
|
||||
for _, tab in ipairs(tabs) do
|
||||
local at = rowOf[tab]
|
||||
if at then
|
||||
tab.button:ClearAllPoints()
|
||||
tab.button:SetPoint("BOTTOMLEFT", frame.TabBar, "BOTTOMLEFT", at.x, 1 + (rows - 1 - at.row) * TAB_ROW_H)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function CreateTabButton(tab)
|
||||
local button = UI.CreateTabButton(frame.TabBar, ResolveLabel(tab.def))
|
||||
button:SetScript("OnClick", function()
|
||||
UI:SelectTab(tab.id)
|
||||
end)
|
||||
tab.button = button
|
||||
end
|
||||
|
||||
function UI:RegisterTab(id, def)
|
||||
if tabsById[id] then
|
||||
return tabsById[id]
|
||||
end
|
||||
local tab = { id = id, def = def, order = def.order or 100, seq = #tabs + 1 }
|
||||
tabsById[id] = tab
|
||||
tabs[#tabs + 1] = tab
|
||||
if built then
|
||||
CreateTabButton(tab)
|
||||
LayoutTabs()
|
||||
end
|
||||
return tab
|
||||
end
|
||||
|
||||
function UI:SelectTab(id)
|
||||
local tab = tabsById[id]
|
||||
if not tab then
|
||||
return
|
||||
end
|
||||
|
||||
for _, other in ipairs(tabs) do
|
||||
if other.frame then
|
||||
other.frame:Hide()
|
||||
end
|
||||
if other.button then
|
||||
other.button:SetActive(other == tab)
|
||||
end
|
||||
end
|
||||
|
||||
if not tab.frame and tab.def.build then
|
||||
tab.frame = tab.def.build(frame.Content)
|
||||
if tab.frame then
|
||||
tab.frame:SetAllPoints(frame.Content)
|
||||
end
|
||||
end
|
||||
if tab.frame then
|
||||
tab.frame:Show()
|
||||
if tab.def.onShow then
|
||||
FW.SafeCall(tab.def.onShow, tab.frame)
|
||||
end
|
||||
end
|
||||
activeId = id
|
||||
end
|
||||
|
||||
local function BuildOnce()
|
||||
if built then
|
||||
return
|
||||
end
|
||||
built = true
|
||||
for _, tab in ipairs(tabs) do
|
||||
CreateTabButton(tab)
|
||||
end
|
||||
LayoutTabs()
|
||||
frame:HookScript("OnSizeChanged", function()
|
||||
LayoutTabs()
|
||||
end)
|
||||
end
|
||||
|
||||
frame:SetScript("OnShow", function()
|
||||
BuildOnce()
|
||||
local _, _, _, toc = GetBuildInfo()
|
||||
local left = FW.L.TITLE .. " | " .. string.format(FW.L.SLASH_VERSION, FW.version, FW.API_VERSION, tostring(toc or "?"))
|
||||
frame.Footer.Left:SetText(left)
|
||||
UI:SelectTab(activeId or (tabs[1] and tabs[1].id))
|
||||
end)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Oeffnen und Schliessen
|
||||
------------------------------------------------------------------------
|
||||
|
||||
function UI:Show(tabId)
|
||||
if tabId then
|
||||
activeId = tabId
|
||||
end
|
||||
if frame:IsShown() then
|
||||
if tabId then
|
||||
self:SelectTab(tabId)
|
||||
end
|
||||
else
|
||||
frame:Show() -- OnShow waehlt den Tab
|
||||
end
|
||||
end
|
||||
|
||||
function UI:Hide()
|
||||
frame:Hide()
|
||||
end
|
||||
|
||||
function UI:Toggle(tabId)
|
||||
if frame:IsShown() then
|
||||
frame:Hide()
|
||||
else
|
||||
self:Show(tabId)
|
||||
end
|
||||
end
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
-- Freewood-OctoWoW-Core: Minimap-Knopf
|
||||
-- Links: Fenster, Rechts: Einstellungen, Ziehen: um die Minimap verschieben.
|
||||
-- Annahme: runde Minimap.
|
||||
|
||||
local ADDON, FW = ...
|
||||
|
||||
local UI = FW.UI
|
||||
local Minimap_ = _G.Minimap
|
||||
|
||||
local M = {}
|
||||
FW.Minimap = M
|
||||
|
||||
local button = CreateFrame("Button", "FreewoodMinimapButton", Minimap_)
|
||||
button:SetSize(32, 32)
|
||||
button:SetFrameStrata("MEDIUM")
|
||||
button:SetFrameLevel(8)
|
||||
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||||
button:RegisterForDrag("LeftButton")
|
||||
|
||||
local overlay = button:CreateTexture(nil, "OVERLAY")
|
||||
overlay:SetSize(53, 53)
|
||||
overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
|
||||
overlay:SetPoint("TOPLEFT", button, "TOPLEFT", 0, 0)
|
||||
|
||||
local background = button:CreateTexture(nil, "BACKGROUND")
|
||||
background:SetSize(20, 20)
|
||||
background:SetTexture("Interface\\Minimap\\UI-Minimap-Background")
|
||||
background:SetPoint("TOPLEFT", button, "TOPLEFT", 7, -5)
|
||||
|
||||
local icon = button:CreateTexture(nil, "ARTWORK")
|
||||
icon:SetSize(17, 17)
|
||||
icon:SetTexture("Interface\\AddOns\\Freewood-OctoWoW-Core\\Media\\FreeWood_Logo.tga")
|
||||
icon:SetPoint("TOPLEFT", button, "TOPLEFT", 7, -6)
|
||||
|
||||
button:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
|
||||
|
||||
local atan2 = math.atan2 or math.atan
|
||||
|
||||
local function UpdatePosition()
|
||||
local angle = math.rad((FW.settings and FW.settings.minimap.angle) or 215)
|
||||
local radius = (Minimap_:GetWidth() / 2) + 5
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint("CENTER", Minimap_, "CENTER", math.cos(angle) * radius, math.sin(angle) * radius)
|
||||
end
|
||||
|
||||
button:SetScript("OnDragStart", function(self)
|
||||
self:SetScript("OnUpdate", function()
|
||||
local mx, my = Minimap_:GetCenter()
|
||||
local px, py = GetCursorPosition()
|
||||
local scale = Minimap_:GetEffectiveScale()
|
||||
px, py = px / scale, py / scale
|
||||
FW.settings.minimap.angle = math.deg(atan2(py - my, px - mx)) % 360
|
||||
UpdatePosition()
|
||||
end)
|
||||
end)
|
||||
|
||||
button:SetScript("OnDragStop", function(self)
|
||||
self:SetScript("OnUpdate", nil)
|
||||
end)
|
||||
|
||||
button:SetScript("OnClick", function(_, mouseButton)
|
||||
if mouseButton == "RightButton" then
|
||||
UI:Show("settings")
|
||||
else
|
||||
UI:Toggle()
|
||||
end
|
||||
end)
|
||||
|
||||
button:SetScript("OnEnter", function(self)
|
||||
local L = FW.L
|
||||
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
|
||||
GameTooltip:SetText("Freewood", 0.94, 0.75, 0.36)
|
||||
GameTooltip:AddLine(L.MINIMAP_TIP_LEFT, 0.8, 0.8, 0.8)
|
||||
GameTooltip:AddLine(L.MINIMAP_TIP_RIGHT, 0.8, 0.8, 0.8)
|
||||
GameTooltip:AddLine(L.MINIMAP_TIP_DRAG, 0.6, 0.6, 0.6)
|
||||
GameTooltip:Show()
|
||||
end)
|
||||
button:SetScript("OnLeave", function()
|
||||
GameTooltip:Hide()
|
||||
end)
|
||||
|
||||
function M:SetHidden(hidden)
|
||||
FW.settings.minimap.hide = hidden and true or false
|
||||
if hidden then
|
||||
button:Hide()
|
||||
else
|
||||
button:Show()
|
||||
end
|
||||
end
|
||||
|
||||
M.button = button
|
||||
|
||||
FW:On("FW_DB_READY", function()
|
||||
UpdatePosition()
|
||||
if FW.settings.minimap.hide then
|
||||
button:Hide()
|
||||
else
|
||||
button:Show()
|
||||
end
|
||||
end)
|
||||
+541
@@ -0,0 +1,541 @@
|
||||
-- Freewood-OctoWoW-Core: die drei eigenen Tabs (Uebersicht, Austausch, Einstellungen)
|
||||
-- Module registrieren ihre Tabs ueber Freewood.UI:RegisterTab(...), siehe MainWindow.lua.
|
||||
|
||||
local ADDON, FW = ...
|
||||
|
||||
local UI = FW.UI
|
||||
local Export = FW.Export
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Uebersicht: geladene Module
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local function BuildOverview(content)
|
||||
local L = FW.L
|
||||
local f = CreateFrame("Frame", nil, content)
|
||||
|
||||
local title = UI.CreateLabel(f, L.OVERVIEW_HEADER, { font = "heading", size = 16, color = "goldLight" })
|
||||
title:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
|
||||
|
||||
local _, build, _, toc = GetBuildInfo()
|
||||
local gameVersion = (GetBuildInfo())
|
||||
local info = UI.CreateLabel(f,
|
||||
string.format(L.OVERVIEW_INFO, FW.version, tostring(gameVersion), tostring(build)),
|
||||
{ size = 11, color = "textDim", justify = "RIGHT" })
|
||||
info:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -2)
|
||||
|
||||
local divider = UI.CreateDivider(f)
|
||||
divider:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -30)
|
||||
divider:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -30)
|
||||
|
||||
local scroll = UI.CreateScrollFrame(f)
|
||||
scroll:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -44)
|
||||
scroll:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
|
||||
|
||||
local empty = UI.CreateLabel(scroll.child, L.OVERVIEW_NONE, { size = 12, color = "textDim", justifyV = "TOP" })
|
||||
empty:SetPoint("TOPLEFT", scroll.child, "TOPLEFT", 0, 0)
|
||||
empty:SetPoint("TOPRIGHT", scroll.child, "TOPRIGHT", 0, 0)
|
||||
|
||||
local ROW_H, GAP = 58, 8
|
||||
local rows = {}
|
||||
|
||||
local function GetRow(i)
|
||||
local row = rows[i]
|
||||
if row then
|
||||
return row
|
||||
end
|
||||
row = UI.CreatePanel(scroll.child, "card", "bronze")
|
||||
row:SetHeight(ROW_H)
|
||||
|
||||
row.name = UI.CreateLabel(row, "", { font = "heading", size = 14, color = "goldLight" })
|
||||
row.name:SetPoint("TOPLEFT", row, "TOPLEFT", 14, -10)
|
||||
|
||||
row.version = UI.CreateLabel(row, "", { size = 11, color = "textDim" })
|
||||
row.version:SetPoint("LEFT", row.name, "RIGHT", 10, 0)
|
||||
|
||||
row.desc = UI.CreateLabel(row, "", { size = 12, color = "text" })
|
||||
row.desc:SetPoint("TOPLEFT", row.name, "BOTTOMLEFT", 0, -6)
|
||||
|
||||
row.status = UI.CreateLabel(row, "", { size = 12, justify = "RIGHT" })
|
||||
row.status:SetPoint("RIGHT", row, "RIGHT", -14, 0)
|
||||
|
||||
rows[i] = row
|
||||
return row
|
||||
end
|
||||
|
||||
function f.Refresh()
|
||||
local list = FW.moduleList
|
||||
if #list == 0 then
|
||||
empty:Show()
|
||||
else
|
||||
empty:Hide()
|
||||
end
|
||||
|
||||
for i, mod in ipairs(list) do
|
||||
local row = GetRow(i)
|
||||
local y = (i - 1) * (ROW_H + GAP)
|
||||
row:ClearAllPoints()
|
||||
row:SetPoint("TOPLEFT", scroll.child, "TOPLEFT", 0, -y)
|
||||
row:SetPoint("TOPRIGHT", scroll.child, "TOPRIGHT", 0, -y)
|
||||
row.name:SetText(mod.title or mod.name)
|
||||
row.version:SetText(mod.version and ("v" .. mod.version) or "")
|
||||
row.desc:SetText(mod.description or "")
|
||||
if mod:IsEnabled() then
|
||||
row.status:SetText("|cff" .. UI.Hex("success") .. L.MODULE_ACTIVE .. "|r")
|
||||
else
|
||||
row.status:SetText("|cff" .. UI.Hex("textDim") .. L.MODULE_INACTIVE .. "|r")
|
||||
end
|
||||
row:Show()
|
||||
end
|
||||
for i = #list + 1, #rows do
|
||||
rows[i]:Hide()
|
||||
end
|
||||
|
||||
scroll:SetContentHeight(math.max(#list * (ROW_H + GAP), 40))
|
||||
end
|
||||
|
||||
f.Refresh()
|
||||
return f
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Austausch: Export und Import
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local function BuildExchange(content)
|
||||
local L = FW.L
|
||||
local f = CreateFrame("Frame", nil, content)
|
||||
f.selected = nil
|
||||
|
||||
local intro = UI.CreateLabel(f, L.EXCHANGE_INTRO, { size = 12, color = "textDim", justifyV = "TOP" })
|
||||
intro:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
|
||||
intro:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
|
||||
|
||||
local kinds = CreateFrame("Frame", nil, f)
|
||||
kinds:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -46)
|
||||
kinds:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -46)
|
||||
kinds:SetHeight(28)
|
||||
|
||||
local none = UI.CreateLabel(kinds, L.EXCHANGE_NO_HANDLERS, { size = 12, color = "textDim" })
|
||||
none:SetPoint("LEFT", kinds, "LEFT", 0, 0)
|
||||
|
||||
local area = UI.CreateTextArea(f)
|
||||
area:SetPoint("TOPLEFT", kinds, "BOTTOMLEFT", 0, -12)
|
||||
area:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 46)
|
||||
|
||||
local status = UI.CreateLabel(f, "", { size = 12 })
|
||||
status:SetWidth(520)
|
||||
|
||||
local function SetStatus(message, colorKey)
|
||||
status:SetText("|cff" .. UI.Hex(colorKey or "text") .. message .. "|r")
|
||||
end
|
||||
|
||||
local function ErrorText(key, extra)
|
||||
local text = L[key]
|
||||
if key == "ERR_NO_HANDLER" then
|
||||
text = string.format(text, tostring(extra))
|
||||
elseif key == "ERR_INVALID" and type(extra) == "string" then
|
||||
text = text .. " (" .. extra .. ")"
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
local kindButtons = {}
|
||||
|
||||
local function RefreshKindButtons()
|
||||
for _, b in ipairs(kindButtons) do
|
||||
b:SetStyle(b.kind == f.selected and "primary" or "default")
|
||||
end
|
||||
end
|
||||
|
||||
local function RebuildKinds()
|
||||
for _, b in ipairs(kindButtons) do
|
||||
b:Hide()
|
||||
end
|
||||
local list = Export.handlerList
|
||||
if #list == 0 then
|
||||
none:Show()
|
||||
f.selected = nil
|
||||
return
|
||||
end
|
||||
none:Hide()
|
||||
|
||||
local found = false
|
||||
for _, h in ipairs(list) do
|
||||
if h.kind == f.selected then
|
||||
found = true
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
f.selected = list[1].kind
|
||||
end
|
||||
|
||||
local x = 0
|
||||
for i, handler in ipairs(list) do
|
||||
local b = kindButtons[i]
|
||||
if not b then
|
||||
b = UI.CreateButton(kinds, "", 150, 28, function(self)
|
||||
f.selected = self.kind
|
||||
RefreshKindButtons()
|
||||
end)
|
||||
kindButtons[i] = b
|
||||
end
|
||||
b.kind = handler.kind
|
||||
local label = Export.GetLabel(handler)
|
||||
b:SetLabel(label)
|
||||
b:SetWidth(math.max(110, b.label:GetStringWidth() + 32))
|
||||
b:ClearAllPoints()
|
||||
b:SetPoint("LEFT", kinds, "LEFT", x, 0)
|
||||
b:Show()
|
||||
x = x + b:GetWidth() + 8
|
||||
end
|
||||
RefreshKindButtons()
|
||||
end
|
||||
|
||||
local exportButton = UI.CreateButton(f, L.EXCHANGE_EXPORT, 130, 30, function()
|
||||
if not f.selected then
|
||||
return -- der Hinweis "kein Modul" steht schon ueber dem Textfeld
|
||||
end
|
||||
local code, err, extra = Export.ExportKind(f.selected)
|
||||
if code then
|
||||
area:SetText(code)
|
||||
area:SelectAll()
|
||||
SetStatus(string.format(L.EXCHANGE_EXPORTED, #code), "success")
|
||||
else
|
||||
SetStatus(ErrorText(err, extra), "danger")
|
||||
end
|
||||
end, "primary")
|
||||
exportButton:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 0)
|
||||
|
||||
local importButton = UI.CreateButton(f, L.EXCHANGE_IMPORT, 130, 30, function()
|
||||
local text = area:GetText() or ""
|
||||
if not text:find("%S") then
|
||||
SetStatus(L.EXCHANGE_EMPTY, "danger")
|
||||
return
|
||||
end
|
||||
local ok, result, extra = Export.Import(text)
|
||||
if ok then
|
||||
local message = type(result) == "string" and result ~= "" and result or L.EXCHANGE_IMPORTED
|
||||
SetStatus(message, "success")
|
||||
else
|
||||
SetStatus(ErrorText(result, extra), "danger")
|
||||
end
|
||||
end)
|
||||
importButton:SetPoint("LEFT", exportButton, "RIGHT", 8, 0)
|
||||
|
||||
local clearButton = UI.CreateButton(f, L.EXCHANGE_CLEAR, 100, 30, function()
|
||||
area:SetText("")
|
||||
status:SetText("")
|
||||
end, "ghost")
|
||||
clearButton:SetPoint("LEFT", importButton, "RIGHT", 8, 0)
|
||||
|
||||
status:SetPoint("LEFT", clearButton, "RIGHT", 16, 0)
|
||||
|
||||
function f.Refresh()
|
||||
RebuildKinds()
|
||||
end
|
||||
|
||||
f.Refresh()
|
||||
return f
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Einstellungen
|
||||
------------------------------------------------------------------------
|
||||
|
||||
-- Module koennen eigene Abschnitte in den Einstellungen anmelden:
|
||||
-- UI:RegisterSettingsSection(id, { order = 100, height = 260, build = function(parent) return frame end, refresh = function(frame) end })
|
||||
-- Die Abschnitte stehen in zwei Spalten rechts neben den allgemeinen Einstellungen. Die Hoehe eines Abschnitts
|
||||
-- ist der Wert frame.flowH, wenn er ihn meldet (UI.CreateSection tut das), sonst def.height. Die ganze Seite
|
||||
-- scrollt, wenn sie hoeher ist als das Fenster; die Breiten richten sich nach der Fensterbreite.
|
||||
local settingsSections = {}
|
||||
local settingsFrame, settingsBody, settingsScroll, settingsLeft
|
||||
local vline1, vline2
|
||||
|
||||
-- Abschnitt mit Ueberschrift, Trennlinie und einem Stapel darunter: local f, stack = UI.CreateSection(parent, "Titel")
|
||||
function UI.CreateSection(parent, titleText)
|
||||
local f = CreateFrame("Frame", nil, parent)
|
||||
local title = UI.CreateLabel(f, titleText, { font = "heading", size = 14, color = "goldLight" })
|
||||
title:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
|
||||
local divider = UI.CreateDivider(f)
|
||||
divider:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -26)
|
||||
divider:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -26)
|
||||
local stack = UI.CreateStack(f, { y = 30, gap = 6, pad = 0 })
|
||||
stack.onHeight = function(h)
|
||||
f.flowH = h + 14
|
||||
f:SetHeight(f.flowH)
|
||||
if f.onFlow then f.onFlow() end
|
||||
end
|
||||
f.stack = stack
|
||||
f.title = title
|
||||
return f, stack
|
||||
end
|
||||
|
||||
local SECTION_GAP = 36 -- Abstand zwischen den beiden Spalten
|
||||
local LEFT_GAP = 40 -- Abstand zwischen allgemeinen Einstellungen und Abschnitten
|
||||
|
||||
local function LeftWidth(W)
|
||||
return FW.Util.Clamp(math.floor(W * 0.28), 300, 420)
|
||||
end
|
||||
|
||||
local layingOut, pendingLayout, layoutDepth = false, false, 0
|
||||
local function LayoutSections()
|
||||
if not settingsBody then
|
||||
return
|
||||
end
|
||||
if layingOut then
|
||||
pendingLayout = true -- eine Hoehe hat sich waehrend des Anordnens geaendert: danach noch einmal
|
||||
return
|
||||
end
|
||||
layingOut = true
|
||||
local W = settingsBody:GetWidth() or 0
|
||||
if W < 200 then
|
||||
W = 1000
|
||||
end
|
||||
local leftW = LeftWidth(W)
|
||||
local x1 = leftW + LEFT_GAP
|
||||
local colW = math.max(200, math.floor((W - x1 - SECTION_GAP) / 2))
|
||||
local x2 = x1 + colW + SECTION_GAP
|
||||
settingsLeft:SetWidth(leftW)
|
||||
local ypos = { 0, 0 }
|
||||
for i, def in ipairs(settingsSections) do
|
||||
def.col = (ypos[1] >= ypos[2]) and 1 or 2 -- jeweils in die kuerzere Spalte
|
||||
local h = (def.frame and def.frame.flowH) or def.height or 260
|
||||
def.y = ypos[def.col]
|
||||
ypos[def.col] = ypos[def.col] - h - 10
|
||||
local frame = def.frame
|
||||
if frame then
|
||||
frame:ClearAllPoints()
|
||||
frame:SetPoint("TOPLEFT", settingsBody, "TOPLEFT", def.col == 2 and x2 or x1, def.y)
|
||||
frame:SetWidth(colW)
|
||||
frame:SetHeight(h)
|
||||
end
|
||||
end
|
||||
local contentH = math.max(-ypos[1], -ypos[2], settingsLeft.flowH or 0) + 20
|
||||
settingsBody.contentH = contentH
|
||||
settingsBody:SetHeight(contentH)
|
||||
settingsScroll:SetContentHeight(contentH)
|
||||
vline1:ClearAllPoints()
|
||||
vline1:SetPoint("TOPLEFT", settingsBody, "TOPLEFT", x1 - 20, 0)
|
||||
vline1:SetPoint("BOTTOMLEFT", settingsBody, "TOPLEFT", x1 - 20, -contentH)
|
||||
vline2:ClearAllPoints()
|
||||
vline2:SetPoint("TOPLEFT", settingsBody, "TOPLEFT", x2 - SECTION_GAP / 2, 0)
|
||||
vline2:SetPoint("BOTTOMLEFT", settingsBody, "TOPLEFT", x2 - SECTION_GAP / 2, -contentH)
|
||||
layingOut = false
|
||||
if pendingLayout and layoutDepth < 4 then
|
||||
pendingLayout = false
|
||||
layoutDepth = layoutDepth + 1
|
||||
LayoutSections()
|
||||
layoutDepth = layoutDepth - 1
|
||||
end
|
||||
pendingLayout = false
|
||||
end
|
||||
|
||||
local function BuildSection(def)
|
||||
if def.frame or not settingsBody then
|
||||
return
|
||||
end
|
||||
local ok, frame = pcall(def.build, settingsBody)
|
||||
if ok and frame then
|
||||
def.frame = frame
|
||||
frame.onFlow = LayoutSections
|
||||
if def.refresh then
|
||||
pcall(def.refresh, frame)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UI:RegisterSettingsSection(id, def)
|
||||
def.id = id
|
||||
def.order = def.order or 100
|
||||
settingsSections[#settingsSections + 1] = def
|
||||
table.sort(settingsSections, function(a, b)
|
||||
return a.order < b.order
|
||||
end)
|
||||
BuildSection(def)
|
||||
LayoutSections()
|
||||
end
|
||||
|
||||
local function BuildSettings(content)
|
||||
local L = FW.L
|
||||
local f = CreateFrame("Frame", nil, content)
|
||||
|
||||
local title = UI.CreateLabel(f, L.SETTINGS_HEADER, { font = "heading", size = 16, color = "goldLight" })
|
||||
title:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
|
||||
|
||||
local divider = UI.CreateDivider(f)
|
||||
divider:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -30)
|
||||
divider:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -30)
|
||||
|
||||
-- Alles darunter scrollt, wenn das Fenster zu niedrig ist
|
||||
local scroll = UI.CreateScrollFrame(f)
|
||||
scroll:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -42)
|
||||
scroll:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
|
||||
local body = scroll.child
|
||||
settingsScroll, settingsBody, settingsFrame = scroll, body, f
|
||||
|
||||
-- allgemeine Einstellungen links (Stapel)
|
||||
local lf = CreateFrame("Frame", nil, body)
|
||||
lf:SetPoint("TOPLEFT", body, "TOPLEFT", 0, 0)
|
||||
lf:SetWidth(400)
|
||||
settingsLeft = lf
|
||||
local stack = UI.CreateStack(lf, { y = 0, gap = 8 })
|
||||
stack.onHeight = function(h)
|
||||
lf.flowH = h
|
||||
lf:SetHeight(h)
|
||||
end
|
||||
|
||||
local minimapBox = UI.CreateCheckbox(lf, L.SETTINGS_MINIMAP,
|
||||
function()
|
||||
return not FW.settings.minimap.hide
|
||||
end,
|
||||
function(value)
|
||||
FW.Minimap:SetHidden(not value)
|
||||
end)
|
||||
stack:Add(minimapBox, { fit = true })
|
||||
|
||||
local debugBox = UI.CreateCheckbox(lf, L.SETTINGS_DEBUG,
|
||||
function()
|
||||
return FW.settings.debug and true or false
|
||||
end,
|
||||
function(value)
|
||||
FW.settings.debug = value and true or false
|
||||
end)
|
||||
stack:Add(debugBox, { fit = true })
|
||||
|
||||
-- Fenstergroesse: Zeile mit - / Prozent / +
|
||||
local scaleLabel = UI.CreateLabel(lf, L.SETTINGS_SCALE, { size = 12 })
|
||||
stack:Add(scaleLabel, { height = 16, gap = 18 })
|
||||
local scaleRow = CreateFrame("Frame", nil, lf)
|
||||
scaleRow:SetHeight(26)
|
||||
stack:Add(scaleRow, { height = 26, gap = 4, stretch = true })
|
||||
local scaleValue = UI.CreateLabel(scaleRow, "", { size = 12, color = "goldLight", justify = "CENTER" })
|
||||
scaleValue:SetWidth(60)
|
||||
|
||||
local function RefreshScale()
|
||||
scaleValue:SetText(string.format("%d%%", math.floor(UI:GetScale() * 100 + 0.5)))
|
||||
end
|
||||
UI:OnScaleChanged(function() RefreshScale() end)
|
||||
|
||||
local minus = UI.CreateButton(scaleRow, "-", 28, 26, function()
|
||||
UI:SetScale(UI:GetScale() - 0.05)
|
||||
end)
|
||||
minus:SetPoint("LEFT", scaleRow, "LEFT", 0, 0)
|
||||
scaleValue:SetPoint("LEFT", minus, "RIGHT", 4, 0)
|
||||
local plus = UI.CreateButton(scaleRow, "+", 28, 26, function()
|
||||
UI:SetScale(UI:GetScale() + 0.05)
|
||||
end)
|
||||
plus:SetPoint("LEFT", scaleValue, "RIGHT", 4, 0)
|
||||
|
||||
-- Sprache: Beschriftung oben, drei Knoepfe gleich breit darunter
|
||||
local langLabel = UI.CreateLabel(lf, L.SETTINGS_LANGUAGE, { size = 12 })
|
||||
stack:Add(langLabel, { height = 16, gap = 18 })
|
||||
local langRow = CreateFrame("Frame", nil, lf)
|
||||
langRow:SetHeight(26)
|
||||
stack:Add(langRow, { height = 26, gap = 4, stretch = true })
|
||||
|
||||
local langButtons = {}
|
||||
local function RefreshLang()
|
||||
for _, b in ipairs(langButtons) do
|
||||
b:SetStyle(FW.settings.locale == b.code and "primary" or "default")
|
||||
end
|
||||
end
|
||||
|
||||
local options = {
|
||||
{ code = "auto", text = L.LANG_AUTO },
|
||||
{ code = "deDE", text = L.LANG_DE },
|
||||
{ code = "enUS", text = L.LANG_EN },
|
||||
}
|
||||
for i, option in ipairs(options) do
|
||||
local b = UI.CreateButton(langRow, option.text, 110, 26, function(self)
|
||||
FW.settings.locale = self.code
|
||||
RefreshLang()
|
||||
end)
|
||||
b.code = option.code
|
||||
langButtons[#langButtons + 1] = b
|
||||
end
|
||||
local function LayoutLang(w)
|
||||
w = w or langRow:GetWidth() or 0
|
||||
if w < 60 then return end
|
||||
local bw = math.floor((w - 12) / 3)
|
||||
for i, b in ipairs(langButtons) do
|
||||
b:ClearAllPoints()
|
||||
b:SetWidth(bw)
|
||||
b:SetPoint("LEFT", langRow, "LEFT", (i - 1) * (bw + 6), 0)
|
||||
end
|
||||
end
|
||||
langRow:SetScript("OnSizeChanged", function(self) LayoutLang(self:GetWidth()) end)
|
||||
LayoutLang(stack:Width())
|
||||
|
||||
local note = UI.CreateLabel(lf, L.SETTINGS_LANGUAGE_NOTE, { size = 11, color = "textDim", justifyV = "TOP" })
|
||||
stack:Add(note, { fit = true, gap = 8 })
|
||||
|
||||
local reset = UI.CreateButton(lf, L.SETTINGS_RESET_POS, 220, 28, function()
|
||||
UI:ResetPosition()
|
||||
end)
|
||||
stack:Add(reset, { height = 28, gap = 16, stretch = true })
|
||||
|
||||
function f.Refresh()
|
||||
minimapBox:Refresh()
|
||||
debugBox:Refresh()
|
||||
RefreshScale()
|
||||
RefreshLang()
|
||||
for _, def in ipairs(settingsSections) do
|
||||
if def.frame and def.refresh then
|
||||
pcall(def.refresh, def.frame)
|
||||
end
|
||||
end
|
||||
stack:Layout()
|
||||
LayoutSections()
|
||||
end
|
||||
|
||||
-- senkrechte Trennstriche zwischen den Spalten
|
||||
local function VLine()
|
||||
local line = body:CreateTexture(nil, "ARTWORK")
|
||||
line:SetWidth(1)
|
||||
line:SetColorTexture(UI.Color("gold", 0.35))
|
||||
return line
|
||||
end
|
||||
vline1, vline2 = VLine(), VLine()
|
||||
|
||||
body:SetScript("OnSizeChanged", function(self)
|
||||
local w = self:GetWidth()
|
||||
if type(w) == "number" and w > 0 then
|
||||
stack:Layout()
|
||||
LayoutSections()
|
||||
end
|
||||
end)
|
||||
for _, def in ipairs(settingsSections) do
|
||||
BuildSection(def)
|
||||
end
|
||||
stack:Layout()
|
||||
LayoutSections()
|
||||
|
||||
f.Refresh()
|
||||
return f
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Anmelden
|
||||
------------------------------------------------------------------------
|
||||
|
||||
UI:RegisterTab("overview", {
|
||||
label = function() return FW.L.TAB_OVERVIEW end,
|
||||
order = 10,
|
||||
build = BuildOverview,
|
||||
onShow = function(f) f.Refresh() end,
|
||||
})
|
||||
|
||||
UI:RegisterTab("exchange", {
|
||||
label = function() return FW.L.TAB_EXCHANGE end,
|
||||
order = 110,
|
||||
build = BuildExchange,
|
||||
onShow = function(f) f.Refresh() end,
|
||||
})
|
||||
|
||||
UI:RegisterTab("settings", {
|
||||
label = function() return FW.L.TAB_SETTINGS end,
|
||||
order = 20,
|
||||
build = BuildSettings,
|
||||
onShow = function(f) f.Refresh() end,
|
||||
})
|
||||
Reference in New Issue
Block a user