From 645a5f5137f90ec1ab1bca756a262f55a5973e2e Mon Sep 17 00:00:00 2001 From: Mikayla Fischler Date: Sat, 23 Sep 2023 14:31:37 -0400 Subject: [PATCH] #344 added focus navigation to checkboxes and radio buttons, refactor of enable handlers --- graphics/element.lua | 16 +++---- graphics/elements/controls/checkbox.lua | 41 ++++++++++++++-- graphics/elements/controls/hazard_button.lua | 4 +- graphics/elements/controls/push_button.lua | 6 +-- graphics/elements/controls/radio_button.lua | 48 +++++++++++++++++-- .../elements/controls/spinbox_numeric.lua | 4 +- graphics/elements/form/number_field.lua | 6 +-- graphics/elements/form/text_field.lua | 6 +-- 8 files changed, 100 insertions(+), 31 deletions(-) diff --git a/graphics/element.lua b/graphics/element.lua index f356c03..80182a9 100644 --- a/graphics/element.lua +++ b/graphics/element.lua @@ -321,6 +321,12 @@ function element.new(args, child_offset_x, child_offset_y) ---@param id element_id element identifier function protected.on_removed(id) end + -- handle enabled + function protected.on_enabled() end + + -- handle disabled + function protected.on_disabled() end + -- handle this element having been focused function protected.on_focused() end @@ -369,12 +375,6 @@ function element.new(args, child_offset_x, child_offset_y) ---@param max integer maximum allowed value function protected.set_max(max) end - -- enable the control - function protected.enable() end - - -- disable the control - function protected.disable() end - -- custom recolor command, varies by element if implemented ---@vararg cpair|color color(s) function protected.recolor(...) end @@ -599,7 +599,7 @@ function element.new(args, child_offset_x, child_offset_y) function public.enable() if not protected.enabled then protected.enabled = true - protected.enable() + protected.on_enabled() end end @@ -607,7 +607,7 @@ function element.new(args, child_offset_x, child_offset_y) function public.disable() if protected.enabled then protected.enabled = false - protected.disable() + protected.on_disabled() public.unfocus_all() end end diff --git a/graphics/elements/controls/checkbox.lua b/graphics/elements/controls/checkbox.lua index 77f9808..1d9e1c7 100644 --- a/graphics/elements/controls/checkbox.lua +++ b/graphics/elements/controls/checkbox.lua @@ -22,6 +22,7 @@ local function checkbox(args) assert(type(args.box_fg_bg) == "table", "graphics.elements.controls.checkbox: box_fg_bg is a required field") assert(type(args.callback) == "function", "graphics.elements.controls.checkbox: callback is a required field") + args.can_focus = true args.height = 1 args.width = 3 + string.len(args.label) @@ -53,6 +54,21 @@ local function checkbox(args) end end + -- write label text + local function draw_label() + if e.enabled and e.is_focused() then + e.w_set_cur(3, 1) + e.w_set_fgd(e.fg_bg.bkg) + e.w_set_bkg(e.fg_bg.fgd) + e.w_write(args.label) + else + e.w_set_cur(3, 1) + e.w_set_fgd(e.fg_bg.fgd) + e.w_set_bkg(e.fg_bg.bkg) + e.w_write(args.label) + end + end + -- handle mouse interaction ---@param event mouse_interaction mouse event function e.handle_mouse(event) @@ -63,6 +79,18 @@ local function checkbox(args) end end + -- handle keyboard interaction + ---@param event key_interaction key event + function e.handle_key(event) + if event.type == core.events.KEY_CLICK.DOWN then + if event.key == keys.space or event.key == keys.enter or event.key == keys.numPadEnter then + e.value = not e.value + draw() + args.callback(e.value) + end + end + end + -- set the value ---@param val integer new value function e.set_value(val) @@ -70,14 +98,17 @@ local function checkbox(args) draw() end - -- write label text - e.w_set_cur(3, 1) - e.w_set_fgd(e.fg_bg.fgd) - e.w_set_bkg(e.fg_bg.bkg) - e.w_write(args.label) + -- handle focus + e.on_focused = draw_label + e.on_unfocused = draw_label + + -- handle enable + e.on_enabled = draw_label + e.on_disabled = draw_label -- initial draw draw() + draw_label() return e.complete() end diff --git a/graphics/elements/controls/hazard_button.lua b/graphics/elements/controls/hazard_button.lua index f6ac2d3..92e4ac5 100644 --- a/graphics/elements/controls/hazard_button.lua +++ b/graphics/elements/controls/hazard_button.lua @@ -178,7 +178,7 @@ local function hazard_button(args) end -- show the button as disabled - function e.disable() + function e.on_disabled() if args.dis_colors then draw_border(args.dis_colors.color_a) e.w_set_fgd(args.dis_colors.color_b) @@ -188,7 +188,7 @@ local function hazard_button(args) end -- show the button as enabled - function e.enable() + function e.on_enabled() draw_border(args.accent) e.w_set_fgd(args.fg_bg.fgd) e.w_set_cur(3, 2) diff --git a/graphics/elements/controls/push_button.lua b/graphics/elements/controls/push_button.lua index b8e3013..cab0977 100644 --- a/graphics/elements/controls/push_button.lua +++ b/graphics/elements/controls/push_button.lua @@ -112,7 +112,7 @@ local function push_button(args) end -- show butten as enabled - function e.enable() + function e.on_enabled() if args.dis_fg_bg ~= nil then e.value = false e.w_set_fgd(e.fg_bg.fgd) @@ -122,7 +122,7 @@ local function push_button(args) end -- show button as disabled - function e.disable() + function e.on_disabled() if args.dis_fg_bg ~= nil then e.value = false e.w_set_fgd(args.dis_fg_bg.fgd) @@ -131,7 +131,7 @@ local function push_button(args) end end - -- handle focus change + -- handle focus e.on_focused = show_pressed e.on_unfocused = show_unpressed diff --git a/graphics/elements/controls/radio_button.lua b/graphics/elements/controls/radio_button.lua index 33a65d5..26c699b 100644 --- a/graphics/elements/controls/radio_button.lua +++ b/graphics/elements/controls/radio_button.lua @@ -33,9 +33,6 @@ local function radio_button(args) assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0), "graphics.elements.controls.radio_button: min_width must be nil or a number > 0") - -- one line per option - args.height = #args.options - -- determine widths local max_width = 1 for i = 1, #args.options do @@ -47,11 +44,16 @@ local function radio_button(args) local button_text_width = math.max(max_width, args.min_width or 0) + -- set automatic args + args.can_focus = true args.width = button_text_width + 2 + args.height = #args.options -- one line per option -- create new graphics element base object local e = element.new(args) + local focused_opt = 1 + -- button state (convert nil to 1 if missing) e.value = args.default or 1 @@ -74,8 +76,14 @@ local function radio_button(args) e.w_write("\x95") -- write button text - e.w_set_fgd(e.fg_bg.fgd) - e.w_set_bkg(e.fg_bg.bkg) + if i == focused_opt and e.is_focused() and e.enabled then + e.w_set_fgd(e.fg_bg.bkg) + e.w_set_bkg(e.fg_bg.fgd) + else + e.w_set_fgd(e.fg_bg.fgd) + e.w_set_bkg(e.fg_bg.bkg) + end + e.w_write(opt) end end @@ -93,6 +101,28 @@ local function radio_button(args) end end + -- handle keyboard interaction + ---@param event key_interaction key event + function e.handle_key(event) + if event.type == core.events.KEY_CLICK.DOWN then + if event.key == keys.space or event.key == keys.enter or event.key == keys.numPadEnter then + e.value = focused_opt + draw() + args.callback(e.value) + elseif event.key == keys.down then + if focused_opt < #args.options then + focused_opt = focused_opt + 1 + draw() + end + elseif event.key == keys.up then + if focused_opt > 1 then + focused_opt = focused_opt - 1 + draw() + end + end + end + end + -- set the value ---@param val integer new value function e.set_value(val) @@ -100,6 +130,14 @@ local function radio_button(args) draw() end + -- handle focus + e.on_focused = draw + e.on_unfocused = draw + + -- handle enable + e.on_enabled = draw + e.on_disabled = draw + -- initial draw draw() diff --git a/graphics/elements/controls/spinbox_numeric.lua b/graphics/elements/controls/spinbox_numeric.lua index 76f6c06..f7d0ee5 100644 --- a/graphics/elements/controls/spinbox_numeric.lua +++ b/graphics/elements/controls/spinbox_numeric.lua @@ -176,12 +176,12 @@ local function spinbox(args) end -- enable this input - function e.enable() + function e.on_enabled() draw_arrows(args.arrow_fg_bg.fgd) end -- disable this input - function e.disable() + function e.on_disabled() draw_arrows(args.arrow_disable or colors.lightGray) end diff --git a/graphics/elements/form/number_field.lua b/graphics/elements/form/number_field.lua index ee75224..43554ce 100644 --- a/graphics/elements/form/number_field.lua +++ b/graphics/elements/form/number_field.lua @@ -158,9 +158,9 @@ local function number_field(args) ifield.show() end - -- on enable/disable - e.enable = ifield.show - e.disable = ifield.show + -- handle enable + e.on_enabled = ifield.show + e.on_disabled = ifield.show -- initial draw ifield.show() diff --git a/graphics/elements/form/text_field.lua b/graphics/elements/form/text_field.lua index 37a91d3..ebeb35a 100644 --- a/graphics/elements/form/text_field.lua +++ b/graphics/elements/form/text_field.lua @@ -85,9 +85,9 @@ local function text_field(args) e.on_focused = ifield.show e.on_unfocused = ifield.show - -- on enable/disable - e.enable = ifield.show - e.disable = ifield.show + -- handle enable + e.on_enabled = ifield.show + e.on_disabled = ifield.show -- initial draw ifield.show()