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