1
0
mirror of https://github.com/OpenTTD/OpenTTD synced 2025-12-10 06:52:05 +01:00

Fix: Drop down scrolling broken for mixed-height items. (#14840)

This commit is contained in:
Peter Nelson
2025-12-06 09:15:55 +00:00
committed by GitHub
parent 06d3ae7381
commit 22569515df

View File

@@ -8,6 +8,7 @@
/** @file dropdown.cpp Implementation of the dropdown widget. */ /** @file dropdown.cpp Implementation of the dropdown widget. */
#include "stdafx.h" #include "stdafx.h"
#include "core/backup_type.hpp"
#include "dropdown_type.h" #include "dropdown_type.h"
#include "dropdown_func.h" #include "dropdown_func.h"
#include "strings_func.h" #include "strings_func.h"
@@ -205,8 +206,9 @@ struct DropdownWindow : Window {
this->GetWidget<NWidgetStacked>(WID_DM_SHOW_SCROLL)->SetDisplayedPlane(list_dim.height > widget_dim.height ? 0 : SZSP_NONE); this->GetWidget<NWidgetStacked>(WID_DM_SHOW_SCROLL)->SetDisplayedPlane(list_dim.height > widget_dim.height ? 0 : SZSP_NONE);
/* Capacity is the average number of items visible */ /* Capacity is the average number of items visible */
this->vscroll->SetCapacity((widget_dim.height - WidgetDimensions::scaled.dropdownlist.Vertical()) * this->list.size() / list_dim.height); this->vscroll->SetCapacity(widget_dim.height - WidgetDimensions::scaled.dropdownlist.Vertical());
this->vscroll->SetCount(this->list.size()); this->vscroll->SetStepSize(list_dim.height / this->list.size());
this->vscroll->SetCount(list_dim.height);
/* If the dropdown is positioned above the parent widget, start selection at the bottom. */ /* If the dropdown is positioned above the parent widget, start selection at the bottom. */
if (this->position.y < button_rect.top && list_dim.height > widget_dim.height) this->vscroll->UpdatePosition(INT_MAX); if (this->position.y < button_rect.top && list_dim.height > widget_dim.height) this->vscroll->UpdatePosition(INT_MAX);
@@ -233,23 +235,22 @@ struct DropdownWindow : Window {
if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return false; if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return false;
const Rect &r = this->GetWidget<NWidgetBase>(WID_DM_ITEMS)->GetCurrentRect().Shrink(WidgetDimensions::scaled.dropdownlist).Shrink(WidgetDimensions::scaled.dropdowntext, RectPadding::zero); const Rect &r = this->GetWidget<NWidgetBase>(WID_DM_ITEMS)->GetCurrentRect().Shrink(WidgetDimensions::scaled.dropdownlist).Shrink(WidgetDimensions::scaled.dropdowntext, RectPadding::zero);
int y = _cursor.pos.y - this->top - r.top; int click_y = _cursor.pos.y - this->top - r.top;
int pos = this->vscroll->GetPosition(); int y = -this->vscroll->GetPosition();
int y_end = r.Height();
for (const auto &item : this->list) { for (const auto &item : this->list) {
/* Skip items that are scrolled up */
if (--pos >= 0) continue;
int item_height = item->Height(); int item_height = item->Height();
if (y < item_height) { /* Skip items that are scrolled up */
if (y > y_end) break;
if (click_y >= y && click_y < y + item_height) {
if (item->masked || !item->Selectable()) return false; if (item->masked || !item->Selectable()) return false;
result = item->result; result = item->result;
click_result = item->OnClick(r.WithY(0, item_height - 1), {_cursor.pos.x - this->left, y}); click_result = item->OnClick(r.WithY(0, item_height - 1), {_cursor.pos.x - this->left, click_y - y});
return true; return true;
} }
y += item_height;
y -= item_height;
} }
return false; return false;
@@ -262,16 +263,25 @@ struct DropdownWindow : Window {
Colours colour = this->GetWidget<NWidgetCore>(widget)->colour; Colours colour = this->GetWidget<NWidgetCore>(widget)->colour;
Rect ir = r.Shrink(WidgetDimensions::scaled.dropdownlist); Rect ir = r.Shrink(WidgetDimensions::scaled.dropdownlist);
int y = ir.top;
int pos = this->vscroll->GetPosition(); /* Setup a clipping rectangle... */
DrawPixelInfo tmp_dpi;
if (!FillDrawPixelInfo(&tmp_dpi, ir)) return;
/* ...but keep coordinates relative to the window. */
tmp_dpi.left += ir.left;
tmp_dpi.top += ir.top;
AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
int y = -this->vscroll->GetPosition();
int y_end = ir.Height();
for (const auto &item : this->list) { for (const auto &item : this->list) {
int item_height = item->Height(); int item_height = item->Height();
/* Skip items that are scrolled up */ /* Skip items that are scrolled up */
if (--pos >= 0) continue; if (y > y_end) break;
if (y > -item_height) {
if (y + item_height - 1 <= ir.bottom) { Rect full = ir.Translate(0, y).WithHeight(item_height);
Rect full = ir.WithY(y, y + item_height - 1);
bool selected = (this->selected_result == item->result) && item->Selectable(); bool selected = (this->selected_result == item->result) && item->Selectable();
if (selected) GfxFillRect(full, PC_BLACK); if (selected) GfxFillRect(full, PC_BLACK);