Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add the Tracks gui, hotkey friendly #1172

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
180 changes: 180 additions & 0 deletions gui/tracks.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
local repeatUtil = require('repeat-util')

local utils = require('utils')
local gui = require('gui')
local widgets = require('gui.widgets')
local guidm = require('gui.dwarfmode')
local world_map = df.global.world.map
local adventure = df.global.adventure

local to_pen = dfhack.pen.parse
local others_track = to_pen{
ch='+',
fg=COLOR_YELLOW,
tile=dfhack.screen.findGraphicsTile('CURSORS', 5, 23),
}

local yours_track = to_pen{
ch='+',
fg=COLOR_CYAN,
tile=dfhack.screen.findGraphicsTile('CURSORS', 5, 22),
}

--tile=dfhack.screen.findGraphicsTile('INTERFACE_BITS_BUILDING_PLACEMENT', 1, 0)
local pen_direction = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for actual arrows for the cardinal directions, use the arrow characters.

e.g. from trackstop.lua:

local NORTH = 'North '..string.char(24)
local EAST = 'East '..string.char(26)
local SOUTH = 'South '..string.char(25)
local WEST = 'West '..string.char(27)

to_pen{ch='v',fg=COLOR_YELLOW,}, -- tile=dfhack.screen.findGraphicsTile('ROLLERS', 8, 2),}, -- 0 South
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lists in Lua are 1-based. If you want to match the value of the direction flag (which appears to be a 0-based enum), assign the indices directly, like:

local pen_direction = {
[df.spoor_flag_dir.north] = to_pen{...},
[df.spoor_flag_dir.south] = ...

to_pen{ch='>',fg=COLOR_YELLOW,}, -- tile=dfhack.screen.findGraphicsTile('ROLLERS', 7, 2),}, -- 1 East
to_pen{ch='\xbf',fg=COLOR_YELLOW,}, -- tile=dfhack.screen.findGraphicsTile('ROLLERS', 5, 2),}, -- 2 NorthWest
to_pen{ch='<',fg=COLOR_YELLOW,}, -- tile=dfhack.screen.findGraphicsTile('ROLLERS', 6, 2),}, -- 3 West
to_pen{ch='\xda',fg=COLOR_YELLOW,}, -- tile=dfhack.screen.findGraphicsTile('ROLLERS', 4, 2),}, -- 4 NorthEast
to_pen{ch='\xd9',fg=COLOR_YELLOW,}, -- tile=dfhack.screen.findGraphicsTile('ROLLERS', 2, 2),}, -- 5 SouthEast
to_pen{ch='\xc0',fg=COLOR_YELLOW,}, -- tile=dfhack.screen.findGraphicsTile('ROLLERS', 3, 2),}, -- 6 SouthWest
to_pen{ch='^',fg=COLOR_YELLOW,}, -- tile=dfhack.screen.findGraphicsTile('ROLLERS', 9, 2),}, -- 7 North
}
local function get_directional_pen(dir)
return pen_direction[dir] or pen_direction[8]
end

local visible_tracks = {}

local timerId = 'testoverlay'
local function onTimer()
visible_tracks = {}
for i=0, adventure.tracks_next_idx do
local x = (adventure.tracks_x[i] - world_map.region_x*48)
local y = (adventure.tracks_y[i] - world_map.region_y*48)
local z = (adventure.tracks_z[i] - world_map.region_z)
if dfhack.maps.isTileVisible(x,y,z) then
local block = dfhack.maps.getTileBlock(x,y,z)
-- "pile" = "lit" and "dig=1" = "visible" in adventure mode
if block.designation[x%16][y%16].pile then
for _, event in pairs(block.block_events) do
if getmetatable(event) == "block_square_event_spoorst" then
local flags = event.flags[x%16][y%16]
if flags.present then
table.insert(visible_tracks, {x=x, y=y, z=z, flags=flags})
end
end
end
end
end
end
end

