added actionable and canRecanReceiveAction filter

This commit is contained in:
Igor Korsukov 2020-06-18 17:37:18 +02:00
parent 83ca802073
commit 7bb1cd2224
10 changed files with 142 additions and 52 deletions

View file

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

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,9 +1,7 @@
import QtQuick 2.7
import MuseScore.NotationScene 1.0
Rectangle {
id: root
FocusScope {
NotationPaintView {
id: view