diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -501,8 +501,8 @@ public: break; case WID_AP_AIRPORT_LIST: { - int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget(widget)->pos_y) / this->line_height; - if (num_clicked >= this->vscroll->GetCount()) break; + int num_clicked = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget); + if (num_clicked == INT_MAX) break; const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); break; diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -458,10 +458,10 @@ struct DepotWindow : Window { } ym = y % this->resize.step_height; - uint row = y / this->resize.step_height; - if (row >= this->vscroll->GetCapacity()) return MODE_ERROR; + int row = this->vscroll->GetScrolledRowFromWidget(y, this, WID_D_MATRIX); + if (row == INT_MAX) return MODE_ERROR; - uint pos = ((row + this->vscroll->GetPosition()) * this->num_columns) + xt; + uint pos = (row * this->num_columns) + xt; if (this->vehicle_list.size() + this->wagon_list.size() <= pos) { /* Clicking on 'line' / 'block' without a vehicle */ diff --git a/src/game/game_gui.cpp b/src/game/game_gui.cpp --- a/src/game/game_gui.cpp +++ b/src/game/game_gui.cpp @@ -267,13 +267,13 @@ struct GSConfigWindow : public Window { break; case WID_GSC_SETTINGS: { - Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero); - int num = (pt.y - r.top) / this->line_height + this->vscroll->GetPosition(); - if (num >= (int)this->visible_settings.size()) break; + auto it = this->vscroll->GetScrolledItemFromWidget(this->visible_settings, pt.y, this, widget); + if (it == this->visible_settings.end()) break; - const ScriptConfigItem &config_item = *this->visible_settings[num]; + const ScriptConfigItem &config_item = **it; if (!this->IsEditableItem(config_item)) return; + int num = it - this->visible_settings.begin(); if (this->clicked_row != num) { this->CloseChildWindows(WC_QUERY_STRING); HideDropDownMenu(this); @@ -283,6 +283,7 @@ struct GSConfigWindow : public Window { bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0; + Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero); int x = pt.x - r.left; if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x; diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -964,12 +964,9 @@ struct SpriteAlignerWindow : Window { break; case WID_SA_LIST: { - const NWidgetBase *nwid = this->GetWidget(widget); - int step_size = nwid->resize_y; - - uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size; - if (i < _newgrf_debug_sprite_picker.sprites.size()) { - SpriteID spr = _newgrf_debug_sprite_picker.sprites[i]; + auto it = this->vscroll->GetScrolledItemFromWidget(_newgrf_debug_sprite_picker.sprites, pt.y, this, widget); + if (it != _newgrf_debug_sprite_picker.sprites.end()) { + SpriteID spr = *it; if (GetSpriteType(spr) == SpriteType::Normal) this->current_sprite = spr; } this->SetDirty(); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -339,8 +339,10 @@ struct NewGRFParametersWindow : public W case WID_NP_BACKGROUND: { if (!this->editable) break; - uint num = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NP_BACKGROUND); - if (num >= this->vscroll->GetCount()) break; + auto it = this->vscroll->GetScrolledItemFromWidget(this->grf_config->param_info, pt.y, this, WID_NP_BACKGROUND); + if (it == this->grf_config->param_info.end()) break; + + uint num = it - this->grf_config->param_info.begin(); if (this->clicked_row != num) { this->CloseChildWindows(WC_QUERY_STRING); HideDropDownMenu(this); @@ -352,7 +354,7 @@ struct NewGRFParametersWindow : public W int x = pt.x - r.left; if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x; - GRFParameterInfo *par_info = (num < this->grf_config->param_info.size()) ? this->grf_config->param_info[num] : nullptr; + GRFParameterInfo *par_info = *it; if (par_info == nullptr) par_info = GetDummyParameterInfo(num); /* One of the arrows is clicked */ diff --git a/src/object_gui.cpp b/src/object_gui.cpp --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -517,10 +517,10 @@ public: { switch (GB(widget, 0, 16)) { case WID_BO_CLASS_LIST: { - int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget(widget)->pos_y) / this->line_height; - if (num_clicked >= (int)this->object_classes.size()) break; + auto it = this->vscroll->GetScrolledItemFromWidget(this->object_classes, widget, this, pt.y); + if (it == this->object_classes.end()) break; - this->SelectOtherClass(this->object_classes[num_clicked]); + this->SelectOtherClass(*it); this->SelectFirstAvailableObject(false); break; } diff --git a/src/order_gui.cpp b/src/order_gui.cpp --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -560,14 +560,10 @@ private: */ VehicleOrderID GetOrderFromPt(int y) { - NWidgetBase *nwid = this->GetWidget(WID_O_ORDER_LIST); - uint sel = (y - nwid->pos_y - WidgetDimensions::scaled.framerect.top) / nwid->resize_y; // Selected line in the WID_O_ORDER_LIST panel. - - if (sel >= this->vscroll->GetCapacity()) return INVALID_VEH_ORDER_ID; - - sel += this->vscroll->GetPosition(); - - return (sel <= vehicle->GetNumOrders()) ? sel : INVALID_VEH_ORDER_ID; + int sel = this->vscroll->GetScrolledRowFromWidget(y, this, WID_O_ORDER_LIST, WidgetDimensions::scaled.framerect.top); + if (sel == INT_MAX) return INVALID_VEH_ORDER_ID; + assert(IsInsideBS(sel, 0, vehicle->GetNumOrders())); + return sel; } /** diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -425,13 +425,13 @@ struct ScriptSettingsWindow : public Win { switch (widget) { case WID_SCRS_BACKGROUND: { - Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero); - int num = (pt.y - r.top) / this->line_height + this->vscroll->GetPosition(); - if (num >= (int)this->visible_settings.size()) break; + auto it = this->vscroll->GetScrolledItemFromWidget(this->visible_settings, pt.y, this, widget); + if (it == this->visible_settings.end()) break; - const ScriptConfigItem &config_item = *this->visible_settings[num]; + const ScriptConfigItem &config_item = **it; if (!this->IsEditableItem(config_item)) return; + int num = it - this->visible_settings.begin(); if (this->clicked_row != num) { this->CloseChildWindows(WC_QUERY_STRING); HideDropDownMenu(this); @@ -441,6 +441,7 @@ struct ScriptSettingsWindow : public Win bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0; + Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero); int x = pt.x - r.left; if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x; diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -215,13 +215,10 @@ struct TimetableWindow : Window { int GetOrderFromTimetableWndPt(int y, const Vehicle *v) { - uint sel = (y - this->GetWidget(WID_VT_TIMETABLE_PANEL)->pos_y - WidgetDimensions::scaled.framerect.top) / FONT_HEIGHT_NORMAL; - - if (sel >= this->vscroll->GetCapacity()) return INVALID_ORDER; - - sel += this->vscroll->GetPosition(); - - return (sel < v->GetNumOrders() * 2u) ? sel : INVALID_ORDER; + int sel = this->vscroll->GetScrolledRowFromWidget(y, this, WID_VT_TIMETABLE_PANEL, WidgetDimensions::scaled.framerect.top); + if (sel == INT_MAX) return INVALID_ORDER; + assert(IsInsideBS(sel, 0, v->GetNumOrders() * 2)); + return sel; } /**