From 58be4adeec47bb5aaefcdc8f38ff844933683ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 1 Jan 2016 09:30:07 +0200 Subject: [PATCH] Refactor|UI|Client: Added SidebarWidget: base class for sidebars --- .../ui/editors/rendererappearanceeditor.h | 10 +- .../include/ui/editors/variablegroupeditor.h | 7 +- .../client/include/ui/widgets/sidebarwidget.h | 52 ++++++ .../defaultstyle.pack/rules.dei | 2 +- .../ui/editors/rendererappearanceeditor.cpp | 134 ++++----------- .../client/src/ui/widgets/sidebarwidget.cpp | 154 ++++++++++++++++++ 6 files changed, 245 insertions(+), 114 deletions(-) create mode 100644 doomsday/apps/client/include/ui/widgets/sidebarwidget.h create mode 100644 doomsday/apps/client/src/ui/widgets/sidebarwidget.cpp diff --git a/doomsday/apps/client/include/ui/editors/rendererappearanceeditor.h b/doomsday/apps/client/include/ui/editors/rendererappearanceeditor.h index 556a004077..edbb5aa472 100644 --- a/doomsday/apps/client/include/ui/editors/rendererappearanceeditor.h +++ b/doomsday/apps/client/include/ui/editors/rendererappearanceeditor.h @@ -19,8 +19,8 @@ #ifndef DENG_CLIENT_RENDERERAPPEARANCEEDITOR_H #define DENG_CLIENT_RENDERERAPPEARANCEEDITOR_H -#include #include +#include "ui/widgets/sidebarwidget.h" /** * Editor for modifying the settings for the renderer's visual appearance. @@ -29,8 +29,8 @@ * * @see ClientApp::rendererAppearanceSettings() */ -class RendererAppearanceEditor : public de::PanelWidget, - public de::IPersistent +class RendererAppearanceEditor : public SidebarWidget + , public de::IPersistent { Q_OBJECT @@ -40,10 +40,6 @@ class RendererAppearanceEditor : public de::PanelWidget, void operator >> (de::PersistentState &toState) const; void operator << (de::PersistentState const &fromState); -protected: - void preparePanelForOpening(); - void panelDismissed(); - private: DENG2_PRIVATE(d) }; diff --git a/doomsday/apps/client/include/ui/editors/variablegroupeditor.h b/doomsday/apps/client/include/ui/editors/variablegroupeditor.h index 024de1fe9c..aec3aa3f52 100644 --- a/doomsday/apps/client/include/ui/editors/variablegroupeditor.h +++ b/doomsday/apps/client/include/ui/editors/variablegroupeditor.h @@ -53,10 +53,7 @@ class VariableGroupEditor : public de::FoldPanelWidget IOwner &owner(); de::ButtonWidget &resetButton(); - de::Rule const &firstColumnWidth() const; - void preparePanelForOpening(); - void panelClosing(); void addSpace(); void addLabel(de::String const &text); @@ -76,6 +73,10 @@ class VariableGroupEditor : public de::FoldPanelWidget void fetch(); + // PanelWidget. + void preparePanelForOpening(); + void panelClosing(); + public slots: virtual void resetToDefaults(); virtual void foldAll(); diff --git a/doomsday/apps/client/include/ui/widgets/sidebarwidget.h b/doomsday/apps/client/include/ui/widgets/sidebarwidget.h new file mode 100644 index 0000000000..c20dfe9c3d --- /dev/null +++ b/doomsday/apps/client/include/ui/widgets/sidebarwidget.h @@ -0,0 +1,52 @@ +/** @file sidebarwidget.h Base class for sidebar widgets. + * + * @authors Copyright (c) 2015-2016 Jaakko Keränen + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, see: + * http://www.gnu.org/licenses + */ + +#ifndef DENG_CLIENT_UI_SIDEBARWIDGET_H +#define DENG_CLIENT_UI_SIDEBARWIDGET_H + +#include +#include +#include + +/** + * Editor for changing model asset parameters. + */ +class SidebarWidget : public de::PanelWidget +{ + Q_OBJECT + +public: + SidebarWidget(de::String const &title, de::String const &name = ""); + + de::SequentialLayout &layout(); + de::ScrollAreaWidget &containerWidget(); + de::IndirectRule &firstColumnWidth(); + de::Rule const &maximumOfAllGroupFirstColumns() const; + +protected: + void updateSidebarLayout(de::Rule const &minWidth); + + void preparePanelForOpening(); + void panelDismissed(); + +private: + DENG2_PRIVATE(d) +}; + + +#endif // DENG_CLIENT_UI_SIDEBARWIDGET_H diff --git a/doomsday/apps/client/net.dengine.client.pack/defaultstyle.pack/rules.dei b/doomsday/apps/client/net.dengine.client.pack/defaultstyle.pack/rules.dei index 3552e11422..254dbfe8c4 100644 --- a/doomsday/apps/client/net.dengine.client.pack/defaultstyle.pack/rules.dei +++ b/doomsday/apps/client/net.dengine.client.pack/defaultstyle.pack/rules.dei @@ -80,6 +80,6 @@ coloradjustment { rule slider { constant $= slider.width.constant * 1.36 } } -rendererappearance { +sidebar { rule width { constant $= UNIT * 100 } } diff --git a/doomsday/apps/client/src/ui/editors/rendererappearanceeditor.cpp b/doomsday/apps/client/src/ui/editors/rendererappearanceeditor.cpp index b09724fadc..879751c3de 100644 --- a/doomsday/apps/client/src/ui/editors/rendererappearanceeditor.cpp +++ b/doomsday/apps/client/src/ui/editors/rendererappearanceeditor.cpp @@ -45,10 +45,6 @@ public VariableGroupEditor::IOwner using Group = VariableGroupEditor; SettingsRegister &settings; - DialogContentStylist stylist; - ScrollAreaWidget *container; - IndirectRule *firstColumnWidth; ///< Shared by all groups. - ButtonWidget *close; ProfilePickerWidget *profile; Group *skyGroup; @@ -66,26 +62,16 @@ public VariableGroupEditor::IOwner Instance(Public *i) : Base(i) , settings(ClientApp::renderSystem().appearanceSettings()) - , firstColumnWidth(new IndirectRule) { // The editor will close automatically when going to Ring Zero. App::app().audienceForGameChange() += this; - settings.audienceForProfileChange += this; - // The contents of the editor will scroll. - container = new ScrollAreaWidget; - container->enableIndicatorDraw(true); - stylist.setContainer(*container); + GuiWidget *container = &self.containerWidget(); - container->add(close = new ButtonWidget); + // The contents of the editor will scroll. container->add(profile = new ProfilePickerWidget(settings, tr("appearance"))); - close->setImage(style().images().image("close.ringless")); - close->setImageColor(style().colors().colorf("altaccent")); - close->setOverrideImageSize(style().fonts().font("title").height().valuei()); - close->setAction(new SignalAction(thisPublic, SLOT(close()))); - // Sky settings. skyGroup = new Group(this, "sky", tr("Sky")); @@ -384,31 +370,27 @@ public VariableGroupEditor::IOwner partGroup->addSlider("rend-particle-visible-near", Ranged(0, 1000), 1, 0)->setMinLabel(tr("None")); partGroup->commit(); - - // Now we can define the first column width. - firstColumnWidth->setSource(maximumOfAllGroupFirstColumns()); } ~Instance() { App::app().audienceForGameChange() -= this; settings.audienceForProfileChange -= this; - releaseRef(firstColumnWidth); } - void resetToDefaults(String const &settingName) + Rule const &firstColumnWidthRule() const { - settings.resetSettingToDefaults(settingName); + return self.firstColumnWidth(); } - Rule const &firstColumnWidthRule() const + ScrollAreaWidget &containerWidget() { - return *firstColumnWidth; + return self.containerWidget(); } - ScrollAreaWidget &containerWidget() + void resetToDefaults(String const &settingName) { - return *container; + settings.resetSettingToDefaults(settingName); } void currentGameChanged(game::Game const &newGame) @@ -426,24 +408,11 @@ public VariableGroupEditor::IOwner fetch(); } - Rule const &maximumOfAllGroupFirstColumns() - { - Rule const *max = 0; - foreach(Widget *child, container->childWidgets()) - { - if(Group *g = child->maybeAs()) - { - changeRef(max, OperatorRule::maximum(g->firstColumnWidth(), max)); - } - } - return *refless(max); - } - void fetch() { bool const isReadOnly = settings.isReadOnlyProfile(settings.currentProfile()); - foreach(Widget *child, container->childWidgets()) + foreach(Widget *child, self.containerWidget().childWidgets()) { if(Group *g = child->maybeAs()) { @@ -465,11 +434,12 @@ public VariableGroupEditor::IOwner void saveFoldState(PersistentState &toState) { - foreach(Widget *child, container->childWidgets()) + foreach(Widget *child, self.containerWidget().childWidgets()) { if(Group *g = child->maybeAs()) { - toState.objectNamespace().set(self.name() + "." + g->name() + ".open", g->isOpen()); + toState.objectNamespace().set(self.name() + "." + g->name() + ".open", + g->isOpen()); } } } @@ -478,7 +448,7 @@ public VariableGroupEditor::IOwner { bool gotState = false; - foreach(Widget *child, container->childWidgets()) + foreach(Widget *child, self.containerWidget().childWidgets()) { if(Group *g = child->maybeAs()) { @@ -503,66 +473,36 @@ public VariableGroupEditor::IOwner }; RendererAppearanceEditor::RendererAppearanceEditor() - : PanelWidget("rendererappearanceeditor") + : SidebarWidget(tr("Renderer Appearance"), "rendererappearanceeditor") , d(new Instance(this)) { - setSizePolicy(Fixed); - setOpeningDirection(Left); - set(Background(style().colors().colorf("background")).withSolidFillOpacity(1)); - d->profile->setOpeningDirection(Down); - // Set up the editor UI. - LabelWidget *title = LabelWidget::newWithText("Renderer Appearance", d->container); - title->setFont("title"); - title->setTextColor("accent"); - - LabelWidget *profLabel = LabelWidget::newWithText(tr("Profile:"), d->container); + LabelWidget *profLabel = LabelWidget::newWithText(tr("Profile:"), &containerWidget()); // Layout. - RuleRectangle const &area = d->container->contentRule(); - title->rule() - .setInput(Rule::Top, area.top()) - .setInput(Rule::Left, area.left()); - d->close->rule() - .setInput(Rule::Right, area.right()) - .setInput(Rule::Bottom, title->rule().bottom()); - - SequentialLayout layout(area.left(), title->rule().bottom(), Down); - - layout.append(*profLabel, SequentialLayout::IgnoreMinorAxis); + layout().append(*profLabel, SequentialLayout::IgnoreMinorAxis); d->profile->rule() .setInput(Rule::Left, profLabel->rule().right()) .setInput(Rule::Top, profLabel->rule().top()); - layout << d->lightGroup->title() << *d->lightGroup - << d->volLightGroup->title() << *d->volLightGroup - << d->glowGroup->title() << *d->glowGroup - << d->shadowGroup->title() << *d->shadowGroup - << d->lensGroup->title() << *d->lensGroup - << d->matGroup->title() << *d->matGroup - << d->objectGroup->title() << *d->objectGroup - << d->modelGroup->title() << *d->modelGroup - << d->spriteGroup->title() << *d->spriteGroup - << d->partGroup->title() << *d->partGroup - << d->skyGroup->title() << *d->skyGroup; - - // Update container size. - d->container->setContentSize(OperatorRule::maximum(layout.width(), - profLabel->rule().width() + - d->profile->rule().width() + - d->profile->button().rule().width(), - style().rules().rule("rendererappearance.width")), - title->rule().height() + layout.height()); - d->container->rule().setSize(d->container->contentRule().width() + - d->container->margins().width(), - rule().height()); - setContent(d->container); + layout() << d->lightGroup->title() << *d->lightGroup + << d->volLightGroup->title() << *d->volLightGroup + << d->glowGroup->title() << *d->glowGroup + << d->shadowGroup->title() << *d->shadowGroup + << d->lensGroup->title() << *d->lensGroup + << d->matGroup->title() << *d->matGroup + << d->objectGroup->title() << *d->objectGroup + << d->modelGroup->title() << *d->modelGroup + << d->spriteGroup->title() << *d->spriteGroup + << d->partGroup->title() << *d->partGroup + << d->skyGroup->title() << *d->skyGroup; + + updateSidebarLayout(profLabel->rule().width() + + d->profile->rule().width() + + d->profile->button().rule().width()); d->fetch(); - - // Install the editor. - ClientWindow::main().setSidebar(ClientWindow::RightEdge, this); } void RendererAppearanceEditor::operator >> (PersistentState &toState) const @@ -574,15 +514,3 @@ void RendererAppearanceEditor::operator << (PersistentState const &fromState) { d->restoreFoldState(fromState); } - -void RendererAppearanceEditor::preparePanelForOpening() -{ - PanelWidget::preparePanelForOpening(); -} - -void RendererAppearanceEditor::panelDismissed() -{ - PanelWidget::panelDismissed(); - - ClientWindow::main().unsetSidebar(ClientWindow::RightEdge); -} diff --git a/doomsday/apps/client/src/ui/widgets/sidebarwidget.cpp b/doomsday/apps/client/src/ui/widgets/sidebarwidget.cpp new file mode 100644 index 0000000000..5966c9cda0 --- /dev/null +++ b/doomsday/apps/client/src/ui/widgets/sidebarwidget.cpp @@ -0,0 +1,154 @@ +/** @file sidebarwidget.cpp Base class for sidebar widgets. + * + * @authors Copyright (c) 2015-2016 Jaakko Keränen + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the GNU + * General Public License along with this program; if not, see: + * http://www.gnu.org/licenses + */ + + +#include "ui/widgets/sidebarwidget.h" +#include "ui/editors/variablegroupeditor.h" +#include "ui/clientwindow.h" + +#include +#include +#include + +using namespace de; +using namespace de::ui; + +DENG_GUI_PIMPL(SidebarWidget) +{ + DialogContentStylist stylist; + ScrollAreaWidget *container; + IndirectRule *firstColumnWidth; ///< Shared by all groups. + LabelWidget *title; + ButtonWidget *close; + SequentialLayout *layout; + + Instance(Public *i) + : Base(i) + , firstColumnWidth(new IndirectRule) + { + // The contents of the editor will scroll. + container = new ScrollAreaWidget; + container->enableIndicatorDraw(true); + stylist.setContainer(*container); + + container->add(close = new ButtonWidget); + + close->setImage(style().images().image("close.ringless")); + close->setImageColor(style().colors().colorf("altaccent")); + close->setOverrideImageSize(style().fonts().font("title").height().valuei()); + close->setAction(new SignalAction(thisPublic, SLOT(close()))); + } + + ~Instance() + { + releaseRef(firstColumnWidth); + } +}; + +SidebarWidget::SidebarWidget(String const &titleText, String const &name) + : PanelWidget(name) + , d(new Instance(this)) +{ + setSizePolicy(Fixed); + setOpeningDirection(Left); + set(Background(style().colors().colorf("background")).withSolidFillOpacity(1)); + + // Set up the editor UI. + d->title = LabelWidget::newWithText(titleText, d->container); + d->title->setFont("title"); + d->title->setTextColor("accent"); + + // Basic layout. + RuleRectangle const &area = d->container->contentRule(); + d->title->rule() + .setInput(Rule::Top, area.top()) + .setInput(Rule::Left, area.left()); + d->close->rule() + .setInput(Rule::Right, area.right()) + .setInput(Rule::Bottom, d->title->rule().bottom()); + + d->layout = new SequentialLayout(area.left(), d->title->rule().bottom(), Down); + + // Update container size. + // Now we can define the first column width. +#if 0 + d->container->setContentSize(OperatorRule::maximum(d->layout->width(), + /*profLabel->rule().width() + + d->profile->rule().width() + + d->profile->button().rule().width(),*/ + style().rules().rule("sidebar.width")), + title->rule().height() + d->layout->height()); +#endif + + d->container->rule().setSize(d->container->contentRule().width() + + d->container->margins().width(), + rule().height()); + setContent(d->container); + + // Install the editor. + ClientWindow::main().setSidebar(ClientWindow::RightEdge, this); +} + +SequentialLayout &SidebarWidget::layout() +{ + return *d->layout; +} + +Rule const &SidebarWidget::maximumOfAllGroupFirstColumns() const +{ + Rule const *max = 0; + foreach(Widget *child, d->container->childWidgets()) + { + if(auto *g = child->maybeAs()) + { + changeRef(max, OperatorRule::maximum(g->firstColumnWidth(), max)); + } + } + return *refless(max); +} + +IndirectRule &SidebarWidget::firstColumnWidth() +{ + return *d->firstColumnWidth; +} + +ScrollAreaWidget &SidebarWidget::containerWidget() +{ + return *d->container; +} + +void SidebarWidget::preparePanelForOpening() +{ + PanelWidget::preparePanelForOpening(); +} + +void SidebarWidget::panelDismissed() +{ + PanelWidget::panelDismissed(); + ClientWindow::main().unsetSidebar(ClientWindow::RightEdge); +} + +void SidebarWidget::updateSidebarLayout(de::Rule const &minWidth) +{ + d->firstColumnWidth->setSource(maximumOfAllGroupFirstColumns()); + + d->container->setContentSize(OperatorRule::maximum(minWidth, + d->layout->width(), + style().rules().rule("sidebar.width")), + d->title->rule().height() + d->layout->height()); +}