From 3ae1b98d3a11764fd7b63cddf3d4bdbc542b5341 Mon Sep 17 00:00:00 2001 From: alberth Date: Sat, 7 Nov 2009 14:40:37 +0000 Subject: (svn r17994) -Codechange: Make the dropdown menu window use pure nested widgets. --- src/widgets/dropdown.cpp | 126 ++++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 62 deletions(-) (limited to 'src/widgets/dropdown.cpp') diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 43550ef36..bd8e3f0a2 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -75,19 +75,20 @@ enum DropdownMenuWidgets { 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[] = { - NWidget(NWID_LAYERED), + NWidget(NWID_HORIZONTAL), 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(), }; +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 */ struct DropdownWindow : Window { 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. byte click_delay; ///< Timer to delay selection. 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). + Point position; ///< Position of the topleft corner of the window. /** Create a dropdown menu. * @param parent Parent window. * @param list Dropdown item list. * @param selected Index of the selected item in the list. * @param button Widget of the parent window doing the dropdown. - * @param instant_close ??? - * @param pos Topleft position of the dropdown menu window. + * @param instant_close Close the window when the mouse button is raised. + * @param position Topleft position of the dropdown menu window. * @param size Size of the dropdown menu window. * @param wi_colour Colour of the parent widget. * @param scroll Dropdown menu has a scrollbar. * @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) : - Window(pos.x, pos.y, size.width, size.height + 4, WC_DROPDOWN_MENU, 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() { - this->FindWindowPlacementAndResize(size.width, size.height + 4); + this->position = position; - this->widget[DDM_ITEMS].colour = wi_colour; - this->widget[DDM_ITEMS].right = size.width - 1; - this->widget[DDM_ITEMS].bottom = size.height + 3; + this->CreateNestedTree(&_dropdown_desc); - this->SetWidgetHiddenState(DDM_SCROLL, !scroll); - if (scroll) { - /* We're scrolling, so enable the scroll bar and shrink the list by - * the scrollbar's width */ - this->widget[DDM_SCROLL].colour = wi_colour; - 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); - } + NWidgetCore *nwi = this->GetWidget(DDM_ITEMS); + nwi->SetMinimalSize(size.width - (scroll ? 12 : 0), size.height + 4); + nwi->colour = wi_colour; - /* Capacity is the average number of items visible */ - this->vscroll.SetCapacity(size.height * (uint16)list->size() / list_height); - this->vscroll.SetCount((uint16)list->size()); + nwi = this->GetWidget(DDM_SCROLL); + if (scroll) { + nwi->colour = wi_colour; + } else { + nwi->min_x = 0; // Make scrollbar invisible. } - this->desc_flags = WDF_DEF_WIDGET; + this->FinishInitNested(&_dropdown_desc, 0); 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_num = parent->window_number; this->parent_button = button; @@ -176,12 +175,22 @@ struct DropdownWindow : Window { 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) { if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return false; - int y = _cursor.pos.y - this->top - 2; - int width = this->widget[DDM_ITEMS].right - 3; + NWidgetBase *nwi = this->GetWidget(DDM_ITEMS); + int y = _cursor.pos.y - this->top - nwi->pos_y - 2; + int width = nwi->current_x - 4; int pos = this->vscroll.GetPosition(); const DropDownList *list = this->list; @@ -208,39 +217,36 @@ struct DropdownWindow : Window { virtual void OnPaint() { this->DrawWidgets(); + } - int x = 1; - int y = 2; - - int sel = this->selected_index; - 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(); + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != DDM_ITEMS) return; - DropDownList *list = this->list; + TextColour colour = (TextColour)this->GetWidget(widget)->colour; - for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) { + int y = r.top + 2; + int pos = this->vscroll.GetPosition(); + for (DropDownList::const_iterator it = this->list->begin(); it != this->list->end(); ++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 */ if (--pos >= 0) continue; - if (y + item_height < height) { - if (sel == item->result) GfxFillRect(x + 1, y, right - 1, y + item_height - 1, 0); + if (y + item_height < r.bottom) { + 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) { - GfxFillRect(x, y, right - 1, y + item_height - 1, - _colour_gradient[this->widget[DDM_ITEMS].colour][5], FILLRECT_CHECKER - ); + GfxFillRect(r.left + 1, y, r.right - 1, y + item_height - 1, _colour_gradient[colour][5], FILLRECT_CHECKER); } } y += item_height; } - }; + } 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) { - static Widget *generated_dropdown_menu_widgets = NULL; - DeleteWindowById(WC_DROPDOWN_MENU, 0); /* 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); - 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}; 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. -- cgit v1.2.3-54-g00ecf