@@ -11,19 +11,79 @@ local ResizingPanel = require('gui.widgets.containers.resizing_panel')
1111
1212---- ----------------------------------------------------------------------------
1313
14- config = config or {
15- follow_units = true ,
16- follow_mouse = true ,
17- }
18- local function change_follow_units (new , old )
19- config .follow_units = new
14+ -- pens are the same as gui/control-panel.lua
15+ local textures = require (' gui.textures' )
16+ local function get_icon_pens ()
17+ local enabled_pen_left = dfhack .pen .parse {fg = COLOR_CYAN ,
18+ tile = curry (textures .tp_control_panel , 1 ), ch = string.byte (' [' )}
19+ local enabled_pen_center = dfhack .pen .parse {fg = COLOR_LIGHTGREEN ,
20+ tile = curry (textures .tp_control_panel , 2 ) or nil , ch = 251 } -- check
21+ local enabled_pen_right = dfhack .pen .parse {fg = COLOR_CYAN ,
22+ tile = curry (textures .tp_control_panel , 3 ) or nil , ch = string.byte (' ]' )}
23+ local disabled_pen_left = dfhack .pen .parse {fg = COLOR_CYAN ,
24+ tile = curry (textures .tp_control_panel , 4 ) or nil , ch = string.byte (' [' )}
25+ local disabled_pen_center = dfhack .pen .parse {fg = COLOR_RED ,
26+ tile = curry (textures .tp_control_panel , 5 ) or nil , ch = string.byte (' x' )}
27+ local disabled_pen_right = dfhack .pen .parse {fg = COLOR_CYAN ,
28+ tile = curry (textures .tp_control_panel , 6 ) or nil , ch = string.byte (' ]' )}
29+ local button_pen_left = dfhack .pen .parse {fg = COLOR_CYAN ,
30+ tile = curry (textures .tp_control_panel , 7 ) or nil , ch = string.byte (' [' )}
31+ local button_pen_right = dfhack .pen .parse {fg = COLOR_CYAN ,
32+ tile = curry (textures .tp_control_panel , 8 ) or nil , ch = string.byte (' ]' )}
33+ local help_pen_center = dfhack .pen .parse {
34+ tile = curry (textures .tp_control_panel , 9 ) or nil , ch = string.byte (' ?' )}
35+ local configure_pen_center = dfhack .pen .parse {
36+ tile = curry (textures .tp_control_panel , 10 ) or nil , ch = 15 } -- gear/masterwork symbol
37+ return enabled_pen_left , enabled_pen_center , enabled_pen_right ,
38+ disabled_pen_left , disabled_pen_center , disabled_pen_right ,
39+ button_pen_left , button_pen_right ,
40+ help_pen_center , configure_pen_center
2041end
21- local function change_follow_mouse (new , old )
22- config .follow_mouse = new
42+ local ENABLED_PEN_LEFT , ENABLED_PEN_CENTER , ENABLED_PEN_RIGHT ,
43+ DISABLED_PEN_LEFT , DISABLED_PEN_CENTER , DISABLED_PEN_RIGHT ,
44+ BUTTON_PEN_LEFT , BUTTON_PEN_RIGHT ,
45+ HELP_PEN_CENTER , CONFIGURE_PEN_CENTER = get_icon_pens ()
46+
47+ if RELOAD then ToggleLabel = nil end
48+ ToggleLabel = defclass (ToggleLabel , widgets .CycleHotkeyLabel )
49+ ToggleLabel .ATTRS {
50+ options = {{value = true },
51+ {value = false }},
52+ }
53+ function ToggleLabel :init ()
54+ ToggleLabel .super .init (self )
55+
56+ local text = self .text
57+ -- the very last token is the On/Off text -- we'll repurpose it as an indicator
58+ text [# text ] = { tile = function () return self :getOptionValue () and ENABLED_PEN_LEFT or DISABLED_PEN_LEFT end }
59+ text [# text + 1 ] = { tile = function () return self :getOptionValue () and ENABLED_PEN_CENTER or DISABLED_PEN_CENTER end }
60+ text [# text + 1 ] = { tile = function () return self :getOptionValue () and ENABLED_PEN_RIGHT or DISABLED_PEN_RIGHT end }
61+ self :setText (text )
2362end
2463
25- local shortenings = {
26- [" Store item in stockpile" ] = " Store item" ,
64+ ---
65+
66+ if RELOAD then config = nil end
67+ config = config or {
68+ follow_units = true ,
69+ follow_mouse = false ,
70+ show_happiness = true ,
71+ happiness_levels = {
72+ -- keep in mind, the text will look differently with game's font
73+ -- colors are same as in ASCII mode, but for then middle (3), which is GREY instead of WHITE
74+ [0 ] =
75+ {text = " =C" , pen = COLOR_RED , visible = true , name = " Miserable" },
76+ {text = " :C" , pen = COLOR_LIGHTRED , visible = true , name = " Unhappy" },
77+ {text = " :(" , pen = COLOR_YELLOW , visible = false , name = " Displeased" },
78+ {text = " :]" , pen = COLOR_GREY , visible = false , name = " Content" },
79+ {text = " :)" , pen = COLOR_GREEN , visible = false , name = " Pleased" },
80+ {text = " :D" , pen = COLOR_LIGHTGREEN , visible = true , name = " Happy" },
81+ {text = " =D" , pen = COLOR_LIGHTCYAN , visible = true , name = " Ecstatic" },
82+ },
83+ show_unit_jobs = true ,
84+ job_shortenings = {
85+ [" Store item in stockpile" ] = " Store item" ,
86+ }
2787}
2888
2989---- ----------------------------------------------------------------------------
@@ -53,44 +113,93 @@ TooltipControlWindow.ATTRS {
53113 frame_inset = 0 ,
54114 resizable = false ,
55115 frame = {
56- w = 25 ,
57- h = 4 ,
116+ w = 27 ,
117+ h = 2 -- border
118+ + 4 -- main options
119+ + 7 -- happiness
120+ ,
58121 -- just under the minimap:
59122 r = 2 ,
60123 t = 18 ,
61124 },
62125}
63126
127+ -- right pad string `s` to `n` symbols with spaces
128+ local function rpad (s , n )
129+ local formatStr = " %-" .. n .. " s" -- `"%-10s"`
130+ return string.format (formatStr , s )
131+ end
132+
64133function TooltipControlWindow :init ()
134+ local w = self .frame .w - 2 - 3 -- 2 is border, 3 is active indicator width
135+ local keyW = 7 -- Length of "Alt+u: "
136+
65137 self :addviews {
66- widgets . ToggleHotkeyLabel {
138+ ToggleLabel {
67139 view_id = ' btn_follow_units' ,
68140 frame = {t = 0 , h = 1 },
69- label = " Follow units " ,
141+ label = rpad ( " Unit banners " , w - keyW ) ,
70142 key = ' CUSTOM_ALT_U' ,
71- on_change = change_follow_units ,
143+ initial_option = config .follow_units ,
144+ on_change = function (new ) config .follow_units = new end ,
72145 },
73- widgets . ToggleHotkeyLabel {
146+ ToggleLabel {
74147 view_id = ' btn_follow_mouse' ,
75148 frame = {t = 1 , h = 1 },
76- label = " Follow mouse " ,
149+ label = rpad ( " Mouse tooltip " , w - keyW ) ,
77150 key = ' CUSTOM_ALT_M' ,
78- on_change = change_follow_mouse ,
151+ initial_option = config .follow_mouse ,
152+ on_change = function (new ) config .follow_mouse = new end ,
153+ },
154+ ToggleLabel {
155+ frame = {t = 2 , h = 1 },
156+ label = rpad (" Show jobs" , w ),
157+ initial_option = config .show_unit_jobs ,
158+ on_change = function (new ) config .show_unit_jobs = new end ,
159+ },
160+ ToggleLabel {
161+ frame = {t = 3 , h = 1 },
162+ label = rpad (" Show stress levels" , w ),
163+ initial_option = config .show_happiness ,
164+ on_change = function (new ) config .show_happiness = new end ,
79165 },
80166 }
167+
168+ local happinessLabels = {}
169+
170+ -- align the emoticons
171+ local maxNameLength = 1
172+ for _ , v in pairs (config .happiness_levels ) do
173+ local l = # v .name
174+ if l > maxNameLength then
175+ maxNameLength = l
176+ end
177+ end
178+
179+ local indent = 3
180+ for lvl , cfg in pairs (config .happiness_levels ) do
181+ happinessLabels [# happinessLabels + 1 ] = ToggleLabel {
182+ frame = {t = 4 + lvl , h = 1 , l = indent },
183+ initial_option = cfg .visible ,
184+ text_pen = cfg .pen ,
185+ label = rpad (rpad (cfg .name , maxNameLength ) .. " " .. cfg .text , w - indent ),
186+ on_change = function (new ) cfg .visible = new end
187+ }
188+ end
189+ self :addviews (happinessLabels )
81190end
82191
83192local function GetUnitHappiness (unit )
84- -- keep in mind, this will look differently with game's font
85- local mapToEmoticon = {[0 ] = " =C" , " :C" , " :(" , " :]" , " :)" , " :D" , " =D" }
86- -- same as in ASCII mode, but for then middle (3), which is GREY instead of WHITE
87- local mapToColor = {[0 ] = COLOR_RED , COLOR_LIGHTRED , COLOR_YELLOW , COLOR_GREY , COLOR_GREEN , COLOR_LIGHTGREEN , COLOR_LIGHTCYAN }
193+ if not config .show_happiness then return end
88194 local stressCat = dfhack .units .getStressCategory (unit )
89195 if stressCat > 6 then stressCat = 6 end
90- return mapToEmoticon [stressCat ], mapToColor [stressCat ]
196+ local happiness_level_cfg = config .happiness_levels [stressCat ]
197+ if not happiness_level_cfg .visible then return end
198+ return happiness_level_cfg .text , happiness_level_cfg .pen
91199end
92200
93201local function GetUnitJob (unit )
202+ if not config .show_unit_jobs then return end
94203 local job = unit .job .current_job
95204 return job and dfhack .job .getName (job )
96205end
189298
190299-- map coordinates -> interface layer coordinates
191300local function GetScreenCoordinates (map_coord )
192- if not map_coord then return end
193301 -- -> map viewport offset
194302 local vp = df .global .world .viewport
195303 local vp_Coord = vp .corner
@@ -234,12 +342,13 @@ function TooltipsOverlay:render(dc)
234342 local height = vp .max_y
235343 local bottomright = {x = topleft .x + width , y = topleft .y + height , z = topleft .z }
236344
237- local units = dfhack .units .getUnitsInBox (topleft , bottomright ) or {}
238- if # units == 0 then return end
345+ local units = dfhack .units .getUnitsInBox (topleft , bottomright )
346+ if not units or # units == 0 then return end
239347
240348 local oneTileOffset = GetScreenCoordinates ({x = topleft .x + 1 , y = topleft .y + 1 , z = topleft .z + 0 })
241349 local pen = COLOR_WHITE
242350
351+ local shortenings = config .job_shortenings
243352 local used_tiles = {}
244353 for i = # units , 1 , - 1 do
245354 local unit = units [i ]
@@ -252,7 +361,9 @@ function TooltipsOverlay:render(dc)
252361 local pos = xyz2pos (dfhack .units .getPosition (unit ))
253362 if not pos then goto continue end
254363
255- local txt = table.concat ({happiness , job }, " " )
364+ local txt = (happiness and job and happiness .. " " .. job )
365+ or happiness
366+ or job
256367
257368 local scrPos = GetScreenCoordinates (pos )
258369 local y = scrPos .y - 1 -- subtract 1 to move the text over the heads
0 commit comments