Merged with trunk R992.
[ardour.git] / gtk2_ardour / imageframe_time_axis_view.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 <algorithm>
22
23 #include <gtkmm.h>
24
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include "imageframe_time_axis_view.h"
28 #include "imageframe_time_axis_group.h"
29 #include "imageframe_view.h"
30 #include "imageframe_time_axis.h"
31 #include "canvas-simplerect.h"
32 #include "region_selection.h"
33 #include "public_editor.h"
34 #include "rgb_macros.h"
35 #include "gui_thread.h"
36
37 #include "i18n.h"
38
39 using namespace ARDOUR ;
40 using namespace Editing;
41
42 //---------------------------------------------------------------------------------------//
43 // Constructor / Desctructor
44                 
45 /**
46  * Constructs a new ImageFrameTimeAxisView.
47  *
48  * @param ifta the parent ImageFrameTimeAxis of this view helper
49  */
50 ImageFrameTimeAxisView::ImageFrameTimeAxisView (ImageFrameTimeAxis& tv)
51         : _trackview (tv),
52           canvas_group (*_trackview.canvas_display),
53           canvas_rect (canvas_group, 0.0, 0.0, 1000000.0, tv.height)
54 {
55         region_color = _trackview.color() ;
56         stream_base_color = color_map[cImageTrackBase] ;
57
58         canvas_rect.property_outline_color_rgba() = color_map[cImageTrackOutline];
59         canvas_rect.property_fill_color_rgba() = stream_base_color;
60
61         canvas_rect.signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_imageframe_view_event), (ArdourCanvas::Item*) &canvas_rect, &tv));
62
63         _samples_per_unit = _trackview.editor.get_current_zoom() ;
64
65         _trackview.editor.ZoomChanged.connect (mem_fun(*this, &ImageFrameTimeAxisView::reset_samples_per_unit)) ;
66
67         selected_imageframe_group = 0 ;
68         selected_imageframe_view = 0 ;
69 }
70
71 /**
72  * Destructor 
73  * Responsible for destroying all items tat may have been added to this time axis
74  */
75 ImageFrameTimeAxisView::~ImageFrameTimeAxisView()
76 {
77         // Destroy all the ImageFrameGroups that we have
78         
79         for(ImageFrameGroupList::iterator iter = imageframe_groups.begin(); iter != imageframe_groups.end(); ++iter)
80         {
81                 ImageFrameTimeAxisGroup* iftag = (*iter) ;
82                 
83                 ImageFrameGroupList::iterator next = iter ;
84                 next++ ;
85
86                 // remove the front element
87                 imageframe_groups.erase(iter) ;
88
89                 delete iftag ;
90                 iftag = 0 ;
91                 
92                 iter = next ;
93         }
94         
95 }
96
97
98 //---------------------------------------------------------------------------------------//
99 // ui methods & data
100         
101 /**
102  * Sets the height of the time axis view and the item upon it
103  *
104  * @param height the new height
105  */
106 int
107 ImageFrameTimeAxisView::set_height (gdouble h)
108 {
109         /* limit the values to something sane-ish */
110         if (h < 10.0 || h > 1000.0) {
111                 return(-1) ;
112         }
113         
114         canvas_rect.property_y2() = h ;
115
116
117         for(ImageFrameGroupList::const_iterator citer = imageframe_groups.begin(); citer != imageframe_groups.end(); ++citer)
118         {
119                 (*citer)->set_item_heights(h) ;
120         }
121
122         return(0) ;
123 }
124         
125 /**
126  * Sets the position of this view helper on the canvas
127  *
128  * @param x the x position upon the canvas
129  * @param y the y position npon the canvas
130  */
131 int
132 ImageFrameTimeAxisView::set_position (gdouble x, gdouble y)
133
134 {
135         canvas_group.property_x() = x;
136         canvas_group.property_y() = y;
137
138         return 0;
139 }
140
141 /**
142  * Sets the current samples per unit.
143  * this method tells each item upon the time axis of the change
144  * 
145  * @param spu the new samples per canvas unit value
146  */
147 int 
148 ImageFrameTimeAxisView::set_samples_per_unit (gdouble spp)
149 {
150         if (spp < 1.0) {
151                 return(-1) ;
152         }
153
154         _samples_per_unit = spp;
155         
156         for(ImageFrameGroupList::const_iterator citer = imageframe_groups.begin(); citer != imageframe_groups.end(); ++citer)
157         {
158                 (*citer)->set_item_samples_per_units(spp) ;
159         }
160         
161         return(0) ;
162 }
163
164 /**
165  * Sets the color of the items contained uopn this view helper
166  *
167  * @param color the new base color
168  */
169 void
170 ImageFrameTimeAxisView::apply_color(Gdk::Color& color)
171 {
172         region_color = color ;
173         for(ImageFrameGroupList::const_iterator citer = imageframe_groups.begin(); citer != imageframe_groups.end(); citer++)
174         {
175                 (*citer)->apply_item_color(region_color) ;
176         }
177 }
178
179
180 /**
181  * convenience method to re-get the samples per unit and tell items upon this view
182  *
183  */
184 void
185 ImageFrameTimeAxisView::reset_samples_per_unit ()
186 {
187         set_samples_per_unit (_trackview.editor.get_current_zoom());
188 }
189
190
191 //---------------------------------------------------------------------------------------//
192 // Child ImageFrameTimeAxisGroup Accessors/Mutators
193                 
194 /**
195  * Adds an ImageFrameTimeAxisGroup to the list of items upon this time axis view helper
196  * the new ImageFrameTimeAxisGroup is returned
197  *
198  * @param group_id the unique id of the new group
199  * @param src the identity of the object that initiated the change
200  */
201 ImageFrameTimeAxisGroup*
202 ImageFrameTimeAxisView::add_imageframe_group(std::string group_id, void* src)
203 {
204         ImageFrameTimeAxisGroup* iftag = 0 ;
205         
206         //check that there is not already a group with that id
207         if(get_named_imageframe_group(group_id) != 0)
208         {
209                 // iftag = 0 ;
210         }
211         else
212         {
213                 iftag = new ImageFrameTimeAxisGroup(*this, group_id) ;
214
215                 imageframe_groups.push_front(iftag) ;
216         
217                 iftag->GoingAway.connect(bind(mem_fun(*this,&ImageFrameTimeAxisView::remove_imageframe_group), iftag, (void*)this)) ;
218         
219                  ImageFrameGroupAdded(iftag, src) ; /* EMIT_SIGNAL */
220         }
221
222         return(iftag) ;
223 }
224
225 /**
226  * Returns the named ImageFrameTimeAxisGroup or 0 if the named group does not exist on this view helper
227  *
228  * @param group_id the unique id of the group to search for
229  * @return the named ImageFrameTimeAxisGroup, or 0 if it is not held upon this view
230  */
231 ImageFrameTimeAxisGroup*
232 ImageFrameTimeAxisView::get_named_imageframe_group(std::string group_id)
233 {
234         ImageFrameTimeAxisGroup* iftag =  0 ;
235         
236         for(ImageFrameGroupList::iterator i = imageframe_groups.begin(); i != imageframe_groups.end(); ++i)
237         {
238                 if (((ImageFrameTimeAxisGroup*)*i)->get_group_name() == group_id)
239                 {
240                         iftag = ((ImageFrameTimeAxisGroup*)*i) ;
241                         break ;
242                 }
243         }
244         
245         return(iftag) ;
246 }
247
248
249 /**
250  * Removes and returns the named ImageFrameTimeAxisGroup from the list of ImageFrameTimeAxisGroup held by this view helper
251  *
252  * @param group_id the ImageFrameTimeAxisGroup unique id to remove
253  * @param src the identity of the object that initiated the change
254  * @see add_imageframe_group
255  */
256 ImageFrameTimeAxisGroup*
257 ImageFrameTimeAxisView::remove_named_imageframe_group(std::string group_id, void* src)
258 {
259         ImageFrameTimeAxisGroup* removed = 0 ;
260         
261         for(ImageFrameGroupList::iterator iter = imageframe_groups.begin(); iter != imageframe_groups.end(); ++iter)
262         {
263                 if(((ImageFrameTimeAxisGroup*)*iter)->get_group_name() == group_id)
264                 {
265                         removed = (*iter) ;
266                         imageframe_groups.erase(iter) ;
267                         
268                         if(removed == selected_imageframe_group)
269                         {
270                                 selected_imageframe_group = 0 ;
271                         }
272                         
273                          ImageFrameGroupRemoved(removed->get_group_name(), src) ; /* EMIT_SIGNAL */
274                         
275                         // break from the for loop
276                         break ;
277                 }
278                 iter++ ;
279         }
280         
281         return(removed) ;
282 }
283
284
285 /**
286  * Removes the specified ImageFrameTimeAxisGroup from the list of ImageFrameTimeAxisGroups upon this TimeAxis.
287  *
288  * @param iftag the ImageFrameView to remove
289  */
290 void
291 ImageFrameTimeAxisView::remove_imageframe_group(ImageFrameTimeAxisGroup* iftag, void* src)
292 {
293         ENSURE_GUI_THREAD(bind (mem_fun(*this, &ImageFrameTimeAxisView::remove_imageframe_group), iftag, src));
294
295         ImageFrameGroupList::iterator i;
296         if((i = find (imageframe_groups.begin(), imageframe_groups.end(), iftag)) != imageframe_groups.end())
297         {
298                 imageframe_groups.erase(i) ;
299                 
300                  ImageFrameGroupRemoved(iftag->get_group_name(), src) ; /* EMIT_SIGNAL */
301         }
302 }
303
304
305
306
307 //---------------------------------------------------------------------------------------//
308 // Selected group methods
309                 
310 /**
311  * Sets the currently selected group upon this time axis
312  *
313  * @param ifv the item to set selected
314  */
315 void
316 ImageFrameTimeAxisView::set_selected_imageframe_group(ImageFrameTimeAxisGroup* iftag)
317 {
318         if(selected_imageframe_group)
319         {
320                 selected_imageframe_group->set_selected(false) ;
321         }
322         
323         selected_imageframe_group = iftag ;
324         selected_imageframe_group->set_selected(true) ;
325 }
326
327 /**
328  * Clears the currently selected image frame group unpo this time axis
329  *
330 */
331 void
332 ImageFrameTimeAxisView::clear_selected_imageframe_group()
333 {
334         if(selected_imageframe_group)
335         {
336                 selected_imageframe_group->set_selected(false) ;
337         }
338         selected_imageframe_group = 0 ;
339 }
340                 
341 /**
342  * Returns the currently selected group upon this time axis
343  *
344  * @return the currently selected group upon this time axis
345  */
346 ImageFrameTimeAxisGroup*
347 ImageFrameTimeAxisView::get_selected_imageframe_group() const
348 {
349         return(selected_imageframe_group) ;
350 }
351
352 //---------------------------------------------------------------------------------------//
353 // Selected item methods
354                 
355 /**
356  * Sets the currently selected imag frame view item
357  *
358  * @param iftag the group the selected item is part
359  * @param ifv the selected item
360  */
361 void
362 ImageFrameTimeAxisView::set_selected_imageframe_view(ImageFrameTimeAxisGroup* iftag, ImageFrameView* ifv)
363 {
364         set_selected_imageframe_group(iftag) ;
365         
366         if(selected_imageframe_view)
367         {
368                 selected_imageframe_view->set_selected(false) ;
369         }
370         
371         selected_imageframe_view = ifv ;
372         selected_imageframe_view->set_selected(true) ;
373 }
374
375 /**
376  * Clears the currently selected image frame view item
377  *
378  */
379 void
380 ImageFrameTimeAxisView::clear_selected_imageframe_item(bool clear_group)
381 {
382         if(clear_group)
383         {
384                 clear_selected_imageframe_group() ;
385         }
386         
387         if(selected_imageframe_view)
388         {
389                 selected_imageframe_view->set_selected(false) ;
390         }
391         selected_imageframe_view = 0 ;
392 }
393                 
394 /**
395  * Returns the currently selected image frame view item upon this time axis
396  *
397  * @return the currently selected image frame view item
398  */
399 ImageFrameView*
400 ImageFrameTimeAxisView::get_selected_imageframe_view() const
401 {
402         return(selected_imageframe_view) ;
403 }
404
405
406
407  
408 void
409 ImageFrameTimeAxisView::set_imageframe_duration_sec(double sec)
410 {
411         if(selected_imageframe_group && selected_imageframe_view)
412         {
413                 selected_imageframe_view->set_duration((nframes_t) (sec * _trackview.editor.current_session()->frame_rate()), this) ;
414         }
415 }
416
417
418
419 /**
420  * Removes the currently selected ImageFrame view item
421  *
422  * @param src the identity of the object that initiated the change
423  * @see add_imageframe_group
424  */
425 void
426 ImageFrameTimeAxisView::remove_selected_imageframe_item(void* src)
427 {
428         if(selected_imageframe_group && selected_imageframe_view)
429         {
430                 ImageFrameView* temp_item = selected_imageframe_view ;
431                 selected_imageframe_group->remove_imageframe_item(temp_item, src) ;
432                 
433                 // XXX although we have removed the item from the group, we need the group id still set within the
434                 //     item as the remove method requires this data when telling others about the deletion
435                 //     to fully specify the item we need the track, group and item id
436                 selected_imageframe_view->remove_this_item(src) ;
437                 clear_selected_imageframe_item(false) ;
438         }
439 }
440