feat(map-editor): dropdown render for action/modal/toggle/separator
Renders the open dropdown for the active menu category with a three-column item layout (indicator | label | hotkey). Toggle items show their bound is_on() state with a [v]/[ ] indicator, modal items append "...", separators draw as thin rules, disabled items render in a muted colour. Submenu chevron is wired but submenus themselves land in a later slice. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
95
init.lua
95
init.lua
@@ -612,6 +612,92 @@ local ui = (function()
|
|||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function dropdown_width_for(items)
|
||||||
|
local w = DROPDOWN_MIN_W
|
||||||
|
for _, it in ipairs(items) do
|
||||||
|
if it.type ~= "separator" then
|
||||||
|
local label_w = engine.render.measure_text(it.label or "", 12)
|
||||||
|
local needed = DROPDOWN_INDICATOR_W + label_w + DROPDOWN_HOTKEY_W + 2 * DROPDOWN_PAD_X
|
||||||
|
if needed > w then w = needed end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return w
|
||||||
|
end
|
||||||
|
|
||||||
|
local function dropdown_layout(cat_layout)
|
||||||
|
local items = cat_layout.items
|
||||||
|
local w = dropdown_width_for(items)
|
||||||
|
local rows = {}
|
||||||
|
local y = cat_layout.y + cat_layout.h + DROPDOWN_PAD_Y
|
||||||
|
for i, it in ipairs(items) do
|
||||||
|
local row_h = (it.type == "separator") and 6 or DROPDOWN_ITEM_H
|
||||||
|
rows[i] = { item = it, x = cat_layout.x, y = y, w = w, h = row_h }
|
||||||
|
y = y + row_h
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
x = cat_layout.x,
|
||||||
|
y = cat_layout.y + cat_layout.h + DROPDOWN_PAD_Y,
|
||||||
|
w = w,
|
||||||
|
h = y - (cat_layout.y + cat_layout.h + DROPDOWN_PAD_Y) + DROPDOWN_PAD_Y,
|
||||||
|
rows = rows,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function item_is_disabled(item)
|
||||||
|
local d = item.disabled
|
||||||
|
if type(d) == "function" then return d() end
|
||||||
|
return d == true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_dropdown_item(row, hovered)
|
||||||
|
local it = row.item
|
||||||
|
if it.type == "separator" then
|
||||||
|
engine.render.draw_line(row.x + 6, row.y + 3,
|
||||||
|
row.x + row.w - 6, row.y + 3,
|
||||||
|
rgba(COL_TEXT_MUTED, 0x60))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local disabled = item_is_disabled(it)
|
||||||
|
if hovered and not disabled then
|
||||||
|
engine.render.draw_rect(row.x, row.y, row.w, row.h,
|
||||||
|
rgba(COL_ROW_HOVER, 0xFF))
|
||||||
|
end
|
||||||
|
local text_col = disabled and COL_TEXT_DISABLED or COL_TEXT
|
||||||
|
-- Left indicator gutter (toggle: [v] / [ ])
|
||||||
|
if it.type == "toggle" then
|
||||||
|
local on = it.is_on and it.is_on() or false
|
||||||
|
engine.render.draw_text(on and "[v]" or "[ ]",
|
||||||
|
row.x + 4, row.y + 5, 11,
|
||||||
|
rgba(on and COL_CHECK or COL_TEXT_MUTED, 0xFF))
|
||||||
|
end
|
||||||
|
-- Label
|
||||||
|
local label = it.label or ""
|
||||||
|
if it.type == "modal" then label = label .. "..." end
|
||||||
|
engine.render.draw_text(label,
|
||||||
|
row.x + DROPDOWN_INDICATOR_W + 2, row.y + 5, 12,
|
||||||
|
rgba(text_col, 0xFF))
|
||||||
|
-- Right column: hotkey or submenu chevron
|
||||||
|
if it.type == "submenu" then
|
||||||
|
engine.render.draw_text(">",
|
||||||
|
row.x + row.w - DROPDOWN_PAD_X - 6, row.y + 5, 12,
|
||||||
|
rgba(COL_TEXT_MUTED, 0xFF))
|
||||||
|
elseif it.hotkey then
|
||||||
|
engine.render.draw_text(it.hotkey,
|
||||||
|
row.x + row.w - DROPDOWN_HOTKEY_W, row.y + 5, 11,
|
||||||
|
rgba(COL_TEXT_MUTED, 0xFF))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_dropdown(cat_layout, mx, my)
|
||||||
|
local dd = dropdown_layout(cat_layout)
|
||||||
|
engine.render.draw_rect(dd.x, dd.y, dd.w, dd.h, rgba(COL_MODAL_BG, 0xFA))
|
||||||
|
engine.render.draw_rect_lines(dd.x, dd.y, dd.w, dd.h, rgba(COL_MODAL_BORDER, 0xFF))
|
||||||
|
for _, row in ipairs(dd.rows) do
|
||||||
|
local hovered = in_rect(mx, my, row.x, row.y, row.w, row.h)
|
||||||
|
draw_dropdown_item(row, hovered)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function draw_menu_bar(mx, my)
|
local function draw_menu_bar(mx, my)
|
||||||
local screen_w = engine.window.size()
|
local screen_w = engine.window.size()
|
||||||
engine.render.draw_rect(0, 0, screen_w, MENU_BAR_H, rgba(COL_TOOLBAR_BG, 0xFF))
|
engine.render.draw_rect(0, 0, screen_w, MENU_BAR_H, rgba(COL_TOOLBAR_BG, 0xFF))
|
||||||
@@ -884,6 +970,15 @@ local ui = (function()
|
|||||||
function M.draw()
|
function M.draw()
|
||||||
local mx, my = engine.input.get_mouse_pos()
|
local mx, my = engine.input.get_mouse_pos()
|
||||||
draw_menu_bar(mx, my)
|
draw_menu_bar(mx, my)
|
||||||
|
local open_name = state.get_menu_open()
|
||||||
|
if open_name then
|
||||||
|
for _, cat in ipairs(menu_bar_categories_layout()) do
|
||||||
|
if cat.name == open_name then
|
||||||
|
draw_dropdown(cat, mx, my)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
draw_top_toolbar(mx, my)
|
draw_top_toolbar(mx, my)
|
||||||
draw_mode_pill()
|
draw_mode_pill()
|
||||||
draw_side_panel(mx, my)
|
draw_side_panel(mx, my)
|
||||||
|
|||||||
Reference in New Issue
Block a user