TestOverlay = defclass(TestOverlay, widgets.Window)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably name this (and TestScreen) something other than "Test"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in addition, it's not an overlay. The common pattern is to name the screen FooScreen and the Window Foo. E.g. TracksScreen and Tracks

TestOverlay.ATTRS {
default_pos={x=20, y=0},
default_enabled=true,
Comment on lines +66 to +67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these two aren't Window attributes and can be removed

frame_title='Test Overlay',
frame={b = 4, r = 4, w = 50, h = 12},
viewscreens= {
'dungeonmode/Default',
},
Comment on lines +70 to +72
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also can be removed

}

function TestOverlay:getLabel()
local pos = dfhack.world.getAdventurer().pos
local adv_x, adv_y, adv_z = pos.x, pos.y, pos.z
return ("Your position: %s, %s, %s"):format(
adv_x, adv_y, adv_z
)
end

function TestOverlay:init()
self.directional = false
self.show_yours = true
self.show_others = true
Comment on lines +84 to +86
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need to copy widget state into your object. you can access the widget state directly. Then you also don't need to have on_change handlers

self:addviews{
widgets.Label{
frame = {l = 0, t = 0},
text = {{ text = self:callback('getLabel') }}
},
widgets.ToggleHotkeyLabel{
frame={l = 0, t = 2},
label='Show Directions',
key='CUSTOM_CTRL_D',
options={{value=true, label="Enabled"},
{value=false, label="Disabled"}},
initial_option = self.directional,
on_change=function(option) self.directional = option end
},
widgets.ToggleHotkeyLabel{
frame={l = 0, t = 3},
label='Show Your Tracks',
key='CUSTOM_CTRL_Y',
options={{value=true, label="Enabled"},
{value=false, label="Disabled"}},
initial_option = self.show_yours,
on_change=function(option) self.show_yours = option end
},
widgets.ToggleHotkeyLabel{
frame={l = 0, t = 4},
label='Show Other Tracks',
key='CUSTOM_CTRL_O',
options={{value=true, label="Enabled"},
{value=false, label="Disabled"}},
initial_option = self.show_others,
on_change=function(option) self.show_others = option end
},
}
end

function TestOverlay:onRenderFrame(dc, rect)
TestOverlay.super.onRenderFrame(self, dc, rect)

for i, track in pairs(visible_tracks) do
if track.z ~= df.global.window_z then goto continue end
local track_xyz = {
x1 = track.x, x2 = track.x,
y1 = track.y, y2 = track.y,
z1 = track.z, z2 = track.z
}
local pen = others_track
if track.flags.yours then
if not self.show_yours then goto continue end
pen = yours_track
else
if not self.show_others then goto continue end
end
if track.flags.has_direction and self.directional then
pen = get_directional_pen(track.flags.direction)
end
guidm.renderMapOverlay(function() return pen end, track_xyz)
::continue::
end
end

TestScreen = defclass(TestScreen, gui.ZScreen)
TestScreen.ATTRS {
focus_path='testscreen',
pass_movement_keys=true,
pass_mouse_clicks=true,
}

function TestScreen:init()
local window = TestOverlay{}
self:addviews{
window,
}
onTimer()
repeatUtil.scheduleEvery(timerId, 1, 'ticks', onTimer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest not using repeatUtil here. That makes cleanup messy. Instead, update in your own render method when the tick counter has incremented.

df.global.adventure.view_tracks_odors.DISPLAY_LATEST = true
df.global.adventure.view_tracks_odors.DISPLAY_ODOR = true
end

function TestScreen:onDismiss()
view = nil
repeatUtil.cancel(timerId)
df.global.adventure.view_tracks_odors.DISPLAY_LATEST = false
df.global.adventure.view_tracks_odors.DISPLAY_ODOR = false
end

if dfhack_flags.module then
return
end

if not dfhack.isMapLoaded() then
qerror('This script requires a map to be loaded')
end

view = view and view:raise() or TestScreen{}:show()
Loading