Fix #10811: Crash getting row from non-resizable widget. (#10833)

GetScrolled*FromWidget took line height from the widget's resize_y value,
however not all widgets are resizable, resulting in a division-by-zero.

Allow passing line height explicitly in cases where a widget is not
resizable.
This commit is contained in:
PeterN 2023-05-15 18:57:50 +01:00 committed by GitHub
parent e4fd9d41d3
commit 40f567d464
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 8 additions and 6 deletions

View File

@ -501,7 +501,7 @@ public:
break;
case WID_AP_AIRPORT_LIST: {
int num_clicked = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
int num_clicked = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget, 0, this->line_height);
if (num_clicked == INT_MAX) break;
const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked);
if (as->IsAvailable()) this->SelectOtherAirport(num_clicked);

View File

@ -2365,11 +2365,12 @@ void NWidgetViewport::UpdateViewportCoordinates(Window *w)
* @param w The window the click was in.
* @param widget Widget number of the widget clicked in.
* @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0.
* @param line_height Height of a single row. A negative value means using the vertical resize step of the widget.
* @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned.
*/
int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding) const
int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding, int line_height) const
{
uint pos = w->GetRowFromWidget(clickpos, widget, padding, -1);
uint pos = w->GetRowFromWidget(clickpos, widget, padding, line_height);
if (pos != INT_MAX) pos += this->GetPosition();
return (pos >= this->GetCount()) ? INT_MAX : pos;
}

View File

@ -788,7 +788,7 @@ public:
}
}
int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0) const;
int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const;
/**
* Return an iterator pointing to the element of a scrolled widget that a user clicked in.
@ -797,13 +797,14 @@ public:
* @param w The window the click was in.
* @param widget Widget number of the widget clicked in.
* @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0.
* @param line_height Height of a single row. A negative value means using the vertical resize step of the widget.
* @return Iterator to the element clicked at. If clicked at a wrong position, returns as interator to the end of the container.
*/
template <typename Tcontainer>
typename Tcontainer::iterator GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window * const w, int widget, int padding = 0) const
typename Tcontainer::iterator GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const
{
assert(this->GetCount() == container.size()); // Scrollbar and container size must match.
int row = this->GetScrolledRowFromWidget(clickpos, w, widget, padding);
int row = this->GetScrolledRowFromWidget(clickpos, w, widget, padding, line_height);
if (row == INT_MAX) return std::end(container);
typename Tcontainer::iterator it = std::begin(container);