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