-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathBetterUI.lua
More file actions
572 lines (510 loc) · 21.4 KB
/
Copy pathBetterUI.lua
File metadata and controls
572 lines (510 loc) · 21.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
--[[
File: BetterUI.lua
Purpose: Main entry point for the BetterUI addon.
Handles module initialization and event registration.
Mechanics: Listens for EVENT_ADD_ON_LOADED to initialize itself.
Manages the loading of sub-modules based on Gamepad mode.
Runtime patches and settings migrations are delegated to CIM/RuntimeSetup.lua.
Author: BetterUI Team
Last Modified: 2026-02-08
-- TODO(ARCHITECTURE): Consider adopting a formal module registration pattern.
-- Current approach: Each module is manually listed in LoadModules() and Initialize().
-- Proposed: BETTERUI.RegisterModule(name, namespace, dependencies) that auto-wires:
-- 1. Settings initialization
-- 2. Setup() call ordering based on dependencies
-- 3. Settings panel registration
-- This would reduce boilerplate and ensure consistent module structure.
-- See: WoW's AceAddon or similar patterns for inspiration.
]]
local LAM = LibAddonMenu2
if BETTERUI == nil then BETTERUI = {} end
-- ============================================================================
-- NAMESPACE INITIALIZATION (Required before module files load)
-- ============================================================================
-- Core addon metadata
BETTERUI.name = "BetterUI"
BETTERUI.version = "3.06"
-- Module namespace tables
BETTERUI.Inventory = BETTERUI.Inventory or {}
BETTERUI.Banking = BETTERUI.Banking or {}
BETTERUI.Writs = BETTERUI.Writs or {}
BETTERUI.CIM = BETTERUI.CIM or {}
BETTERUI.GeneralInterface = BETTERUI.GeneralInterface or {}
BETTERUI.Nameplates = BETTERUI.Nameplates or {}
BETTERUI.ResourceOrbFrames = BETTERUI.ResourceOrbFrames or {}
-- UI Component namespaces
BETTERUI.GenericHeader = BETTERUI.GenericHeader or {}
BETTERUI.GenericFooter = BETTERUI.GenericFooter or {}
BETTERUI.Interface = BETTERUI.Interface or {}
-- Legacy namespace for backward compatibility
BETTERUI.CONST = BETTERUI.CONST or {}
-- Engine helper references
BETTERUI.WindowManager = GetWindowManager()
BETTERUI.EventManager = GetEventManager()
-- Research traits cache (populated by CIM/Core/ResearchCache.lua)
BETTERUI.ResearchTraits = BETTERUI.ResearchTraits or {}
-- Default settings structure
BETTERUI.DefaultSettings = {
firstInstall = true,
useAccountWide = false,
Modules = {}
}
--- Updates the Common Interface Module (CIM) state based on dependents.
---
--- Purpose: Ensures CIM is enabled if any module requiring it (Inventory, Banking) is active.
--- Mechanics: Checks settings for Tooltips, Inventory, and Banking.
--- Updates the CIM m_enabled setting accordingly.
--- References: Called when toggling module settings in the options panel.
---
function BETTERUI.UpdateCIMState()
local shouldEnable = BETTERUI.GetModuleEnabled("GeneralInterface") or
BETTERUI.GetModuleEnabled("Inventory") or
BETTERUI.GetModuleEnabled("Banking")
if BETTERUI.Settings.Modules["CIM"] then
BETTERUI.Settings.Modules["CIM"].m_enabled = shouldEnable
end
end
--- Initializes the module options panel in the settings menu.
---
--- Purpose: Registers the add-on settings panel using LibAddonMenu2.
--- Mechanics: Construct a table of options including checkboxes for each module.
--- Registers the panel and options with LAM.
--- References: Called during BETTERUI.Initialize.
---
function BETTERUI.InitModuleOptions()
local panelData = BETTERUI.Init_ModulePanel("Master", GetString(SI_BETTERUI_MASTER_SETTINGS_TITLE))
local optionsTable = {
{
type = "header",
name = GetString(SI_BETTERUI_MASTER_SETTINGS_HEADER),
width = "full",
},
{
type = "checkbox",
name = GetString(SI_BETTERUI_ENABLE_GLOBAL_SETTINGS),
tooltip = GetString(SI_BETTERUI_ENABLE_GLOBAL_TOOLTIP),
getFunc = function() return BETTERUI.SavedVars.useAccountWide end,
setFunc = function(value)
BETTERUI.SavedVars.useAccountWide = value
end,
width = "full",
requiresReload = true,
},
}
local function NormalizeModuleToggleSortName(name)
if type(name) ~= "string" then
return ""
end
local normalized = name
normalized = normalized:gsub("|c%x%x%x%x%x%x", "")
normalized = normalized:gsub("|r", "")
normalized = normalized:gsub("|t[^|]+|t", "")
normalized = normalized:gsub("^%s+", "")
normalized = normalized:gsub("%s+$", "")
-- Sort by the feature wording after "Enable ..." for consistency.
normalized = normalized:gsub("^Enable%s+", "")
normalized = normalized:gsub("^Activer%s+", "")
normalized = normalized:gsub("^Activar%s+", "")
normalized = normalized:gsub("^Aktivieren%s+", "")
normalized = normalized:gsub("^Включить%s+", "")
normalized = normalized:gsub("^启用", "")
normalized = normalized:gsub("^有効にする%s*", "")
if zo_strlower then
return zo_strlower(normalized)
end
return string.lower(normalized)
end
-- Keep "Use Global Settings" first, then sort module toggles by displayed label content.
local moduleToggleOptions = {
{
sortKey = "Banking",
type = "checkbox",
name = GetString(SI_BETTERUI_ENABLE_BANKING),
tooltip = GetString(SI_BETTERUI_ENABLE_BANKING_TOOLTIP),
getFunc = function()
local modules = BETTERUI.Settings and BETTERUI.Settings.Modules
return modules and modules["Banking"] and modules["Banking"].m_enabled or false
end,
setFunc = function(value)
BETTERUI.Settings.Modules["Banking"] = BETTERUI.Settings.Modules["Banking"] or {}
BETTERUI.Settings.Modules["Banking"].m_enabled = value
BETTERUI.UpdateCIMState()
end,
width = "full",
requiresReload = true,
},
{
sortKey = "General Interface",
type = "checkbox",
name = GetString(SI_BETTERUI_ENABLE_TOOLTIPS),
tooltip = GetString(SI_BETTERUI_ENABLE_TOOLTIPS_TOOLTIP),
getFunc = function()
local modules = BETTERUI.Settings and BETTERUI.Settings.Modules
return modules and modules["GeneralInterface"] and modules["GeneralInterface"].m_enabled or false
end,
setFunc = function(value)
BETTERUI.Settings.Modules["GeneralInterface"] = BETTERUI.Settings.Modules["GeneralInterface"] or {}
BETTERUI.Settings.Modules["GeneralInterface"].m_enabled = value
BETTERUI.UpdateCIMState()
end,
width = "full",
requiresReload = true,
},
{
sortKey = "Inventory",
type = "checkbox",
name = GetString(SI_BETTERUI_ENABLE_INVENTORY),
tooltip = GetString(SI_BETTERUI_ENABLE_INVENTORY_TOOLTIP),
getFunc = function()
local modules = BETTERUI.Settings and BETTERUI.Settings.Modules
return modules and modules["Inventory"] and modules["Inventory"].m_enabled or false
end,
setFunc = function(value)
BETTERUI.Settings.Modules["Inventory"] = BETTERUI.Settings.Modules["Inventory"] or {}
BETTERUI.Settings.Modules["Inventory"].m_enabled = value
BETTERUI.UpdateCIMState()
end,
width = "full",
requiresReload = true,
},
{
sortKey = "Resource Orb Frames",
type = "checkbox",
name = GetString(SI_BETTERUI_ENABLE_ORBS),
tooltip = GetString(SI_BETTERUI_ENABLE_ORBS_TOOLTIP),
getFunc = function()
return BETTERUI.GetModuleEnabled("ResourceOrbFrames")
end,
setFunc = function(value)
if not BETTERUI.Settings.Modules["ResourceOrbFrames"] then BETTERUI.Settings.Modules["ResourceOrbFrames"] = {} end
BETTERUI.Settings.Modules["ResourceOrbFrames"].m_enabled = value
end,
width = "full",
requiresReload = true,
},
{
sortKey = "Writs",
type = "checkbox",
name = GetString(SI_BETTERUI_ENABLE_WRITS),
tooltip = GetString(SI_BETTERUI_ENABLE_WRITS_TOOLTIP),
getFunc = function()
local modules = BETTERUI.Settings and BETTERUI.Settings.Modules
return modules and modules["Writs"] and modules["Writs"].m_enabled or false
end,
setFunc = function(value)
BETTERUI.Settings.Modules["Writs"] = BETTERUI.Settings.Modules["Writs"] or {}
BETTERUI.Settings.Modules["Writs"].m_enabled = value
end,
width = "full",
requiresReload = true,
},
}
for _, control in ipairs(moduleToggleOptions) do
control.sortKey = NormalizeModuleToggleSortName(control.name)
end
table.sort(moduleToggleOptions, function(left, right)
if left.sortKey == right.sortKey then
return tostring(left.name) < tostring(right.name)
end
return left.sortKey < right.sortKey
end)
for _, control in ipairs(moduleToggleOptions) do
control.sortKey = nil
table.insert(optionsTable, control)
end
-- NOTE: CIM toggle removed in v2.93 - CIM is now auto-managed internally
-- based on dependent modules (Inventory, Banking, GeneralInterface)
-- Developer-only feature flag controls (hidden for normal users)
local showDeveloperSettings = BETTERUI.CIM
and BETTERUI.CIM.Debug
and BETTERUI.CIM.Debug.ShouldShowDeveloperSettings
and BETTERUI.CIM.Debug.ShouldShowDeveloperSettings()
if showDeveloperSettings and BETTERUI.CIM and BETTERUI.CIM.FeatureFlags and BETTERUI.CIM.FeatureFlags.GetAllFlags then
local flagControls = {
{
type = "header",
name = GetString(SI_BETTERUI_FEATURE_FLAGS_HEADER),
width = "full",
},
{
type = "description",
text = GetString(SI_BETTERUI_FEATURE_FLAGS_DESC),
width = "full",
},
}
local allFlags = BETTERUI.CIM.FeatureFlags.GetAllFlags()
-- Sort flag names for consistent ordering
local sortedFlags = {}
for name in pairs(allFlags) do
table.insert(sortedFlags, name)
end
table.sort(sortedFlags)
for _, flagName in ipairs(sortedFlags) do
local flagData = allFlags[flagName]
local def = (flagData and flagData.definition) or {}
table.insert(flagControls, {
type = "checkbox",
name = def.name or flagName,
tooltip = (def.description or flagName) .. " | Version " .. (def.version or "?"),
getFunc = function()
return BETTERUI.CIM.FeatureFlags.IsEnabled(flagName)
end,
setFunc = function(value)
BETTERUI.CIM.FeatureFlags.SetEnabled(flagName, value)
end,
width = "full",
requiresReload = (flagName == "ENHANCED_TOOLTIPS"),
})
end
-- Append flag controls to options table
for _, control in ipairs(flagControls) do
table.insert(optionsTable, control)
end
end
table.insert(optionsTable, {
type = "divider",
width = "full",
})
table.insert(optionsTable, {
type = "button",
name = GetString(SI_BETTERUI_MASTER_RESET_ALL),
tooltip = GetString(SI_BETTERUI_MASTER_RESET_ALL_TOOLTIP),
func = function()
if BETTERUI.CIM and BETTERUI.CIM.Settings and BETTERUI.CIM.Settings.ResetAllSettingsToDefaults then
BETTERUI.CIM.Settings.ResetAllSettingsToDefaults()
end
end,
width = "full",
})
LAM:RegisterAddonPanel("BETTERUI_" .. "Modules", panelData)
LAM:RegisterOptionControls("BETTERUI_" .. "Modules", optionsTable)
end
--- Calls a module's InitModule function to set up default options.
---
--- Purpose: Standardizes the initialization of module-specific settings.
--- Mechanics: Checks if the module has an InitModule function and calls it with provided options.
--- On failure, disables the module to prevent cascading errors.
--- References: Called by BETTERUI.Initialize for each registered module (Inventory, Banking, etc.).
---
--- @param m_namespace table The module's namespace table.
--- @param m_options table The options table for the module.
--- @param moduleName string|nil Optional module name for error reporting.
--- @return table|nil The initialized module namespace, or nil on failure.
function BETTERUI.ModuleOptions(m_namespace, m_options, moduleName)
if m_namespace and m_namespace.InitModule then
-- Wrap in pcall to prevent one module's error from breaking the entire addon
local success, result = pcall(m_namespace.InitModule, m_options)
if success then
m_options = result
else
local name = moduleName or "unknown"
BETTERUI.Debug("[Error] InitModule failed for " .. name .. ": " .. tostring(result))
-- TODO(bug): Auto-disable writes to persistent SavedVars -- a transient init error permanently disables the module with no user notification or recovery path; should skip for current session only without persisting
if moduleName and BETTERUI.Settings and BETTERUI.Settings.Modules[moduleName] then
BETTERUI.Settings.Modules[moduleName].m_enabled = false
BETTERUI.Debug("[Recovery] Auto-disabled module: " .. name)
end
return nil -- Signal to caller that init failed
end
end
return m_namespace
end
--[[
Function: BETTERUI.ValidateAndSetupModule
Description: Validates a module before calling its Setup function.
Rationale: Enforces interface contracts to catch configuration errors early.
Mechanism: Uses CIM.Interfaces.ValidateModule if available, falls back to basic check.
param: moduleName (string) - The name of the module for logging
param: moduleNamespace (table) - The module's namespace table
return: boolean - True if module was successfully set up
]]
local function ValidateAndSetupModule(moduleName, moduleNamespace)
if not moduleNamespace then
BETTERUI.Debug(string.format("[Validation] Module '%s' namespace is nil", moduleName))
return false
end
-- Prevent double Setup (LAM:RegisterAddonPanel will crash with "Duplicate name")
if moduleNamespace._setupComplete then return true end
-- Validate using CIM interface validation if available
if BETTERUI.CIM and BETTERUI.CIM.Interfaces and BETTERUI.CIM.Interfaces.ValidateModule then
-- Temporarily add name for validation (modules don't store their own name)
local tempModule = { name = moduleName, Setup = moduleNamespace.Setup }
local valid, err = BETTERUI.CIM.Interfaces.ValidateModule(tempModule)
if not valid then
BETTERUI.Debug(string.format("[Validation] Module '%s' failed validation: %s", moduleName, tostring(err)))
return false
end
else
-- Fallback: basic Setup check
if type(moduleNamespace.Setup) ~= "function" then
BETTERUI.Debug(string.format("[Validation] Module '%s' has no Setup function", moduleName))
return false
end
end
-- Module is valid, call Setup
-- TODO(bug): Setup() is not wrapped in pcall -- if any module's Setup() throws, all subsequent modules in the init sequence silently fail to load; also return value is ignored by all callers
moduleNamespace.Setup()
moduleNamespace._setupComplete = true
return true
end
--- Loads and initializes all enabled modules.
---
--- Purpose: Orchestrates the loading of sub-modules when in Gamepad mode.
--- Mechanics: Calls RuntimeSetup.Apply() for API patches and settings migrations.
--- Validates modules using CIM.Interfaces before calling Setup.
--- Initializes research data and module-specific setups (Inventory, Banking, Writs, etc.).
--- References: Called on initialization and when switching to Gamepad mode.
---
function BETTERUI.LoadModules()
if BETTERUI._initialized then return end
BETTERUI.Debug("Initializing BETTERUI...")
-- Apply runtime safety patches and settings migrations
-- (Extracted to Modules/CIM/RuntimeSetup.lua for cleaner separation)
if BETTERUI.CIM and BETTERUI.CIM.RuntimeSetup and BETTERUI.CIM.RuntimeSetup.Apply then
BETTERUI.CIM.RuntimeSetup.Apply(BETTERUI.Settings)
end
-- Initialize research data once
BETTERUI.GetResearch()
local settings = BETTERUI.Settings.Modules
-- Initialize CIM-dependent modules with validation
if BETTERUI.GetModuleEnabled("CIM") then
if BETTERUI.GetModuleEnabled("Inventory") and BETTERUI.Inventory then
-- Pre-Setup hooks (must run before Setup)
if BETTERUI.Inventory.HookDestroyItem then BETTERUI.Inventory.HookDestroyItem() end
if BETTERUI.Inventory.HookActionDialog then BETTERUI.Inventory.HookActionDialog() end
-- Validated Setup
ValidateAndSetupModule("Inventory", BETTERUI.Inventory)
end
if BETTERUI.GetModuleEnabled("Banking") then
ValidateAndSetupModule("Banking", BETTERUI.Banking)
end
end
-- Initialize independent modules with validation
if BETTERUI.GetModuleEnabled("Writs") then
ValidateAndSetupModule("Writs", BETTERUI.Writs)
end
-- Initialize General Interface (Settings & Tooltips)
if BETTERUI.GetModuleEnabled("GeneralInterface") then
ValidateAndSetupModule("GeneralInterface", BETTERUI.GeneralInterface)
end
-- Nameplates (Dependent on General Interface)
if BETTERUI.GetModuleEnabled("GeneralInterface") and BETTERUI.GetModuleEnabled("Nameplates") then
ValidateAndSetupModule("Nameplates", BETTERUI.Nameplates)
end
-- Resource Orb Frames
if BETTERUI.GetModuleEnabled("ResourceOrbFrames") then
ValidateAndSetupModule("ResourceOrbFrames", BETTERUI.ResourceOrbFrames)
end
BETTERUI.Debug("Finished! BETTERUI is loaded")
BETTERUI._initialized = true
end
--- Main addon initialization handler.
---
--- Purpose: Responds to the EVENT_ADD_ON_LOADED event.
--- Mechanics: Loads saved variables, initializes settings, and sets up event listeners.
--- Decides whether to load modules immediately (if in Gamepad mode).
--- References: Registered to EVENT_ADD_ON_LOADED.
---
--- @param event number The event ID.
--- @param addon string The name of the addon being loaded.
function BETTERUI.Initialize(event, addon)
-- Only handle our own addon load event
if addon ~= BETTERUI.name then return end
-- Load saved variables
-- Changed version to 2.89 to prevent issues with prior saved variables
BETTERUI.SavedVars = ZO_SavedVars:New("BetterUISavedVars", 2.89, nil, BETTERUI.DefaultSettings)
BETTERUI.GlobalVars = ZO_SavedVars:NewAccountWide("BetterUISavedVars", 2.89, nil, BETTERUI.DefaultSettings)
-- Determine which settings to use
if BETTERUI.SavedVars.useAccountWide then
BETTERUI.Settings = BETTERUI.GlobalVars
else
BETTERUI.Settings = BETTERUI.SavedVars
end
-- Initialize or update module settings with defaults
-- This runs for EVERYONE to ensure new settings (like showStyleTrait) are merged into existing SavedVars
local modules = {
{ "CIM", BETTERUI.CIM },
{ "Inventory", BETTERUI.Inventory },
{ "Banking", BETTERUI.Banking },
{ "Writs", BETTERUI.Writs },
{ "GeneralInterface", BETTERUI.GeneralInterface },
{ "Nameplates", BETTERUI.Nameplates },
{ "ResourceOrbFrames", BETTERUI.ResourceOrbFrames }
}
for _, moduleInfo in ipairs(modules) do
local moduleName, moduleNamespace = moduleInfo[1], moduleInfo[2]
if moduleNamespace then
-- Ensure the settings table exists before initializing
if BETTERUI.Settings.Modules[moduleName] == nil then
BETTERUI.Settings.Modules[moduleName] = {}
end
local result = BETTERUI.ModuleOptions(moduleNamespace, BETTERUI.Settings.Modules[moduleName], moduleName)
if not result then
BETTERUI.Debug("[Warning] Skipping broken module: " .. moduleName)
end
end
end
-- Apply first-install defaults and mark as complete
if BETTERUI.Settings.firstInstall then
-- Apply module enable defaults from centralized registry
if BETTERUI.Defaults and BETTERUI.Defaults.ApplyFirstInstallDefaults then
BETTERUI.Defaults.ApplyFirstInstallDefaults(BETTERUI.Settings)
end
BETTERUI.Debug("First install detected - applied default module states")
BETTERUI.Settings.firstInstall = false
end
-- Note: Settings migrations (Tooltips->GeneralInterface, enabled->m_enabled)
-- are now handled in Modules/CIM/RuntimeSetup.lua via RuntimeSetup.Apply()
-- Unregister the initialization event
-- TODO(bug): Namespace mismatch - registered as BETTERUI.name ("BetterUI") at line 515 but unregistered as "BetterUIInitialize" here; unregister is a silent no-op, handler leaks for entire session
BETTERUI.EventManager:UnregisterForEvent("BetterUIInitialize", EVENT_ADD_ON_LOADED)
-- Initialize the options panel
BETTERUI.InitModuleOptions()
BETTERUI.UpdateCIMState()
-- Load modules if in gamepad mode
if IsInGamepadPreferredMode() then
BETTERUI.LoadModules()
else
BETTERUI._initialized = false
-- Keyboard mode: register ALL module settings panels so users on "Automatic"
-- input can always access addon configuration regardless of current UI mode.
-- NOTE: Only LAM settings panels are registered here. Gameplay hooks (inventory
-- destroy/action hooks, etc.) remain in LoadModules() and only activate
-- when gamepad mode is entered.
if BETTERUI.GetModuleEnabled("Inventory") and BETTERUI.Inventory then
ValidateAndSetupModule("Inventory", BETTERUI.Inventory)
end
if BETTERUI.GetModuleEnabled("Banking") and BETTERUI.Banking then
ValidateAndSetupModule("Banking", BETTERUI.Banking)
end
if BETTERUI.GetModuleEnabled("Writs") and BETTERUI.Writs then
ValidateAndSetupModule("Writs", BETTERUI.Writs)
end
if BETTERUI.GetModuleEnabled("GeneralInterface") and BETTERUI.GeneralInterface then
ValidateAndSetupModule("GeneralInterface", BETTERUI.GeneralInterface)
end
if BETTERUI.GetModuleEnabled("GeneralInterface") and BETTERUI.GetModuleEnabled("Nameplates") and BETTERUI.Nameplates then
ValidateAndSetupModule("Nameplates", BETTERUI.Nameplates)
end
if BETTERUI.GetModuleEnabled("ResourceOrbFrames") and BETTERUI.ResourceOrbFrames then
ValidateAndSetupModule("ResourceOrbFrames", BETTERUI.ResourceOrbFrames)
end
end
-- Ensure companion equip patch is queued even if modules didn't hook above
if BETTERUI.Inventory and BETTERUI.Inventory.EnsureCompanionEquipPatched then
BETTERUI.Inventory.EnsureCompanionEquipPatched()
end
end
-- Event handlers for initialization and gamepad mode changes
BETTERUI.EventManager:RegisterForEvent(BETTERUI.name, EVENT_ADD_ON_LOADED, function(...) BETTERUI.Initialize(...) end)
BETTERUI.EventManager:RegisterForEvent(BETTERUI.name .. "_Gamepad", EVENT_GAMEPAD_PREFERRED_MODE_CHANGED,
function(code, inGamepad)
if inGamepad then
-- Switching to gamepad: load all modules (idempotent via _initialized guard)
BETTERUI.LoadModules()
end
-- Switching to keyboard: ResourceOrbFrames handles its own mode-change event
-- inside SetupModule(). All other modules remain inactive in keyboard mode.
end)
-- Debug commands are now in Modules/CIM/Core/DeveloperDebug.lua
-- Enable debug mode via the DEBUG_LOGGING feature flag or set BETTERUI_DEBUG = true