Commit graph

948 commits

Author SHA1 Message Date
3f396ef3b2 Timeline: ZoomWindow now passes all tests according to spec
- some test definitions were simply numerically wrong
- changed some aspects of the specified behaviour, to be more consistent
  + scrolling is more liberal and always allows to extend canvas
  + setting window to a given duration expands around anchor point
2022-11-11 03:06:33 +01:00
93de063ae5 Timeline: fix next ZoomWindow_test failure 2022-11-10 21:00:00 +01:00
fa4fbe5225 Timeline: clarify or fix further ZoomWindow_test failures
- forgot the bias towards the next larger grid aligned size
- implement safeguard against empty window
2022-11-09 03:25:35 +01:00
29f030d2a1 Timeline: implement rule for relative ZoomWindow positioning
This function allows to move the visible range such that it contains
a given time position; the relative location of this point within
the visible range however is in turn determined by relating it to
the current overall canvas: if we are close to the beginning, the
position is also located rather to the left side, and if we're
approaching the canvas end, the position tends to the right side...

(and yes, I am aware that the variant taking a rational number
can be derailed by causing internal numeric overflow, when passing
a maliciously crafted rational number, like INT_MAX-1 / INT_MAX )
2022-11-08 02:55:38 +01:00
a9df13f078 Timeline: define basic ZoomWindow setters on top of the normalisation
Rearrange the internal mutator functions to follow a common scheme,
so that most of the setters can be implemented by simple forwarding.
Move the change-listener triggering up into the actual setters.

This makes further test cases pass
 - verify_setup
 - verify_calibration
...implying that the pixel width is now retained
and basic behaviour matches expectations
2022-11-07 03:24:04 +01:00
14da237d5c Timeline: integrate relative scaling into ZoomWindow invariant handling
Since conformWindowToMetric() is always called prior to performing
the complete invariant-reestablishment sequence, we can even integrate
the rule for relative scaling into this central function, which
simplifies the mutation implementation significantly. Should
relative positioning go south, the following sanity checks
will push the window back into bounds.

With these changes, the verify_simpleUsage() test passes!
2022-11-07 01:30:27 +01:00
292be817b7 Timeline: investigate problem with numeric overflow in fractional arithmetic
Extensive tests with corner cases soon highlighted this problem
inherent to integer calculations with fractional numbers: it is
possible to derail the calculation by numeric overflow with values
not excessively large, but using large numbers as denominator.
This problem is typically triggered by addition and subtraction,
where you'd naively not expect any problems.

Thus changed the approach in the normalisation function, relying
on an explicitly coded test rather, and performing the adjustment
only after conversion back to simple integral micro-tick scale.
2022-11-07 00:19:28 +01:00
5ed5905d7f Timeline: work out a scheme of Invariants and Normalisation for the ZoomWindow
Getting all those requirements translated into code turns out to be a challenging task;
and the usual ascent to handle such a situation is to define **Invariants**
in conjunction with a normalisation scheme; each manipulation will then be
translated into invocation of one of the three fundamental mutators,
and these in turn always lead into the common normalisation sequence.

__Invariants__
- oriented and non-empty windows
- never alter given pxWidth
- zoom metric factor < max zoom
- visibleWindow ⊂ Canvas
2022-11-06 02:46:11 +01:00
f2ef893adb Timeline: complete specification of ZoomWindow expected behaviour
Writing this specification unveiled a limitation of our internal
time base implementation, which is a 64bit microsecond grid.
As it turns out, any grid based time representation will always
be not precise enough to handle some relevant time specifications,
which are defined by a divisor. Most notably this affects the precise
display of frame duration in the GUI, and even more relevant,
the sample accurate editing of sound in the timeline.

Thus I decided to perform the internal computation in ZoomWindow
as rational numbers, based on boost::rational

Note: implementation stubbed only, test fails
2022-11-04 03:40:36 +01:00
f1b3f4e666 Timeline: reconsider time handling and Stage/Steam integration
This ZoomWindow_test highlights again the question about the intended usage
of the Lumiera time entities. In which way do we want to perform time calculations,
and under which circumstances is it adequate to perform arithmetic on
raw time values?

