added actionable and canRecanReceiveAction filter
This commit is contained in:
parent
83ca802073
commit
7bb1cd2224
10 changed files with 142 additions and 52 deletions
|
@ -23,6 +23,7 @@ set(MODULE_SRC
|
|||
${CMAKE_CURRENT_LIST_DIR}/actionsmodule.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/actionsmodule.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/iactionsdispatcher.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/actionable.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/action.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/actionsdispatcher.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/internal/actionsdispatcher.h
|
||||
|
|
50
framework/actions/actionable.h
Normal file
50
framework/actions/actionable.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA and others
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.
|
||||
//
|
||||
// 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, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//=============================================================================
|
||||
#ifndef MU_ACTIONS_ACTIONABLE_H
|
||||
#define MU_ACTIONS_ACTIONABLE_H
|
||||
|
||||
#include "iactionsdispatcher.h"
|
||||
|
||||
namespace mu {
|
||||
namespace actions {
|
||||
class Actionable
|
||||
{
|
||||
public:
|
||||
virtual ~Actionable()
|
||||
{
|
||||
if (m_dispatcher) {
|
||||
m_dispatcher->unReg(this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool canReceiveAction(const ActionName& action) const = 0;
|
||||
|
||||
inline void setDispatcher(IActionsDispatcher* dispatcher)
|
||||
{
|
||||
m_dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
IActionsDispatcher* m_dispatcher = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_ACTIONS_ACTIONABLE_H
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
namespace mu {
|
||||
namespace actions {
|
||||
class Actionable;
|
||||
class IActionsDispatcher : MODULE_EXPORT_INTERFACE
|
||||
{
|
||||
INTERFACE_ID(IActionsDispatcher)
|
||||
|
@ -37,40 +38,43 @@ public:
|
|||
|
||||
virtual void dispatch(const ActionName& a) = 0;
|
||||
virtual void dispatch(const ActionName& a, const ActionData& data) = 0;
|
||||
virtual void reg(const ActionName& action, const ActionCallBackWithNameAndData& call) = 0;
|
||||
|
||||
void reg(const ActionName& action, const ActionCallBack& call)
|
||||
virtual void unReg(Actionable* client) = 0;
|
||||
virtual void reg(Actionable* client, const ActionName& action, const ActionCallBackWithNameAndData& call) = 0;
|
||||
|
||||
void reg(Actionable* client, const ActionName& action, const ActionCallBack& call)
|
||||
{
|
||||
reg(action, [call](const ActionName&, const ActionData&) { call(); });
|
||||
reg(client, action, [call](const ActionName&, const ActionData&) { call(); });
|
||||
}
|
||||
|
||||
void reg(const ActionName& action, const ActionCallBackWithName& call)
|
||||
void reg(Actionable* client, const ActionName& action, const ActionCallBackWithName& call)
|
||||
{
|
||||
reg(action, [call](const ActionName& action, const ActionData&) { call(action); });
|
||||
reg(client, action, [call](const ActionName& action, const ActionData&) { call(action); });
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void reg(const ActionName& action, T* caller, void (T::* func)(const ActionName& action))
|
||||
void reg(Actionable* client, const ActionName& action, T* caller, void (T::* func)(const ActionName& action))
|
||||
{
|
||||
reg(action, [caller, func](const ActionName& action) { (caller->*func)(action); });
|
||||
reg(client, action, [caller, func](const ActionName& action) { (caller->*func)(action); });
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void reg(const ActionName& action, T* caller, void (T::* func)())
|
||||
void reg(Actionable* client, const ActionName& action, T* caller, void (T::* func)())
|
||||
{
|
||||
reg(action, [caller, func](const ActionName&) { (caller->*func)(); });
|
||||
reg(client, action, [caller, func](const ActionName&) { (caller->*func)(); });
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void reg(const ActionName& action, T* caller, void (T::* func)(const ActionName& action, const ActionData& data))
|
||||
void reg(Actionable* client, const ActionName& action, T* caller, void (T::* func)(const ActionName& action,
|
||||
const ActionData& data))
|
||||
{
|
||||
reg(action,[caller, func](const ActionName& a, const ActionData& data) { (caller->*func)(a, data); });
|
||||
reg(client, action,[caller, func](const ActionName& a, const ActionData& data) { (caller->*func)(a, data); });
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void reg(const ActionName& action, T* caller, void (T::* func)(const ActionData& data))
|
||||
void reg(Actionable* client, const ActionName& action, T* caller, void (T::* func)(const ActionData& data))
|
||||
{
|
||||
reg(action, [caller, func](const ActionName&, const ActionData& data) { (caller->*func)(data); });
|
||||
reg(client, action, [caller, func](const ActionName&, const ActionData& data) { (caller->*func)(data); });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
//=============================================================================
|
||||
#include "actionsdispatcher.h"
|
||||
#include "log.h"
|
||||
#include "actionable.h"
|
||||
|
||||
using namespace mu::actions;
|
||||
|
||||
|
@ -27,45 +28,48 @@ ActionsDispatcher::ActionsDispatcher()
|
|||
|
||||
void ActionsDispatcher::dispatch(const ActionName& action)
|
||||
{
|
||||
auto it = m_callbacks.find(action);
|
||||
if (it == m_callbacks.end()) {
|
||||
LOGW() << "not registred action: " << action;
|
||||
return;
|
||||
}
|
||||
|
||||
ActionCallBackWithNameAndData& callback = it->second;
|
||||
LOGI() << "try call action: " << action;
|
||||
|
||||
static ActionData dummy;
|
||||
callback(action, dummy);
|
||||
dispatch(action, dummy);
|
||||
}
|
||||
|
||||
void ActionsDispatcher::dispatch(const ActionName& action, const ActionData& data)
|
||||
{
|
||||
auto it = m_callbacks.find(action);
|
||||
if (it == m_callbacks.end()) {
|
||||
auto it = m_clients.find(action);
|
||||
if (it == m_clients.end()) {
|
||||
LOGW() << "not registred action: " << action;
|
||||
return;
|
||||
}
|
||||
|
||||
ActionCallBackWithNameAndData& callback = it->second;
|
||||
LOGI() << "try call action: " << action;
|
||||
callback(action, data);
|
||||
Clients& clients = it->second;
|
||||
for (auto cit = clients.cbegin(); cit != clients.cend(); ++cit) {
|
||||
const Actionable* client = cit->first;
|
||||
if (client->canReceiveAction(action)) {
|
||||
const CallBacks& callbacks = cit->second;
|
||||
auto cbit = callbacks.find(action);
|
||||
IF_ASSERT_FAILED(cbit != callbacks.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ActionCallBackWithNameAndData& callback = cbit->second;
|
||||
LOGI() << "try call action: " << action;
|
||||
callback(action, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ActionsDispatcher::isRegistred(const ActionName& action) const
|
||||
void ActionsDispatcher::unReg(Actionable* client)
|
||||
{
|
||||
auto it = m_callbacks.find(action);
|
||||
if (it != m_callbacks.end()) {
|
||||
return true;
|
||||
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
|
||||
Clients& clients = it->second;
|
||||
clients.erase(client);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ActionsDispatcher::reg(const ActionName& action, const ActionCallBackWithNameAndData& call)
|
||||
void ActionsDispatcher::reg(Actionable* client, const ActionName& action, const ActionCallBackWithNameAndData& call)
|
||||
{
|
||||
IF_ASSERT_FAILED_X(!isRegistred(action), std::string("already registred action: ") + action) {
|
||||
return;
|
||||
}
|
||||
m_callbacks.insert({ action, call });
|
||||
client->setDispatcher(this);
|
||||
|
||||
Clients& clients = m_clients[action];
|
||||
CallBacks& callbacks = clients[client];
|
||||
callbacks.insert({ action, call });
|
||||
}
|
||||
|
|
|
@ -33,13 +33,15 @@ public:
|
|||
void dispatch(const ActionName& a) override;
|
||||
void dispatch(const ActionName& action, const ActionData& data) override;
|
||||
|
||||
void reg(const ActionName& action, const ActionCallBackWithNameAndData& call) override;
|
||||
void unReg(Actionable* client) override;
|
||||
void reg(Actionable* client, const ActionName& action, const ActionCallBackWithNameAndData& call) override;
|
||||
|
||||
private:
|
||||
|
||||
bool isRegistred(const ActionName& action) const;
|
||||
using CallBacks = std::map<ActionName, ActionCallBackWithNameAndData>;
|
||||
using Clients = std::map<Actionable*, CallBacks>;
|
||||
|
||||
std::map<ActionName, ActionCallBackWithNameAndData> m_callbacks;
|
||||
std::map<ActionName, Clients > m_clients;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,16 @@ using namespace mu::actions;
|
|||
|
||||
NotationActionController::NotationActionController()
|
||||
{
|
||||
dispatcher()->reg("domain/notation/note-input", this, &NotationActionController::toggleNoteInput);
|
||||
dispatcher()->reg("domain/notation/pad-note-4", [this]() { padNote(Pad::NOTE4); });
|
||||
dispatcher()->reg("domain/notation/pad-note-8", [this]() { padNote(Pad::NOTE8); });
|
||||
dispatcher()->reg("domain/notation/pad-note-16", [this]() { padNote(Pad::NOTE16); });
|
||||
dispatcher()->reg("domain/notation/put-note", this, &NotationActionController::putNote);
|
||||
dispatcher()->reg(this, "domain/notation/note-input", this, &NotationActionController::toggleNoteInput);
|
||||
dispatcher()->reg(this, "domain/notation/pad-note-4", [this]() { padNote(Pad::NOTE4); });
|
||||
dispatcher()->reg(this, "domain/notation/pad-note-8", [this]() { padNote(Pad::NOTE8); });
|
||||
dispatcher()->reg(this, "domain/notation/pad-note-16", [this]() { padNote(Pad::NOTE16); });
|
||||
dispatcher()->reg(this, "domain/notation/put-note", this, &NotationActionController::putNote);
|
||||
}
|
||||
|
||||
bool NotationActionController::canReceiveAction(const actions::ActionName&) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<INotation> NotationActionController::currentNotation() const
|
||||
|
|
|
@ -21,13 +21,14 @@
|
|||
|
||||
#include "modularity/ioc.h"
|
||||
#include "actions/iactionsdispatcher.h"
|
||||
#include "actions/actionable.h"
|
||||
#include "context/iglobalcontext.h"
|
||||
#include "../inotation.h"
|
||||
|
||||
namespace mu {
|
||||
namespace domain {
|
||||
namespace notation {
|
||||
class NotationActionController
|
||||
class NotationActionController : public actions::Actionable
|
||||
{
|
||||
INJECT(notation, actions::IActionsDispatcher, dispatcher)
|
||||
INJECT(notation, context::IGlobalContext, globalContext)
|
||||
|
@ -43,6 +44,8 @@ public:
|
|||
private:
|
||||
NotationActionController();
|
||||
|
||||
bool canReceiveAction(const actions::ActionName& action) const override;
|
||||
|
||||
std::shared_ptr<INotation> currentNotation() const;
|
||||
INotationInteraction* currentNotationInteraction() const;
|
||||
|
||||
|
|
|
@ -46,7 +46,11 @@ NotationPaintView::NotationPaintView()
|
|||
connect(this, &QQuickPaintedItem::heightChanged, this, &NotationPaintView::onViewSizeChanged);
|
||||
|
||||
// actions
|
||||
dispatcher()->reg("domain/notation/file-open", [this](const actions::ActionName&) { open(); });
|
||||
dispatcher()->reg(this, "domain/notation/file-open", [this](const actions::ActionName&) { open(); });
|
||||
|
||||
dispatcher()->reg(this, "copy", [this](const actions::ActionName&) {
|
||||
LOGI() << "NotationPaintView copy";
|
||||
});
|
||||
|
||||
// configuration
|
||||
m_backgroundColor = configuration()->backgroundColor();
|
||||
|
@ -56,6 +60,14 @@ NotationPaintView::NotationPaintView()
|
|||
});
|
||||
}
|
||||
|
||||
bool NotationPaintView::canReceiveAction(const actions::ActionName& action) const
|
||||
{
|
||||
if (action == "domain/notation/file-open") {
|
||||
return true;
|
||||
}
|
||||
return hasFocus();
|
||||
}
|
||||
|
||||
//! NOTE Temporary method for tests
|
||||
void NotationPaintView::open()
|
||||
{
|
||||
|
@ -258,6 +270,8 @@ void NotationPaintView::wheelEvent(QWheelEvent* ev)
|
|||
|
||||
void NotationPaintView::mousePressEvent(QMouseEvent* ev)
|
||||
{
|
||||
setFocus(true);
|
||||
|
||||
if (!isInited()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "iinteractive.h"
|
||||
#include "domain/notation/inotationcreator.h"
|
||||
#include "actions/iactionsdispatcher.h"
|
||||
#include "actions/actionable.h"
|
||||
#include "context/iglobalcontext.h"
|
||||
#include "async/asyncable.h"
|
||||
|
||||
|
@ -36,7 +37,9 @@
|
|||
namespace mu {
|
||||
namespace scene {
|
||||
namespace notation {
|
||||
class NotationPaintView : public QQuickPaintedItem, public IControlledView, public async::Asyncable
|
||||
class NotationViewInputController;
|
||||
class NotationPaintView : public QQuickPaintedItem, public IControlledView, public async::Asyncable,
|
||||
public actions::Actionable
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -74,6 +77,12 @@ private slots:
|
|||
|
||||
private:
|
||||
|
||||
<< << << < HEAD
|
||||
==
|
||||
== ===friend class NotationViewInputController;
|
||||
|
||||
bool canReceiveAction(const actions::ActionName& action) const override;
|
||||
>> >> >> > 189990597 ... added actionable and canRecanReceiveAction filter
|
||||
bool isInited() const;
|
||||
std::shared_ptr<domain::notation::INotation> notation() const;
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import QtQuick 2.7
|
||||
import MuseScore.NotationScene 1.0
|
||||
|
||||
Rectangle {
|
||||
|
||||
id: root
|
||||
FocusScope {
|
||||
|
||||
NotationPaintView {
|
||||
id: view
|
||||
|
|
Loading…
Reference in a new issue