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;
167 this->position.x = button_rect.right + 1 - (int)(widget_dim.width + (list_dim.height > widget_dim.height ? NWidgetScrollbar::GetVerticalDimension().width : 0));
169 this->position.x = button_rect.left;
172 this->items_dim = widget_dim;
177 this->vscroll->
SetCount(this->list.size());
180 if (this->position.y < button_rect.top && list_dim.height > widget_dim.height) this->vscroll->
UpdatePosition(INT_MAX);
188 Point OnInitialPosition([[maybe_unused]] int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]]
int window_number)
override
203 int y = _cursor.
pos.y - this->
top - r.top;
206 for (
const auto &item : this->list) {
208 if (--pos >= 0)
continue;
210 int item_height = item->Height();
212 if (y < item_height) {
213 if (item->masked || !item->Selectable())
return false;
214 value = item->result;
224 void DrawWidget(
const Rect &r,
WidgetID widget)
const override
228 Colours colour = this->GetWidget<NWidgetCore>(widget)->colour;
233 for (
const auto &item : this->list) {
234 int item_height = item->Height();
237 if (--pos >= 0)
continue;
239 if (y + item_height - 1 <= ir.bottom) {
240 Rect full{ir.left, y, ir.right, y + item_height - 1};
242 bool selected = (this->selected_result == item->result) && item->Selectable();
251 void OnClick([[maybe_unused]]
Point pt,
WidgetID widget, [[maybe_unused]]
int click_count)
override
256 this->click_delay = 4;
257 this->selected_result = item;
264 if (this->scrolling == 0)
return;
273 if (this->click_delay != 0 && --this->click_delay == 0) {
276 if (!this->persist) this->Close();
281 if (this->drag_mode) {
285 this->drag_mode =
false;
287 if (this->instant_close) this->Close();
290 this->click_delay = 2;
292 if (_cursor.
pos.y <= this->top + 2) {
294 this->scrolling = -1;
296 }
else if (_cursor.
pos.y >= this->top + this->height - 2) {
305 if (this->selected_result != item) {
306 this->selected_result = item;
314 this->list = std::move(
list);
317 this->
InitializePositionSize(this->position.x, this->position.y, this->nested_root->smallest_x, this->nested_root->smallest_y);
325 if (ddw !=
nullptr) ddw->ReplaceList(std::move(list));
336 for (
const auto &item : list) {
337 dim.height += item->Height();
338 dim.width = std::max(dim.width, item->Width());
359 new DropdownWindow(w, std::move(list), selected, button, wi_rect, instant_close, wi_colour, persist);
379 Rect wi_rect = nwi->GetCurrentRect();
380 Colours wi_colour = nwi->
colour;
397 ShowDropDownListAt(w, std::move(list), selected, button, wi_rect, wi_colour, instant_close, persist);
416 if (!
HasBit(hidden_mask, i)) {
417 list.push_back(std::make_unique<DropDownListStringItem>(strings[i], i,
HasBit(disabled_mask, i)));
421 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.