start with actual rework of the timeline display

draft a concept for timeline layout management
This commit is contained in:
Fischlurch 2016-11-30 23:12:44 +01:00
parent 170c505a8a
commit 67beeab25a
9 changed files with 1451 additions and 2582 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -99,7 +99,7 @@ namespace gui {
*/
namespace model {}
/** The namespace of all video output implementations. */
/** Video output implementation. */
namespace output {}
/** Dialog box classes. */
@ -114,6 +114,9 @@ namespace gui {
/** The workspace window and it's helper classes. */
namespace workspace {}
/** The timeline display and editing operations. */
namespace timeline {}
/** GUI helpers, utility functions and classes. */
namespace util {}

View file

@ -0,0 +1,569 @@
/*
TimelineWidget - custom widget for timeline display of the project
Copyright (C) Lumiera.org
2016, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file timeline-widget.cpp
** Implementation details of Lumiera's timeline display widget.
**
** @todo as of 12/2016 a complete rework of the timeline display is underway
**
*/
#include "gui/gtk-lumiera.hpp"
#include "gui/timeline/timeline-widget.hpp"
//#include "gui/workspace/workspace-window.hpp"
//#include "gui/ui-bus.hpp"
//#include "lib/format-string.hpp"
//#include "lib/format-cout.hpp"
//#include "lib/util.hpp"
//#include <algorithm>
//#include <cstdlib>
//using util::_Fmt;
//using std::shared_ptr;
//using std::weak_ptr;
//using util::contains;
//using Gtk::Widget;
//using sigc::mem_fun;
//using sigc::ptr_fun;
//using std::cout;
//using std::endl;
namespace gui {
namespace timeline {
const int TimelineWidget::TrackPadding = 1;
const int TimelineWidget::HeaderWidth = 150;
const int TimelineWidget::HeaderIndentWidth = 10;
TimelineWidget::TimelineWidget (shared_ptr<timeline::TimelineState> source_state)
: Table(2, 2)
, layoutHelper(*this)
, headerContainer(NULL)
, body(NULL)
, ruler(NULL)
, horizontalAdjustment(Gtk::Adjustment::create(0, 0, 0))
, verticalAdjustment(Gtk::Adjustment::create(0, 0, 0))
, horizontalScroll(horizontalAdjustment)
, verticalScroll(verticalAdjustment)
, update_tracks_frozen(false)
{
body = manage(new TimelineBody(*this));
ENSURE(body != NULL);
headerContainer = manage(new TimelineHeaderContainer(*this));
ENSURE(headerContainer != NULL);
ruler = manage(new TimelineRuler(*this));
ENSURE(ruler != NULL);
horizontalAdjustment->signal_value_changed().connect( sigc::mem_fun(
this, &TimelineWidget::on_scroll) );
verticalAdjustment->signal_value_changed().connect( sigc::mem_fun(
this, &TimelineWidget::on_scroll) );
body->signal_motion_notify_event().connect( sigc::mem_fun(
this, &TimelineWidget::on_motion_in_body_notify_event) );
update_tracks();
attach(*body, 1, 2, 1, 2, FILL|EXPAND, FILL|EXPAND);
attach(*ruler, 1, 2, 0, 1, FILL|EXPAND, SHRINK);
attach(*headerContainer, 0, 1, 1, 2, SHRINK, FILL|EXPAND);
attach(horizontalScroll, 1, 2, 2, 3, FILL|EXPAND, SHRINK);
attach(verticalScroll, 2, 3, 1, 2, SHRINK, FILL|EXPAND);
set_state(source_state);
set_tool(timeline::Arrow);
}
TimelineWidget::~TimelineWidget()
{
REQUIRE(headerContainer);
headerContainer->clear_headers();
trackMap.clear();
}
/* ===== Data Access ===== */
/** @deprecated for #955 */
shared_ptr<timeline::TimelineState>
TimelineWidget::get_state()
{
return state;
}
/** @deprecated for #955 */
void
TimelineWidget::set_state (shared_ptr<timeline::TimelineState> new_state)
{
state = new_state;
// Clear the track tree
trackMap.clear();
if (state)
{
// Hook up event handlers
state->getViewWindow().changed_signal().connect( sigc::mem_fun(
this, &TimelineWidget::on_view_window_changed) );
state->getSequence()->get_child_track_list().signal_changed().
connect(sigc::mem_fun(
this, &TimelineWidget::on_track_list_changed ) );
state->selectionChangedSignal().connect(mem_fun(*this,
&TimelineWidget::on_body_changed));
state->playbackChangedSignal().connect(mem_fun(*this,
&TimelineWidget::on_body_changed));
}
update_tracks();
// Send the state changed signal
stateChangedSignal.emit (state);
}
void
TimelineWidget::zoom_view (double timescale_ratio)
{
if(state)
{
const int view_width = body->get_allocation().get_width();
state->getViewWindow().zoom_view(view_width / 2, timescale_ratio);
}
}
ToolType
TimelineWidget::get_tool() const
{
REQUIRE(body != NULL);
return body->get_tool();
}
void
TimelineWidget::set_tool(ToolType tool_type)
{
REQUIRE(body != NULL);
body->set_tool(tool_type);
}
shared_ptr<timeline::Track>
TimelineWidget::get_hovering_track() const
{
return hoveringTrack;
}
/* ===== Signals ===== */
sigc::signal<void, Time>
TimelineWidget::mouse_hover_signal() const
{
return mouseHoverSignal;
}
sigc::signal<void>
TimelineWidget::playback_period_drag_released_signal() const
{
return playbackPeriodDragReleasedSignal;
}
sigc::signal<void, shared_ptr<timeline::Track> >
TimelineWidget::hovering_track_changed_signal() const
{
return hoveringTrackChangedSignal;
}
TimelineWidget::TimelineStateChangeSignal
TimelineWidget::state_changed_signal() const
{
return stateChangedSignal;
}
/* ===== Events ===== */
void
TimelineWidget::on_scroll()
{
if(state)
{
TimeValue newStartOffset ((gavl_time_t)horizontalAdjustment->get_value());
state->getViewWindow().set_time_offset(Time(newStartOffset));
}
}
void
TimelineWidget::on_size_allocate(Allocation& allocation)
{
Widget::on_size_allocate(allocation);
update_scroll();
}
void
TimelineWidget::on_view_window_changed()
{
REQUIRE(ruler != NULL);
if(state)
{
timeline::TimelineViewWindow &window = state->getViewWindow();
const int view_width = body->get_allocation().get_width();
horizontalAdjustment->set_page_size(
window.get_time_scale() * view_width);
horizontalAdjustment->set_value(_raw(window.get_time_offset()));
}
}
void
TimelineWidget::on_body_changed()
{
REQUIRE(ruler != NULL);
REQUIRE(body != NULL);
ruler->queue_draw();
body->queue_draw();
}
void
TimelineWidget::on_add_track_command()
{
// # TEST CODE
if(sequence())
sequence()->get_child_track_list().push_back(
shared_ptr<model::Track>(new model::ClipTrack()));
}
/* ===== Internals ===== */
void
TimelineWidget::update_tracks()
{
if(update_tracks_frozen)
return;
if(state)
{
// Remove any tracks which are no longer present in the model
remove_orphaned_tracks();
// Create timeline tracks from all the model tracks
create_timeline_tracks();
// Update the layout helper
layoutHelper.clone_tree_from_sequence();
layoutHelper.update_layout();
}
else
trackMap.clear();
}
void
TimelineWidget::freeze_update_tracks()
{
update_tracks_frozen = true;
}
void
TimelineWidget::thaw_update_tracks()
{
update_tracks_frozen = false;
}
void
TimelineWidget::create_timeline_tracks()
{
REQUIRE(state);
BOOST_FOREACH(shared_ptr<model::Track> child,
sequence()->get_child_tracks())
create_timeline_tracks_from_branch(child);
// Update the header container
REQUIRE(headerContainer != NULL);
headerContainer->update_headers();
}
/** @deprecated for #955 */
void
TimelineWidget::create_timeline_tracks_from_branch(
shared_ptr<model::Track> modelTrack)
{
REQUIRE(modelTrack);
// Is a timeline UI track present in the map already?
if (!contains(trackMap, modelTrack))
{
// The timeline UI track is not present
// We will need to create one
trackMap[modelTrack] =
create_timeline_track_from_modelTrack(modelTrack);
}
// Recurse to child tracks
BOOST_FOREACH(shared_ptr<model::Track> child,
modelTrack->get_child_tracks())
create_timeline_tracks_from_branch(child);
}
/** @deprecated for #955 */
shared_ptr<timeline::Track>
TimelineWidget::create_timeline_track_from_modelTrack(
shared_ptr<model::Track> modelTrack)
{
REQUIRE(modelTrack);
// Choose a corresponding timeline track class from the model track's
// class
if(typeid(*modelTrack) == typeid(model::ClipTrack))
return shared_ptr<timeline::Track>(new timeline::ClipTrack(
*this, dynamic_pointer_cast<model::ClipTrack>(modelTrack)));
else if(typeid(*modelTrack) == typeid(model::GroupTrack))
return shared_ptr<timeline::Track>(new timeline::GroupTrack(
*this, dynamic_pointer_cast<model::GroupTrack>(modelTrack)));
ASSERT(NULL); // Unknown track type;
return shared_ptr<timeline::Track>();
}
/** @deprecated for #955 */
void
TimelineWidget::remove_orphaned_tracks()
{
std::map<shared_ptr<model::Track>,
shared_ptr<timeline::Track> >
orphan_track_map(trackMap);
// Remove all tracks which are still present in the sequence
BOOST_FOREACH(shared_ptr<model::Track> child,
sequence()->get_child_tracks())
search_orphaned_tracks_in_branch(child, orphan_track_map);
// orphan_track_map now contains all the orphaned tracks
// Remove them
std::pair<shared_ptr<model::Track>, shared_ptr<timeline::Track> >
pair;
BOOST_FOREACH( pair, orphan_track_map )
{
ENSURE(pair.first);
trackMap.erase(pair.first);
}
}
/** @deprecated for #955 */
void
TimelineWidget::search_orphaned_tracks_in_branch(
shared_ptr<model::Track> modelTrack,
std::map<shared_ptr<model::Track>,
shared_ptr<timeline::Track> > &orphan_track_map)
{
REQUIRE(modelTrack);
// Is the timeline UI still present?
if(contains(orphan_track_map, modelTrack))
orphan_track_map.erase(modelTrack);
// Recurse to child tracks
BOOST_FOREACH(shared_ptr<model::Track> child,
modelTrack->get_child_tracks())
search_orphaned_tracks_in_branch(child, orphan_track_map);
}
/** @deprecated for #955 */
shared_ptr<timeline::Track>
TimelineWidget::lookup_timeline_track(
shared_ptr<model::Track> modelTrack) const
{
REQUIRE(modelTrack);
REQUIRE(modelTrack != sequence()); // The sequence isn't
// really a track
std::map<shared_ptr<model::Track>, shared_ptr<timeline::Track> >::
const_iterator iterator = trackMap.find(modelTrack);
if (iterator == trackMap.end())
{
// The track is not present in the map
// We are in an error condition if the timeline track is not found
// - the timeline tracks must always be synchronous with the model
// tracks.
ENSURE(0);
return shared_ptr<timeline::Track>();
}
ENSURE(iterator->second != NULL);
return iterator->second;
}
void
TimelineWidget::on_layout_changed()
{
REQUIRE(headerContainer != NULL);
REQUIRE(body != NULL);
headerContainer->on_layout_changed();
body->queue_draw();
update_scroll();
}
void
TimelineWidget::update_scroll()
{
REQUIRE(body != NULL);
const Allocation body_allocation = body->get_allocation();
if(state)
{
///////////////////////////////////////////////TICKET #861 shoudln't that be performed by TimelineViewWindow, instead of manipulating values from the outside?
timeline::TimelineViewWindow &window = state->getViewWindow();
//----- Horizontal Scroll ------//
// TEST CODE
horizontalAdjustment->set_upper( 1000 * GAVL_TIME_SCALE / 200);
horizontalAdjustment->set_lower(-1000 * GAVL_TIME_SCALE / 200);
// Set the page size
horizontalAdjustment->set_page_size(
window.get_time_scale() * body_allocation.get_width());
//----- Vertical Scroll -----//
// Calculate the vertical length that can be scrolled:
// the total height of all the tracks minus one screenful
int y_scroll_length = layoutHelper.get_total_height() -
body_allocation.get_height();
if(y_scroll_length < 0) y_scroll_length = 0;
// If by resizing we're now over-scrolled, scroll back to
// maximum distance
if((int)verticalAdjustment->get_value() > y_scroll_length)
verticalAdjustment->set_value(y_scroll_length);
verticalAdjustment->set_upper(y_scroll_length);
// Hide the scrollbar if no scrolling is possible
// Having this code included seems to cause a layout loop as the
// window is shrunk
if(y_scroll_length <= 0 && verticalScroll.get_visible())
verticalScroll.hide();
else if(y_scroll_length > 0 && !verticalScroll.get_visible())
verticalScroll.show();
}
}
int
TimelineWidget::get_y_scroll_offset() const
{
return (int)verticalAdjustment->get_value();
}
void
TimelineWidget::set_y_scroll_offset(const int offset)
{
verticalAdjustment->set_value(offset);
}
bool
TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event)
{
REQUIRE(event != NULL);
ruler->set_mouse_chevron_offset(event->x);
if(state)
{
timeline::TimelineViewWindow &window = state->getViewWindow();
mouseHoverSignal.emit(window.x_to_time(event->x));
}
return true;
}
/** @deprecated for #955 */
shared_ptr<model::Sequence>
TimelineWidget::sequence() const
{
if(!state)
return shared_ptr<model::Sequence>();
shared_ptr<model::Sequence> sequence = state->getSequence();
ENSURE(sequence);
return sequence;
}
void
TimelineWidget::on_track_list_changed()
{
update_tracks();
}
void
TimelineWidget::on_playback_period_drag_released()
{
playbackPeriodDragReleasedSignal.emit();
}
void
TimelineWidget::set_hovering_track(shared_ptr<timeline::Track> hovering_track)
{
hoveringTrack = hovering_track;
hoveringTrackChangedSignal.emit(hovering_track);
}
}}// namespace gui::timeline

View file

@ -0,0 +1,291 @@
/*
TIMELINE-WIDGET.hpp - custom widget for timeline display of the project
Copyright (C) Lumiera.org
2016, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file timeline-widget.hpp
** This file defines the core component of the Lumiera GUI
**
** @todo as of 12/2016 a complete rework of the timeline display is underway
**
*/
#ifndef GUI_TIMELINE_TIMELINE_WIDGET_H
#define GUI_TIMELINE_TIMELINE_WIDGET_H
#include "gui/gtk-base.hpp"
#include "lib/time/timevalue.hpp"
//#include <memory>
//#include <vector>
namespace gui {
namespace timeline {
/**
* Core timeline display (custom widget).
* @remarks This widget is a composite of several widgets contained
* within the timeline namespace.
* @deprecated dysfunctional and broken by switch to GTK-3. Needs to be rewritten
*/
class TimelineWidget
: public Gtk::Table
{
public:
/**
* @param source_state state to be used used as the
* data source (model) for this timeline widget.
*/
TimelineWidget (shared_ptr<timeline::TimelineState> source_state);
virtual ~TimelineWidget();
public: /* ===== Data Access ===== */
/**
* Gets a pointer to the current state object.
* @return The state object that the timeline widget is currently
* working with.
*/
shared_ptr<timeline::TimelineState> get_state();
/**
* Replaces the current TimelineState object with another.
* @param new_state The new state to swap in.
*/
void set_state(shared_ptr<timeline::TimelineState> new_state);
/**
* Zooms the view in or out as by a number of steps while keeping a
* given point on the timeline still.
* @param zoom_size The number of steps to zoom by. The scale factor
* is 1.25^(-zoom_size).
*/
void zoom_view(double timescale_ratio);
/**
* Gets the type of the tool currently active.
*/
timeline::ToolType get_tool() const;
/**
* Sets the type of the tool currently active.
*/
void set_tool(timeline::ToolType tool_type);
shared_ptr<timeline::Track>
get_hovering_track() const;
public:
/* ===== Signals ===== */
typedef sigc::signal<void, shared_ptr<timeline::TimelineState> > TimelineStateChangeSignal;
typedef sigc::signal<void, shared_ptr<timeline::Track> > HoveringTrackChangedSignal;
sigc::signal<void, lib::time::Time> mouse_hover_signal() const;
sigc::signal<void> playback_period_drag_released_signal() const;
HoveringTrackChangedSignal hovering_track_changed_signal() const;
TimelineStateChangeSignal state_changed_signal() const;
/* ===== Events ===== */
protected:
void on_scroll();
void on_size_allocate(Gtk::Allocation& allocation);
void on_view_window_changed();
void on_body_changed();
void on_add_track_command();
/* ===== Utilities ===== */
protected:
/* ===== Internals ===== */
private:
// ----- Track Mapping Functions ----- //
/**
* Updates the timeline widget to match the state of the track tree.
*/
void update_tracks();
void freeze_update_tracks();
void thaw_update_tracks();
/**
* Ensures timeline UI tracks have been created for every model track
* present in sequence.
*/
void create_timeline_tracks();
/**
* Iterates through a branch of tracks, recursing into each sub-branch
* creating UI timeline tracks for each model track if they don't
* already exist in trackMap.
* @param list The parent track of the branch.
*/
void
create_timeline_tracks_from_branch (shared_ptr<model::Track> modelTrack);
/**
* Creates a timeline UI track to correspond to a model track.
* @param modelTrack The model track to create a timeline track from.
* @return The timeline track created, or an empty shared_ptr if
* modelTrack has an unreckognised type (this is an error condition).
*/
shared_ptr<timeline::Track>
create_timeline_track_from_modelTrack(shared_ptr<model::Track> modelTrack);
/**
* Removes any UI tracks which no longer have corresponding model
* tracks present in the sequence.
*/
void remove_orphaned_tracks();
void
search_orphaned_tracks_in_branch (shared_ptr<model::Track> modelTrack,
std::map<shared_ptr<model::Track>,
shared_ptr<timeline::Track> > &orphan_track_map);
/**
* Looks up a timeline UI track in trackMap that corresponds to a
* given modelTrack.
* @param modelTrack The model track to look up.
* @returns The timeline UI track found, or an empty shared_ptr if
* modelTrack has no corresponding timeline UI track (this is an
* error condition).
*/
shared_ptr<timeline::Track>
lookup_timeline_track (shared_ptr<model::Track> modelTrack) const;
// ----- Layout Functions ----- //
void on_layout_changed();
void update_scroll();
int get_y_scroll_offset() const;
void set_y_scroll_offset(const int offset);
// ----- Event Handlers -----//
/**
* An event handler that receives notifications for when the
* sequence's track tree has been changed.
*/
void on_track_list_changed();
void on_playback_period_drag_released();
bool on_motion_in_body_notify_event(GdkEventMotion *event);
// ----- Helper Functions ----- //
/**
* Helper to get the sequence object from the state.
* @return Returns a shared pointer to the sequence.
*/
shared_ptr<model::Sequence> sequence() const;
// ----- Other Functions ----- //
void
set_hovering_track (shared_ptr<timeline::Track> hovering_track);
protected:
/**
* The state that will be used as the data source for this timeline
* widget.
* @deprecated for #955
*/
shared_ptr<timeline::TimelineState> state;
// Model Data
/**
* The trackMap maps model tracks to timeline widget tracks which are
* responsible for the UI representation of a track.
* @remarks The tree structure is maintained by the model, and as the
* widget is updated with update_tracks, timeline tracks are added and
* removed from the map in correspondence with the tree.
* @deprecated for #955
*/
std::map<shared_ptr<model::Track>
,shared_ptr<timeline::Track> >
trackMap;
shared_ptr<timeline::Track> hoveringTrack;
// Helper Classes
timeline::TimelineLayoutHelper layoutHelper;
// Child Widgets
timeline::TimelineHeaderContainer *headerContainer;
timeline::TimelineBody *body;
timeline::TimelineRuler *ruler;
Glib::RefPtr<Gtk::Adjustment> horizontalAdjustment, verticalAdjustment;
Gtk::HScrollbar horizontalScroll;
Gtk::VScrollbar verticalScroll;
// Signals
sigc::signal<void, Time> mouseHoverSignal;
sigc::signal<void> playbackPeriodDragReleasedSignal;
HoveringTrackChangedSignal hoveringTrackChangedSignal;
TimelineStateChangeSignal stateChangedSignal;
bool update_tracks_frozen;
/* ===== Constants ===== */
protected:
static const int TrackPadding;
static const int HeaderWidth;
static const int HeaderIndentWidth;
friend class timeline::TimelineBody;
friend class timeline::TimelineHeaderContainer;
friend class timeline::TimelineHeaderWidget;
friend class timeline::TimelineLayoutHelper;
friend class timeline::TimelineRuler;
friend class timeline::GroupTrack;
};
}}// namespace gui::timeline
#endif /*GUI_TIMELINE_TIMELINE_WIDGET_H*/

View file

@ -21,6 +21,14 @@
* *****************************************************/
/** @file timeline-widget.cpp
**
** @deprecated as of 11/2016, a complete rework of the timeline display is underway
** @see gui::timeline::TimelineWidget new timeline display
**
*/
#include "gui/widget/timeline-widget.hpp"
#include <boost/foreach.hpp>

View file

@ -30,6 +30,7 @@
** Moreover, this class is designed way to monolithic.
** It will never be able to scale to the full planned
** timeline and editing functionality of Lumiera
** @see gui::timeline::TimelineWidget new timeline display
*/
@ -60,7 +61,10 @@ namespace widget {
using lib::time::Time;
using std::shared_ptr;
/** namespace of timeline widget helper classes. */
/** namespace of timeline widget helper classes.
* @deprecated as of 11/2016, a complete rework of the timeline display is underway
* @see (\ref gui::timeline) namespace of the new timeline display
*/
namespace timeline {}

File diff suppressed because it is too large Load diff

View file

@ -2452,11 +2452,11 @@ we need a test setup for this investigation.
* realistic: shall reflect the situation in our actual UI
</pre>
</div>
<div title="GuiClipWidget" creator="Ichthyostega" modifier="Ichthyostega" created="201611180114" modified="201611272357" tags="GuiPattern design draft" changecount="18">
<div title="GuiClipWidget" creator="Ichthyostega" modifier="Ichthyostega" created="201611180114" modified="201612011708" tags="GuiPattern design draft" changecount="20">
<pre>//The representation of a [[media clip|Clip]] for manipulation by the user within the UI.//
Within Lumiera, a clip is conceived as a //chunk of media,// which can be handled in compound. Clip as such is an abstract concept, which is treated with minimal assumptions...
* we know that a clip has //media content,// which need not be uniform and can be inherently structured (e.g. several media, several channels)
* like anything within a timeline, a clip has a temporal extension (but not necessarily finite; it can be zero, or it can be infinite)
* like anything within a timeline, a clip has a temporal extension (but not necessarily finite; it can //not be zero,// but it can be infinite)
* by virtue of [[Placement]], a clip acquires a time position.
Due to this unspecific nature, a clip might take on various //appearances// within the UI.
@ -8132,10 +8132,13 @@ Actually, Timeline is both an interface and acts as façade. Its an interface, b
Besides building on the asset management, implementing Timeline (and Sequence) as StructAsset yields another benefit: ~StructAssets can be retrieved by query, allowing to specify more details of the configuration immediately on creation. //But on the short term, this approach causes problems:// there is no real inference engine integrated into Lumiera yet (as of 2/2010 the plan is to get an early alpha working end to end first). For now we're bound to use the {{{fake-configrules}}} and to rely on a hard wired simulation of the intended behaviour of a real query resolution. Just some special magic queries will work for now, but that's enough to get ahead.
</pre>
</div>
<div title="TimelineDisplayManager" creator="Ichthyostega" modifier="Ichthyostega" created="201611280235" tags="spec GuiPattern" changecount="1">
<div title="TimelineDisplayManager" creator="Ichthyostega" modifier="Ichthyostega" created="201611280235" modified="201612011740" tags="spec GuiPattern img" changecount="4">
<pre>//guide and control the concrete display properties of the various sub components (tracks, clips) comprising a timeline display.//
The TimelineDisplayManager actually is an abstraction, a control interface, revolving around the guidance individual components need in order to settle on a proper display. Those components are represented as mediating entities, the TrackPresenter and the ClipPresenter, each of which controls and manages a mostly passive GTK widget. To this end, the presenters need to know at which virtual coordinates their corresponding widgets would show up, and they need to know if these widgets need to be actually present at the moment. Also, especially the ClipPresenter needs to know which ''clip appearance style'' to choose for the corresponding slave widget.
!display evaluation pass
[&gt;img[Clip presentation control|uml/Timeline-display-evaluation.png]]Since the timeline display is formed by several nested collections of elements, a proper display layout must incorporate information from all those parts. A naive approach likely would just iterate over them and reach in to extract data -- or even worse, build a separate display data store, which then needs to be kept in sync with the component hierarchy. Any of this would lead to high coupling and turns any necessary adjustment and changes due to evolution of requirements into a liability. Such a dangerous situation can be avoided altogether by admitting the collaborative nature of the task at hand. To get there, we need to distil the abstraction shared between the global and the local concerns, and we need to shape it such as to build onto some kind of invariant, allowing that abstraction to re-emerge at several levels of locality.
</pre>
</div>
<div title="TimelineSequences" modifier="Ichthyostega" created="200811011836" modified="201505310138" tags="design decision img" changecount="4">

View file

@ -134,7 +134,7 @@
<node CREATED="1479688653913" ID="ID_1435784278" MODIFIED="1479688666394" TEXT="dieser wiederum mu&#xdf; f&#xfc;r jede Erweiterung konsultiert werden"/>
</node>
</node>
<node CREATED="1479774700668" ID="ID_1407821684" MODIFIED="1479774704971" TEXT="Mutation">
<node CREATED="1479774700668" HGAP="36" ID="ID_1407821684" MODIFIED="1480606879554" TEXT="Mutation" VSHIFT="7">
<node CREATED="1479774705839" ID="ID_301222108" MODIFIED="1479774729887" TEXT="Problem">
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#d30f0f" CREATED="1479774731141" ID="ID_1523088286" MODIFIED="1479774739456" TEXT="Element != Widget"/>
@ -316,7 +316,7 @@
</node>
</node>
</node>
<node CREATED="1480300573857" ID="ID_434577605" MODIFIED="1480300855667" TEXT="Anzeige-Steuerung" VSHIFT="20">
<node CREATED="1480300573857" HGAP="68" ID="ID_434577605" MODIFIED="1480606887745" TEXT="Anzeige-Steuerung" VSHIFT="39">
<icon BUILTIN="pencil"/>
<node CREATED="1480300584454" ID="ID_202830560" MODIFIED="1480300592344" TEXT="globaler Layout-Manager">
<node CREATED="1480300595820" ID="ID_1004344887" MODIFIED="1480300606631" TEXT="fungiert als Service"/>
@ -366,6 +366,18 @@
</node>
</node>
</node>
<node CREATED="1480606888860" HGAP="25" ID="ID_899101975" MODIFIED="1480606903105" TEXT="Implementierung" VSHIFT="14">
<icon BUILTIN="pencil"/>
<node CREATED="1480606950372" ID="ID_1502878943" MODIFIED="1480606953527" TEXT="Grundstruktur"/>
<node CREATED="1480606954115" ID="ID_1178000371" MODIFIED="1480606960326" TEXT="Struktur-Modell"/>
<node CREATED="1480606973713" ID="ID_163713350" MODIFIED="1480606978899" TEXT="Track-Presenter"/>
<node CREATED="1480607029673" ID="ID_619470641" MODIFIED="1480607052500" TEXT="Track-Anzeige">
<node CREATED="1480607033512" ID="ID_1815699851" MODIFIED="1480607035268" TEXT="Kopf"/>
<node CREATED="1480607035712" ID="ID_1405339006" MODIFIED="1480607037355" TEXT="Rumpf"/>
</node>
<node CREATED="1480606985087" ID="ID_885244508" MODIFIED="1480606989354" TEXT="Layout-Manager"/>
<node CREATED="1480607059909" ID="ID_703281238" MODIFIED="1480607061944" TEXT="Control"/>
</node>
</node>
<node CREATED="1476376943985" HGAP="22" ID="ID_1422206856" MODIFIED="1479434895083" TEXT="Viewer" VSHIFT="10"/>
<node CREATED="1479434763643" HGAP="25" ID="ID_1572413636" MODIFIED="1479434887744" TEXT="Clip" VSHIFT="31">