- need to simplify the design to make it effective
- add small sharpening seams and balance with drop shaddow
- reorder the lightening/drakening bevels to work properly
on top of various background colours
rework each of the 32px, 48px and 16px variants
so that the shape appears clear and succinct when rendered,
taking the aliasing into account; fine-tune and balance shadows.
Since this is one of the most central concepts in Lumiera,
and this Icon is expected to become a hallmark of the Lumiera UI,
it seems adequate to spend about two days on this graphic work.
Create an Icon or Emblem to represent the Placement concept.
Alluding to an Anchor, a Hook and the Letter "P"
This expands upon an Idea conceived some years ago
and used thus far within architecture and design diagrams
- remove unreferred definitions
- remove redundant style settings
- place bounding box tiles uniformly
- establish a standard stacking order
- introduce a naming scheme for the IDs
The reason for this pedantry is to simplify maintennance,
and to make the actual changes stand out clearly in Git
- Test the new layout code with debugger + dump messages
- Experiment: live changes to the name-ID content
(send msg. "manip" -> Text changed and Layout properly revalidated)
devise a more fine grained algorithm for adapting the display of IDLabel
to a situation with size constrained layout, e.g. for a time calibrated canvas.
We still do not implement the shortening of ID labels (see #1242),
since doing so would be surprisingly expensive. But at least we
do proceed in several steps now
- first attempt to reduce the name-ID (for now: hide it)
- if this doesn't suffice, also hide the menu
- and as a last resort, hide the icon and thus make the IDLabel empty
We are using buttons now, but the standard theme introduces a lot of padding arount button's contents.
Thus we need to consider ways to address the compound of widgets forming an ElementBox; moreover,
this is the classical situation where the BEM notation helps to clarify the intention....
The problem leading to custom styling here is the padding within buttons;
the default stylesheet seemingly adds a min-width and min-height setting,
and some padding within the Button; based on systematic CSS class names,
it is possible to remove these settings specifically for buttons
within the IDLabel in general (no need to treat only the case of an EventBoxLabel
-- IDLabel could become a custom widget on its own
As we continue with building the backbone of the UI,
and abundance of detail information regaring Layout and styling
will be encountered -- it is tantamount to have a place to
write those findings down....
as it turns out, this is a self-contained separate concern,
and thus this arrangement of two icons plus a caption shall
now manage itself as a custom widget.
And while touching this subject, I have also reconsidered
the purpose and arrangement of those icons and completed
the specification with some decisions...
- context menus will be left-click, selection right-click (Blender!)
- we will always show those two icons, just allocate different graphics
- when there is no expander, the 2nd icon will just serve to open the menu
- so the button is almost redundant in that case (except when dragging)
Further extended GTK code survey to clarify the role of the minimum_size,
it is indeed ignored by most standard containers, but it is actually
used by Gtk::Layout as starting point for the query sequence. Thus
it does not make sense to treat minimum and natural size differently;
both queries should be responded by returning our size constraint.
Unless we define additional borders and margins in the CSS, we can be sure
that GTK will base the size allocation on the exact values returned
from the get_required_* functions.
These functions will be invoked only from within the Event Loop
and after the ctor is finished, but before the first "draw".
They will be re-invoked on each "size change" event and on each
focus change (since a focus change may change the style and thus
the actual extension).
...the key point is to ask the embedded box holding the label
about it's preferred_size() -- this info is updated immediately,
even at begin, when the nested child widgets did not yet receive
an allocation.
Even while the preferred-size is something different than the
actual allocation, it will always be smaller and is thus sufficient
to decide if the size constraint can be met
The header "format-cout.hpp" offers a convenience function
to print pretty much any object or data in human readable form.
However, the formatter for pointers used within this framework
switched std::cout into hexadecimal display of numbers and failed
to clean-up this state.
Since the "stickyness" of IOS stream manipulators is generally a problem,
we now provide a RAII helper to capture the previous stream state and
automatically restore it when leaving the scope.
...does not work reliably yet...
- on first invocation, the child allocation is still zero
- later on, there seem to be lots of further invocations,
always when the application window gains focus
- these further invocations somehow change the visible extension
of the widget's background
identify the various dimensions, which require flexibility
to support the intended use cases; try to come up with a
design draft, allowing to settle on a preliminary version
soon, while not hampering further development later on.
Obviously this is a very deep and challenging topic,
and we're far from even remotely addressing it adequately;
we just need to get to the point to use this drafted version
as building block, since these usages will then push us further
into the right direction...
Investigate how the GTK implementation allocates size extension
to widgets and child widgets; identify possible extensions points
and work out a solution strategy to make GTK observe our specific
size constraints, which are derived from a time calibrated canvas.
The flexible custom styling yet needs to be definied.
Just adding a stock icon and a standard sized label field for now.
Widget can be constructed and successfully attached to a track.
Complete the investigation and turn the solution into a generic
mix-in-template, which can be used in flexible ways to support
this qualifier notation.
Moreover, recapitulate requirements for the ElementBoxWidget
Basically we want to create ElementBoxWidgets according to a
preconfigured layout scheme, yet we'll need to pass some additional
qualifiers and optional features, and these need to be checked
and used in accordance with the chosen flavour...
Investigating a possible solution based on additional ctor parameters,
which are given as "algebraic terms", and actually wrap a functor
to manipulate a builder configuration record
Seems to work solid now, after switching to the root coordinates provided by GDK.
With local relative coordinates, the subject fidgets while being dragged,
for obvious reasons, since we're shifting the relative point of reference.
Also clarified a strange behaviour of the test drawing code:
Cairo is "turtle graphics", so we need to set the starting point explicitly.
...well, the metric translation is not quite correct,
so it doesn't yet stick to the mouse. But all the challenging
problems within the framework for implementing such a generic
gesture seem to be solved now.
The ClipPresenter can access the CanvasHook wired into its actual ClipDelegate (widget).
And this in turn exposes the DisplayMetric, with the ability to transform
presentation coordinates (pixels) into a model representation (Time)
The actual translation is still hardwired placeholder code,
since it is planned to build an generic component "ZoomWindow"
to provide all the typical zomming and view window translations
found in every timeline editor
- move construct into the buffer
- directly invoke the payload constructor through PlantingHandle
- reconsider type signature and size constraint
- extend the unit test
- document a corner case of c++ "perfect forwarding",
which caused me some grief here
...this extension was spurred by the previeous refactoring.
Since 'emplace' now clearly denotes an operation to move-embed an existing object,
we could as well offer a separate 'create' API, which would take forwarding
arguments as usual and just delegates to the placement-new operation 'create'
already available in the InPlaceBuffer class.
Such would be a convenience shortcut and is not strictly necessary,
since move-construction is typically optimised away; yet it would also
allow to support strictly non-copyable payload types.
This refactoring also highlights a fuzziness in the existing design,
where we just passed the interface type, while being sloppy about the
DEFAULT type. In fact this *is* relevant, since any kind of construction
might fail, necessitating to default-construct a placeholder, since
InPlaceBuffer was intended for zero-overhead usage and thus has in itself
no means to know about the state of its buffer's contents. Thus the
only sane contract is that there is always a valid object emplaced
into the buffer, which in turn forces us to provide a loophole for
class hierarchies with an abstract base class -- in such a case the
user has to provide a fallback type explicitly.
...for the operation on a PlantingHandle, which allows
to implant a sub type instance into the opaque buffer.
* "create" should be used for a constructor invocation
* "emplace" takes an existing object and move-constructs
this allows to avoid multi-step indirection
when translating mouse dragging pixel coordinates
into a time offset for the dragged clip widget.
Moreover this also improves the design,
since the handling of canvas metric is pretty much
a self contained, separate concern
...previously this was modelled as part of the CanvasHook abstraction,
and in fact it will in any case be implemented by delegation to the
TimelineLayout or some kind of display manager.
We need this to tanslate mouse pixel movements into a time change
while dragging, effectively we have to translate a mouse position delta
into a TimeValue delta, and we want to avoid direct coupling to some
timeline display manager, to keep the gesture logic mostly generic.
some bugfixes,
but also a notable change: detect the completion of the gesture
directly when the button is released; this is necessary, because
seemingly we do not get motion_events when no button is pressed,
at least not in this test setup based on a Gtk::Button widget.
In 2017, I did a first design draft, followed by a design critique,
which partially obsoleted some ideas regarding command binding.
Mostly, the reason to abandon parts of that initial design was
due to the fact, that to many actual construction details of the
UI framework were not worked out at that time.
Thus I rather focussed on (re)-building a backbone for the timeline display,
in order to support that kind of flexibility aspired within the session model.
Now, when re-visiting the topic of an UI gesture (using simple dragging
of a clip in the timeline as an example for a first draft), I picked up
some of those planned structures, but tend to bind them together in
a slightly different way -- more akin to a state machine and less
in the way of an LR-parser.
This chagneset updates the relevant part within the TiddlyWiki
and the corresponding UML drawing to better reflect my actual thinking.
...because this is a prototype, but should fit in
with a future frameworks to handle complex interactions and gestures.
And no, we can not afford to rely on a UI toolkit for such a core concern
It is impossible that a framework like e.g. GTK will allow us to
support a custom made hardware controller and integrate it seamlessly
into getsture handling, thereby following a design philosophy that
is in accordance with our fundamental decisions.
...found out that GTK already implements an "implicit grab",
and thus the tricky situation that the mouse slides off the widget
can not happen at all; so in the end it's rather easy to build a trigger
for a dragging gesture.
The demo code is now activated only after the button is down
and just prints the position...
PS: did some research regarding the new Coroutines in C++
Setup the scaffolding necessary to get at the actual clip widget
and to establish a signal connection to the button_pressed signal.
The intention is to watch this in conjunction with mouse movements
for detection of the actual gesture.
At the moment, I am using button widgets as placeholder for the actual
clip widgets (not yet implemented...). And, as a tiny little success,
these buttons now invoke the gesture controller on right click
(left click is seemingly consumed by the button itself)
thus far my implementation concept seems to work as intended....
note: when populating the timeline with actual Clips,
the not-yet implemented linkSubject()-Function of the DragRelocateController
gets invoked (as it should), thereby killing Lumiera