mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Add and use GetScrolledItemFromWidget to get a list item.
This function returns an iterator, either to the selected item or the container's end. This makes handling the result more robust as indices are not used.pull/10815/head
parent
86e5dfce3d
commit
941dbadf9e
|
@ -617,12 +617,11 @@ public:
|
|||
} else {
|
||||
click_side = 1;
|
||||
}
|
||||
uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget);
|
||||
size_t engine_count = this->engines[click_side].size();
|
||||
|
||||
EngineID e = INVALID_ENGINE;
|
||||
if (i < engine_count) {
|
||||
const auto &item = this->engines[click_side][i];
|
||||
const auto it = this->vscroll[click_side]->GetScrolledItemFromWidget(this->engines[click_side], pt.y, this, widget);
|
||||
if (it != this->engines[click_side].end()) {
|
||||
const auto &item = *it;
|
||||
const Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL);
|
||||
if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) {
|
||||
/* toggle folded flag on engine */
|
||||
|
|
|
@ -264,9 +264,9 @@ public:
|
|||
switch (widget) {
|
||||
default: break;
|
||||
case WID_BBS_BRIDGE_LIST: {
|
||||
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BBS_BRIDGE_LIST);
|
||||
if (i < this->bridges->size()) {
|
||||
this->BuildBridge(i);
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(*this->bridges, pt.y, this, WID_BBS_BRIDGE_LIST);
|
||||
if (it != this->bridges->end()) {
|
||||
this->BuildBridge(it - this->bridges->begin());
|
||||
this->Close();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1588,11 +1588,10 @@ struct BuildVehicleWindow : Window {
|
|||
break;
|
||||
|
||||
case WID_BV_LIST: {
|
||||
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST);
|
||||
size_t num_items = this->eng_list.size();
|
||||
EngineID e = INVALID_ENGINE;
|
||||
if (i < num_items) {
|
||||
const auto &item = this->eng_list[i];
|
||||
const auto it = this->vscroll->GetScrolledItemFromWidget(this->eng_list, pt.y, this, WID_BV_LIST);
|
||||
if (it != this->eng_list.end()) {
|
||||
const auto &item = *it;
|
||||
const Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL);
|
||||
if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) {
|
||||
/* toggle folded flag on engine */
|
||||
|
|
|
@ -999,13 +999,9 @@ struct PaymentRatesGraphWindow : BaseGraphWindow {
|
|||
}
|
||||
|
||||
case WID_CPR_MATRIX: {
|
||||
uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX);
|
||||
if (row >= this->vscroll->GetCount()) return;
|
||||
|
||||
for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
|
||||
if (row-- > 0) continue;
|
||||
|
||||
ToggleBit(_legend_excluded_cargo, cs->Index());
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(_sorted_standard_cargo_specs, pt.y, this, WID_CPR_MATRIX);
|
||||
if (it != _sorted_standard_cargo_specs.end()) {
|
||||
ToggleBit(_legend_excluded_cargo, (*it)->Index());
|
||||
this->UpdateExcludedData();
|
||||
this->SetDirty();
|
||||
break;
|
||||
|
|
|
@ -691,10 +691,11 @@ public:
|
|||
break;
|
||||
|
||||
case WID_GL_LIST_GROUP: { // Matrix Group
|
||||
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
|
||||
if (id_g >= this->groups.size()) return;
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
if (it == this->groups.end()) return;
|
||||
|
||||
if (groups[id_g]->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) {
|
||||
size_t id_g = it - this->groups.begin();
|
||||
if ((*it)->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) {
|
||||
/* The group has children, check if the user clicked the fold / unfold button. */
|
||||
NWidgetCore *group_display = this->GetWidget<NWidgetCore>(widget);
|
||||
int x = _current_text_dir == TD_RTL ?
|
||||
|
@ -731,10 +732,10 @@ public:
|
|||
}
|
||||
|
||||
case WID_GL_LIST_VEHICLE: { // Matrix Vehicle
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE);
|
||||
if (id_v >= this->vehgroups.size()) return; // click out of list bound
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
|
||||
if (it == this->vehgroups.end()) return; // click out of list bound
|
||||
|
||||
const GUIVehicleGroup &vehgroup = this->vehgroups[id_v];
|
||||
const GUIVehicleGroup &vehgroup = *it;
|
||||
|
||||
const Vehicle *v = nullptr;
|
||||
|
||||
|
@ -845,8 +846,8 @@ public:
|
|||
break;
|
||||
|
||||
case WID_GL_LIST_GROUP: { // Matrix group
|
||||
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = id_g >= this->groups.size() ? INVALID_GROUP : this->groups[id_g]->index;
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = it == this->groups.end() ? INVALID_GROUP : (*it)->index;
|
||||
|
||||
if (this->group_sel != new_g && g->parent != new_g) {
|
||||
Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, new_g, {});
|
||||
|
@ -878,8 +879,8 @@ public:
|
|||
this->group_over = INVALID_GROUP;
|
||||
this->SetDirty();
|
||||
|
||||
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index;
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = it == this->groups.end() ? NEW_GROUP : (*it)->index;
|
||||
|
||||
Command<CMD_ADD_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr, new_g, vindex, _ctrl_pressed || this->grouping == GB_SHARED_ORDERS);
|
||||
break;
|
||||
|
@ -891,10 +892,10 @@ public:
|
|||
this->group_over = INVALID_GROUP;
|
||||
this->SetDirty();
|
||||
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE);
|
||||
if (id_v >= this->vehgroups.size()) return; // click out of list bound
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
|
||||
if (it == this->vehgroups.end()) return; // click out of list bound
|
||||
|
||||
const GUIVehicleGroup &vehgroup = this->vehgroups[id_v];
|
||||
const GUIVehicleGroup &vehgroup = *it;
|
||||
switch (this->grouping) {
|
||||
case GB_NONE: {
|
||||
const Vehicle *v = vehgroup.GetSingleVehicle();
|
||||
|
@ -1023,8 +1024,8 @@ public:
|
|||
break;
|
||||
|
||||
case WID_GL_LIST_GROUP: { // ... the list of custom groups.
|
||||
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
|
||||
new_group_over = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index;
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
new_group_over = it == this->groups.end() ? NEW_GROUP : (*it)->index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -632,9 +632,9 @@ public:
|
|||
}
|
||||
|
||||
case WID_DPI_MATRIX_WIDGET: {
|
||||
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_DPI_MATRIX_WIDGET);
|
||||
if (y != INT_MAX) { // Is it within the boundaries of available data?
|
||||
this->selected_type = this->list[y];
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->list, pt.y, this, WID_DPI_MATRIX_WIDGET);
|
||||
if (it != this->list.end()) { // Is it within the boundaries of available data?
|
||||
this->selected_type = *it;
|
||||
this->UpdateAvailability();
|
||||
|
||||
const IndustrySpec *indsp = GetIndustrySpec(this->selected_type);
|
||||
|
@ -1742,12 +1742,12 @@ public:
|
|||
break;
|
||||
|
||||
case WID_ID_INDUSTRY_LIST: {
|
||||
uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WidgetDimensions::scaled.framerect.top);
|
||||
if (p < this->industries.size()) {
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->industries, pt.y, this, WID_ID_INDUSTRY_LIST, WidgetDimensions::scaled.framerect.top);
|
||||
if (it != this->industries.end()) {
|
||||
if (_ctrl_pressed) {
|
||||
ShowExtraViewportWindow(this->industries[p]->location.tile);
|
||||
ShowExtraViewportWindow((*it)->location.tile);
|
||||
} else {
|
||||
ScrollMainWindowToTile(this->industries[p]->location.tile);
|
||||
ScrollMainWindowToTile((*it)->location.tile);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -799,11 +799,11 @@ public:
|
|||
|
||||
switch (widget) {
|
||||
case WID_NCL_MATRIX: {
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX);
|
||||
if (id_v >= this->content.size()) return; // click out of bounds
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->content, pt.y, this, WID_NCL_MATRIX);
|
||||
if (it == this->content.end()) return; // click out of bounds
|
||||
|
||||
this->selected = this->content[id_v];
|
||||
this->list_pos = id_v;
|
||||
this->selected = *it;
|
||||
this->list_pos = it - this->content.begin();
|
||||
|
||||
const NWidgetBase *checkbox = this->GetWidget<NWidgetBase>(WID_NCL_CHECKBOX);
|
||||
if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) {
|
||||
|
|
|
@ -746,9 +746,9 @@ public:
|
|||
break;
|
||||
|
||||
case WID_NG_MATRIX: { // Show available network games
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NG_MATRIX);
|
||||
this->server = (id_v < this->servers.size()) ? this->servers[id_v] : nullptr;
|
||||
this->list_pos = (server == nullptr) ? SLP_INVALID : id_v;
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->servers, pt.y, this, WID_NG_MATRIX);
|
||||
this->server = (it != this->servers.end()) ? *it : nullptr;
|
||||
this->list_pos = (server == nullptr) ? SLP_INVALID : it - this->servers.begin();
|
||||
this->SetDirty();
|
||||
|
||||
/* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */
|
||||
|
|
|
@ -1071,13 +1071,13 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
|
|||
case WID_NS_AVAIL_LIST: { // Select a non-active GRF.
|
||||
ResetObjectToPlace();
|
||||
|
||||
uint i = this->vscroll2->GetScrolledRowFromWidget(pt.y, this, WID_NS_AVAIL_LIST);
|
||||
auto it = this->vscroll2->GetScrolledItemFromWidget(this->avails, pt.y, this, WID_NS_AVAIL_LIST);
|
||||
this->active_sel = nullptr;
|
||||
CloseWindowByClass(WC_GRF_PARAMETERS);
|
||||
if (i < this->avails.size()) {
|
||||
if (this->avail_sel != this->avails[i]) CloseWindowByClass(WC_TEXTFILE);
|
||||
this->avail_sel = this->avails[i];
|
||||
this->avail_pos = i;
|
||||
if (it != this->avails.end()) {
|
||||
if (this->avail_sel != *it) CloseWindowByClass(WC_TEXTFILE);
|
||||
this->avail_sel = *it;
|
||||
this->avail_pos = it - this->avails.begin();
|
||||
}
|
||||
this->InvalidateData();
|
||||
if (click_count == 1) {
|
||||
|
@ -2123,10 +2123,10 @@ struct SavePresetWindow : public Window {
|
|||
{
|
||||
switch (widget) {
|
||||
case WID_SVP_PRESET_LIST: {
|
||||
uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SVP_PRESET_LIST);
|
||||
if (row < this->presets.size()) {
|
||||
this->selected = row;
|
||||
this->presetname_editbox.text.Assign(this->presets[row].c_str());
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->presets, pt.y, this, WID_SVP_PRESET_LIST);
|
||||
if (it != this->presets.end()) {
|
||||
this->selected = it - this->presets.begin();
|
||||
this->presetname_editbox.text.Assign(it->c_str());
|
||||
this->SetWidgetDirty(WID_SVP_PRESET_LIST);
|
||||
this->SetWidgetDirty(WID_SVP_EDITBOX);
|
||||
}
|
||||
|
|
|
@ -1454,9 +1454,9 @@ public:
|
|||
break;
|
||||
|
||||
case WID_BRAS_NEWST_LIST: {
|
||||
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST);
|
||||
if (y >= (int)this->station_classes.size()) return;
|
||||
StationClassID station_class_id = this->station_classes[y];
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->station_classes, pt.y, this, WID_BRAS_NEWST_LIST);
|
||||
if (it == this->station_classes.end()) return;
|
||||
StationClassID station_class_id = *it;
|
||||
if (_railstation.station_class != station_class_id) {
|
||||
StationClass *station_class = StationClass::Get(station_class_id);
|
||||
_railstation.station_class = station_class_id;
|
||||
|
|
|
@ -1533,9 +1533,9 @@ public:
|
|||
break;
|
||||
|
||||
case WID_BROS_NEWST_LIST: {
|
||||
int y = this->vscrollList->GetScrolledRowFromWidget(pt.y, this, WID_BROS_NEWST_LIST);
|
||||
if (y >= (int)this->roadstop_classes.size()) return;
|
||||
RoadStopClassID class_id = this->roadstop_classes[y];
|
||||
auto it = this->vscrollList->GetScrolledItemFromWidget(this->roadstop_classes, pt.y, this, WID_BROS_NEWST_LIST);
|
||||
if (it == this->roadstop_classes.end()) return;
|
||||
RoadStopClassID class_id = *it;
|
||||
if (_roadstop_gui_settings.roadstop_class != class_id && GetIfClassHasNewStopsByType(RoadStopClass::Get(class_id), roadStopType, _cur_roadtype)) {
|
||||
_roadstop_gui_settings.roadstop_class = class_id;
|
||||
RoadStopClass *rsclass = RoadStopClass::Get(_roadstop_gui_settings.roadstop_class);
|
||||
|
|
|
@ -235,10 +235,10 @@ struct SignListWindow : Window, SignList {
|
|||
{
|
||||
switch (widget) {
|
||||
case WID_SIL_LIST: {
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SIL_LIST, WidgetDimensions::scaled.framerect.top);
|
||||
if (id_v == INT_MAX) return;
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->signs, pt.y, this, WID_SIL_LIST, WidgetDimensions::scaled.framerect.top);
|
||||
if (it == this->signs.end()) return;
|
||||
|
||||
const Sign *si = this->signs[id_v];
|
||||
const Sign *si = *it;
|
||||
ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -507,10 +507,10 @@ public:
|
|||
{
|
||||
switch (widget) {
|
||||
case WID_STL_LIST: {
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST);
|
||||
if (id_v >= this->stations.size()) return; // click out of list bound
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->stations, pt.y, this, WID_STL_LIST);
|
||||
if (it == this->stations.end()) return; // click out of list bound
|
||||
|
||||
const Station *st = this->stations[id_v];
|
||||
const Station *st = *it;
|
||||
/* do not check HasStationInUse - it is slow and may be invalid */
|
||||
assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE);
|
||||
|
||||
|
|
|
@ -942,10 +942,10 @@ public:
|
|||
break;
|
||||
|
||||
case WID_TD_LIST: { // Click on Town Matrix
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_TD_LIST, WidgetDimensions::scaled.framerect.top);
|
||||
if (id_v >= this->towns.size()) return; // click out of town bounds
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->towns, pt.y, this, WID_TD_LIST, WidgetDimensions::scaled.framerect.top);
|
||||
if (it == this->towns.end()) return; // click out of town bounds
|
||||
|
||||
const Town *t = this->towns[id_v];
|
||||
const Town *t = *it;
|
||||
assert(t != nullptr);
|
||||
if (_ctrl_pressed) {
|
||||
ShowExtraViewportWindow(t->xy);
|
||||
|
|
|
@ -2024,10 +2024,10 @@ public:
|
|||
break;
|
||||
|
||||
case WID_VL_LIST: { // Matrix to show vehicles
|
||||
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VL_LIST);
|
||||
if (id_v >= this->vehgroups.size()) return; // click out of list bound
|
||||
auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_VL_LIST);
|
||||
if (it == this->vehgroups.end()) return; // click out of list bound
|
||||
|
||||
const GUIVehicleGroup &vehgroup = this->vehgroups[id_v];
|
||||
const GUIVehicleGroup &vehgroup = *it;
|
||||
switch (this->grouping) {
|
||||
case GB_NONE: {
|
||||
const Vehicle *v = vehgroup.GetSingleVehicle();
|
||||
|
|
|
@ -789,6 +789,28 @@ public:
|
|||
}
|
||||
|
||||
int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0) const;
|
||||
|
||||
/**
|
||||
* Return an iterator pointing to the element of a scrolled widget that a user clicked in.
|
||||
* @param container Container of elements represented by the scrollbar.
|
||||
* @param clickpos Vertical position of the mouse click (without taking scrolling into account).
|
||||
* @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.
|
||||
* @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
|
||||
{
|
||||
assert(this->GetCount() == container.size()); // Scrollbar and container size must match.
|
||||
int row = this->GetScrolledRowFromWidget(clickpos, w, widget, padding);
|
||||
if (row == INT_MAX) return std::end(container);
|
||||
|
||||
typename Tcontainer::iterator it = std::begin(container);
|
||||
std::advance(it, row);
|
||||
return it;
|
||||
}
|
||||
|
||||
EventState UpdateListPositionOnKeyPress(int &list_position, uint16 keycode) const;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue