@@ -2,17 +2,319 @@ local gui = require('gui')
22local spectate = require (' plugins.spectate' )
33local widgets = require (' gui.widgets' )
44
5+ ---- ----------------------------------------------------------------------------
6+ --- ToggleLabel
7+
8+ -- pens are the same as gui/control-panel.lua
9+ local textures = require (' gui.textures' )
10+ local function get_icon_pens ()
11+ local enabled_pen_left = dfhack .pen .parse {fg = COLOR_CYAN ,
12+ tile = curry (textures .tp_control_panel , 1 ), ch = string.byte (' [' )}
13+ local enabled_pen_center = dfhack .pen .parse {fg = COLOR_LIGHTGREEN ,
14+ tile = curry (textures .tp_control_panel , 2 ) or nil , ch = 251 } -- check
15+ local enabled_pen_right = dfhack .pen .parse {fg = COLOR_CYAN ,
16+ tile = curry (textures .tp_control_panel , 3 ) or nil , ch = string.byte (' ]' )}
17+ local disabled_pen_left = dfhack .pen .parse {fg = COLOR_CYAN ,
18+ tile = curry (textures .tp_control_panel , 4 ) or nil , ch = string.byte (' [' )}
19+ local disabled_pen_center = dfhack .pen .parse {fg = COLOR_RED ,
20+ tile = curry (textures .tp_control_panel , 5 ) or nil , ch = string.byte (' x' )}
21+ local disabled_pen_right = dfhack .pen .parse {fg = COLOR_CYAN ,
22+ tile = curry (textures .tp_control_panel , 6 ) or nil , ch = string.byte (' ]' )}
23+ local button_pen_left = dfhack .pen .parse {fg = COLOR_CYAN ,
24+ tile = curry (textures .tp_control_panel , 7 ) or nil , ch = string.byte (' [' )}
25+ local button_pen_right = dfhack .pen .parse {fg = COLOR_CYAN ,
26+ tile = curry (textures .tp_control_panel , 8 ) or nil , ch = string.byte (' ]' )}
27+ local help_pen_center = dfhack .pen .parse {
28+ tile = curry (textures .tp_control_panel , 9 ) or nil , ch = string.byte (' ?' )}
29+ local configure_pen_center = dfhack .pen .parse {
30+ tile = curry (textures .tp_control_panel , 10 ) or nil , ch = 15 } -- gear/masterwork symbol
31+ return enabled_pen_left , enabled_pen_center , enabled_pen_right ,
32+ disabled_pen_left , disabled_pen_center , disabled_pen_right ,
33+ button_pen_left , button_pen_right ,
34+ help_pen_center , configure_pen_center
35+ end
36+ local ENABLED_PEN_LEFT , ENABLED_PEN_CENTER , ENABLED_PEN_RIGHT ,
37+ DISABLED_PEN_LEFT , DISABLED_PEN_CENTER , DISABLED_PEN_RIGHT ,
38+ BUTTON_PEN_LEFT , BUTTON_PEN_RIGHT ,
39+ HELP_PEN_CENTER , CONFIGURE_PEN_CENTER = get_icon_pens ()
40+
41+ ToggleLabel = defclass (ToggleLabel , widgets .CycleHotkeyLabel )
42+ ToggleLabel .ATTRS {
43+ options = {{value = true },
44+ {value = false }},
45+ }
46+ function ToggleLabel :init ()
47+ ToggleLabel .super .init (self )
48+
49+ local text = self .text
50+ -- the very last token is the On/Off text -- we'll repurpose it as an indicator
51+ text [# text ] = { tile = function () return self :getOptionValue () and ENABLED_PEN_LEFT or DISABLED_PEN_LEFT end }
52+ text [# text + 1 ] = { tile = function () return self :getOptionValue () and ENABLED_PEN_CENTER or DISABLED_PEN_CENTER end }
53+ text [# text + 1 ] = { tile = function () return self :getOptionValue () and ENABLED_PEN_RIGHT or DISABLED_PEN_RIGHT end }
54+ self :setText (text )
55+ end
56+
57+ ---- ----------------------------------------------------------------------------
58+ --- Spectate config window
559Spectate = defclass (Spectate , widgets .Window )
660Spectate .ATTRS {
761 frame_title = ' Spectate' ,
8- frame = {w = 50 , h = 45 },
62+ frame = {w = 35 , h = 30 },
963 resizable = true ,
10- resize_min = {w = 50 , h = 20 },
64+ resize_min = {w = 35 , h = 30 },
1165}
1266
67+ local function append (t , args )
68+ for i = 1 , # args do
69+ t [# t + 1 ] = args [i ]
70+ end
71+ return t
72+ end
73+
74+ local function create_toggle_button (cfg , cfg_key , left , top , hotkey , label )
75+ return ToggleLabel {
76+ frame = {t = top ,l = left },
77+ initial_option = cfg [cfg_key ],
78+ on_change = function (new , old ) cfg [cfg_key ] = new ; spectate .save_state () end ,
79+ key = hotkey ,
80+ label = label ,
81+ }
82+ end
83+
84+ local function create_numeric_edit_field (cfg , cfg_key , left , top , hotkey , label )
85+ local editOnSubmit
86+ local ef = widgets .EditField {
87+ frame = {t = top ,l = left },
88+ label_text = label ,
89+ text = tostring (cfg [cfg_key ]),
90+ modal = true ,
91+ key = hotkey ,
92+ on_char = function (new_char ,text ) return ' 0' <= new_char and new_char <= ' 9' end ,
93+ on_submit = function (text ) editOnSubmit (text ) end ,
94+ }
95+ editOnSubmit = function (text )
96+ if text == ' ' then
97+ ef :setText (tostring (cfg [cfg_key ]))
98+ else
99+ cfg [cfg_key ] = tonumber (text )
100+ spectate .save_state ()
101+ end
102+ end
103+
104+ return ef
105+ end
106+
107+ local function create_toggle_buttons (cfgFollow , keyFollow , cfgHover , keyHover , colFollow , colHover , top )
108+ local tlFollow = create_toggle_button (cfgFollow , keyFollow , colFollow + 2 , top )
109+ local tlHover = create_toggle_button (cfgHover , keyHover , colHover + 1 , top )
110+
111+ return tlFollow , tlHover
112+ end
113+
114+ local function create_row (label , hotkey , suffix , colFollow , colHover , top )
115+ local config = spectate .config
116+
117+ suffix = suffix or ' '
118+ if suffix ~= ' ' then suffix = ' -' .. suffix end
119+
120+ local keyFollow = ' tooltip-follow' .. suffix
121+ local keyHover = ' tooltip-hover' .. suffix
122+
123+ local tlFollow , tlHover = create_toggle_buttons (config , keyFollow , config , keyHover , colFollow , colHover , top )
124+ local views = {
125+ widgets .HotkeyLabel {
126+ frame = {t = top ,l = 0 ,w = 1 },
127+ key = ' CUSTOM_' .. hotkey ,
128+ key_sep = ' ' ,
129+ on_activate = function () tlFollow :cycle () end ,
130+ },
131+ widgets .HotkeyLabel {
132+ frame = {t = top ,l = 1 ,w = 1 },
133+ key = ' CUSTOM_SHIFT_' .. hotkey ,
134+ key_sep = ' ' ,
135+ on_activate = function () tlHover :cycle () end ,
136+ },
137+ widgets .Label {
138+ frame = {t = top ,l = 2 },
139+ text = ' : ' .. label ,
140+ },
141+ tlFollow ,
142+ tlHover ,
143+ }
144+
145+ return views
146+ end
147+
148+ local function make_choice (text , tlFollow , tlHover )
149+ return {
150+ text = text ,
151+ data = {tlFollow = tlFollow , tlHover = tlHover },
152+ }
153+ end
154+
155+ local function pairsByKeys (t , f )
156+ local a = {}
157+ for n in pairs (t ) do table.insert (a , n ) end
158+ table.sort (a , f )
159+ local i = 0 -- iterator variable
160+ local iter = function () -- iterator function
161+ i = i + 1
162+ if a [i ] == nil then return nil
163+ else return a [i ], t [a [i ]]
164+ end
165+ end
166+ return iter
167+ end
168+
169+ local function rpad (s , i )
170+ return string.format (" %-" .. i .. " s" , s )
171+ end
172+
173+ local overlay = require (' plugins.overlay' )
174+ local OVERLAY_NAME = ' spectate.tooltip'
175+ local function isOverlayEnabled ()
176+ return overlay .get_state ().config [OVERLAY_NAME ].enabled
177+ end
178+
179+ local function enable_overlay (enabled )
180+ local tokens = {' overlay' }
181+ table.insert (tokens , enabled and ' enable' or ' disable' )
182+ table.insert (tokens , OVERLAY_NAME )
183+ dfhack .run_command (tokens )
184+ end
185+
186+ function Spectate :updateOverlayDisabledGag (widget )
187+ local w = widget or self .subviews .overlayIsDisabledGag
188+
189+ if isOverlayEnabled () then
190+ if w .frame .t < 500 then
191+ w .frame .t = w .frame .t + 500
192+ end
193+ else
194+ if w .frame .t > 500 then
195+ w .frame .t = w .frame .t - 500
196+ end
197+ end
198+
199+ if not widget then
200+ self :updateLayout ()
201+ end
202+ end
203+
13204function Spectate :init ()
14- self :addviews {
205+ local config = spectate .config
206+
207+ local views = {}
208+ local t = 0
209+
210+ local len = 20
211+ append (views , {create_toggle_button (config , ' auto-disengage' , 0 , t , ' CUSTOM_ALT_D' , rpad (" Auto disengage" , len ))}); t = t + 1
212+ append (views , {create_toggle_button (config , ' auto-unpause' , 0 , t , ' CUSTOM_ALT_U' , rpad (" Auto unpause" , len ))}); t = t + 1
213+ append (views , {create_toggle_button (config , ' cinematic-action' , 0 , t , ' CUSTOM_ALT_C' , rpad (" Cinematic action" , len ))}); t = t + 1
214+ append (views , {create_numeric_edit_field (config , ' follow-seconds' , 0 , t , ' CUSTOM_ALT_F' , " Follow (s): " )}); t = t + 1
215+ append (views , {create_toggle_button (config , ' include-animals' , 0 , t , ' CUSTOM_ALT_A' , rpad (" Include animals" , len ))}); t = t + 1
216+ append (views , {create_toggle_button (config , ' include-hostiles' , 0 , t , ' CUSTOM_ALT_H' , rpad (" Include hostiles" , len ))}); t = t + 1
217+ append (views , {create_toggle_button (config , ' include-visitors' , 0 , t , ' CUSTOM_ALT_V' , rpad (" Include visitors" , len ))}); t = t + 1
218+ append (views , {create_toggle_button (config , ' include-wildlife' , 0 , t , ' CUSTOM_ALT_W' , rpad (" Include wildlife" , len ))}); t = t + 1
219+ append (views , {create_toggle_button (config , ' prefer-conflict' , 0 , t , ' CUSTOM_ALT_B' , rpad (" Prefer conflict" , len ))}); t = t + 1
220+ append (views , {create_toggle_button (config , ' prefer-new-arrivals' , 0 , t , ' CUSTOM_ALT_N' , rpad (" Prefer new arrivals" , len ))}); t = t + 1
221+
222+ t = t + 1 -- add a blank line
223+ local colFollow , colHover = 15 , 25
224+ -- tooltips headers
225+ append (views , {
226+ widgets .Label {
227+ frame = {t = t ,l = 0 },
228+ text = " Tooltips:"
229+ },
230+ })
231+ -- t = t + 1
232+ -- overlay is prerequisite for any other tooltip option
233+ local overlayIsDisabledGag = nil
234+ local lblOverlayOnChange = function (new , old )
235+ enable_overlay (new )
236+ self :updateOverlayDisabledGag ()
237+ end
238+ append (views , {
239+ ToggleLabel {
240+ frame = {t = t ,l = 12 },
241+ initial_option = isOverlayEnabled (),
242+ on_change = lblOverlayOnChange ,
243+ key = ' CUSTOM_ALT_O' ,
244+ label = " Overlay " ,
245+ }
246+ })
247+ t = t + 1
248+ overlayIsDisabledGag = widgets .Panel {
249+ view_id = ' overlayIsDisabledGag' ,
250+ frame = {t = t ,l = 0 ,r = 0 ,b = 1 }, -- b=1 because the very last row is where the HelpButton is placed
251+ frame_background = gui .CLEAR_PEN ,
252+ subviews = {
253+ widgets .WrappedLabel {
254+ frame = {t = 0 ,l = 0 ,r = 0 ,b = 0 },
255+ frame_background = gui .CLEAR_PEN ,
256+ text_to_wrap = " Overlay has to be enabled for tooltips." ,
257+ }
258+ },
15259 }
260+
261+ append (views , {
262+ widgets .Label {
263+ frame = {t = t ,l = colFollow },
264+ text = " Follow"
265+ },
266+ widgets .Label {
267+ frame = {t = t ,l = colHover },
268+ text = " Hover"
269+ },
270+ })
271+ t = t + 1
272+
273+ -- enable/disable
274+ append (views , create_row (" Enable" , ' E' , ' ' , colFollow , colHover , t )); t = t + 1
275+ append (views , create_row (" Job" , ' J' , ' job' , colFollow , colHover , t )); t = t + 1
276+ append (views , create_row (" Name" , ' N' , ' name' , colFollow , colHover , t )); t = t + 1
277+ append (views , create_row (" Stress" , ' S' , ' stress' , colFollow , colHover , t )); t = t + 1
278+
279+ -- next are individual stress levels
280+ -- a list on the left to select one, individual buttons in two columns to be able to click on them
281+ local choices = {}
282+ local levels = config [' tooltip-stress-levels' ]
283+ local stressFollow = config [' tooltip-follow-stress-levels' ]
284+ local stressHover = config [' tooltip-hover-stress-levels' ]
285+ local tList = t
286+ for l , cfg in pairsByKeys (levels ) do
287+ local tlFollow , tlHover = create_toggle_buttons (stressFollow , l , stressHover , l , colFollow , colHover , t )
288+ append (views , { tlFollow , tlHover })
289+
290+ table.insert (choices , make_choice ({{text = cfg .text , pen = cfg .pen }, ' ' , cfg .name }, tlFollow , tlHover ))
291+
292+ t = t + 1
293+ end
294+ append (views ,{
295+ widgets .List {
296+ frame = {t = tList ,l = 2 },
297+ view_id = ' list_levels' ,
298+ on_submit = function (index , choice ) choice .data .tlFollow :cycle () end ,
299+ on_submit2 = function (index , choice ) choice .data .tlHover :cycle () end ,
300+ row_height = 1 ,
301+ choices = choices ,
302+ },
303+ })
304+
305+ append (views , {create_numeric_edit_field (config , ' tooltip-follow-blink-milliseconds' , 0 , t , ' CUSTOM_B' , " Blink duration (ms): " )}); t = t + 1
306+
307+ append (views , {
308+ widgets .HelpButton {
309+ frame = {b = 0 ,r = 0 },
310+ command = ' spectate' ,
311+ }
312+ })
313+
314+ append (views , {overlayIsDisabledGag }) -- must be the very last thing
315+ self :updateOverlayDisabledGag (overlayIsDisabledGag )
316+
317+ self :addviews (views )
16318end
17319
18320SpectateScreen = defclass (SpectateScreen , gui .ZScreen )
0 commit comments