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:
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user