Basic zoom.
authorCarl Hetherington <cth@carlh.net>
Mon, 2 Jul 2018 14:57:55 +0000 (15:57 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 2 Jul 2018 14:57:55 +0000 (15:57 +0100)
35 files changed:
graphics/linux/128/dcpomatic2.png
graphics/linux/16/dcpomatic2.png
graphics/linux/22/dcpomatic2.png
graphics/linux/256/dcpomatic2.png
graphics/linux/32/dcpomatic2.png
graphics/linux/48/dcpomatic2.png
graphics/linux/512/dcpomatic2.png
graphics/linux/64/dcpomatic2.png
graphics/osx/dcpomatic2.iconset/icon_128x128.png
graphics/osx/dcpomatic2.iconset/icon_128x128@2x.png
graphics/osx/dcpomatic2.iconset/icon_16x16.png
graphics/osx/dcpomatic2.iconset/icon_16x16@2x.png
graphics/osx/dcpomatic2.iconset/icon_256x256.png
graphics/osx/dcpomatic2.iconset/icon_256x256@2x.png
graphics/osx/dcpomatic2.iconset/icon_32x32.png
graphics/osx/dcpomatic2.iconset/icon_32x32@2x.png
graphics/osx/dcpomatic2.iconset/icon_512x512.png
graphics/osx/dcpomatic2.iconset/icon_512x512@2x.png
graphics/select.png [new file with mode: 0644]
graphics/splash.png
graphics/src/select.svg [new file with mode: 0644]
graphics/src/zoom.svg [new file with mode: 0644]
graphics/update
graphics/web/favicon-128x128.png
graphics/web/favicon-16x16.png
graphics/web/favicon-256x256.png
graphics/web/favicon-32x32.png
graphics/web/favicon-64x64.png
graphics/web/logo.png
graphics/wscript
graphics/zoom.png [new file with mode: 0644]
src/wx/timeline.cc
src/wx/timeline.h
src/wx/timeline_dialog.cc
src/wx/timeline_dialog.h

index 002c8a43aa5aa763c00ed3f783ff6a0d67c01712..928669ef528e658cbfe7e15537990576b310ba05 100644 (file)
Binary files a/graphics/linux/128/dcpomatic2.png and b/graphics/linux/128/dcpomatic2.png differ
index eb295c31db171b9b0ecf310daff50f1f35fe0384..433c6c567138b8463dd719e7dcda75b76c01bdee 100644 (file)
Binary files a/graphics/linux/16/dcpomatic2.png and b/graphics/linux/16/dcpomatic2.png differ
index 7564c87a2dc524ecd913e97b65cff81c3f459120..b572be179b77ddaf002b4c760f6fdd18f164f938 100644 (file)
Binary files a/graphics/linux/22/dcpomatic2.png and b/graphics/linux/22/dcpomatic2.png differ
index 0cb634e1eba53381768e00df7ab24d61f6331e43..82cbe2d5fc4ac0cb48317830c046fecc36ce92a6 100644 (file)
Binary files a/graphics/linux/256/dcpomatic2.png and b/graphics/linux/256/dcpomatic2.png differ
index edfbbb7439e889e32c3af28463133af4f9b28c11..1b2f450be738285eb43dd16e695ef55f9f991df5 100644 (file)
Binary files a/graphics/linux/32/dcpomatic2.png and b/graphics/linux/32/dcpomatic2.png differ
index 98e8e5b6e644b229220d0a22cf8047d06c36f5ec..36d96a5e7bc4767d8ed3f8cb2d3cfbfc6bb0c4c0 100644 (file)
Binary files a/graphics/linux/48/dcpomatic2.png and b/graphics/linux/48/dcpomatic2.png differ
index 66b67d2e0216c2369453749a1e8be4676271b1fd..1c3520a3b15d30299f7866d6427a7be2397f917a 100644 (file)
Binary files a/graphics/linux/512/dcpomatic2.png and b/graphics/linux/512/dcpomatic2.png differ
index 0b10add1ee2003f630b4eaffabbfa771d4631dc6..9f21929a9d5a60d950c13b7433941494e6575bfe 100644 (file)
Binary files a/graphics/linux/64/dcpomatic2.png and b/graphics/linux/64/dcpomatic2.png differ
index 002c8a43aa5aa763c00ed3f783ff6a0d67c01712..928669ef528e658cbfe7e15537990576b310ba05 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_128x128.png and b/graphics/osx/dcpomatic2.iconset/icon_128x128.png differ
index 002c8a43aa5aa763c00ed3f783ff6a0d67c01712..928669ef528e658cbfe7e15537990576b310ba05 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_128x128@2x.png and b/graphics/osx/dcpomatic2.iconset/icon_128x128@2x.png differ
index eb295c31db171b9b0ecf310daff50f1f35fe0384..433c6c567138b8463dd719e7dcda75b76c01bdee 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_16x16.png and b/graphics/osx/dcpomatic2.iconset/icon_16x16.png differ
index eb295c31db171b9b0ecf310daff50f1f35fe0384..433c6c567138b8463dd719e7dcda75b76c01bdee 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_16x16@2x.png and b/graphics/osx/dcpomatic2.iconset/icon_16x16@2x.png differ
index 0cb634e1eba53381768e00df7ab24d61f6331e43..82cbe2d5fc4ac0cb48317830c046fecc36ce92a6 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_256x256.png and b/graphics/osx/dcpomatic2.iconset/icon_256x256.png differ
index 0cb634e1eba53381768e00df7ab24d61f6331e43..82cbe2d5fc4ac0cb48317830c046fecc36ce92a6 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_256x256@2x.png and b/graphics/osx/dcpomatic2.iconset/icon_256x256@2x.png differ
index edfbbb7439e889e32c3af28463133af4f9b28c11..1b2f450be738285eb43dd16e695ef55f9f991df5 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_32x32.png and b/graphics/osx/dcpomatic2.iconset/icon_32x32.png differ
index edfbbb7439e889e32c3af28463133af4f9b28c11..1b2f450be738285eb43dd16e695ef55f9f991df5 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_32x32@2x.png and b/graphics/osx/dcpomatic2.iconset/icon_32x32@2x.png differ
index 66b67d2e0216c2369453749a1e8be4676271b1fd..1c3520a3b15d30299f7866d6427a7be2397f917a 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_512x512.png and b/graphics/osx/dcpomatic2.iconset/icon_512x512.png differ
index 66b67d2e0216c2369453749a1e8be4676271b1fd..1c3520a3b15d30299f7866d6427a7be2397f917a 100644 (file)
Binary files a/graphics/osx/dcpomatic2.iconset/icon_512x512@2x.png and b/graphics/osx/dcpomatic2.iconset/icon_512x512@2x.png differ
diff --git a/graphics/select.png b/graphics/select.png
new file mode 100644 (file)
index 0000000..82f5dd3
Binary files /dev/null and b/graphics/select.png differ
index f14760948737e30a5615bfe44d7dbc1af0943afe..29b69a45c44b24bd6fb14510ba2b7c52bfa3e027 100644 (file)
Binary files a/graphics/splash.png and b/graphics/splash.png differ
diff --git a/graphics/src/select.svg b/graphics/src/select.svg
new file mode 100644 (file)
index 0000000..0ebba99
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="35mm"
+   height="35mm"
+   viewBox="0 0 35.000001 35"
+   version="1.1"
+   id="svg8"
+   inkscape:version="0.92.3 (2405546, 2018-03-11)"
+   sodipodi:docname="select.svg">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8284271"
+     inkscape:cx="4.8524935"
+     inkscape:cy="34.228523"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1680"
+     inkscape:window-height="995"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:snap-global="false" />
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-6.3144683,15.262769)">
+    <path
+       style="opacity:1;vector-effect:none;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1.10000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-end:none"
+       d="M 21.604698,2.5582203 37.559549,18.494139 c 0.739437,0.413423 1.494454,0.785898 2.673133,0.04548 0.773585,-1.191683 0.420947,-1.927565 0,-2.635791 L 24.205701,-0.15491415 c -6.5e-5,-0.0684839 -1.360739,1.61587825 -2.601003,2.71313445 z"
+       id="path5828"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccccc" />
+    <path
+       style="opacity:1;vector-effect:none;fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-width:1.10000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-end:none"
+       d="M 36.6434,-0.90186321 C 26.383577,2.6511488 23.447169,6.069677 19.999778,17.261513 19.762588,18.031545 11.947724,-3.2916786 7.9848587,-13.668122 Z"
+       id="path5884"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cscc" />
+  </g>
+</svg>
diff --git a/graphics/src/zoom.svg b/graphics/src/zoom.svg
new file mode 100644 (file)
index 0000000..26e4c36
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="35mm"
+   height="35mm"
+   viewBox="0 0 35.000001 35"
+   version="1.1"
+   id="svg8"
+   inkscape:version="0.92.3 (2405546, 2018-03-11)"
+   sodipodi:docname="zoom.svg">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8284272"
+     inkscape:cx="-24.841773"
+     inkscape:cy="49.172909"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1680"
+     inkscape:window-height="995"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-6.3144683,15.262769)">
+    <path
+       style="opacity:1;vector-effect:none;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1.10000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-end:none"
+       d="M 21.219999,2.4159489 37.174851,18.351868 c 0.739437,0.413423 1.494454,0.785898 2.673133,0.04548 0.773585,-1.191683 0.420947,-1.927565 0,-2.635791 L 23.821002,-0.29718512 c -6.5e-5,-0.06848 -1.360739,1.61587802 -2.601003,2.71313402 z"
+       id="path5828-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccccc" />
+    <ellipse
+       style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-end:none"
+       id="path5809"
+       cx="20.144106"
+       cy="-1.0881108"
+       rx="12.398235"
+       ry="12.398153" />
+  </g>
+</svg>
index e33e9a8b540bd87bb81cde2c95ecc4f2c2f677b2..9c14f2157f62bb3f31965ef3c2efc2c263efb956 100755 (executable)
@@ -65,6 +65,10 @@ else
     # Splash screen (all platforms)
     $INKSCAPE splash.png src/splash.svg -w 400 -h 300
 
