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