9e1eef2b2e7bb8a8ce13e1c889323401afbcd30d
[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
86 /**
87  * Destructor
88  * Responsible for destroying any child image items that may have been added to thie time axis
89  */
90 ImageFrameTimeAxis::~ImageFrameTimeAxis ()
91 {
92          GoingAway ; /* EMIT_SIGNAL */
93
94         // Destroy all the marker views we may have associaited with this TimeAxis
95         for(MarkerTimeAxisList::iterator iter = marker_time_axis_list.begin(); iter != marker_time_axis_list.end(); ++iter)
96         {
97                 MarkerTimeAxis* mta = *iter ;
98                 MarkerTimeAxisList::iterator next = iter ;
99                 next++ ;
100
101                 marker_time_axis_list.erase(iter) ;
102
103                 delete mta ;
104                 mta = 0 ;
105
106                 iter = next ;
107         }
108
109         delete image_action_menu ;
110         image_action_menu = 0 ;
111
112         delete selection_group;
113         selection_group = 0 ;
114
115         // Destroy our Axis View helper
116         delete view ;
117         view = 0 ;
118 }
119
120 //---------------------------------------------------------------------------------------//
121 // ui methods & data
122
123 /**
124  * Sets the height of this TrackView to one of ths TrackHeghts
125  *
126  * @param h
127  */
128 void
129 ImageFrameTimeAxis::set_height (uint32_t h)
130 {
131         VisualTimeAxis::set_height(h) ;
132
133         // tell out view helper of the change too
134         if(view != 0)
135         {
136                 view->set_height((double) height) ;
137         }
138
139         // tell those interested that we have had our height changed
140          gui_changed("track_height",(void*)0); /* EMIT_SIGNAL */
141 }
142
143 /**
144  * Sets the number of samples per unit that are used.
145  * This is used to determine the siezes of items upon this time axis
146  *
147  * @param spu the number of samples per unit
148  */
149 void
150 ImageFrameTimeAxis::set_samples_per_unit(double spu)
151 {
152         TimeAxisView::set_samples_per_unit (editor.get_current_zoom());
153
154         if(view) {
155                 view->set_samples_per_unit(spu) ;
156         }
157 }
158
159
160 /**
161  * Returns the available height for images to be drawn onto
162  *
163  * @return the available height for an image item to be drawn onto
164  */
165 int
166 ImageFrameTimeAxis::get_image_display_height()
167 {
168         return(height - (gint)TimeAxisViewItem::NAME_HIGHLIGHT_SIZE) ;
169 }
170
171
172 /**
173  * Show the popup edit menu
174  *
175  * @param button the mouse button pressed
176  * @param time when to show the popup
177  * @param clicked_imageframe the ImageFrameItem that the event ocured upon, or 0 if none
178  * @param with_item true if an item has been selected upon the time axis, used to set context menu
179  */
180 void
181 ImageFrameTimeAxis::popup_imageframe_edit_menu(int button, int32_t time, ImageFrameView* clicked_imageframe, bool with_item)
182 {
183         if (!imageframe_menu)
184         {
185                 create_imageframe_menu() ;
186         }
187
188         if(with_item)
189         {
190                 imageframe_item_menu->set_sensitive(true) ;
191         }
192         else
193         {
194                 imageframe_item_menu->set_sensitive(false) ;
195         }
196
197         imageframe_menu->popup(button,time) ;
198 }
199
200 /**
201  * convenience method to select a new track color and apply it to the view and view items
202  *
203  */
204 void
205 ImageFrameTimeAxis::select_track_color()
206 {
207         if (choose_time_axis_color())
208         {
209                 if (view)
210                 {
211                         view->apply_color (_color) ;
212                 }
213         }
214 }
215
216 /**
217  * Handles the building of the popup menu
218  */
219 void
220 ImageFrameTimeAxis::build_display_menu()
221 {
222         using namespace Menu_Helpers;
223         using Gtk::Menu;
224
225         /* get the size menu ready */
226
227         build_size_menu();
228
229         /* prepare it */
230
231         TimeAxisView::build_display_menu () ;
232
233         /* now fill it with our stuff */
234
235         MenuList& items = display_menu->items();
236
237         items.push_back (MenuElem (_("Rename"), sigc::mem_fun(*this, &ImageFrameTimeAxis::start_time_axis_rename)));
238
239         image_action_menu = new Menu() ;
240         image_action_menu->set_name ("ArdourContextMenu");
241         MenuList image_items = image_action_menu->items() ;
242
243         items.push_back (SeparatorElem());
244         items.push_back (MenuElem (_("Height"), *size_menu));
245         items.push_back (MenuElem (_("Color"), sigc::mem_fun(*this, &ImageFrameTimeAxis::select_track_color)));
246
247         items.push_back (SeparatorElem());
248         items.push_back (MenuElem (_("Remove"), sigc::bind(sigc::mem_fun(*this, &VisualTimeAxis::remove_this_time_axis), (void*)this))) ;
249 }
250
251 /**
252  * handles the building of the ImageFrameView sub menu
253  */
254 void
255 ImageFrameTimeAxis::create_imageframe_menu()
256 {
257         using namespace Menu_Helpers;
258         using Gtk::Menu;
259
260         imageframe_menu = manage(new Menu) ;
261         imageframe_menu->set_name ("ArdourContextMenu");
262         MenuList& items = imageframe_menu->items();
263
264         imageframe_item_menu = manage(new Menu) ;
265         imageframe_item_menu->set_name ("ArdourContextMenu");
266         MenuList& imageframe_sub_items = imageframe_item_menu->items() ;
267
268         /* duration menu */
269         Menu* duration_menu = manage(new Menu) ;
270         duration_menu->set_name ("ArdourContextMenu");
271         MenuList& duration_items = duration_menu->items() ;
272
273         if(view)
274         {
275                 duration_items.push_back(MenuElem (_("0.5 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 0.5))) ;
276                 duration_items.push_back(MenuElem (_("1 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 1.0))) ;
277                 duration_items.push_back(MenuElem (_("1.5 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 1.5))) ;
278                 duration_items.push_back(MenuElem (_("2 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 2.0))) ;
279                 duration_items.push_back(MenuElem (_("2.5 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 2.5))) ;
280                 duration_items.push_back(MenuElem (_("3 seconds"), sigc::bind (sigc::mem_fun (view, &ImageFrameTimeAxisView::set_imageframe_duration_sec), 3.0))) ;
281                 //duration_items.push_back(SeparatorElem()) ;
282                 //duration_items.push_back(MenuElem (_("custom"), sigc::mem_fun(*this, &ImageFrameTimeAxis::set_imageframe_duration_custom))) ;
283         }
284
285         imageframe_sub_items.push_back(MenuElem(_("Duration (sec)"), *duration_menu)) ;
286
287         imageframe_sub_items.push_back(SeparatorElem()) ;
288         if(view)
289         {
290                 imageframe_sub_items.push_back(MenuElem (_("Remove Frame"), sigc::bind(sigc::mem_fun (view, &ImageFrameTimeAxisView::remove_selected_imageframe_item), (void*)this))) ;
291         }
292
293         items.push_back(MenuElem(_("Image Frame"), *imageframe_item_menu)) ;
294         items.push_back(MenuElem (_("Rename Track"), sigc::mem_fun(*this,&ImageFrameTimeAxis::start_time_axis_rename))) ;
295
296         imageframe_menu->show_all() ;
297 }
298
299
300
301
302 //---------------------------------------------------------------------------------------//
303 // Marker Time Axis Methods
304
305 /**
306  * Add a MarkerTimeAxis to the ilst of MarkerTimeAxis' associated with this ImageFrameTimeAxis
307  *
308  * @param marker_track the MarkerTimeAxis to add
309  * @param src the identity of the object that initiated the change
310  * @return true if the addition was a success,
311  *         false otherwise
312  */
313 bool
314 ImageFrameTimeAxis::add_marker_time_axis(MarkerTimeAxis* marker_track, void* src)
315 {
316         bool ret = false ;
317
318         if(get_named_marker_time_axis(marker_track->name()) != 0)
319         {
320                 ret = false ;
321         }
322         else
323         {
324                 marker_time_axis_list.push_back(marker_track) ;
325                 scoped_connect (marker_track->GoingAway, boost::bind (&ImageFrameTimeAxis::remove_time_axis_view, this, marker_track, (void*)this));
326
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(MarkerTimeAxis* mta, void* src)
394 {
395         ENSURE_GUI_THREAD (*this, &ImageFrameTimeAxis::remove_time_axis_view, mta, src)
396
397         MarkerTimeAxisList::iterator i;
398         if((i = find (marker_time_axis_list.begin(), marker_time_axis_list.end(), mta)) != marker_time_axis_list.end())
399         {
400                 // note that we dont delete the object itself, we just remove it from our list
401                 marker_time_axis_list.erase(i) ;
402
403                  MarkerTimeAxisRemoved(mta->name(), src) ; /* EMIT_SIGNAL */
404         }
405 }
406
407
408 //---------------------------------------------------------------------------------------//
409 // Parent/Child helper object accessors
410
411 /**
412  * Returns the view helper of this TimeAxis
413  *
414  * @return the view helper of this TimeAxis
415  */
416 ImageFrameTimeAxisView*
417 ImageFrameTimeAxis::get_view()
418 {
419         return(view) ;
420 }