Skip to content

Commit 72c4da9

Browse files
committed
Add UI-agnostic button abstraction and new Finalize API
Phase 1 of UI abstraction: Create ActionButton() and EditorButton() wrappers that work in both Chili and RmlUi modes without editors knowing which mode. New files: - ui_controls.lua: ActionButton() and EditorButton() functions - Detect mode via IsRmlUiMode() - Return Chili buttons OR RmlUi wrappers transparently - Editors use these instead of TabbedPanelButton/Button:New directly Editor changes: - Finalize() now accepts layout options: {actionButtons = {...}} - Old API still works: Finalize(children, opts) for compatibility - New API: Finalize({actionButtons = {btn1, btn2}}, opts) - Automatically builds ScrollPanel in Chili mode - Automatically generates button HTML in RmlUi mode New implementation methods: - _FinalizeRmlUiNew(layout, opts): RmlUi mode with new API - _FinalizeChiliNew(layout, opts): Chili mode with new API - _FinalizeChiliWindow(children, opts): Extracted for old API Updated editors: - heightmap_editor.lua: Now uses ActionButton() and new Finalize API Editors are now UI-agnostic - no "if RmlUi then" checks needed! Next: Update remaining 7 simple editors to use new API.
1 parent 695c7d0 commit 72c4da9

File tree

4 files changed

+179
-25
lines changed

4 files changed

+179
-25
lines changed

scen_edit/view/editor.lua

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ end
9797

9898
--- Called at the end of :init(), to finalize the UI
9999
--- Override.
100-
-- @tparam table children List of Chili controls.
100+
-- @tparam table layout Layout options (UI-agnostic) or old-style children array
101101
-- @tparam table opts Editor options
102102
-- @tparam[opt=false] boolean opts.notMainWindow If true,
103103
-- editor will not be added to the main panel (right side), but will instead be a floating window.
@@ -107,23 +107,51 @@ end
107107
-- Values include "ok", "cancel" and "close"
108108
-- @tparam boolean opts.disposeOnClose If true, the window will
109109
-- be disposed when closed. Defaults to true if opts.notMainWindow is true, otherwise it defaults to false.
110-
function Editor:Finalize(children, opts)
110+
function Editor:Finalize(layout, opts)
111111
if not self.__initializing then
112112
Log.Error("\"Editor.init(self)\" wasn't invoked properly.")
113113
Log.Error(debug.traceback())
114114
assert(self.__initializing, "\"Editor.init(self)\" wasn't invoked properly.")
115115
end
116116

117+
-- Support old API: if layout is an array, treat it as old-style children array
118+
local isOldAPI = layout and #layout > 0
119+
if isOldAPI then
120+
-- Old API compatibility: Finalize(children, opts)
121+
local children = layout
122+
opts = opts or {}
123+
124+
if SB.view and SB.view.useRmlUi then
125+
self:_FinalizeRmlUi(children, opts)
126+
self.__initializing = false
127+
return
128+
end
129+
130+
-- Continue with old Chili mode path
131+
self:_FinalizeButtons(children, opts)
132+
self:_FinalizeChiliWindow(children, opts)
133+
self.__initializing = false
134+
return
135+
end
136+
137+
-- New API: Finalize({actionButtons = {...}}, opts)
138+
layout = layout or {}
117139
opts = opts or {}
118140

119-
-- In RmlUi mode, generate RML from fields instead of creating Chili controls
141+
-- In RmlUi mode, generate RML from fields and buttons
120142
if SB.view and SB.view.useRmlUi then
121-
self:_FinalizeRmlUi(children, opts)
143+
self:_FinalizeRmlUiNew(layout, opts)
122144
self.__initializing = false
123145
return
124146
end
125147

126-
-- Chili mode continues below
148+
-- New Chili mode path
149+
self:_FinalizeChiliNew(layout, opts)
150+
self.__initializing = false
151+
end
152+
153+
-- Old Chili mode path (extracted for old API compatibility)
154+
function Editor:_FinalizeChiliWindow(children, opts)
127155
self:_FinalizeButtons(children, opts)
128156

