From e815bd4fd2a37f3addd8ee35d99ca134c871eafd Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Fri, 12 Sep 2008 20:55:54 +0100 Subject: [PATCH 1/6] Moved buttons to the timeline --- src/gui/panels/timeline-panel.cpp | 14 ++++++++++++++ src/gui/panels/timeline-panel.hpp | 15 +++++++++++---- src/gui/panels/viewer-panel.cpp | 13 ++----------- src/gui/panels/viewer-panel.hpp | 13 ++----------- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp index 65e9ae6b7..b079c0b2f 100644 --- a/src/gui/panels/timeline-panel.cpp +++ b/src/gui/panels/timeline-panel.cpp @@ -39,6 +39,11 @@ const int TimelinePanel::ZoomToolSteps = 2; // 2 seems comfortable TimelinePanel::TimelinePanel() : Panel("timeline", _("Timeline"), "panel_timeline"), + previousButton(Stock::MEDIA_PREVIOUS), + rewindButton(Stock::MEDIA_REWIND), + playPauseButton(Stock::MEDIA_PLAY), + forwardButton(Stock::MEDIA_FORWARD), + nextButton(Stock::MEDIA_NEXT), arrowTool(Gtk::StockID("tool_arrow")), iBeamTool(Gtk::StockID("tool_i_beam")), zoomIn(Stock::ZOOM_IN), @@ -52,6 +57,13 @@ TimelinePanel::TimelinePanel() : // Setup the toolbar timeIndicatorButton.set_label_widget(timeIndicator); + + toolbar.append(previousButton); + toolbar.append(rewindButton); + toolbar.append(playPauseButton); + toolbar.append(forwardButton); + toolbar.append(nextButton); + toolbar.append(timeIndicatorButton); toolbar.append(seperator1); @@ -60,7 +72,9 @@ TimelinePanel::TimelinePanel() : &TimelinePanel::on_arrow_tool)); toolbar.append(iBeamTool, mem_fun(this, &TimelinePanel::on_ibeam_tool)); + toolbar.append(seperator2); + toolbar.append(zoomIn, mem_fun(this, &TimelinePanel::on_zoom_in)); toolbar.append(zoomOut, mem_fun(this, &TimelinePanel::on_zoom_out)); diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp index b46218e87..e154e9a26 100644 --- a/src/gui/panels/timeline-panel.hpp +++ b/src/gui/panels/timeline-panel.hpp @@ -75,6 +75,16 @@ private: TimelineWidget timelineWidget; // Toolbar Widgets + + Gtk::Label timeIndicator; + Gtk::ToolButton timeIndicatorButton; + + Gtk::ToolButton previousButton; + Gtk::ToolButton rewindButton; + Gtk::ToolButton playPauseButton; + Gtk::ToolButton forwardButton; + Gtk::ToolButton nextButton; + Gtk::ToggleToolButton arrowTool; Gtk::ToggleToolButton iBeamTool; @@ -84,10 +94,7 @@ private: Gtk::ToolButton zoomOut; Gtk::SeparatorToolItem seperator2; - - Gtk::Label timeIndicator; - Gtk::ToolButton timeIndicatorButton; - + // Internals bool updatingToolbar; diff --git a/src/gui/panels/viewer-panel.cpp b/src/gui/panels/viewer-panel.cpp index 323859b9a..ee129a606 100644 --- a/src/gui/panels/viewer-panel.cpp +++ b/src/gui/panels/viewer-panel.cpp @@ -31,20 +31,11 @@ namespace gui { namespace panels { ViewerPanel::ViewerPanel() : - Panel("viewer", _("Viewer"), "panel_viewer"), - previousButton(Stock::MEDIA_PREVIOUS), - rewindButton(Stock::MEDIA_REWIND), - playPauseButton(Stock::MEDIA_PLAY), - forwardButton(Stock::MEDIA_FORWARD), - nextButton(Stock::MEDIA_NEXT) + Panel("viewer", _("Viewer"), "panel_viewer") { //----- Set up the Tool Bar -----// // Add the commands - toolBar.append(previousButton); - toolBar.append(rewindButton); - toolBar.append(playPauseButton); - toolBar.append(forwardButton); - toolBar.append(nextButton); + // Configure the toolbar toolBar.set_toolbar_style(TOOLBAR_ICONS); diff --git a/src/gui/panels/viewer-panel.hpp b/src/gui/panels/viewer-panel.hpp index 9f92b4f63..5400aee41 100644 --- a/src/gui/panels/viewer-panel.hpp +++ b/src/gui/panels/viewer-panel.hpp @@ -31,9 +31,6 @@ #include "panel.hpp" #include "../widgets/video-display-widget.hpp" -using namespace lumiera::gui::widgets; -using namespace Gtk; - namespace lumiera { namespace gui { namespace panels { @@ -45,14 +42,8 @@ namespace panels { protected: - ToolButton previousButton; - ToolButton rewindButton; - ToolButton playPauseButton; - ToolButton forwardButton; - ToolButton nextButton; - - VideoDisplayWidget display; - Toolbar toolBar; + lumiera::gui::widgets::VideoDisplayWidget display; + Gtk::Toolbar toolBar; }; } // namespace panels From becfcb3935c8f2307162ef06988a82c4c96805fa Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 13 Sep 2008 01:59:39 +0200 Subject: [PATCH 2/6] increase timeout (2sec) to avoid problems when running in a VM --- tests/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.sh b/tests/test.sh index d919ed073..e2d5159b7 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -30,7 +30,7 @@ export LC_ALL=C arg0="$0" srcdir="$(dirname "$arg0")" -ulimit -S -t 1 -v 524288 +ulimit -S -t 2 -v 524288 valgrind="" if [ "$VALGRINDFLAGS" = 'DISABLE' ]; then echo "valgrind explicit disabled" From caf7497021549f11ce2f98e0c51c6483c913fca0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 5 Oct 2008 07:10:15 +0200 Subject: [PATCH 3/6] drawing to show time position of frames used in Design Entry regarding time handling --- doc/devel/draw/FramePositions.svg | 1269 +++++++++++++++++++++++++++++ wiki/draw/FramePositions1.png | Bin 0 -> 2478 bytes wiki/draw/FramePositions2.png | Bin 0 -> 12685 bytes wiki/index.html | 77 +- 4 files changed, 1344 insertions(+), 2 deletions(-) create mode 100644 doc/devel/draw/FramePositions.svg create mode 100644 wiki/draw/FramePositions1.png create mode 100644 wiki/draw/FramePositions2.png diff --git a/doc/devel/draw/FramePositions.svg b/doc/devel/draw/FramePositions.svg new file mode 100644 index 000000000..01cc14ca1 --- /dev/null +++ b/doc/devel/draw/FramePositions.svg @@ -0,0 +1,1269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + style="overflow:visible"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + t + + + + + + + + + + + + + + + + + + + + + + + t + + + + + + + + + + + + + + + + + + + + + + + + + t + + diff --git a/wiki/draw/FramePositions1.png b/wiki/draw/FramePositions1.png new file mode 100644 index 0000000000000000000000000000000000000000..520788cb652835d95caa0a7f41688092c203f63e GIT binary patch literal 2478 zcmcImX;jkN7XKsWtfgh8d9}DcD@`mcN7Pb#YL1yh&UH&12^1B`l(d_fiZ7=UMXhYS zjzy^`l0|7IL*+n*f(=SJ3k6yZ_upIZ%lr1eytCFmXP>iw`>efxd#`oQWj`M`O*MTr z001;S++Fpce2c$TD44YhyJ5Q7gQafq4k%7NaPhh6K3SQ?k+=Jcx9aXc+N__#iH|?(vO)Do zT=U7(=@*9l&x&A44evL%;J;k-JgL4;hWIIeVcTC#sUEIc!n9g;NPila*y1LrQ8i0E zN(_%pwLBm;@V8~#RV!l~XVq^vxSl4|nWjQuFji5;-P~N|1HRhY>*K3oFv9`lVOQim zVqPx6Pr6Ba;rhgG*vA{~1M4)Nv%7&Pc(x{fIO(5Lw$e0>V!a<10l9@DOS2~`UBMIRJrPN)gUp4J zXQ#V)wylhT#~Ni1MN-A`NT+T#{C|L^c@#2&wi{)2Z}l$7RT)YdYq0p@gfqzFtv||#4|K&mtL#@U zxeeNMpR!RKr&CcQXHb}m;eTaFeqsFgLyXoLyjBiZD^Q-DSFK}WQ!nS1K8}Kl6yhP! ztB}#Insd*70bwA+oWuZv)Lc9=dZD*pkfwcK1!ZN}X2PH+G!wz%`R_)#-HFmqEC;0g@3ci8s;H6^(GWAxQDS04$|Jy!8dX| zw|MD;7#hh=)SAbgKwxzivvAy>v>Yf{{c(vXsa?7$m`txAO6O3aD|H>G~xuxwWygQc7;I(U3xQS|De z<2ad(w5)?%1#qm8DahPv@(n4B;+ZwrWhxHGllp>Vg8ph~Kqth-#l7(J#lYP|N{CMUxyFN`Yieo3j-gnp;aOks%fZvw!8G_&24l)4_DiPN^u zU_N+f6ND5#Yw_k`Cp!B9Dl+rW-!I7)st$XW@00$x`S5Id`_gcRx=qsbhR#k0fNGPL z>(C)+lV`c*3&-Fok#?iodOLnQPo4@Y_0AZtzUGiQ9vnp%U-Z7O84DoHtbxdtac6O~ zjkuki=+vxZ6OHQ2>Y?K7KV5B7a5pLO3=Iv{uc)Zd2@DJj2n>8PFi;u`=Jm^xXa0=+ zPpBN%n1u3DoLxU>aoiWb#kYy@CGiuR0A_;h{J6t$d2Hq8q&*m%eQUj~z{b)}L@aSy zTUfpM5D0Rl?@4fhewms1@ce;G{ki0jUTGSd)KWiXCP$J*V-gkFhFWqVwtWYqX@Gci z{Uv_zMg#XJEVhg?+=;qc06(sI#oc%UC9|p3-?nXI{uT>nAKOkf6KcU44;OPQyO+q8 zrxfNrE$#gdYIS|*H4wA=tM2~6^1)Ysl$(oU*zXoXq?~C+w52pMJ(VP6;C(uuvOGzy zu%x&)pCIRsRboF z3xN@pd5MrT&JjEy4i1y-XCHL`Qd6CXb$Wrn;kv^{PHE1JFibE)u6e?}`}BhHH~Fq8 zhaJ-+Z=-~vjcrIV2ETPv!{lJ?&mG9BrcL`NR!%=?zczRK2w zDZ6fRJ~Krr^Gw=zTIck8*`AFi=ZqzOyr!La!L-HPiy7WNqGSMKG<5@-4m2WYs$J;Q z*6js~*gA^C1|j^G5is)BS7?q(3(2xg>c>Evpd~Ol2Qb|JZb6`kR6<5`ZBgv|+jdSf-j_*d8DabtN%;v94aT3arYSu`+0%wcL{^FJ5`S>+=DGQk$`F zq&~r#_k%u6;lF;DIq3e_eLBA716t5nwtP7#1eb8X#pEn*RLZl};p3q-l2UwB%xPsug$^s%D@-aC1-iVxB4G7h@5aPR zP)-UK9b<@}MUpyS;wv-nNMpGpcgEd8CHxvDL_PS5+KHhzY9ofi@R{(4g&xA?0>2MC z{5S{A=BYUN=$s_Jy6kEFr=SyP?zDhf7Z#j%)-}ie01xy!>OD{Xk;2W$uTYXf`F6ql zu)p5B=9pCpBK0=w7*yywEPpP>3ZE4R7$ewmJlvm_Q(Jwp)X%Y8r!P6j!6w}uUOjy~QTTgw-Ke=ES_u#an_^NH-g0gj2%djJ3c literal 0 HcmV?d00001 diff --git a/wiki/draw/FramePositions2.png b/wiki/draw/FramePositions2.png new file mode 100644 index 0000000000000000000000000000000000000000..8eccf3664ff2e323c33d53e8988a016901753c22 GIT binary patch literal 12685 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 literal 0 HcmV?d00001 diff --git a/wiki/index.html b/wiki/index.html index fd3fe210e..89790640d 100644 --- a/wiki/index.html +++ b/wiki/index.html @@ -802,12 +802,14 @@ for __Running__
LumieraWiki
 ShortCuts
