dragging logic

develop
Myk Taylor 2022-12-12 18:07:05 -08:00
parent 945942a28b
commit 38a3bec953
No known key found for this signature in database
GPG Key ID: 8A39CA0FA0C16E78
1 changed files with 147 additions and 0 deletions

@ -3,6 +3,7 @@
local _ENV = mkmodule('gui.widgets')
local gui = require('gui')
local guidm = require('gui.dwarfmode')
local utils = require('utils')
local dscreen = dfhack.screen
@ -70,14 +71,156 @@ Panel.ATTRS {
frame_title = DEFAULT_NIL, -- as in gui.FramedScreen
on_render = DEFAULT_NIL,
on_layout = DEFAULT_NIL,
draggable = false,
drag_anchors = copyall({title=true, frame=false, body=false}),
drag_bound = 'frame', -- or 'body'
on_drag_begin = DEFAULT_NIL,
on_drag_end = DEFAULT_NIL,
autoarrange_subviews = false, -- whether to automatically lay out subviews
autoarrange_gap = 0, -- how many blank lines to insert between widgets
}
function Panel:init(args)
self.keyboard_drag = nil -- true when we are in keyboard dragging mode
self.saved_frame = nil -- copy of frame when dragging started
self.saved_frame_rect = nil -- copy of frame_rect when dragging started
self.drag_offset = nil -- relative pos of held panel tile
self:addviews(args.subviews)
end
local function Panel_update_frame(self, frame, clear_state)
if clear_state then
self.keyboard_drag = nil
self.saved_frame = nil
self.saved_frame_rect = nil
self.drag_offset = nil
end
if not frame then return end
if self.frame.l == frame.l and self.frame.r == frame.r
and self.frame.t == frame.t and self.frame.b == frame.b
and self.frame.w == frame.w and self.frame.h == frame.h then
return
end
self.frame = frame
self:updateLayout()
end
local function Panel_drag_frame(self, mouse_pos)
local frame = copyall(self.frame)
local parent_rect, frame_rect = self.frame_parent_rect, self.frame_rect
local bound_rect = self.drag_bound == 'body' and self.frame_body
or frame_rect
local offset = self.drag_offset
local max_width = parent_rect.width - (bound_rect.x2-frame_rect.x1+1)
local max_height = parent_rect.height - (bound_rect.y2-frame_rect.y1+1)
if frame.t or not frame.b then
local min_pos = frame_rect.y1 - bound_rect.y1
frame.t = math.max(min_pos,
math.min(max_height, mouse_pos.y - parent_rect.y1 - offset.y))
end
if frame.b or not frame.t then
local min_pos = bound_rect.y2 - frame_rect.y2
frame.b = math.max(min_pos,
math.min(max_height, parent_rect.y2 - mouse_pos.y - offset.y))
end
if frame.l or not frame.r then
local min_pos = frame_rect.x1 - bound_rect.x1
frame.l = math.max(min_pos,
math.min(max_width, mouse_pos.x - parent_rect.x1 - offset.x))
end
if frame.r or not frame.l then
local min_pos = bound_rect.x2 - frame_rect.x2
frame.r = math.max(min_pos,
math.min(max_width, parent_rect.x2 - mouse_pos.x - offset.x))
end
return frame
end
local function Panel_make_frame(self, mouse_pos)
mouse_pos = mouse_pos or xy2pos(dfhack.screen.getMousePos())
return Panel_drag_frame(self, mouse_pos)
end
local function Panel_begin_drag(self, drag_offset)
Panel_update_frame(self, nil, true)
self.drag_offset = drag_offset or {x=0, y=0}
self.saved_frame = copyall(self.frame)
self.saved_frame_rect = copyall(self.frame_rect)
self.prev_focus_owner = self.focus_group.cur
self:setFocus(true)
if self.on_drag_begin then self.on_drag_begin() end
end
local function Panel_end_drag(self, frame, success)
if self.prev_focus_owner then
self.prev_focus_owner:setFocus(true)
else
self:setFocus(false)
end
Panel_update_frame(self, frame, true)
if self.on_drag_end then self.on_drag_end(success) end
end
function Panel:onInput(keys)
if self.keyboard_drag then
if keys.SELECT or keys.LEAVESCREEN then
Panel_end_drag(self, nil, keys.SELECT)
return true
end
for code in pairs(keys) do
local dx, dy = guidm.get_movement_delta(code, 1, 10)
if dx then
local kbd_pos = {x=self.frame_rect.x1+dx,
y=self.frame_rect.y1+dy}
Panel_update_frame(self, Panel_make_frame(self, kbd_pos))
return true
end
end
return
end
if self.drag_offset then
if keys._MOUSE_R_DOWN then
Panel_end_drag(self, self.saved_frame)
elseif keys._MOUSE_L then
Panel_update_frame(self, Panel_make_frame(self))
end
return true
end
if self:inputToSubviews(keys) then
return true
end
if not keys._MOUSE_L_DOWN then return end
local rect = self.frame_rect
local x,y = self:getMousePos(gui.ViewRect{rect=rect})
if not x then return end
local is_dragging = false
if self.draggable then
local on_body = self:getMousePos()
is_dragging = (self.drag_anchors.title and self.frame_style and y == 0)
or (self.drag_anchors.frame and not on_body) -- includes inset
or (self.drag_anchors.body and on_body)
end
if is_dragging then
Panel_begin_drag(self, {x=x, y=y})
return true
end
end
function Panel:setCursorMoveEnabled(enabled)
if (enabled and self.keyboard_drag)
or (not enabled and not self.keyboard_drag) then
return
end
if enabled then
Panel_begin_drag(self)
else
Panel_end_drag(self)
end
self.keyboard_drag = enabled
end
function Panel:onRenderBody(dc)
if self.on_render then self.on_render(dc) end
end
@ -118,6 +261,10 @@ function Panel:onRenderFrame(dc, rect)
if not self.frame_style then return end
local x1,y1,x2,y2 = rect.x1, rect.y1, rect.x2, rect.y2
gui.paint_frame(x1, y1, x2, y2, self.frame_style, self.frame_title)
if self.drag_offset and not self.keyboard_drag
and df.global.enabler.mouse_lbut == 0 then
Panel_end_drag(self, nil, true)
end
end
-------------------