summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-08-22 22:28:52 +0400
committerAlexander Gavrilov2012-08-22 22:29:01 +0400
commitcf4b8a01966cc680b6f7c74db5f6bad30adc3e64 (patch)
treefbc8d0af3cffbaf5fb845aeee3c1d74796a937af /library
parent92c0b555dcf5656bf4e01c1d602e868dd62c3c03 (diff)
downloaddfhack-cf4b8a01966cc680b6f7c74db5f6bad30adc3e64.tar.gz
dfhack-cf4b8a01966cc680b6f7c74db5f6bad30adc3e64.tar.bz2
dfhack-cf4b8a01966cc680b6f7c74db5f6bad30adc3e64.tar.xz
Improve viewport manipulation utilities and support scroll in mechanisms.
I.e. allow the user to scroll around with cursor keys, provided that keeps the cursor still visible.
Diffstat (limited to 'library')
-rw-r--r--library/lua/gui.lua19
-rw-r--r--library/lua/gui/dwarfmode.lua207
2 files changed, 166 insertions, 60 deletions
diff --git a/library/lua/gui.lua b/library/lua/gui.lua
index abe1047c..f9a45548 100644
--- a/library/lua/gui.lua
+++ b/library/lua/gui.lua
@@ -245,6 +245,16 @@ end
function Screen:onShown()
end
+function Screen:dismiss()
+ if self._native and not dscreen.isDismissed(self) then
+ dscreen.dismiss(self)
+ self:onDismissed()
+ end
+end
+
+function Screen:onDismissed()
+end
+
------------------------
-- Framed screen object --
------------------------
@@ -311,8 +321,7 @@ local function hint_coord(gap,hint)
end
end
-function FramedScreen:updateLayout()
- local sw, sh = dscreen.getWindowSize()
+function FramedScreen:updateFrameSize(sw,sh)
local iw, ih = sw-2, sh-2
local width = math.min(self.frame_width or iw, iw)
local height = math.min(self.frame_height or ih, ih)
@@ -322,9 +331,11 @@ function FramedScreen:updateLayout()
self.frame_opaque = (gw == 0 and gh == 0)
end
-function FramedScreen:onRender()
- self:updateLayout()
+function FramedScreen:onResize(w,h)
+ self:updateFrameSize(w,h)
+end
+function FramedScreen:onRender()
local rect = self.frame_rect
local x1,y1,x2,y2 = rect.x1-1, rect.y1-1, rect.x2+1, rect.y2+1
diff --git a/library/lua/gui/dwarfmode.lua b/library/lua/gui/dwarfmode.lua
index 2d19b2f0..dde5225a 100644
--- a/library/lua/gui/dwarfmode.lua
+++ b/library/lua/gui/dwarfmode.lua
@@ -4,6 +4,7 @@ local _ENV = mkmodule('gui.dwarfmode')
local gui = require('gui')
local dscreen = dfhack.screen
+local world_map = df.global.world.map
AREA_MAP_WIDTH = 23
MENU_WIDTH = 30
@@ -40,71 +41,135 @@ function getPanelLayout()
end
function getCursorPos()
- return copyall(df.global.cursor)
+ if df.global.cursor.x ~= -30000 then
+ return copyall(df.global.cursor)
+ end
end
function setCursorPos(cursor)
df.global.cursor = cursor
end
-function getViewportPos()
- return {
- x = df.global.window_x,
- y = df.global.window_y,
- z = df.global.window_z
- }
+function clearCursorPos()
+ df.global.cursor = xyz2pos(nil)
+end
+
+Viewport = defclass(Viewport)
+
+function Viewport.make(map,x,y,z)
+ local self = gui.mkdims_wh(x,y,map.width,map.height)
+ self.z = z
+ return mkinstance(Viewport, self)
+end
+
+function Viewport.get(layout)
+ return Viewport.make(
+ (layout or getPanelLayout()).map,
+ df.global.window_x,
+ df.global.window_y,
+ df.global.window_z
+ )
end
-function clipViewport(view, layout)
- local map = df.global.world.map
- layout = layout or getPanelLayout()
- return {
- x = math.max(0, math.min(view.x, map.x_count-layout.map.width)),
- y = math.max(0, math.min(view.y, map.y_count-layout.map.height)),
- z = math.max(0, math.min(view.z, map.z_count-1))
- }
+function Viewport:resize(layout)
+ return Viewport.make(
+ (layout or getPanelLayout()).map,
+ self.x1, self.y1, self.z
+ )
end
-function setViewportPos(view, layout)
- local map = df.global.world.map
- layout = layout or getPanelLayout()
- local vp = clipViewport(view, layout)
- df.global.window_x = vp.x
- df.global.window_y = vp.y
+function Viewport:set()
+ local vp = self:clip()
+ df.global.window_x = vp.x1
+ df.global.window_y = vp.y1
df.global.window_z = vp.z
return vp
end
-function centerViewportOn(target, layout)
- layout = layout or getPanelLayout()
- local view = xyz2pos(
- target.x-math.floor(layout.map.width/2),
- target.y-math.floor(layout.map.height/2),
- target.z
+function Viewport:clip(x,y,z)
+ return self:make(
+ math.max(0, math.min(x or self.x1, world_map.x_count-self.width)),
+ math.max(0, math.min(y or self.y1, world_map.y_count-self.height)),
+ math.max(0, math.min(z or self.z, world_map.z_count-1))
)
- return setViewportPos(view, layout)
end
-function isInViewport(layout,view,target,gap)
+function Viewport:isVisibleXY(target,gap)
gap = gap or 0
- local map = df.global.world.map
- return math.max(target.x-gap,0) >= view.x
- and math.min(target.x+gap,map.x_count-1) < view.x+layout.map.width
- and math.max(target.y-gap,0) >= view.y
- and math.min(target.y+gap,map.y_count-1) < view.y+layout.map.height
- and target.z == view.z
+ return math.max(target.x-gap,0) >= self.x1
+ and math.min(target.x+gap,world_map.x_count-1) <= self.x2
+ and math.max(target.y-gap,0) >= self.y1
+ and math.min(target.y+gap,world_map.y_count-1) <= self.y2
end
-function revealInViewport(target,gap,view,layout)
- layout = layout or getPanelLayout()
+function Viewport:isVisible(target,gap)
+ gap = gap or 0
- if not isInViewport(layout, getViewportPos(), target, gap) then
- if view and isInViewport(layout, view, target, gap) then
- return setViewportPos(view, layout)
- else
- return centerViewportOn(target, layout)
- end
+ return self:isVisibleXY(target,gap) and target.z == self.z
+end
+
+function Viewport:centerOn(target)
+ return self:clip(
+ target.x - math.floor(self.width/2),
+ target.y - math.floor(self.height/2),
+ target.z
+ )
+end
+
+function Viewport:scrollTo(target,gap)
+ gap = math.max(0, gap or 5)
+ if gap*2 >= math.min(self.width, self.height) then
+ gap = math.floor(math.min(self.width, self.height)/2)
+ end
+ local x = math.min(self.x1, target.x-gap)
+ x = math.max(x, target.x+gap+1-self.width)
+ local y = math.min(self.y1, target.y-gap)
+ y = math.max(y, target.y+gap+1-self.height)
+ return self:clip(x, y, target.z)
+end
+
+function Viewport:reveal(target,gap,max_scroll,scroll_gap,scroll_z)
+ gap = math.max(0, gap or 5)
+ if self:isVisible(target, gap) then
+ return self
+ end
+
+ max_scroll = math.max(0, max_scroll or 5)
+ if self:isVisibleXY(target, -max_scroll)
+ and (scroll_z or target.z == self.z) then
+ return self:scrollTo(target, scroll_gap or gap)
+ else
+ return self:centerOn(target)
+ end
+end
+
+MOVEMENT_KEYS = {
+ CURSOR_UP = { 0, -1, 0 }, CURSOR_DOWN = { 0, 1, 0 },
+ CURSOR_LEFT = { -1, 0, 0 }, CURSOR_RIGHT = { 1, 0, 0 },
+ CURSOR_UPLEFT = { -1, -1, 0 }, CURSOR_UPRIGHT = { 1, -1, 0 },
+ CURSOR_DOWNLEFT = { -1, 1, 0 }, CURSOR_DOWNRIGHT = { 1, 1, 0 },
+ CURSOR_UP_FAST = { 0, -1, 0, true }, CURSOR_DOWN_FAST = { 0, 1, 0, true },
+ CURSOR_LEFT_FAST = { -1, 0, 0, true }, CURSOR_RIGHT_FAST = { 1, 0, 0, true },
+ CURSOR_UPLEFT_FAST = { -1, -1, 0, true }, CURSOR_UPRIGHT_FAST = { 1, -1, 0, true },
+ CURSOR_DOWNLEFT_FAST = { -1, 1, 0, true }, CURSOR_DOWNRIGHT_FAST = { 1, 1, 0, true },
+ CURSOR_UP_Z = { 0, 0, 1 }, CURSOR_DOWN_Z = { 0, 0, -1 },
+ CURSOR_UP_Z_AUX = { 0, 0, 1 }, CURSOR_DOWN_Z_AUX = { 0, 0, -1 },
+}
+
+function Viewport:scrollByKey(key)
+ local info = MOVEMENT_KEYS[key]
+ if info then
+ local delta = 10
+ if info[4] then delta = 20 end
+
+ return self:clip(
+ self.x1 + delta*info[1],
+ self.y1 + delta*info[2],
+ self.z + info[3]
+ )
+ else
+ return self
end
end
@@ -112,23 +177,53 @@ DwarfOverlay = defclass(DwarfOverlay, gui.Screen)
function DwarfOverlay:updateLayout()
self.df_layout = getPanelLayout()
- self.df_viewport = getViewportPos()
- self.df_cursor = getCursorPos()
end
-local move_keys = {
- 'CURSOR_UP', 'CURSOR_DOWN', 'CURSOR_LEFT', 'CURSOR_RIGHT',
- 'CURSOR_UPLEFT', 'CURSOR_UPRIGHT', 'CURSOR_DOWNLEFT', 'CURSOR_DOWNRIGHT',
- 'CURSOR_UP_FAST', 'CURSOR_DOWN_FAST', 'CURSOR_LEFT_FAST', 'CURSOR_RIGHT_FAST',
- 'CURSOR_UPLEFT_FAST', 'CURSOR_UPRIGHT_FAST', 'CURSOR_DOWNLEFT_FAST', 'CURSOR_DOWNRIGHT_FAST',
- 'CURSOR_UP_Z', 'CURSOR_DOWN_Z', 'CURSOR_UP_Z_AUX', 'CURSOR_DOWN_Z_AUX'
-}
+function DwarfOverlay:onShown()
+ self:updateLayout()
+end
+
+function DwarfOverlay:onResize(w,h)
+ self:updateLayout()
+end
+
+function DwarfOverlay:getViewport(old_vp)
+ if old_vp then
+ return old_vp:resize(self.df_layout)
+ else
+ return Viewport.get(self.df_layout)
+ end
+end
function DwarfOverlay:propagateMoveKeys(keys)
- for _,v in ipairs(move_keys) do
- if keys[v] then
- self:sendInputToParent(v)
- return v
+ for code,_ in pairs(MOVEMENT_KEYS) do
+ if keys[code] then
+ self:sendInputToParent(code)
+ return code
+ end
+ end
+end
+
+function DwarfOverlay:simulateViewScroll(keys, anchor, no_clip_cursor)
+ local layout = self.df_layout
+ local cursor = getCursorPos()
+
+ anchor = anchor or cursor
+
+ if anchor and keys.A_MOVE_SAME_SQUARE then
+ self:getViewport():centerOn(anchor):set()
+ return 'A_MOVE_SAME_SQUARE'
+ end
+
+ for code,_ in pairs(MOVEMENT_KEYS) do
+ if keys[code] then
+ local vp = self:getViewport():scrollByKey(code)
+ if (cursor and not no_clip_cursor) or no_clip_cursor == false then
+ vp = vp:reveal(anchor,4,20,4,true)
+ end
+ vp:set()
+
+ return code
end
end
end