129157
local OnShow = {function() self:__OnShow() end}
@@ -846,6 +874,79 @@ function Editor:_FinalizeRmlUi(children, opts)
846874
self.hidden = true
847875
end
848876

877+
-- New RmlUi finalization (new API with layout options)
878+
function Editor:_FinalizeRmlUiNew(layout, opts)
879+
self.actionButtons = layout.actionButtons or {}
880+
self.regularButtons = {}
881+
882+
-- Generate RML for action buttons (placed at top)
883+
local buttonsHtml = ''
884+
if #self.actionButtons > 0 then
885+
buttonsHtml = '<div class="action-buttons-panel">'
886+
for _, button in ipairs(self.actionButtons) do
887+
buttonsHtml = buttonsHtml .. button:GenerateRml()
888+
end
889+
buttonsHtml = buttonsHtml .. '</div>'
890+
end
891+
892+
-- Generate RML for all fields
893+
local fieldsHtml = ''
894+
for _, fieldName in ipairs(self.fieldOrder) do
895+
local field = self.fields[fieldName]
896+
if field and not field._isGroupChild then
897+
if field.GenerateRml then
898+
fieldsHtml = fieldsHtml .. field:GenerateRml()
899+
else
900+
-- Check if it's a control with a button inside
901+
if field.ctrl and field.ctrl.GenerateRml then
902+
fieldsHtml = fieldsHtml .. field.ctrl:GenerateRml()
903+
table.insert(self.regularButtons, field.ctrl)
904+
end
905+
end
906+
end
907+
end
908+
909+
-- Combine buttons and fields
910+
self.generatedRml = buttonsHtml .. fieldsHtml
911+
912+
-- Mark as hidden by default
913+
self.hidden = true
914+
end
915+
916+
-- New Chili finalization (new API with layout options)
917+
function Editor:_FinalizeChiliNew(layout, opts)
918+
local actionButtons = layout.actionButtons or {}
919+
local customControls = layout.customControls or {}
920+
921+
-- Build children array for Chili
922+
local children = {}
923+
924+
-- Add action buttons first
925+
for _, btn in ipairs(actionButtons) do
926+
table.insert(children, btn)
927+
end
928+
929+
-- Add custom controls if provided
930+
for _, ctrl in ipairs(customControls) do
931+
table.insert(children, ctrl)
932+
end
933+
934+
-- Add ScrollPanel with fields
935+
local yPos = #actionButtons > 0 and 70 or 0
936+
table.insert(children, ScrollPanel:New {
937+
x = 0,
938+
y = yPos,
939+
bottom = 30,
940+
right = 0,
941+
borderColor = {0,0,0,0},
942+
horizontalScrollbar = false,
943+
children = { self.stackPanel },
944+
})
945+
946+
-- Use the old Chili window creation
947+
self:_FinalizeChiliWindow(children, opts)
948+
end
949+
849950
-- Show the editor in RmlUi mode
850951
function Editor:ShowRmlUi()
851952
self.hidden = false

scen_edit/view/map/heightmap_editor.lua

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function HeightmapEditor:init()
3838
end
3939
}))
4040

