Skip to content

Commit 6092a93

Browse files
authored
Merge pull request #5749 from Halavus/gui-slider-min-max
Fix sliders allowing values outside their number of stops
2 parents c2f513d + 082d707 commit 6092a93

4 files changed

Lines changed: 32 additions & 26 deletions

File tree

‎docs/changelog.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ Template for new versions:
133133

134134
## Lua
135135
- Added ``dfhack.maps.forEachTile`` to scan a cuboid of tiles with a declarative filter and apply actions (count, set tiletype or per-tiletype replacements, set designation/occupancy fields, spawn constructions, Lua callback) in a single native call
136+
- ``widgets.Slider`` and ``widgets.RangeSlider``: fix sliders allowing values outside their number of stops (``num_stops``) when clicked or dragged with the mouse
136137
- Fixed ``ipairs()`` on enum attribute tables (e.g. ``df.item_type.attrs``) never terminating (issue #1860)
137138
- Added ``dfhack.maps.getTileBlockCoord``, ``dfhack.maps.getBlockOrigin``, and ``dfhack.maps.getTileBlockOffset`` to convert between tile and block coordinates
138139

‎library/lua/gui/widgets/range_slider.lua‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
local core = require('gui.widgets.slide_core')
1+
local _SliderCore = require('gui.widgets.slide_core')
22

33
--------------------------------
44
-- RangeSlider
@@ -16,11 +16,11 @@ local core = require('gui.widgets.slide_core')
1616
---@class widgets.RangeSlider.initTable: widgets.RangeSlider.attrs
1717
---@field num_stops integer
1818

19-
---@class widgets.RangeSlider: widgets.Widget, widgets.RangeSlider.attrs
20-
---@field super widgets.Widget
19+
---@class widgets.RangeSlider: widgets._SliderCore, widgets.RangeSlider.attrs
20+
---@field super widgets._SliderCore
2121
---@field ATTRS widgets.RangeSlider.attrs|fun(attributes: widgets.RangeSlider.attrs.partial)
2222
---@overload fun(init_table: widgets.RangeSlider.initTable): self
23-
RangeSlider = defclass(RangeSlider, slide_core)
23+
RangeSlider = defclass(RangeSlider, _SliderCore)
2424
RangeSlider.ATTRS{
2525
get_left_idx_fn=DEFAULT_NIL,
2626
get_right_idx_fn=DEFAULT_NIL,
@@ -44,7 +44,7 @@ function RangeSlider:onInput(keys)
4444
local left_pos = width_per_idx*(left_idx-1)
4545
local right_pos = width_per_idx*(right_idx-1) + 4
4646
if x < left_pos then
47-
self.on_left_change(self.get_left_idx_fn() - 1)
47+
self.on_left_change(self:clamp_idx(self.get_left_idx_fn() - 1))
4848
elseif x < left_pos+3 then
4949
self.is_dragging_target = 'left'
5050
self.is_dragging_idx = x - left_pos
@@ -55,7 +55,7 @@ function RangeSlider:onInput(keys)
5555
self.is_dragging_target = 'right'
5656
self.is_dragging_idx = x - right_pos
5757
else
58-
self.on_right_change(self.get_right_idx_fn() + 1)
58+
self.on_right_change(self:clamp_idx(self.get_right_idx_fn() + 1))
5959
end
6060
return true
6161
end

‎library/lua/gui/widgets/slide_core.lua‎

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,58 @@ local Widget = require('gui.widgets.widget')
33
local to_pen = dfhack.pen.parse
44

55
--------------------------------
6-
-- slide_core
6+
-- _SliderCore
77
--------------------------------
88

9-
---@class widgets.slide_core.attrs: widgets.Widget.attrs
9+
---@class widgets._SliderCore.attrs: widgets.Widget.attrs
1010
---@field num_stops integer
1111
---@field is_single boolean
1212
---@field w integer
1313

14-
---@class widgets.slide_core.attrs.partial: widgets.slide_core.attrs
14+
---@class widgets._SliderCore.attrs.partial: widgets._SliderCore.attrs
1515

16-
---@class widgets.slide_core.initTable: widgets.slide_core.attrs
16+
---@class widgets._SliderCore.initTable: widgets._SliderCore.attrs
1717
---@field num_stops integer
1818

19-
---@class widgets.slide_core: widgets.Widget, widgets.slide_core.attrs
19+
---@class widgets._SliderCore: widgets.Widget, widgets._SliderCore.attrs
2020
---@field super widgets.Widget
21-
---@field ATTRS widgets.slide_core.attrs|fun(attributes: widgets.slide_core.attrs.partial)
22-
---@overload fun(init_table: widgets.slide_core.initTable): self
23-
slide_core = defclass(slide_core, Widget)
24-
slide_core.ATTRS{
21+
---@field ATTRS widgets._SliderCore.attrs|fun(attributes: widgets._SliderCore.attrs.partial)
22+
---@overload fun(init_table: widgets._SliderCore.initTable): self
23+
_SliderCore = defclass(_SliderCore, Widget)
24+
_SliderCore.ATTRS{
2525
num_stops=DEFAULT_NIL,
2626
is_single=DEFAULT_NIL,
2727
w=DEFAULT_NIL
2828
}
2929

30-
function slide_core:preinit(init_table)
30+
function _SliderCore:preinit(init_table)
3131
init_table.frame = init_table.frame or {}
3232
init_table.frame.h = init_table.frame.h or 1
3333
end
3434

35-
function slide_core:init()
35+
function _SliderCore:init()
3636
local min_stops = self:get_min_stops()
3737
if self.num_stops < min_stops then error(('too few stops, expected at least %s'):format(min_stops)) end
3838
self.is_dragging_target = nil -- 'left', 'right', or 'both'
3939
self.is_dragging_idx = nil -- offset from leftmost dragged tile
4040
end
4141

42-
function slide_core:get_min_stops()
42+
function _SliderCore:get_min_stops()
4343
return self.is_single and 1 or 2
4444
end
4545

46+
function _SliderCore:clamp_idx(idx)
47+
return math.max(1, math.min(self.num_stops, idx))
48+
end
49+
4650
local function do_drag(self, width_per_idx)
4751
local x = self.frame_body:localXY(dfhack.screen.getMousePos())
4852
local cur_pos = x - self.is_dragging_idx
4953
cur_pos = math.max(0, cur_pos)
5054
cur_pos = math.min(width_per_idx*(self.num_stops-1)+7, cur_pos)
5155
local offset = self.is_dragging_target == 'right' and -2 or 1
5256
local new_idx = math.max(0, cur_pos+offset)//width_per_idx + 1
57+
new_idx = self:clamp_idx(new_idx)
5358
local new_left_idx, new_right_idx
5459
if self.is_dragging_target == 'right' then
5560
new_right_idx = new_idx
@@ -96,7 +101,7 @@ local SLIDER_TAB_LEFT = to_pen{ch=60, fg=COLOR_BLACK, bg=COLOR_YELLOW}
96101
local SLIDER_TAB_CENTER = to_pen{ch=9, fg=COLOR_BLACK, bg=COLOR_YELLOW}
97102
local SLIDER_TAB_RIGHT = to_pen{ch=62, fg=COLOR_BLACK, bg=COLOR_YELLOW}
98103

99-
function slide_core:onRenderBody(dc, rect)
104+
function _SliderCore:onRenderBody(dc, rect)
100105
local left_idx, right_idx
101106
if self.get_idx_fn ~= nil then
102107
left_idx = self.get_idx_fn()
@@ -160,4 +165,4 @@ function slide_core:onRenderBody(dc, rect)
160165
end
161166
end
162167

163-
return slide_core
168+
return _SliderCore

‎library/lua/gui/widgets/slider.lua‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
local core = require('gui.widgets.slide_core')
1+
local _SliderCore = require('gui.widgets.slide_core')
22

33
--------------------------------
44
-- Slider
@@ -15,11 +15,11 @@ local core = require('gui.widgets.slide_core')
1515
---@class widgets.Slider.initTable: widgets.Slider.attrs
1616
---@field num_stops integer
1717

18-
---@class widgets.Slider: widgets.Widget, widgets.Slider.attrs
19-
---@field super widgets.Widget
18+
---@class widgets.Slider: widgets._SliderCore, widgets.Slider.attrs
19+
---@field super widgets._SliderCore
2020
---@field ATTRS widgets.Slider.attrs|fun(attributes: widgets.Slider.attrs.partial)
2121
---@overload fun(init_table: widgets.Slider.initTable): self
22-
Slider = defclass(Slider, slide_core)
22+
Slider = defclass(Slider, _SliderCore)
2323
Slider.ATTRS{
2424
get_idx_fn=DEFAULT_NIL,
2525
on_change=DEFAULT_NIL,
@@ -41,7 +41,7 @@ function Slider:onInput(keys)
4141
local left_pos = width_per_idx*(left_idx-1)
4242
local right_pos = width_per_idx*(right_idx-1) + 4
4343
if x < left_pos then
44-
self.on_change(self.get_idx_fn() - 1)
44+
self.on_change(self:clamp_idx(self.get_idx_fn() - 1))
4545
elseif x < left_pos+3 then
4646
self.is_dragging_target = 'left'
4747
self.is_dragging_idx = x - left_pos
@@ -52,7 +52,7 @@ function Slider:onInput(keys)
5252
self.is_dragging_target = 'right'
5353
self.is_dragging_idx = x - right_pos
5454
else
55-
self.on_change(self.get_idx_fn() + 1)
55+
self.on_change(self:clamp_idx(self.get_idx_fn() + 1))
5656
end
5757
return true
5858
end

0 commit comments

Comments
 (0)