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

Create gui/spectate #1365

Merged
merged 23 commits into from
Feb 22, 2025
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1ed5e22
Create tooltips.lua
TymurGubayev Jan 4, 2025
7abc355
Create tooltips.rst
TymurGubayev Jan 4, 2025
66dce0d
Update docs/gui/tooltips.rst
TymurGubayev Jan 6, 2025
c27777a
Update gui/tooltips.lua
TymurGubayev Jan 6, 2025
0ca5a9a
enter emoticons
TymurGubayev Jan 7, 2025
0f6aeba
fix GetScreenCoordinates for ASCII mode
TymurGubayev Jan 7, 2025
be5bccd
tooltips.rst: add IMPORTANT NOTE as well as some clarifications
TymurGubayev Jan 7, 2025
9484f8e
vieport.window_x -> .coord
TymurGubayev Jan 12, 2025
33dbe85
use `getUnitsInBox(pos1, pos2)` overload
TymurGubayev Jan 12, 2025
8d345a7
make this an overlay
TymurGubayev Jan 12, 2025
66d8d39
make possible to show specific stress/happiness levels; add config UI
TymurGubayev Jan 18, 2025
e97201c
trim trailing whitespaces
TymurGubayev Jan 18, 2025
2e1cf87
fix an ASCII mode exception
TymurGubayev Jan 18, 2025
7e53def
render mouse tooltips over unit banners
TymurGubayev Feb 1, 2025
ec27b39
use list instead of labels in config UI
TymurGubayev Feb 1, 2025
5ec1e54
persist config (globally)
TymurGubayev Feb 1, 2025
6c98c34
Merge branch 'master' into gui/tooltips/1
TymurGubayev Feb 21, 2025
7abd0f9
Delete docs/gui/tooltips.rst
TymurGubayev Feb 21, 2025
bb4972f
Delete gui/tooltips.lua
TymurGubayev Feb 21, 2025
561eeab
implement gui/spectate.lua
TymurGubayev Feb 21, 2025
3c3fa05
adjust starting position
TymurGubayev Feb 21, 2025
40f3913
Merge branch 'master' into HEAD
myk002 Feb 22, 2025
46689c2
refactor UI and use upstreamed functionality
myk002 Feb 22, 2025
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
3 changes: 3 additions & 0 deletions docs/gui/spectate.rst
Original file line number Diff line number Diff line change
@@ -8,6 +8,9 @@ gui/spectate
This is an in-game configuration interface for `spectate`, which automatically
sets the camera to follow interesting units.

You can configure the overlay tooltip settings as well as the follow mode
settings.

Usage
-----

228 changes: 225 additions & 3 deletions gui/spectate.lua
Original file line number Diff line number Diff line change
@@ -1,20 +1,242 @@
local gui = require('gui')
local overlay = require('plugins.overlay')
local spectate = require('plugins.spectate')
local textures = require('gui.textures')
local utils = require('utils')
local widgets = require('gui.widgets')

local OVERLAY_NAME = 'spectate.tooltip'

--------------------------------------------------------------------------------
--- ToggleLabel

-- pens are the same as gui/control-panel.lua
local function get_icon_pens()
local enabled_pen_left = dfhack.pen.parse{fg=COLOR_CYAN,
tile=curry(textures.tp_control_panel, 1), ch=string.byte('[')}
local enabled_pen_center = dfhack.pen.parse{fg=COLOR_LIGHTGREEN,
tile=curry(textures.tp_control_panel, 2) or nil, ch=251} -- check
local enabled_pen_right = dfhack.pen.parse{fg=COLOR_CYAN,
tile=curry(textures.tp_control_panel, 3) or nil, ch=string.byte(']')}
local disabled_pen_left = dfhack.pen.parse{fg=COLOR_CYAN,
tile=curry(textures.tp_control_panel, 4) or nil, ch=string.byte('[')}
local disabled_pen_center = dfhack.pen.parse{fg=COLOR_RED,
tile=curry(textures.tp_control_panel, 5) or nil, ch=string.byte('x')}
local disabled_pen_right = dfhack.pen.parse{fg=COLOR_CYAN,
tile=curry(textures.tp_control_panel, 6) or nil, ch=string.byte(']')}
return enabled_pen_left, enabled_pen_center, enabled_pen_right,
disabled_pen_left, disabled_pen_center, disabled_pen_right
end
local ENABLED_PEN_LEFT, ENABLED_PEN_CENTER, ENABLED_PEN_RIGHT,
DISABLED_PEN_LEFT, DISABLED_PEN_CENTER, DISABLED_PEN_RIGHT = get_icon_pens()