-
+
* There is a [[Manifest]] explaining the vision of the Lumiera project
 * The foundation how we work together is defined in LumieraDesignProcess
 * There is a description how the git repository is set up in RepositorySetup
 * we decided to write code in GNU style, with no tabs (use spaces)
-
+ +!basic decisions +* TimeHandling
/***
@@ -4602,6 +4604,77 @@ Thus no server and no network connection is needed. Simply open the file in your
  * see [[Homepage|http://tiddlywiki.com]], [[Wiki-Markup|http://tiddlywiki.com/#MainFeatures]]
 
+
+
/%||'''State'''||''Final''||%/
+||'''State'''||''Draft''||
+||'''Date'''||[[Date(2007-06-21T05:12:03Z)]]||
+||'''Proprosed by'''||["Ichthyostega"]||
+
+!time handling
+how to handle time values in the code and which policy to aply to the "current" position
+
+!!Description
+# Representation of time values
+#* we use an uniform time type. Time is time, not frames, samples etc.
+#* all timings in Lumiera are based on integral datatypes
+#* we use a fixed, very fine grid, something of the sort of microseconds
+#* the internal representation is based on a {{{typedef int64_t gavl_time_t}}}
+#* we use a set of library routines and  convenience-methods to
+#** get time in different formats (fractional seconds, frame counts)
+#** calculate with time values (overloaded operators)
+#* time measurement is zero based (of course :-P )
+# Quantizing to a frame index or similar
+#* quantizing/rounding shall happen only once at a defined point in the calculation chain and, if in doubt, be done always as late as possible. 
+#* values needing to be quantized to time (grid) positions are calculated by half-way rounding, but the result should not depend on the actual zero-point of the scale (i.e. {{{floor(0.5+val)}}}, thus quant(0.5) yields 1, quant(0.49) yields 0, quant(-0.5) yields 0 )
+# Position of frames[>img[draw/FramePositions1.png]]
+#* frame numbers are zero based and Frame 0 starts at time=0 (or whatever the nominal start time is)
+#* each frame starts when the locator hits its lower border (inclusively) and ends when the locator is on its upper border (exclusively)
+#** when the locator snaps to frames this means it can be placed on the start positions of the frames solely
+#** when the locator is placed on such a start position, this means //always// displaying the frame starting at this position, irrespective of playback direction.
+# Current position for keyframe nodes and automation[>img[draw/FramePositions2.png]]
+#* when parameter values for plugins/automation need to be retrieved on a per frame base (which normally is the case), for each frame there is a well defined __//point of evalutation//__ time position, irrespective of the playback direction
+#* there is no single best choice where to put this "POE", thus we provide a switch
+#** //point of evalutation// of the automation is in the middle of the timespan covered by a frame
+#** //point of evalutation// is on the lower bound of each frame
+#** maybe additional position or fraction (?)
+#* moreover, we provide an option to snap the keyframe nodes to the //point of evalutation// within each frame or to be able to move them arbitrarily
+#* when keyframes are set by tweaking of parameters, they are located at the //point of evalutation// position.
+
+
+!!!!Tasks
+* figure out what has to be done when switching the "current position" policy on a existing project
+
+
+!!!Alternatives
+Leave everything as in Cinelerra2, i.e. show frames after the locator has passed over them, behave differnt when playing backwards and set the keyframes on the position of the locator but use them on the frame actually to be shown (which differs according to the playback direction but is always "one off").
+
+Why not? because it makes frame-precise working with keyframes a real pain and even creates contradictory situations when you
+switch back and forward while tweaking.
+
+Similar for the issues with quantized values. At first sight, e.g. directly using the frame numbers as coordinates (as Cinelerra does) seems to be clever, but on the long run we get lots of case distinctions scattered all over the code. Thus better use one uniform scheme and work with precise time values as long as possible and only quantize for rendering a given frame.
+
+
+!!Rationale
+The intention is to make time handling and calculations as uniform and "rational" as possible. We try to stick to the precise mathematical values and let the calculations just yield an result in an uniform manner, instead of sticking to "simple" values like frame counts or even a session-wide frame rate
+# time and interval calculations are tricky. Solve this question once and be done.
+# rounding is always dangerous, rounded values are not the more "clean" values. The floor-rounding rule is chosen, because the length of an interval after quantizion should not depend on the position in relation to the zero point. The usual mathematical rounding behaves "symmetrical" to the zero point, which could yield a different length after quantizion if an interval contains the zero point
+# this is based on the analoy with real film running through a film projector (or the usual fencepost problem)
+# while using the actual position of the locator as the "current" position for keyframes seems more natural at first, it crates problems when mixing footage with different framerate or when using a low-framerate proxy footage
+
+
+
+!Comments
+This is the summary of a discussion cehteh, Plouj and ichthyo just had on irc.
+ -- ["Ichthyostega"] //2007-06-21T05:12:03Z//
+
+We use Gavl now
+ -- ["ct"] //2008-03-05T16:19:22Z//
+
+I've tidied up this old design proposal, we could make it final now. I've changed the rounding rule, please check if it's OK. In the original proposal, we  wanted to use the common mathematical rounding rule, i.e. round(-x) = - round(x) . I changed this, because of the danger of interval lengts or alignment to "jump" dependant on the position in relation to the time zero point.
+ -- ["Ichthyostega"] //2008-10-04T22:47:54Z//
+
+
+
The question to find out about is: how much of the coding to do with the help of BOUML. Basically, BOUML is capable to permanently support the coding; you can define all entities, fields and methods in the UML model an just develop the method bodies //conventionally// with a text editor. 
 

From 094ce0654d83d1892388a1c54789ca69f75306b8 Mon Sep 17 00:00:00 2001
From: Joel Holdsworth 
Date: Tue, 7 Oct 2008 21:17:29 +0100
Subject: [PATCH 4/6] Added playback support in the timeline

---
 src/gui/lumiera_ui.rc                       |  14 +-
 src/gui/panels/timeline-panel.cpp           | 105 ++++++++++-
 src/gui/panels/timeline-panel.hpp           |  16 ++
 src/gui/widgets/timeline-widget.cpp         |  27 +++
 src/gui/widgets/timeline-widget.hpp         |  28 +++
 src/gui/widgets/timeline/timeline-body.cpp  | 198 +++++++++++++-------
 src/gui/widgets/timeline/timeline-body.hpp  |  20 ++
 src/gui/widgets/timeline/timeline-ruler.cpp | 138 ++++++++++----
 src/gui/widgets/timeline/timeline-ruler.hpp |  23 ++-
 9 files changed, 451 insertions(+), 118 deletions(-)

diff --git a/src/gui/lumiera_ui.rc b/src/gui/lumiera_ui.rc
index 02f6d90fc..a13ba209d 100644
--- a/src/gui/lumiera_ui.rc
+++ b/src/gui/lumiera_ui.rc
@@ -126,6 +126,7 @@ style "timeline_body"
   gtkmm__CustomObject_TimelineBody::background = "#7E838B"
   gtkmm__CustomObject_TimelineBody::selection = "#2D2D90"
   gtkmm__CustomObject_TimelineBody::selection_alpha = 0.5
+  gtkmm__CustomObject_TimelineBody::playback_point = "#006000"
 }
 
 style "timeline_ruler" = "default_base"
@@ -140,10 +141,15 @@ style "timeline_ruler" = "default_base"
   gtkmm__CustomObject_TimelineRuler::min_division_width = 100
   gtkmm__CustomObject_TimelineRuler::mouse_chevron_size = 5
   gtkmm__CustomObject_TimelineRuler::selection_chevron_size = 5
-  gtkmm__CustomObject_TimelineRuler::playback_arrow_colour = "#2D2D90"
-  gtkmm__CustomObject_TimelineRuler::playback_arrow_alpha = 0.5
-  gtkmm__CustomObject_TimelineRuler::playback_arrow_size = 10
-  gtkmm__CustomObject_TimelineRuler::playback_arrow_stem_size = 3
+  
+  gtkmm__CustomObject_TimelineRuler::playback_point_colour = "#006000"
+  gtkmm__CustomObject_TimelineRuler::playback_point_alpha = 0.5
+  gtkmm__CustomObject_TimelineRuler::playback_point_size = 12
+  
+  gtkmm__CustomObject_TimelineRuler::playback_period_arrow_colour = "#2D2D90"
+  gtkmm__CustomObject_TimelineRuler::playback_period_arrow_alpha = 0.5
+  gtkmm__CustomObject_TimelineRuler::playback_period_arrow_size = 10
+  gtkmm__CustomObject_TimelineRuler::playback_period_arrow_stem_size = 3
 }
 
 style "timeline_header_base" = "default_base"
diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp
index b079c0b2f..709323bad 100644
--- a/src/gui/panels/timeline-panel.cpp
+++ b/src/gui/panels/timeline-panel.cpp
@@ -42,6 +42,7 @@ TimelinePanel::TimelinePanel() :
   previousButton(Stock::MEDIA_PREVIOUS),
   rewindButton(Stock::MEDIA_REWIND),
   playPauseButton(Stock::MEDIA_PLAY),
+  stopButton(Stock::MEDIA_STOP),
   forwardButton(Stock::MEDIA_FORWARD),
   nextButton(Stock::MEDIA_NEXT),
   arrowTool(Gtk::StockID("tool_arrow")),
@@ -54,24 +55,29 @@ TimelinePanel::TimelinePanel() :
   // Setup the widget
   timelineWidget.mouse_hover_signal().connect(
     mem_fun(this, &TimelinePanel::on_mouse_hover));
+  timelineWidget.playback_period_drag_released_signal().connect(
+    mem_fun(this, &TimelinePanel::on_playback_period_drag_released));
   
   // Setup the toolbar
   timeIndicatorButton.set_label_widget(timeIndicator);
   
+  toolbar.append(timeIndicatorButton);
+  
   toolbar.append(previousButton);
   toolbar.append(rewindButton);
-  toolbar.append(playPauseButton);
+  toolbar.append(playPauseButton,
+    mem_fun(this, &TimelinePanel::on_play_pause));
+  toolbar.append(stopButton,
+    mem_fun(this, &TimelinePanel::on_stop));
   toolbar.append(forwardButton);
   toolbar.append(nextButton);
-    
-  toolbar.append(timeIndicatorButton);
   
   toolbar.append(seperator1);
   
-  toolbar.append(arrowTool, mem_fun(this,
-    &TimelinePanel::on_arrow_tool));
-  toolbar.append(iBeamTool, mem_fun(this,
-    &TimelinePanel::on_ibeam_tool));
+  toolbar.append(arrowTool,
+    mem_fun(this, &TimelinePanel::on_arrow_tool));
+  toolbar.append(iBeamTool,
+    mem_fun(this, &TimelinePanel::on_ibeam_tool));
     
   toolbar.append(seperator2);
   
@@ -92,6 +98,33 @@ TimelinePanel::TimelinePanel() :
   show_time(0);
 }
 
+void
+TimelinePanel::on_play_pause()
+{ 
+  // TEST CODE! 
+  if(!is_playing())
+    {
+      play();
+    }
+  else
+    {
+      frameEvent.disconnect();
+    }
+  
+  update_playback_buttons();
+}
+
+void
+TimelinePanel::on_stop()
+{
+  // TEST CODE! 
+  timelineWidget.set_playback_point(GAVL_TIME_UNDEFINED);
+  frameEvent.disconnect();
+  show_time(timelineWidget.get_playback_period_start());
+  
+  update_playback_buttons();
+}
+
 void
 TimelinePanel::on_arrow_tool()
 {
@@ -126,7 +159,26 @@ TimelinePanel::on_zoom_out()
 void
 TimelinePanel::on_mouse_hover(gavl_time_t time)
 {
-  show_time(time);
+
+}
+
+void
+TimelinePanel::on_playback_period_drag_released()
+{
+  //----- TEST CODE - this needs to set the playback point via the
+  // real backend
+  timelineWidget.set_playback_point(
+    timelineWidget.get_playback_period_start());
+  //----- END TEST CODE
+  
+  play();
+}
+
+void
+TimelinePanel::update_playback_buttons()
+{
+  playPauseButton.set_stock_id(is_playing() ?
+    Stock::MEDIA_PAUSE : Stock::MEDIA_PLAY);  
 }
 
 void
@@ -150,12 +202,49 @@ TimelinePanel::update_zoom_buttons()
     TimelineWidget::MaxScale);
 }
 
+void
+TimelinePanel::play()
+{
+  if(timelineWidget.get_playback_point() == GAVL_TIME_UNDEFINED)
+    timelineWidget.set_playback_point(
+      timelineWidget.get_playback_period_start());
+  frameEvent = Glib::signal_timeout().connect(
+    sigc::mem_fun(this, &TimelinePanel::on_frame),
+    1000 / 25);
+}
+
+bool
+TimelinePanel::is_playing() const
+{
+  // TEST CODE! - this should be hooked up to the real playback control
+  return frameEvent.connected();
+}
+
 void
 TimelinePanel::show_time(gavl_time_t time)
 {
   timeIndicator.set_text(lumiera_tmpbuf_print_time(time));
 }
 
+bool
+TimelinePanel::on_frame()
+{
+  // TEST CODE!  
+  const gavl_time_t point = timelineWidget.get_playback_point()
+    + GAVL_TIME_SCALE / 25;
+  if(point < timelineWidget.get_playback_period_end())
+    {
+      show_time(point);
+      timelineWidget.set_playback_point(point);
+      
+      
+    }
+  else
+    on_stop();
+    
+  return true;
+}
+
 }   // namespace panels
 }   // namespace gui
 }   // namespace lumiera
diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp
index e154e9a26..e12a827f6 100644
--- a/src/gui/panels/timeline-panel.hpp
+++ b/src/gui/panels/timeline-panel.hpp
@@ -49,6 +49,10 @@ public:
 
 private:
   //----- Event Handlers -----//
+  
+  void on_play_pause();
+  void on_stop();
+  
   void on_arrow_tool();
   void on_ibeam_tool();
   
@@ -58,11 +62,16 @@ private:
   void on_time_pressed();
   
   void on_mouse_hover(gavl_time_t time);
+  void on_playback_period_drag_released();
   
 private:
+  void update_playback_buttons();
   void update_tool_buttons();
   void update_zoom_buttons();
   
+  void play();
+  bool is_playing() const;
+  
   void show_time(gavl_time_t time);
 
 private:
@@ -82,6 +91,7 @@ private:
   Gtk::ToolButton previousButton;
   Gtk::ToolButton rewindButton;
   Gtk::ToolButton playPauseButton;
+  Gtk::ToolButton stopButton;
   Gtk::ToolButton forwardButton;
   Gtk::ToolButton nextButton;
     
@@ -98,7 +108,13 @@ private:
   // Internals
   bool updatingToolbar;
   
+private:
+  // TEST CODE
+  bool on_frame();
+  sigc::connection frameEvent;
+  
   //----- Constants -----//
+private:
   static const int ZoomToolSteps;
 };
 
diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp
index c7463768b..2bf6285f9 100644
--- a/src/gui/widgets/timeline-widget.cpp
+++ b/src/gui/widgets/timeline-widget.cpp
@@ -48,6 +48,7 @@ TimelineWidget::TimelineWidget() :
   selectionEnd(0),
   playbackPeriodStart(0),
   playbackPeriodEnd(0),
+  playbackPoint(GAVL_TIME_UNDEFINED),
   horizontalScroll(horizontalAdjustment),
   verticalScroll(verticalAdjustment)
 {
@@ -248,6 +249,20 @@ TimelineWidget::set_playback_period(gavl_time_t start, gavl_time_t end)
   body->queue_draw();
 }
 
+void
+TimelineWidget::set_playback_point(gavl_time_t point)
+{
+  playbackPoint = point;
+  ruler->queue_draw();
+  body->queue_draw();
+}
+
+gavl_time_t
+TimelineWidget::get_playback_point() const
+{
+  return playbackPoint;
+}
+
 ToolType
 TimelineWidget::get_tool() const
 {
@@ -274,6 +289,12 @@ TimelineWidget::mouse_hover_signal() const
   return mouseHoverSignal;
 }
 
+sigc::signal
+TimelineWidget::playback_period_drag_released_signal() const
+{
+  return playbackPeriodDragReleasedSignal;
+}
+
 void
 TimelineWidget::on_scroll()
 {
@@ -372,6 +393,12 @@ TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event)
   return true;
 }
 
+void
+TimelineWidget::on_playback_period_drag_released()
+{
+  playbackPeriodDragReleasedSignal.emit();
+}
+
 }   // namespace widgets
 }   // namespace gui
 }   // namespace lumiera
diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp
index ef13ef556..4e307bd19 100644
--- a/src/gui/widgets/timeline-widget.hpp
+++ b/src/gui/widgets/timeline-widget.hpp
@@ -52,8 +52,14 @@ namespace timeline {}
 class TimelineWidget : public Gtk::Table
 {
 public:
+  /**
+   * Constructor
+   */
   TimelineWidget();
 