These questions made me think about rather far reaching concerns regarding
subsidiarity and implicit or explicit usage context. Basically I could
reconfirm the design choices taken some years ago -- while I must admit
that the project is headed towards a way larger scale and more loose
coupling of the parts, than I could imagine several years ago, at the
time when the design started...

As a side note: we can not avoid that some knowledge about the time implementation
leaks out from the support lib; time codes themselves are tightly coupled
to the usage scenario within the session and can not be used as means
for implementing UI concerns. And the more generic time frameworks,
like std::chrono (as much as it is desirable to have some integration here)
will not be of any help for most of our specific usage patterns.
The reason is, for film editing we do not have a global time scale,
rather the truth is when the film starts....
2022-10-30 23:12:34 +01:00
7145d0d9ce Timeline: ZoomWindow implementation draft
implement the first test case: nudge the zoom factor
⟹ scale factor doubled
⟹ visible window reduced to half size
⟹ visible window placed in the middle of the overall range
2022-10-30 01:31:25 +02:00
b3fe6e16c6 Timeline: requirement analysis to define the ZoomWindow (see #1196) 2022-10-29 01:59:42 +02:00
7eca11b332 Timeline: draft arrangement to provide a display-metric (closes #1213)
The solution is to provide a standard implementation in the form of a mix-in,
which directly houses a `ZoomWindow` instance. Moreover, the latter
is deemed a prominent use case for the time::Control, allowing other
components to attach and push changes of the zoom state or register
as listeners to react to state changes.

Actually, the `TimelineLayout`, which hosts all the actual visible
widgets forming the timeline-UI, now integrates this mix-in; and since
`TimelineLayout` is passed to `TimelineController` and used there as
reference-`CanvasHook` for the root track, this implementation of
the `DisplayMetric` interface will ''effectively be used by all
widgets'' attached to the timeline canvas.
2022-10-28 02:08:34 +02:00
6637864be5 Timeline: reassess design of relative widget coordinates (see #1207)
Reading my work notes from two years ago, the concept can be validated.
Clarify the relation of the interfaces involved, and the role foreseen
for the upcoming `ZoomWindow` abstraction. This solution approach
will lead to multiple-stage indirect calls, which however are deemed
not to be overly concerning and will be investigated later, to avoid
premature optimisation (see #1254)

- `DisplayMetric` is a focused special purpose abstraction
- it belongs into the general abstraction of the `DisplayManager`
- it is rather linked by use to the other abstraction, the `CanvasHook`
- while the `RelativeCanvasHook` is not an interface, but an implementation mix-in
- and the actual `DisplayMetric` implementation can likewise be provided
  as mix-in, since it will typically be implemented in terms of a `ZoomWindow`

Using this scheme, it will be possible to avoid some of the indirect cally
by making this mix-in visible higher up the call graph -- in case the
actual need for optimisation can be confirmed in practice.
2022-10-27 23:10:39 +02:00
eb500dd453 ElementBox: successfully implemented size-constrained ClipWidget (closes #1235)
* restructure the widgets used to implement ElementBox
 * inject a Gtk::EventBox top-level base type to capture all Gdk-Events
 * push the Gtk::Frame one level down (TODO: API for managing children)

With these changes
 * dragging of Clips in the timeline works as expected
 * size constraints are observed precisely
 * all warnings and assertion failures from GTK disappeared

Thus we can conclude that the solution approach for size constrained widgets
was successful and this challenging problem is solved.
2022-10-21 19:18:21 +02:00
3953bbd5ee ElementBox: investigate and fix problem with label
...as it turned out, the ClipWidget did still invoke the
Gtk::Frame::set_label() function, thereby deactivate our
elaborate custom IDLabel and showing the label text
unconditionally instead (also violating our size constraint)
2022-10-21 01:24:54 +02:00
15e00e01c2 ElementBox: lower requirements for size-constraint handling
...as it turns out, this code basically works already when the
widget is not(yet) realized:
- when a widget is hidden, it responds with size=0
- when a widget is shown, it reponds with proper or at least
  preliminary size requirement, irrespective if already drawn

After injecting the diff, the widgets are created and then adjusted
in several steps; however, this code all executes from within a single
call to the UI-bus, and thus just piles up a sequence of realize()
and resize() messages, which are only executed later, in case the
Application-UI as a whole is visible on screen.

*Remaining Problems*:
 - size-constraint code not working correct in all cases
 - dragging works only on the buttons, not on the background
2022-10-20 19:36:59 +02:00
fd31f47498 ElementBox: integrate as base for Clip widget (see #1038)
According to plan, this was more or less a drop-in replacement.
However, this first integration prototype highlights some design problems

 * `ElementBoxWidget` is designed ''constructor-centric''
 * but the population by diff messages will supply crucial information later
 * and seemingly the size-constraint code is now invoked prior to widget realisation \\
   ⟹ Assertion Failure
2022-10-17 04:19:26 +02:00
34011b5d5e ElementBox: initial analysis regarding content rendering
...which is prerequisite to find out about the actual way
how ElementBoxWidget can be hooked up to serve as »Clip Widget«
2022-10-16 01:55:04 +02:00
aa26180824 ElementBox: integrate new Placement and Menu icon design (closes #1236)
The menu icon is possibly sightly to bright,
but it will do for now....
2022-10-15 19:44:41 +02:00
8abcc14ab2 Icon: variants turning the hand up/down 2022-10-14 20:26:49 +02:00
b3f2129473 Icon: draft an arrow hand for menu and expander
...required for the ElementBoxWidget,
featuring either a menu, or an expand/collapse button
2022-10-10 00:48:00 +02:00
06b5413987 Icon: fine-tuning and hinting the »Placement« design
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.
2022-10-09 21:19:03 +02:00
0a2f3ba395 ElementBox: further testing and investigation
- 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)
2022-10-04 00:51:05 +02:00
3bf3391a63 ElementBox: coping with size constraints (closes #1238)
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
2022-10-03 02:51:23 +02:00
8b6991e0f5 ElementBox: establish basic styling
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
2022-10-02 03:57:16 +02:00
ab8d1f3fb2 DOC: new section on GUI styles
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....
2022-10-01 20:44:07 +02:00
53c614afc2 ElementBox: extract the caption and size handling logic into sub widget
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)
2022-09-30 18:55:22 +02:00
c05abb88ab ElementBox: complete (base) implementation of size constrained layout
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).
2022-09-30 01:55:12 +02:00
b500fcd8f4 ElementBox: investigate adverse behaviour and work out solution
...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
2022-09-27 23:29:35 +02:00
f393780845 Lib: fix a bug with diagnostic output
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.
2022-09-27 01:51:21 +02:00
8fdde735d4 ElementBox: draft logic to impose size constraint on child widgets
...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
2022-09-26 02:48:49 +02:00
36594cd774 ElementBox: wire the standard implementation for size allocation
...if the strategy does not impose an explicit size constraint,
then use the inherited layout functions from GTK
2022-09-25 22:17:44 +02:00
acaeb330c3 ElementBox: Analysis and design for layout strategy...
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...
2022-09-25 01:16:10 +02:00
c439ade3da ElementBox: detailed survey of GTK layout code (see #1235)
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.
2022-09-24 02:41:11 +02:00
0f3298f004 ElementBox: push Icon spec into the Strategy helper
...the actual selection strategy remains to be implemented
...decision to stick to the Stock-ID scheme until we consider
   migration to GTK-4
2022-09-23 02:53:52 +02:00
4977d75014 ElementBox: support CSS selectors
The CSS class .background ensures there is an opaque backgdrop;
adding ID names to allow direct addressing in the stylesheet
2022-09-02 01:29:17 +02:00
38b6228fac ElementBox: working draft of ElementBoxWidget, establishing ctor framework
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.
2022-09-01 19:34:38 +02:00
ed7e3b4b32 ElementBox: extract builder qualifier support as library implementation
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
2022-08-28 23:36:27 +02:00
ff6234829a ElementBox: investigate ctor syntax possibilites
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
2022-08-28 01:02:10 +02:00
a0fe89689c private.mm: planning ElementBoxWidget (see #1185) 2022-06-05 19:35:24 +02:00
0622ddece8 private.mm: infos noted while debugging Yoshimi 2021-11-05 21:19:10 +01:00
6c63e5e3c0 Clip-Widget: considerations how to build it 2021-07-11 02:41:26 +02:00
5b1dfe4534 Clip-Drag: further investigation and clean-up
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.
2021-06-19 17:12:02 +02:00
b9657320ed Clip-Drag: Yay! dummy clip moves in the timeline when dragged
...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.
2021-05-14 19:42:20 +02:00
526f1d09e7 Clip-Drag: integrate indirectly with the TimelineLayout for metric translation
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
2021-05-13 18:29:37 +02:00
3e9aae30b3 Clip-Drag: switch implementation to the new observer/adapter 2021-05-13 16:14:11 +02:00
aad4087e26 Clip-Drag: reshape the Subject API to use a delegate/adapter
...for tracking and updating while the gesture is in formation
2021-05-09 15:14:14 +02:00
4caf790339 Library: verify PlantingHandle's extended capabilities
- 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
2021-05-07 22:50:13 +02:00
5a37bce855 Lib/Diff: extend PlantingHandle to allow for placment-new
...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.
2021-05-02 19:40:11 +02:00
5aa41accfc Lib/Diff: prefer the name "emplace" over "build"
...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
2021-05-02 18:31:47 +02:00
73740a24e3 Clip-Drag: refactor into sub-component of TimelineLayout
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
2021-04-30 19:46:32 +02:00
0fb3aab95b Clip-Drag: introduce sub-interface for canvas metric
...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
2021-04-30 18:44:10 +02:00
910a521ded Clip-Drag: investigate how to approach metric translation
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.
2021-04-29 14:41:02 +02:00
db3a525d6e Clip-Drag: get the gesture logic to work
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.
2021-04-17 22:32:26 +02:00
b5cf8b2303 Clip-Drag: draft the dragging controller logic
direct implementation with state flags in-class
Intention is to refactor this into a state machine eventually
2021-04-17 19:43:29 +02:00
8b5f6b0dea DOC: update and rework documentation regarding command access
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.
2021-04-16 18:14:33 +02:00
9796a8ebd0 Clip-Drag: requirements analysis in wider scope
...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.
2021-04-15 18:46:49 +02:00
0e98a1a940 Clip-Drag: investigate how to deal with motion events
...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++
2021-04-09 00:18:38 +02:00
e72df5c02d Clip-Drag: successfully hook up a signal binding for the trigger condition
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)
2021-04-03 19:49:30 +02:00
1187a81943 Clip-Drag: hook up the access point to the gesture definition
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
2021-04-02 17:39:42 +02:00
91273e5931 Clip-Drag: consider translation of command ctxID into a InteractionState implementation
...actually postpone to build a generic translation system and use hard wired relations for now;
it is acknowledged that we'll need some kind of translation system eventually,
once the GUI has to handle a lot of possibly configurable gestures.
2021-03-28 18:03:40 +02:00
65f16d54fa Clip-Drag: setup access-front-end via dependency injection
Decision to use a dedicated holder service (GestureState),
maintained as sub-service within InteractionDirector
2021-03-27 16:47:22 +01:00
451673dd09 Clip-Drag: now able to detect creation of a new clip widget
..and thus there is now one dedicated source location,
where configuration of new clip widgets can be done reliably.

So all prerequisites are solved and we can start
building a prototypical drag-gesture implementation
2021-03-27 14:42:08 +01:00
98a675e54c Clip-Drag: refactoring to establish prerequisites for dragging support
The specific twist with the clip display lies in the fact
that there might or might not be a dedicated clip widget,
based on the current presentation style and zoom level.

Consequently we need hook up the widget for dragging,
only when, and whenever a new clip widget is actually created.
This boils down to the requirement to detect whenever a state change
creates a dedicated widget -- and this can only be sensibly implemented
when all display state transitions are handled by a single function.

Previously, we had two specialised functions for this purpose:
one to initially create the delegate and one to switch the
implementation type for an already existing delegate.

This refactoring attempts to merge all this logic into a single function,
which now unfortunately became quite complex and hard to understand.
2021-03-27 01:30:06 +01:00
e2292e0239 Clip-Drag: start prototypical implementation of a gesture controller (see #1218)
My planning thus far seems solid enough to start fleshing out one concrete gesture handling,
which can serve as a blueprint for a generic scheme to be worked out later.
Moreover, the implementation is limited to mouse interaction for the time being,
while the goal remains to treat "gestures" in a way to span several
Interaction-Schemes eventually (mouse, key sequence, pen...).
2021-03-26 01:21:46 +01:00
e3f64d1c3c Clip-Drag: reshape that solution to avoid abundance of cross-links
...since it would be problematic, so store the prospective context data
for any conceivable gesture within each Widget possibly addressed by that gesture.

After some mulling over, today it finally occurred to me,
that I already solved a similar problem for the layout management,
and the very structure of ViewModel vs. Widget vs. Canvas settles
around that solution. Thus we could try to expand that structure --
which means that the gesture context is only created *late*, when the
gesture starts; and then the *subject* should be reponsible to collect
and establish the context for the gesture and feed it to the
gesture-controller, not the other way round
2021-03-12 16:54:19 +01:00
a64dc9c05f Clip-Drag: draft a solution for handling gestures
...even while keeping the focus to the actual problem at hand,
this solution must be built with the larger goal in mind, which
is the ability to support various editing gestures, transmitted
possibly through several control-systems (mouse, keybindings, pen...)

It is obvious that we'll need a dedicated controller for each kind of gesture;
what turns out as tricky is to maintain and bind a stateful context
and find the correct participants while a specific gesture is under way.
2021-02-28 23:04:06 +01:00
154868e8e2 Clip-Drag: reconsider the state of the command invocation scheme
As it turned out, I drafted a rather elaborate vision in 2017,
leading to the conclusion to better just implement the very simple
"point and shot" command invocation and to postpone anything more
advanced to a later point, when the properties of the actual UI
are defined more clearly.

Thus, what I have to build now is a first step in the direction
of the more elaborate vision, but only that, namely a first draft,
which should fit into the more complete solution later.
2021-02-22 00:21:53 +01:00
7e946fa1cc Clip-Drag: investigate the problem...
Can we build a simple feature to allow dragging clips in the timeline display?

Well... not really, at least not "simple".
As it turns out, the GTK-framework only supports classic "drag-n-drop",
which translates into sending an action to a drag target to receive a "document".

And, even worse, dragging clips must be implemented as a UI gesture,
and as such overlaps with the other gestures for editing, trimming.

In 2017, I did an comprehensive analysis of this problem, and then
concluded to postpone it. Thus the task now would be to build a
*simplified preview*, while being aware of the danger of creating
oversimplified structures, and the danger to hamper a complete
solution for implementing UI gestures...
2021-02-21 15:40:08 +01:00
ab718ed6aa DisplayEvaluation: get corrdinated vertical size roughly to work
Now basically the header labels are aligned with the start of the corresponding body area.

However, there still seems to be some minor glitch hidden somewhere,
and the labels seem to be off by one pixel per track. Also the allocated
canvas size is to small after first evaluation, but somehow gets
corrected whenever the window is resized.
2021-02-08 01:09:16 +01:00
8f572fc122 DisplayEvaluation: draft coordinated vertical layout (see #1211)
a first rather simplistic attempt to establish a vertically
synchronised layout between track header and body.

TODO: doesn't yet work as intended
2021-02-07 20:45:28 +01:00
34725afaa8 Clip: try out some solution to enforce a fixed extension
..now this more or less works and indeed crops the button widget
used here for a proof-of concept; however the label within that button
emits a lot of layout warnings on each event handling and drawing routine,
indicating that we violated its fundamental assumptions.

Not sure how to proceed from here; also not sure if this actually
becomes turns into a relevant issue in practice, since maybe in most cases
we'll rather increase the size, and all we really have to do is handle
the Clip's textual label properly. A clip smaller than some drop-down icon
should probably not be rendered explicitly, just as overview
2021-02-06 15:30:59 +01:00
453ee08803 Clip: investigate how to enforce a fixed horizontal extension
GTK doesn't expose a first-class API for this,
since -- by design -- the extension of a widget is negotiated.
Thus I'm looking for some kind of workaround for our specific use-case,
where a clip widget must be rendered with a well defined horizontal size,
corresponding to its length.

Thus far, we're only able to increase the size of the Button widget
used as placeholder, but we can not forcibly shrink that button,
probably because the embedded Gtk::Lable requires additional extension.
2021-02-05 00:21:08 +01:00
5570850377 Clip: review ClipDelegate creation
implement the special convention for Time::NEVER to hide such clips
2021-01-30 19:36:47 +01:00
c4634837a3 DisplayEvaluation: further testing and bugfixes
- fix a regression introduced with the 3rd DisplayEvaluation pass
- use references to pass the timings more efficiently to the ClipDelegate
- DisplayEvalutation in fact has a real LifeCycle and is not disposable
- generate the population diff for this test in canonical form
2021-01-30 19:01:56 +01:00
4451d5bfc9 Clip: implement re-attachment after layout change
with these changes, essentially the clip is moved to the
new position established in the preceding DisplayEvaluation.

...there is still some problem when this DisplayEvaluation itself
is triggered from within draw(), because then GTK still uses the old
sub-widget coordinates within this draw code, pretty much as if
they were cached somewhere. The next draw() call then uses the
proper new coordinates.
2021-01-30 16:29:06 +01:00
2e4cd56f4f Relative-Hook: rectify the design
Partially as a leftover from the way more ambitious initial design,
we ended up with CanvasHook as an elaboration/specialisation of the
ViewHook abstraction. However, as it stands, this design is tilted,
since CanvasHook is not just an elaboration, but rather a variation
of the same basic idea.

And this is now more like a building pattern and less of a generic
framework, it seems adequate to separate these two variations completely,
even if this incurs a small amount of code duplication.


Actually this refactoring is necessary to resolve a bug, where
we ended up with the same Clip widgets attached two times to the
same Canvas control, one time through the ViewHook baseclass,
and a second time by the ctor of the "derived" CanvasHook
2021-01-30 13:29:50 +01:00
e175805481 Clip: rearrange storage of clip presentation data
This can only be a preliminary solution, since we do not know
the actual usage pattern of the ClipDelegate object yet.
We only know there will typically be a huge amount of clips
to represent in the UI, and we need to be careful to avoid
unneccesary reallocations.

Thus for now we use a data record as base class, and we
move the data record into the new allocation when switching gears.
However, this could easily be converted into a data delegate,
where we'd only transfer ownership without reallocation,
in case this turns out to be more efficient.
2021-01-29 23:08:53 +01:00
96dfbf7d96 DisplayEvaluation: introduce a 3rd pass to adjust widget positions
After some in-depth analysis, it seems best to reattach the Clips and Marker
top-down through the control structure, rather than building some additional
magic callback into the CanvasHook. Thus the 3rd DisplayEvaluation pass
now not only has to rebalance track header and body, but also
reatach or move each attached widget within the body, using its
nominal coordinates. This should then pick up the changed
layout decoration size
2021-01-29 14:15:18 +01:00
5b33605469 Clip: fill in minimal implementation to make the clip appear 2021-01-25 03:06:27 +01:00
21f6e61fd3 Clip: evaluate state of the clip display implementation
...as it turns out, a first preliminary clip display should be working by now;
seemingly I was able to the tough theoretical problems last spring,
and was at the point of actually allocating display extension space
within the custom drawing area of the timeline.

Thus a simple placeholder widget based on a Gtk::Button should show up
at the right position, when sending a suitable diff message. The only
thing missing seems to be a first rough draft for the function
determineRequiredVerticalExtension()
2021-01-24 14:54:53 +01:00
acb674a9d2 Project: update and clean-up Doxygen configuration
...in an attempt to clarify why numerous cross links are not generated.
In the end, this attempt was not very successful, yet I could find some breadcrumbs...

- file comments generally seem to have a problem with auto link generation;
  only fully qualified names seem to work reliably

- cross links to entities within a namespace do not work,
  if the corresponding namespace is not documented in Doxygen

- documentation for entities within anonymous namespaces
  must be explicitly enabled. Of course this makes only sense
  for detailed documentation (but we do generate detailed
  documentation here, including implementation notes)

- and the notorious problem: each file needs a valid @file comment

- the hierarchy of Markdown headings must be consistent within each
  documentation section. This entails also to individual documented
  entities. Basically, there must be a level-one heading (prefix "#"),
  otherwise all headings will just disappear...

- sometimes the doc/devel/doxygen-warnings.txt gives further clues
2021-01-24 19:35:45 +01:00
06dbb9fad5 DiffFramework: simplify existing bindings
...by relying on the newly implemented automatic standard binding
Looks like a significant improvement for me, now the actual bindings
only details aspects, which are related to the target, and no longer
such technicalitis like how to place a Child-Mutator into a buffer handle
2021-01-23 12:55:10 +01:00
05b5ee9a7e Diff-Framework: investigate simplification for the most common case
After this long break during the "Covid Year 2020",
I pick this clean-up task as a means to fresh up my knowledge about the code base

The point to note is, when looking at all the existing diff bindings,
seemingly there is a lot of redundancy on some technical details,
which do not cary much meaining or relevance at the usage site:

- the most prominent case is binding to a collection of DiffMutables hold by smart-ptr
- all these objects expose an object identity (getID() function), which can be used as »Matcher«
- and all these objects can just delegate to the child's buildMutator() function
  for entering a recursive mutation.
2021-01-22 12:38:45 +01:00
657b94a4e3 ++ a strange year passed by ++
read the code, documentation and mindmap to find out
at what point I was when this story unfolded
2021-01-20 08:05:30 +01:00
28adf9a642 Clip: pondering about the representation of clip timings 2020-04-09 00:15:05 +02:00
765d124fff Clip: draft the decision logic for the clip presentation mode 2020-04-03 19:44:46 +02:00
e33eae729b Relative-Hook: complete refactoring down to tracks and clips (see #1213)
...and the result was very much worth the effort,
leading to more focused and cleaner code.

 - all the concerns of moving widgets and translating coordinates
   are now confined to the second abstraction layer (CanvasHook)

 - while the ViewHook now deals exclusively with attachment, detachment
   and reordering of attachment sequence
2020-03-23 04:16:10 +01:00
f956f27ff4 Relative-Hook: build CanvasHook abstraction based on ViewHook
this refactoring was expedient, as the code becomes
way more legible within each of the two levels of abstraction
2020-03-23 02:02:06 +01:00
22bc2167f9 Relative-Hook: prepare to split the abstraction into two levels
Level-1 : generic attachment into some kind of view
Level-2 : attachment by coordinates onto some kind of canvas
2020-03-22 16:37:58 +01:00
030fbd74c4 Clip: next step to establish a Delegate and appearance style
while the actual selection logic for the appearance style still remains
to be coded, this changeset basically settles the tricky initialisation sequence
2020-03-16 01:49:53 +01:00
dd016667ad Diff-Listener: add a variant to trigger also on value assignment (see #1206)
As it turned out, it is rather easy to extend the existing listener
for structural changes to detect also value assignments. Actually
it seems we'd need both flavours, so be it.
2020-03-15 23:11:14 +01:00
31116fb079 Clip: draft state-switching operation 2020-03-15 17:26:13 +01:00
4015a98d23 Clip: wire the optional startpoint parameter
...to indicate how the setting up the delegate might decide upon the appearance style

WIP: this is more than half baked
 - for one it seems doubtful to pass a hidden hint regarding appearance through that optional argument
 - and then, most importantly, we should be passing a time::TimeSpan
2020-03-15 00:47:55 +01:00
e4db0dbfd1 Clip: draft initialisation of display delegate (see #1038)
...first steps towards a solution to switch the appearence style of clips
2020-03-14 22:02:03 +01:00
4070cc0d83 DisplayEvaluation: draft evaluation invocation per track
...however, running into some type deduction problems...
2020-03-08 01:11:21 +01:00
5ddf426add DisplayEvaluation: skeleton of the evaluation invocation 2020-03-07 00:30:06 +01:00
5ad04edceb DisplayEvaluation: abandon the idea of scheduling batched resizes
- it seems such a feature is not possible to implement in a totally
   sane and safe way, since intermixed other UI messages might cause
   removal of some widgets for which we scheduled a change. And there
   is no simple and performant mechanism available to track the lifecycle
   of all the widgets involved

 - as it stands, it is actually not necessary to schedule the resizing
   for later, since the UI runs single-threaded, and thus GTK has no
   opportunity to act on them while our evaluation pass is running
2020-03-06 21:46:08 +01:00
1ea32c36a1 DisplayEvaluation: draft interfaces 2020-03-06 03:14:33 +01:00