diff --git a/doomsday/client/include/ui/editors/rendererappearanceeditor.h b/doomsday/client/include/ui/editors/rendererappearanceeditor.h index 2d5ba43fc6..e2def71697 100644 --- a/doomsday/client/include/ui/editors/rendererappearanceeditor.h +++ b/doomsday/client/include/ui/editors/rendererappearanceeditor.h @@ -36,7 +36,8 @@ class RendererAppearanceEditor : public PanelWidget RendererAppearanceEditor(); public slots: - //void showRendererSettings(); + void foldAll(); + void unfoldAll(); protected: void preparePanelForOpening(); diff --git a/doomsday/client/include/ui/framework/guiwidget.h b/doomsday/client/include/ui/framework/guiwidget.h index 7b94017021..ae692da97b 100644 --- a/doomsday/client/include/ui/framework/guiwidget.h +++ b/doomsday/client/include/ui/framework/guiwidget.h @@ -136,6 +136,25 @@ class GuiWidget : public QObject, public de::Widget typedef de::Vertex2TexRgba DefaultVertex; typedef de::GLBufferT DefaultVertexBuf; + /** + * Handles events. + */ + class IEventHandler + { + public: + virtual ~IEventHandler() {} + + /** + * Handle an event. + * + * @param widget Widget that received the event. + * @param event Event. + * + * @return @c true, if the event was eaten. @c false otherwise. + */ + virtual bool handleEvent(GuiWidget &widget, de::Event const &event) = 0; + }; + public: GuiWidget(de::String const &name = ""); @@ -214,12 +233,24 @@ class GuiWidget : public QObject, public de::Widget */ float visibleOpacity() const; + /** + * Sets an object that will be offered events received by this widget. The + * handler may eat the event. Any number of event handlers can be added; + * they are called in the order of addition. + * + * @param handler Event handler. Ownership given to GuiWidget. + */ + void addEventHandler(IEventHandler *handler); + + void removeEventHandler(IEventHandler *handler); + // Events. void initialize(); void deinitialize(); void viewResized(); void update(); void draw() /*final*/; + bool handleEvent(de::Event const &event); /** * Determines if the widget occupies on-screen position @a pos. diff --git a/doomsday/client/src/ui/editors/rendererappearanceeditor.cpp b/doomsday/client/src/ui/editors/rendererappearanceeditor.cpp index 707a4c8db0..b47494ff79 100644 --- a/doomsday/client/src/ui/editors/rendererappearanceeditor.cpp +++ b/doomsday/client/src/ui/editors/rendererappearanceeditor.cpp @@ -39,6 +39,40 @@ DENG_GUI_PIMPL(RendererAppearanceEditor), DENG2_OBSERVES(SettingsRegister, ProfileChange), DENG2_OBSERVES(App, GameChange) { + /** + * Opens a popup menu for folding/unfolding all settings groups. + */ + struct RightClickHandler : public GuiWidget::IEventHandler + { + Instance *d; + + RightClickHandler(Instance *inst) : d(inst) {} + + bool handleEvent(GuiWidget &widget, Event const &event) + { + switch(widget.handleMouseClick(event, MouseEvent::Right)) + { + case MouseClickFinished: { + MouseEvent const &mouse = event.as(); + PopupMenuWidget *pop = new PopupMenuWidget; + pop->setDeleteAfterDismissed(true); + d->self.add(pop); + pop->setAnchorAndOpeningDirection(widget.rule(), ui::Left); + pop->items() + << new ActionItem(tr("Fold All"), new SignalAction(d->thisPublic, SLOT(foldAll()))) + << new ActionItem(tr("Unfold All"), new SignalAction(d->thisPublic, SLOT(unfoldAll()))); + pop->open(); + return true; } + + case MouseClickUnrelated: + return false; + + default: + return true; + } + } + }; + /** * Foldable group of settings. */ @@ -60,7 +94,6 @@ DENG2_OBSERVES(App, GameChange) }; public: - Group(RendererAppearanceEditor::Instance *inst, String const &titleText) : d(inst), _firstColumnWidth(0) { @@ -69,6 +102,9 @@ DENG2_OBSERVES(App, GameChange) title().setText(titleText); title().setTextColor("accent"); + // Set up a context menu for right-clicking. + title().addEventHandler(new RightClickHandler(d)); + // We want the first column of all groups to be aligned with each other. _layout.setColumnFixedWidth(0, *d->firstColumnWidth); @@ -597,6 +633,20 @@ DENG2_OBSERVES(App, GameChange) } } } + + void foldAll(bool fold) + { + foreach(Widget *child, container->childWidgets()) + { + if(Group *g = child->maybeAs()) + { + if(fold) + g->close(0); + else + g->open(); + } + } + } }; RendererAppearanceEditor::RendererAppearanceEditor() @@ -664,6 +714,16 @@ RendererAppearanceEditor::RendererAppearanceEditor() d->lightGroup->open(); } +void RendererAppearanceEditor::foldAll() +{ + d->foldAll(true); +} + +void RendererAppearanceEditor::unfoldAll() +{ + d->foldAll(false); +} + /* void RendererAppearanceEditor::showRendererSettings() { diff --git a/doomsday/client/src/ui/framework/guiwidget.cpp b/doomsday/client/src/ui/framework/guiwidget.cpp index e9ecfcb18d..947d8674a6 100644 --- a/doomsday/client/src/ui/framework/guiwidget.cpp +++ b/doomsday/client/src/ui/framework/guiwidget.cpp @@ -26,6 +26,8 @@ #include #include +#include + using namespace de; DENG2_PIMPL(GuiWidget), @@ -44,6 +46,7 @@ DENG2_OBSERVES(ui::Margins, Change) bool styleChanged; Background background; Animation opacity; + QList eventHandlers; // Style. DotPath fontId; @@ -91,6 +94,8 @@ DENG2_OBSERVES(ui::Margins, Change) ~Instance() { + qDeleteAll(eventHandlers); + // The base class will delete all children, but we need to deinitialize // them first. self.notifyTree(&Widget::deinitialize); @@ -419,6 +424,16 @@ float GuiWidget::visibleOpacity() const return opacity; } +void GuiWidget::addEventHandler(IEventHandler *handler) +{ + d->eventHandlers.append(handler); +} + +void GuiWidget::removeEventHandler(IEventHandler *handler) +{ + d->eventHandlers.removeOne(handler); +} + void GuiWidget::initialize() { if(d->inited) return; @@ -490,6 +505,18 @@ void GuiWidget::draw() } } +bool GuiWidget::handleEvent(Event const &event) +{ + foreach(IEventHandler *handler, d->eventHandlers) + { + if(handler->handleEvent(*this, event)) + { + return true; + } + } + return Widget::handleEvent(event); +} + bool GuiWidget::hitTest(Vector2i const &pos) const { if(behavior().testFlag(Unhittable)) diff --git a/doomsday/client/src/ui/widgets/buttonwidget.cpp b/doomsday/client/src/ui/widgets/buttonwidget.cpp index f3c34e7244..05bf31ee52 100644 --- a/doomsday/client/src/ui/widgets/buttonwidget.cpp +++ b/doomsday/client/src/ui/widgets/buttonwidget.cpp @@ -223,7 +223,8 @@ bool ButtonWidget::handleEvent(Event const &event) } } } - return false; + + return LabelWidget::handleEvent(event); } void ButtonWidget::updateModelViewProjection(GLUniform &uMvp)