+  /**
+   * Destructor
+   */
   ~TimelineWidget();
   
   /* ===== Data Access ===== */
@@ -145,6 +151,20 @@ public:
    */
   void set_playback_period(gavl_time_t start, gavl_time_t end);
   
+  /**
+   * Sets the time which is currenty being played back.
+   * @param point The time index being played. This value may be
+   * GAVL_TIME_UNDEFINED, if there is no playback point.
+   */
+  void set_playback_point(gavl_time_t point);
+  
+  /**
+   * Gets the current playback point.
+   * @return The time index of the playback point. This value may be
+   * GAVL_TIME_UNDEFINED, if there is no playback point.
+   */
+  gavl_time_t get_playback_point() const;
+  
   /**
    * Gets the type of the tool currently active.
    */
@@ -160,6 +180,8 @@ public:
   sigc::signal view_changed_signal() const;
   
   sigc::signal mouse_hover_signal() const;
+  
+  sigc::signal playback_period_drag_released_signal() const;
     
   /* ===== Events ===== */
 protected:
@@ -183,6 +205,8 @@ private:
   int get_y_scroll_offset() const;
   
   bool on_motion_in_body_notify_event(GdkEventMotion *event);
+  
+  void on_playback_period_drag_released();
 
 protected:
 
@@ -195,6 +219,7 @@ protected:
   gavl_time_t selectionEnd;
   gavl_time_t playbackPeriodStart;
   gavl_time_t playbackPeriodEnd;
