diff --git a/lua/lib/ui.lua b/lua/lib/ui.lua index 879630c..9c61853 100644 --- a/lua/lib/ui.lua +++ b/lua/lib/ui.lua @@ -28,6 +28,7 @@ local ui = {} ---@field on_exit? UiHandler ---@field on_click? UiHandler ---@field paint? fun(id: NodeId, x: integer, y: integer, w: integer, h: integer) +---@field press_style? boolean False for a widget that paints its own press feedback. ---@class UiConfirmSpec ---@field title string @@ -49,6 +50,9 @@ local THEMES = { } local enterHandlers, exitHandlers, clickHandlers, painters = {}, {}, {}, {} +-- A widget that paints its own press feedback opts out, so pressing one key does not +-- repaint the whole node the way a pressed style would. +local pressStyles = {} local laidOut = false local themeName local activeScreen @@ -119,6 +123,7 @@ loadTheme(savedTheme and savedTheme:match("^%s*(.-)%s*$") or "light") local function clearState() enterHandlers, exitHandlers, clickHandlers, painters = {}, {}, {}, {} + pressStyles = {} end node.setPainter(function(id, x, y, w, h) @@ -164,6 +169,7 @@ local function build(spec, kind) exitHandlers[id] = spec.on_exit clickHandlers[id] = spec.on_click painters[id] = spec.paint + pressStyles[id] = spec.press_style ~= false return id end @@ -340,13 +346,13 @@ local function inside(id, x, y) end local function enter(id, x, y) - node.setPressed(id, true) + if pressStyles[id] then node.setPressed(id, true) end local handler = enterHandlers[id] if handler then handler(id, x, y) end end local function exit(id, x, y) - node.setPressed(id, false) + if pressStyles[id] then node.setPressed(id, false) end local handler = exitHandlers[id] if handler then handler(id, x, y) end end diff --git a/lua/test/ui.lua b/lua/test/ui.lua index 8b3717a..b493fd7 100644 --- a/lua/test/ui.lua +++ b/lua/test/ui.lua @@ -194,4 +194,24 @@ assert(columns == 3 and side == 93, "width is the binding constraint in portrait -- Five cards are two rows, so a reserve that eats the height budget shrinks the card. assert(select(1, ui.cardSide(5, 12, 8, 300)) == 74, "height binds once the reserve is large") +-- A widget painting its own feedback is never given a pressed style, while an ordinary one +-- still is. Which node was hit is geometry, so the test names the target directly. +ui.reset() +local pressedCalls = {} +node.setPressed = function(_, on) pressedCalls[#pressedCalls + 1] = on end +local own = ui.custom{h = 20, press_style = false, on_click = function() end} +local styled = ui.button{h = 20, label = "ok", on_click = function() end} +local board = ui.screen(ui.box{own, styled}) +local target +node.hit = function() return target end + +target = own +board:down(0, 0) +board:up(0, 0) +assert(#pressedCalls == 0, "a self-painting widget is not styled on press") + +target = styled +board:down(0, 0) +assert(pressedCalls[1] == true, "an ordinary widget still gets its pressed style") + print("ok")