diff --git a/doomsday/sdk/libappfw/include/de/widgets/popupmenuwidget.h b/doomsday/sdk/libappfw/include/de/widgets/popupmenuwidget.h index 8e333d6041..d4aa10b627 100644 --- a/doomsday/sdk/libappfw/include/de/widgets/popupmenuwidget.h +++ b/doomsday/sdk/libappfw/include/de/widgets/popupmenuwidget.h @@ -34,6 +34,8 @@ class LIBAPPFW_PUBLIC PopupMenuWidget : public PopupWidget public: PopupMenuWidget(String const &name = ""); + void setParentPopup(PopupWidget *parentPopup); + MenuWidget &menu() const; ui::Data &items() { return menu().items(); } diff --git a/doomsday/sdk/libappfw/src/widgets/menuwidget.cpp b/doomsday/sdk/libappfw/src/widgets/menuwidget.cpp index 781121c6b3..d69acdc48c 100644 --- a/doomsday/sdk/libappfw/src/widgets/menuwidget.cpp +++ b/doomsday/sdk/libappfw/src/widgets/menuwidget.cpp @@ -87,6 +87,15 @@ DENG2_PIMPL(MenuWidget) Action::trigger(); + if(auto *subMenu = _widget->maybeAs()) + { + // Parent is the anchor button, owned by a MenuWidget, possibly owned a + // the popup menu. + if(auto *parentMenu = parent().parentWidget()) + { + subMenu->setParentPopup(parentMenu->parent()->maybeAs()); + } + } _widget->setAnchorAndOpeningDirection(parent().hitRule(), _dir); d->keepTrackOfSubWidget(_widget); diff --git a/doomsday/sdk/libappfw/src/widgets/popupmenuwidget.cpp b/doomsday/sdk/libappfw/src/widgets/popupmenuwidget.cpp index 0f0814828a..7aa5d3c403 100644 --- a/doomsday/sdk/libappfw/src/widgets/popupmenuwidget.cpp +++ b/doomsday/sdk/libappfw/src/widgets/popupmenuwidget.cpp @@ -94,6 +94,7 @@ DENG_GUI_PIMPL(PopupMenuWidget) int oldScrollY; Rule const *widestItem; IndirectRule *maxItemWidth; + SafeWidgetPtr parentPopup; Instance(Public *i) : Base(i) @@ -351,6 +352,8 @@ DENG_GUI_PIMPL(PopupMenuWidget) { // The popup menu is closed when an action is triggered. self.close(); + + if(parentPopup) parentPopup->close(); } void updateIfScrolled() @@ -413,6 +416,12 @@ PopupMenuWidget::PopupMenuWidget(String const &name) menu().organizer().audienceForWidgetUpdate() += d; } +void PopupMenuWidget::setParentPopup(PopupWidget *parentPopup) +{ + // The parent will be closed, too, if the submenu is closed due to activation. + d->parentPopup.reset(parentPopup); +} + MenuWidget &PopupMenuWidget::menu() const { return static_cast(content()); diff --git a/doomsday/sdk/libappfw/src/widgets/popupwidget.cpp b/doomsday/sdk/libappfw/src/widgets/popupwidget.cpp index 2d987def7a..382a973188 100644 --- a/doomsday/sdk/libappfw/src/widgets/popupwidget.cpp +++ b/doomsday/sdk/libappfw/src/widgets/popupwidget.cpp @@ -32,19 +32,13 @@ namespace de { DENG_GUI_PIMPL(PopupWidget) -, DENG2_OBSERVES(Widget, Deletion) { bool flexibleDir = true; ColorTheme colorTheme = Normal; bool deleteAfterDismiss = false; bool clickToClose = true; bool outsideClickOngoing = false; - Widget *realParent = nullptr; - /*Rule const *anchorTop = nullptr; - Rule const *anchorY = nullptr; - //Rule const *anchorWidth = nullptr; - Rule const *anchorBottom = nullptr; - Rule const *anchorOffset = new ConstantRule(0);*/ + SafeWidgetPtr realParent; RuleRectangle anchor; Rule const *marker; @@ -54,11 +48,6 @@ DENG_GUI_PIMPL(PopupWidget) marker = &rule("gap"); } - ~Instance() - { - if(realParent) realParent->audienceForDeletion() -= this; - } - void flipOpeningDirectionIfNeeded() { ui::Direction openDir = self.openingDirection(); @@ -225,15 +214,6 @@ DENG_GUI_PIMPL(PopupWidget) self.set(self.background().withSolidFillOpacity(1)); } } - - void widgetBeingDeleted(Widget &widget) - { - if(&widget == realParent) - { - // We don't know who the real parent is any more. - realParent = nullptr; - } - } }; PopupWidget::PopupWidget(String const &name) : PanelWidget(name), d(new Instance(this)) @@ -245,7 +225,7 @@ PopupWidget::PopupWidget(String const &name) : PanelWidget(name), d(new Instance int PopupWidget::levelOfNesting() const { int nesting = 0; - for(Widget const *p = d->realParent? d->realParent : parentWidget(); p; p = p->parent()) + for(Widget const *p = d->realParent? d->realParent.get() : parentWidget(); p; p = p->parent()) { if(p->is()) { @@ -258,27 +238,6 @@ int PopupWidget::levelOfNesting() const void PopupWidget::setAnchorAndOpeningDirection(RuleRectangle const &rule, ui::Direction dir) { d->anchor.setRect(rule); - -/* if(dir == ui::NoDirection) - { - // Anchored to the middle by default. - setAnchor(rule.left() + rule.width() / 2, - rule.top() + rule.height() / 2); - } - else if(dir == ui::Left || dir == ui::Right) - { - setAnchorY(rule.top() + rule.height() / 2); - setAnchorX(dir == ui::Left? rule.left() : rule.right()); - } - else if(dir == ui::Up || dir == ui::Down) - { - setAnchorX(rule.left() + rule.width() / 2); - setAnchorY(dir == ui::Up? rule.top() : rule.bottom()); - } - - changeRef(d->anchorWidth, rule.width()); - changeRef(d->anchorHeight, rule.height());*/ - setOpeningDirection(dir); } @@ -477,9 +436,8 @@ void PopupWidget::preparePanelForOpening() } // Reparent the popup into the root widget, on top of everything else. - d->realParent = Widget::parent(); - DENG2_ASSERT(d->realParent != 0); - d->realParent->audienceForDeletion() += d; + d->realParent.reset(Widget::parent()); + DENG2_ASSERT(d->realParent); d->realParent->remove(*this); d->realParent->root().as().addOnTop(this); @@ -491,14 +449,11 @@ void PopupWidget::panelDismissed() PanelWidget::panelDismissed(); // Move back to the original parent widget. - if(d->realParent) - { - d->realParent->audienceForDeletion() -= d; - } - else + if(!d->realParent) { // The real parent has been deleted. - d->realParent = &root(); + d->realParent.reset(&root()); + DENG2_ASSERT(d->realParent); } parentWidget()->remove(*this); @@ -512,7 +467,7 @@ void PopupWidget::panelDismissed() d->realParent->add(this); } - d->realParent = 0; + d->realParent.reset(); } } // namespace de