Lumiera  0.pre.03
»edit your freedom«
tangible.hpp File Reference

Go to the source code of this file.

Description

Abstraction: a tangible element of the User Interface.

This is a generic foundation for any elements of more than local relevance within the Lumiera UI.
Any such element is connected to the UI-Bus.

rationale

Simple user interfaces can be built by wiring up the actions right within the code processing the trigger of actions. This leads to core functionality littered and tangled with presentation code. The next step towards a more sane architecture would be to code a forwarding call into every UI action, invoking some core facade in turn. This approach works, but is repetitive and thus lures the lazy programmer into taking shortcuts. Since we can foresee the Lumiera UI to become quite challenging in itself, we prefer to introduce a mediating backbone, impersonating the role of the Model and the Controler in the MVC-Pattern in common UI architecture.

The MVC-Pattern as such is fine, and probably the best we know for construction of user interfaces. But it doesn't scale well towards the integration into a larger and more structured system. There is a tension between the Controller in the UI and other parts of an application, which as well need to be in control. And, even more important, there is a tension between the demands of UI elements for support by a model, and the demands to be placed on a core domain model of a large scale application. This tension is resolved by enacting these roles while transforming the requests and demands into Messages.

This way, we separate between immediate local control of UI state and the more global, generic concerns of interaction control and command binding. The immediately tangible "mechanics" of the UI shall be implemented in a conventional way, right within the concrete widget (or controller) code. But, since any widget concerned with more than local behaviour will inherit from Tangible, the embedded UI-Bus terminal Tangible::uiBus_ can be used for interaction with core services.

the generic interface element API

The generic interface element based on Tangible covers a set of behaviour common to all elements of the interface. This behaviour is targeted towards the integration with the core application. Beyond that, there are still several concerns regarding presentation, like a common styling. These are addressed the conventional way, through a common StyleManager. The following discussion focuses on the aspects of integration with the core.

For one reason or another, any element in the UI can appear and go away. This lifecycle behaviour corresponds to attachment and deregistration at the UI-Bus

In regular, operative state, an interface element may initiate actions, which translate into commands at the session interface. To complicate matters, there might be higher-level, cooperative gestures implemented within the interface, leading to actions being formed similar to sentences of spoken language, with the help of a focus concept – anyway, this means, in the end, there is a subject and a predicate. These need to be bound in order to form an action. And some interface element takes on or relates to the role of the underlying, the subject, the tangible element.

Todo:
Some actions are very common and can be represented by a shorthand. An example would be to tweak some property, which means to mutate the attribute of a model element known beforehand. Such tweaks are often caused by direct interaction, and thus have the tendency to appear in flushes, which we want to batch in order to remove some load from the lower layers.

And then there are manipulations that alter presentation state: Scrolling, canvas dragging, expanding and collapsing, moving by focus or manipulation of a similar presentation control. These manipulations in itself do not constitute an action. But there typically is some widget or controller, which is responsible for the touched presentation state. If this entity judges the state change to be relevant and persistent, it may send a state mark into the UI-Bus – expecting this marked state to be remembered. In turn this means the bus terminal might feed a state mark back into the tangible element, expecting this state to be restored.

A special case of state marking is the presentation of transient feedback. Such feedback is pushed from "somewhere" towards given elements, which react through an implementation dependent visual state change (flushing, colour change, marker icon). If such state marking is to be persistent, the interface element has in turn to send a specific state mark. An example would be a permanent error flag with an explanatory text showed in mouse over.

And finally, there are the essential updates – any changes in the model for real. These are sent as notifications just to some relevant top level element, expecting this element to request a diff and to mutate contents into shape recursively.

Interactions

  • lifecycle: connect to an existing term, supply the EntryID of the new element. This interaction also implies, that the element automatically detaches itself at end of life.
  • act: send a GenNode representing the action
  • note: send a GenNode representing the state mark
  • mark: receive a GenNode representing the feedback, a replayed state mark or generic message.
  • diff: prompt the element to retrieve a diff, which
    • either is an incremental status update
    • or is a from-scratch reconfiguration

Beside these basic interactions, the generic element also exposes some common signal slots

  • slotExpand() prompts the element to transition into expanded / unfolded state. If this state is to be sticky, the element answers with a state mark
  • slotReveal() prompts the element to bring the indicated child into sight. Typically, this request will "bubble up" recursively. These slots are defined to be sigc::trackable for automated disconnection see sigc-track for an explanation.
See also
AbstractTangible_test
BusTerm_test

Definition in file tangible.hpp.

#include "lib/error.hpp"
#include "lib/nocopy.hpp"
#include "stage/ctrl/bus-term.hpp"
#include "stage/model/expander-revealer.hpp"
#include "lib/diff/diff-mutable.hpp"
#include "lib/idi/entry-id.hpp"
#include "lib/symbol.hpp"
#include <sigc++/trackable.h>
#include <utility>
#include <string>

Classes

class  Tangible
 Interface common to all UI elements of relevance for the Lumiera application. More...
 

Functions

template<typename... ARGS>
lib::diff::GenNode commandMessage (Symbol cmdID, ARGS &&... args)
 convenience shortcut to build a message suitable for command invocation More...
 

Namespaces

 stage
 Lumiera GTK UI implementation root.
 
 stage::model
 The Lumiera GTK-GUI uses a thin proxy layer data model on top of the actual "high-level-model", which lives in the Steam-Layer below.