From a34be02e070ab4a5b1458eb55c31da466c4fdb0d Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sun, 5 Feb 2017 03:19:25 +0100 Subject: [PATCH] refs #617, CActionItem supports icon * standard paths for applications * support for Qt::DecorationRole * QMap m_availableActions * Constructor for icon only * only leafs support actions --- src/blackcore/actionbind.cpp | 17 +++++++++- src/blackcore/actionbind.h | 19 +++++++---- src/blackcore/inputmanager.cpp | 14 ++++---- src/blackcore/inputmanager.h | 12 ++++--- .../components/settingshotkeycomponent.h | 3 +- src/blackgui/components/weathercomponent.cpp | 3 +- src/blackgui/guiactionbind.cpp | 27 +++++++++++---- src/blackgui/guiactionbind.h | 6 ++++ src/blackgui/models/actionitem.cpp | 8 +++-- src/blackgui/models/actionitem.h | 13 ++++++- src/blackgui/models/actionmodel.cpp | 34 +++++++++++++------ src/swiftguistandard/swiftguistdmenus.cpp | 8 +++-- 12 files changed, 120 insertions(+), 44 deletions(-) diff --git a/src/blackcore/actionbind.cpp b/src/blackcore/actionbind.cpp index c89e65a14..e67b8cf57 100644 --- a/src/blackcore/actionbind.cpp +++ b/src/blackcore/actionbind.cpp @@ -11,6 +11,20 @@ namespace BlackCore { + CActionBind::CActionBind(const QString &action, const QPixmap &icon) + { + CActionBind::registerAction(action, icon); + } + + QString CActionBind::registerAction(const QString &action, const QPixmap &icon) + { + const QString a = CActionBind::normalizeAction(action); + auto inputManger = CInputManager::instance(); + Q_ASSERT_X(inputManger, Q_FUNC_INFO, "Missing input manager"); + inputManger->registerAction(a, icon); + return a; + } + CActionBind::~CActionBind() { unbind(); @@ -31,7 +45,8 @@ namespace BlackCore QString CActionBind::normalizeAction(const QString &action) { QString n = action.trimmed(); - if (!n.startsWith('/')) { return n.insert(0, QChar('/')); } + if (!n.startsWith('/')) { n.insert(0, QChar('/')); } + if (n.endsWith('/')) { n.remove(n.length() - 1 , 1);} return n; } } diff --git a/src/blackcore/actionbind.h b/src/blackcore/actionbind.h index a9f14b044..c8010cb74 100644 --- a/src/blackcore/actionbind.h +++ b/src/blackcore/actionbind.h @@ -14,6 +14,7 @@ #include "blackcore/inputmanager.h" #include "blackcoreexport.h" +#include namespace BlackCore { @@ -29,15 +30,18 @@ namespace BlackCore //! Constructor template - CActionBind(const QString &action, Receiver *receiver, MembFunc slot = nullptr, const std::function &deleteCallback = {}) : + CActionBind(const QString &action, const QPixmap &icon, Receiver *receiver, + MembFunc slot = nullptr, + const std::function &deleteCallback = {}) : m_deleteCallback(deleteCallback) { - const QString a = CActionBind::normalizeAction(action); - auto inputManger = CInputManager::instance(); - inputManger->registerAction(a); - m_index = inputManger->bind(a, receiver, slot); + const QString a = CActionBind::registerAction(action, icon); + m_index = CInputManager::instance()->bind(a, receiver, slot); } + //! Signature just to set an icon for an action + CActionBind(const QString &action, const QPixmap &icon); + //! Destructor ~CActionBind(); @@ -51,9 +55,12 @@ namespace BlackCore int getIndex() const { return m_index; } private: - //! normalize the name string + //! Normalize the action string static QString normalizeAction(const QString &action); + //! Register action + static QString registerAction(const QString &action, const QPixmap &icon); + int m_index = -1; //!< action indexx (unique) std::function m_deleteCallback; //!< called when deleted }; diff --git a/src/blackcore/inputmanager.cpp b/src/blackcore/inputmanager.cpp index 609727c0e..6cd34e71b 100644 --- a/src/blackcore/inputmanager.cpp +++ b/src/blackcore/inputmanager.cpp @@ -37,12 +37,12 @@ namespace BlackCore return &instance; } - void CInputManager::registerAction(const QString &action) + void CInputManager::registerAction(const QString &action, const QPixmap &icon) { if (!m_availableActions.contains(action)) { - m_availableActions.push_back(action); - emit hotkeyActionRegistered( { action } ); + m_availableActions.insert(action, icon); + emit hotkeyActionRegistered({ action }); } } @@ -52,15 +52,15 @@ namespace BlackCore { if (!m_availableActions.contains(action)) { - m_availableActions.push_back(action); - emit hotkeyActionRegistered( { action } ); + m_availableActions.insert(action, {}); + emit hotkeyActionRegistered({ action }); } } } void CInputManager::unbind(int index) { - auto info = std::find_if (m_boundActions.begin(), m_boundActions.end(), [index] (const BindInfo &info) { return info.m_index == index; }); + auto info = std::find_if(m_boundActions.begin(), m_boundActions.end(), [index](const BindInfo & info) { return info.m_index == index; }); if (info != m_boundActions.end()) { m_boundActions.erase(info); @@ -104,7 +104,7 @@ namespace BlackCore void CInputManager::callFunctionsBy(const QString &action, bool isKeyDown) { if (action.isEmpty()) { return; } - if(m_actionRelayingEnabled) emit remoteActionFromLocal(action, isKeyDown); + if (m_actionRelayingEnabled) emit remoteActionFromLocal(action, isKeyDown); for (const auto &boundAction : m_boundActions) { diff --git a/src/blackcore/inputmanager.h b/src/blackcore/inputmanager.h index 2fa8fb577..d0a77bb79 100644 --- a/src/blackcore/inputmanager.h +++ b/src/blackcore/inputmanager.h @@ -18,6 +18,7 @@ #include "blackinput/keyboard.h" #include "blackmisc/input/hotkeycombination.h" #include "blackmisc/settingscache.h" +#include "blackmisc/icons.h" #include #include @@ -38,7 +39,7 @@ namespace BlackCore public: //! Register new action - void registerAction(const QString &action); + void registerAction(const QString &action, const QPixmap &icon = BlackMisc::CIcons::empty16()); //! Register remote actions void registerRemoteActions(const QStringList &actions); @@ -72,7 +73,10 @@ namespace BlackCore void resetAllActions() { m_configuredActions.clear(); } //! Get all available and known actions - QStringList allAvailableActions() const { return m_availableActions; } + QStringList allAvailableActions() const { return m_availableActions.keys(); } + + //! All actions and their icons (if any) + QMap allAvailableActionsAndIcons() const { return m_availableActions; } //! Enable event forwarding to core void setForwarding(bool enabled) { m_actionRelayingEnabled = enabled; } @@ -129,7 +133,7 @@ namespace BlackCore std::unique_ptr m_keyboard; std::unique_ptr m_joystick; - QStringList m_availableActions; + QMap m_availableActions; QHash m_configuredActions; QVector m_boundActions; @@ -142,4 +146,4 @@ namespace BlackCore }; } -#endif //BLACKCORE_INPUTMANAGER_H +#endif //guard diff --git a/src/blackgui/components/settingshotkeycomponent.h b/src/blackgui/components/settingshotkeycomponent.h index e4f4de2ca..90752d703 100644 --- a/src/blackgui/components/settingshotkeycomponent.h +++ b/src/blackgui/components/settingshotkeycomponent.h @@ -19,6 +19,7 @@ #include "blackmisc/input/actionhotkey.h" #include "blackmisc/input/actionhotkeylist.h" #include "blackmisc/settingscache.h" +#include "blackmisc/icons.h" #include #include @@ -60,7 +61,7 @@ namespace BlackGui QScopedPointer ui; BlackGui::Models::CActionHotkeyListModel m_model; BlackMisc::CSetting m_actionHotkeys { this }; - BlackCore::CActionBind m_action { "/Test/Message", this, &CSettingsHotkeyComponent::ps_hotkeySlot }; + BlackCore::CActionBind m_action { "/Test/Message", BlackMisc::CIcons::wrench16(), this, &CSettingsHotkeyComponent::ps_hotkeySlot }; }; } // ns } // ns diff --git a/src/blackgui/components/weathercomponent.cpp b/src/blackgui/components/weathercomponent.cpp index 2a05bf926..d0231c766 100644 --- a/src/blackgui/components/weathercomponent.cpp +++ b/src/blackgui/components/weathercomponent.cpp @@ -60,7 +60,8 @@ namespace BlackGui setupCompleter(); // hotkeys - m_hotkeyBindings.append(CGuiActionBindHandler::bindButton(ui->pb_ActivateWeather, "Weather/Toggle weather", true)); + const QString swift(CGuiActionBindHandler::pathSwiftPilotClient()); + m_hotkeyBindings.append(CGuiActionBindHandler::bindButton(ui->pb_ActivateWeather, swift + "Weather/Toggle weather", true)); // Set interval to 5 min m_weatherUpdateTimer.setInterval(1000 * 60 * 5); diff --git a/src/blackgui/guiactionbind.cpp b/src/blackgui/guiactionbind.cpp index 0f373a7e9..8e3fde64d 100644 --- a/src/blackgui/guiactionbind.cpp +++ b/src/blackgui/guiactionbind.cpp @@ -9,6 +9,7 @@ #include "guiactionbind.h" #include "blackmisc/fileutils.h" +#include "blackmisc/imageutils.h" using namespace BlackMisc; using namespace BlackCore; @@ -38,7 +39,7 @@ namespace BlackGui for (QAction *action : menu->actions()) { if (action->text().isEmpty()) { continue; } - if (action->isSeparator()) { continue; } + if (action->isSeparator()) { continue; } const QString pathNew = CGuiActionBindHandler::appendPath(path, action->text()).remove('&'); // remove E&xit key codes if (action->menu()) @@ -46,8 +47,9 @@ namespace BlackGui CGuiActionBindHandler::bindMenu(action->menu(), pathNew); } + const bool hasIcon = !action->icon().isNull(); CGuiActionBindHandler *bindHandler = new CGuiActionBindHandler(action); - CActionBinding actionBinding(new CActionBind(pathNew, bindHandler, &CGuiActionBindHandler::boundFunction, [bindHandler]() { CGuiActionBindHandler::actionBindWasDestroyed(bindHandler); })); + CActionBinding actionBinding(new CActionBind(pathNew, hasIcon ? action->icon().pixmap(CIcons::empty16().size()) : CIcons::empty16(), bindHandler, &CGuiActionBindHandler::boundFunction, [bindHandler]() { CGuiActionBindHandler::actionBindWasDestroyed(bindHandler); })); bindHandler->m_index = actionBinding->getIndex(); boundActions.append(actionBinding); // takes ownership } @@ -61,7 +63,8 @@ namespace BlackGui path : CGuiActionBindHandler::appendPath(path, button->text()).remove('&'); // remove E&xit key codes CGuiActionBindHandler *bindHandler = new CGuiActionBindHandler(button); - CActionBinding actionBinding(new CActionBind(pathNew, bindHandler, &CGuiActionBindHandler::boundFunction, [bindHandler]() { CGuiActionBindHandler::actionBindWasDestroyed(bindHandler); })); + const bool hasIcon = !button->icon().isNull(); + CActionBinding actionBinding(new CActionBind(pathNew, hasIcon ? button->icon().pixmap(CIcons::empty16().size()) : CIcons::empty16(), bindHandler, &CGuiActionBindHandler::boundFunction, [bindHandler]() { CGuiActionBindHandler::actionBindWasDestroyed(bindHandler); })); bindHandler->m_index = actionBinding->getIndex(); return actionBinding; } @@ -84,12 +87,10 @@ namespace BlackGui void CGuiActionBindHandler::unbind() { + Q_ASSERT_X(CInputManager::instance(), Q_FUNC_INFO, "Missing input manager"); if (this->hasTarget()) { - if (CInputManager::instance()) - { - CInputManager::instance()->unbind(this->m_index); - } + CInputManager::instance()->unbind(this->m_index); } this->reset(); } @@ -123,4 +124,16 @@ namespace BlackGui { return CFileUtils::appendFilePaths(path, name); } + + const QString &CGuiActionBindHandler::pathSwiftPilotClient() + { + static const QString s("Pilot client UI/"); + return s; + } + + const QString &CGuiActionBindHandler::pathSwiftCore() + { + static const QString s("Core UI/"); + return s; + } } // namespace diff --git a/src/blackgui/guiactionbind.h b/src/blackgui/guiactionbind.h index e7ae2a6a5..1a7956e04 100644 --- a/src/blackgui/guiactionbind.h +++ b/src/blackgui/guiactionbind.h @@ -46,6 +46,12 @@ namespace BlackGui //! Corresponding BlackCore::CActionBind died, so delete CGuiActionBindHandler static void actionBindWasDestroyed(CGuiActionBindHandler *bindHandler); + //! Path + static const QString &pathSwiftPilotClient(); + + //! Path + static const QString &pathSwiftCore(); + private: //! Constructor for QAction CGuiActionBindHandler(QAction *action); diff --git a/src/blackgui/models/actionitem.cpp b/src/blackgui/models/actionitem.cpp index 6d6428d74..cf26eba65 100644 --- a/src/blackgui/models/actionitem.cpp +++ b/src/blackgui/models/actionitem.cpp @@ -14,8 +14,12 @@ namespace BlackGui { namespace Models { - CActionItem::CActionItem(const QString &action, const QString &name, CActionItem *parent) : - m_action(action), m_actionName(name), m_parentItem(parent) + CActionItem::CActionItem(const QString &action, const QString &name, CActionItem *parentItem) : + m_action(action), m_actionName(name), m_parentItem(parentItem) + { } + + CActionItem::CActionItem(const QString &action, const QString &name, const QPixmap &icon, CActionItem *parentItem) : + m_action(action), m_actionName(name), m_icon(icon), m_parentItem(parentItem) { } CActionItem::~CActionItem() diff --git a/src/blackgui/models/actionitem.h b/src/blackgui/models/actionitem.h index f0364db32..3887fd237 100644 --- a/src/blackgui/models/actionitem.h +++ b/src/blackgui/models/actionitem.h @@ -14,6 +14,7 @@ #include #include +#include namespace BlackGui { @@ -26,6 +27,9 @@ namespace BlackGui //! Constructor CActionItem(const QString &action, const QString &name, CActionItem *parentItem = nullptr); + //! Constructor + CActionItem(const QString &action, const QString &name, const QPixmap &icon, CActionItem *parentItem = nullptr); + //! Destructor ~CActionItem(); @@ -41,6 +45,12 @@ namespace BlackGui //! Number of children int getChildCount() const; + //! Icon + const QPixmap &getIcon() const { return m_icon; } + + //! Set icon + void setIcon(const QPixmap &icon) { m_icon = icon; } + //! Has children? bool hasChildren() const; @@ -60,9 +70,10 @@ namespace BlackGui CActionItem *getParentItem() const; private: - QList m_childItems; QString m_action; QString m_actionName; + QPixmap m_icon; + QList m_childItems; CActionItem *m_parentItem = nullptr; }; } diff --git a/src/blackgui/models/actionmodel.cpp b/src/blackgui/models/actionmodel.cpp index eb11e10db..6c0a49c7c 100644 --- a/src/blackgui/models/actionmodel.cpp +++ b/src/blackgui/models/actionmodel.cpp @@ -10,11 +10,16 @@ #include "blackcore/inputmanager.h" #include "blackgui/models/actionitem.h" #include "blackgui/models/actionmodel.h" +#include "blackmisc/icons.h" #include #include +#include #include +using namespace BlackMisc; +using namespace BlackCore; + namespace BlackGui { namespace Models @@ -41,9 +46,11 @@ namespace BlackGui if (!index.isValid()) { return QVariant(); } const CActionItem *item = static_cast(index.internalPointer()); + Q_ASSERT_X(item, Q_FUNC_INFO, "Missing item"); - if (role == Qt::DisplayRole) { return item->getActionName(); } if (role == ActionRole) { return item->getAction(); } + if (role == Qt::DisplayRole) { return item->getActionName(); } + if (role == Qt::DecorationRole) { return item->getIcon(); } return {}; } @@ -62,8 +69,8 @@ namespace BlackGui if (!hasIndex(row, column, parent)) { return QModelIndex(); } const CActionItem *parentItem = parent.isValid() ? - static_cast(parent.internalPointer()) : - m_rootItem.data(); + static_cast(parent.internalPointer()) : + m_rootItem.data(); CActionItem *childItem = parentItem->getChildByRow(row); return childItem ? @@ -85,12 +92,10 @@ namespace BlackGui int CActionModel::rowCount(const QModelIndex &parent) const { - CActionItem *parentItem; if (parent.column() > 0) { return 0; } - - if (!parent.isValid()) { parentItem = m_rootItem.data(); } - else { parentItem = static_cast(parent.internalPointer()); } - + const CActionItem *parentItem = parent.isValid() ? + static_cast(parent.internalPointer()) : + m_rootItem.data(); return parentItem->getChildCount(); } @@ -98,16 +103,23 @@ namespace BlackGui { m_rootItem.reset(new CActionItem(QString(), QString())); - for (const auto &actionPath : BlackCore::CInputManager::instance()->allAvailableActions()) + const QMap availableActionsAndIcons = CInputManager::instance()->allAvailableActionsAndIcons(); + QStringList keys = availableActionsAndIcons.keys(); + keys.sort(); + for (const QString &actionPath : as_const(keys)) { - const auto tokens = actionPath.split("/", QString::SkipEmptyParts); + QString currentPath; + const QStringList tokens = actionPath.split("/", QString::SkipEmptyParts); CActionItem *parentItem = m_rootItem.data(); for (const auto &token : tokens) { + currentPath += QLatin1Char('/') % token; CActionItem *child = parentItem->findChildByName(token); if (child == nullptr) { - child = new CActionItem(actionPath, token, parentItem); + const bool isAction = currentPath == actionPath; // action istelf, or just a node? + const QPixmap icon = isAction ? availableActionsAndIcons[actionPath] : CIcons::empty16(); + child = new CActionItem(isAction ? actionPath : "", token, icon, parentItem); parentItem->appendChild(child); } Q_ASSERT(child); diff --git a/src/swiftguistandard/swiftguistdmenus.cpp b/src/swiftguistandard/swiftguistdmenus.cpp index f79296a4f..704580506 100644 --- a/src/swiftguistandard/swiftguistdmenus.cpp +++ b/src/swiftguistandard/swiftguistdmenus.cpp @@ -77,7 +77,9 @@ void SwiftGuiStd::initMenus() ui->menu_InfoAreas->addActions(ui->comp_MainInfoArea->getInfoAreaSelectActions(ui->menu_InfoAreas)); // for hotkeys - m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_InfoAreas, "Info areas")); - m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_File, "File")); - m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_Window, "Window")); + const QString swift(CGuiActionBindHandler::pathSwiftPilotClient()); + static const CActionBind swiftRoot(swift, CIcons::swift16()); + m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_InfoAreas, swift + "Info areas")); + m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_File, swift + "File")); + m_menuHotkeyHandlers.append(CGuiActionBindHandler::bindMenu(ui->menu_Window, swift + "Window")); }