+    # Timeline toolbar icons (all platforms)
+    $INKSCAPE select.png src/select.svg -w 24 -h 24
+    $INKSCAPE zoom.png src/zoom.svg -w 24 -h 24
+
     # favicon
     mkdir -p web
     convert src/web.png -resize 256x256 -transparent white web/favicon-256x256.png
index 073162d09cd6738235d8010be5f8e5ff06718150..bc58be5941951f8110c57238c136fee765a36547 100644 (file)
Binary files a/graphics/web/favicon-128x128.png and b/graphics/web/favicon-128x128.png differ
index e17129704db96ea9b126d7754e176574ea8fa54a..44dbdb713554682703c2a1d2e93db095bd15655c 100644 (file)
Binary files a/graphics/web/favicon-16x16.png and b/graphics/web/favicon-16x16.png differ
index 7a26e4a988398f05a7e70521521138fecf66fb1b..9a2e8bd03f3895f771ab8f891c5c2a464a611d12 100644 (file)
Binary files a/graphics/web/favicon-256x256.png and b/graphics/web/favicon-256x256.png differ
index 56f7415c8f8d60c2ad2b17e5222b3a4930fb9dca..c65be6ff81688fc394fb804a7af8fde187f52b4e 100644 (file)
Binary files a/graphics/web/favicon-32x32.png and b/graphics/web/favicon-32x32.png differ
index 680867f7b1d2daf458862accad7e0a1bab2c9d70..7537c82203f2074d58ca8e26e889e076112dd9d3 100644 (file)
Binary files a/graphics/web/favicon-64x64.png and b/graphics/web/favicon-64x64.png differ
index 97b8fdcd88bbdfa8f2ef9428e486f3170a2fcb79..2170aff8b24e46a759c92e82df3e0edc8c900988 100644 (file)
Binary files a/graphics/web/logo.png and b/graphics/web/logo.png differ
index 23c3d56ea7827c1c624d7ce0cae605cb672f44f9..1be119783bfa092a26d5b9a289d995c721b87af1 100644 (file)
@@ -30,3 +30,5 @@ def build(bld):
     if not bld.env.TARGET_WINDOWS:
         bld.install_as('${PREFIX}/share/dcpomatic2/dcpomatic2_server_small.png', 'linux/16/dcpomatic2.png')
         bld.install_files('${PREFIX}/share/dcpomatic2', 'splash.png')
