diff --git a/doc/devel/uml/Timeline-display-evaluation.png b/doc/devel/uml/Timeline-display-evaluation.png new file mode 100644 index 000000000..bca88dbe2 Binary files /dev/null and b/doc/devel/uml/Timeline-display-evaluation.png differ diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp index c102f66a6..d32b4167c 100644 --- a/src/gui/gtk-lumiera.hpp +++ b/src/gui/gtk-lumiera.hpp @@ -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 {} diff --git a/src/gui/timeline/timeline-widget.cpp b/src/gui/timeline/timeline-widget.cpp new file mode 100644 index 000000000..4e99efe8e --- /dev/null +++ b/src/gui/timeline/timeline-widget.cpp @@ -0,0 +1,569 @@ +/* + TimelineWidget - custom widget for timeline display of the project + + Copyright (C) Lumiera.org + 2016, Hermann Vosseler + + 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 +//#include + + + +//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 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 + TimelineWidget::get_state() + { + return state; + } + + /** @deprecated for #955 */ + void + TimelineWidget::set_state (shared_ptr 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 + TimelineWidget::get_hovering_track() const + { + return hoveringTrack; + } + + + /* ===== Signals ===== */ + + sigc::signal + TimelineWidget::mouse_hover_signal() const + { + return mouseHoverSignal; + } + + sigc::signal + TimelineWidget::playback_period_drag_released_signal() const + { + return playbackPeriodDragReleasedSignal; + } + + sigc::signal > + 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(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 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 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 child, + modelTrack->get_child_tracks()) + create_timeline_tracks_from_branch(child); + } + + + /** @deprecated for #955 */ + shared_ptr + TimelineWidget::create_timeline_track_from_modelTrack( + shared_ptr modelTrack) + { + REQUIRE(modelTrack); + + // Choose a corresponding timeline track class from the model track's + // class + if(typeid(*modelTrack) == typeid(model::ClipTrack)) + return shared_ptr(new timeline::ClipTrack( + *this, dynamic_pointer_cast(modelTrack))); + else if(typeid(*modelTrack) == typeid(model::GroupTrack)) + return shared_ptr(new timeline::GroupTrack( + *this, dynamic_pointer_cast(modelTrack))); + + ASSERT(NULL); // Unknown track type; + return shared_ptr(); + } + + + /** @deprecated for #955 */ + void + TimelineWidget::remove_orphaned_tracks() + { + std::map, + shared_ptr > + orphan_track_map(trackMap); + + // Remove all tracks which are still present in the sequence + BOOST_FOREACH(shared_ptr 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 > + 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 modelTrack, + std::map, + shared_ptr > &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 child, + modelTrack->get_child_tracks()) + search_orphaned_tracks_in_branch(child, orphan_track_map); + } + + + /** @deprecated for #955 */ + shared_ptr + TimelineWidget::lookup_timeline_track( + shared_ptr modelTrack) const + { + REQUIRE(modelTrack); + REQUIRE(modelTrack != sequence()); // The sequence isn't + // really a track + + std::map, shared_ptr >:: + 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(); + } + 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 + TimelineWidget::sequence() const + { + if(!state) + return shared_ptr(); + shared_ptr 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 hovering_track) + { + hoveringTrack = hovering_track; + hoveringTrackChangedSignal.emit(hovering_track); + } + + +}}// namespace gui::timeline diff --git a/src/gui/timeline/timeline-widget.hpp b/src/gui/timeline/timeline-widget.hpp new file mode 100644 index 000000000..0b987eb9d --- /dev/null +++ b/src/gui/timeline/timeline-widget.hpp @@ -0,0 +1,291 @@ +/* + TIMELINE-WIDGET.hpp - custom widget for timeline display of the project + + Copyright (C) Lumiera.org + 2016, Hermann Vosseler + + 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 +//#include + + + +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 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 get_state(); + + /** + * Replaces the current TimelineState object with another. + * @param new_state The new state to swap in. + */ + void set_state(shared_ptr 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 + get_hovering_track() const; + + public: + /* ===== Signals ===== */ + typedef sigc::signal > TimelineStateChangeSignal; + typedef sigc::signal > HoveringTrackChangedSignal; + + sigc::signal mouse_hover_signal() const; + + sigc::signal 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 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 + create_timeline_track_from_modelTrack(shared_ptr 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 modelTrack, + std::map, + shared_ptr > &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 + lookup_timeline_track (shared_ptr 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 sequence() const; + + // ----- Other Functions ----- // + + void + set_hovering_track (shared_ptr hovering_track); + + protected: + + /** + * The state that will be used as the data source for this timeline + * widget. + * @deprecated for #955 + */ + shared_ptr 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 > + trackMap; + + shared_ptr hoveringTrack; + + // Helper Classes + timeline::TimelineLayoutHelper layoutHelper; + + // Child Widgets + timeline::TimelineHeaderContainer *headerContainer; + timeline::TimelineBody *body; + timeline::TimelineRuler *ruler; + + Glib::RefPtr horizontalAdjustment, verticalAdjustment; + Gtk::HScrollbar horizontalScroll; + Gtk::VScrollbar verticalScroll; + + // Signals + sigc::signal mouseHoverSignal; + sigc::signal 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*/ diff --git a/src/gui/widget/timeline-widget.cpp b/src/gui/widget/timeline-widget.cpp index 6f3ecdf52..40016d796 100644 --- a/src/gui/widget/timeline-widget.cpp +++ b/src/gui/widget/timeline-widget.cpp @@ -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 diff --git a/src/gui/widget/timeline-widget.hpp b/src/gui/widget/timeline-widget.hpp index 8e40f606d..bd7ba41c8 100644 --- a/src/gui/widget/timeline-widget.hpp +++ b/src/gui/widget/timeline-widget.hpp @@ -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 {} diff --git a/uml/Lumiera.xmi b/uml/Lumiera.xmi index 8d50dfaae..5141e9fdb 100644 --- a/uml/Lumiera.xmi +++ b/uml/Lumiera.xmi @@ -1,5 +1,5 @@ - + umbrello uml modeller http://umbrello.kde.org @@ -17,6 +17,7 @@ + @@ -71,7 +72,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -151,30 +240,34 @@ + + + + - + - + - - + + - - - + + + - + - + @@ -191,7 +284,7 @@ - + @@ -204,22 +297,22 @@ - + - + - + - - - - + + + + @@ -228,13 +321,13 @@ - + - - + + - + @@ -262,7 +355,7 @@ - + @@ -300,6 +393,17 @@ + + + + + + + + + + + @@ -340,43 +444,7 @@
- - -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
-
+ @@ -486,7 +554,7 @@ - +
@@ -527,7 +595,7 @@
- +
@@ -538,111 +606,6 @@
- -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
- -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
- -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
@@ -765,7 +728,7 @@ - +
@@ -806,7 +769,7 @@
- +
@@ -819,117 +782,6 @@
- - - -
- -
-
- -
- -
- -
- -
- -
- -
-
-
- -
- -
- - - -
- -
-
- -
- -
- -
- -
- -
- -
-
-
- -
- -
- - - -
- -
-
- -
- -
- -
- -
- -
- -
-
-
- -
- - -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
-
-
@@ -1015,36 +867,119 @@ - + + + + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
- +
- +
- +
- -
- -
-
- -
- -
-
- -
- -
-
- +
@@ -1052,6 +987,87 @@
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
@@ -1079,172 +1095,6 @@ - -
- -
- - -
- -
- - -
- -
- -
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
@@ -1256,43 +1106,7 @@
- - -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
-
+
@@ -1321,172 +1135,6 @@ - -
- -
- - -
- -
- - -
- -
- -
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
@@ -1527,172 +1175,6 @@ - -
- -
- - -
- -
- - -
- -
- -
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
@@ -1733,172 +1215,6 @@ - -
- -
- - -
- -
- - -
- -
- -
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
@@ -1919,7 +1235,7 @@ - +
@@ -1939,204 +1255,6 @@
- -
- -
- - -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
-
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
@@ -2173,7 +1291,7 @@ - +
@@ -2184,111 +1302,6 @@
- -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
- -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
- -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
@@ -2318,204 +1331,6 @@ - -
- -
- - -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
-
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
@@ -2572,7 +1387,7 @@ - +
@@ -2592,204 +1407,6 @@
- -
- -
- - -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
-
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
@@ -2826,7 +1443,7 @@ - +
@@ -2839,660 +1456,6 @@
- - - -
- -
-
- -
- -
-
- -
- -
-
- -
- -
- - -
- -
-
- -
- -
- - -
- -
- - -
- -
- -
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
-
-
- -
- -
-
-
-
- -
- -
- - - -
- -
-
- -
- -
-
- -
- -
-
- -
- -
- - -
- -
-
- -
- -
- - -
- -
- - -
- -
- -
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
-
-
- -
- -
-
-
-
- -
- -
- - - -
- -
-
- -
- -
-
- -
- -
-
- -
- -
- - -
- -
-
- -
- -
- - -
- -
- - -
- -
- -
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
-
-
- -
- -
-
-
-
- -
- - -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
-
-
@@ -3520,204 +1483,6 @@ - -
- -
- - -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- - -
- -
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
-
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- - -
- -
- -
- -
- -
- -
-
-
- -
- -
- -
-
-
-
-
-
-
@@ -3765,36 +1530,136 @@ - + +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
- +
- +
- -
- -
-
- -
- -
-
- -
- -
-
- +
@@ -3802,6 +1667,120 @@
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
diff --git a/wiki/renderengine.html b/wiki/renderengine.html index fd0928637..bddb2965b 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -2452,11 +2452,11 @@ we need a test setup for this investigation. * realistic: shall reflect the situation in our actual UI -
+
//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.
 
-
+
//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
+[>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.
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index fbd570494..b0096f8d9 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -134,7 +134,7 @@ - + @@ -316,7 +316,7 @@ - + @@ -366,6 +366,18 @@ + + + + + + + + + + + +