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