Gnome::Canvas -> ArdourCanvas and some other small fixes
[ardour.git] / gtk2_ardour / imageframe_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 #include <cmath>
23
24 #include <gtkmm.h>
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include "imageframe_time_axis.h"
28 #include "imageframe_time_axis_group.h"
29 #include "marker_time_axis.h"
30 #include "marker_time_axis_view.h"
31 #include "public_editor.h"
32 #include "utils.h"
33 #include "imageframe_view.h"
34 #include "canvas-imageframe.h"
35 #include "gui_thread.h"
36
37 using namespace sigc ;
38 using namespace ARDOUR ;
39
40 sigc::signal<void,ImageFrameView*> ImageFrameView::GoingAway;
41
42 /**
43  * Constructs a new ImageFrameView upon the canvas
44  *
45  * @param item_id unique id of this item
46  * @param parent the parent canvas item
47  * @param tv the time axis view that this item is to be placed upon
48  * @param group the ImageFrameGroup that this item is a member of
49  * @param spu the current samples per canvas unit
50  * @param start the start frame ogf this item
51  * @param duration the duration of this item
52  * @param rgb_data the rgb data of the image
53  * @param width the width of the original rgb_data image data
54  * @param height the width of the origianl rgb_data image data
55  * @param num_channels the number of color channels within rgb_data
56  */
57 ImageFrameView::ImageFrameView(std::string item_id,
58         ArdourCanvas::Group *parent,
59         ImageFrameTimeAxis* tv,
60         ImageFrameTimeAxisGroup* item_group,
61         double spu,
62        Gdk::Color& basic_color,
63         jack_nframes_t start,
64         jack_nframes_t duration,
65         unsigned char* rgb_data,
66         uint32_t width,
67         uint32_t height,
68         uint32_t num_channels)
69   : TimeAxisViewItem(item_id, *parent, *tv, spu, basic_color, start, duration,
70                      TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText|
71                                                    TimeAxisViewItem::ShowNameHighlight|
72                                                    TimeAxisViewItem::ShowFrame|
73                                                    TimeAxisViewItem::ShowHandles))
74
75 {
76         the_parent_group = item_group ;
77         set_name_text(item_id) ;
78         
79         image_data_width = width ;
80         image_data_height = height ;
81         image_data_num_channels = num_channels ;
82         
83         //This should be art_free'd once the ArtPixBuf is destroyed - this should happen when we destroy the imageframe canvas item
84         unsigned char* the_rgb_data = (unsigned char*) art_alloc(width*height*num_channels) ;
85         memcpy(the_rgb_data, rgb_data, (width*height*num_channels)) ;
86
87         ArtPixBuf* pbuf ;
88         pbuf = art_pixbuf_new_rgba(the_rgb_data, width, height, (num_channels * width));
89         imageframe = 0 ;
90         
91         //calculate our image width based on the track height
92         double im_ratio = (double)width/(double)height ;
93         int im_width = (int)((double)(trackview.height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE) * im_ratio) ;
94         
95         imageframe = gnome_canvas_item_new(GNOME_CANVAS_GROUP(group),
96                                            gnome_canvas_imageframe_get_type(),
97                                            "pixbuf", pbuf,
98                                            "x", (gdouble) 1.0,
99                                            "y", (gdouble) 1.0,
100                                            "anchor", GTK_ANCHOR_NW,
101                                            "width", (gdouble) im_width,
102                                            "height", (gdouble) (trackview.height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE),
103                                            NULL) ;
104
105         frame_handle_start->signal_event().connect() (bind (mem_fun (editor, &PublicEditor::canvas_imageframe_start_handle_event), frame_handle_start));
106         frame_handle_end->signal_event().connect() (bind (mem_fun (editor, &PublicEditor::canvas_imageframe_end_handle_event), frame_handle_end));
107         group->signal_event().connect() (bind (mem_fun (editor, &PublicEditor::canvas_imageframe_item_view_event, this);), group));
108
109         
110         frame_handle_start->raise_to_top();
111         frame_handle_end->raise_to_top();
112         
113     set_position(start, this) ;
114     set_duration(duration, this) ;
115 }
116
117 /**
118  * Destructor
119  * Reposible for removing and destroying all marker items associated with this item
120  */
121 ImageFrameView::~ImageFrameView()
122 {
123         GoingAway (this);
124
125         // destroy any marker items we have associated with this item
126                 
127         for(MarkerViewList::iterator iter = marker_view_list.begin(); iter != marker_view_list.end(); ++iter)
128         {
129                 MarkerView* mv = (*iter) ;
130                 
131                 MarkerViewList::iterator next = iter ;
132                 next++ ;
133
134                 // remove the item from our marker list
135                 // the current iterator becomes invalid after this point, so we cannot call next upon it
136                 // luckily enough, we already have next
137                 marker_view_list.erase(iter) ;
138
139                 // remove the item from the marker time axis
140                 MarkerTimeAxisView* mtav = dynamic_cast<MarkerTimeAxis*>(&mv->get_time_axis_view())->get_view() ;
141                 if(mtav)
142                 {
143                         mtav->remove_marker_view(mv, this) ;
144                 }
145
146                 mv->set_marked_item(0) ;
147                 delete mv ;
148                 mv = 0 ;
149                 
150                 // set our iterator to next, as we have invalided the current iterator with the call to erase 
151                 iter = next ;
152         }
153         
154         // if we are the currently selected item withi the parent track, we need to se-select
155         if(the_parent_group)
156         {
157                 if(the_parent_group->get_view().get_selected_imageframe_view() == this)
158                 {
159                         the_parent_group->get_view().clear_selected_imageframe_item(false) ;
160                 }
161         }
162
163         if(imageframe)
164         {
165                 gtk_object_destroy(GTK_OBJECT(imageframe)) ;
166                 imageframe = 0 ;
167         }
168 }
169
170
171 //---------------------------------------------------------------------------------------//
172 // Position and duration Accessors/Mutators
173
174 /**
175  * Set the position of this item to the specified value
176  *
177  * @param pos the new position
178  * @param src the identity of the object that initiated the change
179  * @return true if the position change was a success, false otherwise
180  */
181 bool
182 ImageFrameView::set_position(jack_nframes_t pos, void* src)
183 {
184         jack_nframes_t old_pos = frame_position ;
185         
186         // do the standard stuff
187         bool ret = TimeAxisViewItem::set_position(pos, src) ;
188
189         // everything went ok with the standard stuff?
190         if(ret)
191         {
192                 /* move each of our associated markers with this ImageFrameView */
193                 for (MarkerViewList::iterator i = marker_view_list.begin(); i != marker_view_list.end(); ++i)
194                 {
195                         // calculate the offset of the marker
196                         MarkerView* mv = (MarkerView*)*i ;
197                         jack_nframes_t marker_old_pos = mv->get_position() ;
198                         
199                         mv->set_position(pos + (marker_old_pos - old_pos), src) ;
200                 }
201         }
202         
203         return(ret) ;
204 }
205                  
206 /**
207  * Sets the duration of this item
208  *
209  * @param dur the new duration of this item
210  * @param src the identity of the object that initiated the change
211  * @return true if the duration change was succesful, false otherwise
212  */
213 bool
214 ImageFrameView::set_duration(jack_nframes_t dur, void* src)
215 {
216         /* do the standard stuff */
217         bool ret = TimeAxisViewItem::set_duration(dur, src) ;
218         
219         // eveything went ok with the standard stuff?
220         if(ret)
221         {
222                 /* handle setting the sizes of our canvas itesm based on the new duration */
223                 gnome_canvas_item_set(imageframe, "drawwidth", (gdouble) trackview.editor.frame_to_pixel(get_duration()), NULL) ;
224         }
225         
226         return(ret) ;
227 }
228
229 //---------------------------------------------------------------------------------------//
230 // Parent Component Methods
231                 
232 /**
233  * Sets the parent ImageFrameTimeAxisGroup of thie item
234  * each Item must be part of exactly one group (or 'scene') upon the timeline
235  *
236  * @param group the new parent group
237  */
238 void
239 ImageFrameView::set_time_axis_group(ImageFrameTimeAxisGroup* group)
240 {
241         the_parent_group = group ;
242 }
243                 
244 /**
245  * Returns the parent group of this item
246  *
247  * @return the parent group of this item
248  */
249 ImageFrameTimeAxisGroup*
250 ImageFrameView::get_time_axis_group()
251 {
252         return(the_parent_group) ;
253 }
254
255
256 //---------------------------------------------------------------------------------------//
257 // ui methods
258                 
259 /**
260  * Set the height of this item
261  *
262  * @param h the new height
263  */
264 void
265 ImageFrameView::set_height (gdouble h)
266 {
267         // set the image size
268         // @todo might have to re-get the image data, for a large height...hmmm.
269         double im_ratio = (double)image_data_width/(double)image_data_height ;
270         int im_width = (int)((double)(h - TimeAxisViewItem::NAME_Y_OFFSET) * im_ratio) ;
271         gnome_canvas_item_set(imageframe, "width", (gdouble)im_width, NULL) ;
272         gnome_canvas_item_set(imageframe, "height",(gdouble) (h - TimeAxisViewItem::NAME_Y_OFFSET), NULL) ;
273
274         frame->raise_to_top();
275         gnome_canvas_item_raise_to_top(imageframe) ;
276         //imageframe->raise_to_top();
277         name_highlight->raise_to_top();
278         name_text->raise_to_top();
279         frame_handle_start->raise_to_top();
280         frame_handle_end->raise_to_top();
281  
282         name_text->set_property ("y", h - TimeAxisViewItem::NAME_Y_OFFSET);
283         frame->set_property ("y2", h);
284
285         name_highlight->set_property ("y1", (gdouble) h - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE);
286         name_highlight->set_property ("y2", (gdouble) h - 1.0);
287 }
288
289
290 //---------------------------------------------------------------------------------------//
291 // MarkerView methods
292
293 /**
294  * Adds a markerView to the list of marker views associated with this item
295  *
296  * @param item the marker item to add
297  * @param src the identity of the object that initiated the change
298  */
299 void
300 ImageFrameView::add_marker_view_item(MarkerView* item, void* src)
301 {
302         marker_view_list.push_back(item) ;
303         
304         item->GoingAway.connect(bind(mem_fun(*this, &ImageFrameView::remove_marker_view_item), (void*)this));
305         
306          MarkerViewAdded(item, src) ; /* EMIT_SIGNAL */
307 }
308                 
309 /**
310  * Removes the named marker view from the list of marker view associated with this item
311  * The Marker view is not destroyed on removal, so the caller must handle the item themself
312  *
313  * @param markId the id/name of the item to remove
314  * @param src the identity of the object that initiated the change
315  * @return the removed marker item
316  */
317 MarkerView*
318 ImageFrameView::remove_named_marker_view_item(std::string markerId, void* src)
319 {
320         MarkerView* mv = 0 ;
321         MarkerViewList::iterator i = marker_view_list.begin() ;
322         
323         while(i != marker_view_list.end())
324         {
325                 if (((MarkerView*)*i)->get_item_name() == markerId)
326                 {
327                         mv = (*i) ;
328
329                         marker_view_list.erase(i) ;
330                         
331                          MarkerViewRemoved(mv,src) ; /* EMIT_SIGNAL */
332                         
333                         // iterator is now invalid, but since we should only ever have
334                         // one item with the specified name, things are ok, and we can
335                         // break from the while loop
336                         break ;
337                 }
338                 i++ ;
339         }
340         
341         return(mv) ;
342 }
343                 
344 /**
345  * Removes item from the list of marker views assocaited with this item
346  * This method will do nothing if item if not assiciated with this item
347  *
348  * @param item the item to remove
349  * @param src the identity of the object that initiated the change
350  */
351 void
352 ImageFrameView::remove_marker_view_item(MarkerView* mv, void* src)
353 {
354         ENSURE_GUI_THREAD(bind (mem_fun(*this, &ImageFrameView::remove_marker_view_item), mv, src));
355
356         MarkerViewList::iterator i ;
357         
358         if((i = find (marker_view_list.begin(), marker_view_list.end(), mv)) != marker_view_list.end()) {
359                 marker_view_list.erase(i) ;
360                  MarkerViewRemoved (mv, src) ; /* EMIT_SIGNAL */
361         }
362 }
363                 
364 /**
365  * Determines if the named marker is one of those associated with this item
366  *
367  * @param markId the id/name of the item to search for
368  */
369 bool
370 ImageFrameView::has_marker_view_item(std::string mname)
371 {
372         bool result = false ;
373         
374         for (MarkerViewList::iterator ci = marker_view_list.begin(); ci != marker_view_list.end(); ++ci)
375         {
376                 if (((MarkerView*)*ci)->get_item_name() == mname)
377                 {
378                         result = true ;
379                         
380                         // found the item, so we can break the for loop
381                         break ;
382                 }
383         }
384         
385         return(result) ;
386 }