+        bld.install_files('${PREFIX}/share/dcpomatic2', 'zoom.png')
+        bld.install_files('${PREFIX}/share/dcpomatic2', 'select.png')
diff --git a/graphics/zoom.png b/graphics/zoom.png
new file mode 100644 (file)
index 0000000..d7dbd6b
Binary files /dev/null and b/graphics/zoom.png differ
index 04db5c628d4e6f148dbb6ab706ed21b857d35400..42fb9187f52f66127ba97ba0826b782fda11b514 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -45,6 +45,7 @@
 
 using std::list;
 using std::cout;
+using std::min;
 using std::max;
 using boost::shared_ptr;
 using boost::weak_ptr;
@@ -53,7 +54,7 @@ using boost::bind;
 using boost::optional;
 
 Timeline::Timeline (wxWindow* parent, ContentPanel* cp, shared_ptr<Film> film)
-       : wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
+       : wxScrolledCanvas (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
        , _content_panel (cp)
        , _film (film)
        , _time_axis_view (new TimelineTimeAxisView (*this, 64))
@@ -65,6 +66,9 @@ Timeline::Timeline (wxWindow* parent, ContentPanel* cp, shared_ptr<Film> film)
        , _first_move (false)
        , _menu (this)
        , _snap (true)
+       , _tool (SELECT)
+       , _x_scroll_rate (16)
+       , _y_scroll_rate (16)
 {
 #ifndef __WXOSX__
        SetDoubleBuffered (true);
@@ -79,31 +83,41 @@ Timeline::Timeline (wxWindow* parent, ContentPanel* cp, shared_ptr<Film> film)
 
        film_changed (Film::CONTENT);
 
-       SetMinSize (wxSize (640, tracks() * track_height() + 96));
+       SetMinSize (wxSize (640, 4 * track_height() + 96));
 
        _tracks_position = Position<int> (_labels_view->bbox().width, 32);
 
        _film_changed_connection = film->Changed.connect (bind (&Timeline::film_changed, this, _1));
        _film_content_changed_connection = film->ContentChanged.connect (bind (&Timeline::film_content_changed, this, _2, _3));
+
+       _pixels_per_second = max (0.01, static_cast<double>(640 - tracks_position().x * 2) / film->length().seconds ());
+
+       setup_scrollbars ();
+       EnableScrolling (true, true);
 }
 
 void
 Timeline::paint ()
 {
        wxPaintDC dc (this);
+       DoPrepareDC (dc);
 
        wxGraphicsContext* gc = wxGraphicsContext::Create (dc);
        if (!gc) {
                return;
        }
 
+       int vsx, vsy;
+       GetViewStart (&vsx, &vsy);
+       gc->Translate (-vsx * _x_scroll_rate, -vsy * _y_scroll_rate);
+
        gc->SetAntialiasMode (wxANTIALIAS_DEFAULT);
 
        BOOST_FOREACH (shared_ptr<TimelineView> i, _views) {
 
                shared_ptr<TimelineContentView> ic = dynamic_pointer_cast<TimelineContentView> (i);
 
-               /* Find areas of overlap */
+               /* Find areas of overlap with other content views, so that we can plot them */
                list<dcpomatic::Rect<int> > overlaps;
                BOOST_FOREACH (shared_ptr<TimelineView> j, _views) {
                        shared_ptr<TimelineContentView> jc = dynamic_pointer_cast<TimelineContentView> (j);
@@ -121,6 +135,19 @@ Timeline::paint ()
                i->paint (gc, overlaps);
        }
 
+       if (_zoom_point) {
+               /* Translate back as _down_point and _zoom_point do not take scroll into account */
+               gc->Translate (vsx * _x_scroll_rate, vsy * _y_scroll_rate);
+               gc->SetPen (*wxBLACK_PEN);
+               gc->SetBrush (*wxTRANSPARENT_BRUSH);
+               gc->DrawRectangle (
+                       min (_down_point.x, _zoom_point->x),
+                       min (_down_point.y, _zoom_point->y),
+                       fabs (_down_point.x - _zoom_point->x),
+                       fabs (_down_point.y - _zoom_point->y)
+                       );
+       }
+
        delete gc;
 }
 
@@ -167,7 +194,7 @@ Timeline::recreate_views ()
        }
 
        assign_tracks ();
-       setup_pixels_per_second ();
+       setup_scrollbars ();
        Refresh ();
 }
 
