Skip to content

Commit

Permalink
Vastly Improved Slider
Browse files Browse the repository at this point in the history
  • Loading branch information
realSquidCoder committed Feb 11, 2025
1 parent c725af3 commit 3752608
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 135 deletions.
35 changes: 24 additions & 11 deletions library/lua/gui/widgets/range_slider.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ RangeSlider.ATTRS{
get_right_idx_fn=DEFAULT_NIL,
on_left_change=DEFAULT_NIL,
on_right_change=DEFAULT_NIL,
is_single=DEFAULT_NIL
}

function RangeSlider:preinit(init_table)
Expand All @@ -43,7 +44,8 @@ function RangeSlider:init()
end

local function rangeslider_get_width_per_idx(self)
return math.max(5, (self.frame_body.width-7) // (self.num_stops-1))
local min_value = (self.is_single) and 3 or 5 -- Single slider = 3, else 5
return math.max(min_value, (self.frame_body.width-7) // (self.num_stops-1))
end

function RangeSlider:onInput(keys)
Expand Down Expand Up @@ -142,16 +144,27 @@ function RangeSlider:onRenderBody(dc, rect)
end
dc:char(nil, SLIDER_TRACK)
dc:char(nil, SLIDER_RIGHT_END)
-- draw tabs
dc:seek(width_per_idx*(left_idx-1))
dc:char(nil, SLIDER_TAB_LEFT)
dc:char(nil, SLIDER_TAB_CENTER)
dc:char(nil, SLIDER_TAB_RIGHT)
dc:seek(width_per_idx*(right_idx-1)+4)
dc:char(nil, SLIDER_TAB_LEFT)
dc:char(nil, SLIDER_TAB_CENTER)
dc:char(nil, SLIDER_TAB_RIGHT)
-- manage dragging

-- Draw tab(s)
if self.is_single then
-- Single slider: Draw one centered tab
dc:seek(width_per_idx * (left_idx-1) + 2) -- Center the tab
dc:char(nil, SLIDER_TAB_LEFT)
dc:char(nil, SLIDER_TAB_CENTER)
dc:char(nil, SLIDER_TAB_RIGHT)
else
-- Dual slider: Draw left and right tabs separately
dc:seek(width_per_idx * (left_idx-1))
dc:char(nil, SLIDER_TAB_LEFT)
dc:char(nil, SLIDER_TAB_CENTER)
dc:char(nil, SLIDER_TAB_RIGHT)
dc:seek(width_per_idx*(right_idx-1)+4)
dc:char(nil, SLIDER_TAB_LEFT)
dc:char(nil, SLIDER_TAB_CENTER)
dc:char(nil, SLIDER_TAB_RIGHT)
end

-- Manage dragging
if self.is_dragging_target then
rangeslider_do_drag(self, width_per_idx)
end
Expand Down
138 changes: 14 additions & 124 deletions library/lua/gui/widgets/slider.lua
Original file line number Diff line number Diff line change
@@ -1,131 +1,21 @@
local Widget = require('gui.widgets.widget')

local to_pen = dfhack.pen.parse

--------------------------------
-- Slider
--------------------------------

---@class widgets.Slider.attrs: widgets.Widget.attrs
---@field num_stops integer
---@field get_idx_fn? function
---@field on_change? fun(index: integer)

---@class widgets.Slider.attrs.partial: widgets.Slider.attrs

---@class widgets.Slider.initTable: widgets.Slider.attrs
---@field num_stops integer

---@class widgets.Slider: widgets.Widget, widgets.Slider.attrs
---@field super widgets.Widget
---@field ATTRS widgets.Slider.attrs|fun(attributes: widgets.Slider.attrs.partial)
---@overload fun(init_table: widgets.Slider.initTable): self
Slider = defclass(Slider, Widget)
Slider.ATTRS{
num_stops=DEFAULT_NIL,
get_idx_fn=DEFAULT_NIL,
on_change=DEFAULT_NIL,
-- slider.lua
local RangeSlider = require('gui.widgets.range_slider')

local Slider = defclass(Slider, RangeSlider)
Slider.ATTRS {
get_idx_fn = DEFAULT_NIL, -- Function to get the current index
on_change = DEFAULT_NIL, -- Function to handle index change
is_single = true
}

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

function Slider:init()
if self.num_stops < 2 then error('too few Slider stops') end
self.is_dragging_target = nil -- 'left', 'right', or 'both'
self.is_dragging_idx = nil -- offset from leftmost dragged tile
end

local function Slider_get_width_per_idx(self)
return math.max(3, (self.frame_body.width-7) // (self.num_stops-1))
end

function Slider:onInput(keys)
if not keys._MOUSE_L then return false end
local x = self:getMousePos()
if not x then return false end
local left_idx = self.get_idx_fn()
local width_per_idx = Slider_get_width_per_idx(self)
local left_pos = width_per_idx*(left_idx-1)
local right_pos = width_per_idx*(left_idx-1) + 4
if x < left_pos then
self.on_change(self.get_idx_fn() - 1)
else
self.is_dragging_target = 'both'
self.is_dragging_idx = x - right_pos
end
return true
end

local function Slider_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 = 1
local new_idx = math.max(0, cur_pos+offset)//width_per_idx + 1
if self.is_dragging_target == 'both' then
if new_idx > self.num_stops then
return
end
end
if new_idx and new_idx ~= self.get_idx_fn() then
self.on_change(new_idx)
end
end

local SLIDER_LEFT_END = to_pen{ch=198, fg=COLOR_GREY, bg=COLOR_BLACK}
local SLIDER_TRACK = to_pen{ch=205, fg=COLOR_GREY, bg=COLOR_BLACK}
local SLIDER_TRACK_SELECTED = to_pen{ch=205, fg=COLOR_LIGHTGREEN, bg=COLOR_BLACK}
local SLIDER_TRACK_STOP = to_pen{ch=216, fg=COLOR_GREY, bg=COLOR_BLACK}
local SLIDER_TRACK_STOP_SELECTED = to_pen{ch=216, fg=COLOR_LIGHTGREEN, bg=COLOR_BLACK}
local SLIDER_RIGHT_END = to_pen{ch=181, fg=COLOR_GREY, bg=COLOR_BLACK}
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 Slider:onRenderBody(dc, rect)
local left_idx = self.get_idx_fn()
local width_per_idx = Slider_get_width_per_idx(self)
-- draw track
dc:seek(1,0)
dc:char(nil, SLIDER_LEFT_END)
dc:char(nil, SLIDER_TRACK)
for stop_idx=1,self.num_stops-1 do
local track_stop_pen = SLIDER_TRACK_STOP_SELECTED
local track_pen = SLIDER_TRACK_SELECTED
if left_idx ~= stop_idx then
track_stop_pen = SLIDER_TRACK_STOP
track_pen = SLIDER_TRACK
elseif left_idx == stop_idx then
track_pen = SLIDER_TRACK
end
dc:char(nil, track_stop_pen)
for i=2,width_per_idx do
dc:char(nil, track_pen)
end
end
if left_idx >= self.num_stops then
dc:char(nil, SLIDER_TRACK_STOP_SELECTED)
else
dc:char(nil, SLIDER_TRACK_STOP)
end
dc:char(nil, SLIDER_TRACK)
dc:char(nil, SLIDER_RIGHT_END)
-- draw tab
dc:seek(width_per_idx*(left_idx-1)+2)
dc:char(nil, SLIDER_TAB_LEFT)
dc:char(nil, SLIDER_TAB_CENTER)
dc:char(nil, SLIDER_TAB_RIGHT)
-- manage dragging
if self.is_dragging_target then
Slider_do_drag(self, width_per_idx)
self.get_left_idx_fn = self.get_idx_fn
self.get_right_idx_fn = self.get_idx_fn
self.on_left_change = function(index)
if self.on_change then self.on_change(index) end
end
if df.global.enabler.mouse_lbut_down == 0 then
self.is_dragging_target = nil
self.is_dragging_idx = nil
self.on_right_change = function(index)
if self.on_change then self.on_change(index) end
end
end

Expand Down

0 comments on commit 3752608

Please sign in to comment.