Commit graph

4740 commits

Author SHA1 Message Date
022d40a8cf Block-Flow: initial draft of ExtentFamily storage
using a simple yet performant data structure.
Not clear yet if this approach is sustainable

- assuming that no value initialisation happens for POD payload
- performance trade-off growth when in wrapped-state vs using a list
2023-07-04 04:42:53 +02:00
23a6fbdf4f Scheduler: investigate modes of operation
- analysis of Activity usage
- derive possible memory management schemes
- research regarding asynchronous IO
- decision regarding the memory management scheme
2023-07-03 18:40:37 +02:00
4176576db0 Scheduler: consider what operations are necessary for layer-1
....still about to find out what kinds of Activities there are,
and what reasonably to implement on layer-2 vs. layer-1

It is clear that the worker will typically invoke a doWork()
operation on layer-2, which in turn will iterate layer-1.

Each worker pulls and performs internal managmenet tasks exclusively
until encountering the next real render task, at which point it will
drop an exclusion flag and then engage into performing the actual
extended work for rendering...
2023-06-27 03:21:10 +02:00
3b6519a7c0 Scheduler: pass activity marker (low-level)
- define a simple record to represent the Activity
- define a handle with an ordering function
- low-level functions to...
  + accept such a handle
  + pick it from the entrace queue
  + pass it for priorisation into the PriQueue
  + dequeue the top priority element
2023-06-26 02:16:50 +02:00
bdcfc94b57 Scheduler: implementation technology
- use Boost-Lockfree as entrance queue for instructions
- use the STL Heap-Algo and Priority-Queue adaptor for time order
2023-06-25 01:02:12 +02:00
3169ba88ad Scheduler: devise the arrangement of basic components
- define organisation of vault-layer namespaces
- define the ground plan of the scheduler implementation
2023-06-24 03:14:17 +02:00
130bc095d9 the new design takes the old name
The second design from 2017, based on a pipeline builder,
is now renamed `TreeExplorer` ⟼ `IterExplorer` and uses
the memorable entrance point `lib::explore(<seq>)`

✔
2023-06-22 20:23:55 +02:00
d109f5e1fb bye bye Monad (closes #1276)
after completing the recent clean-up and refactoring work,
the monad based framework for recursive tree expansion
can be abandoned and retracted.

This approach from functional programming leads to code,
which is ''cool to write'' yet ''hard to understand.''

A second design attempt was based on the pipeline and decorator pattern
and integrates the monadic expansion as a special case, used here to
discover the prerequisites for a render job. This turned out to be
more effective and prolific and became standard for several exploring
and backtracking algorithms in Lumiera.
2023-06-22 20:23:55 +02:00
8c78e50730 Job-Planning: extended deadline integration test
- allow to configure the expected job runtime in the test spec
- remove link to EngineConfig and hard-wire the engine latency for now

... extended integration testing reveals two further bugs ;-)
... document deadline calculation
2023-06-21 04:04:11 +02:00
1f840730a0 Job-Planning: build and verify complete pipeline
- strip the builder
- add a terminal / front-end with convenience functions
- verify integration, incl multi-step prerequisites and deadlines
2023-06-20 01:46:44 +02:00
848bb6fb86 Job-Planning: implement handling of deadlines for prerequisites
...simple implementation
...decide *not* to cache the deadlines for now (possibly quadratic!)
...Test GREEN
2023-06-19 18:28:01 +02:00
dc1bbfc918 Job-Planning: rework pipeline to enable dependency planning
This finishes the last series of refactorings; the basic concept
remains the same, but in the initial version we arranged the expander
function in the pipeline to maintain a Tuple (parent, child) for the
JobTickets. Unfortunately this turned out to be insufficient, since
JobTicket is effectively const and responsible for a complete Sement,
so there is no room to memorise a Deadline for the parent dependency.

This leads to the better idea to link the JobPlanning aggregators
themselves by parent-child references, which is possible since the
whole dependency chain actually sits in the stack embedded into the
Expander (in the pipeline)
2023-06-19 03:56:11 +02:00
2b92dab377 Library: change »assignment« of ItemWrapper to destroy-create
This very deep change (which requires almost complete rebuild)
was prompted by the need to process an object (JobPlanning),
which holds several references and is thus move-only, in the
middle of a complex processing pipeline with child expansion.

If this works out well, a long-standing and obnoxious problem
with transforming iterators would be solved, albeit by incurring
a (presumably small) performance overhead, since now the new
value is no longer *assigned*, but rather the existing payload
is destroyed and a new instance is copy/move constructed into
the inline buffer.

The primary purpose (and widely used in Lumieara) is to have a
Lambda create a new Object, which is then returned by value
and thus immediately moved into this inline buffer, where it
resides for further use (as long as the enclosing pipeline
stays alive). Unless such an object does very elaborate
allocations and registrations behind the scene, the
expense of assigning vs creating should be the same.
2023-06-19 02:33:50 +02:00
9ef3d98de7 Job-Planning: replace FrameCoord by direct references
...in the hope that the Optimiser is able to elide those references entirely,
when (as is here the case) they point into another field of a larger object compound
2023-06-19 01:51:48 +02:00
a1c1456849 Job-Planning: dispose of FrameCoord in pipeline and Dispatcher interface
...as a preparation for solving a logical problem with the Planning-Pipeline;
it can not quite work as intended just by passing down the pair of
current ticket and dependent ticket, since we have to calculate a chained
calculation of job deadlines, leading up to the root ticket for a frame.

My solution idea is to create the JobPlanning earlier in the pipeline,
already *before* the expansion of prerequisites, and rather to integrate
the representation of the dependency relation direcly into JobPlanning
2023-06-18 03:50:48 +02:00
661d768fad Job-Planning: frame number now additionally required in FrameCoord
...which was the reason why the test failed;
the calculation works as expected


PS: rename JobPlanningSetup_test to JobPlanningPipeline_test
2023-06-17 03:10:57 +02:00
6228c623b4 Job-Planning: implement braindead deadline calculation
...using hard coded values instead of observation of actual runtimes,
but at least the calculation scheme (now relocated from TimeAnchor to JobPlanning)
should be a reasonable starting point.

TODO: test fails...
2023-06-16 04:09:38 +02:00
73a9e4495a Job-Planning: code up simplest use case 2023-06-16 01:50:11 +02:00
b9f8356afc Job-Planning: investigate input data
- collect list of entities to be picked up from the dispatcher-pipeline
- as it turns out: there is no sensible use for the realTimeDeadline in
  in the FrameCoord record ==> remove it
2023-06-15 18:24:25 +02:00
a551314e80 Job-Planning: start rework of the planning data aggregation
The initial implementation effort for Player and Job-Planning
has been reviewed and largely reworked, and some parts are now
obsoleted by the reworked alternative and can be disabled.

The basic idea will be retained though: JobPlanning is a
data aggregator and performs the final step of creating a Job
2023-06-15 03:51:07 +02:00
f84517547b Dispatcher-Pipeline: coordination of base tick and prerequisite expansion
- had to fix a logical inconsistency in the underlying Expander implementation
  in TreeExplorer: the source-pipeline was pulled in advance on expansion,
  in order to "consume" the expanded element immediately; now we retain
  this element (actually inaccessible) until all of the immediate
  children are consumed; thus the (visible) state of the PipeFrameTick
  stays at the frame number corresponding to the top-level frame Job,
  while possibly expanding a complete tree of flexible prerequisites

This test now gives a nice visualisation of the interconnected states
in the Job-Planning pipeline. This can be quite complex, yet I still think
that this semi-functional approach with a stateful pipeline and expand functors
is the cleanest way to handle this while encapsulating all details
2023-06-14 18:12:41 +02:00
08dfe1007c Dispatcher-Pipeline: verify the expansion of prerequisites
- fix a bug in the MockDispatcher, when duplicating the ExitNodes.
  A vector-ctor with curly braces will be interpreted as std::initializer_list

- add visualisation of the contents appearing at the end of the pipeline

