Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ Template for new versions:

## Lua
- 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
- ``widgets.Slider`` and ``widgets.RangeSlider``: fix sliders allowing values outside their number of stops (``num_stops``) when clicked or dragged with the mouse

## Removed

Expand Down
12 changes: 6 additions & 6 deletions library/lua/gui/widgets/range_slider.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local core = require('gui.widgets.slide_core')
local _SliderCore = require('gui.widgets.slide_core')

--------------------------------
-- RangeSlider
Expand All @@ -16,11 +16,11 @@ local core = require('gui.widgets.slide_core')
---@class widgets.RangeSlider.initTable: widgets.RangeSlider.attrs
---@field num_stops integer

---@class widgets.RangeSlider: widgets.Widget, widgets.RangeSlider.attrs
---@field super widgets.Widget
---@class widgets.RangeSlider: widgets._SliderCore, widgets.RangeSlider.attrs
---@field super widgets._SliderCore
---@field ATTRS widgets.RangeSlider.attrs|fun(attributes: widgets.RangeSlider.attrs.partial)
---@overload fun(init_table: widgets.RangeSlider.initTable): self
RangeSlider = defclass(RangeSlider, slide_core)
RangeSlider = defclass(RangeSlider, _SliderCore)
RangeSlider.ATTRS{
get_left_idx_fn=DEFAULT_NIL,
get_right_idx_fn=DEFAULT_NIL,
Expand All @@ -44,7 +44,7 @@ function RangeSlider:onInput(keys)
local left_pos = width_per_idx*(left_idx-1)
local right_pos = width_per_idx*(right_idx-1) + 4
if x < left_pos then
self.on_left_change(self.get_left_idx_fn() - 1)
self.on_left_change(self:clamp_idx(self.get_left_idx_fn() - 1))
elseif x < left_pos+3 then
self.is_dragging_target = 'left'
self.is_dragging_idx = x - left_pos
Expand All @@ -55,7 +55,7 @@ function RangeSlider:onInput(keys)
self.is_dragging_target = 'right'
self.is_dragging_idx = x - right_pos
else
self.on_right_change(self.get_right_idx_fn() + 1)
self.on_right_change(self:clamp_idx(self.get_right_idx_fn() + 1))
end
return true
end
Expand Down
33 changes: 19 additions & 14 deletions library/lua/gui/widgets/slide_core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,58 @@ local Widget = require('gui.widgets.widget')
local to_pen = dfhack.pen.parse

--------------------------------
-- slide_core
-- _SliderCore
--------------------------------

---@class widgets.slide_core.attrs: widgets.Widget.attrs
---@class widgets._SliderCore.attrs: widgets.Widget.attrs
---@field num_stops integer
---@field is_single boolean
---@field w integer

---@class widgets.slide_core.attrs.partial: widgets.slide_core.attrs
---@class widgets._SliderCore.attrs.partial: widgets._SliderCore.attrs

---@class widgets.slide_core.initTable: widgets.slide_core.attrs
---@class widgets._SliderCore.initTable: widgets._SliderCore.attrs
---@field num_stops integer

---@class widgets.slide_core: widgets.Widget, widgets.slide_core.attrs
---@class widgets._SliderCore: widgets.Widget, widgets._SliderCore.attrs
---@field super widgets.Widget
---@field ATTRS widgets.slide_core.attrs|fun(attributes: widgets.slide_core.attrs.partial)
---@overload fun(init_table: widgets.slide_core.initTable): self
slide_core = defclass(slide_core, Widget)
slide_core.ATTRS{
---@field ATTRS widgets._SliderCore.attrs|fun(attributes: widgets._SliderCore.attrs.partial)
---@overload fun(init_table: widgets._SliderCore.initTable): self
_SliderCore = defclass(_SliderCore, Widget)
_SliderCore.ATTRS{
num_stops=DEFAULT_NIL,
is_single=DEFAULT_NIL,
w=DEFAULT_NIL
}

function slide_core:preinit(init_table)
function _SliderCore:preinit(init_table)
init_table.frame = init_table.frame or {}
init_table.frame.h = init_table.frame.h or 1
end

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

function slide_core:get_min_stops()
function _SliderCore:get_min_stops()
return self.is_single and 1 or 2
end

function _SliderCore:clamp_idx(idx)
return math.max(1, math.min(self.num_stops, idx))
end

local function do_drag(self, width_per_idx)
local x = self.frame_body:localXY(dfhack.screen.getMousePos())
local cur_pos = x - self.is_dragging_idx
cur_pos = math.max(0, cur_pos)
cur_pos = math.min(width_per_idx*(self.num_stops-1)+7, cur_pos)
local offset = self.is_dragging_target == 'right' and -2 or 1
local new_idx = math.max(0, cur_pos+offset)//width_per_idx + 1
new_idx = self:clamp_idx(new_idx)
local new_left_idx, new_right_idx
if self.is_dragging_target == 'right' then
new_right_idx = new_idx
Expand Down Expand Up @@ -96,7 +101,7 @@ local SLIDER_TAB_LEFT = to_pen{ch=60, fg=COLOR_BLACK, bg=COLOR_YELLOW}
local SLIDER_TAB_CENTER = to_pen{ch=9, fg=COLOR_BLACK, bg=COLOR_YELLOW}
local SLIDER_TAB_RIGHT = to_pen{ch=62, fg=COLOR_BLACK, bg=COLOR_YELLOW}

function slide_core:onRenderBody(dc, rect)
function _SliderCore:onRenderBody(dc, rect)
local left_idx, right_idx
if self.get_idx_fn ~= nil then
left_idx = self.get_idx_fn()
Expand Down Expand Up @@ -160,4 +165,4 @@ function slide_core:onRenderBody(dc, rect)
end
end

return slide_core
return _SliderCore
12 changes: 6 additions & 6 deletions library/lua/gui/widgets/slider.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local core = require('gui.widgets.slide_core')
local _SliderCore = require('gui.widgets.slide_core')

--------------------------------
-- Slider
Expand All @@ -15,11 +15,11 @@ local core = require('gui.widgets.slide_core')
---@class widgets.Slider.initTable: widgets.Slider.attrs
---@field num_stops integer

---@class widgets.Slider: widgets.Widget, widgets.Slider.attrs
---@field super widgets.Widget
---@class widgets.Slider: widgets._SliderCore, widgets.Slider.attrs
---@field super widgets._SliderCore
---@field ATTRS widgets.Slider.attrs|fun(attributes: widgets.Slider.attrs.partial)
---@overload fun(init_table: widgets.Slider.initTable): self
Slider = defclass(Slider, slide_core)
Slider = defclass(Slider, _SliderCore)
Slider.ATTRS{
get_idx_fn=DEFAULT_NIL,
on_change=DEFAULT_NIL,
Expand All @@ -41,7 +41,7 @@ function Slider:onInput(keys)
local left_pos = width_per_idx*(left_idx-1)
local right_pos = width_per_idx*(right_idx-1) + 4
if x < left_pos then
self.on_change(self.get_idx_fn() - 1)
self.on_change(self:clamp_idx(self.get_idx_fn() - 1))
elseif x < left_pos+3 then
self.is_dragging_target = 'left'
self.is_dragging_idx = x - left_pos
Expand All @@ -52,7 +52,7 @@ function Slider:onInput(keys)
self.is_dragging_target = 'right'
self.is_dragging_idx = x - right_pos
else
self.on_change(self.get_idx_fn() + 1)
self.on_change(self:clamp_idx(self.get_idx_fn() + 1))
end
return true
end
Expand Down
Loading