26 #include <SDL2/SDL_rect.h>
29 #define DBG_FT LOG_STREAM(debug, log_font)
30 #define LOG_FT LOG_STREAM(info, log_font)
35 static const int text_width = 400;
36 static const double height_fudge = 0.95;
40 tooltip(
const SDL_Rect& r,
const std::string&
msg,
const std::string& act =
"");
46 bool label_initialized =
false;
49 void update_label_pos();
55 DBG_FT <<
"created tooltip for " << origin <<
" at " <<
loc;
58 void tooltip::init_label()
60 const color_t bgcolor {0,0,0,192};
64 label.set_font_size(font_size);
66 label.set_width(text_width);
67 label.set_height(1000000);
69 label.set_bg_color(bgcolor);
72 label.clear_texture();
73 label.create_texture();
76 int new_text_width = text_width *
static_cast<float>(lsize.y)/
game_canvas.h;
87 bool wont_fit =
false;
92 DBG_FT <<
"lsize.x,y = " << lsize.x <<
"," << lsize.y <<
", new_text_width = " << new_text_width;
94 label.set_width(new_text_width);
95 label.clear_texture();
96 label.create_texture();
98 lsize =
label.get_draw_size();
99 DBG_FT <<
"new label lsize.x,y = " << lsize.x <<
"," << lsize.y;
103 new_text_width *= 1.3;
107 label_initialized =
true;
110 void tooltip::update_label_pos()
115 loc = {0, 0, lsize.x, lsize.y};
117 DBG_FT <<
"\nupdate_label_pos() Start: loc = " <<
loc.
x <<
"," <<
loc.
y <<
" origin = " << origin.x <<
"," << origin.y;
119 if(origin.y >
loc.h) {
122 DBG_FT <<
"\tAbove: loc = " <<
loc.
x <<
"," <<
loc.
y <<
" origin = " << origin.x <<
"," << origin.y;
123 }
else if((origin.y + origin.h +
loc.h) <=
game_canvas.h*height_fudge) {
125 loc.
y = origin.y + origin.h;
126 DBG_FT <<
"\tBelow: loc = " <<
loc.
x <<
"," <<
loc.
y <<
" origin = " << origin.x <<
"," << origin.y;
127 }
else if(((origin.y + origin.h/2 -
loc.h/2) >= 0) &&
128 ((origin.y + origin.h/2 +
loc.h/2) <=
game_canvas.h*height_fudge)) {
130 loc.
y = origin.y + origin.h/2 -
loc.h/2;
131 DBG_FT <<
"\tCenter: loc = " <<
loc.
x <<
"," <<
loc.
y <<
" origin = " << origin.x <<
"," << origin.y;
135 DBG_FT <<
"\tScreen Center: loc = " <<
loc.
x <<
"," <<
loc.
y <<
" origin = " << origin.x <<
"," << origin.y;
139 DBG_FT <<
"\tToo big: loc = " <<
loc.
x <<
"," <<
loc.
y <<
" origin = " << origin.x <<
"," << origin.y;
142 DBG_FT <<
"\tBefore x adjust: loc.x,y,w,h = " <<
loc.
x <<
"," <<
loc.
y <<
"," <<
loc.w <<
"," <<
loc.h <<
" origin = " << origin.
x <<
"," << origin.y;
152 DBG_FT <<
"\tFinal: loc.x,y,w,h = " <<
loc.
x <<
"," <<
loc.
y <<
"," <<
loc.w <<
"," <<
loc.h <<
" origin = " << origin.
x <<
"," << origin.y;
157 std::map<int, tooltip>
tips;
158 int active_tooltip = 0;
173 if(!active_tooltip) {
176 DBG_FT <<
"clearing active tooltip " << active_tooltip;
177 tips.at(active_tooltip).label.undraw();
187 current_manager =
this;
195 current_manager =
nullptr;
200 if(!active_tooltip) {
204 if(!
tip.label_initialized) {
209 tip.label.update(std::chrono::steady_clock::now());
215 if(!active_tooltip) {
219 if(!
tip.loc.overlaps(region)) {
229 if(!active_tooltip) {
232 return tips.at(active_tooltip).loc;
238 LOG_FT <<
"clearing all tooltips";
245 for(
auto i =
tips.begin();
i !=
tips.end(); ) {
246 if(
i->second.origin.overlaps(r)) {
247 DBG_FT <<
"clearing tip " <<
i->first <<
" at "
248 <<
i->second.origin <<
" overlapping " << r;
250 if (
i->first == active_tooltip) {
251 i->second.label.undraw();
265 if (it ==
tips.end() )
return false;
267 if(
tip.message == message &&
tip.origin == origin) {
270 if(
tip.message != message) {
271 LOG_FT <<
"updating tooltip " <<
id <<
" message";
272 tip.message = message;
276 if(
tip.origin != origin) {
277 DBG_FT <<
"updating tooltip " <<
id <<
" origin " << origin;
279 tip.update_label_pos();
287 DBG_FT <<
"removing tooltip " <<
id;
288 if(
id == active_tooltip) {
294 int add_tooltip(
const SDL_Rect& origin,
const std::string& message,
const std::string& action)
299 if(
tip.origin == origin &&
tip.message == message &&
tip.action == action) {
303 DBG_FT <<
"adding tooltip for " << origin;
308 int id = tooltip_id++;
309 tips.try_emplace(
id, origin, message, action);
316 if(!current_manager) {
317 throw game::error(
"trying to show tooltip with no tooltip manager");
324 if(active_tooltip ==
id) {
328 LOG_FT <<
"showing tip " <<
id <<
" for " <<
tip.origin;
331 tip.label.update(std::chrono::steady_clock::now());
337 point mouseloc{mousex, mousey};
339 if(
tip.origin.contains(mouseloc)) {
346 LOG_FT <<
"clearing tooltip because none hovered";
353 for(
auto& [
id,
tip] :
tips) { (void)
id;
354 if(!
tip.action.empty() &&
tip.origin.contains(mousex, mousey)) {
@ border
The border of the map.
std::string label
What to show in the filter's drop-down list.
std::string tooltip
Shown when hovering over an entry in the filter's drop-down list.
std::string id
Text to match against addon_info.tags()
Standard logging facilities (interface).
void raise_drawable(top_level_drawable *tld)
Raise a TLD to the top of the drawing stack.
const color_t NORMAL_COLOR
static std::unique_ptr< tooltip > tip
std::vector< game_tip > tips
void show_help(const std::string &show_topic)
Open the help browser, show topic with id show_topic.
rect game_canvas()
The game canvas area, in drawing coordinates.
std::string::const_iterator iterator
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
The basic class for representing 8-bit RGB or RGBA colour values.
Base class for all the errors encountered by the engine.
An abstract description of a rectangle with integer coordinates.