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