*** something still broken here, increments don't happen as expected
2023-06-14 04:20:50 +02:00
542017aa65 Dispatcher-Pipeline: mocked Dispatcher implementation complete (closes: #1294)
`steam/engine/mock-dispatcher.hpp |cpp` now integrates this
''complete mock setup for render jobs and frame dispatching.''
The exising `DummyJob` has been slightly adapted and renamed
to `MockJob` and is tightly integrated with the other mocks.

The implementation of a `MockDispatcher` necessitated to change
the use of `MockJobTicket`. The initial attempts used a complete
mock implementation, but this approach turned out not to be viable.
Instead — based on the ideas developed for the mock setup —
now the prospective real implementation of `JobTicket` is available
and will be used by the mock setup too. Instead of a synthetic spec,
now a setup of recursively connected `ExitNode`(s) is used; the latter
seems to develop into some kind of Facade for the render node network.

Based on this mock setup, we can now demonstrate the (mostly) complete
Job-Planning pipeline, starting from a segmentation up to render jobs,
and verify proper connectivity and job invocation.
✔
2023-06-13 20:23:33 +02:00
0b9705692b Dispatcher-Pipeline: now (finally) able to implement MockDispatcher
MockSupport_test      : PASS
JobPlanningSetup_test : PASS(as far as defined)
2023-06-13 03:47:42 +02:00
122addbff5 Dispatcher-Pipeline: expected behaviour of (mock)Dispatcher 2023-06-13 00:15:16 +02:00
2031a58775 Dispatcher-Pipeline: decide upon the translation into portIDX
- has to be prepared / supported by the RenderEnvironmentClosure
- actual translation happens when building the Dispatcher-Pipeline
- implementation delegate through
    virtual size_t Dispatcher::resolveModelPort (ModelPort)
2023-06-12 19:21:14 +02:00
e6dcb6253c Dispatcher-Pipeline: resolve further problems with re-entrant allocation
...ouch this was insidious: the STL implementation for list does not
return a pointer to the element just allocated, but rather retrieves
and dereferences the back() / front() iterator after returning from emplace_back|front()

...which in case of re-entrant allocations is something wildly different
than the initial allocation. Thus a *cheap* and dirty placeholder implementation
just using a STL container is not possible, and we need at least
to code up likewise cheesy placeholder implementation by hand.
- separate allocation and ctor all
- use an inline buffer in the STL container
- explicitly handle ctor failures to discard allocation
- NOT THREADSAFE and likely WASTFUL in terms of performance


==> MockSupport_test now back to GREEN after complete refactoring
2023-06-12 17:21:41 +02:00
bf3e612c55 Dispatcher-Pipeline: create hook for self-validation
...later to be extended into the render nodes network
2023-06-12 01:18:59 +02:00
0933d2bba8 Dispatcher-Pipeline: simplify JobTicket and remove channel differentiation
The existing implementation of the Player from 2012~2015 inclduded
an additional differentiation by media channel (for multichannel media)
and would build a separate CalcStream for each channel.

The in-depth analysis conducted for the ongoing »Vertical Slice« effort
revealed that this differentiation is besides the point and would never
be materialised: Since -- by definition -- all media processing has
to be done by the engine, also the generation of the final output format
including any channel multiplexing will happen in render nodes.
The only exception would be when only a single channel of multichannel
media is extracted -- yet this case would then translate into a
dedicated ModelPort.

Based on this reasoning, a lot of complexity (and some contradictions)
within the JobTicket implementation can be removed -- together with
some further leftovers of the fist attempt to build JobTickets always
from a Mock specification (we now use construction by the Segment,
based on an ExitNode, which is the expected actual implementation
for production setup)
2023-06-12 00:04:45 +02:00
b18e79d077 Dispatcher-Pipeline: solve allocation of JobTicket instances
...by defining a new scheme for access to custom allocators
...and then passing a reference to such an accessor into the
   JobTicket ctor, thereby allowing the ticket istelf recursively
   to place further JobTicket instances into the allocation space

--> success, test passes (finally)
2023-06-11 04:37:38 +02:00
f25ec2f5ef Dispatcher-Pipeline: switch JobTicket creation to use ExitNode directly
Up to now, a draft/mock implementation was used, relying on a »spec tuple«,
which was fabricated by MockJobTicket. But with the introduction of
NodeGraphAttachment, the MockSequence now generates a nested ExitNode structure,
and thus the JobTicket will be created through the "real" ctor, and
no longer via MockJobTicket.

Thus it is possible to skip this whole interspersed »spec tuple«,
since ExitNode *is* already this aggregated / abstracted Spec
2023-06-10 04:52:40 +02:00
2c3b85a122 Dispatcher-Pipeline: allocate JobTicket in Segment
PROBLEM: can not implement Spec-generation, since
 - we must use a λ for internal allocation of JobTickets
 - but recursive type inference is not possible

Will thus need to abandon the Spec-Tuple and relocate this
traversal-and-generation code into JobTicket itself
2023-06-09 02:48:38 +02:00
c246c21e41 Dispatcher-Pipeline: remould Segment for on-demand JobTicket generation
Use another unit-test (FixtureSegment_test) to guide and cover
the transition from the existing fake-implementation to the
actual implementation, where the JobTicket will be generated
on-demand, from a NodeGraphAttachment
2023-06-08 03:21:43 +02:00
f6af4c6a16 Dispatcher-Pipeline: prepare test for the new NodeGraphAttachment
It turns out that the real (not mocked) implementation of JobTicket creation
is already required now for this planned (mock)Dispatcher setup;
moreover, this real implementation turns out to be almost identical
to the mock implementation written recently -- just nested structure
of prerequiste JobTickets need to be changed into a similar structur
of ExitNodes

-- as an aside: rearrange various tests to be more in-line
   with the envisioned architecture of playback and engine
2023-06-07 04:03:00 +02:00
3b2e5db7b4 Dispatcher-Pipeline: consider how to access render nodes from job
...this opens up yet another difficult question and a host of new problems
- how are prerequisites detected or arranged by the Builder
- how are prerequisites represented?
- what is an ExitNode in terms of implementation? A subclass of ProcNode?
- how will the actual implementation of JobTicket creation (on-demand) work?
- how to adapt the Mock implementation, while retaining the Specification
  for Segments and prerequisites?
2023-06-06 04:25:12 +02:00
7d5c32e6b6 Dispatcher-Pipeline: draft test for JobTicket access 2023-06-05 18:09:42 +02:00
a5b3a16f3e Dispatcher-Pipeline: clean setup for builder and pipeline types
..this is now the third attempt, and it seems this one leads to a
clean solution for the type rebinding problem, while also allowing
to unit-test each step in isolation.

The idea is to layer a *templated* builder class on top,
but to slice it away in each step, re-assemble the pipeline
and decorate a new builder instance on top. The net result
is a tightly interconnected processing pipeline without
any spurious interspersed leftovers from the builder,
while all intermediate steps are fully operational
and can thus be unit-tested...
2023-06-05 02:52:10 +02:00
41a8c7ec1a Dispatcher-Pipeline: draft Step-2 and Step-3
...still very rough edged...
...based on the idea to have a pair(Dependent,Dependency) and to shift these on each level of expansion

PROBLEMS:
 - what to use as root level?
 - can not handle JobTicket const& in transform-iterator (assignement operator)
2023-06-04 03:58:15 +02:00
4601c6350e Dispatcher-Pipeline: arrangement of builder types
...it turns out that we actually do not need to wrap TreeExplorer
on the builder types, because basically there is only a single active
builder type, and the complete processing pipeline can be assembled
in a single terminal function.

The type rebinding problem can thus be solved just by a simple
marker struct, which inherits from a template parameter
2023-06-04 02:01:07 +02:00
71ea10bf21 Dispatcher-Pipeline: implement the frame-tick core
splitting into a sequence of builder types seems to have done the trick
2023-06-03 18:38:37 +02:00
81ee9a2e67 Dispatcher-Pipeline: builder type rebinding problems
...hard to tackle...
The idea is to wrap the TreeExplorer builder, so that our specific
builder functions can delegated to the (inherited) generic builder functions
and would just need to supply some cleverly bound lambdas. However,
resulting types are recursive, which does not play nice with type inference,
and working around that problem leads to capturing a self reference,
which at time of invocation is already invalidated (due to moving the
whole pipeline into the final storage)
2023-06-03 03:44:22 +02:00
94fe4a4bec Dispatcher-Pipeline: draft builder-API
...which leads to the next daunting problems:
- we need some mocked ModelPort and DataSink placeholders
- we need a way how to inherit from a partial TreeExplorer pipeline
2023-06-02 05:32:15 +02:00
ad173540d9 Library: allow for a stop condition in iterator pipeline
...introduced in preparation for building the Dispatcher pipeline,
which at its core means to iterate over a sequence of frame positions;
thus we need a way to stop rendering at a predetermined point...
2023-06-01 16:48:27 +02:00
fbfbd2a078 Dispatcher+Scheduler: decision to dispose of the TimeAnchor
several years ago, it seemed like a good idea to incorporate
the link between nominal time and wall-clock time into a dedicated
anchor point, which also regulates the continued frame planning.

But it turned out that such a design mixes up several concepts
and introduces confusion regarding the meaning of "real time"
- latency can not be reasonably defined for a whole planning chunk
- skipping or sliding due to missed deadlines can not reasonably handled
  within such an abstract entity; it must be handled rather at the
  level of a playback process
- linking the frame grid generation directly to a planning chunk
  undercuts the possible abstraction of a planning pipeline
2023-05-31 03:27:13 +02:00
87f40c8169 Dispatcher+Scheduler: Requirement analysis and planning work 2023-05-29 04:43:10 +02:00
b4c0ffab25 Job-Planning: Analysis for the next step
...which is build a »Job planning pipeline« step by step
in a test setup, and then factor that out as RenderDrive,
to supersede the existing CalcPlanContinuation and get
rid of the Monads this way...

Challenges
- there is a inconsistency with channel usage
- need to establish a way how to transport the output-Sink into the JobFunctor
- need a way to propagate the current frame number to the next planning chunk
2023-05-26 04:20:12 +02:00
e33689e5d6 Job-Planning: verify and complete the build-up of mock structures (see #1294)
The prototypical setup of data structures and test support components
is largely complete by now — with the exception of the `MockDispatcher`,
which will be completed while moving to the next steps pertaining the
setup of a frame dispatch pipeline.

 * the existing `DummyJob` was augmented to allow verification of
   association between Job and `JobTicket`
 * the existing implementation of `JobTicket` was verified and augmented
   to allow coverage of the whole usage cycle
 * a `MockJobTicket` was implemented on top, which can be generated
   from a symbolical test specification (rather than from the real
   Fixture data structure)
 * a complete `MockSegmentation` was developed, allowing to establish
   all the aforementioned data structures without an actual backing
   Render Engine. Moreover, `MockSegmentation` can be generated
   from the aforementioned symbolic test specification.
 * as part of this work, an algorithm to split an existing Segmentation
   and to splice in new segments was developed and verified
2023-05-24 03:38:12 +02:00
4f37b0412c Job-Planning: finally complete the MockSegmentation tests
Last testcase: add deeply nested Prerequisites.
Turns out that the allocator must be able to handle
re-entrant allocations, which std::deque can not fulfil.
Thus using std::list here for the Mock implementation.

In the end, the real allocations will be done by our custom
allocator (AllocationCluster), which can be arranged easily
to support re-entrant allocation calls (since the whole point
is to just place those objects into a pre-allocated large block
and only de-allocate them later in one sway. Thus the allocator
does not need to wait for the object constructor to finish, which
trivially allows for re-entrant calls)
2023-05-23 06:40:18 +02:00
94cec423d0 Job-Planning: switch to processing references
...which uncovers further deeply nested problems,
especially when referring to non-copyable types.

Thus need to construct a common type that can be used
both to refer to the source elements and the expanded elements,
and use this common type as result type and also attempt to
produce better diagnostic messages on type mismatch....
2023-05-23 01:08:05 +02:00
bf6951afcf Job-Planning: verify pipeline can now be constructed (after bugfix)
verify by in-depth investigation that all nested typedefs are now properly constructed
2023-05-23 01:07:53 +02:00
0df0fd001e Library: fix follow-up problems with const correctness
...the improved const correctness on STL iterators uncovered another
latent problem with out diagnositc format helper, which provide
consistently rounded float and double output, but failed to take
CV-qualifiaction into account
2023-05-23 01:07:53 +02:00
e176e54004 Library: adjust and fix semantics of nested 'value_type' binding
This is a subtle and far reaching fix, which hopefully removes
a roadblock regarding a Dispatcher pipeline: Our type rebinding
template used to pick up nested type definitions, especially
'value_type' and 'reference' from iterators and containers,
took an overly simplistic approach, which was then fixed
at various places driven by individual problems.

Now:
 - value_type is conceptually the "thing" exposed by the iterator
 - and pointers are treated as simple values, and no longer linked
   to their pointee type; rather we handle the twist regarding
   STL const_iterator direcly (it defines a non const value_type,
   which is sensible from the STL point of view, but breaks our
   generic iterator wrapping mechanism)
2023-05-23 01:07:53 +02:00
46ab053b8a Library: investigate / consolidate usages of type rebinding from iterators
...in an attempt to resolve the deeply nested problems encountered
while building an iterator pipeline for the Dispatcher. It seems
that I was sloppy some years ago and just "bashed them into submission",
thereby mixing up two different meanings of "value_type"

Moreover I seemingly implemented the same helper trait template twice,
so the first step is to switch all usages to meta::TypeBinding
2023-05-23 01:07:53 +02:00
67468f15d5 Job-Planning: Attempt to build a prerequisite-Pipeline failed -- investigate why
To complete the mock setup, the next step would be to extend the GenNode-based spec langage
to allow defining prerequisite Mock-JobTickets. Setting this up seems rather straight forward --

however, defining a simple testcase to cover this extension runs into surprisingly tricky problems..
- for one, the singleValIterator from Itertools has serious difficulties handling references
- but even more surprising, it seems impossible to make the "prerequisites iterator"
  fit into the Tree-Explorer framework (which I intend to use as replacement
  for the monadic approach)

after some extended analysis of generic types and template instances,
it seems that not TreeExplorer as such is the primary problem, but rather
there is a conceptual mismatch somewhere deep down in Itertools or Iter-Adapter
2023-05-23 01:07:07 +02:00
27a8e91fa2 Job-Ticket: consider how to deal with channels and prerequisites
By reasoning and analysis I conclude that the differentiation into
multiple channels is likely misplaced in JobTicket; it belongs ratther
into the Segment and should provide a suitable JobTicket for each ModelPort

Handling of prerequisites also needs to be reshaped entirely after
switching to a pipeline builder for the Job-planning pipeline; as
preliminary access point, just add an iterator over the immediate
prerequisites, thereby shifting the exploration mechanism entirely
out of the JobTicket implementation
2023-05-11 22:47:56 +02:00
a940cd25bc Library: extract helper for unloading a sequence into a tuple 2023-05-10 14:49:51 +02:00
566f73de2a Segmentation: verify standard cases..
Testcase: A simple Sementation with a single and bounded Segment


As aside, figured out how to unpack an iterator such as to
tie a fixed number of references through a structural binding:

auto const& [s1,s2,s3] = seqTuple<3> (mockSegs.eachSeg());
2023-05-10 03:59:46 +02:00
e5cdb86ac3 Segmentation: integrate SplitSplice and build mock-segmentation
...now able to build a mock segmentation which issues dummy jobs,
and is wired such as to verify the right job is invoked for each segment.

And this allows to build and verify the Dispatcher,
without being able to invoke actual render jobs yet.
2023-05-05 03:46:42 +02:00
256045f91d Segmentation: add test case to cover instance management
- only the parts actually touched by the algo will be re-allocated
- when a segment is split, the clone copies carry on all data


Library: add function to check for a bare address (without type info)
2023-05-05 01:34:41 +02:00
52dad70753 Segmentation: Split-Splice algorithm implementation complete
...and verified including corner cases...
2023-05-04 15:59:17 +02:00
3f2f3db568 Segmentation: verify Split-Splice standard cases
Algorithm seems to work basically...
There was a copy-n-paste error in the treatment of the Successor,
leading to spurious duplication in some cases
2023-05-04 14:43:40 +02:00
1f83e5209b Library: relocate signature-detection macro
This macro has turned out to be quite useful in cases
where a generic setup / algorithm / builder need to be customised
with λ adaptors for binding to local or custom types. It relies
on the metafunctions defined in lib/meta/function.hpp to match
the signature of "anything function-like"; so this seems the
proper place to provide that macro alongside
2023-05-04 12:35:23 +02:00
f9a4d6134c Segmentation: setup for simple demo test case works
due to having extracted the Algo implementation as template,
we can now instantiate it for isolated tests with simple integer intervals
2023-05-04 02:07:38 +02:00
00ca84a2aa test-helper for comparison with expected (string) result
...this is something I should have done since YEARS, really...

Whenever working with symbolically represented data, tests
typically involve checking *hundreds* of expected results,
and thus it can be really hard to find out where the
failure actually happens; it is better for readability
to have the expected result string immediately in the
test code; now this expected result can be marked
with a user-defined literal, and then on mismatch
the expected and the real value will be printed.
2023-05-04 00:48:29 +02:00
640f029496 Segmentation: extract split-splice algorithm into library header 2023-05-03 05:01:45 +02:00
139b0d4c7b Segmentation: make implementation generic
The algorithm coded thus far turns out to be rather generic,
and thus it can be rewritten into a template, while all specific parts
are supplied as λ-Functors.

- instead of Time we use a generic ordering type
- the Iterator is likewise turned into a template parameter
- all the operations are directly supplied as functor types
- C++17 is able to pick up all those λ-Types from the ctor call

This change looks like "low hanging fruit"; the legibility of the code
is not seriously hampered, yet we get the benefit to test this rather
technical piece of logic by an isolated test (which for now is the
primary motivation), and we can hope to re-use it for similar tasks.
2023-05-03 04:43:10 +02:00
2378be5d86 Segmentation: code up the algorithm according to spec
...derive the implementation mostly by logical reasoning
...indicate positions by Iterators of a random-access list
2023-05-03 03:32:49 +02:00
bf978fcda1 Segmentation: devise algorithm for splitSplice operation 2023-05-02 21:37:15 +02:00
b582c35c9f Segmentation: structure analysis for splitSplice operation
There are 12 distinct cases regarding the orientation of two intervals;
The Segmentation::splitSplice() operation shall insert a new Segment
and adjust / truncate / expand / split / delete existing segments
such as to retain the *Invariant* (seamless segmentation covering
the complete time axis)
2023-05-02 04:29:34 +02:00
56405b2e2d Job-Planning: simulate backing by specific JobTicket
right now we're lacking a complete working implementation of render node invocation,
and thus the Dispatcher implementation can only be verified with the help
of mocked jobs. However, at least a preliminary implementation of tagging the
invocation instance is available, and thus we're able to verify that
a given job instance indeed belongs to and is "backed" by a specific JobTicket.

This is prerequisite for building up a (likewise mocked) Fixture datastructure,
and this in turn was meant to form the basis for attacking an actual Scheduler
implementation, followed by a real render node invocation.
2023-05-01 14:07:21 +02:00
f6fbc15e5f Job-Planning: provide stub implementation for NOP job (see #1296)
- can now create a Job from JobTicket::NIL
- on invocation this Job will to nothing

Only when the first real output backend is implemented,
we can decide if this simplistic implementation is enough,
or if an empty output must be explicitly generated...
2023-05-01 01:48:36 +02:00
fef0c05b64 Job-Planning: base implementation of job instance creation
* using a simplified preliminary implementation of hash chaining (see #1293)
 * simplistic implementation of hashing for time values (half-rotation)
 * for now just hashing the time into the upper part of the LUID

Maybe we can even live with that implementation for some time,
depending on how important uniform distribution of hash values is
for proper usage of the frame cache.

Needless to say, various further fine points need more consideration,
especially questions of portability (32bit anyone?). Moreover, since
frame times are typically quantised, the search space for the hashed
time values is drastically reduced; conceivably we should rather
research and implement a good hash function for 128bit and then combine
all information into a single hash key....
2023-04-30 22:33:42 +02:00
8aa0c258ba Job-Planning: investigate invocation of jobs
...using the MockJobTicket setup as point of reference,
since the actual invocation of render nodes will only be drafted
later in this "Vertical Slice" integration effort...
2023-04-30 02:18:56 +02:00
685b5beba6 Segmentation: simple implementation of time-based access
- introduce a JobTicket::NOP (null-object pattern)
- assuming that the function splitSplice() will retain complete coverage allways

Remark:
`Fixture::getPlaylistForRender()` is a leftover from the very early implementation drafts.
This function was more or less based on the way Cinelerra works; it is clear by now
that Lumiera can not possibly work this way, given that we'll build a low-level model
and dispatch precompiled render jobs....
2023-04-27 22:30:49 +02:00
d73b316ead Segmentation: consider preliminary data structure
...and consider how that can be extended later into the full
structure, which has to support a transactional switch
2023-04-27 19:38:37 +02:00
d58174db4d Segmentation: reorganise namespaces
The Fixture and the low-level model backbone deserve a distinct namespace on their own.
Since it's built by the Builder from the Session contents, and also used by the frame dispatch,
we can expect dependence on some types from Steam-Layer, and thus this namespace
needs to reside in Steam-Layer rather, while the actual low-level Model
might become part of Vault-Layer, creating a hierarchy of data structures.

(Remark: likely also the session related namespaces will need a reorganisation)
2023-04-25 18:27:16 +02:00
90593776f6 Segmentation: a plan to bootstrap into the required structure
The idea is to escape a "design deadlock" by using a test-driven prototype
implementation of the data structure to back a further development
of the Dispatcher and Scheduler implementation, which then can be used
to gradually elaborate and switch over to an actual implementation
data structure
2023-04-25 13:40:20 +02:00
b93a9a7985 Job-Planning: elaborate mock setup for render job 2023-04-21 05:29:10 +02:00
305eb825af Job-Planning: first testcase - empty JobTicket
...requires a first attempt towards defining a `JobTiket`.
This turns out quite tricky, due to using those `LinkedElements`
(intrusive single linked list), which requires all added records
actually to live elsewhere. Since we want to use a custom allocator
later (the `AllocationCluster`), this boils down to allocating those
records only when about to construct the `JobTicket` itself.

What makes matters even worse: at the moment we use a separate spec
per Media channel (maybe these specs can be collapsed later non).
And thus we need to pass a collection -- or better an iterator
with raw specs, which in turn must reveal yet another nested
sequence for the prerequisite `JobTickets`.

Anyhow, now we're able at least to create an empty `JobTicket`,
backed by a dummy `JobFunctor`....
2023-04-20 23:55:02 +02:00
856d8a3b51 Library: allow to reverse intrusive single linked list
Looks like we'll actually retain and use this low-level solution
in cases where we just can not afford heap allocations but need
to keep polymorphic objects close to one another in memory.

Since single linked lists are filled by prepending, it is rather
common to need the reversed order of elements for traversal,
which can be achieved in linear time.

And while we're here, we can modernise the templated emplacement functions
2023-04-20 18:53:17 +02:00
d341f003ca Job-Planning: attempt to stake claims
desperately trying to move forward and define a minimal first test case...
2023-04-18 20:02:36 +02:00
1dd1ec0e79 Job-Planning: decision how to rework bottom-up and test driven
- build the reworked Job-planning pipeline more or less from scratch
- back that with mocked `Dispatcher` and `JobTicket`
- then transfer this into a `RenderDrive`, which can be tested as well
- could continue then to a `CalcStream` integration test....
2023-04-17 17:10:53 +02:00
25c8579695 Job-Planning: new draft - organise the overall planning process
- introduce a new entity: RenderDrive
- it supersedes the CalcPlanCalculation, but is managed by CalcStream
- moreover, the RenderDrive will house a IterTreeExplorer-Pipeline
- define the concerns and relationships more clearly (see Drawing)
- prerequisite to disentangle the Job-planning "mechanics"
2023-04-17 04:51:38 +02:00
bcd2b3d632 PlaybackVerticalSlice: design analysis for Frame Dispatcher and Scheduler
- decision: the Monad-style iteration framework will be abandoned
- the job-planning will be recast in terms of the iter-tree-explorer
- job-planning and frame dispatch will be disentangled
- the Scheduler will deliberately offer a high-level interface
- on this high-level, Scheduler will support dependency management
- the low-level implementation of the Scheduler will be based on Activity verbs
2023-04-14 04:43:39 +02:00
bc330f0525 MERGE: Join completed GUI developments (closes: #1230)
All preceding integration work (#1014 and #1099) completed.
Ready to start on the [ticket:1221 »Playback Vertical Slice«]...
2023-03-22 23:56:08 +01:00
dfcb17b890 GUI: close out rework of top-level and timeline
This finishes a long lasting effort to rework the top-level of the Lumiera GTK UI,
to adapt to GTK-3 and the new asynchronous message based architecture.

Special credits and thanks to
 * Joel Holdsworth
 * Stefan Kangas

Without their relentless foundational work, the Lumiera UI could
never be where it is now. Even if some code was rewritten and several
parts of the old GTK-2 implementation are now obsolete, numerous ideas
solutions and inspirations were drawn from those early contributions
and live on as part of the reworked GUI.
2023-03-22 02:58:04 +01:00
5b64507560 Timeline: remove visual debugging and add timeline style
for sake of developement of the timeline body drawing code,
several tweaks were added to make the impact of the styling stand
out clearly. This changeset removes all those tweaks and restors
the code to intended neutral behaviour

Moreover, the cursom drawing of the timeline now requires some
basic aids to be present in the stylesheet, otherwise the track structure
will not be visible. Thus add some minimalistic styling to the
"light-theme-complement"-stylesheet, mostly based on the usual
predefined theme colours and some box-shadow settings.

This is by no means an adequate graphical solution,
yet it should be enough to get on with coding....
2023-03-19 14:32:11 +01:00
28331f9f8a Timeline: complete the rework of UI backbone and Timeline (closes: #1014)
check private notes and mindmap and fix some remaining minor inconsistencies,
notably the calculations in the overlay renderer in the `BodyCanvasWidget`.
2023-03-18 00:58:55 +01:00
8fec337f60 Timeline: investigate setup of initial canvas widthin pixels
Not sure if the initial window width is used properly for calibration
of ZoomWindow "pixel width" base setting.


Follow-up to the layout logic established with this commit:
09714cfe28
2023-03-15 02:05:34 +01:00
d564ce429a Timeline: remove diagnostic functions (closes #1201)
An extended round of rebuilding and reworking the global UI structures
can be concluded now. A flexible recursive structure of Tracks has
been implemented for the new Timeline-UI, allowing to contro all
relevant aspects of structure composition by **Diff Messages** sent
up from the Steam-Layer into the UI.

Moreover, the ability to control the custom drawing code through regular
**CSS style rules** has been demonstrated, allowing for seamless integration
of Lumiera UI elements with the existing desktop theme.
2023-03-10 17:23:17 +01:00
fc0fcad4d6 Timeline: implement structure connections for sub-Tracks (closes: #1018)
This completes the initial implementation round for the TrackHead.
- arrangement and layout for nested sub-Tracks is now settled
- a graphical representation of scope nesting was implemented

Postponed for later...
- still some minor discrepancies on synchronisation of vertical space
  between TrackHead and custom drawing in the body (off-by-one?)
- Expanding / Collapsing of Tracks
- Implement actual Controls to influence the Scope, e.g. Volume, Mix-Mode
- Dynamically indicate selection and Muting on the structure display
2023-03-06 01:51:35 +01:00
caffcef559 Timeline: Bugfix - can not assume scale factor one
While by default the Cairo Context is scaled to device units,
we must not assume that the given Context is unscaled; rather
it might have been deliberately scaled...

A notable example is the Gtk Inspector, which offers a "Magnifier" feature
2023-03-05 17:20:24 +01:00
fc74fbcd4f Timeline: complete integration of bracket drawing into the Layout
- pick up all relevant values from CSS
- also control the width of the StaveBracket
- observe the given overall height

Moreover, complete documentation drawing in Inkscape
and add a page to the TiddlyWiki, describing the principles
underlying this design and construction.
2023-03-05 04:00:49 +01:00
47108fa2d8 Timeline: expand and document system of marker style classes
.timeline__head : The complete header container on the left side
.timeline__navi : navigation control at top
.timeline__pbay : container holding the patchbay on the left side
.fork__head     : each individual TrackHeadWidget (possibly nested)
.fork__control  : container for the control components for each track scope
.fork__bracket  : the StaveBracket drawing to indicate the nesting structure
2023-03-03 18:36:33 +01:00
c234ab733b Timeline: Bugfix in drawing code
...the gap at the lower end of the line was caused
by an unintended conversion from double to int, prior to scaling
2023-03-02 17:59:54 +01:00
6108fdb738 Timeline: now able to implement placement and complete drawing
The tricky part is to derive the anchor point for the upper
and the lower cap of the bracket, taking into account possible padding.
There seems to be a bug hidden somewhere in this logic, since the
line turns out too short at the lower end....?
2023-03-02 02:06:56 +01:00
2565856f2e Timeline: investigation how to retrieve font size
According to the documentation, we should be able to get a Pango
font description from the CSS style context, and from there we should
be able to retrieve a font-size specification (and a DPI for the display)

Running this experimental code yields a font-size value of 9pt,
leading to a scale factor of about ~6, which seems plausible.
2023-03-01 01:43:57 +01:00
d66949a70a Timeline: setup for layout control of scope brackets
after weighting in the pro, and cons,
I decided to follow the standard path and pick up values
for each StaveBracket instance individually from Gtk::StyleContext,
assuming that the GTK framework will care for caching and performance
2023-02-27 02:04:56 +01:00
b7ea68e285 Timeline: draft Cairo drawing code to implement this shape
...this settles the most tricky part: how to get the curved end caps
defined and placed precisely; the solution approach is thereby confirmed.
2023-02-26 16:58:07 +01:00
171c3e30d7 Timeline: fix horizontal allocation on leaf-tracks
...as it turned out, it suffices just to state desired behaviour explicitly
- make the StaveBracket expand=false
- declare the HeadControl expand=true

The reason lies in the fact that on leaf-tracks there are just two
adjacent cells in a single row, lacking any exterior source of layout guidance.
2023-02-11 04:30:26 +01:00
4444e2b0ec Timeline: setup framework for custom drawing for the track structure
...just drawing a marker cross for now to indicate allocated size;
speaking of size -- GTK sometimes expands allocation horizontally,
while we'd prefer an absolutely fixed size for the purpose at hand.
2023-02-10 17:51:02 +01:00
70b8b86182 Timeline: determine remaining work to wrap-up
Intention is to shift focus of development work down towards Player and Scheduler soon.
However, since the timeline display saw substantial improvement it seems prudent
to finish work on some open ends, notably

- the track head structure
- the drawing and styling code

While content rendering for Clip widgets can safely be postponed, regarding the TrackHeadWidget,
where custom drawing is planned to display a structural outline of the nested scopes, some
ground work should be completed to make those plannings explicit.
2023-02-09 01:30:32 +01:00
37543024fd Timeline: use ElementBoxWidget to display the track header
This both demonstrates the layout of the `TrackHeadWidget`
and puts `ElementBoxWidget` into intended use to indicate
the scope of a track and to provide a placement icon and
an expander/collapser button.

see #1018
see #1219
2023-02-03 04:38:56 +01:00
25be54ecbe Timeline: remove diagnostic code (closes: #1211)
Layout calculation and balancing between body and track header
now works reasonably well, labels are placed properly and the
calculated layout remains stable when changing window size,
connected panes and scrollbars behave as expected now.

Quite a feat!
2023-01-25 01:42:40 +01:00
e0e0192938 Timeline: fix height calculation
...to properly account for
- the "prelude" padding above the root track
- overview rulers located into a fixed separate canvas at top
- slope-down and slope-up borders around nested tracks.

After testing, results seem now to be accurate up to ± 1px

Finally (sigh)
2023-01-23 23:44:55 +01:00
9bfae3cee1 Timeline: control alignment to sub-tracks through additional padding
...a huge improvement;
however, it becomes obiouvs now that we'll have to deal specifically
with the root track ruler canvas and "prelude" padding...
2023-01-22 00:50:34 +01:00
b38481fa89 Timeline: solve basic layout issue by properly calculating the height
As it turns out, we need to take the actual allocation of the cells
within the grid explicitly into account: combined cells will report
their extension for each of the underlying cells, thus leading to
excessively overestimated measurements.

So we now calculate the overall height based on the actual structure
- first row holds the label
- left column below used as expander
- right column holds individual content

Remaining problems:
- height of ruler canvas at top not taken into account (11px in this example)
- start of sub-track headers not synchronised with start of sub-tracks
  in the body area
2023-01-20 23:57:21 +01:00
4887194589 Timeline: investigate vertical space allocation on nested tracks
...seemingly the allocation of grid cells in the `TrackHeadWidget`
is not quite correct yet: even when there are nested sub-tracks,
we always need another row to hold the controls corresponding to
the track itself and the whole scope. And this row is also what
should be adjusted to match the vertical extension of the content
area.

As it turns out, the whole topic how to handle collapsed tracks
was not even considered yet; the calculation of the "track profile"
would need to be reworked to accommodate collapsed tracks, see: #1265
2023-01-19 23:58:42 +01:00
a04d2b01c6 Timeline: hunt down and fix a numeric-wrap problem
Sometimes, fractional seconds in the ZoomWindow metric can build up
to numerator and denominator values in the 64-bit integer domain.
Thus the division and truncation of the Window pixel with value
must be done in int64_t, while the result value is then
guaranteed to be a small integer < 100000

This caused the canvas to flicker and jump in size and the
resulting scrollbar change caused various cascading effects
on the further layout calculations...
2023-01-17 02:16:30 +01:00
2fb182e7ff Timeline: analyse and fix re-entrance problem in DisplayEvaluation
Note: the actual root cause, why this re-entrance happens,
is due to another obvious numerics bug not yet solved.
Here, the canvas width was suddenly set to zero, causing
the scrollbar position to change and thus the ZoomWindow
to re-fire the structure change signal.

However, such invalidation of previously established baseline
values can never be totally excluded in advanced layout calculations,
and thus the evaluation mechanism must be prepared and re-triggered
to start over, until a stable layout is achieved.
2023-01-16 00:07:05 +01:00
0a99e5dfc8 Timeline: reorganise additional padding in TrackHeadWidget
- rearrange cell content and disable auto-expand to prevent
  the content area from becoming oversized initially

- fix autocompletion error in signal binding,
  causing segfault when moving the scrollbar
2023-01-15 02:51:00 +01:00
61f0e2f6a7 Timeline: further (unsuccessful) efforts towards layout sync
attempting to get the vertical space allocation in header and content area
synchronised; previously we conflated the content size and additional
padding, but even after distinguishing both, we still get a cyclic
dependency, leading to progressive increasing of allocated size...
2023-01-10 04:02:26 +01:00
832dc72652 fix indentation 2023-01-10 02:48:45 +01:00
09714cfe28 Timeline: draft solution to interconnect ZoomWindow and scrollbar
After quite some tinkering, instead of extending the DisplayManager interface,
I now prefer to treat this connection rather as an intricate implementation detail:

The TimelineLayout implementatino now provides two translation functions,
which are directly wired as slots from the Signals emitted by moving the
hand of the scrollbar; the idea is that these functions mutate the ZoomWindow,
which then triggers a DisplayEvaltuation, which in turn causes the
drawing code to pick up and translate back the new metric and position.

Results look promising, insofar the DisplayEvaluation is now triggered
repeatedly, and the actual window width in pixel is propagated;
however, the response of the layout code is seemingly random at times,
the allocated height grows monontonously and the code Segfaults when
moving the scrollbar...
2023-01-06 03:09:28 +01:00
941d3088d5 Timeline: rearrange ruler canvas into a slave scrolled pane
this makes the arrangement more symmetric and natural
and also makes the overview ruler scroll alongside the content pane,
thereby creating the (intended) impression of one uniform layout space
2023-01-05 02:45:11 +01:00
f3098daeb4 Timeline: investigate problem with horizontal scrollbar
As it turns out, this happens as side-effect from the workaround 2019-08-22

fc5eaf857c

Obviously, just set_size() on the canvas is not sufficient for
GTK actually to establish a size-request (seemingly the canvas counts
as /empty/ and only real widgets would make a difference).
However, since the ruler canvas is directly placed into the box,
and not adapted by a ScrolledWindow, explicitly set_size_request()
also causes the enclosing Box to "inherit" this minimal required size,
thereby also spreading out the BodyCanvasWidget beyond the size
actually available. GTK handles this situation by hard-clipping
on the right side, which causes the vertical scrollbar to disappear
and keeps the horizontal scrollbar disabled (since nominally it still
spans the whole size available, even while this size is then clipped
subsequently).

This changeset adds a lot of debug printing and demonstrates this
behaviour by setting only a minimal horizontal size_request, so that
the window is no longer expanded and clipped.
2023-01-04 23:55:21 +01:00
c22bbe5f93 Timeline: Refactor DisplayEvaluation to integrate zoom calibration
This does not really change the logic of the DisplayEvaluation mechanism,
but makes it much more flexible: instead of having two hard wired components,
the DisplayEvaluation visitor now holds a collection of LayoutElement pointers.
This way, the Layout manager itself (on behalf of the ZoomWindow) can
participate in the process, and on activation will now establish the
window width in pixel.

This works now insofar the drawing on the canvas is adapted coherently;
however something with the setup of the Scrollbar is still not quite right;
some time ago I recall the scrollbar worked, but now it is blocked
and the canvas just clips to the right side.
2023-01-04 03:36:12 +01:00
061b70c96f Timeline: integrate ZoomWindow change listener
- connect to TimelineLayout::signalStructureChange
 - this causes the trackProfile to be reset
 - next draw() call will then triger display-evaluation
2023-01-03 02:23:22 +01:00
62bad8720a Timeline: decide upon handling of the canvas origin
It is now tied to the start of ZoomWindow::overallSpan(),
thereby defining the (technical) pixel coordinates within the window
and for drawing on the canvas to be always positive. Whenever ZoomWindow
re-calibrates, it's change signal will trigger, causing the
TimelineLayout to perform a new DisplayEvaluationPass,
which in turn prompts all embedded widgets to readjust
their positions accordingly.
2023-01-03 00:20:09 +01:00
52d3231226 Timeline: finish ZoomWindow implementation and boundrary tests 2022-12-18 03:47:40 +01:00
e436023ef9 Timeline: properly handling maximal zoom-in and alignment to µ-ticks 2022-12-17 17:47:10 +01:00
b1514f6632 Timeline: properly handling extreme scroll-steps 2022-12-17 01:15:34 +01:00
3893968502 Timeline: improve handling of window size changes at extreme positions
...again and again surprising how much inconsitencies can hide in just some lines of code...
2022-12-16 19:59:47 +01:00
77bb156615 Timeline: verify handling of extreme time offsets 2022-12-16 02:23:20 +01:00
5e595c57ca Timeline: automatically orient and shift into allowed time domain
Note: changing behaviour of TimeSpan to possibly flip start and end,
and also to use Offset as Offset and then re-orient,
since this seems the least surprising behaviour.

These changes carry over into changed default and limiting
on ZoomWindow constructor and various mutators, and most
notably shifting the time span always into allowed domain.
2022-12-14 03:00:07 +01:00
777024ee40 Timeline: resolve yet another insidious corner case at maximum zoom
...the implementation was way too naive; in some cases we could go
into an infinite loop. In the end, using Newton approximation was not
necessary (and thus there is no loop anymore), but it helped me get
at a much better solution with very small error margin on average case.

All these corner cases are obviously "academic" to some degree,
but it turns out there is no clear-cut point where you'd be able
just so set a limit and be sure that fractional integer arithmetic
works flawless in all cases.

Thus the choice is
 - give up (fractional) integers and work with floats and have to
   deal with error accumulation
 - or do something as chosen here, namely add a boundary zone, where
   fractional integer arithmetic can be kept under control, while admitting
   small errors, and in turn get the absolutely precise integers in all
   everyday standard cases
2022-12-13 01:21:18 +01:00
c31522c236 Timeline: define better internal zoom-out limit
The value used previously was too conservative, and prevented ZommWindow
from zooming out to the complete Time domain. This was due to missing the
Time::SCALE denominator, which increaded the limit by factor 1e6

In fact the code is able to handle even this extremely reduced limit,
but doing so seems over the top, since now detox() kicks in on several
calculations, leading to rather coarse grained errors.

Thus I decided to use a compromise: lower the limit only by factor 1000;
with typical screen pixel widths, we can reach the full time domain,
while most scaling and zoom calculations can be performed precisely,
without detox() kicking in. Obviously this change requires adjusting
a lot of the test case expectations, since we can now zoom out maximally.
2022-12-10 04:26:22 +01:00
40f003a962 Timeline: stress-test with excessive zoom-out reveals further weakness
As it turns out, the calculation path initially choosen for the mutateScale(Rat)
was needlessly indirect, and also duplicated several of the safeguards,
meanwhile implemented way better in conformWindowToMetric(Rat)

Thus, instead of relatively re-scaling the window, now we just
limit the given zoomFactor and pass it to conformWindowToMetric()
2022-12-09 23:13:27 +01:00
ce3713d872 Timeline: now able to increase to maximum pixel count
There is a built-in limitation, which now is even
lowered to 100000 pixels horizontally.

With the techniques introduced in this changeset, it seems possible
to support more -- yet this would be a case of unnecessary genricity;
handling such large numbers will drive more computations into the
danger zone, and doing so incurs cost in terms of testing and debugging.

Placing that into context, contemporary displays are not even 4K on
average, and it does not look likely even for cinema display to go
way beyond 8k -- so yes, I want display hardware with 100000 pixels!!


The key takeaway of this changeset:
 - can calculate px = trunc(zoomFactor * duration) step wise,
   even when the direct calculation would lead to wrap-around
 - can safely adjust and fix the zoomFactor using Newton approximation
2022-12-09 19:37:35 +01:00
068549dace Timeline: now able to handle maximal zoom-out
...even zooming out to span the complete time domain (~19000 years).
But only under the condition that the display window is sufficiently
large in terms of pixels, so we can handle the computation without
glitches.

This should not be a relevant limitation in practice, since a window
size of some 100 pixels is enough to handle Duration::MAX. Needless to add
that it's hard to imagine a media timeline of such tremendous size...
building on these Library changes, plus the safe-add function
developed some days ago, it is now possible to mark a large displacement
as `time::Offset`, and apply this to yield any valid time position,
even extreme negative values
2022-12-08 18:06:37 +01:00
006758f349 Library/Timeline: now able to scroll to extreme positions (closes #1263)
...building on these Library changes, plus the safe-add function
developed some days ago, it is now possible to mark a large displacement
as `time::Offset`, and apply this to yield any valid time position,
even extreme negative values
2022-12-05 03:34:04 +01:00
13adc56f34 Library: rectify confusingly named function on the Grid API
The APIs for time quantisation were drafted in an early stage of the project
and then never followed-up. Especially Grid::gridAlign has no
real-world usage yet, and is only massaged in some tests.

When looking at QuantiserBasics_test, I was puzzled and led astray,
since this function suggests to materialise a continuous time into
a quantised time -- which it doesn't (there is another dedicated
function Quantiser::materialise() to that end); so, without engaging
into the discussion if this function is of any use, I'll hereby
choose a name better reflecting what it does.
2022-12-05 01:05:23 +01:00
50c602ec3f Library: rectify clipping of time::Duration (see #1263)
This is a deep refactoring to allow to represent the distance
between all valid time points as a time::Offset or time::Duration.

By design this is possible, since Time::MAX was defined as 1/30 of
the maximum value technically representable as int64_t. However,
introducing a different limiter for offsets and durations turns
out difficult, due to the inconsistencies in the exiting hierarchy
of temporal entities. Which in turn seems to stem from the unfortunate
decision to make time entities immutable, see #1261

Since the limiter is hard wired into the `time::TimeValue` constructor,
we are forced to create a "backdoor" of sorts, to pass up values
with different limiting from child classes. This would not be so
much of a problem if calculations weren't forced to go through `TimeVar`,
which does not distinguish between time points and time durations.

This solution rearranges all checks to be performed now by time::Offset,
while time::Duration will only take the absolute value at construction,
based on the fact that there is no valid construction path to yield
a duration which does not go through an offset first.

Later, when we're ready to sort out the implementation base of time values
(see #1258), this design issue should be revisited
- either we'll allow derived classes explicitly to invoke the limiter functions
- or we may be able to have an automatic conversion path from clearly
  marked base implementation types, in which case we wouldn't use the
  buildRaw_() and _raw() "backdoor" functions any more...
2022-12-05 00:58:32 +01:00
4d79bdce5f Timeline: sophisticated helper function to resolve problems with numeric precision
While the calculation was already basically under control, I just was not content
with the achieved numeric precision -- and the fact that the test case in fact
misses the bar, making it difficult do demonstrate that the calculation
is not derailed. I just had the gut feeling that it must be somehow possible
to achieve an absolute error level, not just a relative error level of 1e-6

Thus I reworked this part into a generic helper function, see #1262

The end result is:
 * partial failure. we can only ''guarantee'' the relative error margin of 1e-6
 * but in most cases not out to the most extreme numbers, the sophisticated
   solution achieves much better results way below the absolute error level of 1µ-Tick

Thus with using rational numbers, we have now a solution that is absolutely precise
in the regular case, and gradually introduces errors at the domain bound
but with an guaranteed relative error margin of 1e-6 (== Time::SCALE)
2022-12-02 22:23:14 +01:00
2ddbed693b Timeline: fix inconsistency in ZoomWindow normalisation numerics
...now able to achieve the expected error bound of 1e-6
...this seems to be the worst-case for ZoomWindow::setVisiblePos(factor)
   for extremely large timeline; seemingly not possible to achieve the
   goal set for this special test case
2022-12-02 03:48:36 +01:00
289f92da7e Timeline: safely calculate sum/difference of large fractional times
...in a similar vein as done for the product calculation.
In this case, we need to check the dimensions carefully and pick
the best calculation path, but as long as the overall result can
be represented, it should be possible to carry out the calculation
with fractional values, albeit introducing a small error.

As a follow-up, I have now also refactored the re-quantisation
functions, to be usable for general requantisation to another grid,
and I used these to replace the *naive* implementation of the
conversion FSecs -> µ-Grid, which caused a lot of integer-wrap-around

However, while the test now works basically without glitch or wrap,
the window position is still numerically of by 1e-6, which becomes
quite noticeably here due to the large overall span used for the test.
2022-12-01 23:23:50 +01:00
7007101357 Timeline: safely calculate the fraction of a very large timespan
...using a requantisation trick to cancel out some factors in the
product of two rational numbers, allowing to calculate the product
without actual multiplication of (dangerously large) numbers.

with these additional safeguards, the anchorWindowAtPosition()
succeeds without Integer-wrap, but the result is not fully correct
(some further calculation error hidden somewhere??)
2022-11-29 02:00:41 +01:00
b898f1514b Timeline: safeguard agains injecting a poisonous metric factor 2022-11-26 19:45:10 +01:00
90aba4df09 Timeline: demonstrate safeguards against reversed and toxic input 2022-11-18 02:55:28 +01:00
cfe3a6618f Lib: cover re-quantisation helper
...which I intend to use for sanitising poisonous rational numbers,
as prerequisite for handling divisor based time scales in the ZoomWindow
2022-11-15 02:13:57 +01:00
ce1220ee72 Lib: test coverage for rational-int corner cases and integer-log
- detailed documentation of known problematic behaviour
  when working with rational fractions
- demonstrate the heuristic predicate to detect dangerous numbers

- add extensive coverage and microbenchmarks for the integer-logarithm
  implementation, based on an example on Stackoverflow. Surprising result:
  The std::ilog(double) function is of comparable speed, at least for
  GCC-8 on Debian-Buster.
2022-11-14 05:20:37 +01:00
8ab0e1acb5 Lib: consider method to sanitise a poisonous rational
Especially rational numbers with large denominator can be insidious,
since they might cause numeric overflow on seemingly harmless operations,
like adding a small number.

A solution might be to *requantise* the number into a different,
way smaller denominator. Obviously this is a lossy operation;
yet a small and controlled numeric error is always better than
an uncontrolled numeric wrap-around.
2022-11-13 16:52:12 +01:00
d3fc6fd4de Timeline: Analysis of possibly toxic input values
- protection against negative numbers seems adequate
- a possible concern are handling of very large time spans
- definitively have to guard against "poisonous" fractions
  (e.g. n / INT_MAX)
2022-11-12 17:35:47 +01:00
cc16953fd8 Timeline: implement and verify ZoomWindow change notification 2022-11-11 16:30:27 +01:00
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
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
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
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
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
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
01740619f1 Code Review with Benny 2022-09-08 14:24:36 +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
0622ddece8 private.mm: infos noted while debugging Yoshimi 2021-11-05 21:19:10 +01:00
e15e893a01 Util: use case-insensitive matching for parsing bool values 2021-08-20 14:33:59 +02:00
ae10442cf2 some whitespace clean-up 2021-08-20 14:33:21 +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
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
b1f739115b move some common helpers into central UI headers 2021-04-04 15:46:40 +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
6578b3cf1c Clip-Drag: wire access to the actual InteractionState for dragging 2021-04-02 16:57:18 +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
d4b1735013 define the ClipPresenter header-only (no change)
A separate translation unit turns out to be unnecessary here,
since this is implementation level code included into one single
other translation unit (timeline-controller.cpp). In such a situation,
having the whole class definition at one code location improves
readability.

Moreover, there clearly is now another abstraction barrier,
insofar all of the clip widget's implementation technicalities
are buried within clip-widget.cpp
2021-03-27 13:47:43 +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
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
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
c52576ffc7 Diff-Framework: fill in the access variations
no metaprogramming since almost a year ... kindof missed that queer feeling
2021-01-22 15:06:43 +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
710e35c87a Fix some further mentions and links to Cinelerra-CV
as indicated by Igor Vladimirsky
2020-12-11 23:48:30 +01:00
28adf9a642 Clip: pondering about the representation of clip timings 2020-04-09 00:15:05 +02:00
ea3ea811bf Clip: sort out access to the canvas abstraction 2020-04-08 22:55:33 +02:00
765d124fff Clip: draft the decision logic for the clip presentation mode 2020-04-03 19:44:46 +02:00
cfa8e87931 Relative-Hook: now able to push down time->pixel translation (see #1213)
the actual translation is still TODO;
we should delegate the calculation to the DisplayManager,
which is in focus within the TrackBody, where the coordinate
translation hook is now located.
2020-03-23 04:29:06 +01: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
0f6f09180e Lib: simplified optional access to nested record attributes
Yeah, C++17, finally!

...not totally sure if we want to go that route.
However, the noise reduction in terms of code size at call site looks compelling
2020-03-14 23:52:04 +01:00
a9ed0c01db Lib: minor indentation fix
by convention, braces for member functions are only indented within a class body,
not for a stand-alone function definition (even if just inline)
2020-03-14 23:04:52 +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
f763e90d2d DisplayEvaluation: prefer simpler solution without templates
...while the first solution looked as a nice API, abstracting away
the actual collections (and in fact helped me to sport and fix a problem
with type substitution), in the end I prefer a simpler solution.
Since we're now passing in a lambda for transform anyway, it is
completely pointless to create an abstracted iterator type, just
for the sole purpose of dereferencing an unique_ptr.

As it stands now, this is all tightly interwoven implementation code,
and the DisplayFrame is no longer intended to become an important
interface on it's own (this role has been taken by the ViewHook /
ViewHooked types).

Note: as an asside, this solution also highlights, that our
TreeExplorer framework has gradually turned into a generic
pipeline building framework, rendering the "monadic use" just
one usage scenario amongst others. And since C++20 will bring
us a language based framework for building iteration pipelines,
very similar to what we have here, we can expect to retrofit
this framework eventually. For this reason, I now start using
the simple name `lib::explore(IT)` as a synonym.
2020-03-08 02:31:49 +01:00
c7d157e295 Library: integrate generic min/max function
...built while investigating type deduction problems on PtrDerefIter
...also allow PtrDerefIter to work with std::unique_ptr
2020-03-08 02:05:39 +01:00
4070cc0d83 DisplayEvaluation: draft evaluation invocation per track
...however, running into some type deduction problems...
2020-03-08 01:11:21 +01:00
8d87029fd5 Timeline: make TrackPresenter header-only
...there is no need for yet another indirection here,
since TrackPresenter is not much of an interface and
only included at into two other translation units.
Moreover, header-only code simplifies the use of
templated lambdas, which come in handy when dealing
with the various nested sub-collections.
2020-03-07 18:21:24 +01:00
5ddf426add DisplayEvaluation: skeleton of the evaluation invocation 2020-03-07 00:30:06 +01:00
e9f05e4ac2 DisplayEvaluation: dependency wiring 2020-03-06 23:35:07 +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
33f299e45f Relative-Hook: observe CSS padding and margin
and voilà: now the placeholder buttons appear nicely within
the content area of each track
2020-02-29 00:24:22 +01:00
2bbbcf36bc Relative-Hook: decide on coordinate system usage
...and resolve associated problems with overal canvas size
2020-02-28 23:13:53 +01:00
99d0f0a0ae Relative-Hook: investigate and resolve wrong offset on child tracks
The reason was: each further ViewRefHook added again the full offset.
Need to change the hierarchy and allow for this chained hooking already
starting from the base interface ViewHook onward (with trivial default impl)
2020-02-28 22:11:00 +01:00
c252449388 problem with automatic scrollbar disappearing after focus loss (see #1208) 2020-02-28 01:49:35 +01:00
396bf9d1ec Relative-Hook: investigate wrong offset of attached widgets
...not fully conclusive yet.
However, the split into two canvas controls plays an important role here;
at some point we need to translate into the coordinates shifted by the height
of the first, pinned canvas (track profile "prefix").

This is an attempt to hide that away as a technical detail,
buried within the calculation of the track body height allocation.
2020-02-28 01:32:34 +01:00
1ee2f18d65 Relative-Hook: remove obsolete direct manipulation (test) code
the marked pars are diagnostics code anyway,
however, the first attempt used direct manipulation of the child offsets from "outside".
Now, after switching to the ViewHook-mechanism, such direct manipulation
of view innards is no longer neccessary, as can be verified by removing that test code now.
2020-02-27 21:42:53 +01:00
0837498cc0 Relative-Hook: proof-of-concept based on ViewHook (see #1207)
this draft commit reshifts the (meanwhile broken) test code from:
03c358fe86

Now the marker Buttons are injected again, but without any detailed
positioning code at call site. This demonstrates the viability of the
Structure-Change / ViewHook refactoring.

To make this change viable, it was necessary to remove the ViewHooked<>
marker template from the rehook() callback. As it turns out, this was
added rather for logical reasons, and is in fact not necessary in
any of the existing ViewHook implementations (and I don't expect any
other implementations to come)

BUT the actual positioning coordinates are still wrong (which seems
to re related to other conceptual problems in coordinate offset handling)
2020-02-27 21:03:46 +01:00
cf8c3c27d6 DummySessionConnection: fix structural defect in population diff
...which erroneously assumed the list of timelines to be empty.
When sending a further population diff, this assumption is broken,
since the first diff resulted in adding a timeline element.

This misatke was detected by the new consistency check added with
9f3fe8a88
2020-02-22 19:05:50 +01:00
d0cf027686 UI-Base: expunge the implicit conversion from UI-Element to BusTerm::ID
this conversion seemed to be somewhat cool,
but turned into a nuisance over time.

In the end its better to be explicit about such stuff.
2020-02-22 18:12:23 +01:00
14b6a1e6aa UI-Base: diagnostic self-ID for any "tangible" UI-Element
low hanging fruit, and quite helpful e.g. when a Diff flounders,
since it will automatically show up in the exception message.
2020-02-22 18:09:24 +01:00
b2b5cf0f6d MERGE: upgrade to Debian/Buster and to C++17 2020-02-22 02:16:25 +01:00
421a2ed49a C++17: some related clean-up 2020-02-21 23:55:09 +01:00
00c9ecb659 C++17: fix detector for function signatures
failure was likewise caused by `noexcept` being part of the signature type now
2020-02-21 20:16:59 +01:00
8c12e88fd3 C++17: fix detector for STL container iterability
the reason for the failure, as it turned out,
is that 'noexcept' is part of the function signature since C++17

And, since typically a STL container has const and non-const variants
of the begin() and end() function, the match to a member function pointer
became ambuguous, when probing with a signature without 'noexcept'

However, we deliberately want to support "any STL container like" types,
and this IMHO should include types with a possibly throwing iterator.
The rationale is, sometimes we want to expose some element *generator*
behind a container-like interface.

At this point I did an investigation if we can emulate something
in the way of a Concept -- i.e. rather than checking for the presence
of some functions on the interface, better try to cover the necessary
behaviour, like in a type class.

Unfortunately, while doable, this turns out to become quite technical;
and this highlights why the C++20 concepts are such an important addition
to the language.

So for the time being, we'll amend the existing solution
and look ahead to C++20
2020-02-21 18:57:49 +01:00
577592c66e C++17: isolate problematic code segments (see Ticket #1138)
as it turns out, "almost" the whole codebase compiles in C++17 mode.

with the exception of two metaprogramming-related problems:

 - our "duck detector" for STL containers does not trigger anymore
 - the Metafunction to dissect Function sigantures (meta::_Fun) flounders
2020-02-18 04:16:03 +01:00
38837da65e Timehandling: choose safer representation for fractional seconds (closes #939)
When drafting the time handling framework some years ago,
I foresaw the possible danger of mixing up numbers relating
to fractional seconds, with other plain numbers intended as
frame counts or as micro ticks. Thus I deliberately picked
an incompatible integer type for FSecs = boost::rational<long>

However, using long is problematic in itself, since its actual
bit length is not fixed, and especially on 32bit platforms long
is quite surprisingly defined to be the same as int.

However, meanwhile, using the new C++ features, I have blocked
pretty much any possible implicit conversion path, requiring
explicit conversions in the relevant ctor invocations. So,
after weighting in the alternatives, FSecs is now defined
as boost::rational<int64_t>.
2020-02-17 03:13:36 +01:00
8867ae55ad Clean-up: problematic function signature
GCC8 now spots and warns about such mismatches.

And we should take such warnings seriously;
code produced by the newer GCC versions tends to segfault,
especially under -O2 and above, when a return statement is
actually missing, even if the return value is actually not
used at call site.

Here, a functor to unlock the active "guard" is passed into
a macro construct, which basically allows to abstract the
various kinds of "guards", be it mutex, condition variable
or the like.

Seemingly, the intention was to deal with a failure when
unlocking -- however all the real implementations prefer
to kill the whole application without much ado.
2020-02-16 02:05:42 +01:00
e639558e2c Debian-Buster: compile Fix for GCC-8
Yeah... we are there, finally!
2020-02-16 02:05:42 +01:00
f7967a674f Structure-Change: complete refactoring of the DisplayFrame 2019-12-22 01:43:56 +01:00
e4049534fa Structure-Change: now able to turn the widgets within DisplayFrame into ViewHooked
...and implemented the base case (=Recursion) of the corresponding ViewHook(s)
2019-12-21 23:57:53 +01:00
c5d0ddb01b Structure-Change: push a set of suitable ViewHook-Interfaces into the DisplayFrame
...actual Operations not yet implemented (but trivial to implement in the end)
2019-12-20 22:15:35 +01:00
33a19c404b Structure-Change: introduce a common accessor interface
...to solve the problem with interwoven nested ctor invocation.
This interface also promises to help with nested invcations,
without being overly generic.
2019-12-20 20:06:26 +01:00
c5bffa21f4 Structure-Change: introduce new ViewHook interface into TimelineLayout
...with the goal to supersede the tricky DisplayFrame ctor closure used for this purpose
2019-12-20 00:21:31 +01:00
cef7917d8e Diff-Listener: finished and unit test pass (closes: #1206) 2019-12-15 21:40:09 +01:00
9f3fe8a885 Diff-Framework: add clean-up hook to diff-application
Our diff language requires a diff to handle the complete contents of the target.
Through this clean-up hook this is now in fact enforced.

The actual reason for adding this however was that I need to ensure
listeners are triggered
2019-12-15 15:06:04 +01:00
3e1d0036ed Diff-Listener: resolve template instantiation errors
As it turned out, the reason was a missing move-ctor.
The base of the whole DSL-Stack, TreeMutator, is defined MoveOnly,
and this is also the intended use (build an anonymous instance
through the DSL and move it into the work buffer prior to diff application)

However, C++ does *cease to define* a move ctor implicitly,
whenever /one of the "big five" is defined explicitly/.

So Detector4StructuralChanges was the culprit, it defined a dtor,
but failed to define the move ctor explicitly.


So.... well, this did cost me several hours to track down,
yet I still rather do not want to write all those ctors explicitly all the time,
and so I am still in favour of implicitly generated ctors, even if they hurt sometimes.
2019-12-15 13:54:29 +01:00
854f4eca58 Diff-Listener: investigate weird template errors
with the new decorator layer, we suddenly trigger a chain of template instantiation errors.
At first sight, they are almost undecipherable, yet after some experimentation, it becomes clear
that they relate down to the base class (TreeMutator), which is defined MoveOnly

This seems to indicate that, at some point in the call chain, we are
digressing from the move-construction scheme and switch over to copy construction,
which in the end failst (and shall fail).

Inconclusive, to be investigated further
2019-12-15 04:12:20 +01:00
d8e0ad179b TreeMutator: better invoke the Builder-ctor explicitly
...by relying on an implicit conversion,
the code does not become simpler, just shorter, and even more confusing :-/
2019-12-15 04:06:57 +01:00
d8b20ae497 Diff-Listener: fill in implementation
...basically just need to intercept three TreeMutator-operations
2019-12-15 04:04:25 +01:00
a33e236630 Diff-Listener: define API 2019-12-14 23:35:16 +01:00
806d569e06 Diff-Framework: resolve lurking problems with specific STL containers
basically the solution was a bit too naive and assumed everything is similar to a vector.
It is not, and this leads to some insidious problems with std::map, which hereby
are resolved by introducing ContainerTraits
2019-12-14 01:29:21 +01:00
3321e5bc6b Diff-Listener: need a really basic test
All of the existing "simple" tests for the »Diff Framework« are way to much low-level;
they might indeed be elementary, but not introductory and simple to grasp.
We need a very simplistic example to show off the idea of mutation by diff,
and this simple example can then be used to build further usage test cases.

My actual goal for #1206 to have such a very basic usage demonstration and then
to attach a listener to this setup, and verify it is actually triggered.

PS: the name "GenNodeBasic_test" is somewhat pathetic, this test covers a lot
of ground and is anything but "basic". GenNode in fact became a widely used
fundamental data structure within Lumiera, and -- admittedly -- the existing
implementation might be somewhat simplistic, while the whole concept as such
is demanding, and we should accept that as the state of affairs
2019-12-12 23:41:26 +01:00
f6a4ee3f89 Library: no need to log lifecycle of the advice system on each invocation
Basically the advice system is just some further helper component with
a lookup table, which "just works" transparently most of the time.

We'd need those diagnostic messages only when explicitly debugging
for some kind of access-after death, which should not happen as long
as we stick to the general policy not to allow any significant functionality
to be hooked up from dtors
2019-12-12 23:17:43 +01:00
c86f914915 Structure-Change: re-order entity naming
ViewHookable -> ViewHook
ViewHook -> ViewHooked
2019-12-12 17:02:24 +01:00
c501a38590 Structure-Change: fix test after refactoring / add lifecycle warning
now the lifecycle of widget and hook are tightly interwoven.
Indeed the test uncovered a situation where a call into the
already destroyed Canvas might halt the application.
2019-12-09 01:24:51 +01:00
0a20d18242 Structure-Change: implement the changed API and memory layout
NOTE: 2 test failures
2019-12-08 23:57:43 +01:00
ffcac2ea1e Structure-Change: implement a simplistic implementation of re-ordering
...verified by the rather conceptual unit test
2019-12-06 23:19:09 +01:00
305ff8e6cc Structure-Change: draft API for re-ordering attached widgets
basically this attempts to work around an "impedance mismatch" caused by relying on Lumiera's Diff framework.
Applying a diff might alter the structural order of components, without those componets
being aware of the change. If especially those components are attached into some
UI layout, or otherwise delegate to display widgets, we need a dedicated mechanism
to reestablish those display elements in proper order after applying the change.

The typical examples is a sequence of sub-Tracks, which might have been reordert due
to applying rules down in the Steam Layer. The resulting diff will propagate the
new order of sub-Tracks up into the UI, yet now all of the elaborate layout and
space allocation done in the presentation code needs to be adjusted or even
recomputed to accomodate the change.
2019-12-06 21:53:43 +01:00
c573630ac1 Structure-Change: draft a design based on ViewHook / ViewHookable
By applying a Diff, the children of some timeline element (track) may be re-ordered.
This imposes specific problems, since these elements hold onto slave-Widgets,
which are already attached into some elaborated and nested widget structure.
To keep complexity under control, we can not allow the TrackPresenter to have
any knowledge regarding the implementation structure of these target widgets.

Thus I am pondering the idea to represent that relation as an abstracted ViewHook link
2019-12-02 00:34:20 +01:00
bdf3351f55 ClipDisplay: basic implementation of ViewHook helper 2019-11-08 20:49:37 +01:00
bf283e8843 QA: check for possible misalignment through placement new (-> #1204) 2019-11-08 01:14:36 +01:00
f9d8f6eb55 ClipDisplay: draft desired properties of the ViewHook helper
...which serves to solve the problem with Canvas access.
Basically we do not want each and every Clip widget to be aware of the concrete canvas implementation widget;
and in addition, automated removal of widgets from the Canvas seems desirable
2019-09-30 02:49:02 +02:00
7c7b910545 ClipDisplay: plot a structure for connecting ClipWidgets with the display canvas 2019-09-29 01:32:34 +02:00
03c358fe86 Timeline: squeeze in some test/diagnostics code to inject a button onto each track
This is dummy/test/diagnostics code and should be removed when the track display code is complete!
It can be activated by sending a "mark"-Message via the UI-Bus, towards the
Timeline element to be tested (Tip: use the same ID as used when injecting
the Timeline via the TestControl Dialog box). When receiving this message
(asynchronously), the TimelineControler asks each nested TrackPresnter
to inject a Button with the corresponding track name onto the BodyCanvasWidget.

This allows us to verify the coordinate calculation and size allocation --
and indeed, the numbers are not yet correct (TODO)
2019-09-07 19:24:54 +02:00
cae013c4f4 Timeline: store current track start coordinates while calculating allocation
admittedly this is a bit sketchy, but I don't have a better framework to hinge upon right now.
Thus we store the vertical start coordinates and the offset of the content area
as a side effect, while calculating the TrackProfile
2019-09-07 17:31:58 +02:00
4785ff8caa Timeline: integrate support for a margin on the timeline content
...which has the nice additional effect of exposing box-shadow on the outside of the content area too.
Thus the content area now behaves equivalent to the rulers, and adjacent
content space of simple tracks without rulers and nesting can be slightly
offset from each other through a margin in CSS
2019-09-07 17:31:53 +02:00
fa4a9014a1 Timeline: nail the problem with calculating overall vertical space
In the end, I used the profile building pass to also calculate and sum up the vertical offsets.
Seems to be the only sane approach to get really precise values, since adjacent
upwards slopes can be combined at various places (and I do not want to use the
actual drawing code for this calculation)
2019-08-29 23:02:44 +02:00
4d2766963b Timeline: size allocation is not yet correct...
need to investigate and probably need to store per track offset values
already while building the track profile. The primary reason for the
observed discrepancy seems to be the rather flexible combination of
slope borders.
2019-08-29 16:19:47 +02:00
360209a381 Timeline: verify visible track structure (and fix a bug with header placement) 2019-08-29 16:19:40 +02:00
737505979b Timeline: also observe additional space for decorations added via CSS 2019-08-23 03:56:38 +02:00
346b5ae769 Timeline: now settle the drawing code with the insights gained thus far
Especially note the tricks we need to play in order to allow for (limited) usage of CSS3 box-shadows.
The reason is, all these CSS3 effects are rendered in one shot and combinend on the StyleContext::render_background() call
Thus we need to ensure that the background is properly aligned with the frames
2019-08-23 03:04:22 +02:00
fc5eaf857c Timeline: find a workaround to cause the Box to reflow the rulerCanvas
seemingly, the Box with PACK_SHRINK allocates a zero height to the rulerCanvas initally,
which is correct at that point, since the widgets are not yet realised.
However, when we later set_size() on the rulerCanvas, the enclosing Box should reflow.
It does indeed if the child widget is a button or something similar, however,
somehow this reflowing does not work when we set_size on the canvas.

A workaround is to place a new set_size_request().

TODO: do this more precisely, and only on the rulerCanvas. To the contrary,
the mainCanvas is placed into a scolling-pane and thus does not need a size-Request.
Moreover, the latter automatically communicates with the hadjustment() / vadjustment() of
the enclosing scrollbars.
2019-08-22 17:34:32 +02:00
2390385dc5 Timeline: implement function to set the drawing canvas size
as can be verified with the debugger, it sets the correct sizes now.
And it is called only once (unless the content size actually changes).

TODO: however, the visible display of the GTK widgets is not adjusted
2019-08-21 19:13:55 +02:00
8c0b3258cb Timeline: investigate details of CSS box-shadow and dawing strategy
- decide upon the actual drawing strategy
- document our approach chosen thus far
- add a new function to fill in the overall canvas size (TODO)
2019-08-21 17:48:25 +02:00
81253cb152 Timeline: some analysis and planning regarding space allocation 2019-08-08 19:08:04 +02:00
7bf7c51375 Investigation: inconclusive further research (context_save/restore)
Indeed I had missed to connect the new "free standing" StyleContext to
some Gdk::Screen, typically the default screen (connected to the current
top level window). But seemingly this was not really necessary, since,
somehow magically, the style context must have connected itself to some
screen, otherwise it wouldn't be able to access the CSS cascade.

Anyhow, fixing this omission does not resolve our problem.
Nor does any combination of re-connecting, invalidating etc.

I poked around in the GTK (C) code a lot, but could not spot any obvious
missing initialisation step. To much magic around here. Without massive
debugging into GTK internals, I don't see any way to further this
investigation. And, moreover there is a viable workaround
(namely to set and remove the classes explicitly, which works as intended)

I posted a question on Stackoverflow and for now
I'll file this topic as "inconclusive"
https://stackoverflow.com/q/57342478
2019-08-08 19:08:04 +02:00
e5371f66b8 UI-Style: reorganise style constants and introduce some BEM notation
Note however, we will not plaster our UI code and CSS with mangled-out selectors
on each and every single element. This is what cascading was meant to be used for.
2019-08-08 19:08:04 +02:00
8824be440a Investigation: integrate findings thus far into our timeline drawing code
DONE
 - can now control the border size through a set of modifier classes

OPEN
 - but context_save()/restore() does not work; seem to loose all styling
 - not clear how to deal with CSS3 effects like box-shadow
2019-08-03 16:41:46 +02:00
06aa5c4c8c Investigation: get the border resizing to work
...as it turns out, a problem with Cascading prevented the additional classes to become effective
2019-08-03 15:45:36 +02:00
e6e68e2e68 Timeline: investigate options to build a suitable ramp style
...somehow does not yet work as intended...

- unable to control the border-width from code
- Gtk::StyleContext::add_class(name) does not seem to have any effect
2019-07-30 19:20:58 +02:00
b5c2009933 Timeline: first attempt at drawing ramps and borders
...does not work out as expected
 - frames are painted solid, not inset/outset
 - unable to manipulate the border width from code
2019-07-20 17:39:49 +02:00
b2c2787ddc Timeline: populate additional Style-Advice for nested ruler tracks 2019-07-20 01:24:17 +02:00
e3cde9b78d Timeline: fabricate a (test/dummy) population diff for a more complex track
The population message is just made up, in order to create more interesting structures
in the UI and so to further the development of the timeline display.

For the actual structure I choose to mirror my example drawing in draw/UI-TimelineLayout-1.png
which is also used in the TiddlyWiki, on the #GuiTimelineView tiddler

https://lumiera.org/wiki/renderengine.html#GuiTimelineView
2019-07-20 01:24:17 +02:00
3102de9d8a Timeline: inject sub-track into the header pane structure 2019-07-20 01:24:17 +02:00
eca09e3ab5 Timeline: work out how Ruler tracks can be managed 2019-07-20 01:24:17 +02:00
d1e2ddc56e Timeline: refactor common drawing code into an abstract baseclass 2019-07-15 00:25:08 +02:00
713178aecd Timeline: better save the number of pinned elements as dedicated field
...within the Profile object, instead of sneaking this info into the prelude verb
2019-07-15 00:06:59 +02:00
ec50407167 Timeline: start implementing some bits of the drawing code
Use a "catchy" style definition with lime background to make the drawing visible
2019-07-14 17:53:21 +02:00
bc4f7604a2 Timeline: draft a scheme to use custom class names within CSS selectors
We can add our custom classes to custom widgets, and we can set the
widget name, which can be used as #id selector from CSS

Unfortunately we can not set the main CSS node name for CustomWidgets defined through GTKmm (C++)
The latter is only possible when deriving the custom widget in plain-C, which is quite tedious.
On a second thought, this limitation is not so severe as it might seem, because
most of the time you actually do *not* want to change the CSS node name,
because you want to match against existing rules in the theme (e.g. box, or paned)

The actual case here would have been an exception to this rule, since here
it would be nice to anchor the whole custom timeline drawing in an "body.timeline" element


NOTE: Current state for the selector path is now:

window.background box.vertical box[2/3].horizontal widget[2/2] widget paned.vertical widget box.vertical notebook[1/1].frame paned.horizontal.timeline-page box.vertical.timeline.timeline-body fork.timeline
2019-07-13 21:04:33 +02:00
826df93955 Timeline: publish virtual CSS path and style context via Advice system
...and perform the initialisation once, when attaching the first timeline to the UI
Now our code produces the following Gtk::WidgetPath (note the last node, which our code added)

window:backdrop:dir-ltr.background box:backdrop:dir-ltr.vertical box:backdrop:dir-ltr[2/3].horizontal widget:backdrop:dir-ltr[2/2] widget:backdrop:dir-ltr paned:backdrop:dir-ltr.vertical widget:backdrop:dir-ltr box:backdrop:dir-ltr.vertical notebook:backdrop:dir-ltr[1/1].frame paned:backdrop:dir-ltr.horizontal box:backdrop:dir-ltr.vertical fork.timeline
2019-07-13 18:04:02 +02:00
6b4bf0a6ea Library: allow to check if Advice was explicitly given
For context: The »Advice System« was coined a long time ago, in 2010,
based on the vague impression that it might be useful for that kind of application
we are about to build here. And, as can be expected, none of the usage situations
envisioned at that time was brought to bear. Non the less, the facility came in
handy at times, precisely because it is cross-cutting and allows to pass
information without imposing any systematic relationship between the
communication partners.

And now we've got again such a situation.
The global style manager in the UI has to build a virtual CSS path,
which is needed by drawing code somewhere deep down, and we absolutely
do not want to pass a reference to the style manager over 20 recursive calls.

The alternatives would be
 (1) to turn the style manager into a public service
 (2) to have a static access function somewhere
 (3) to use a global variable.
For rationale, (1) would be overblown, because we do not actually request
a service to do work for us, rather we need some global piece of information.
(2) would be equivalent to (1), just more confusing. And (3) is basically
what the Advice system does, with the added benefit of a clear-cut service
access point and a well defined lifecycle.

This changeset adds the ability to check if actual Advice has been published,
which allows us to invoke the (possibly expensive) GTK path building and
style context building code only once.
2019-07-13 17:00:23 +02:00
dde3778cad UiStyle: fix naming 2019-07-13 14:34:55 +02:00
d5cbeab2d8 Timeline: GTK-Code to construct a "virtal" CSS path (see #1168)
This code was cooked up by following the example of gtk_widget_path_append_for_widget()
See gtkwidget.c, 16413
2019-07-13 00:59:05 +02:00
60d28fea2c Timeline: establish a way to pass a StyleContext via Advice system
- at some (yet to be defined) location, a virtual WidgetPath is constructed
  and used to build a Gtk::StyleContext in accordance to the curren CSS

- within the drawing routine, we use Lumiera's Advice-System to access this info
2019-07-12 23:58:25 +02:00
8ffab2f002 Dependencies: get rid of boost-regexp (see #995)
Mostly, std::regexp can be used as a drop-in replacement.

Note: unfortunately ECMA regexps do not support lookbehind assertions.
This lookbehind is necesary here because we want to allow parsing values
from strings with additional content, which means we need explicitly to
exclude mismatches due to invalid syntax.

We can work around that issue like "either line start, or *not* one of these characters.


Alternatively we could consider to make the match more rigid,
i.e we would require the string to conain *only* the timecode spec to be parsed.
2019-06-24 02:41:02 +02:00
ab90d9c71d Functions-Commands: discard the ability to compare functors for equivalence (closes #294)
evil hack R.I.P
2019-06-23 19:45:30 +02:00
94edb5de86 BufferMetadata: likewise abandon use of function comparison for buffer handlers
The existing implementation created a Buffer-Type based on various traits,
including the constructor and destructor functions for the buffer content.
However, this necessitates calculating the hash_value of a std::function,
which (see #294) is generally not possible to implement.

So with this changeset we now store an additional identity hash value
right into the TypeHandler, based on the target type placed into the buffer
2019-06-23 18:57:21 +02:00
d57770ca89 Commands: disable equivalence-test on command equality
This was prompted by a test failing under Boost-1.65 (--> see #294)
When reviewed now, the whole idea of testing Steam-Layer Commands for
equivalence feels a bit sketchy.

Just the comparison for the command ''identity'' alone seems sufficient,
i.e. the test if a command-ID is associated with the same backend-handle
and thus the same functor binding.
2019-06-23 17:35:21 +02:00
aad71a496a Boost-1.65: fix another integer ambiguity problem with boost::rational
<rant>
the "improved" boost::rational can no longer compute 1/x
quite brilliant
</rant>

well... the reason is again signed vs unsigned int.
FrameRate is based on unsigned int (since a negative frame rate makes no sense).
2019-06-22 21:43:33 +02:00
dc301231cf Boost-1.65: resolve ambiguity in timevalue comparison
seemingly, the newer boost libraries added an internal type rational<I>::bool_type
together with an overload for the equality comparison operator.

Unfortunately this now renders a comparison ambiguous with the constant zero (i.e. int{0})
because in our use case we employ rational<uint>.

Workaround is to compare explicitly to a zero of the underlying integer type.
2019-06-22 19:15:19 +02:00
06163f6016 Timeline: filter to select the pinned prefix part of the profile
...when rendering this part, which shall be always visible.
And the rest of the profile needs to be rendered into a second canvas,
which is placed within a pane with scrollbar.

Implemented as a statefull iterator filter
2019-06-21 23:18:44 +02:00
ac3f1d8bef Timeline: implement access mechanism through getter lambda
works, but not really convinced yet...
2019-06-21 20:00:44 +02:00
6b6ed5e0eb Timeline: need accessor function for profile
TODO / WIP.
We can no longer just grab the profile by reference;
rather we need a sensible way how to activate the recomputation logic
2019-06-20 19:01:15 +02:00
77805a5c8c Timeline: handle notification of structural updates 2019-06-20 18:53:12 +02:00
83c462abc3 Timeline: investigate how to handle profile rebuilding
as it turns out, the core problem is that we need a way to detect and signal
structural changes to the logical UI model
2019-06-20 15:36:09 +02:00
d5af020520 Timeline: possible solution for construction of the TrackProfile
...not yet really convinced though
...how does this relate to the "display evaluation pass" of the Layout Manager?
2019-06-15 21:45:38 +02:00
c87ca5d632 Timeline: generalise unsafe access to embedded profile data
While somewhat ugly, I deem this acceptable in such a context,
where the implementation handles its own embedded storage structure.
2019-06-15 17:41:17 +02:00
371b7a487e Timeline: better parametrisation of timeline renderers
and yes, we indeed need the PixSpan: it defines the *horizontal* extension of what needs drawing...
2019-06-15 16:04:18 +02:00
a105e02b52 Timeline: wire distinct grounding/overlay renderers
TODO:
 - actual draw operations not yet implemented
 - find a way how to select the prelude / body part of the track profile

This is a consequence of subsuming the timeline ruler under the concept of an overview track
2019-06-13 18:17:46 +02:00
3f04bb8698 Timeline: sort out how to link the ProfileInterpreter into the draw function 2019-06-13 17:54:06 +02:00
223113ee44 Timeline: switch TrackProfile to hold a sequence of VerbPack entries
turns out to be mostly a drop-in replacement.
2019-06-12 03:29:00 +02:00
1a8917e60a Timeline: after a long break... reconsider how to integrate the new VerbPack
...into the draft skeleton of timeline drawing
2019-06-11 02:40:20 +02:00
f6e5886348 Library: complete test coverage of VerbPack 2019-06-11 02:40:20 +02:00
3d5a67ed14 Library: finish and clean-up the solution for VerbPack dispatch 2019-06-10 16:08:50 +02:00
8f43c2591e Library: investigate malfunction in metaprogramming
the template lib::PolymorphicValue seemingly picked the wrong
implementation strategy for "virtual copy support": In fact it is possible
to use the optimal strategy here, since our interface inherits from CloneSupport,
yet the metaprogramming logic picked the mix-in-adapter (which requires one additional "slot"
of storage plus a dynamic_cast at runtime).

The reason for this malfunction was the fact that we used META_DETECT_FUNCTION
to detect the presence of a clone-support-function. This is not correct, since
it can only detect a function in the *same* class, not an inherited function.

Thus, switching to META_DETECT_FUNCTION_NAME solves this problem
Well, this solution has some downsides, but since I intend to rewrite the
whole virtual copy support (#1197) anyway, I'll deem this acceptable for now


TODO / WIP: still some diagnostics code to clean up, plus a better solution for the EmptyBase
2019-05-10 02:19:01 +02:00
23c9da7c62 Library: solve the dilemma by inheriting from VerbToken
...which, in the end, can even be considered the more logical design choice,
since the "verb visitor" is a more elaborated and sophisiticated Verb-Token,
adding the special twist of embedded storage for variable function arguments
2019-05-09 23:40:47 +02:00
a530665769 Library: fix some reference passing errors
...but bad news on the main issue:
the workaround consumes the tuple and thus is not tenable!

And what is even worse: the textbook implementation of std::apply is
equivalent to our workaround and also consumes the argument tuple
2019-04-22 16:54:22 +02:00
e28635a11a Library: investigate copy behaviour in forwarding calls 2019-04-21 03:52:34 +02:00
5191073558 Library: continue Investigation with workaround, inconclusive yet
A simple yet weird workaround (and basically equivalent to our helper function)
is to wrap the argument tuple itself into std::forward<Args> -- which has the
effect of exposing RValue references to the forwarding function, thus silencing
the compiler.

I am not happy with this result, since it contradicts the notion of perfect forwarding.

As an asside, the ressearch has sorted out some secondary suspicions..
- it is *not* the Varargs argument pack as such
- it is *not* the VerbToken type as such

The problem clearly is related to exposing tuple elements to a forwarding function.
2019-04-20 17:27:47 +02:00
6fbd1021ba Library: first attempt to get the flexible VerbToken to work
...still not decided yet if this whole apporach is sound...
2019-04-17 18:32:21 +02:00
9b5fdd39b8 Library: draft for a visitor-like VerbToken
this is a generalisation of what we use in the diff framework;
typically you'd package the VerbToken into some kind of container,
together with the concrete invocation argument.

However, the specific twist here is that we want *variable arguments*,
depending on the actual operation called on the interpreter interface.
2019-04-16 18:21:51 +02:00
500af8aa34 Library: allow for subclassing PolymorphicValue
Up to now, PolymorphicValue was always used as-is, packaged into a typedef.
Now we consider using it as building block within an adapter for visitor-like tokens.

Which requires to pass-down the ctor call directly from the subclass, at least if we
want to emplace the resulting entity directly into a stdlib container.

As an asside, PolymorphicValue also used explicit specialisations for N-arguments,
which meanwhile can be replaced by variadic templates
2019-04-16 18:15:24 +02:00
ec9b2388da Timeline: consider how to integrate the drawing code
...which leads to a specific twist here; while in the simple version
we still could hope to get away with a simple uniform uint argument,
the situation has changed altogether now. The canvas has turned into
some generic component, since it is instantiated two times, onece for
the time ruler and once for the actual body content. Thus all of the
specifics of the drawing code need to be pushed into a new, dedicated
renderer component. And this more or less forces us to pass all the
actual presentation variations through the invocation arguments of
the visitor.

So we're now off again for a digression, we need a more generalised visitor
2019-04-14 15:38:57 +02:00
7ee0baa241 Timeline: reorganise widget structure within body pane to accommodate time ruler
After thinking the whole concept over several times, it occurred to me that
a separate implementation of a time ruler would be quite redundant with the
envisioned feature of per-track overview rulers. Following this line of thought,
the time ruler would just be some specifically configured overview ruler.

This has the somewhat unfortunate consequence, that it becomes the responsibility
of the body canvas to render the overview ruler, thereby somehow delegating
to a common renderer implementation. Which makes the whole setup of the body canvas
way more complex, because now we get *two* canvas like painting areas, one
always visible at top, and the second one, the content area, fully scrollable
within the lower part.
2019-04-13 17:55:28 +02:00
bd13df2308 Timeline: establish wiring with the timeline DisplayManager 2019-04-12 02:00:19 +02:00
9292da84f2 Timeline: generate the symbolic track profile description
...by recursive walk over the track structure
2019-04-11 17:31:09 +02:00
abdac7aab6 Timeline: setup the framework for building and rendering a track profile 2019-04-10 02:42:08 +02:00
972ec9851b Timeline: perform track profile with given interpreter object 2019-04-10 01:58:11 +02:00
e85f218045 Timeline: define representation of the profile verb tokens 2019-04-06 19:34:31 +02:00
df02258547 Timeline: use a sequence of structure description verbs
...like
 * ruler
 * gap
 * content
 * open/close sub scope
...
2019-04-06 18:21:26 +02:00
b005df1697 Timeline: pick up work on the track drawing logic
...there was a long intermission, first caused by some contribution to Yoshimi,
then by a private project related to Kubernetes
2019-04-05 23:37:56 +02:00
1cf2e459c6 Timeline: consider to turn RulerTrack into a part of the systematic UI model
...meaing
 - it can be diff mutated
 - it is attached to the UI-Bus
 - it has persistent presentation state
2018-12-15 06:05:18 +01:00
1452f1f022 Timeline: plan how to organise time ruler and overview ruler
...the idea is to subsume them within a generic ruler concept
2018-12-15 03:32:57 +01:00
ad9043ae1d Timeline: add the typical framework for custom drawing on the canvas
see gtk-canvas-experiment.cpp
2018-12-10 00:12:53 +01:00
615796d812 Timeline: set an initial size for the canvas 2018-12-10 00:12:53 +01:00
116600b20a Timeline: draft a concept to attack the custom layout
the core question is: how to translate time into pixel coordinates
2018-12-10 00:12:52 +01:00
7b7ec310b3 Dispatcher: rename in accordance to the layer
so now we've got a "SteamDispatcher" ... cute ;-)
2018-12-10 00:12:52 +01:00
2ea89fcb54 Dispatcher: rework loop control logic
- we got occasional hangups when waiting for disabled state
- the builder was not triggered properly, sometimes redundant, sometimes without timeout

As it turned out, the loop control logic is more like a state machine,
and the state variables need to be separated from the external influenced variables.

As a consequence, the inChange_ variable was not calculated properly when disabled in a race,
and then the loop went into infinite wait state, without propagating this to
the externally waiting client, which caused the deadlock
2018-12-10 00:12:52 +01:00
48a829d544 Library: clarify usage of the basic time scale
effectively we rely in the micro tick timescale promoted by libGAVL,
but it seems indicated to introduce our own constant definition.
And also clarify some comments and tests.

(this changeset does not change any values or functionality)
2018-12-10 00:12:52 +01:00
b68d0f24cb Library: settle long standing confusion regarding time border conditions
basically we can pick just any convention here, and so we should pick the convention in a way
that makes most sense informally, for a *human reader*. But what we previously did, was to pick
the condition such as to make it simple in some situations for the programmer....

With the predictable result: even with the disappointingly small number of usages we have up to now,
we got that condition backwards several times.

OK, so from now on!!!

Time::NEVER == Time::MAX, because "never" is as far as possible into the future
2018-12-10 00:12:43 +01:00
a49d79ffbd Library: fix spurious wake-up from (non)timed wait
A classical carry-over of dirty values...
Problem arises, when starting an unconditional wait on the same object monitor,
which previously conducted a timed wait. Then the obsolete timeout from the previous
wait remained in place, causing our Sync-Wrapper (erroneously) to assume a timed wait
and then pthread to return immediately from this timed wait.

The result was permanent idle looping in the ProcDispatcher, after the first command was processed
2018-12-10 00:09:56 +01:00
bc1cf3a0b5 Library: sharpen detection of possible string conversion
When invoking the util::toString conversion, we indeed to want any conversion,
including explicit conversion operators. However, probing the possibility to build a string
can be dangerous, since there is a string constructor from characters, and
integral types can be converted to characters.

OTOH, leaving out explicit conversions is likewise not desirable, since there are
class types, which deliberately do not offer an implicit conversion, but allow
explicit conversion for dump and diagnostic output. The notorious example for
such a situation is the lib::idi::EntryID<TY>. We certainly do not want an
EntryID to be converted into a string without further notice, but we do want
an EntryID to be automatically rendered to string in diagnostic output, since
this will include the human readable ID part.

See especially: 8432420726

Now we'll attempt to get out of this dilemma by probing explicitly for the presence
of a string conversion operator, which will fail for any non-class types, thereby
ruling out all those nasty indirect type -> character -> string conversion paths.

The rationale is: if someone queries the predicate can_convertToString, the intention
is really to get an string rendering, and not just to invoke some random function
with an string argument.
2018-12-10 00:09:56 +01:00
d3d7ea35ad Global-Layer-Renaming: fix remaining textual usages and IDs in the code
- most notably the NOBUG logging flags have been renamed now
 - but for the configuration, I'll stick to "GUI" for now,
   since "Stage" would be bewildering for an occasional user
 - in a similar vein, most documentation continues to refer to the GUI
2018-12-10 00:09:56 +01:00
8d6cb19e3f Global-Layer-Renaming: fix handling of GuiResources in the build
the new structure causes them now to be installed into $TARGET/stage
which is simply not what I want. I still consider $TARGET/gui the better choice,
since an administrator or packager is not aware of our layer namings.

The existing solution was half baked anyway, it did not really replicate the source tree.
On the other hand, I want to retain the location of the CSS files within the GUI tree,
since I consider it a good practice, to keep "code-like" resources with the actual code,
and not far away in some arcane "data" directory.

No I've noticed, that the env.GuiResource() function is only used once, for this very task.
So, for the time being, we can keep it simple and deditaced to that task, i.e
we pick up all CSS files we find and install it into a single target directory.

NOTE: this issue has brought to my attention two further, completely unrelated issues

 * Ticket #1192 (Lumiera hangs on failed GUI start)
 * The ProcDispatcher does an idle wait, due to an error in timed-wait implementation
2018-11-16 18:18:33 +01:00
480104b945 Global-Layer-Renaming: adapt the build system to the new layer names
...with one exception: I'll retain the name "gui" for the final product to be built.
2018-11-16 15:25:28 +01:00
02c5809707 Global-Layer-Renaming: adjust namespace qualification 2018-11-15 23:59:23 +01:00
555ca0bff9 Global-Layer-Renaming: rename namespaces 2018-11-15 23:55:13 +01:00
72b15b8e45 Global-Layer-Renaming: transform header include guards
btw... we could change to #pragma once
2018-11-15 23:52:02 +01:00
2d5ebcd5fa Global-Layer-Renaming: adjust header includes 2018-11-15 23:42:43 +01:00
6261779531 Global-Layer-Renaming: rearrange directories
backend -> vault
proc -> steam
gui -> stage
2018-11-15 23:28:03 +01:00
9e951e1eeb Global-Layer-Renaming: adapt lots of documentation 2018-11-15 21:13:52 +01:00
866d7efe0a Timeline: push the trackname attribute down into the widget/display
...in accordance to our general design guideline: we don't duplicate
actual model values within the controllers/presenters, since our widgets
act themselves as view-model
2018-11-10 03:02:24 +01:00
c8dc5a24a8 DummySessionConnection: extend population diff to send distinct root-track
This change demonstrates how to deal properly with possible duplicate entities
with similar symbolic ID: define a RandomID (to guarantee a distinct hash on each instance).
In the actual implementation, this should happen already within the domain model,
not when constructing the diff (obviously of course...)

This change also adds a mutation sequence to inject the actual track name
2018-11-10 02:39:17 +01:00
a4c37ed99c Library: allow for an explicitly random EntryID
same pattern as the existing EntryID, i.e. a human readable symbol plus a hash
but the hash is just random, instead of deriving it from the symbol text.

Use case is when we explicitly need a distinct identity, even when the
human readable symbolic name is the same. Actual example: the fork root in the timeline
2018-11-10 01:01:59 +01:00
8432420726 Library: fix unwanted implicit conversion
...it should have been explicit from start, since there is no point
in converting an EntryID into a plain flat string without further notice

this became evident, when the compiler picked the string overload on

MakeRec().genNode(specialID)

...which is in compliance to the rules, since string is a direct match,
while BareEntryID would be an (slicing) upcast. However, obviously we
want the BareEntryID here, and not an implicit string conversion,
thereby discarding the special hash value hidden within the ID
2018-11-09 23:09:28 +01:00
7cc68fadea GenNode / Timeline: allow to mutate attribute objects with explicitly given ID
so this seems to be the better approach for dealing with this insidious problem.
In some cases -- as here most prominently with the root track within the timeline --
we have to care within the domain model to prepare unique ids even for sub objects
treated as attributes. In the actual case, without that special attention,
all timelines would hold onto an attribute "fork" with the same ID, based
on the type of the nested object plus the string "fork". Thus all root track
representations in the GUI would end up listening to the same ID on the UI-Bus...
2018-11-09 22:55:08 +01:00
1bbe903202 GenNode: revert -- better not handle this problem on ETD level
...rather extend the "object builder" DSL notation to allow passing in a given EntryID literally.
Rationale is, we should handle the problem of unique IDs on the level of the domain model.
If we attempt to "fix" this within GenNode, the price would be to make the ETD creation stateful
2018-11-09 22:50:48 +01:00
83394a6f01 GenNode: investigate Problem with non-unique attribute IDs
this is not a problem, strictly sepaking, locally.
But it becomes a problem once the GUI uses those attribute IDs
as Element-IDs for tangible UI entities, which need to be uniquely
addressable via the UI-Bus.

An obvious solution is to inject randomness into the Attribute ID hash
2018-11-09 20:19:45 +01:00
20451c958a Timeline: add preliminary track-head display
just some labels, so that we can see the added content
TODO: unsolved problem: how to pass the track name
2018-11-06 01:01:00 +01:00
8ab6c54b9d DummySessionConnection: switch the dummy-ID on each use
...otherwise we'll get several seemingly identical Timeline tabs in the UI,
since this fake function just sends an INS for each newly injected Timeline,
and there is no deduplication in the UI (we assume that in a real session
and timeline-IDs will be unique)
2018-11-05 04:56:01 +01:00
320539344b Timeline: make the injected timeline basically visible 2018-11-01 21:35:09 +01:00
13286f4b90 ElementBox: define the desired properties of this fundamental building block (#1185) 2018-11-01 20:37:36 +01:00
04b665afd1 Timeline: concept for the TrackBody helpers
these recursively nested helper entities work together with the TimelineCanvas
and enable the latter to draw the track background in the Timeline Widget and
to find out about the vertical coordinates where to place content (Clip, Effects, Markers)
2018-10-31 03:52:24 +01:00
0aa4a8cb42 Timeline: make the Patchbay a Viewport container, to follow body scrolling
Gtk::Viewport allows to add the ability to scroll a partial view window
for a container larger than the available display area. The position
and movement of this window is controlled by Gtk::Adjustments,
which can be located elsewhere.

Here we use the existing Adjustments of the ScrolledWindow
holding the body canvas; this setup makes the header pane follow
the scroll movements of the body
2018-10-30 03:37:55 +01:00
8803af1a0a Timeline: further steps towards attaching the widget structure 2018-10-28 18:56:04 +01:00
3dd3fc7810 Timeline: decide upon the organisation of the header pane
we'll uses a recursive structure here, based on nested grids
2018-10-28 01:56:24 +02:00
c212ce94ca Timeline: setup basic widget structure 2018-10-28 01:30:02 +02:00
2d4e58db02 Timeline: consider how to manage size and layout of timeline contents
bottom line is to do most autmatically, and to establish a slave-relation
navigation-area -> timeline-ruler
header-pane-content -> corresponding track-body

this can be accomplished mostly by connecting the aproprieate signals,
thus these widgets will live within the Layout-Manager, which consequently
is renamed into TimelineLayout
2018-10-27 17:27:29 +02:00
c3d91d4ed3 Timeline: draft for building the nested recursive display structure
the solution idea is to use a helper frame, and an "anchor functor",
which is passed down from the respective parent context, and which
does the actual work of injecting the child widgets at the apropriate
position within the parent display.
2018-10-27 01:52:46 +02:00
572bd38fec DummySessionConnection: produce a simple population diff message
seems to work surprisingly well...
the diff application poceeds in the GUI up to the point
where the TrackPresenter need to be inserted into a two-fold display context
2018-10-15 02:54:42 +02:00
de5f0b85d4 DummySessionConnection: new tab in the TestControl dialog box
...to trigger the new fake-functionality
2018-10-14 23:59:35 +02:00
77902d54a6 DummySessionConnection: prepare schaffolding for fake-commands (see #1042)
To drive the timeline display in the UI ahead, the plan is to have
a faked action, which injects dummy population diff messages into the GUI,
resulting in the build-up of a typical simple session timeline
2018-10-14 17:24:13 +02:00
67cccbdc5d Timeline: actually accept and install the TimelineWidget
As starting point, provide an empty placeholder widget to fill the void
2018-10-14 03:48:39 +02:00