From f24abe9e7bca168edca88e3ceec7386fb374c4cf Mon Sep 17 00:00:00 2001 From: skyjake Date: Tue, 16 Jul 2013 19:21:30 +0300 Subject: [PATCH] Client|MenuWidget: Added an optional sort order for menu items Any object that implements ISortOrder can be used as the sort order for menu items. --- .../client/include/ui/widgets/menuwidget.h | 28 +++++++++++++++ doomsday/client/src/ui/widgets/menuwidget.cpp | 34 +++++++++++++++++-- .../client/src/ui/widgets/popupmenuwidget.cpp | 2 +- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/doomsday/client/include/ui/widgets/menuwidget.h b/doomsday/client/include/ui/widgets/menuwidget.h index 4754dda475..6d55c0657e 100644 --- a/doomsday/client/include/ui/widgets/menuwidget.h +++ b/doomsday/client/include/ui/widgets/menuwidget.h @@ -28,9 +28,30 @@ * One of the dimensions of the grid can be configured to use ui::Expand * policy, but then the child widgets must manage their size on that axis by * themselves. + * + * A sort order for the items can be optionally defined using + * MenuWidget::ISortOrder. Sorting affects layout only, not the actual order of + * the children. */ class MenuWidget : public ScrollAreaWidget { +public: + class ISortOrder + { + public: + virtual ~ISortOrder() {} + + /** + * Determines the sort order for a pair of menu items. + * + * @param a First menu item. + * @param b Second menu item. + * + * @return -1 if a < b; +1 if a > b; 0 if equal. + */ + virtual int compareMenuItemsForSorting(Widget const &a, Widget const &b) const = 0; + }; + public: MenuWidget(de::String const &name = ""); @@ -57,6 +78,13 @@ class MenuWidget : public ScrollAreaWidget void setGridSize(int columns, ui::SizePolicy columnPolicy, int rows, ui::SizePolicy rowPolicy); + /** + * Sets the sort order for item layout. + * + * @param sorting Sort order object. MenuWidget takes ownership. + */ + void setLayoutSortOrder(ISortOrder *sorting); + ButtonWidget *addItem(de::String const &styledText, de::Action *action = 0); ButtonWidget *addItem(de::Image const &image, de::String const &styledText, de::Action *action = 0); diff --git a/doomsday/client/src/ui/widgets/menuwidget.cpp b/doomsday/client/src/ui/widgets/menuwidget.cpp index e22074eb9d..0d0dae0165 100644 --- a/doomsday/client/src/ui/widgets/menuwidget.cpp +++ b/doomsday/client/src/ui/widgets/menuwidget.cpp @@ -24,6 +24,8 @@ using namespace ui; DENG2_PIMPL(MenuWidget) { bool needLayout; + QScopedPointer sorting; + WidgetList sortedChildren; SizePolicy colPolicy; SizePolicy rowPolicy; @@ -105,6 +107,8 @@ DENG2_PIMPL(MenuWidget) Vector2i size; int ord = 0; + DENG2_ASSERT(sortedChildren.size() == int(self.childCount())); + foreach(Widget *i, self.Widget::children()) { if(isVisibleItem(i)) @@ -116,10 +120,29 @@ DENG2_PIMPL(MenuWidget) return size; } + // Functor for quicksort comparisons. + struct Sorter { + Instance &d; + Sorter(Instance *inst) : d(*inst) {} + bool operator () (Widget const *a, Widget const *b) const { + DENG2_ASSERT(!d.sorting.isNull()); + return d.sorting->compareMenuItemsForSorting(*a, *b) < 0; + } + }; + + void prepareSortedChildren() + { + sortedChildren = self.Widget::children(); + if(!sorting.isNull()) + { + qSort(sortedChildren.begin(), sortedChildren.end(), Sorter(this)); + } + } + GuiWidget *findItem(int col, int row) const { int ord = 0; - foreach(Widget *i, self.Widget::children()) + foreach(Widget *i, sortedChildren) { if(isVisibleItem(i)) { @@ -234,6 +257,12 @@ void MenuWidget::setGridSize(int columns, ui::SizePolicy columnPolicy, d->needLayout = true; } +void MenuWidget::setLayoutSortOrder(ISortOrder *sorting) +{ + d->sorting.reset(sorting); + d->needLayout = true; +} + ButtonWidget *MenuWidget::addItem(String const &styledText, Action *action) { return addItem(Image(), styledText, action); @@ -278,7 +307,8 @@ int MenuWidget::count() const void MenuWidget::updateLayout() { - //qDebug() << path().toString() << "Menu has" << d->countVisible() << "visible items"; + // Sort children again. + d->prepareSortedChildren(); Rule const *baseVert = holdRef(&contentRule().top()); diff --git a/doomsday/client/src/ui/widgets/popupmenuwidget.cpp b/doomsday/client/src/ui/widgets/popupmenuwidget.cpp index 0c4405cc55..9a9cd0cf7e 100644 --- a/doomsday/client/src/ui/widgets/popupmenuwidget.cpp +++ b/doomsday/client/src/ui/widgets/popupmenuwidget.cpp @@ -150,9 +150,9 @@ void PopupMenuWidget::preparePopupForOpening() PopupWidget::preparePopupForOpening(); // Redo the layout. + menu().updateLayout(); menu().rule().setInput(Rule::Width, *refless(menu().newColumnWidthRule(0)) + 2 * margin()); - menu().updateLayout(); } void PopupMenuWidget::popupClosing()