+  gavl_time_t playbackPoint;
 
   int totalHeight;
 
@@ -202,6 +227,7 @@ protected:
   timeline::Track video2;
   std::vector tracks;
 
+  // Child Widgets
   timeline::HeaderContainer *headerContainer;
   timeline::TimelineBody *body;
   timeline::TimelineRuler *ruler;
@@ -213,6 +239,8 @@ protected:
   // Signals
   sigc::signal viewChangedSignal;
   sigc::signal mouseHoverSignal;
+  sigc::signal
+    playbackPeriodDragReleasedSignal;
    
   /* ===== Constants ===== */
 public:
diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp
index a3602572a..0d620ef07 100644
--- a/src/gui/widgets/timeline/timeline-body.cpp
+++ b/src/gui/widgets/timeline/timeline-body.cpp
@@ -132,8 +132,6 @@ TimelineBody::on_realize()
 bool
 TimelineBody::on_expose_event(GdkEventExpose* event)
 {
-  Cairo::Matrix view_matrix;
-  
   REQUIRE(event != NULL);
   REQUIRE(timelineWidget != NULL);
   
@@ -146,78 +144,18 @@ TimelineBody::on_expose_event(GdkEventExpose* event)
   read_styles();
   
   // Prepare to render via cairo
-  Glib::RefPtr