From b758d7cd5e37a3cc03504dc7686500fdcd76757b Mon Sep 17 00:00:00 2001 From: David <97603719+Commodore64user@users.noreply.github.com> Date: Thu, 27 Feb 2025 19:10:43 +0000 Subject: [PATCH] [DoubleSpinWidget, SpinWidget] change values with page-turn buttons (#13208) --- frontend/ui/widget/doublespinwidget.lua | 80 +++++++++++++++++------ frontend/ui/widget/numberpickerwidget.lua | 28 ++++---- frontend/ui/widget/spinwidget.lua | 55 ++++++++++++---- 3 files changed, 119 insertions(+), 44 deletions(-) diff --git a/frontend/ui/widget/doublespinwidget.lua b/frontend/ui/widget/doublespinwidget.lua index 86b5a1d2e..e64ce05a6 100644 --- a/frontend/ui/widget/doublespinwidget.lua +++ b/frontend/ui/widget/doublespinwidget.lua @@ -68,6 +68,20 @@ function DoubleSpinWidget:init() end if Device:hasKeys() then self.key_events.Close = { { Device.input.group.Back } } + if Device:hasDPad() and Device:useDPadAsActionKeys() then + self.key_events.LeftWidgetValueUp = { { "LPgFwd" }, event = "DoubleSpinButtonPressed", args = { true, 1 } } + self.key_events.LeftWidgetValueDown = { { "LPgBack" }, event = "DoubleSpinButtonPressed", args = { true, -1 } } + self.key_events.RightWidgetValueUp = { { "RPgFwd" }, event = "DoubleSpinButtonPressed", args = { false, 1 } } + self.key_events.RightWidgetValueDown = { { "RPgBack" }, event = "DoubleSpinButtonPressed", args = { false, -1 } } + if Device:hasScreenKB() or Device:hasKeyboard() then + local modifier = Device:hasScreenKB() and "ScreenKB" or "Shift" + local HOLD = true -- use hold step value + self.key_events.LeftWidgetHoldValueUp = { { modifier, "LPgFwd" }, event = "DoubleSpinButtonPressed", args = { true, 1, HOLD } } + self.key_events.LeftWidgetHoldValueDown = { { modifier, "LPgBack" }, event = "DoubleSpinButtonPressed", args = { true, -1, HOLD } } + self.key_events.RightWidgetHoldValueUp = { { modifier, "RPgFwd" }, event = "DoubleSpinButtonPressed", args = { false, 1, HOLD } } + self.key_events.RightWidgetHoldValueDown = { { modifier, "RPgBack" }, event = "DoubleSpinButtonPressed", args = { false, -1, HOLD } } + end + end end if Device:isTouchDevice() then self.ges_events.TapClose = { @@ -88,13 +102,22 @@ function DoubleSpinWidget:init() -- Actually the widget layout self:update() + + -- Move focus to OK button on devices which have key_events, saves time for users + if Device:hasDPad() and Device:useDPadAsActionKeys() and not Device:isTouchDevice() then + -- Since button table is the last row in our layout, and OK is the last button + -- We need to set focus to both last row, and last column + local last_row = #self.layout + local last_col = #self.layout[last_row] + self:moveFocusTo(last_col, last_row) + end end function DoubleSpinWidget:update(numberpicker_left_value, numberpicker_right_value) local prev_movable_offset = self.movable and self.movable:getMovedOffset() local prev_movable_alpha = self.movable and self.movable.alpha self.layout = {} - local left_widget = NumberPickerWidget:new{ + self.left_widget = NumberPickerWidget:new{ show_parent = self, value = numberpicker_left_value or self.left_value, value_min = self.left_min, @@ -105,8 +128,8 @@ function DoubleSpinWidget:update(numberpicker_left_value, numberpicker_right_val wrap = self.left_wrap, unit = self.unit, } - self:mergeLayoutInHorizontal(left_widget) - local right_widget = NumberPickerWidget:new{ + self:mergeLayoutInHorizontal(self.left_widget) + self.right_widget = NumberPickerWidget:new{ show_parent = self, value = numberpicker_right_value or self.right_value, value_min = self.right_min, @@ -117,12 +140,12 @@ function DoubleSpinWidget:update(numberpicker_left_value, numberpicker_right_val wrap = self.right_wrap, unit = self.unit, } - self:mergeLayoutInHorizontal(right_widget) - left_widget.picker_updated_callback = function(value) - self:update(value, right_widget:getValue()) + self:mergeLayoutInHorizontal(self.right_widget) + self.left_widget.picker_updated_callback = function(value) + self:update(value, self.right_widget:getValue()) end - right_widget.picker_updated_callback = function(value) - self:update(left_widget:getValue(), value) + self.right_widget.picker_updated_callback = function(value) + self:update(self.left_widget:getValue(), value) end local separator_widget = TextWidget:new{ text = self.is_range and "–" or "", @@ -133,7 +156,7 @@ function DoubleSpinWidget:update(numberpicker_left_value, numberpicker_right_val local text_max_width = math.floor(0.95 * self.width / 2) local left_vertical_group = VerticalGroup:new{ align = "center", - left_widget, + self.left_widget, } local separator_vertical_group = VerticalGroup:new{ align = "center", @@ -141,7 +164,7 @@ function DoubleSpinWidget:update(numberpicker_left_value, numberpicker_right_val } local right_vertical_group = VerticalGroup:new{ align = "center", - right_widget, + self.right_widget, } if self.left_text ~= "" or self.right_text ~= "" then @@ -211,10 +234,10 @@ function DoubleSpinWidget:update(numberpicker_left_value, numberpicker_right_val self.right_precision and string.format(self.right_precision, self.right_default) or self.right_default, unit, separator), callback = function() - left_widget.value = self.left_default - right_widget.value = self.right_default - left_widget:update() - right_widget:update() + self.left_widget.value = self.left_default + self.right_widget.value = self.right_default + self.left_widget:update() + self.right_widget:update() end, } }) @@ -225,7 +248,7 @@ function DoubleSpinWidget:update(numberpicker_left_value, numberpicker_right_val text = self.extra_text, callback = function() if self.extra_callback then - self.extra_callback(left_widget:getValue(), right_widget:getValue()) + self.extra_callback(self.left_widget:getValue(), self.right_widget:getValue()) end if not self.keep_shown_on_apply then -- assume extra wants it same as ok self:onClose() @@ -246,11 +269,11 @@ function DoubleSpinWidget:update(numberpicker_left_value, numberpicker_right_val }, { text = self.ok_text, - enabled = self.ok_always_enabled or self.left_value ~= left_widget:getValue() - or self.right_value ~= right_widget:getValue(), + enabled = self.ok_always_enabled or self.left_value ~= self.left_widget:getValue() + or self.right_value ~= self.right_widget:getValue(), callback = function() - self.left_value = left_widget:getValue() - self.right_value = right_widget:getValue() + self.left_value = self.left_widget:getValue() + self.right_value = self.right_widget:getValue() if self.callback then self.callback(self.left_value, self.right_value) end @@ -350,4 +373,23 @@ function DoubleSpinWidget:onClose() return true end +--[[ +This method processes value changes based on the direction of the spin, applying the appropriate +step value to either the left or right widget component. + +@param args {table} A table containing: + - is_left_widget {boolean}. True for self.left_widget or False for self.right_widget + - direction {int}. The direction of change (1 for increase, -1 for decrease) + - is_hold_event {boolean}. True if the event is a hold event, false otherwise +@return {boolean} Returns true to indicate the event was handled +]] +function DoubleSpinWidget:onDoubleSpinButtonPressed(args) + local is_left_widget, direction, is_hold_event = unpack(args) + local target_widget = is_left_widget and self.left_widget or self.right_widget + local step = is_hold_event and target_widget.value_hold_step or target_widget.value_step + target_widget.value = target_widget:changeValue(step * direction) + target_widget:update() + return true +end + return DoubleSpinWidget diff --git a/frontend/ui/widget/numberpickerwidget.lua b/frontend/ui/widget/numberpickerwidget.lua index c4f55f360..1f23436df 100644 --- a/frontend/ui/widget/numberpickerwidget.lua +++ b/frontend/ui/widget/numberpickerwidget.lua @@ -78,14 +78,14 @@ function NumberPickerWidget:init() if self.date_month and self.date_year then self.value_max = self:getDaysInMonth(self.date_month:getValue(), self.date_year:getValue()) end - self.value = self:changeValue(self.value, self.value_step, self.value_max, self.value_min, self.wrap) + self.value = self:changeValue(self.value_step) self:update() end, hold_callback = function() if self.date_month and self.date_year then self.value_max = self:getDaysInMonth(self.date_month:getValue(), self.date_year:getValue()) end - self.value = self:changeValue(self.value, self.value_hold_step, self.value_max, self.value_min, self.wrap) + self.value = self:changeValue(self.value_hold_step) self:update() end } @@ -102,14 +102,14 @@ function NumberPickerWidget:init() if self.date_month and self.date_year then self.value_max = self:getDaysInMonth(self.date_month:getValue(), self.date_year:getValue()) end - self.value = self:changeValue(self.value, self.value_step * -1, self.value_max, self.value_min, self.wrap) + self.value = self:changeValue(-self.value_step) self:update() end, hold_callback = function() if self.date_month and self.date_year then self.value_max = self:getDaysInMonth(self.date_month:getValue(), self.date_year:getValue()) end - self.value = self:changeValue(self.value, self.value_hold_step * -1, self.value_max, self.value_min, self.wrap) + self.value = self:changeValue(-self.value_hold_step) self:update() end } @@ -295,22 +295,22 @@ end --[[-- Change value. --]] -function NumberPickerWidget:changeValue(value, step, max, min, wrap) +function NumberPickerWidget:changeValue(step) + local value if self.value_index then self.value_index = self.value_index + step if self.value_index > #self.value_table then - self.value_index = wrap and 1 or #self.value_table - elseif - self.value_index < 1 then - self.value_index = wrap and #self.value_table or 1 + self.value_index = self.wrap and 1 or #self.value_table + elseif self.value_index < 1 then + self.value_index = self.wrap and #self.value_table or 1 end value = self.value_table[self.value_index] else - value = value + step - if value > max then - value = wrap and min or max - elseif value < min then - value = wrap and max or min + value = self.value + step + if value > self.value_max then + value = self.wrap and self.value_min or self.value_max + elseif value < self.value_min then + value = self.wrap and self.value_max or self.value_min end end return value diff --git a/frontend/ui/widget/spinwidget.lua b/frontend/ui/widget/spinwidget.lua index 540dac5dd..732931055 100644 --- a/frontend/ui/widget/spinwidget.lua +++ b/frontend/ui/widget/spinwidget.lua @@ -66,6 +66,14 @@ function SpinWidget:init() end if Device:hasKeys() then self.key_events.Close = { { Device.input.group.Back } } + self.key_events.WidgetValueUp = { { Device.input.group.PgFwd }, event = "SpinButtonPressed", args = { 1, false } } + self.key_events.WidgetValueDown = { { Device.input.group.PgBack }, event = "SpinButtonPressed", args = { -1, false } } + if Device:hasScreenKB() or Device:hasKeyboard() then + local modifier = Device:hasScreenKB() and "ScreenKB" or "Shift" + local HOLD = true -- use hold step value + self.key_events.WidgetHoldValueUp = { { modifier, Device.input.group.PgFwd }, event = "SpinButtonPressed", args = { 1, HOLD } } + self.key_events.WidgetHoldValueDown = { { modifier, Device.input.group.LPgBack }, event = "SpinButtonPressed", args = { -1, HOLD } } + end end if Device:isTouchDevice() then self.ges_events.TapClose = { @@ -84,13 +92,22 @@ function SpinWidget:init() end -- Actually the widget layout self:update() + + -- Move focus to OK button on NT devices with key_events, saves time for users + if Device:hasDPad() and Device:useDPadAsActionKeys() and not Device:isTouchDevice() then + -- Since button table is the last row in our layout, and OK is the last button + -- We need to set focus to both last row, and last column + local last_row = #self.layout + local last_col = #self.layout[last_row] + self:moveFocusTo(last_col, last_row) + end end function SpinWidget:update(numberpicker_value, numberpicker_value_index) local prev_movable_offset = self.movable and self.movable:getMovedOffset() local prev_movable_alpha = self.movable and self.movable.alpha self.layout = {} - local value_widget = NumberPickerWidget:new{ + self.value_widget = NumberPickerWidget:new{ show_parent = self, value = numberpicker_value or self.value, value_table = self.value_table, @@ -106,10 +123,10 @@ function SpinWidget:update(numberpicker_value, numberpicker_value_index) end, unit = self.unit, } - self:mergeLayoutInVertical(value_widget) + self:mergeLayoutInVertical(self.value_widget) local value_group = HorizontalGroup:new{ align = "center", - value_widget, + self.value_widget, } local title_bar = TitleBar:new{ @@ -149,12 +166,12 @@ function SpinWidget:update(numberpicker_value, numberpicker_value_index) { text = T(_("Default value: %1%2"), value, unit), callback = function() - if value_widget.value_table then - value_widget.value_index = self.default_value + if self.value_widget.value_table then + self.value_widget.value_index = self.default_value else - value_widget.value = self.default_value + self.value_widget.value = self.default_value end - value_widget:update() + self.value_widget:update() end, }, }) @@ -164,7 +181,7 @@ function SpinWidget:update(numberpicker_value, numberpicker_value_index) text = self.extra_text, callback = function() if self.extra_callback then - self.value, self.value_index = value_widget:getValue() + self.value, self.value_index = self.value_widget:getValue() self.extra_callback(self) end if not self.keep_shown_on_apply then -- assume extra wants it same as ok @@ -176,7 +193,7 @@ function SpinWidget:update(numberpicker_value, numberpicker_value_index) text = self.option_text, callback = function() if self.option_callback then - self.value, self.value_index = value_widget:getValue() + self.value, self.value_index = self.value_widget:getValue() self.option_callback(self) end if not self.keep_shown_on_apply then -- assume option wants it same as ok @@ -203,9 +220,9 @@ function SpinWidget:update(numberpicker_value, numberpicker_value_index) }, { text = self.ok_text, - enabled = self.ok_always_enabled or self.original_value ~= value_widget:getValue(), + enabled = self.ok_always_enabled or self.original_value ~= self.value_widget:getValue(), callback = function() - self.value, self.value_index = value_widget:getValue() + self.value, self.value_index = self.value_widget:getValue() self.original_value = self.value if self.callback then self.callback(self) @@ -338,4 +355,20 @@ function SpinWidget:onClose() return true end +--[[ +This method updates the widget's value based on the direction of the spin. + +@param args {table} A table containing: + - direction {number}. The direction of the spin (-1 for decrease, 1 for increase) + - is_hold_event {boolean}. True if the event is a hold event, false otherwise +@return boolean Always returns true to indicate the event was handled +]] +function SpinWidget:onSpinButtonPressed(args) + local direction, is_hold_event = unpack(args) + local step = is_hold_event and self.value_hold_step or self.value_step + self.value_widget.value = self.value_widget:changeValue(step * direction) + self.value_widget:update() + return true +end + return SpinWidget