improve tooltip placement on sidebar (#8908)

This commit is contained in:
white-haired-uncle 2024-07-30 18:27:27 -04:00 committed by GitHub
parent 64caa4acda
commit d74b4061fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 76 additions and 7 deletions

View file

@ -104,6 +104,11 @@ rect floating_label::get_bg_rect(const rect& text_rect) const
};
}
void floating_label::clear_texture()
{
tex_.reset();
}
bool floating_label::create_texture()
{
if(video::headless()) {

View file

@ -86,6 +86,8 @@ public:
*/
bool create_texture();
void clear_texture();
/** Return the size of the label in drawing coordinates */
SDL_Point get_draw_size() const
{

View file

@ -33,6 +33,7 @@ namespace {
static const int font_size = font::SIZE_SMALL;
static const int text_width = 400;
static const double height_fudge = 0.95; // An artificial "border" to keep tip text from crowding lower edge of viewing area
struct tooltip
{
@ -60,16 +61,56 @@ void tooltip::init_label()
rect game_canvas = video::game_canvas();
unsigned int border = 10;
rect huge;
huge.h=1000000;
huge.w=1000000;
label.set_font_size(font_size);
label.set_color(font::NORMAL_COLOR);
label.set_clip_rect(game_canvas);
label.set_width(text_width);
label.set_clip_rect(huge);
label.set_width(text_width); // If tooltip will be too tall for game_canvas, this could be scaled up appropriately
label.set_alignment(font::LEFT_ALIGN);
label.set_bg_color(bgcolor);
label.set_border_size(border);
label.create_texture();
point lsize = label.get_draw_size();
int new_text_width = text_width * static_cast<float>(lsize.y)/game_canvas.h; // If necessary, scale width to reduce height while preserving area of label
while((lsize.y > game_canvas.h*height_fudge) && (lsize.x < game_canvas.w)) {
// Scaling the tip to reduce height is hard, since making a texture wider is no guarantee that there will be fewer lines of text:
//
// This block of text is just
// as tall as the other one.
//
// This block of text is just as tall as the other
// one.
//
// Creating this over and over may not be the most efficient route, but it will work and will be quite rare (tip taller than screen).
bool wont_fit = false;
if(new_text_width>game_canvas.w) {
new_text_width=game_canvas.w;
wont_fit = true;
}
DBG_FT << "lsize.x,y = " << lsize.x << "," << lsize.y << ", new_text_width = " << new_text_width;
label.set_width(new_text_width);
label.clear_texture();
label.create_texture();
lsize = label.get_draw_size();
DBG_FT << "new label lsize.x,y = " << lsize.x << "," << lsize.y;
if(wont_fit) {
break;
}
new_text_width *= 1.3;
}
// I don't know if it's strictly necessary to create the texture yet again just to make sure the clip_rect is set to game_canvas
// but it seems like the safe course of action.
label.set_clip_rect(game_canvas);
label.clear_texture();
label.create_texture();
update_label_pos();
}
@ -80,21 +121,42 @@ void tooltip::update_label_pos()
point lsize = label.get_draw_size();
loc = {0, 0, lsize.x, lsize.y};
// See if there is enough room to fit it above the tip area
DBG_FT << "\nupdate_label_pos() Start: loc = " << loc.x << "," << loc.y << " origin = " << origin.x << "," << origin.y;
if(origin.y > loc.h) {
// There is enough room to fit it above the tip area
loc.y = origin.y - loc.h;
} else {
DBG_FT << "\tAbove: loc = " << loc.x << "," << loc.y << " origin = " << origin.x << "," << origin.y;
} else if((origin.y + origin.h + loc.h) <= game_canvas.h*height_fudge) {
// There is enough room to fit it below the tip area
loc.y = origin.y + origin.h;
DBG_FT << "\tBelow: loc = " << loc.x << "," << loc.y << " origin = " << origin.x << "," << origin.y;
} else if(((origin.y + origin.h/2 - loc.h/2) >= 0) &&
((origin.y + origin.h/2 + loc.h/2) <= game_canvas.h*height_fudge)) {
// There is enough room to center it at the tip area
loc.y = origin.y + origin.h/2 - loc.h/2;
DBG_FT << "\tCenter: loc = " << loc.x << "," << loc.y << " origin = " << origin.x << "," << origin.y;
} else if(loc.h <= game_canvas.h*0.95) {
// There is enough room to center it
loc.y = game_canvas.h/2 - loc.h/2;
DBG_FT << "\tScreen Center: loc = " << loc.x << "," << loc.y << " origin = " << origin.x << "," << origin.y;
} else {
// It doesn't fit
loc.y = 0;
DBG_FT << "\tToo big: loc = " << loc.x << "," << loc.y << " origin = " << origin.x << "," << origin.y;
}
DBG_FT << "\tBefore x adjust: loc.x,y,w,h = " << loc.x << "," << loc.y << "," << loc.w << "," << loc.h << " origin = " << origin.x << "," << origin.y;
// Try to keep it within the screen
loc.x = origin.x;
if(loc.x < 0) {
loc.x = 0;
} else if(loc.x + loc.w > game_canvas.w) {
if(loc.x + loc.w > game_canvas.w) {
loc.x = game_canvas.w - loc.w;
}
if(loc.x < 0) {
loc.x = 0;
}
DBG_FT << "\tFinal: loc.x,y,w,h = " << loc.x << "," << loc.y << "," << loc.w << "," << loc.h << " origin = " << origin.x << "," << origin.y;
label.set_position(loc.x, loc.y);
}