refs #617, CActionItem supports icon

* standard paths for applications
* support for Qt::DecorationRole
* QMap<QString, QPixmap> m_availableActions
* Constructor for icon only
* only leafs support actions
This commit is contained in:
Klaus Basan
2017-02-05 03:19:25 +01:00
committed by Mathew Sutcliffe
parent 6a96d14baa
commit a34be02e07
12 changed files with 120 additions and 44 deletions

View File

@@ -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;
}
}

View File

@@ -14,6 +14,7 @@
#include "blackcore/inputmanager.h"
#include "blackcoreexport.h"
#include <QPixmap>
namespace BlackCore
{
@@ -29,15 +30,18 @@ namespace BlackCore
//! Constructor
template <typename Receiver>
CActionBind(const QString &action, Receiver *receiver, MembFunc<Receiver> slot = nullptr, const std::function<void()> &deleteCallback = {}) :
CActionBind(const QString &action, const QPixmap &icon, Receiver *receiver,
MembFunc<Receiver> slot = nullptr,
const std::function<void()> &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<void()> m_deleteCallback; //!< called when deleted
};

View File

@@ -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)
{

View File

@@ -18,6 +18,7 @@
#include "blackinput/keyboard.h"
#include "blackmisc/input/hotkeycombination.h"
#include "blackmisc/settingscache.h"
#include "blackmisc/icons.h"
#include <QHash>
#include <QObject>
@@ -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<QString, QPixmap> 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<BlackInput::IKeyboard> m_keyboard;
std::unique_ptr<BlackInput::IJoystick> m_joystick;
QStringList m_availableActions;
QMap<QString, QPixmap> m_availableActions;
QHash<BlackMisc::Input::CHotkeyCombination, QString> m_configuredActions;
QVector<BindInfo> m_boundActions;
@@ -142,4 +146,4 @@ namespace BlackCore
};
}
#endif //BLACKCORE_INPUTMANAGER_H
#endif //guard

View File

@@ -19,6 +19,7 @@
#include "blackmisc/input/actionhotkey.h"
#include "blackmisc/input/actionhotkeylist.h"
#include "blackmisc/settingscache.h"
#include "blackmisc/icons.h"
#include <QFrame>
#include <QObject>
@@ -60,7 +61,7 @@ namespace BlackGui
QScopedPointer<Ui::CSettingsHotkeyComponent> ui;
BlackGui::Models::CActionHotkeyListModel m_model;
BlackMisc::CSetting<BlackCore::Application::TActionHotkeys> 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

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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()

View File

@@ -14,6 +14,7 @@
#include <QList>
#include <QString>
#include <QPixmap>
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<CActionItem *> m_childItems;
QString m_action;
QString m_actionName;
QPixmap m_icon;
QList<CActionItem *> m_childItems;
CActionItem *m_parentItem = nullptr;
};
}

View File

@@ -10,11 +10,16 @@
#include "blackcore/inputmanager.h"
#include "blackgui/models/actionitem.h"
#include "blackgui/models/actionmodel.h"
#include "blackmisc/icons.h"
#include <QString>
#include <QStringList>
#include <QStringBuilder>
#include <QtGlobal>
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<CActionItem *>(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<CActionItem *>(parent.internalPointer()) :
m_rootItem.data();
static_cast<CActionItem *>(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<CActionItem *>(parent.internalPointer()); }
const CActionItem *parentItem = parent.isValid() ?
static_cast<CActionItem *>(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<QString, QPixmap> 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);

View File

@@ -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"));
}