diff --git a/src/stage/widget/element-box-widget.cpp b/src/stage/widget/element-box-widget.cpp index e80e5ec24..9139df578 100644 --- a/src/stage/widget/element-box-widget.cpp +++ b/src/stage/widget/element-box-widget.cpp @@ -95,8 +95,11 @@ namespace widget { + + IDLabel::~IDLabel() { } ElementBoxWidget::~ElementBoxWidget() { } + Literal ElementBoxWidget::Config::getIconID() const { @@ -104,6 +107,13 @@ namespace widget { return "track_enabled"; //////////////////////////////////////////////TICKET #1219 : maybe at least a better generic placeholder icon...? } + Literal + ElementBoxWidget::Config::getMenuSymb() const + { + ///////////////////////////////////////////////////////////////////////////TICKET #1185 : implement logic to pick suitable icon... + return "gtk-go-down"; //////////////////////////////////////////////TICKET #1219 : maybe at least a better generic placeholder icon...? + } + Gtk::IconSize ElementBoxWidget::Config::getIconSize() const { @@ -124,25 +134,49 @@ namespace widget { } + IDLabel::IDLabel (Literal iconID, Literal menuSymb, Gtk::IconSize siz) + : Gtk::Box{Gtk::ORIENTATION_HORIZONTAL} + , imgIcon_{Gtk::StockID{iconID}, siz} ///////////////////////////////TICKET #1030 : use of stockIDs is deprecated; care for a more modern icon naming scheme + , imgMenu_{Gtk::StockID{menuSymb}, siz} //////////////////////// + { + icon_.set_image(imgIcon_); + menu_.set_image(imgMenu_); + this->add(icon_); + this->add(menu_); + this->add(name_); + this->set_name(ID_caption); + this->get_style_context()->add_class(CLASS_background); + name_.set_hexpand(true); + } + + + cuString + IDLabel::getCaption() const + { + return name_.get_text(); + } + + void + IDLabel::setCaption(cuString& idCaption) + { + name_.set_text(idCaption); + } + + ElementBoxWidget::ElementBoxWidget (Config config) : Frame{} , strategy_{config.buildLayoutStrategy(*this)} - , label_{Gtk::ORIENTATION_HORIZONTAL} - , icon_{Gtk::StockID{config.getIconID()} ///////////////////////////////TICKET #1030 : use of stockIDs is deprecated; care for a more modern icon naming scheme - , config.getIconSize()} + , label_{config.getIconID() + ,config.getMenuSymb() + ,config.getIconSize()} { set_name(ID_element); get_style_context()->add_class(CLASS_background); // Style to ensure an opaque backdrop set_label_align(0.0, 0.0); set_label_widget(label_); - label_.add(icon_); - label_.add(name_); - label_.set_name(ID_caption); - label_.get_style_context()->add_class(CLASS_background); - name_.set_text(config.getName()); - name_.set_hexpand(true); + label_.setCaption(config.getName()); this->show_all(); } @@ -238,15 +272,29 @@ namespace widget { * in case the extension of ElementBoxWidget is explicitly constrained in size. */ void - ElementBoxWidget::imposeSizeConstraint(int widthC, int heightC) + ElementBoxWidget::imposeSizeConstraint (int widthC, int heightC) { - ASSERT (name_.get_realized(), "ElementBoxWidget layout constraint imposed " - "on widget not yet realized by GTK"); - - bool hiddenCaption = not name_.get_visible(); - if (not hiddenCaption) + ASSERT (label_.get_realized(), "ElementBoxWidget layout constraint imposed " + "on widget not yet realized by GTK"); + label_.imposeSizeConstraint (widthC, heightC); + } + + /** + * Ensure the IDLabel stays within a given size constraint. + * In case the standard rendering of with icon and name caption exceeds + * the given screen space, this simplified initial implementation just + * hides the name caption, assuming without further check that the two + * icons will fit into the constrained space. + * @todo as of 9/22, a planned full implementation will eventually + * shorten the caption text and possibly also combine both + * Icons into a single button when necessary... ///////////////////TICKET #1238 : adjust size of the ID caption + */ + void + IDLabel::imposeSizeConstraint (int widthC, int heightC) + { + if (name_.get_visible()) { // detect if label box fits within given size constraint - queryNaturalSize (label_, labelFullSize_); + queryNaturalSize (*this, labelFullSize_); if (labelFullSize_.width > widthC or labelFullSize_.height > heightC) name_.hide(); diff --git a/src/stage/widget/element-box-widget.hpp b/src/stage/widget/element-box-widget.hpp index 17570e9ed..d57528993 100644 --- a/src/stage/widget/element-box-widget.hpp +++ b/src/stage/widget/element-box-widget.hpp @@ -93,12 +93,49 @@ namespace widget { using SizeGetter = std::function; + + /** + * Widget arrangement to represent an entity for manipulation. + * This uniform standard arrangement is comprised of + * - a leading Placement- or Type-Icon + * - a Menu button + * - a caption for identification + * The IDLabel widget offers standard hooks for wiring signals + * and controlling the layout; notably the widget extension + * can be confined to stay within given constraints. + */ + class IDLabel + : public Gtk::Box + { + Gtk::Image imgIcon_; + Gtk::Image imgMenu_; + Gtk::Button icon_; + Gtk::Button menu_; + Gtk::Label name_; + + public: + ~IDLabel(); + IDLabel(Literal iconID, Literal menuSymb, Gtk::IconSize); + + cuString getCaption() const; + void setCaption(cuString&); + + void imposeSizeConstraint(int, int); + + private: + Gtk::Requisition labelFullSize_{}; + }; + + + + /*************************************************************************//** * A basic building block of the Lumiera UI. - * Representation of an entity, with a marker icon, a menu, descriptive label and - * possibly a content renderer (e.g. for a video clip). Depending on the presentation intent, - * the widget can extend to a defined time range horizontally. Pre-defined styling and bindings - * to expand the display and to invoke a menu are provided + * Representation of an entity, with a marker icon, a menu, descriptive label + * and possibly a content renderer (e.g. for a video clip). Depending on the + * presentation intent, the widget can be set to a fixed horizontal extension, + * to allow presentation on a time calibrated canvas. Pre-defined styling and + * bindings to expand the display and to invoke a menu are provided. * @todo consider policy based design, //////////////////////////////////////////////////////////////////TICKET #1239 : re-evaluate Design, maybe use Policy Based Design * but need more exposure and real world usage as of 9/22 */ @@ -117,10 +154,7 @@ namespace widget { /** actual layout strategy binding for this widget */ Strategy strategy_; - - Gtk::Box label_; - Gtk::Image icon_; - Gtk::Label name_; + IDLabel label_; public: class Config; @@ -142,7 +176,6 @@ namespace widget { void on_size_allocate (Gtk::Allocation&) override; void imposeSizeConstraint(int, int); - Gtk::Requisition labelFullSize_{}; }; @@ -172,7 +205,8 @@ namespace widget { /** decide upon the presentation strategy */ Strategy buildLayoutStrategy(ElementBoxWidget&); - Literal getIconID() const; + Literal getIconID() const; + Literal getMenuSymb() const; Gtk::IconSize getIconSize() const; cuString diff --git a/wiki/renderengine.html b/wiki/renderengine.html index ccafa926f..44437d3c7 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -3217,7 +3217,7 @@ In accordance with this structure, we introduce a central component, the {{{Pane -
+
//A building block used pervasively throughout the Lumiera UI  to represent a named entity.//
 This widget presents a horizontally extended body, which holds a characteristic ''Head-Triplet'' of visual Elements:
 * an //Icon// to create the visual anchor point. In many cases, this will be ''the Placment Icon'' (a hallmark of Lumiera's UI)
@@ -3237,7 +3237,7 @@ This characteristic cadence of elements gives us a horizontal box with distinct
 !Properties
 * the Icon shall be easily configurable (from the coding view point, of course this is all hard wired in the code or the theme)
 ** the default is to configure the ''Placement Icon''
-** alternatively a ~Stock-ID can be given
+** alternatively the icon shall indicate the type of the object (video, audio, events, meta,...)
 * the horizontal extension is easy to control, through several options
 ** natural extension; don't give any ''size request'', let GTK figure out the extension rather
 ** set a fixed length-limit, causing the text label to be abridged eventually
@@ -3247,9 +3247,10 @@ This characteristic cadence of elements gives us a horizontal box with distinct
 We offer pre-arranged options for standard wiring of interaction response
 * when the Icon is a Placement, it will launch the [[Placement-Pop-up|GuiPlacementDisplay]] -- which in turn can be de-modalised, thereby allocating a place in the [[Property grid pane|GuiPropertyPane]]. When such a placement control already is open and allocated, the click to the placement icon will lead there.
 * in the most basic case, there is only one common binding, which is a signal, emitted when clicking on the icon or the menu button
-* yet there can be two distinct bindings (signals) for the icon and the button
-* the ''Expander'' (which is part of the UI-Element protocol) is pre-wired with the arrow on the menu button, to yield a visible clue for the expand/collapse state
+* yet there can be two distinct bindings (signals) for the icon and the button; when present, these //push aside (or shadow)// the generic signal
+* the ''Expander'' (which is part of the UI-Element protocol) is pre-wired with the arrow on the menu button, to yield a visible clue for the expand/collapse state; in this case, the menu changes to an up/down arrow and shadows the generic signal (which is typically a context menu)
 * each of the bindings can be easily replaced by a [[pop-up menu|GuiPopupMenu]]
+* the context menu opens on ''left click'' (selection will be ''right click'' in Lumiera!)
 
 !!!usage and setup
 The class {{{widget::ElementBoxWidget}}} uses a flexible declarative constructor style, defining the //intended use// while delegating the details of styling to CSS classes. On construction, it is mandatory to define
@@ -3277,8 +3278,23 @@ In addition to these mandatory arguments, a sequence of //qualifiers// can be su
 *{{{constrained(λ, [λₙ])}}} : constrain widget extension, providing getter functors to retrieve desired size in canvas pixels
 
 
+!!!presentation intent and layout
+The indicated //intent of presentation// controls various aspects of the basic arrangement and wiring -- this custom widget has to cover two quite different usage situations, and aims at establishing an uniform handling scheme throughout the UI. For one, it will represent an //item,// either within a selection or within a control pane (e.g. track head). While the other usage scenario is to present //content.//
+* presentation of items should be concise, and the visual clues serve to indicate the type of data or object
+* while the presentation of content aims at manipulation and arrangement; in many cases there is also an interaction with the content itself
+The common denominator however is, that ''each element is an object'' and thus can be ''placed'' (by a [[Placement]]), and it offers ''methods'' through a ''context menu''. Moreover, //mutations and manipulations// shall only be possible on ''selected elements'' (never accidentally by just clicking on something). Selection has to be //kept distinct from manipulation.// Just clicking on the placement icon (or the type icon for that) will activate a //property box,// enabling to tweak the //way of placement// together with some further generic marks and tags. Settings and tweaks on the content are rather accessed through the content display -- while there should be also a shortcut to move from the property box into tweaking of parameters (e.g. of effects)
+
+!!!!To summarise...
+* first icon → placement property box
+* second icon →
+** either expand / collapse
+** or the regular object context menu
+* click on the object also yields that context menu
+* mutation methods are only accessible when the entity is selected
+* the same holds true for manipulation through gestures (dragging, trim edits)
+
 !!!proportional Head placement
-This behaviour pattern (see [[#1186|https://issues.lumiera.org/ticket/1186]]) is a distinguishing trait of the Lumiera timeline display. It indicates elements with a temporal extension surpassing the current display window. Such elements are typically represented by an {{{ElementBoxWidget}}} with an large horizontal extension. Yet when scrolling, the head-triplet shall always remain within the visible area, but it will slowly glide from one side to the other, thereby indicating the our relative position. This pattern of behaviour matters, since, together with the scolled content display, it creates the dominant movement when scrolling an extended timeline
+This behaviour pattern (see [[#1186|https://issues.lumiera.org/ticket/1186]]) is a distinguishing trait of the Lumiera timeline display. It indicates elements with a temporal extension surpassing the current display window. Such elements are typically represented by an {{{ElementBoxWidget}}} with an large horizontal extension. Yet when scrolling, the head-triplet shall always remain within the visible area, but it will slowly glide from one side to the other, thereby indicating the our relative position. This pattern of behaviour matters, since, together with the scrolled content display, it creates the dominant movement when scrolling an extended timeline
 
 ''Technically'', this has to be build as a self-contained component, which can be unit-tested. The input and reference is a "Window" (in fact an interval) together with its start position //relative// to the element's own start position. The component has to derive from this input the actual relational configuration of the window's extension with respect to its own extension. For context, the //window// corresponds to the visible area, which can be larger, smaller disjoint, partially overlapping and fully contained. Please note that ''handling the relations of intervals is a notoriously challenging problem.''
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 3851babb7..6f47272e7 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -18184,6 +18184,79 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+  
+    
+  
+  
+    

+ ...das heißt, der Menü-Button ist dann nur pro forma da, und bietet eine Fläche, auf der man zuverlässig dieses Menü trifft; letzteres ist relevant für eine Anzeige in Listen und Bins, bei der ansonsten die Ausdehnung des Widgets stark reduziert ist. Ein Klick auf das Name-Label hat eine andere Funktion (nämlich Editieren des Namens). Ein Weiterer Aspekt ist die Drag-Geste: es ist denkbar, diese auf dem Menü-Button nicht zu starten (wobei allerdings zu bedenken ist, das Ziehen auch noch an weitere Voraussetzungen zu knüpfen, z.B. einen Modifiere, oder den Umstand, daß das Objekt auch selektiert ist) +

+ +
+ + + + + + +

+ Ja, wir wollen das alte Blender-Modell: Selektion mit rechts, Aktion mit links +

+ +
+ + +
+ + + + + + + + +

+ in diesem Fall ist das dann eine Art Toggle-Button, d.h. er wechselt auch seine Gestalt +

+ +
+ + + + + + + +

+ das verdrängt lediglich das Kontext-Menü +

+ +
+ + + + + +

+ ...denn das Kontext-Menü soll auf dem ganzen Widget liegen (und konkurriert übrigens mit der Drag-Geste) +

+ +
+
+
+
+
@@ -18223,8 +18296,8 @@
- - + + @@ -18260,7 +18333,7 @@ - + @@ -18587,6 +18660,43 @@ + + + + + + +
    +
  • + festes Schema aus zwei Icons +
  • +
  • + nur die Art der Icons wird ausgewechselt +
  • +
  • + beide Icons sind Buttons und lösen führen eine Steuer-Aktion aus (keine direkte Manipulation) +
  • +
  • + der erste Button führt immer in den Placement-Editor, der so etwas wie eine Property-Box darstellt (ggfs als Pop-Up, ggfs in einem Pannel-Grid) +
  • +
  • + der zweite Button öffnet entweder das normale Pop-up-Menü (das auf Linksklick liegt), oder er betätigt den Expander +
  • +
+ +
+ + +
+ + + + + + + + + @@ -19139,17 +19249,61 @@
+ + + + + + + + +

+ setName(cuString&) implementieren +

+ +
+ +
+ + + + + + + + + + + + + + + +
- - - + + + + + + - + + + + + + + + + + + @@ -19350,6 +19504,10 @@ + + + + @@ -58691,9 +58849,9 @@ - - + +