diff --git a/init.lua b/init.lua index 3162c69..67e8ca7 100644 --- a/init.lua +++ b/init.lua @@ -612,6 +612,92 @@ local ui = (function() return out 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 screen_w = engine.window.size() 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() local mx, my = engine.input.get_mouse_pos() 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_mode_pill() draw_side_panel(mx, my)