leftmost_position => leftmost_sample, current_page_frames => current_page_samples
[ardour.git] / gtk2_ardour / imageframe_time_axis.cc
1 /*
2     Copyright (C) 2003 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <string>
21 #include <algorithm>
22
23 #include "pbd/error.h"
24
25 #include <gtkmm/menu.h>
26
27 #include <gtkmm2ext/utils.h>
28 #include <gtkmm2ext/gtk_ui.h>
29
30 #include "ardour/session.h"
31 #include "ardour/utils.h"
32
33 #include "public_editor.h"
34 #include "imageframe_time_axis.h"
35 #include "enums.h"
36 #include "imageframe_time_axis_view.h"
37 #include "imageframe_time_axis_group.h"
38 #include "marker_time_axis_view.h"
39 #include "imageframe_view.h"
40 #include "marker_time_axis.h"
41 #include "marker_view.h"
42 #include "gui_thread.h"
43
44 #include "i18n.h"
45
46 using namespace ARDOUR;
47 using namespace PBD;
48 using namespace Gtk;
49
50 /**
51  * Constructs a new ImageFrameTimeAxis.
52  *
53  * @param track_id the track name/id
54  * @param ed the PublicEditor
55  * @param sess the current session
56  * @param canvas the parent canvas item
57  */
58 ImageFrameTimeAxis::ImageFrameTimeAxis(const string & track_id, PublicEditor& ed, ARDOUR::Session* sess, ArdourCanvas::Canvas& canvas)
59         : AxisView(sess),
60           VisualTimeAxis(track_id, ed, sess, canvas)
61 {
62         _color = unique_random_color() ;
63
64         selection_group = new ArdourCanvas::Group (*canvas_display);
65         selection_group->hide();
66
67         // intialize our data items
68         y_position = -1 ;
69
70         /* create our new image frame view */
71         view = new ImageFrameTimeAxisView(*this) ;
72
73         /* create the Image Frame Edit Menu */
74         create_imageframe_menu() ;
75
76         // set the initial time axis text label
77         label_view() ;
78
79         // set the initial height of this time axis
80         set_height(hNormal) ;
81
82         TimeAxisView::CatchDeletion.connect (*this, boost::bind (&ImageFrameTimeAxis::remove_time_axis_view, this, _1), gui_context());
83 }
84
85 /**
86  * Destructor
87  * Responsible for destroying any child image items that may have been added to thie time axis
88  */
89 ImageFrameTimeAxis::~ImageFrameTimeAxis ()
90 {
91         CatchDeletion (this);
92
93         // Destroy all the marker views we may have associaited with this TimeAxis
94         for(MarkerTimeAxisList::iterator iter = marker_time_axis_list.begin(); iter != marker_time_axis_list.end(); ++iter)
95         {
96                 MarkerTimeAxis* mta = *iter ;
97                 MarkerTimeAxisList::iterator next = iter ;
98                 next++ ;
99
100                 marker_time_axis_list.erase(iter) ;
101
102                 delete mta ;
103                 mta = 0 ;
104
105                 iter = next ;
106         }
107
108         delete image_action_menu ;
109         image_action_menu = 0 ;
110
111         delete selection_group;
112         selection_group = 0 ;
113
114         // Destroy our Axis View helper
115         delete view ;
116         view = 0 ;
117 }
118
119 //---------------------------------------------------------------------------------------//
120 // ui methods & data
121
122 /**
123  * Sets the height of this TrackView to one of ths TrackHeghts
124  *
125  * @param h
126  */
127 void
128 ImageFrameTimeAxis::set_height (uint32_t h)
129 {
130         VisualTimeAxis::set_height(h) ;
131
132         // tell out view helper of the change too
133         if(view != 0)
134         {
135                 view->set_height((double) height) ;
136         }
137
138         // tell those interested that we have had our height changed
139         gui_changed("track_height",(void*)0); /* EMIT_SIGNAL */
140 }
141
142 /**
143  * Sets the number of frames per pixel that are used.
144  * This is used to determine the siezes of items upon this time axis
145  *
146  * @param fpp the number of frames per pixel
147  */
148 void
149 ImageFrameTimeAxis::set_frames_per_pixel (double fpp)
150 {
151         TimeAxisView::set_frames_per_pixel (editor.get_current_zoom ());
152
153         if (view) {
154                 view->set_frames_per_pixel (fpp);
155         }
156 }
157
158
159 /**
160  * Returns the available height for images to be drawn onto
161  *
162  * @return the available height for an image item to be drawn onto
163  */
164 int
165 ImageFrameTimeAxis::get_image_display_height()
166 {
167         return(height - (gint)TimeAxisViewItem::NAME_HIGHLIGHT_SIZE) ;
168 }
169
170
171 /**
172  * Show the popup edit menu
173  *
174  * @param button the mouse button pressed
175  * @param time when to show the popup
176  * @param clicked_imageframe the ImageFrameItem that the event ocured upon, or 0 if none
177  * @param with_item true if an item has been selected upon the time axis, used to set context menu
178  */
179 void
180 ImageFrameTimeAxis::popup_imageframe_edit_menu(int button, int32_t time, ImageFrameView* clicked_imageframe, bool with_item)
181 {
182         if (!imageframe_menu)
183         {
184                 create_imageframe_menu() ;
185         }
186
187         if(with_item)
188         {
189                 imageframe_item_menu->set_sensitive(true) ;
190         }
191         else
192         {
193                 imageframe_item_menu->set_sensitive(false) ;
194         }
195
196         imageframe_menu->popup(button,time) ;
197 }
198
199 /**
200  * convenience method to select a new track color and apply it to the view and view items
201  *
202  */
203 void
204 ImageFrameTimeAxis::select_track_color()
205 {
206         if (choose_time_axis_color())
207         {
208                 if (view)
209                 {
210                         view->apply_color (_color) ;
211                 }
212         }
213 }
214
215 /**
216  * Handles the building of the popup menu
217  */
218 void
219 ImageFrameTimeAxis::build_display_menu()
220 {
221         using namespace Menu_Helpers;
222         using Gtk::Menu;
223
224         /* get the size menu ready */
225
226         build_size_menu();
227
228         /* prepare it */
229
230         TimeAxisView::build_display_menu () ;
231
232         /* now fill it with our stuff */
233
234         MenuList& items = display_menu->items();
235
236         items.push_back (MenuElem (_("Rename"), sigc::mem_fun(*this, &ImageFrameTimeAxis::start_time_axis_rename)));
237
238         image_action_menu = new Menu() ;
239         image_action_menu->set_name ("ArdourContextMenu");
240         MenuList image_items = image_action_menu->items() ;
241
242         items.push_back (SeparatorElem());
243         items.push_back (MenuElem (_("Height"), *size_menu));
244         items.push_back (MenuElem (_("Color"), sigc::mem_fun(*this, &ImageFrameTimeAxis::select_track_color)));
245
246         items.push_back (SeparatorElem());
247         items.push_back (MenuElem (_("Remove"), sigc::bind(sigc::mem_fun(*this, &VisualTimeAxis::remove_this_time_axis), (void*)this))) ;
248 }
249
250 /**
251  * handles the building of the ImageFrameView sub menu
252  */
253 void
254 ImageFrameTimeAxis::create_imageframe_menu()
255 {
256         using namespace Menu_Helpers;
257         using Gtk::Menu;
258
259         imageframe_menu = manage(new Menu) ;
260         imageframe_menu->set_name ("ArdourContextMenu");
261         MenuList& items = imageframe_menu->items();
262
263         imageframe_item_menu = manage(new Menu) ;
264         imageframe_item_menu->set_name ("ArdourContextMenu");
265         MenuList& imageframe_sub_items = imageframe_item_menu->items() ;
266
267         /* duration menu */
268         Menu* duration_menu = manage(new Menu) ;
269         duration_menu->set_name ("ArdourContextMenu");
270         MenuList& duration_items = duration_menu->items() ;
271
272         if(view)
273         {
274                 duration_items.push_back(MenuElem (_("0.5 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 0.5))) ;
275                 duration_items.push_back(MenuElem (_("1 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 1.0))) ;
276                 duration_items.push_back(MenuElem (_("1.5 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 1.5))) ;
277                 duration_items.push_back(MenuElem (_("2 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 2.0))) ;
278                 duration_items.push_back(MenuElem (_("2.5 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 2.5))) ;
279                 duration_items.push_back(MenuElem (_("3 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 3.0))) ;
280                 //duration_items.push_back(SeparatorElem()) ;
281                 //duration_items.push_back(MenuElem (_("custom"), sigc::mem_fun(*this, &ImageFrameTimeAxis::set_imageframe_duration_custom))) ;
282         }
283
284         imageframe_sub_items.push_back(MenuElem(_("Duration (sec)"), *duration_menu)) ;
285
286         imageframe_sub_items.push_back(SeparatorElem()) ;
287         if(view)
288         {
289                 imageframe_sub_items.push_back(MenuElem (_("Remove Frame"), sigc::bind(sigc::mem_fun (view, &ImageFrameTimeAxisView::remove_selected_imageframe_item), (void*)this))) ;
290         }
291
292         items.push_back(MenuElem(_("Image Frame"), *imageframe_item_menu)) ;
293         items.push_back(MenuElem (_("Rename Track"), sigc::mem_fun(*this,&ImageFrameTimeAxis::start_time_axis_rename))) ;
294
295         imageframe_menu->show_all() ;
296 }
297
298
299
300
301 //---------------------------------------------------------------------------------------//
302 // Marker Time Axis Methods
303
304 /**
305  * Add a MarkerTimeAxis to the ilst of MarkerTimeAxis' associated with this ImageFrameTimeAxis
306  *
307  * @param marker_track the MarkerTimeAxis to add
308  * @param src the identity of the object that initiated the change
309  * @return true if the addition was a success,
310  *         false otherwise
311  */
312 bool
313 ImageFrameTimeAxis::add_marker_time_axis(MarkerTimeAxis* marker_track, void* src)
314 {
315         bool ret = false ;
316
317         if(get_named_marker_time_axis(marker_track->name()) != 0)
318         {
319                 ret = false ;
320         }
321         else
322         {
323                 marker_time_axis_list.push_back(marker_track) ;
324                  MarkerTimeAxisAdded(marker_track, src) ; /* EMIT_SIGNAL */
325                 ret = true ;
326         }
327
328         return(ret) ;
329 }
330
331 /**
332  * Returns the named MarkerTimeAxis associated with this ImageFrameTimeAxis
333  *
334  * @param track_id the track_id of the MarkerTimeAxis to search for
335  * @return the named markerTimeAxis, or 0 if the named MarkerTimeAxis is not associated with this ImageFrameTimeAxis
336  */
337 MarkerTimeAxis*
338 ImageFrameTimeAxis::get_named_marker_time_axis(const string & track_id)
339 {
340         MarkerTimeAxis* mta =  0 ;
341
342         for (MarkerTimeAxisList::iterator i = marker_time_axis_list.begin(); i != marker_time_axis_list.end(); ++i)
343         {
344                 if (((MarkerTimeAxis*)*i)->name() == track_id)
345                 {
346                         mta = ((MarkerTimeAxis*)*i) ;
347                         break ;
348                 }
349         }
350         return(mta) ;
351 }
352
353 /**
354  * Removes the named markerTimeAxis from those associated with this ImageFrameTimeAxis
355  *
356  * @param track_id the track id of the MarkerTimeAxis to remove
357  * @param src the identity of the object that initiated the change
358  * @return the removed MarkerTimeAxis
359  */
360 MarkerTimeAxis*
361 ImageFrameTimeAxis::remove_named_marker_time_axis(const string & track_id, void* src)
362 {
363         MarkerTimeAxis* mta = 0 ;
364
365         for(MarkerTimeAxisList::iterator i = marker_time_axis_list.begin(); i != marker_time_axis_list.end(); ++i)
366         {
367                 if (((MarkerTimeAxis*)*i)->name() == track_id)
368                 {
369                         mta = ((MarkerTimeAxis*)*i) ;
370
371                         // the iterator is invalid after this call, so we can no longer use it as is.
372                         marker_time_axis_list.erase(i) ;
373
374                          MarkerTimeAxisRemoved(mta->name(), src) ; /* EMIT_SIGNAL */
375                         break ;
376                 }
377         }
378
379         return(mta) ;
380 }
381
382 /**
383  * Removes the specified MarkerTimeAxis from the list of MarkerTimaAxis associated with this ImageFrameTimeAxis
384  * Note that the MarkerTimeAxis is not deleted, only removed from the list os associated tracks
385  *
386  * @param mta the TimeAxis to remove
387  * @param src the identity of the object that initiated the change
388  */
389 void
390 ImageFrameTimeAxis::remove_time_axis_view (TimeAxisView* tav)
391 {
392         MarkerTimeAxisView* mtav = dynamic_cast<MarkerTimeAxisView*> (tav);
393
394         if (!mtav) {
395                 return;
396         }
397
398         MarkerTimeAxisList::iterator i;
399
400         if ((i = find (marker_time_axis_list.begin(), marker_time_axis_list.end(), mta)) != marker_time_axis_list.end())  {
401                 // note that we dont delete the object itself, we just remove it from our list
402                 marker_time_axis_list.erase(i) ;
403                 MarkerTimeAxisRemoved (mta->name(), src) ; /* EMIT_SIGNAL */
404         }
405 }
406
407
408 //---------------------------------------------------------------------------------------//
409 // Parent/Child helper object accessors
410
411 /**
412  * Returns the view helper of this TimeAxis
413  *
414  * @return the view helper of this TimeAxis
415  */
416 ImageFrameTimeAxisView*
417 ImageFrameTimeAxis::get_view()
418 {
419         return(view) ;
420 }