41-
self.btnAddState = TabbedPanelButton({
41+
self.btnAddState = ActionButton({
4242
x = 0,
4343
y = 0,
4444
tooltip = "Left Click to add height, Right Click to remove height",
@@ -53,7 +53,7 @@ function HeightmapEditor:init()
5353
},
5454
})
5555

56-
self.btnSetState = TabbedPanelButton({
56+
self.btnSetState = ActionButton({
5757
x = 70,
5858
y = 0,
5959
tooltip = "Left Click to set height. Right click to sample height",
@@ -68,7 +68,7 @@ function HeightmapEditor:init()
6868
},
6969
})
7070

71-
self.btnSmoothState = TabbedPanelButton({
71+
self.btnSmoothState = ActionButton({
7272
x = 140,
7373
y = 0,
7474
tooltip = "Click to smooth terrain",
@@ -89,7 +89,7 @@ function HeightmapEditor:init()
8989
})
9090

9191
self:AddControl("btn-show-elevation", {
92-
Button:New {
92+
EditorButton {
9393
caption = "Show elevation",
9494
width = 200,
9595
height = 40,
@@ -139,22 +139,13 @@ function HeightmapEditor:init()
139139
self:Update("size")
140140
self:SetInvisibleFields("applyDir")
141141

142-
local children = {
143-
self.btnAddState,
144-
self.btnSetState,
145-
self.btnSmoothState,
146-
ScrollPanel:New {
147-
x = 0,
148-
y = 70,
149-
bottom = 30,
150-
right = 0,
151-
borderColor = {0,0,0,0},
152-
horizontalScrollbar = false,
153-
children = { self.stackPanel },
154-
},
155-
}
156-
157-
self:Finalize(children)
142+
self:Finalize({
143+
actionButtons = {
144+
self.btnAddState,
145+
self.btnSetState,
146+
self.btnSmoothState,
147+
}
148+
})
158149
end
159150

160151
function HeightmapEditor:OnLeaveState(state)

scen_edit/view/ui_controls.lua

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
-- UI-agnostic control wrappers for editors
2+
-- Editors should use these instead of Chili components directly
3+
-- These create Chili controls OR RmlUi wrappers depending on mode
4+
5+
-- Detect if RmlUi mode is active
6+
local function IsRmlUiMode()
7+
return SB.view and SB.view.useRmlUi
8+
end
9+
10+
-- ActionButton - replacement for TabbedPanelButton
11+
-- Used for editor action buttons like "Add", "Set", "Smooth", "Paint", etc.
12+
function ActionButton(opts)
13+
if IsRmlUiMode() then
14+
-- Extract caption and image from children (Chili pattern)
15+
local caption = ""
16+
local image = nil
17+
if opts.children then
18+
for _, child in ipairs(opts.children) do
19+
if child.caption then
20+
caption = child.caption
21+
elseif child.file then
22+
image = child.file
23+
end
24+
end
25+
end
26+
27+
return RmlUiTabbedPanelButton({
28+
x = opts.x,
29+
y = opts.y,
30+
tooltip = opts.tooltip or "",
31+
OnClick = opts.OnClick or {},
32+
caption = caption,
33+
image = image,
34+
})
35+
else
36+
-- Chili mode - use original TabbedPanelButton
37+
return TabbedPanelButton(opts)
38+
end
39+
end
40+
41+
-- EditorButton - replacement for Button:New in AddControl
42+
-- Used for regular buttons like "Show elevation", "Compile", etc.
43+
function EditorButton(opts)
44+
if IsRmlUiMode() then
45+
return RmlUiButton({
46+
caption = opts.caption or "Button",
47+
OnClick = opts.OnClick or {},
48+
width = opts.width,
49+
height = opts.height,
50+
tooltip = opts.tooltip,
51+
})
52+
else
53+
-- Chili mode - use original Button
54+
return Button:New(opts)
55+
end
56+
end
57+
58+
Log.Notice("UI controls abstraction layer loaded")

scen_edit/view/view.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function View:InitializeRmlUi()
5151
SB.Include(Path.Join(SB.DIRS.SRC, 'view/rmlui_component.lua')) -- Base class for components
5252
SB.Include(Path.Join(SB.DIRS.SRC, 'view/rmlui_fields.lua'))
5353
SB.Include(Path.Join(SB.DIRS.SRC, 'view/rmlui_field_compat.lua')) -- Makes StringField() etc work
54+
SB.Include(Path.Join(SB.DIRS.SRC, 'view/ui_controls.lua')) -- ActionButton(), EditorButton()
5455

5556
-- Load main UI template
5657
local rmlPath = Path.Join(SB.DIRS.SRC, 'view/rml/springboard_main.rml')
@@ -174,6 +175,9 @@ function View:SetupRmlUiEvents()
174175
end
175176

176177
function View:InitializeChili()
178+
-- Load UI controls abstraction (ActionButton, EditorButton)
179+
SB.Include(Path.Join(SB.DIRS.SRC, 'view/ui_controls.lua'))
180+
177181
self.tabbedWindow = TabbedWindow()
178182
self.bottomBar = BottomBar()
179183
self.teamSelector = TeamSelector()

0 commit comments

Comments
 (0)