Fix mouse-selection in listboxes

Commit d355ef4030 removed a seemingly unnecessary modification of the
global variable grd_curcanv->cv_font, after eliminating all local reads
of it.  However, a non-local read, buried in listbox_mouse, depended on
grd_curcanv->cv_font being set to a MEDIUM font.  After that commit,
grd_curcanv->cv_font retained its prior value, which is not a MEDIUM
font.  This caused listbox_mouse to compute an incorrect height of the
lines in the listbox, which manifested as the game choosing the wrong
line when the mouse is clicked in the listbox.

Fix the problem by explicitly using MEDIUM3_FONT, since that was
usually the value left in grd_curcanv->cv_font prior to that commit.  In
some cases, a different MEDIUM font would be left there, but all the
MEDIUM fonts have the same height, so they are interchangeable for this
purpose.

Reported-by: Q3BFG10K <https://github.com/dxx-rebirth/dxx-rebirth/issues/498>
Fixes: d355ef4030 ("Pass font to various drawing functions")
This commit is contained in:
Kp 2020-04-04 19:30:23 +00:00
parent 23ebf27554
commit d197ba42c3
3 changed files with 42 additions and 27 deletions

View file

@ -293,6 +293,7 @@ void gr_printt(grs_canvas &, const grs_font &, int x, int y, const char *format,
#define gr_printf(A1,A2,A3,A4,F,...) dxx_call_printf_checked(gr_printfs,gr_string,(A1,A2,A3,A4),(F),##__VA_ARGS__)
#define gr_uprintf(A1,A2,A3,A4,F,...) dxx_call_printf_checked(gr_printfus,gr_ustring,(A1,A2,A3,A4),(F),##__VA_ARGS__)
std::pair<const char *, unsigned> gr_get_string_wrap(const grs_font &, const char *s, unsigned limit);
int gr_get_string_height(const grs_font &cv_font, unsigned lines);
void gr_get_string_size(const grs_font &, const char *s, int *string_width, int *string_height, int *average_width);
void gr_get_string_size(const grs_font &, const char *s, int *string_width, int *string_height, int *average_width, const unsigned max_chars_per_line);

View file

@ -771,6 +771,12 @@ void gr_ustring(grs_canvas &canvas, const grs_font &cv_font, const int x, const
gr_ustring_mono(canvas, cv_font, x, y, s);
}
int gr_get_string_height(const grs_font &cv_font, const unsigned lines)
{
const auto fontscale_y = FONTSCALE_Y(cv_font.ft_h);
return static_cast<int>(fontscale_y + (lines * (fontscale_y + FSPACY(1))));
}
void gr_get_string_size(const grs_font &cv_font, const char *s, int *const string_width, int *const string_height, int *const average_width)
{
gr_get_string_size(cv_font, s, string_width, string_height, average_width, UINT_MAX);
@ -815,10 +821,7 @@ void gr_get_string_size(const grs_font &cv_font, const char *s, int *const strin
if (string_width)
*string_width = std::max(longest_width, string_width_f);
if (string_height)
{
const auto fontscale_y = FONTSCALE_Y(cv_font.ft_h);
*string_height = static_cast<int>(fontscale_y + (lines * (fontscale_y + FSPACY(1))));
}
*string_height = gr_get_string_height(cv_font, lines);
}
std::pair<const char *, unsigned> gr_get_string_wrap(const grs_font &cv_font, const char *s, unsigned limit)

View file

@ -1753,31 +1753,41 @@ static void update_scroll_position(listbox *lb)
static window_event_result listbox_mouse(window *, const d_event &event, listbox *lb, int button)
{
int mx, my, mz, x1, x2, y1, y2;
switch (button)
{
case MBTN_LEFT:
{
if (lb->mouse_state)
{
int mx, my, mz;
mouse_get_pos(&mx, &my, &mz);
const auto &&line_spacing = LINE_SPACING(*grd_curcanv->cv_font, *GAME_FONT);
for (int i = lb->first_item; i < lb->first_item + lb->items_on_screen; ++i)
{
if (i >= lb->nitems)
break;
int h;
gr_get_string_size(*grd_curcanv->cv_font, lb->item[i], nullptr, &h, nullptr);
x1 = lb->box_x;
x2 = lb->box_x + lb->box_w;
y1 = (i - lb->first_item) * line_spacing + lb->box_y;
y2 = y1+h;
if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
lb->citem = i;
return window_event_result::handled;
}
}
const int x1 = lb->box_x;
if (mx <= x1)
break;
const int x2 = x1 + lb->box_w;
if (mx >= x2)
break;
const int by = lb->box_y;
if (my <= by)
break;
const int my_relative_by = my - by;
const auto &&line_spacing = LINE_SPACING(*MEDIUM3_FONT, *GAME_FONT);
if (line_spacing < 1)
break;
const int idx_relative_first_visible_item = my_relative_by / line_spacing;
const auto first_visible_item = lb->first_item;
const auto nitems = lb->nitems;
const auto last_visible_item = std::min(first_visible_item + lb->items_on_screen, nitems);
if (idx_relative_first_visible_item >= last_visible_item)
break;
const int px_within_item = my_relative_by % static_cast<int>(line_spacing);
const int h = gr_get_string_height(*MEDIUM3_FONT, 1);
if (px_within_item >= h)
break;
const int idx_absolute_item = idx_relative_first_visible_item + first_visible_item;
if (idx_absolute_item >= nitems)
break;
lb->citem = idx_absolute_item;
}
else if (event.type == EVENT_MOUSE_BUTTON_UP)
{
@ -1786,12 +1796,13 @@ static window_event_result listbox_mouse(window *, const d_event &event, listbox
if (lb->citem < 0)
return window_event_result::ignored;
int mx, my, mz;
mouse_get_pos(&mx, &my, &mz);
gr_get_string_size(*grd_curcanv->cv_font, lb->item[lb->citem], nullptr, &h, nullptr);
x1 = lb->box_x;
x2 = lb->box_x + lb->box_w;
y1 = (lb->citem - lb->first_item) * LINE_SPACING(*grd_curcanv->cv_font, *GAME_FONT) + lb->box_y;
y2 = y1+h;
gr_get_string_size(*MEDIUM3_FONT, lb->item[lb->citem], nullptr, &h, nullptr);
const int x1 = lb->box_x;
const int x2 = lb->box_x + lb->box_w;
const int y1 = (lb->citem - lb->first_item) * LINE_SPACING(*MEDIUM3_FONT, *GAME_FONT) + lb->box_y;
const int y2 = y1 + h;
if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) )
{
// Tell callback, if it wants to close it will return window_event_result::close