@@ -179,7 +206,7 @@ Timeline::film_content_changed (int property, bool frequent)
        if (property == AudioContentProperty::STREAMS) {
                recreate_views ();
        } else if (!frequent) {
-               setup_pixels_per_second ();
+               setup_scrollbars ();
                Refresh ();
        }
 }
@@ -322,14 +349,14 @@ Timeline::tracks () const
 }
 
 void
-Timeline::setup_pixels_per_second ()
+Timeline::setup_scrollbars ()
 {
        shared_ptr<const Film> film = _film.lock ();
-       if (!film || film->length() == DCPTime ()) {
+       if (!film || !_pixels_per_second) {
                return;
        }
-
-       _pixels_per_second = static_cast<double>(width() - tracks_position().x * 2) / film->length().seconds ();
+       SetVirtualSize (*_pixels_per_second * film->length().seconds(), tracks() * track_height() + 96);
+       SetScrollRate (_x_scroll_rate, _y_scroll_rate);
 }
 
 shared_ptr<TimelineView>
@@ -352,6 +379,22 @@ Timeline::event_to_view (wxMouseEvent& ev)
 
 void
 Timeline::left_down (wxMouseEvent& ev)
+{
+       _left_down = true;
+       _down_point = ev.GetPosition ();
+
+       switch (_tool) {
+       case SELECT:
+               left_down_select (ev);
+               break;
+       case ZOOM:
+               /* Nothing to do */
+               break;
+       }
+}
+
+void
+Timeline::left_down_select (wxMouseEvent& ev)
 {
        shared_ptr<TimelineView> view = event_to_view (ev);
        shared_ptr<TimelineContentView> content_view = dynamic_pointer_cast<TimelineContentView> (view);
@@ -378,8 +421,6 @@ Timeline::left_down (wxMouseEvent& ev)
                content_view->set_selected (!content_view->selected ());
        }
 
-       _left_down = true;
-       _down_point = ev.GetPosition ();
        _first_move = false;
 
        if (_down_view) {
@@ -410,6 +451,19 @@ Timeline::left_up (wxMouseEvent& ev)
 {
        _left_down = false;
 
+       switch (_tool) {
+       case SELECT:
+               left_up_select (ev);
+               break;
+       case ZOOM:
+               left_up_zoom (ev);
+               break;
+       }
+}
+
+void
+Timeline::left_up_select (wxMouseEvent& ev)
+{
        if (_down_view) {
                _down_view->content()->set_change_signals_frequent (false);
        }
@@ -419,15 +473,51 @@ Timeline::left_up (wxMouseEvent& ev)
 
        /* Clear up up the stuff we don't do during drag */
        assign_tracks ();
-       setup_pixels_per_second ();
+       setup_scrollbars ();
        Refresh ();
 
        _start_snaps.clear ();
        _end_snaps.clear ();
 }
 
+void
+Timeline::left_up_zoom (wxMouseEvent& ev)
+{
+       _zoom_point = ev.GetPosition ();
+
+       int vsx, vsy;
+       GetViewStart (&vsx, &vsy);
+
+       wxPoint top_left(min(_down_point.x, _zoom_point->x), min(_down_point.y, _zoom_point->y));
+       wxPoint bottom_right(max(_down_point.x, _zoom_point->x), max(_down_point.y, _zoom_point->y));
+
+       DCPTime time_left = DCPTime::from_seconds((top_left.x + vsx - _tracks_position.x) / *_pixels_per_second);
+       DCPTime time_right = DCPTime::from_seconds((bottom_right.x + vsx - _tracks_position.x) / *_pixels_per_second);
+       _pixels_per_second = GetSize().GetWidth() / (time_right.seconds() - time_left.seconds());
+       cout << "Zoom range " << to_string(time_left) << " " << to_string(time_right) << " " << *_pixels_per_second << "\n";
+       setup_scrollbars ();
+       Scroll (time_left.seconds() * *_pixels_per_second / _x_scroll_rate, wxDefaultCoord);
+       cout << "Offset " << (time_left.seconds() * *_pixels_per_second / _x_scroll_rate) << "\n";
+
+       _zoom_point = optional<wxPoint> ();
+       Refresh ();
+}
+
 void
 Timeline::mouse_moved (wxMouseEvent& ev)
+{
+       switch (_tool) {
+       case SELECT:
+               mouse_moved_select (ev);
+               break;
+       case ZOOM:
+               mouse_moved_zoom (ev);
+               break;
+       }
+}
+
+void
+Timeline::mouse_moved_select (wxMouseEvent& ev)
 {
        if (!_left_down) {
                return;
@@ -436,8 +526,34 @@ Timeline::mouse_moved (wxMouseEvent& ev)
        set_position_from_event (ev);
 }
 
+void
+Timeline::mouse_moved_zoom (wxMouseEvent& ev)
+{
+       if (!_left_down) {
+               return;
+       }
+
+       _zoom_point = ev.GetPosition ();
+       Refresh ();
+}
+
 void
 Timeline::right_down (wxMouseEvent& ev)
+{
+       switch (_tool) {
+       case SELECT:
+               right_down_select (ev);
+               break;
+       case ZOOM:
+               /* Zoom out */
+               _pixels_per_second = *_pixels_per_second / 2;
+               setup_scrollbars ();
+               break;
+       }
+}
+
+void
+Timeline::right_down_select (wxMouseEvent& ev)
 {
        shared_ptr<TimelineView> view = event_to_view (ev);
        shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (view);
@@ -542,7 +658,7 @@ Timeline::film () const
 void
 Timeline::resized ()
 {
-       setup_pixels_per_second ();
+       setup_scrollbars ();
 }
 
 void
index c8424541eb8eb226a7cd0b6e707107df901cbf4c..375a837a808ed1a7c586aed9efb5ae6590c6ab7b 100644 (file)
@@ -35,7 +35,7 @@ class TimelineTimeAxisView;
 class TimelineReelsView;
 class TimelineLabelsView;
 
-class Timeline : public wxPanel
+class Timeline : public wxScrolledCanvas
 {
 public:
        Timeline (wxWindow *, ContentPanel *, boost::shared_ptr<Film>);
@@ -45,7 +45,7 @@ public:
        void force_redraw (dcpomatic::Rect<int> const &);
 
        int width () const {
-               return GetSize().GetWidth ();
+               return GetVirtualSize().GetWidth ();
        }
 
        int track_height () const {
@@ -62,8 +62,6 @@ public:
 
        int tracks () const;
 
-       void setup_pixels_per_second ();
-
        void set_snap (bool s) {
                _snap = s;
        }
@@ -74,12 +72,27 @@ public:
 
        void set_selection (ContentList selection);
 
+       enum Tool {
+               SELECT,
+               ZOOM
+       };
+
+       void set_tool (Tool t) {
+               _tool = t;
+       }
+
 private:
        void paint ();
        void left_down (wxMouseEvent &);
+       void left_down_select (wxMouseEvent &);
        void left_up (wxMouseEvent &);
+       void left_up_select (wxMouseEvent &);
+       void left_up_zoom (wxMouseEvent &);
        void right_down (wxMouseEvent &);
+       void right_down_select (wxMouseEvent &);
        void mouse_moved (wxMouseEvent &);
+       void mouse_moved_select (wxMouseEvent &);
+       void mouse_moved_zoom (wxMouseEvent &);
        void film_changed (Film::Property);
        void film_content_changed (int, bool frequent);
        void resized ();
@@ -87,6 +100,7 @@ private:
        void set_position_from_event (wxMouseEvent &);
        void clear_selection ();
        void recreate_views ();
+       void setup_scrollbars ();
 
        boost::shared_ptr<TimelineView> event_to_view (wxMouseEvent &);
        TimelineContentViewList selected_views () const;
@@ -103,6 +117,7 @@ private:
        boost::optional<double> _pixels_per_second;
        bool _left_down;
        wxPoint _down_point;
+       boost::optional<wxPoint> _zoom_point;
        boost::shared_ptr<TimelineContentView> _down_view;
        DCPTime _down_view_position;
        bool _first_move;
@@ -111,6 +126,9 @@ private:
        std::list<DCPTime> _start_snaps;
        std::list<DCPTime> _end_snaps;
        Position<int> _tracks_position;
+       Tool _tool;
+       int _x_scroll_rate;
+       int _y_scroll_rate;
 
        boost::signals2::scoped_connection _film_changed_connection;
        boost::signals2::scoped_connection _film_content_changed_connection;
index 36ca0ff7b7213c5d4c6ef47931a3ffb4b6df40d9..dd28f9c234cfbd08af6ede7506b5d6dce6a8eef9 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 
 */
 
-#include <list>
-#include <wx/graphics.h>
-#include "lib/playlist.h"
 #include "film_editor.h"
 #include "timeline_dialog.h"
 #include "wx_util.h"
 #include "content_panel.h"
+#include "lib/playlist.h"
+#include "lib/cross.h"
+#include <wx/graphics.h>
 #include <iostream>
+#include <list>
 
 using std::list;
 using std::cout;
@@ -57,6 +58,16 @@ TimelineDialog::TimelineDialog (ContentPanel* cp, shared_ptr<Film> film)
        controls->Add (_snap);
        _sequence = new wxCheckBox (this, wxID_ANY, _("Keep video and subtitles in sequence"));
        controls->Add (_sequence, 1, wxLEFT, 12);
+       wxToolBar* toolbar = new wxToolBar (this, wxID_ANY);
+
+#ifdef DCPOMATIC_LINUX
+       wxBitmap select (wxString::Format (wxT ("%s/select.png"), std_to_wx (shared_path().string())), wxBITMAP_TYPE_PNG);
+       wxBitmap zoom (wxString::Format (wxT ("%s/zoom.png"), std_to_wx (shared_path().string())), wxBITMAP_TYPE_PNG);
+#endif
+       toolbar->AddRadioTool ((int) Timeline::SELECT, _("Select"), select);
+       toolbar->AddRadioTool ((int) Timeline::ZOOM, _("Zoom"), zoom);
+       controls->Add (toolbar);
+       toolbar->Bind (wxEVT_TOOL, bind (&TimelineDialog::tool_changed, this, _1));
 
        sizer->Add (controls, 0, wxALL, 12);
        sizer->Add (&_timeline, 1, wxEXPAND | wxALL, 12);
@@ -115,3 +126,9 @@ TimelineDialog::set_selection (ContentList selection)
 {
        _timeline.set_selection (selection);
 }
+
+void
+TimelineDialog::tool_changed (wxCommandEvent& ev)
+{
+       _timeline.set_tool ((Timeline::Tool) ev.GetId());
+}
index c970b3b41295c2194f5a04c5fb8598f2a0b21247..dc583a9f08ca35c32b73d4e6d6977dfffcd86633 100644 (file)
@@ -36,6 +36,7 @@ private:
        void snap_toggled ();
        void sequence_toggled ();
        void film_changed (Film::Property);
+       void tool_changed (wxCommandEvent& id);
 
        boost::weak_ptr<Film> _film;
        Timeline _timeline;