Files

654 lines
34 KiB
Lua

QuestieOcto.Options = QuestieOcto.Options or {}
local O = QuestieOcto.Options
O.configFrame=nil
O.initialized=false
O.openedFromGameMenu=false
O.stats={
initializes=0,opens=0,closes=0,changes=0,
lastSetKey="none",lastSetValue="none",
aceGUI=false,aceRegistry=false,aceDialog=false
}
local APP_NAME="Questie Options"
-- ShaguTweaks' Darkened UI is the Vanilla compatibility reference here.
-- Keep the original Questie outer-shell tint, but treat the AceConfig content
-- like ShaguTweaks' Advanced Options: dark translucent backdrops instead of a
-- recursive gray vertex-color wash over every descendant texture.
local SHELL_R,SHELL_G,SHELL_B,SHELL_A=0.30,0.30,0.30,0.90
local INNER_R,INNER_G,INNER_B,INNER_A=0.035,0.035,0.035,0.84
local INNER_BORDER_R,INNER_BORDER_G,INNER_BORDER_B,INNER_BORDER_A=0.20,0.20,0.20,0.95
local TAB_R,TAB_G,TAB_B,TAB_A=0.28,0.28,0.28,1.0
-- 1.12 reports nil for a backdrop color/border that was never explicitly set
-- (the AceGUI Frame shell never sets a border color, so its default is white).
-- Fill nil with 1 so the value is restorable. `x or 1` is safe here because Lua
-- treats 0 as truthy, so a legitimate black (0) component is preserved.
local function CaptureBackdropColors(frame)
if not frame or frame.questieOctoThemeCaptured then return end
frame.questieOctoThemeCaptured=true
if frame.GetBackdropColor then
local r,g,b,a=frame:GetBackdropColor()
frame.questieOctoBgR,frame.questieOctoBgG,frame.questieOctoBgB,frame.questieOctoBgA=r or 1,g or 1,b or 1,a or 1
end
if frame.GetBackdropBorderColor then
local r,g,b,a=frame:GetBackdropBorderColor()
frame.questieOctoBdR,frame.questieOctoBdG,frame.questieOctoBdB,frame.questieOctoBdA=r or 1,g or 1,b or 1,a or 1
end
end
local function CaptureVertexColor(region)
if not region or region.questieOctoVertexCaptured then return end
region.questieOctoVertexCaptured=true
if region.GetVertexColor then
local r,g,b,a=region:GetVertexColor()
region.questieOctoVR,region.questieOctoVG,region.questieOctoVB,region.questieOctoVA=r or 1,g or 1,b or 1,a or 1
end
end
local function RestoreBackdropColors(frame)
if not frame or not frame.questieOctoThemeCaptured then return end
if frame.SetBackdropColor and frame.questieOctoBgR then
local a=frame.questieOctoBgA
if a==nil then a=1 end
frame:SetBackdropColor(frame.questieOctoBgR,frame.questieOctoBgG,frame.questieOctoBgB,a)
end
if frame.SetBackdropBorderColor and frame.questieOctoBdR then
local a=frame.questieOctoBdA
if a==nil then a=1 end
frame:SetBackdropBorderColor(frame.questieOctoBdR,frame.questieOctoBdG,frame.questieOctoBdB,a)
end
end
local function RestoreVertexColor(region)
if not region or not region.questieOctoVertexCaptured then return end
if region.SetVertexColor and region.questieOctoVR then
local a=region.questieOctoVA
if a==nil then a=1 end
region:SetVertexColor(region.questieOctoVR,region.questieOctoVG,region.questieOctoVB,a)
end
end
-- Undo the dark pass by walking the same frame tree and restoring every color
-- captured on the way in. Frames AceConfig rebuilt after the last darken were
-- never captured, so they are already at their Blizzard default and skipped.
local function RestoreDefaultTheme(frame)
if not frame then return end
RestoreBackdropColors(frame)
if frame.GetRegions then
local regions={frame:GetRegions()}
for _,region in pairs(regions) do
if region and region.GetObjectType and region:GetObjectType()=="Texture" then
RestoreVertexColor(region)
end
end
end
if frame.GetChildren then
local children={frame:GetChildren()}
for _,child in pairs(children) do
RestoreDefaultTheme(child)
end
end
end
local function ShouldSkipShellTexture(region)
if not region or not region.GetTexture then return true end
local texture=region:GetTexture()
if not texture then return true end
local name=region.GetName and region:GetName() or nil
if name then
if string.find(name,"Button",1,true) or string.find(name,"Icon",1,true) then return true end
end
if type(texture)=="string" then
if string.find(texture,"Button",1,true)
or string.find(texture,"Icon",1,true)
or string.find(texture,"WHITE8X8",1,true)
or string.find(texture,"StatusBar",1,true)
or string.find(texture,"BarFill",1,true)
or string.find(texture,"Portrait",1,true) then
return true
end
end
if region.GetBlendMode and region:GetBlendMode()=="ADD" then return true end
return false
end
-- Only tint the physical AceGUI Frame itself. This preserves the successful
-- outer-frame look from 0.1.81 without washing the entire options contents gray.
local function DarkenOuterShell(frame)
if not frame then return end
-- Capture ALL originals before mutating anything. SetBackdropBorderColor
-- tints the backdrop's edge textures, and those same textures are returned by
-- GetRegions(); capturing their vertex color after that call would record the
-- already-darkened value and leave the shell border stuck dark on toggle-off.
CaptureBackdropColors(frame)
if frame.GetRegions then
local regions={frame:GetRegions()}
for _,region in pairs(regions) do
if region and region.GetObjectType and region:GetObjectType()=="Texture"
and region.SetVertexColor and not ShouldSkipShellTexture(region) then
CaptureVertexColor(region)
end
end
end
if frame.SetBackdropBorderColor then
frame:SetBackdropBorderColor(SHELL_R,SHELL_G,SHELL_B,SHELL_A)
end
if frame.GetRegions then
local regions={frame:GetRegions()}
for _,region in pairs(regions) do
if region and region.GetObjectType and region:GetObjectType()=="Texture"
and region.SetVertexColor and not ShouldSkipShellTexture(region) then
region:SetVertexColor(SHELL_R,SHELL_G,SHELL_B,SHELL_A)
end
end
end
end
local function IsTabTexture(region)
if not region or not region.GetTexture then return false end
local texture=region:GetTexture()
return type(texture)=="string" and string.find(texture,"ChatFrameTab",1,true) and true or false
end
-- AceGUI's ScrollFrame places a UIPanelScrollBarTemplate just outside the
-- scrolling viewport. Keep that native Vanilla control above Questie's dark
-- content panels and do not recolor it as if it were a backdrop container.
local function IsAceConfigScrollbar(frame)
if not frame or not frame.GetName then return false end
local name=frame:GetName()
return name and string.find(name,"AceConfigDialogScrollFrame",1,true)
and string.find(name,"ScrollBar",1,true) and true or false
end
local function RaiseScrollbar(frame)
if not frame then return end
if IsAceConfigScrollbar(frame) then
local parent=frame.GetParent and frame:GetParent() or nil
local base=(parent and parent.GetFrameLevel and parent:GetFrameLevel()) or 0
if frame.SetFrameLevel then frame:SetFrameLevel(base+20) end
-- Vanilla's UIPanelScrollBarTemplate thumb artwork is wider than the
-- 16-pixel Slider frame used by AceGUI. On the 1.12 client that narrow
-- slider can crop the outer edge of the native thumb texture even though
-- the control is correctly positioned in the right gutter. Give the
-- slider its native visual width instead of moving it inward; this lets the
-- full thumb render at the same right-side location.
if frame.SetWidth and (not frame.questieOctoFullThumbWidth) then
frame:SetWidth(20)
frame.questieOctoFullThumbWidth=true
end
-- UIPanelScrollBarTemplate's arrow buttons and thumb artwork are children/
-- regions of the slider. Raising them too avoids client-specific 1.12
-- ordering where the thumb can otherwise appear partly behind the panel.
if frame.GetChildren then
local children={frame:GetChildren()}
for _,child in pairs(children) do
if child and child.SetFrameLevel then child:SetFrameLevel(base+21) end
end
end
return
end
if frame.GetChildren then
local children={frame:GetChildren()}
for _,child in pairs(children) do
RaiseScrollbar(child)
end
end
end
-- ShaguTweaks' own config builds dark panels by coloring frame backdrops
-- (.1/.1/.1) rather than painting a gray vertex color over all child regions.
-- Do the same for Questie's AceGUI content tree. Backdrop-less controls remain
-- untouched; their native checkbox/slider/button artwork therefore stays crisp.
local function DarkenInnerContent(frame)
if not frame then return end
-- Leave the native Vanilla scrollbar completely untouched by the panel
-- darkening pass. It is a control, not a content backdrop.
if IsAceConfigScrollbar(frame) then return end
if frame.SetBackdropColor or frame.SetBackdropBorderColor then
CaptureBackdropColors(frame)
end
if frame.SetBackdropColor then
frame:SetBackdropColor(INNER_R,INNER_G,INNER_B,INNER_A)
end
if frame.SetBackdropBorderColor then
frame:SetBackdropBorderColor(INNER_BORDER_R,INNER_BORDER_G,INNER_BORDER_B,INNER_BORDER_A)
end
-- The top Questie tabs use ChatFrameTab textures instead of a backdrop.
-- Tint only that known decorative texture; do not touch checkbox, slider,
-- icon, highlight or status-bar artwork.
if frame.GetRegions then
local regions={frame:GetRegions()}
for _,region in pairs(regions) do
if region and region.GetObjectType and region:GetObjectType()=="Texture"
and region.SetVertexColor and IsTabTexture(region) then
CaptureVertexColor(region)
region:SetVertexColor(TAB_R,TAB_G,TAB_B,TAB_A)
end
end
end
if frame.GetChildren then
local children={frame:GetChildren()}
for _,child in pairs(children) do
DarkenInnerContent(child)
end
end
end
function O:ApplyDarkTheme(apply)
if not self.configFrame or not self.configFrame.frame then return end
-- No-argument callers (the initial open and AceConfig's post-refresh reapply)
-- must honor the saved setting, not force the theme on. Only the toggle's own
-- setter passes an explicit boolean.
if apply == nil then
apply=(QuestieOcto.MinimapSettings and QuestieOcto.MinimapSettings:Get("useDarkTheme")) and true or false
end
local shell=self.configFrame.frame
if apply then
DarkenOuterShell(shell)
-- Apply the inner treatment only below the outer shell. Keeping the shell
-- separate is important because its DialogFrame textures need vertex tinting,
-- while AceConfig's content containers look better with dark backdrops.
if shell.GetChildren then
local children={shell:GetChildren()}
for _,child in pairs(children) do
DarkenInnerContent(child)
end
end
else
-- Unchecked: return every frame/texture the dark pass touched to the exact
-- Blizzard color it had on load.
RestoreDefaultTheme(shell)
end
-- Run after backdrop darkening so the scrollbar is always the final/top UI
-- layer, including after AceConfig rebuilds the currently selected tab.
RaiseScrollbar(shell)
end
local function Settings()
return QuestieOcto.MinimapSettings
end
local function ClearSavedConfigPosition()
local Dialog=LibStub and LibStub("QuestieOcto_AceConfigDialog-3.0",true)
if not Dialog or not Dialog.GetStatusTable then return end
local status=Dialog:GetStatusTable(APP_NAME)
if status then
status.top=nil
status.left=nil
end
end
local function GetValue(info)
local key=info[table.getn(info)]
return Settings():Get(key)
end
local function SetValue(info,value)
local key=info[table.getn(info)]
O.stats.lastSetKey=tostring(key or "nil")
O.stats.lastSetValue=tostring(value)
local changed=Settings():Set(key,value)
if changed then
O.stats.changes=O.stats.changes+1
end
-- AceConfigDialog refreshes the custom frame immediately after setters.
-- Clear AceGUI's persisted drag coordinates before that refresh happens.
ClearSavedConfigPosition()
end
local function EnabledMinimap()
return Settings():Get("enableMiniMapIcons") and true or false
end
local function CreateGeneralTab()
return {
name="General", type="group", order=1,
args={
icon_header={type="header",order=1,name="Icon Settings"},
enableMapIcons={type="toggle",order=2,name="Show Quests",desc="Show quest icons on the main map.",width="full",get=GetValue,set=SetValue},
showCompletedQuests={type="toggle",order=2.1,name="Always Show Completed Quests",desc="Always show completed quests on minimap and map regardless if zone is collapsed.",width="full",get=GetValue,set=SetValue},
world_map_visibility_header={type="header",order=3,name="World Map Visibility"},
showAllQuestsWorldMap={type="toggle",order=3.1,name="Show Quests on the World Map",desc="Show normal quest pickup and turn-in icons on continent maps.",width="full",get=GetValue,set=SetValue},
showSpecialQuestsWorldMap={type="toggle",order=3.2,name="Show Special Quests on the World Map",desc="Show repeatable, PvP, and active event quest icons on continent maps.",width="full",get=GetValue,set=SetValue},
showMapFlightMaster={type="toggle",order=3.3,name="Show Flight Master on the World Map",desc="Show Flight Master icons on the map.",width="full",get=GetValue,set=SetValue},
enableMiniMapIcons={type="toggle",order=4,name="Enable Minimap Icons",desc="Show quest icons on the minimap.",width="full",get=GetValue,set=SetValue},
type_header={type="header",order=5,name="Quest Icon Types"},
enableObjectives={type="toggle",order=5,name="Enable Objective Icons",desc="Show active quest objectives on the map and minimap.",width="full",get=GetValue,set=SetValue},
enableTurnins={type="toggle",order=6,name="Enable Completed Quest Icons",desc="Show completed quest turn-ins on the map and minimap.",width="full",get=GetValue,set=SetValue},
enableAvailable={type="toggle",order=7,name="Enable Available Quest Icons",desc="Show available quests on the map and minimap.",width="full",get=GetValue,set=SetValue},
objective_nodes={type="group",order=8,name="Objective Nodes",inline=true,args={
objectiveNodeDensity={type="select",order=1,name="Objective Node Density",desc="Clustered groups nearby spawns. Full Nodes shows every known spawn.",width="double",values={clustered="Clustered",full="Full Nodes"},get=GetValue,set=SetValue},
}},
item_start_options={type="group",order=9,name="Item-Start Quests",inline=true,args={
showItemStartQuests={type="toggle",order=1,name="Show Item-Start Quests",desc="Show quests started by dropped or looted items.",width="full",get=GetValue,set=SetValue},
showItemStartMap={type="toggle",order=2,name="Show on World Map",desc="Show item-start quest sources on the World Map.",width="full",disabled=function() return not Settings():Get("showItemStartQuests") end,get=GetValue,set=SetValue},
showItemStartMinimap={type="toggle",order=3,name="Show on Minimap",desc="Show item-start quest sources on the minimap.",width="full",disabled=function() return not Settings():Get("showItemStartQuests") end,get=GetValue,set=SetValue},
itemStartDensity={type="select",order=4,name="Node Density",desc="Clustered groups nearby sources. Full Nodes shows every known source.",width="double",values={clustered="Clustered",full="Full Nodes"},disabled=function() return not Settings():Get("showItemStartQuests") end,get=GetValue,set=SetValue},
}},
quest_options={type="group",order=10,name="Quest Options",inline=true,args={
showQuestRoute={type="toggle",order=1,name="Show Quest Route",desc="Shows fasted route on map to complete objectives.",width="full",get=GetValue,set=SetValue},
showQuestArrow={type="toggle",order=2,name="Show Quest Arrow",desc="Shows arrow that points towards nearest quest objective.",width="full",get=GetValue,set=SetValue},
questLogShowLevels={type="toggle",order=3,name="Show Quest Levels",desc="Show quest levels in the Quest Log.",width="full",get=GetValue,set=SetValue},
showLowLevelQuests={type="toggle",order=4,name="Show Low-Level Quests",desc="Show quests below the normal green quest range.",get=GetValue,set=SetValue},
lowLevelQuestRange={type="range",order=5,name=function()
local value=tonumber(Settings():Get("lowLevelQuestRange")) or 35
if value>=35 then return "Levels Below: All" end
return "Levels Below: "..tostring(value)
end,desc="Limit how many levels below you are shown. All removes the limit.",width="normal",min=5,max=35,step=5,arg={questieHideEditBox=true,questieMaxLabel="All",questieCommitOnMouseUp=true,questieLiveLabelPrefix="Levels Below: "},disabled=function() return not Settings():Get("showLowLevelQuests") end,get=GetValue,set=SetValue},
showRepeatableQuests={type="toggle",order=6,name="Show Repeatable Quests",desc="Show available repeatable quests.",width="full",get=GetValue,set=SetValue},
showEventQuests={type="toggle",order=7,name="Show Event Quests",desc="Show available event quests.",width="full",get=GetValue,set=SetValue},
showPvPRelatedQuests={type="toggle",order=8,name="Show PVP Related Quests",desc="Show PvP quest icons on the map and minimap.",width="full",get=GetValue,set=SetValue},
}},
reset_header={type="header",order=90,name="Questie Options"},
enableDarkTheme={type="toggle",order=91,name="Enable Dark Theme",desc="Darken the configuration frame backdrops.",width="full",
get=function()
return Settings():Get("useDarkTheme")
end,
set=function(_, value)
Settings():Set("useDarkTheme", value)
O:ApplyDarkTheme(value)
end
},
reset_text={type="description",order=92,name="Restore Questie-Octo options to their defaults. Quest data and completed-quest history are not deleted.",fontSize="medium"},
resetOptions={type="execute",order=93,name="Reset Options",desc="Restore option defaults.",func=function()
Settings():Reset()
ClearSavedConfigPosition()
local Registry=LibStub and LibStub("QuestieOcto_AceConfigRegistry-3.0",true)
if Registry and Registry.NotifyChange then Registry:NotifyChange(APP_NAME) end
end},
},
}
end
local function CreateMapTab()
return {
name="Map", type="group", order=10,
args={
map_options={type="header",order=1,name="Map Options"},
alwaysGlowMap={type="toggle",order=1.1,name="Enable Map Icon Glow",desc="Add a colored glow behind objective icons.",width="full",get=GetValue,set=SetValue},
questObjectiveColors={type="toggle",order=1.2,name="Enable Different Map Icon Color for Each Quest",desc="Use a different color for each quest's objective icons.",width="full",get=GetValue,set=SetValue},
notes_header={type="header",order=2,name="Map Note Options"},
globalScale={type="range",order=2.2,name="Global Scale for Map Icons",desc="Adjust map icon size.",width="double",min=0.01,max=4,step=0.01,disabled=function() return not Settings():Get("enableMapIcons") end,get=GetValue,set=SetValue},
miscellaneous_icons={type="header",order=20,name="Miscellaneous icons"},
showMapClassTrainer={type="toggle",order=20.2,name="Class Trainers",desc="Show Class Trainers on the map.",width="full",get=GetValue,set=SetValue},
showMapProfessionTrainer={type="toggle",order=20.3,name="Profession Trainers",desc="Show Profession Trainers on the map.",width="full",get=GetValue,set=SetValue},
showMapRareMonsters={type="toggle",order=20.4,name="Rare Monsters",desc="Show Rare Monster icons on the map.",width="full",get=GetValue,set=SetValue},
showMapAuctioneer={type="toggle",order=20.5,name="Auctioneer",desc="Show Auctioneer icons on the map.",width="full",get=GetValue,set=SetValue},
showMapBanker={type="toggle",order=20.6,name="Banker",desc="Show Banker icons on the map.",width="full",get=GetValue,set=SetValue},
showMapFlightMaster={type="toggle",order=20.7,name="Flight Master",desc="Show Flight Master icons on the map.",width="full",get=GetValue,set=SetValue},
showMapMailbox={type="toggle",order=20.8,name="Mailbox",desc="Show Mailbox icons on the map.",width="full",get=GetValue,set=SetValue},
showMapBattlemaster={type="toggle",order=20.9,name="Battlemaster",desc="Show Battlemaster icons on the map.",width="full",get=GetValue,set=SetValue},
showMapInnkeeper={type="toggle",order=21,name="Innkeeper",desc="Show Innkeeper icons on the map.",width="full",get=GetValue,set=SetValue},
showMapMeetingStone={type="toggle",order=21.1,name="Meeting Stones",desc="Show Meeting Stone icons on the map.",width="full",get=GetValue,set=SetValue},
showMapRepair={type="toggle",order=21.2,name="Repair",desc="Show Repair icons on the map.",width="full",get=GetValue,set=SetValue},
showMapSpiritHealer={type="toggle",order=21.3,name="Spirit Healer",desc="Show Spirit Healer icons on the map.",width="full",get=GetValue,set=SetValue},
showMapStableMaster={type="toggle",order=21.4,name="Stable Master",desc="Show Stable Master icons on the map.",width="full",get=GetValue,set=SetValue},
showMapVendor={type="toggle",order=21.5,name="Vendor",desc="Show Vendor icons on the map.",width="full",get=GetValue,set=SetValue},
},
}
end
local function CreateMinimapTab()
return {
name="Minimap", type="group", order=11,
args={
options_header={type="header",order=1,name="Minimap Options"},
alwaysGlowMinimap={type="toggle",order=1.1,name="Enable Minimap Icon Glow",desc="Add a colored glow behind objective icons.",width="full",disabled=function() return not EnabledMinimap() end,get=GetValue,set=SetValue},
questMinimapObjectiveColors={type="toggle",order=1.2,name="Enable Different Minimap Icon Color for Each Quest",desc="Use a different color for each quest's objective icons.",width="full",disabled=function() return not EnabledMinimap() end,get=GetValue,set=SetValue},
notes_header={type="header",order=2,name="Minimap Note Options"},
globalMiniMapScale={type="range",order=2.2,name="Global Scale for Minimap Icons",desc="Adjust minimap icon size.",width="double",min=0.01,max=4,step=0.01,disabled=function() return not EnabledMinimap() end,get=GetValue,set=SetValue},
miscellaneous_icons={type="header",order=20,name="Miscellaneous icons"},
showMinimapClassTrainer={type="toggle",order=20.1,name="Class Trainers",desc="Show Class Trainers on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapProfessionTrainer={type="toggle",order=20.2,name="Profession Trainers",desc="Show Profession Trainers on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapRareMonsters={type="toggle",order=20.3,name="Rare Monsters",desc="Show Rare Monster icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapAuctioneer={type="toggle",order=20.4,name="Auctioneer",desc="Show Auctioneer icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapBanker={type="toggle",order=20.5,name="Banker",desc="Show Banker icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapFlightMaster={type="toggle",order=20.6,name="Flight Master",desc="Show Flight Master icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapMailbox={type="toggle",order=20.7,name="Mailbox",desc="Show Mailbox icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapBattlemaster={type="toggle",order=20.8,name="Battlemaster",desc="Show Battlemaster icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapInnkeeper={type="toggle",order=20.9,name="Innkeeper",desc="Show Innkeeper icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapMeetingStone={type="toggle",order=21,name="Meeting Stones",desc="Show Meeting Stone icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapRepair={type="toggle",order=21.1,name="Repair",desc="Show Repair icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapSpiritHealer={type="toggle",order=21.2,name="Spirit Healer",desc="Show Spirit Healer icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapStableMaster={type="toggle",order=21.3,name="Stable Master",desc="Show Stable Master icons on the minimap.",width="full",get=GetValue,set=SetValue},
showMinimapVendor={type="toggle",order=21.4,name="Vendor",desc="Show Vendor icons on the minimap.",width="full",get=GetValue,set=SetValue},
},
}
end
local function CreateTrackerTab()
return {
name="Tracker", type="group", order=12,
args={
tracker_header={type="header",order=1,name="Tracker Options"},
trackerEnabled={type="toggle",order=2,name="Enable Quest Tracker",desc="Show or hide the quest tracker.",width="full",get=GetValue,set=SetValue},
resetTracker={type="execute",order=2.5,name="Reset Tracker Position",desc="Return the tracker to its default position.",func=function()
if QuestieOcto.TrackerFrame and QuestieOcto.TrackerFrame.ResetLocation then QuestieOcto.TrackerFrame:ResetLocation() end
end},
trackerLocked={type="toggle",order=3,name="Lock Tracker",desc="Prevent the tracker from being moved.",width="full",get=GetValue,set=SetValue},
trackerAutoTrack={type="toggle",order=4,name="Auto Track Quests",desc="Automatically track accepted quests.",width="full",get=GetValue,set=SetValue},
trackerShowCompleted={type="toggle",order=5,name="Show Completed Quests",desc="Keep completed quests visible until turned in.",width="full",get=GetValue,set=SetValue},
trackerHideCompletedObjectives={type="toggle",order=6,name="Hide Completed Objectives",desc="Hide completed objective lines.",width="full",get=GetValue,set=SetValue},
sorting_header={type="header",order=10,name="Sorting"},
trackerSort={type="select",order=11,name="Sort Quests",desc="Choose how quests are sorted.",width="double",values={zone="Zone",proximity="Proximity",level="Level"},get=GetValue,set=SetValue},
appearance_header={type="header",order=20,name="Appearance"},
trackerHideInCombat={type="toggle",order=12,name="Hide Tracker in Combat",desc="Hide the tracker while in combat.",width="full",get=GetValue,set=SetValue},
trackerOutlineText={type="toggle",order=20.1,name="Outline",desc="Add an outline to tracker text.",width="full",get=GetValue,set=SetValue},
trackerThickOutlineText={type="toggle",order=20.2,name="Thick Outline",desc="Add a thicker outline to tracker text.",width="full",get=GetValue,set=SetValue},
trackerFontSize={type="range",order=21,name="Font Size",desc="Adjust tracker text size.",width="double",min=8,max=18,step=1,get=GetValue,set=SetValue},
trackerMaxWidth={type="range",order=22,name="Width",desc="Set the maximum tracker width.",width="double",min=200,max=500,step=10,get=GetValue,set=SetValue},
trackerVisibleRows={type="range",order=23,name="Visible Rows",desc="Set the maximum number of visible rows.",width="double",min=6,max=60,step=1,get=GetValue,set=SetValue},
trackerBackgroundOpacity={type="range",order=24,name="Background Opacity",desc="Adjust tracker background opacity.",width="double",min=0,max=1,step=0.05,get=GetValue,set=SetValue},
manual_hint={type="description",order=30,name="Shift + Left Click a quest in the Quest Log to track or untrack it manually.",fontSize="medium"},
},
}
end
local function CreateTooltipTab()
return {
name="Tooltips", type="group", order=13,
args={
header={type="header",order=1,name="Tooltip Options"},
enableTooltips={type="toggle",order=2,name="Enable Questie Tooltips",desc="Show quest information on map markers and world tooltips.",width="full",get=GetValue,set=SetValue},
enableTooltipsQuestLevel={type="toggle",order=3,name="Show Quest Levels",desc="Show quest levels in tooltips.",width="full",disabled=function() return not Settings():Get("enableTooltips") end,get=GetValue,set=SetValue},
enableTooltipDroprates={type="toggle",order=4,name="Show Drop Rates",desc="Show item drop rates.",width="full",disabled=function() return not Settings():Get("enableTooltips") end,get=GetValue,set=SetValue},
id_header={type="header",order=10,name="Tooltip IDs"},
enableTooltipsQuestID={type="toggle",order=11,name="Show Quest IDs",desc="Show quest IDs.",width="full",disabled=function() return not Settings():Get("enableTooltips") end,get=GetValue,set=SetValue},
enableTooltipsNPCID={type="toggle",order=12,name="Show NPC IDs",desc="Show NPC IDs.",width="full",disabled=function() return not Settings():Get("enableTooltips") end,get=GetValue,set=SetValue},
enableTooltipsItemID={type="toggle",order=13,name="Show Item IDs",desc="Show item IDs.",width="full",disabled=function() return not Settings():Get("enableTooltips") end,get=GetValue,set=SetValue},
},
}
end
local function CreateOptionsTable()
return {
name="Questie Options",
type="group",
childGroups="tab",
args={
general_tab=CreateGeneralTab(),
map_tab=CreateMapTab(),
minimap_tab=CreateMinimapTab(),
tracker_tab=CreateTrackerTab(),
tooltip_tab=CreateTooltipTab(),
--quests_tab=QuestieOcto.QuestResearch:GetOptionsTab(),
},
}
end
function O:Initialize()
if self.initialized then return true end
local AceGUI=LibStub and LibStub("QuestieOcto_AceGUI-3.0",true)
local Registry=LibStub and LibStub("QuestieOcto_AceConfigRegistry-3.0",true)
local Dialog=LibStub and LibStub("QuestieOcto_AceConfigDialog-3.0",true)
self.stats.aceGUI=AceGUI and true or false
self.stats.aceRegistry=Registry and true or false
self.stats.aceDialog=Dialog and true or false
if not AceGUI or not Registry or not Dialog then
QuestieOcto:Error("Questie-style AceConfig runtime unavailable")
return false
end
-- Equivalent to Questie 5/6 RegisterOptionsTable(), without AceConfigCmd.
-- We intentionally avoid Blizzard InterfaceOptions registration on 1.12.
Registry:RegisterOptionsTable(APP_NAME,CreateOptionsTable())
-- Questie 5.2.3/6.0.0/3.3.5 create a standalone AceGUI Frame, then feed
-- AceConfigDialog into that frame and keep it for later toggling.
local configFrame=AceGUI:Create("Frame")
configFrame:Hide()
Dialog:SetDefaultSize(APP_NAME,625,700)
Dialog:Open(APP_NAME,configFrame)
configFrame:SetLayout("Fill")
-- Questie 5/6/3.3.5 use one persistent AceGUI frame as the options shell.
-- On this Vanilla/Ace3v runtime, AceConfigDialog calls SetStatusTable() on
-- that same custom root frame after every option activation. AceGUI Frame's
-- SetStatusTable() immediately runs ApplyStatus(), which clears/reanchors the
-- physical frame. Turtle's 1.12 layout path can therefore visibly jump the
-- window even when status.top/status.left are nil.
--
-- The mature Questie behavior we need is simpler: refresh the option widgets,
-- not the already-open outer shell. The frame is non-resizable here, so after
-- its initial Questie size has been applied there is no legitimate refresh
-- reason to re-run outer-frame geometry. Preserve the status table for Ace3
-- semantics, but deliberately do not call ApplyStatus() on later refreshes.
if configFrame.SetStatusTable then
configFrame.SetStatusTable=function(self,status)
if status then
status.top=nil
status.left=nil
self.status=status
end
end
end
if configFrame.EnableResize then
configFrame:EnableResize(false)
end
configFrame:Hide()
self.configFrame=configFrame
-- Questie 5.2.3/6.0.0/3.3.5/7/8 register the actual standalone
-- AceGUI config object in UISpecialFrames through a global name. The widget
-- already exposes IsShown()/Hide(), so Vanilla ESC can close the real shell
-- directly; no hidden proxy frame is required.
QuestieOctoConfigFrame=configFrame
local registered=false
for _,name in pairs(UISpecialFrames or {}) do
if name=="QuestieOctoConfigFrame" then registered=true break end
end
if not registered then
table.insert(UISpecialFrames,"QuestieOctoConfigFrame")
end
-- Vanilla GameMenu compatibility: when Questie Options was opened from ESC,
-- closing it returns to the Game Menu, matching ShaguTweaks' proven 1.12 flow.
-- Slash-command opens do not trigger this behavior.
configFrame:SetCallback("OnClose",function()
O.stats.closes=O.stats.closes+1
if O.openedFromGameMenu then
local origin=O.openedFromGameMenu
O.openedFromGameMenu=false
if origin=="dragonflight" and DFRL and DFRL.menuframe then
DFRL.menuframe:Show()
elseif GameMenuFrame and ShowUIPanel then
ShowUIPanel(GameMenuFrame)
end
if UpdateMicroButtons then UpdateMicroButtons() end
end
end)
self.initialized=true
self.stats.initializes=self.stats.initializes+1
-- QuestieOctoConfigFrame above is the UISpecialFrames participant, matching
-- the supplied Questie options architecture.
return true
end
local function RecenterConfigFrame(configFrame)
ClearSavedConfigPosition()
if not configFrame or not configFrame.frame then return end
local frame=configFrame.frame
-- Keep Questie's persistent AceGUI frame architecture, but make drag
-- placement temporary: every explicit open returns to the default center.
if frame.ClearAllPoints then frame:ClearAllPoints() end
if frame.SetPoint then frame:SetPoint("CENTER",UIParent,"CENTER",0,0) end
end
function O:Show()
if not self:Initialize() then return end
local Dialog=LibStub("QuestieOcto_AceConfigDialog-3.0")
-- Questie 3.3.5 refreshes the existing standalone frame through Open().
Dialog:Open(APP_NAME,self.configFrame)
RecenterConfigFrame(self.configFrame)
self:ApplyDarkTheme()
self.stats.opens=self.stats.opens+1
end
function O:Hide()
if self.configFrame and self.configFrame:IsShown() then
self.configFrame:Hide()
end
end
function O:ShowFromGameMenu(origin)
self.openedFromGameMenu=origin or true
self:Show()
end
function O:Toggle()
if not self:Initialize() then return end
if self.configFrame:IsShown() then
self:Hide()
else
self:Show()
end
end
-- Build the hidden frame after login rather than during file load.
QuestieOcto.Scheduler:After(0.10,function()
O:Initialize()
end,"questie-options-init")