Go to the documentation of this file.
10 #include "../stdafx.h"
11 #include "../window_gui.h"
12 #include "../string_func.h"
13 #include "../strings_func.h"
14 #include "../window_func.h"
15 #include "../zoom_func.h"
16 #include "../timer/timer.h"
17 #include "../timer/timer_window.h"
22 #include "../safeguards.h"
25 static constexpr
NWidgetPart _nested_dropdown_menu_widgets[] = {
34 static WindowDesc _dropdown_desc(__FILE__, __LINE__,
38 std::begin(_nested_dropdown_menu_widgets), std::end(_nested_dropdown_menu_widgets)
48 bool drag_mode =
true;
77 assert(!this->list.empty());
83 this->GetWidget<NWidgetCore>(
WID_DM_ITEMS)->colour = wi_colour;
84 this->GetWidget<NWidgetCore>(
WID_DM_SCROLL)->colour = wi_colour;
92 void Close([[maybe_unused]]
int data = 0)
override
111 this->instant_close =
false;
124 if (desired.height < available_height)
return;
127 uint avg_height =
list.height / (uint)this->list.size();
130 desired.width = std::max(
list.width, desired.width - NWidgetScrollbar::GetVerticalDimension().width);
150 widget_dim.width = std::max<uint>(widget_dim.width, button_rect.
Width());
153 uint available_height_below = std::max(
GetMainViewBottom() - button_rect.bottom - 1, 0);
154 uint available_height_above = std::max(button_rect.top - 1 -
GetMainViewTop(), 0);
157 if (widget_dim.height > available_height_below && available_height_above > available_height_below) {
159 this->position.y = button_rect.top - widget_dim.height;
162 this->position.y = button_rect.bottom + 1;
165 this->position.x = (
_current_text_dir ==
TD_RTL) ? button_rect.right + 1 - (
int)widget_dim.width : button_rect.left;
167 this->items_dim = widget_dim;
172 this->vscroll->
SetCount(this->list.size());
175 if (this->position.y < button_rect.top && list_dim.height > widget_dim.height) this->vscroll->
UpdatePosition(INT_MAX);
183 Point OnInitialPosition([[maybe_unused]] int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]]
int window_number)
override
198 int y = _cursor.
pos.y - this->
top - r.top;
201 for (
const auto &item : this->list) {
203 if (--pos >= 0)
continue;
205 int item_height = item->Height();
207 if (y < item_height) {
208 if (item->masked || !item->Selectable())
return false;
209 value = item->result;
219 void DrawWidget(
const Rect &r,
WidgetID widget)
const override
223 Colours colour = this->GetWidget<NWidgetCore>(widget)->colour;
228 for (
const auto &item : this->list) {
229 int item_height = item->Height();
232 if (--pos >= 0)
continue;
234 if (y + item_height - 1 <= ir.bottom) {
235 Rect full{ir.left, y, ir.right, y + item_height - 1};
237 bool selected = (this->selected_result == item->result) && item->Selectable();
246 void OnClick([[maybe_unused]]
Point pt,
WidgetID widget, [[maybe_unused]]
int click_count)
override
251 this->click_delay = 4;
252 this->selected_result = item;
259 if (this->scrolling == 0)
return;
268 if (this->click_delay != 0 && --this->click_delay == 0) {
271 if (!this->persist) this->Close();
276 if (this->drag_mode) {
280 this->drag_mode =
false;
282 if (this->instant_close) this->Close();
285 this->click_delay = 2;
287 if (_cursor.
pos.y <= this->top + 2) {
289 this->scrolling = -1;
291 }
else if (_cursor.
pos.y >= this->top + this->height - 2) {
300 if (this->selected_result != item) {
301 this->selected_result = item;
309 this->list = std::move(
list);
312 this->
InitializePositionSize(this->position.x, this->position.y, this->nested_root->smallest_x, this->nested_root->smallest_y);
320 if (ddw !=
nullptr) ddw->ReplaceList(std::move(list));
331 for (
const auto &item : list) {
332 dim.height += item->Height();
333 dim.width = std::max(dim.width, item->Width());
354 new DropdownWindow(w, std::move(list), selected, button, wi_rect, instant_close, wi_colour, persist);
374 Rect wi_rect = nwi->GetCurrentRect();
375 Colours wi_colour = nwi->
colour;
392 ShowDropDownListAt(w, std::move(list), selected, button, wi_rect, wi_colour, instant_close, persist);
411 if (!
HasBit(hidden_mask, i)) {
412 list.push_back(std::make_unique<DropDownListStringItem>(strings[i], i,
HasBit(disabled_mask, i)));
416 if (!list.empty())
ShowDropDownList(w, std::move(list), selected, button, width);
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Dimensions (a width and height) of a rectangle in 2D.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
int selected_result
Result value of the selected item in the list.
bool persist
Persist dropdown menu.
virtual void OnDropdownClose(Point pt, WidgetID widget, int index, bool instant_close)
A dropdown window associated to this window has been closed.
void InitializePositionSize(int x, int y, int min_width, int min_height)
Set the position and smallest size of the window.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Rect wi_rect
Rect of the button that opened the dropdown.
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
@ WDF_NO_FOCUS
This window won't get focus/make any other window lose focus when click.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Dimension items_dim
Calculated cropped and padded dimension for the items widget.
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
High level window description.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
ResizeInfo resize
Resize information.
DropDownList list
List with dropdown menu items.
void FitAvailableHeight(Dimension &desired, const Dimension &list, uint available_height)
Fit dropdown list into available height, rounding to average item size.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
@ WF_WHITE_BORDER
Window white border counter bit mask.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
bool GetDropDownItem(int &value)
Find the dropdown item under the cursor.
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, bool instant_close, bool persist)
Show a drop down list.
byte click_delay
Timer to delay selection.
int GetMainViewTop()
Return the top of the main view available for general use.
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Window * parent
Parent window.
int left
x position of left edge of the window
WindowFlags flags
Window flags.
Coordinates of a point in 2D.
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, WidgetID button, uint32_t disabled_mask, uint32_t hidden_mask, uint width)
Show a dropdown menu window near a widget of the parent window.
WindowNumber window_number
Window number within the window class.
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
bool instant_close
Close the window when the mouse button is raised.
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Point position
Position of the topleft corner of the window.
int scrolling
If non-zero, auto-scroll the item list (one time).
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
void OnFocusLost(bool closing) override
The window has lost focus.
void UpdateSizeAndPosition()
Update size and position of window to fit dropdown list into available space.
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
virtual void OnDropdownSelect([[maybe_unused]] WidgetID widget, [[maybe_unused]] int index)
A dropdown option associated to this window has been selected.
static const uint8_t PC_BLACK
Black palette colour.
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
int top
y position of top edge of the window
@ WDP_MANUAL
Manually align the window (so no automatic location finding)
void OnMouseLoop() override
Called for every mouse loop run, which is at least once per (game) tick.
Data structure for an opened window.
Dimension GetDropDownListDimension(const DropDownList &list)
Determine width and height required to fully display a DropDownList.
int Width() const
Get width of Rect.
WidgetID parent_button
Parent widget number where the window is dropped from.
int GetMainViewBottom()
Return the bottom of the main view available for general use.
Specification of a rectangle with absolute coordinates of all edges.
Point pos
logical mouse position
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
#define CLRBITS(x, y)
Clears several bits in a variable.
bool _left_button_clicked
Is left mouse button clicked?
@ TD_RTL
Text is written right-to-left by default.
TextDirection _current_text_dir
Text direction of the currently selected language.
IntervalTimer< TimerWindow > scroll_interval
Rate limit how fast scrolling happens.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
DropdownWindow(Window *parent, DropDownList &&list, int selected, WidgetID button, const Rect wi_rect, bool instant_close, Colours wi_colour, bool persist)
Create a dropdown menu.
Window * FindChildWindow(WindowClass wc=WC_INVALID) const
Find the Window whose parent pointer points to this window.
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.