Basic repeat.
authorCarl Hetherington <cth@carlh.net>
Fri, 19 Jul 2013 12:23:54 +0000 (13:23 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 19 Jul 2013 12:23:54 +0000 (13:23 +0100)
src/lib/playlist.cc
src/lib/playlist.h
src/wx/repeat_dialog.cc [new file with mode: 0644]
src/wx/repeat_dialog.h [new file with mode: 0644]
src/wx/timeline.cc
src/wx/timeline.h
src/wx/wscript

index c70c79972f0d44891393a7f1d49fce5cc0a67a69..31b16b646f9237cdbaca486d88257722f691dd02 100644 (file)
@@ -289,3 +289,18 @@ Playlist::content () const
 {
        return _content;
 }
+
+void
+Playlist::repeat (shared_ptr<Content> c, int n)
+{
+       Time pos = c->end ();
+       for (int i = 0; i < n; ++i) {
+               shared_ptr<Content> copy = c->clone ();
+               copy->set_start (pos);
+               _content.push_back (copy);
+               pos = copy->end ();
+       }
+
+       reconnect ();
+       Changed ();
+}
index 735ef7a4323b313eed06d5d982fb8db905051703..e949de0ea077b231a8acba935bdb7616fbad749f 100644 (file)
@@ -77,6 +77,8 @@ public:
        void set_sequence_video (bool);
        void maybe_sequence_video ();
 
+       void repeat (boost::shared_ptr<Content>, int);
+
        mutable boost::signals2::signal<void ()> Changed;
        /** Third parameter is true if signals are currently being emitted frequently */
        mutable boost::signals2::signal<void (boost::weak_ptr<Content>, int, bool)> ContentChanged;
diff --git a/src/wx/repeat_dialog.cc b/src/wx/repeat_dialog.cc
new file mode 100644 (file)
index 0000000..9eb02ba
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+    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.
+
+*/
+
+#include "repeat_dialog.h"
+#include "wx_util.h"
+
+RepeatDialog::RepeatDialog (wxWindow* parent)
+       : wxDialog (parent, wxID_ANY, _("Repeat Content"))
+{
+       wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
+       SetSizer (overall_sizer);
+       
+       wxFlexGridSizer* table = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+       table->AddGrowableCol (1, 1);
+       overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6);
+
+       add_label_to_sizer (table, this, _("Repeat"), true);
+       _number = new wxSpinCtrl (this, wxID_ANY);
+       table->Add (_number, 1);
+
+       add_label_to_sizer (table, this, _("times"), false);
+
+       _number->SetRange (1, 1024);
+
+       wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
+       if (buttons) {
+               overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
+       }
+
+       overall_sizer->Layout ();
+       overall_sizer->SetSizeHints (this);
+}
+
+int
+RepeatDialog::number () const
+{
+       return _number->GetValue ();
+}
diff --git a/src/wx/repeat_dialog.h b/src/wx/repeat_dialog.h
new file mode 100644 (file)
index 0000000..cbcc6bb
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+    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.
+
+*/
+
+#include <wx/wx.h>
+#include <wx/spinctrl.h>
+
+class RepeatDialog : public wxDialog
+{
+public:
+       RepeatDialog (wxWindow *);
+
+       int number () const;
+
+private:
+       wxSpinCtrl* _number;
+};
index 8d70a938132fef2c10941493be95235f3c1dbda4..e3eca8a1d4f31efab0aac1af38a89b5100ad5156 100644 (file)
@@ -25,6 +25,7 @@
 #include "film_editor.h"
 #include "timeline.h"
 #include "wx_util.h"
+#include "repeat_dialog.h"
 
 using std::list;
 using std::cout;
@@ -314,6 +315,10 @@ private:
        int _y;
 };
 
+enum {
+       ID_repeat
+};
+
 Timeline::Timeline (wxWindow* parent, FilmEditor* ed, shared_ptr<Film> film)
        : wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
        , _film_editor (ed)
@@ -324,26 +329,25 @@ Timeline::Timeline (wxWindow* parent, FilmEditor* ed, shared_ptr<Film> film)
        , _left_down (false)
        , _down_view_start (0)
        , _first_move (false)
+       , _menu (0)
 {
 #ifndef __WXOSX__
        SetDoubleBuffered (true);
 #endif 
 
-       setup_pixels_per_time_unit ();
-       
        Connect (wxID_ANY, wxEVT_PAINT, wxPaintEventHandler (Timeline::paint), 0, this);
        Connect (wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler (Timeline::left_down), 0, this);
        Connect (wxID_ANY, wxEVT_LEFT_UP, wxMouseEventHandler (Timeline::left_up), 0, this);
+       Connect (wxID_ANY, wxEVT_RIGHT_DOWN, wxMouseEventHandler (Timeline::right_down), 0, this);
        Connect (wxID_ANY, wxEVT_MOTION, wxMouseEventHandler (Timeline::mouse_moved), 0, this);
        Connect (wxID_ANY, wxEVT_SIZE, wxSizeEventHandler (Timeline::resized), 0, this);
+       Connect (ID_repeat, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Timeline::repeat), 0, this);
 
        playlist_changed ();
 
        SetMinSize (wxSize (640, tracks() * track_height() + 96));
 
        _playlist_connection = film->playlist()->Changed.connect (bind (&Timeline::playlist_changed, this));
-
-       _views.push_back (_time_axis_view);
 }
 
 void
@@ -374,6 +378,7 @@ Timeline::playlist_changed ()
        }
 
        _views.clear ();
