2015-01-06 14:37:26 +01:00
|
|
|
/*
|
2015-11-27 19:24:00 +01:00
|
|
|
Tangible - common implementation base of all relevant interface elements
|
2015-01-06 14:37:26 +01:00
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2015, 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.
|
|
|
|
|
|
|
|
|
|
* *****************************************************/
|
|
|
|
|
|
|
|
|
|
|
2015-11-28 01:20:40 +01:00
|
|
|
/** @file tangible.cpp
|
|
|
|
|
** Common base implementation of all tangible and connected interface elements.
|
2015-01-06 14:37:26 +01:00
|
|
|
**
|
2015-11-28 01:20:40 +01:00
|
|
|
** @see abstract-tangible-test.cpp
|
2015-12-27 03:16:49 +01:00
|
|
|
** @see [explanation of the fundamental interactions](tangible.hpp)
|
2015-01-06 14:37:26 +01:00
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2015-11-27 19:24:00 +01:00
|
|
|
#include "gui/model/tangible.hpp"
|
2015-11-28 21:43:09 +01:00
|
|
|
#include "gui/model/widget.hpp"
|
|
|
|
|
#include "gui/model/controller.hpp"
|
2016-02-12 01:31:51 +01:00
|
|
|
#include "lib/diff/gen-node.hpp"
|
2015-01-06 14:37:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace gui {
|
|
|
|
|
namespace model {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-11-28 01:20:40 +01:00
|
|
|
Tangible::~Tangible() { } // Emit VTables here...
|
2015-01-06 14:37:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-12-27 01:58:15 +01:00
|
|
|
/** invoke the generic reset hook
|
|
|
|
|
* @note the actual subclass has to override the doReset() hook
|
|
|
|
|
* to perform the actual clean-up work.
|
|
|
|
|
* @remarks the intention is that, after invoking reset(), the
|
|
|
|
|
* interface element or controller is in pristine (presentation) state
|
|
|
|
|
*/
|
2015-11-28 23:50:56 +01:00
|
|
|
void
|
|
|
|
|
Tangible::reset()
|
|
|
|
|
{
|
|
|
|
|
this->doReset();
|
2016-02-13 22:36:42 +01:00
|
|
|
uiBus_.note (GenNode("reset", true));
|
2015-11-28 23:50:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-11-28 08:15:32 +01:00
|
|
|
/**
|
|
|
|
|
* Prepare a command or action for actual invocation, once the execution context
|
|
|
|
|
* has been established. The action is not executed right away, but it is now ready
|
2015-12-27 03:16:49 +01:00
|
|
|
* and bound to the concrete arguments supplied with the [record](\ref lib::diff::Rec).
|
2015-11-28 08:15:32 +01:00
|
|
|
* @param prototype handle to a command instantiation, to be readied for invocation
|
|
|
|
|
* @param arguments suitable tuple of values, to be used to outfit the prototype
|
|
|
|
|
*/
|
|
|
|
|
void
|
2015-11-28 21:43:09 +01:00
|
|
|
Tangible::prepareCommand (Cmd const& prototype, Rec&& arguments)
|
2015-11-28 08:15:32 +01:00
|
|
|
{
|
2015-12-18 01:02:19 +01:00
|
|
|
uiBus_.act (prototype.bind (std::forward<Rec>(arguments)));
|
2015-11-28 08:15:32 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-06 14:37:26 +01:00
|
|
|
|
|
|
|
|
/**
|
2015-11-28 08:15:32 +01:00
|
|
|
* Actually trigger execution of an action or command.
|
|
|
|
|
* @param preparedAction handle pointing to a command definition,
|
|
|
|
|
* which needs to be outfitted with arguments and ready for invocation.
|
2015-01-06 14:37:26 +01:00
|
|
|
*/
|
2015-11-28 08:15:32 +01:00
|
|
|
void
|
2015-11-28 21:43:09 +01:00
|
|
|
Tangible::issueCommand (Cmd const& preparedAction)
|
2015-01-06 14:37:26 +01:00
|
|
|
{
|
2015-11-28 21:43:09 +01:00
|
|
|
uiBus_.act (preparedAction.bang());
|
2015-01-06 14:37:26 +01:00
|
|
|
}
|
2015-11-28 08:15:32 +01:00
|
|
|
|
|
|
|
|
|
2015-12-25 03:53:26 +01:00
|
|
|
/**
|
|
|
|
|
* Expand this element and remember the expanded state.
|
|
|
|
|
* This is a generic Slot to connect UI signals against.
|
2015-12-26 00:59:16 +01:00
|
|
|
* @note The concrete Widget or Controller has to override the
|
|
|
|
|
* ::doExpand() extension point to provide the actual UI
|
|
|
|
|
* behaviour. If this virtual method returns `true`, the
|
|
|
|
|
* state change is deemed relevant and persistent, and
|
|
|
|
|
* thus a "state mark" is sent on the UI-Bus.
|
2015-12-25 03:53:26 +01:00
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
Tangible::slotExpand()
|
|
|
|
|
{
|
2015-12-26 00:59:16 +01:00
|
|
|
if (this->doExpand(true))
|
|
|
|
|
uiBus_.note (GenNode("expand", true));
|
2015-12-25 03:53:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Collapse or minimise this element and remember the collapsed state.
|
|
|
|
|
* This is a generic Slot to connect UI signals against.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
Tangible::slotCollapse()
|
|
|
|
|
{
|
2015-12-26 00:59:16 +01:00
|
|
|
if (this->doExpand(false))
|
|
|
|
|
uiBus_.note (GenNode("expand", false));
|
2015-12-25 03:53:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-12-27 01:58:15 +01:00
|
|
|
* @todo 12/2015 not clear yet what needs to be done
|
|
|
|
|
* @remarks the intention is to request the given child
|
|
|
|
|
* to be brought into sight. We need to set up some kind
|
|
|
|
|
* of children registration, but better not do this in
|
|
|
|
|
* a completely generic fashion, for danger of overengineering.
|
|
|
|
|
* Moreover, it is not clear yet, who will issue this request
|
|
|
|
|
* and at which element the initial request can/will be targeted.
|
2015-12-25 03:53:26 +01:00
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
Tangible::slotReveal(ID child)
|
|
|
|
|
{
|
|
|
|
|
this->doReveal(child);
|
|
|
|
|
this->doRevealYourself();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-12 01:31:51 +01:00
|
|
|
/**
|
|
|
|
|
* default implementation and catch-all handler for receiving »state mark« messages.
|
|
|
|
|
* Such messages serve either to cause a presentation state effect specific to this
|
|
|
|
|
* element, or they are used to re-play a former state change to restore some
|
|
|
|
|
* specific UI state captured within a past working session. Events handled here:
|
|
|
|
|
* - *expand* with a `bool` argument calls the `doExpand(bool)` virtual function.
|
|
|
|
|
* It is up to the concrete element to give this a tangible meaning, e.g. a track
|
|
|
|
|
* might switch to detail view and a clip might reveal attached effects.
|
|
|
|
|
* - *reset* restores the element to the hard wired default, by invoking `doReset()`
|
|
|
|
|
* - *revealYourself* prompts the element to take the necessary actions to bring
|
|
|
|
|
* itself into view. There is no requirement for an element to even implement
|
|
|
|
|
* this call, but those which do typically know some kind of _"parent object"_
|
|
|
|
|
* to forward this request, by invoking `doReveal(myID)` on this parent.
|
|
|
|
|
* For instance, a clip might ask the enclosing track, which in turn might
|
|
|
|
|
* call the enclosing timeline display for help, resulting in a scroll action
|
|
|
|
|
* to bring the clip into sight.
|
|
|
|
|
* @note this is a default implementation for a virtual function declared _abstract_
|
|
|
|
|
* with the intention for derived classes to tail-call this default handler.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
Tangible::doMark (GenNode const& stateMark)
|
|
|
|
|
{
|
|
|
|
|
if (stateMark.idi.getSym() == "expand")
|
|
|
|
|
this->doExpand (stateMark.data.get<bool>());
|
|
|
|
|
else
|
|
|
|
|
if (stateMark.idi.getSym() == "reset")
|
|
|
|
|
this->doReset();
|
|
|
|
|
else
|
|
|
|
|
if (stateMark.idi.getSym() == "revealYourself")
|
|
|
|
|
this->doRevealYourself();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-11-28 08:15:32 +01:00
|
|
|
|
2015-01-06 14:37:26 +01:00
|
|
|
}} // namespace gui::model
|