ToggleLabel = defclass(ToggleLabel, widgets.ToggleHotkeyLabel)

function ToggleLabel:init()
local text = self.text
-- the very last token is the On/Off text -- we'll repurpose it as an indicator
text[#text] = { tile = function() return self:getOptionValue() and ENABLED_PEN_LEFT or DISABLED_PEN_LEFT end }
text[#text + 1] = { tile = function() return self:getOptionValue() and ENABLED_PEN_CENTER or DISABLED_PEN_CENTER end }
text[#text + 1] = { tile = function() return self:getOptionValue() and ENABLED_PEN_RIGHT or DISABLED_PEN_RIGHT end }
self:setText(text)
end

--------------------------------------------------------------------------------
--- Spectate config window
Spectate = defclass(Spectate, widgets.Window)
Spectate.ATTRS {
frame_title='Spectate',
frame={w=50, h=45},
resizable=true,
resize_min={w=50, h=20},
frame={l=5, t=5, w=36, h=39},
}

local function create_toggle_button(frame, cfg_elem, hotkey, label, cfg_elem_key)
return ToggleLabel{
frame=frame,
initial_option=spectate.get_config_elem(cfg_elem, cfg_elem_key),
on_change=function(val) dfhack.run_command('spectate', 'set', cfg_elem, tostring(val)) end,
key=hotkey,
label=label,
}
end

local function create_numeric_edit_field(frame, cfg_elem, hotkey, label)
local editOnSubmit
local ef = widgets.EditField{
frame=frame,
label_text = label,
text = tostring(spectate.get_config_elem(cfg_elem)),
modal = true,
key = hotkey,
on_char = function(ch) return ch:match('%d') end,
on_submit = function(text) editOnSubmit(text) end,
}
editOnSubmit = function(text)
if text == '' then
ef:setText(tostring(spectate.get_config_elem(cfg_elem)))
else
dfhack.run_command('spectate', 'set', cfg_elem, text)
end
end

return ef
end

local function create_row_toggle_buttons(keyFollow, keyHover, colFollow, colHover, cfg_elem_key)
local tlFollow = create_toggle_button({l=colFollow+2}, keyFollow, nil, nil, cfg_elem_key)
local tlHover = create_toggle_button({l=colHover+1}, keyHover, nil, nil, cfg_elem_key)
return tlFollow, tlHover
end

local function create_row(frame, label, hotkey, suffix, colFollow, colHover)
suffix = suffix or ''
if suffix ~= '' then suffix = '-'..suffix end

local keyFollow = 'tooltip-follow'..suffix
local keyHover = 'tooltip-hover'..suffix

local tlFollow, tlHover = create_row_toggle_buttons(keyFollow, keyHover, colFollow, colHover)

return widgets.Panel{
frame=utils.assign({h=1}, frame),
subviews={
widgets.HotkeyLabel{
frame={l=0,w=1},
key='CUSTOM_' .. hotkey,
key_sep='',
on_activate=function() tlFollow:cycle() end,
},
widgets.HotkeyLabel{
frame={l=1,w=1},
key='CUSTOM_SHIFT_' .. hotkey,
key_sep='',
on_activate=function() tlHover:cycle() end,
},
widgets.Label{
frame={l=2},
text = ': ' .. label,
},
tlFollow,
tlHover,
},
}
end

local function make_choice(text, tlFollow, tlHover)
return {
text=text,
data={tlFollow=tlFollow, tlHover=tlHover},
}
end

-- individual stress levels
-- a list on the left to select one, individual buttons in two columns to be able to click on them
local function create_stress_list(frame, colFollow, colHover)
local levelsKey = 'tooltip-stress-levels'
local stressFollowKey = 'tooltip-follow-stress-levels'
local stressHoverKey = 'tooltip-hover-stress-levels'

local choices, subviews = {}, {}
for idx=0,6 do
local cfgElemKey = tostring(idx)
local tlFollow, tlHover = create_row_toggle_buttons(stressFollowKey, stressHoverKey, colFollow, colHover, cfgElemKey)
table.insert(subviews, widgets.Panel{
frame={t=idx, h=1},
subviews={
tlFollow,
tlHover,
}
})

local elem = spectate.get_config_elem(levelsKey, cfgElemKey)
table.insert(choices, make_choice({{text=elem.text, pen=elem.pen}, ' ', elem.name}, tlFollow, tlHover))
end

table.insert(subviews, widgets.List{
frame={l=2},
on_submit=function(_, choice) choice.data.tlFollow:cycle() end,
on_submit2=function(_, choice) choice.data.tlHover:cycle() end,
choices=choices,
})

return widgets.Panel{
frame=frame,
subviews=subviews,
}
end

local function rpad(s, i)
return string.format("%-"..i.."s", s)
end

function Spectate:init()
local lWidth = 21
local colFollow, colHover = 15, 25

self:addviews{
widgets.Label{
frame={t=0, l=0},
text='See help for option details:',
},
widgets.HelpButton{
frame={t=0, r=0},
command = 'spectate',
},
ToggleLabel{
frame={t=2},
view_id='spectate_mode',
initial_option=spectate.isEnabled(),
on_change=function(val) dfhack.run_command(val and 'enable' or 'disable', 'spectate') end,
key='CUSTOM_ALT_E',
label='Spectate mode ',
},
create_numeric_edit_field({t=4}, 'follow-seconds', 'CUSTOM_ALT_F', 'Switch target (sec): '),
create_toggle_button({t=6}, 'auto-unpause', 'CUSTOM_ALT_U', rpad('Auto unpause', lWidth)),
create_toggle_button({t=7}, 'cinematic-action', 'CUSTOM_ALT_C', rpad('Cinematic action', lWidth)),
create_toggle_button({t=8}, 'include-animals', 'CUSTOM_ALT_A', rpad('Include animals', lWidth)),
create_toggle_button({t=9}, 'include-hostiles', 'CUSTOM_ALT_H', rpad('Include hostiles', lWidth)),
create_toggle_button({t=10}, 'include-visitors', 'CUSTOM_ALT_V', rpad('Include visitors', lWidth)),
create_toggle_button({t=11}, 'include-wildlife', 'CUSTOM_ALT_W', rpad('Include wildlife', lWidth)),
create_toggle_button({t=12}, 'prefer-conflict', 'CUSTOM_ALT_B', rpad('Prefer conflict', lWidth)),
create_toggle_button({t=13}, 'prefer-new-arrivals', 'CUSTOM_ALT_N', rpad('Prefer new arrivals', lWidth)),
widgets.Divider{
frame={t=15, h=1},
frame_style=gui.FRAME_THIN,
frame_style_l=false,
frame_style_r=false,
},
widgets.Label{
frame={t=17, l=0},
text="Tooltips:"
},
ToggleLabel{
frame={t=17, l=12},
initial_option=overlay.isOverlayEnabled(OVERLAY_NAME),
on_change=function(val) dfhack.run_command('overlay', val and 'enable' or 'disable', OVERLAY_NAME) end,
key='CUSTOM_ALT_O',
label="Overlay ",
},
widgets.Label{
frame={t=19, l=colFollow},
text='Follow',
},
widgets.Label{
frame={t=19, l=colHover},
text='Hover',
},
create_row({t=21}, 'Enabled', 'E', '', colFollow, colHover),
create_numeric_edit_field({t=23}, 'tooltip-follow-blink-milliseconds', 'CUSTOM_B', 'Blink period (ms): '),
create_row({t=25}, 'Job', 'J', 'job', colFollow, colHover),
create_row({t=26}, 'Name', 'N', 'name', colFollow, colHover),
create_row({t=27}, 'Stress', 'S', 'stress', colFollow, colHover),
create_stress_list({t=28}, colFollow, colHover),
}
end

function Spectate:render(dc)
self.subviews.spectate_mode:setOption(spectate.isEnabled())
Spectate.super.render(self, dc)
end

SpectateScreen = defclass(SpectateScreen, gui.ZScreen)
SpectateScreen.ATTRS {
focus_path='spectate',