Skip to content

Commit 66d8d39

Browse files
authored
make possible to show specific stress/happiness levels; add config UI
1 parent 8d345a7 commit 66d8d39

File tree

1 file changed

+138
-27
lines changed

1 file changed

+138
-27
lines changed

gui/tooltips.lua

Lines changed: 138 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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
2041
end
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)
2362
end
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+
64133
function 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)
81190
end
82191

83192
local 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
91199
end
92200

93201
local 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)
96205
end
@@ -189,7 +298,6 @@ end
189298

190299
-- map coordinates -> interface layer coordinates
191300
local 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

Comments
 (0)