mirror of https://github.com/OpenTTD/OpenTTD
(svn r17994) -Codechange: Make the dropdown menu window use pure nested widgets.
parent
d03bf874fc
commit
3ae1b98d3a
|
@ -75,19 +75,20 @@ enum DropdownMenuWidgets {
|
||||||
DDM_SCROLL, ///< Scrollbar.
|
DDM_SCROLL, ///< Scrollbar.
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Widget _dropdown_menu_widgets[] = {
|
|
||||||
{ WWT_PANEL, RESIZE_NONE, COLOUR_END, 0, 0, 0, 0, 0x0, STR_NULL}, ///< DDM_ITEMS
|
|
||||||
{ WWT_SCROLLBAR, RESIZE_NONE, COLOUR_END, 0, 0, 0, 0, 0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST}, ///< DDM_SCROLL
|
|
||||||
{ WIDGETS_END},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const NWidgetPart _nested_dropdown_menu_widgets[] = {
|
static const NWidgetPart _nested_dropdown_menu_widgets[] = {
|
||||||
NWidget(NWID_LAYERED),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(WWT_PANEL, COLOUR_END, DDM_ITEMS), SetMinimalSize(1, 1), EndContainer(),
|
NWidget(WWT_PANEL, COLOUR_END, DDM_ITEMS), SetMinimalSize(1, 1), EndContainer(),
|
||||||
NWidget(WWT_SCROLLBAR, COLOUR_END, DDM_SCROLL), SetMinimalSize(1, 1),
|
NWidget(WWT_SCROLLBAR, COLOUR_END, DDM_SCROLL),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const WindowDesc _dropdown_desc(
|
||||||
|
0, 0, 0, 0, 0, 0, // x/y position not used.
|
||||||
|
WC_DROPDOWN_MENU, WC_NONE,
|
||||||
|
WDF_DEF_WIDGET,
|
||||||
|
NULL, _nested_dropdown_menu_widgets, lengthof(_nested_dropdown_menu_widgets)
|
||||||
|
);
|
||||||
|
|
||||||
/** Drop-down menu window */
|
/** Drop-down menu window */
|
||||||
struct DropdownWindow : Window {
|
struct DropdownWindow : Window {
|
||||||
WindowClass parent_wnd_class; ///< Parent window class.
|
WindowClass parent_wnd_class; ///< Parent window class.
|
||||||
|
@ -97,55 +98,53 @@ struct DropdownWindow : Window {
|
||||||
int selected_index; ///< Index of the selected item in the list.
|
int selected_index; ///< Index of the selected item in the list.
|
||||||
byte click_delay; ///< Timer to delay selection.
|
byte click_delay; ///< Timer to delay selection.
|
||||||
bool drag_mode;
|
bool drag_mode;
|
||||||
bool instant_close;
|
bool instant_close; ///< Close the window when the mouse button is raised.
|
||||||
int scrolling; ///< If non-zero, auto-scroll the item list (one time).
|
int scrolling; ///< If non-zero, auto-scroll the item list (one time).
|
||||||
|
Point position; ///< Position of the topleft corner of the window.
|
||||||
|
|
||||||
/** Create a dropdown menu.
|
/** Create a dropdown menu.
|
||||||
* @param parent Parent window.
|
* @param parent Parent window.
|
||||||
* @param list Dropdown item list.
|
* @param list Dropdown item list.
|
||||||
* @param selected Index of the selected item in the list.
|
* @param selected Index of the selected item in the list.
|
||||||
* @param button Widget of the parent window doing the dropdown.
|
* @param button Widget of the parent window doing the dropdown.
|
||||||
* @param instant_close ???
|
* @param instant_close Close the window when the mouse button is raised.
|
||||||
* @param pos Topleft position of the dropdown menu window.
|
* @param position Topleft position of the dropdown menu window.
|
||||||
* @param size Size of the dropdown menu window.
|
* @param size Size of the dropdown menu window.
|
||||||
* @param wi_colour Colour of the parent widget.
|
* @param wi_colour Colour of the parent widget.
|
||||||
* @param scroll Dropdown menu has a scrollbar.
|
* @param scroll Dropdown menu has a scrollbar.
|
||||||
* @param widget Widgets of the dropdown menu window.
|
* @param widget Widgets of the dropdown menu window.
|
||||||
*/
|
*/
|
||||||
DropdownWindow(Window *parent, DropDownList *list, int selected, int button, bool instant_close, const Point &pos, const Dimension &size, Colours wi_colour, bool scroll, const Widget *widget) :
|
DropdownWindow(Window *parent, DropDownList *list, int selected, int button, bool instant_close, const Point &position, const Dimension &size, Colours wi_colour, bool scroll) : Window()
|
||||||
Window(pos.x, pos.y, size.width, size.height + 4, WC_DROPDOWN_MENU, widget)
|
|
||||||
{
|
{
|
||||||
this->FindWindowPlacementAndResize(size.width, size.height + 4);
|
this->position = position;
|
||||||
|
|
||||||
this->widget[DDM_ITEMS].colour = wi_colour;
|
this->CreateNestedTree(&_dropdown_desc);
|
||||||
this->widget[DDM_ITEMS].right = size.width - 1;
|
|
||||||
this->widget[DDM_ITEMS].bottom = size.height + 3;
|
|
||||||
|
|
||||||
this->SetWidgetHiddenState(DDM_SCROLL, !scroll);
|
NWidgetCore *nwi = this->GetWidget<NWidgetCore>(DDM_ITEMS);
|
||||||
|
nwi->SetMinimalSize(size.width - (scroll ? 12 : 0), size.height + 4);
|
||||||
|
nwi->colour = wi_colour;
|
||||||
|
|
||||||
|
nwi = this->GetWidget<NWidgetCore>(DDM_SCROLL);
|
||||||
if (scroll) {
|
if (scroll) {
|
||||||
/* We're scrolling, so enable the scroll bar and shrink the list by
|
nwi->colour = wi_colour;
|
||||||
* the scrollbar's width */
|
} else {
|
||||||
this->widget[DDM_SCROLL].colour = wi_colour;
|
nwi->min_x = 0; // Make scrollbar invisible.
|
||||||
this->widget[DDM_SCROLL].right = this->widget[DDM_ITEMS].right;
|
|
||||||
this->widget[DDM_SCROLL].left = this->widget[DDM_SCROLL].right - (WD_VSCROLLBAR_WIDTH - 1);
|
|
||||||
this->widget[DDM_SCROLL].bottom = this->widget[DDM_ITEMS].bottom;
|
|
||||||
this->widget[DDM_ITEMS].right -= WD_VSCROLLBAR_WIDTH;
|
|
||||||
|
|
||||||
/* Total length of list */
|
|
||||||
int list_height = 0;
|
|
||||||
for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) {
|
|
||||||
DropDownListItem *item = *it;
|
|
||||||
list_height += item->Height(size.width - WD_VSCROLLBAR_WIDTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Capacity is the average number of items visible */
|
|
||||||
this->vscroll.SetCapacity(size.height * (uint16)list->size() / list_height);
|
|
||||||
this->vscroll.SetCount((uint16)list->size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->desc_flags = WDF_DEF_WIDGET;
|
this->FinishInitNested(&_dropdown_desc, 0);
|
||||||
this->flags4 &= ~WF_WHITE_BORDER_MASK;
|
this->flags4 &= ~WF_WHITE_BORDER_MASK;
|
||||||
|
|
||||||
|
/* Total length of list */
|
||||||
|
int list_height = 0;
|
||||||
|
for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) {
|
||||||
|
DropDownListItem *item = *it;
|
||||||
|
list_height += item->Height(size.width - WD_VSCROLLBAR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Capacity is the average number of items visible */
|
||||||
|
this->vscroll.SetCapacity(size.height * (uint16)list->size() / list_height);
|
||||||
|
this->vscroll.SetCount((uint16)list->size());
|
||||||
|
|
||||||
this->parent_wnd_class = parent->window_class;
|
this->parent_wnd_class = parent->window_class;
|
||||||
this->parent_wnd_num = parent->window_number;
|
this->parent_wnd_num = parent->window_number;
|
||||||
this->parent_button = button;
|
this->parent_button = button;
|
||||||
|
@ -176,12 +175,22 @@ struct DropdownWindow : Window {
|
||||||
DeleteDropDownList(this->list);
|
DeleteDropDownList(this->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
|
||||||
|
{
|
||||||
|
return this->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Find the dropdown item under the cursor.
|
||||||
|
* @param value [out] Selected item, if function returns \c true.
|
||||||
|
* @return Cursor points to a dropdown item.
|
||||||
|
*/
|
||||||
bool GetDropDownItem(int &value)
|
bool GetDropDownItem(int &value)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
int y = _cursor.pos.y - this->top - 2;
|
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(DDM_ITEMS);
|
||||||
int width = this->widget[DDM_ITEMS].right - 3;
|
int y = _cursor.pos.y - this->top - nwi->pos_y - 2;
|
||||||
|
int width = nwi->current_x - 4;
|
||||||
int pos = this->vscroll.GetPosition();
|
int pos = this->vscroll.GetPosition();
|
||||||
|
|
||||||
const DropDownList *list = this->list;
|
const DropDownList *list = this->list;
|
||||||
|
@ -208,39 +217,36 @@ struct DropdownWindow : Window {
|
||||||
virtual void OnPaint()
|
virtual void OnPaint()
|
||||||
{
|
{
|
||||||
this->DrawWidgets();
|
this->DrawWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
int x = 1;
|
virtual void DrawWidget(const Rect &r, int widget) const
|
||||||
int y = 2;
|
{
|
||||||
|
if (widget != DDM_ITEMS) return;
|
||||||
|
|
||||||
int sel = this->selected_index;
|
TextColour colour = (TextColour)this->GetWidget<NWidgetCore>(widget)->colour;
|
||||||
int width = this->widget[DDM_ITEMS].right - 2;
|
|
||||||
int right = this->widget[DDM_ITEMS].right;
|
|
||||||
int bottom = this->widget[DDM_ITEMS].bottom;
|
|
||||||
int pos = this->vscroll.GetPosition();
|
|
||||||
|
|
||||||
DropDownList *list = this->list;
|
int y = r.top + 2;
|
||||||
|
int pos = this->vscroll.GetPosition();
|
||||||
for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) {
|
for (DropDownList::const_iterator it = this->list->begin(); it != this->list->end(); ++it) {
|
||||||
const DropDownListItem *item = *it;
|
const DropDownListItem *item = *it;
|
||||||
int item_height = item->Height(width);
|
int item_height = item->Height(r.right - r.left + 1);
|
||||||
|
|
||||||
/* Skip items that are scrolled up */
|
/* Skip items that are scrolled up */
|
||||||
if (--pos >= 0) continue;
|
if (--pos >= 0) continue;
|
||||||
|
|
||||||
if (y + item_height < height) {
|
if (y + item_height < r.bottom) {
|
||||||
if (sel == item->result) GfxFillRect(x + 1, y, right - 1, y + item_height - 1, 0);
|
bool selected = (this->selected_index == item->result);
|
||||||
|
if (selected) GfxFillRect(r.left + 2, y, r.right - 1, y + item_height - 1, 0);
|
||||||
|
|
||||||
item->Draw(0, right, y, bottom, sel == item->result, (TextColour)this->widget[DDM_ITEMS].colour);
|
item->Draw(r.left, r.right, y, r.bottom, selected, colour);
|
||||||
|
|
||||||
if (item->masked) {
|
if (item->masked) {
|
||||||
GfxFillRect(x, y, right - 1, y + item_height - 1,
|
GfxFillRect(r.left + 1, y, r.right - 1, y + item_height - 1, _colour_gradient[colour][5], FILLRECT_CHECKER);
|
||||||
_colour_gradient[this->widget[DDM_ITEMS].colour][5], FILLRECT_CHECKER
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
y += item_height;
|
y += item_height;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual void OnClick(Point pt, int widget)
|
virtual void OnClick(Point pt, int widget)
|
||||||
{
|
{
|
||||||
|
@ -313,8 +319,6 @@ struct DropdownWindow : Window {
|
||||||
|
|
||||||
void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, uint width, bool auto_width, bool instant_close)
|
void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, uint width, bool auto_width, bool instant_close)
|
||||||
{
|
{
|
||||||
static Widget *generated_dropdown_menu_widgets = NULL;
|
|
||||||
|
|
||||||
DeleteWindowById(WC_DROPDOWN_MENU, 0);
|
DeleteWindowById(WC_DROPDOWN_MENU, 0);
|
||||||
|
|
||||||
/* Our parent's button widget is used to determine where to place the drop
|
/* Our parent's button widget is used to determine where to place the drop
|
||||||
|
@ -401,11 +405,9 @@ void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, u
|
||||||
|
|
||||||
if (auto_width) width = max(width, max_item_width);
|
if (auto_width) width = max(width, max_item_width);
|
||||||
|
|
||||||
const Widget *wid = InitializeWidgetArrayFromNestedWidgets(_nested_dropdown_menu_widgets, lengthof(_nested_dropdown_menu_widgets),
|
|
||||||
_dropdown_menu_widgets, &generated_dropdown_menu_widgets);
|
|
||||||
Point dw_pos = {w->left + wi_rect.left, top};
|
Point dw_pos = {w->left + wi_rect.left, top};
|
||||||
Dimension dw_size = {width, height};
|
Dimension dw_size = {width, height};
|
||||||
new DropdownWindow(w, list, selected, button, instant_close, dw_pos, dw_size, wi_colour, scroll, wid);
|
new DropdownWindow(w, list, selected, button, instant_close, dw_pos, dw_size, wi_colour, scroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Show a dropdown menu window near a widget of the parent window.
|
/** Show a dropdown menu window near a widget of the parent window.
|
||||||
|
|
Loading…
Reference in New Issue