+       _views.push_back (_time_axis_view);
 
        Playlist::ContentList content = fl->playlist()->content ();
 
@@ -387,6 +392,7 @@ Timeline::playlist_changed ()
        }
 
        assign_tracks ();
+       setup_pixels_per_time_unit ();
        Refresh ();
 }
 
@@ -463,8 +469,8 @@ Timeline::setup_pixels_per_time_unit ()
        _pixels_per_time_unit = static_cast<double>(width() - x_offset() * 2) / film->length ();
 }
 
-void
-Timeline::left_down (wxMouseEvent& ev)
+shared_ptr<View>
+Timeline::event_to_view (wxMouseEvent& ev)
 {
        list<shared_ptr<View> >::iterator i = _views.begin();
        Position<int> const p (ev.GetX(), ev.GetY());
@@ -472,21 +478,33 @@ Timeline::left_down (wxMouseEvent& ev)
                ++i;
        }
 
+       if (i == _views.end ()) {
+               return shared_ptr<View> ();
+       }
+
+       return *i;
+}
+
+void
+Timeline::left_down (wxMouseEvent& ev)
+{
+       shared_ptr<View> view = event_to_view (ev);
+
        _down_view.reset ();
 
-       if (i != _views.end ()) {
-               shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
+       if (view) {
+               shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (view);
                if (cv) {
                        _down_view = cv;
                        _down_view_start = cv->content()->start ();
                }
        }
 
-       for (list<shared_ptr<View> >::iterator j = _views.begin(); j != _views.end(); ++j) {
-               shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*j);
+       for (list<shared_ptr<View> >::iterator i = _views.begin(); i != _views.end(); ++i) {
+               shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
                if (cv) {
-                       cv->set_selected (i == j);
-                       if (i == j) {
+                       cv->set_selected (view == *i);
+                       if (view == *i) {
                                _film_editor->set_selection (cv->content ());
                        }
                }
@@ -523,6 +541,28 @@ Timeline::mouse_moved (wxMouseEvent& ev)
        set_start_from_event (ev);
 }
 
+void
+Timeline::right_down (wxMouseEvent& ev)
+{
+       shared_ptr<View> view = event_to_view (ev);
+       shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (view);
+       if (!cv) {
+               return;
+       }
+
+       if (!cv->selected ()) {
+               clear_selection ();
+               cv->set_selected (true);
+       }
+
+       if (!_menu) {
+               _menu = new wxMenu;
+               _menu->Append (ID_repeat, _("Repeat..."));
+       }
+
+       PopupMenu (_menu, ev.GetPosition ());
+}
+
 void
 Timeline::set_start_from_event (wxMouseEvent& ev)
 {
@@ -563,3 +603,48 @@ Timeline::resized (wxSizeEvent &)
 {
        setup_pixels_per_time_unit ();
 }
+
+void
+Timeline::clear_selection ()
+{
+       for (list<shared_ptr<View> >::iterator i = _views.begin(); i != _views.end(); ++i) {
+               shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
+               if (cv) {
+                       cv->set_selected (false);
+               }
+       }
+}
+
+void
+Timeline::repeat (wxCommandEvent &)
+{
+       shared_ptr<ContentView> sel = selected ();
+       if (!sel) {
+               return;
+       }
+               
+       RepeatDialog d (this);
+       d.ShowModal ();
+
+       shared_ptr<const Film> film = _film.lock ();
+       if (!film) {
+               return;
+       }
+
+       film->playlist()->repeat (sel->content (), d.number ());
+       d.Destroy ();
+}
+
+shared_ptr<ContentView>
+Timeline::selected () const
+{
+       for (list<shared_ptr<View> >::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+               shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*i);
+               if (cv && cv->selected()) {
+                       return cv;
+               }
+       }
+
+       return shared_ptr<ContentView> ();
+}
+               
index 6979d6a7804dd28e3abd4f709a2c66b254c10b1d..a50f8e6923da720fa30b1519bf444f3ab1e117b0 100644 (file)
@@ -64,13 +64,19 @@ public:
 private:
        void paint (wxPaintEvent &);
        void left_down (wxMouseEvent &);
-       void mouse_moved (wxMouseEvent &);
        void left_up (wxMouseEvent &);
+       void right_down (wxMouseEvent &);
+       void mouse_moved (wxMouseEvent &);
        void playlist_changed ();
        void setup_pixels_per_time_unit ();
        void resized (wxSizeEvent &);
        void assign_tracks ();
        void set_start_from_event (wxMouseEvent &);
+       void clear_selection ();
+       void repeat (wxCommandEvent &);
+
+       boost::shared_ptr<View> event_to_view (wxMouseEvent &);
+       boost::shared_ptr<ContentView> selected () const;
 
        FilmEditor* _film_editor;
        boost::weak_ptr<Film> _film;
@@ -83,6 +89,7 @@ private:
        boost::shared_ptr<ContentView> _down_view;
        Time _down_view_start;
        bool _first_move;
+       wxMenu* _menu;
 
        boost::signals2::scoped_connection _playlist_connection;
 };
index 9dea367c9faeaf73bd3ffe4c93f1bb51af4dbcac..3402d4b415bc6e75a835da66f7739f4c7b9a6180 100644 (file)
@@ -21,6 +21,7 @@ sources = """
           job_wrapper.cc
           new_film_dialog.cc
           properties_dialog.cc
+          repeat_dialog.cc
           server_dialog.cc
           timecode.cc
           timeline.cc