changes to help strp silence
[ardour.git] / gtk2_ardour / imageframe_time_axis_group.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 <algorithm>
21
22 #include <gtkmm.h>
23 #include <gtkmm2ext/gtk_ui.h>
24
25 #include "imageframe_time_axis_group.h"
26 #include "imageframe_time_axis_view.h"
27 #include "imageframe_view.h"
28 #include "imageframe_time_axis.h"
29 #include "canvas-simplerect.h"
30 #include "region_selection.h"
31 #include "public_editor.h"
32 #include "gui_thread.h"
33
34 #include "i18n.h"
35
36 using namespace ARDOUR;
37
38 PBD::Signal1<void,ImageFrameTimeAxisGroup*> ImageFrameTimeAxisGroup::CatchDeletion;
39
40 //---------------------------------------------------------------------------------------//
41 // Constructor / Desctructor
42
43 /**
44  * Constructs a new ImageFrameTimeAxisGroup.
45  *
46  * @param iftav the parent ImageFrameTimeAxis of this view helper
47  * @param group_id the unique name/id of this group
48  */
49 ImageFrameTimeAxisGroup::ImageFrameTimeAxisGroup(ImageFrameTimeAxisView& iftav, const string & group_id)
50         : _view_helper(iftav), _group_id(group_id)
51 {
52         selected_imageframe_item = 0;
53         is_selected = false;
54
55         ImageFrameView::CatchDeletion.connect (*this, ui_bind (&ImageFrameTimeAxisGroup::remove_imageframe_item, this, _1), gui_context());
56 }
57
58 /**
59  * Destructor
60  * Responsible for destroying any Items that may have been added to this group
61  *
62  */
63 ImageFrameTimeAxisGroup::~ImageFrameTimeAxisGroup()
64 {
65         // Destroy all the ImageFramViews that we have
66         for(ImageFrameViewList::iterator iter = imageframe_views.begin(); iter != imageframe_views.end(); ++iter)
67         {
68                 ImageFrameView* ifv = *iter;
69
70                 ImageFrameViewList::iterator next = iter;
71                 next++;
72
73                 imageframe_views.erase(iter);
74
75                 delete ifv;
76                 ifv = 0;
77
78                 iter = next;
79         }
80
81          CatchDeletion; /* EMIT_SIGNAL */
82 }
83
84
85 //---------------------------------------------------------------------------------------//
86 // Name/Id Accessors/Mutators
87
88 /**
89  * Set the name/Id of this group.
90  *
91  * @param new_name the new name of this group
92  * @param src the identity of the object that initiated the change
93  */
94 void
95 ImageFrameTimeAxisGroup::set_group_name(const string & new_name, void* src)
96 {
97         if(_group_id != new_name)
98         {
99                 std::string temp_name = _group_id;
100                 _group_id = new_name;
101                  NameChanged(_group_id, temp_name, src); /* EMIT_SIGNAL */
102         }
103 }
104
105 /**
106  * Returns the id of this group
107  * The group id must be unique upon a time axis
108  *
109  * @return the id of this group
110  */
111 std::string
112 ImageFrameTimeAxisGroup::get_group_name() const
113 {
114         return(_group_id);
115 }
116
117
118 //---------------------------------------------------------------------------------------//
119 // ui methods & data
120
121 /**
122  * Sets the height of the time axis view and the item upon it
123  *
124  * @param height the new height
125  */
126 int
127 ImageFrameTimeAxisGroup::set_item_heights(gdouble h)
128 {
129         /* limit the values to something sane-ish */
130         if (h < 10.0 || h > 1000.0)
131         {
132                 return(-1);
133         }
134
135         // set the heights of all the imaeg frame views within the group
136         for(ImageFrameViewList::const_iterator citer = imageframe_views.begin(); citer != imageframe_views.end(); ++citer)
137         {
138                 (*citer)->set_height(h);
139         }
140
141         return(0);
142 }
143
144 /**
145  * Sets the current samples per unit.
146  * this method tells each item upon the time axis of the change
147  *
148  * @param spu the new samples per canvas unit value
149  */
150 int
151 ImageFrameTimeAxisGroup::set_item_samples_per_units(gdouble spp)
152 {
153         if(spp < 1.0)
154         {
155                 return(-1);
156         }
157
158         for(ImageFrameViewList::const_iterator citer = imageframe_views.begin(); citer != imageframe_views.end(); ++citer)
159         {
160                 (*citer)->set_samples_per_unit(spp);
161         }
162
163         return(0);
164 }
165
166 /**
167  * Sets the color of the items contained uopn this view helper
168  *
169  * @param color the new base color
170  */
171 void
172 ImageFrameTimeAxisGroup::apply_item_color(Gdk::Color& color)
173 {
174         region_color = color;
175         for(ImageFrameViewList::const_iterator citer = imageframe_views.begin(); citer != imageframe_views.end(); citer++)
176         {
177                 (*citer)->set_color (region_color);
178         }
179 }
180
181
182
183 //---------------------------------------------------------------------------------------//
184 // child ImageFrameView methods
185
186 /**
187  * Adds an ImageFrameView to the list of items upon this time axis view helper
188  * the new ImageFrameView is returned
189  *
190  * @param item_id the unique id of the new item
191  * @param image_id the id/name of the image data we are usin
192  * @param start the position the new item should be placed upon the time line
193  * @param duration the duration the new item should be placed upon the timeline
194  * @param rgb_data the rgb data of the image
195  * @param width the original image width of the rgb_data (not the size to display)
196  * @param height the irigianl height of the rgb_data
197  * @param num_channels the number of channles within the rgb_data
198  * @param src the identity of the object that initiated the change
199  */
200 ImageFrameView*
201 ImageFrameTimeAxisGroup::add_imageframe_item(const string & frame_id, nframes_t start, nframes_t duration, unsigned char* rgb_data, uint32_t width, uint32_t height, uint32_t num_channels, void* src)
202 {
203         ImageFrameView* ifv = 0;
204
205         //check that there is not already an imageframe with that id
206         if(get_named_imageframe_item(frame_id) == 0)
207         {
208                 ifv = new ImageFrameView(frame_id,
209                         _view_helper.canvas_item()->property_parent(),
210                         &(_view_helper.trackview()),
211                         this,
212                         _view_helper.trackview().editor.get_current_zoom(),
213                         region_color,
214                         start,
215                         duration,
216                         rgb_data,
217                         width,
218                         height,
219                         num_channels);
220
221                 imageframe_views.push_front(ifv);
222                 ImageFrameAdded(ifv, src); /* EMIT_SIGNAL */
223         }
224
225         return(ifv);
226 }
227
228
229 /**
230  * Returns the named ImageFrameView or 0 if the named view does not exist on this view helper
231  *
232  * @param item_id the unique id of the item to search for
233  * @return the named ImageFrameView, or 0 if it is not held upon this view
234  */
235 ImageFrameView*
236 ImageFrameTimeAxisGroup::get_named_imageframe_item(const string & frame_id)
237 {
238         ImageFrameView* ifv =  0;
239
240         for (ImageFrameViewList::const_iterator i = imageframe_views.begin(); i != imageframe_views.end(); ++i)
241         {
242                 if (((ImageFrameView*)*i)->get_item_name() == frame_id)
243                 {
244                         ifv = ((ImageFrameView*)*i);
245                         break;
246                 }
247         }
248         return(ifv);
249 }
250
251 /**
252  * Removes the currently selected ImageFrameView
253  *
254  * @param src the identity of the object that initiated the change
255  * @todo need to remoev this, the selected item within group is no longer
256  *       used in favour of a time axis selected item
257  * @see add_imageframe_view
258  */
259 void
260 ImageFrameTimeAxisGroup::remove_selected_imageframe_item(void* src)
261 {
262         std::string frame_id;
263
264         if(selected_imageframe_item)
265         {
266                 ImageFrameViewList::iterator i;
267
268                 if((i = find(imageframe_views.begin(), imageframe_views.end(), selected_imageframe_item)) != imageframe_views.end())
269                 {
270                         imageframe_views.erase(i);
271                         frame_id = selected_imageframe_item->get_item_name();
272
273                         // note that we delete the item here
274                         delete(selected_imageframe_item);
275                         selected_imageframe_item = 0;
276
277                         std::string track_id = _view_helper.trackview().name();
278                          ImageFrameRemoved(track_id, _group_id, frame_id, src); /* EMIT_SIGNAL */
279                 }
280         }
281         else
282         {
283                 //cerr << "No Selected ImageFrame" << endl;
284         }
285 }
286
287
288 /**
289  * Removes and returns the named ImageFrameView from the list of ImageFrameViews held by this view helper
290  *
291  * @param item_id the ImageFrameView unique id to remove
292  * @param src the identity of the object that initiated the change
293  * @see add_imageframe_view
294  */
295 ImageFrameView*
296 ImageFrameTimeAxisGroup::remove_named_imageframe_item(const string & frame_id, void* src)
297 {
298         ImageFrameView* removed = 0;
299
300         for(ImageFrameViewList::iterator iter = imageframe_views.begin(); iter != imageframe_views.end(); ++iter)
301         {
302                 ImageFrameView* tempItem = *iter;
303                 if(tempItem->get_item_name() == frame_id)
304                 {
305                         removed = tempItem;
306                         imageframe_views.erase(iter);
307
308                         if (removed == selected_imageframe_item)
309                         {
310                                 selected_imageframe_item = 0;
311                         }
312
313                         std::string track_id = _view_helper.trackview().name();
314                          ImageFrameRemoved(track_id, _group_id, frame_id, src); /* EMIT_SIGNAL */
315
316                         // break from the for loop
317                         break;
318                 }
319                 iter++;
320         }
321
322         return(removed);
323 }
324
325 /**
326  * Removes ifv from the list of ImageFrameViews upon this TimeAxis.
327  * if ifv is not upon this TimeAxis, this method takes no action
328  *
329  * @param ifv the ImageFrameView to remove
330  */
331 void
332 ImageFrameTimeAxisGroup::remove_imageframe_item (ImageFrameView* ifv)
333 {
334         ENSURE_GUI_THREAD (*this, &ImageFrameTimeAxisGroup::remove_imageframe_item, ifv, src)
335
336         ImageFrameViewList::iterator i;
337
338         if((i = find (imageframe_views.begin(), imageframe_views.end(), ifv)) != imageframe_views.end()) {
339                 imageframe_views.erase(i);
340
341                 std::string frame_id = ifv->get_item_name();
342                 std::string track_id = _view_helper.trackview().name();
343                  ImageFrameRemoved(track_id, _group_id, frame_id, src); /* EMIT_SIGNAL */
344         }
345 }
346
347 //---------------------------------------------------------------------------------------//
348 // Selected group methods
349
350 /**
351  * Sets the currently selected item upon this time axis
352  *
353  * @param ifv the item to set selected
354  */
355 //void
356 //ImageFrameTimeAxisGroup::set_selected_imageframe_item(ImageFrameView* ifv)
357 //{
358 //      if(selected_imageframe_item)
359 //      {
360 //              selected_imageframe_item->set_selected(false, this);
361 //      }
362 //
363 //      selected_imageframe_item = ifv;
364 //
365 //      if(!ifv->get_selected())
366 //      {
367 //              selected_imageframe_item->set_selected(true, this);
368 //      }
369 //}
370
371
372 /**
373  * Sets the currently selected item upon this time axis to the named item
374  *
375  * @param item_id the name/id of the item to set selected
376  */
377 //void
378 //ImageFrameTimeAxisGroup::set_selected_imageframe_item(std::string frame_id)
379 //{
380 //      selected_imageframe_item = get_named_imageframe_item(frame_id);
381 //}
382
383
384 /**
385  * Returns the currently selected item upon this time axis
386  *
387  * @return the currently selected item pon this time axis
388  */
389 // ImageFrameView*
390 // ImageFrameTimeAxisGroup::get_selected_imageframe_item()
391 // {
392         // return(selected_imageframe_item);
393 // }
394
395
396
397 /**
398  * Returns whether this grou pis currently selected
399  *
400  * @returns true if this group is currently selected
401  */
402 bool
403 ImageFrameTimeAxisGroup::get_selected() const
404 {
405         return(is_selected);
406 }
407
408
409 /**
410  * Sets he selected state of this group
411  *
412  * @param yn set true if this group is selected, false otherwise
413  */
414 void
415 ImageFrameTimeAxisGroup::set_selected(bool yn)
416 {
417         is_selected = yn;
418 }
419
420
421
422 //---------------------------------------------------------------------------------------//
423 // Handle time axis removal
424
425 /**
426  * Handles the Removal of this VisualTimeAxis
427  * This _needs_ to be called to alert others of the removal properly, ie where the source
428  * of the removal came from.
429  *
430  * XXX Although im not too happy about this method of doing things, I cant think of a cleaner method
431  *     just now to capture the source of the removal
432  *
433  * @param src the identity of the object that initiated the change
434  */
435 void
436 ImageFrameTimeAxisGroup::remove_this_group(void* src)
437 {
438         /*
439            defer to idle loop, otherwise we'll delete this object
440            while we're still inside this function ...
441         */
442         Glib::signal_idle().connect(sigc::bind(ptr_fun(&ImageFrameTimeAxisGroup::idle_remove_this_group), this, src));
443 }
444
445 /**
446  * Callback used to remove this group during the gtk idle loop
447  * This is used to avoid deleting the obejct while inside the remove_this_group
448  * method
449  *
450  * @param group the ImageFrameTimeAxisGroup to remove
451  * @param src the identity of the object that initiated the change
452  */
453 gint
454 ImageFrameTimeAxisGroup::idle_remove_this_group(ImageFrameTimeAxisGroup* group, void* src)
455 {
456         delete group;
457         group = 0;
458          group->GroupRemoved(group->get_group_name(), src); /* EMIT_SIGNAL */
459         return(false);
460 }
461