Obsoletes and replaces the ad-hoc written type rebindings from
iter-adapter and friends. The new scheme is more consistent and does
less magic, which necessitates an additional remove_pointer<IT> within
the iterator adaptors. Rationale is, "pointer" is treated now just as
a primitive type without additional magic or unwrapping, since it is
impossible to tell generically if the pointer or the pointee was
meant to be the "value"
Oh well.
This kept me busy a whole day long -- and someone less stubborn like myself
would probably supect a "compiler bug" or put the blame on the language C++
So to stress this point: the compiler behaved CORRECT
Just SFINAE is dangerous stuff: the metafunction I concieved yesterday requires
a complete type, yet, under rather specific circumstances, when instantiating
mutually dependent templates (in our case lib::diff::Record<GenNode> is a
recursive type), the distinction between "complete" and "incomplete"
becomes blurry, and depends on the processing order. Which gave the
misleading impression as if there was a side-effect where the presence
of one definition changes the meaning of another one used in the same
program. What happened in fact was just that the evaluation order was
changed, causing the metafunction to fail silently, thus picking
another specialisation.
attempt to re-use the same traits as much as possible
NOTE: new code not passing compiler yet, but refactored old code
does, and still passes unit test
...which uncovered an error in the test fixture
plus helped to spot the spurious copy when passing the argument to the expand functor
And my GDB crashed when loading the executable, YAY!
so we'll need to coment out some code from now on,
until we're able to switch to a more recent toolchain (#1118)
...while this implementation works now, it is still very complex and intricate.
I am still doubtful this is a good approach, but well, we need to try that route....
but possible only for the iterator -> iterator case
Since we can not "probe" a generic lambda, we get only one shot:
we can try to bind it into a std::function with the assumed signature
...since all those metaprogramming techniques rely on SFINAE,
but *instantiating* a template means to compile it, which is more
than just substituate a type into the signature
If forming the signature fails -> SFINAE, try next one
If instantiating a template fails -> compile error, abort
Basically we want to support two distinct cases, just by slightly adapting
the invocation of the expansion functor:
Case-1: classical monadic flatMap:
the Functor accepts a value yielded by the source iterator
and builds a new "expaneded" iterator
Case-2: manipulation of opaque implementation state
the Functor knows internal details of the source iterator
and thus takes the source iterator as such as argument,
performs some manipulation and then builds a new sub-iterator
A soulution to reconcile those two distinct cases can be built
with the help of a generic lambda
Here, the tricky question remains, how to relate this evalutaion scheme
to the well known monadic handling of collections and iterators.
It seems, we can not yet decide upon that question, rather we should
first try to build a concrete implementation of the envisioned algorithm
and then reconsider the question later, to what extent this is "monadic"
This can be seen as a side track, but the hope is
by relying on some kind of monadic evaluation pattern, we'll be
able to to reconcile the IterExplorer draft from 2012 with the requirement
to keep the implementation of "tree position" entirely opaque.
The latter is mandatory in the use case here, since we must not intermingle
the algorithm to resolve UI-coordinates in any way with the code actually
navigating and accessing GTK widgets. Thus, we're forced to build some kind
of abstraction barrier, and this turns out to be surprisingly difficult.
...which was deliberately represented in an asymmetric way, to verify the
design's ability to cope with such implementation intricacies. So basically
we have to kick in at LEVEL == 1 and access the implementation differently.
This exercise just shows again, that treating tree structures recursively
is the way to go, and we should do similar when coding up the query-API
for the real GTK toolkit based window elements...
...which can be helpful when a function usually returns a somewhat dressed-up iterator,
but needs to return a specific fixed value under some circumstances
this fixes a silly mistake:
obviously we want named sub-nodes, aka. "Attributes",
but we used the anonymous sub-nodes instead, aka. "Children"
Incidentally, this renders the definitions also way more readable;
in fact the strange post-fix naming notation of the original version
was a clear indication of using the system backwards....
obviously, we get a trivial case, when the path is explicit,
and we need a tricky full blown resolution with backtracking
when forced to interpolate wildcards to cover a given UICoord
spec against the actual UI topology.
Do we need it?
* actually not right now
* but already a complete implementation of the ViewSpec concept
requires such a resolution
...to limit them to the UI-Coordinates themselves,
while declining the possibility to mutate the target environment
through the PathResolver. Better handle changes within the
target environment by dedicated API calls on the target elements,
instead of creating some kind of "universal structure"
..this collection of ideas, terms and conclusions has been shaped
since some time within the TiddlyWiki. Since I've now started even
some supporting implementation regarding these concepts, its time
to publish them in the design documentation section of the Website
After completing the self-contained UICoord data elements,
the next thing to consider might be how to resolve UI coordinates
against an actual window topology. We need to define a suitable
command-and-query interface in order to build and verify this
intricate resolution process separated from the actual UI code.
exploring the idea of a configuration DSL.
As a first step, this could be a simple internal DSL,
implemented as a bunch of static functor objects, which are internally bound
and thus implemented by the ViewLocator within InteractionDirector
...we have to face the problem that we need some generic strategy
for access to component views, which possibly will become customisable.
And the allowed patterns of access are quite different for the various
kind of view we know....
responsible for access and allocation of component views.
Internally wired to the PanelLocator within the global WindowLocator
This setup settles those nasty qeustions of crosswise top-level access
this starts work on a new UI global topic (#1004)
- coin a new term: "view component"
- distinction between veiw component and Panel
- consider how to locate view components
- WindowList becomes WindowLocator
actually I do not know much regarding the actual situation when,
within the Builder run, we're able to detect a change and generate
a diff description. However, as a first step, I'll pick IterSrouce
as a base interface and use a "generation context", which is to be
passed by shared-ptr
the (trivial) implementation turned out to be correct as written,
but it was (again) damn challenging to get the mulithreaded chaotic
test fixture and especially the lambda captures to work correct.
- concept for a first preliminary implementation of dispatch into the UI thread
- define an integration effort to build a complete working communication chain
This change was caused by investigation of UI event loop dispatch;
since the GTK UI is designed to run single threaded, any invocation
from other threads need to be diepatched explicitly.
A possible way to achieve this is to use Glib::Dispatcher, which
in turn requires that the current thread (which is in this case the UI thread)
already holds a Glib::MainContext
This prompted me to create a tight link between the external facade interfaces
of the UI and the event loop itself. What remains to be settled is how
to hand over arguments to the action in the main loop
After investigation of current GTK and GIO code, I came to the conclusion
that we do *not* want to rely on the shiny new Gtk::Application, which
provides a lot of additional "convenience" functionality we do neither
need nor want. Most notably, we do not want extended desktop integration
like automatically connecting to D-Bus or exposing application actions
as desktop events.
After stripping away all those optional functions and extensions, it turns
out the basic code to operate the GTK main event loop is quite simple.
This changeset extracts this code from the (deprecated) Gtk::Main and
integrates it directly in Lumiera's UI framework object (UiManager).
this is just a tiny change to make things more othogonal.
Now the unwinding and calls to any GTK / Widget dtors happen *after*
emitting the term signal from UI shutdown. Which means, the other subsystems
are shutting down (in their dedicated threads) as well, thus lowering
the probability of some action still using the UI and triggering an exception
as it turned out, the former functionality was deactivated in 2009
with changeset 6151415
The whole concept seems to be unfinished, and needs to be reworked
and integrated with "Views and Perspectives" (whatever that is...)
See also #1097
Gtk::Main is deprecated, but the new solution, instantiating a
Gtk::Application object does not match our use case, since we handle
all application concerns already and just need a Gtk main loop to run.
Anyway, it became clear that the "main object" will be the new UiManager.
As a first step, I've now moved the (deprecated) Gtk::Main object
down there. Next step (planned) will be to inherit from Gio::Application
and clone some functionality from Gtk::Application
...which opens more questions than it solves at the moment.
Especially note #1096, the question how to refer to object-IDs
Maybe we need to enable sending EntryIDs via GenNode?
Anyway, the magic spell is broken now: we have a way how to
establish commands and how to issue them from the UI, with full integration
of UI-Bus, layer separation facade, instance management and ProcDispatcher
Looks like a stepping stone
after extended analysis, it turned out to be a "placeholder concept"
and introduces an indirection, which can be removed altogether
- simple command invocation happens at gui::model::Tangible
- it is based on the command (definition) ID
- instance management happens automatically and transparently
- the extended case of context-bound commands will be treated later,
and is entirely self-contained
while the initial design treated the commands in a strictly top-down manner,
where the ID is known solely to the CommandRegistry, this change and information
duplication became necessary now, since by default we now always enqueue and
dispatch anonymous clone copies from the original command definition (prototype).
This implementation uses the trick to tag this command-ID when a command-hanlde
is activated, which is also the moment when it is tracked in the registry.
in accordance to the design changes concluded yesterday.
- in the standard cases we now check the global registry first
- automatically create anonymous clone copy from global commands
- reorganise code internally to use common tail implementation
as it turns out, we can always trigger commands right away,
the moment all arguments are known. Thus it is sufficient to
send a single argument binding message, which allows us to
get rid of a lot or ugly complexities (payload visitor).
It seems more adequate to push the somewhat intricate mechanics
for the "fall back" onto generic commands down into the implementation
level of CommandInstanceManager. The point is, we know the standard
usage situation is to rely on the instance manager, and thus we want
to avoid redundant table lookups, only to support the rare case of
fallback to global commands. The latter is currently used only from
unit-tests, but might in future also be used by scripts.
Due to thread safety considerations, I have refrained from handing
out a direct reference to the command token sitting in the registry,
even while not doing so incurs a small runtime penalty (accessing
the shared ref-count for creating a copy of the smart-handle).
This is the typical situation where you'd be tempted to sacrifice
sanity for the sake of an imaginary performance benefit, which
in fact is dwarfed by all the machinery of UI-Bus and argument
passing via GenNode.