From 92d2c588a80516cd7f0d827d51624f12d1d69e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= Date: Tue, 5 Jul 2016 18:45:53 +0300 Subject: [PATCH] UI|Resources|Home: PackagesDialog can be used for selecting optionals The [...] buttons in PackagesDialog now show a "Select Packages" item if the package has optional content. --- .../ui/widgets/packagecontentoptionswidget.h | 2 +- .../client/src/ui/dialogs/packagesdialog.cpp | 23 ++++++++++- .../src/ui/home/packagescolumnwidget.cpp | 5 ++- .../widgets/packagecontentoptionswidget.cpp | 2 +- .../client/src/ui/widgets/packageswidget.cpp | 39 +++---------------- .../sdk/libcore/include/de/filesys/package.h | 4 ++ doomsday/sdk/libcore/src/filesys/package.cpp | 17 ++++++++ 7 files changed, 52 insertions(+), 40 deletions(-) diff --git a/doomsday/apps/client/include/ui/widgets/packagecontentoptionswidget.h b/doomsday/apps/client/include/ui/widgets/packagecontentoptionswidget.h index 59e88ac9b9..e3db3ca332 100644 --- a/doomsday/apps/client/include/ui/widgets/packagecontentoptionswidget.h +++ b/doomsday/apps/client/include/ui/widgets/packagecontentoptionswidget.h @@ -28,7 +28,7 @@ class PackageContentOptionsWidget : public de::GuiWidget { public: PackageContentOptionsWidget(de::String const &packageId, - de::Rule const &maxHeight, + de::Rule const &maxHeight, de::String const &name = de::String()); private: diff --git a/doomsday/apps/client/src/ui/dialogs/packagesdialog.cpp b/doomsday/apps/client/src/ui/dialogs/packagesdialog.cpp index 8a3932d689..8420525c22 100644 --- a/doomsday/apps/client/src/ui/dialogs/packagesdialog.cpp +++ b/doomsday/apps/client/src/ui/dialogs/packagesdialog.cpp @@ -216,7 +216,26 @@ DENG_GUI_PIMPL(PackagesDialog) // Action for showing information about the package. actions << new ui::SubwidgetItem(tr("..."), ui::Up, [this] () -> PopupWidget * { - return new PackagePopupWidget(browser->actionPackage()); + String const id = browser->actionPackage(); + if (Package::hasOptionalContent(id)) + { + auto *menu = new PopupMenuWidget; + menu->setColorTheme(Inverted); + menu->items() + << new ui::SubwidgetItem(tr("Info"), ui::Up, + [this] () -> PopupWidget * { + return new PackagePopupWidget(browser->actionPackage()); + }) + << new ui::ActionItem(style().images().image("gear"), tr("Select Packages"), + new CallbackAction([this] () { + browser->openContentOptions(*browser->actionItem()); + })); + return menu; + } + else + { + return new PackagePopupWidget(id); + } }); // Action for (de)selecting the package. @@ -283,7 +302,7 @@ DENG_GUI_PIMPL(PackagesDialog) { // Only list here the game data files; Doomsday's PK3s are always // there so listing them is not very helpful. - if (Package::tags(*file).contains(QStringLiteral("gamedata"))) + if (Package::matchTags(*file, QStringLiteral("\\bgamedata\\b"))) { // Resolve indirection (symbolic links and interpretations) to // describe the actual source file of the package. diff --git a/doomsday/apps/client/src/ui/home/packagescolumnwidget.cpp b/doomsday/apps/client/src/ui/home/packagescolumnwidget.cpp index b4f8052d0b..728e738ff2 100644 --- a/doomsday/apps/client/src/ui/home/packagescolumnwidget.cpp +++ b/doomsday/apps/client/src/ui/home/packagescolumnwidget.cpp @@ -21,11 +21,12 @@ #include "ui/widgets/packagepopupwidget.h" #include "ui/widgets/homeitemwidget.h" -#include #include #include #include #include +#include +#include #include #include @@ -74,7 +75,7 @@ DENG_GUI_PIMPL(PackagesColumnWidget) return new PackagePopupWidget(packageId); }); - if (DataBundle::packageBundleFormat(packageId) == DataBundle::Collection) + if (Package::hasOptionalContent(packageId)) { auto openOpts = [this] () { packages->openContentOptions(*packages->actionItem()); diff --git a/doomsday/apps/client/src/ui/widgets/packagecontentoptionswidget.cpp b/doomsday/apps/client/src/ui/widgets/packagecontentoptionswidget.cpp index ee60a0ea45..e38745a39f 100644 --- a/doomsday/apps/client/src/ui/widgets/packagecontentoptionswidget.cpp +++ b/doomsday/apps/client/src/ui/widgets/packagecontentoptionswidget.cpp @@ -328,7 +328,7 @@ DENG_GUI_PIMPL(PackageContentOptionsWidget) }; PackageContentOptionsWidget::PackageContentOptionsWidget(String const &packageId, - Rule const &maxHeight, + Rule const &maxHeight, String const &name) : GuiWidget(name) , d(new Impl(this, packageId, maxHeight)) diff --git a/doomsday/apps/client/src/ui/widgets/packageswidget.cpp b/doomsday/apps/client/src/ui/widgets/packageswidget.cpp index e1a1ed216a..b29a5bafb1 100644 --- a/doomsday/apps/client/src/ui/widgets/packageswidget.cpp +++ b/doomsday/apps/client/src/ui/widgets/packageswidget.cpp @@ -323,51 +323,22 @@ DENG_GUI_PIMPL(PackagesWidget) void openContentOptions() { - DENG2_ASSERT(_item->file->target().maybeAs()); - DENG2_ASSERT(_item->file->target().maybeAs()->format() == DataBundle::Collection); + DENG2_ASSERT(Package::hasOptionalContent(*_item->file)); if (!_optionsPopup) { _optionsPopup.reset(new PopupWidget); _optionsPopup->setDeleteAfterDismissed(true); _optionsPopup->setAnchorAndOpeningDirection(rule(), ui::Left); - - //_panelScroll = new ScrollAreaWidget; - //_panelScroll->enableIndicatorDraw(true); - - auto *opts = new PackageContentOptionsWidget(packageId(), root().viewHeight()); - - // Add a close button. - auto *close = new ButtonWidget; - close->setSizePolicy(ui::Expand, ui::Expand); - close->margins().set("dialog.gap"); - close->setStyleImage("close.ringless", "small"); - //close->setImageColor(style().colors().colorf("altaccent")); - close->setActionFn([this] () + _optionsPopup->closeButton().setActionFn([this] () { root().setFocus(this); _optionsPopup->close(); }); - close->setBackgroundColor("transparent"); - close->rule() - .setInput(Rule::Right, opts->rule().right() - opts->margins().right()) - .setInput(Rule::Top, opts->rule().top() + opts->margins().top()); - - // Embed the options inside a scroll area so longer contents can be - // scrolled. - //_panelScroll->add(opts); - opts->add(close); - //_panelScroll->setContentSize(opts->rule().width(), opts->rule().height()); + + auto *opts = new PackageContentOptionsWidget(packageId(), root().viewHeight()); opts->rule().setInput(Rule::Width, rule().width()); - //.setInput(Rule::Top, opts->contentRule().top()) - //.setInput(Rule::Left, opts->contentRule().left()); - /*_panelScroll->rule() - .setInput(Rule::Width, rule().width()) - .setInput(Rule::Height, - OperatorRule::minimum(root().viewHeight(), - opts->rule().height()));*/ - - _optionsPopup->setContent(opts);//Scroll); + _optionsPopup->setContent(opts); add(_optionsPopup); _optionsPopup->open(); } diff --git a/doomsday/sdk/libcore/include/de/filesys/package.h b/doomsday/sdk/libcore/include/de/filesys/package.h index c57a4576a3..aec2fede79 100644 --- a/doomsday/sdk/libcore/include/de/filesys/package.h +++ b/doomsday/sdk/libcore/include/de/filesys/package.h @@ -181,6 +181,10 @@ class DENG2_PUBLIC Package : public IObject static void addRequiredPackage(File &packageFile, String const &id); + static bool hasOptionalContent(String const &packageId); + + static bool hasOptionalContent(File const &packageFile); + /** * Splits a string containing a package identifier and version. The * expected format of the string is `{packageId}_{version}`. diff --git a/doomsday/sdk/libcore/src/filesys/package.cpp b/doomsday/sdk/libcore/src/filesys/package.cpp index 26f68d5d0f..a8509f5045 100644 --- a/doomsday/sdk/libcore/src/filesys/package.cpp +++ b/doomsday/sdk/libcore/src/filesys/package.cpp @@ -38,6 +38,8 @@ String const Package::VAR_TITLE ("title"); static String const PACKAGE_ORDER ("package.__order__"); static String const PACKAGE_IMPORT_PATH("package.importPath"); static String const PACKAGE_REQUIRES ("package.requires"); +static String const PACKAGE_RECOMMENDS ("package.recommends"); +static String const PACKAGE_EXTRAS ("package.extras"); static String const PACKAGE_TAGS ("package.tags"); static String const VAR_ID ("ID"); @@ -370,6 +372,21 @@ void Package::addRequiredPackage(File &packageFile, String const &id) packageFile.objectNamespace().appendToArray(PACKAGE_REQUIRES, new TextValue(id)); } +bool Package::hasOptionalContent(String const &packageId) +{ + if (File const *file = PackageLoader::get().select(packageId)) + { + return hasOptionalContent(*file); + } + return false; +} + +bool Package::hasOptionalContent(File const &packageFile) +{ + Record const &meta = packageFile.objectNamespace(); + return meta.has(PACKAGE_RECOMMENDS) || meta.has(PACKAGE_EXTRAS); +} + static String stripAfterFirstUnderscore(String str) { int pos = str.indexOf('_');