lumiera_/src/gui/ctrl/mutation-message.hpp
Ichthyostega c8ad698ac4 MutationMessage: limit to treating of gui::model::Tangible
the generic typing to DiffMutatble does not make much sense,
since the desired implementation within gui::ctrl::Nexus
is bound to work on Tangibles only, since that is what
the UI-Bus stores in the routing table
2016-10-02 23:51:45 +02:00

163 lines
5.5 KiB
C++

/*
MUTATION-MESSAGE.hpp - message on UI-Bus to cause changes to tangible UI elements
Copyright (C) Lumiera.org
2016, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
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.
*/
/** @file mutation-message.hpp
** Message on the UI-Bus to cause changes on the targeted [UI-Element](\ref Tangible).
** The UI-Bus offers a dedicated API to direct MutationMessages towards Tangible elements,
** as designated by the given ID. Actually, such messages serve as capsule to transport a
** diff-sequence -- since a diff sequence as such is always concrete and tied to a specific context,
** we can not represent it directly as an abstract type on interface level. The receiver of a diff
** sequence must offer the ability to be reshaped through diff messages, which is expressed through
** the interface DiffMutable. In the case at question here, gui::model::Tangible offers this interface
** and thus the ability to construct a concrete lib::diff::TreeMutator, which in turn is bound to the
** internals of the actual UI-Element. Together this allows for a generic implementation of MutationMessage
** handling, where the designated UI-Element is reshaped by applying an embedded concrete diff message
** with the help of a `DiffApplicator<DiffMutable>`, based on the TreeMutator exposed.
**
** ## Creating mutation messages
** The UI-Bus invocation actually takes a reference to MutationMessage, and thus on usage a
** concrete instance needs to be created. This concrete Message embeds an actual diff sequence,
** which is some iterable sequence of lib::diff::DiffStep records.
** @warning be sure to understand that the diff sequence is really moved away and then consumed.
**
** @see [AbstractTangible_test]
**
*/
#ifndef GUI_CTRL_MUTATION_MESSAGE_H
#define GUI_CTRL_MUTATION_MESSAGE_H
#include "lib/error.hpp"
#include "lib/opaque-holder.hpp"
#include "lib/diff/tree-diff-application.hpp"
#include "gui/model/tangible.hpp"
#include "lib/format-util.hpp"
#include <utility>
#include <string>
namespace gui {
namespace ctrl{
using std::string;
namespace diff_msg { // implementation details for embedding concrete diff messages
using lib::diff::DiffApplicator;
using model::Tangible;
using std::move;
class Holder
{
public:
virtual ~Holder(); ///< this is an interface
virtual void applyTo (Tangible&) =0;
virtual string describe() const =0;
};
template<typename DIFF>
class Wrapped
: public Holder
{
DIFF diff_;
virtual void
applyTo (Tangible& target) override
{
DiffApplicator<Tangible> applicator(target);
applicator.consume (move(diff_));
}
virtual string
describe() const override
{
DIFF copy(diff_); // NOTE: we copy, since each iteration consumes.
return util::join (move(copy));
}
public:
Wrapped (DIFF&& diffSeq)
: diff_(move(diffSeq))
{ }
};
/** standard size to reserve for the concrete diff representation
* @note this is a pragmatic guess, based on the actual usage pattern within Lumiera.
* This determines the size of the inline buffer within MutationMessage.
* You'll get an static assertion failure when creating a MutationMessage
* from a concrete diff representation requiring more size...
*/
enum { SIZE_OF_DIFF_REPRESENTATION = sizeof(std::vector<string>)
+ sizeof(size_t)
+ sizeof(void*)
};
using Buffer = lib::InPlaceBuffer<Holder, SIZE_OF_DIFF_REPRESENTATION>;
}//(End) implementation details...
/**
* Message on the UI-Bus holding an embedded diff sequence.
* The Nexus (hub of the UI-Bus) will prompt the designated Tangible
* to expose a TreeMutator, and then apply the embedded diff.
*/
class MutationMessage
: public diff_msg::Buffer
{
public:
/** build a MutationMessage by _consuming_ the given diff sequence
* @param diffSeq some iterable DiffStep sequence.
* @warning parameter will be moved into the embedded buffer and consumed
*/
template<typename DIFF>
MutationMessage(DIFF&& diffSeq)
: diff_msg::Buffer{ embedType<diff_msg::Wrapped<DIFF>>()
, std::move(diffSeq)}
{ }
void
applyTo (model::Tangible& target)
{
access<diff_msg::Holder>()->applyTo(target);
}
operator string() const
{
return unConst(this)->access<diff_msg::Holder>()->describe();
}
protected:
};
}} // namespace gui::ctrl
#endif /*GUI_CTRL_MUTATION_MESSAGE_H*/