2 Copyright (C) 2003 Paul Davis
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.
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.
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.
25 #include <gtkmm2ext/gtk_ui.h>
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 "canvas-simplerect.h"
32 #include "public_editor.h"
34 #include "imageframe_view.h"
35 #include "canvas-imageframe.h"
36 #include "gui_thread.h"
38 using namespace sigc ;
39 using namespace ARDOUR ;
41 sigc::signal<void,ImageFrameView*> ImageFrameView::GoingAway;
44 * Constructs a new ImageFrameView upon the canvas
46 * @param item_id unique id of this item
47 * @param parent the parent canvas item
48 * @param tv the time axis view that this item is to be placed upon
49 * @param group the ImageFrameGroup that this item is a member of
50 * @param spu the current samples per canvas unit
51 * @param start the start frame ogf this item
52 * @param duration the duration of this item
53 * @param rgb_data the rgb data of the image
54 * @param width the width of the original rgb_data image data
55 * @param height the width of the origianl rgb_data image data
56 * @param num_channels the number of color channels within rgb_data
58 ImageFrameView::ImageFrameView(std::string item_id,
59 GtkCanvasGroup *parent,
60 ImageFrameTimeAxis* tv,
61 ImageFrameTimeAxisGroup* item_group,
63 GdkColor& basic_color,
65 jack_nframes_t duration,
66 unsigned char* rgb_data,
69 uint32_t num_channels)
70 : TimeAxisViewItem(item_id, parent, *tv, spu, basic_color, start, duration,
71 TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText|
72 TimeAxisViewItem::ShowNameHighlight|
73 TimeAxisViewItem::ShowFrame|
74 TimeAxisViewItem::ShowHandles))
77 the_parent_group = item_group ;
78 set_name_text(item_id) ;
80 image_data_width = width ;
81 image_data_height = height ;
82 image_data_num_channels = num_channels ;
84 //This should be art_free'd once the ArtPixBuf is destroyed - this should happen when we destroy the imageframe canvas item
85 unsigned char* the_rgb_data = (unsigned char*) art_alloc(width*height*num_channels) ;
86 memcpy(the_rgb_data, rgb_data, (width*height*num_channels)) ;
89 pbuf = art_pixbuf_new_rgba(the_rgb_data, width, height, (num_channels * width));
92 //calculate our image width based on the track height
93 double im_ratio = (double)width/(double)height ;
94 int im_width = (int)((double)(trackview.height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE) * im_ratio) ;
96 imageframe = gtk_canvas_item_new(GTK_CANVAS_GROUP(group),
97 gtk_canvas_imageframe_get_type(),
101 "anchor", GTK_ANCHOR_NW,
102 "width", (gdouble) im_width,
103 "height", (gdouble) (trackview.height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE),
107 gtk_signal_connect (GTK_OBJECT(frame_handle_start), "event",
108 (GtkSignalFunc) PublicEditor::canvas_imageframe_start_handle_event,
111 gtk_signal_connect (GTK_OBJECT(frame_handle_end), "event",
112 (GtkSignalFunc) PublicEditor::canvas_imageframe_end_handle_event,
115 gtk_signal_connect (GTK_OBJECT(group), "event",
116 (GtkSignalFunc) PublicEditor::canvas_imageframe_item_view_event, this);
118 /* handle any specific details required by the initial start end duration values */
120 gtk_canvas_item_raise_to_top(frame_handle_start) ;
121 gtk_canvas_item_raise_to_top(frame_handle_end) ;
123 set_position(start, this) ;
124 set_duration(duration, this) ;
129 * Reposible for removing and destroying all marker items associated with this item
131 ImageFrameView::~ImageFrameView()
135 // destroy any marker items we have associated with this item
137 for(MarkerViewList::iterator iter = marker_view_list.begin(); iter != marker_view_list.end(); ++iter)
139 MarkerView* mv = (*iter) ;
141 MarkerViewList::iterator next = iter ;
144 // remove the item from our marker list
145 // the current iterator becomes invalid after this point, so we cannot call next upon it
146 // luckily enough, we already have next
147 marker_view_list.erase(iter) ;
149 // remove the item from the marker time axis
150 MarkerTimeAxisView* mtav = dynamic_cast<MarkerTimeAxis*>(&mv->get_time_axis_view())->get_view() ;
153 mtav->remove_marker_view(mv, this) ;
156 mv->set_marked_item(0) ;
160 // set our iterator to next, as we have invalided the current iterator with the call to erase
164 // if we are the currently selected item withi the parent track, we need to se-select
167 if(the_parent_group->get_view().get_selected_imageframe_view() == this)
169 the_parent_group->get_view().clear_selected_imageframe_item(false) ;
175 gtk_object_destroy(GTK_OBJECT(imageframe)) ;
181 //---------------------------------------------------------------------------------------//
182 // Position and duration Accessors/Mutators
185 * Set the position of this item to the specified value
187 * @param pos the new position
188 * @param src the identity of the object that initiated the change
189 * @return true if the position change was a success, false otherwise
192 ImageFrameView::set_position(jack_nframes_t pos, void* src)
194 jack_nframes_t old_pos = frame_position ;
196 // do the standard stuff
197 bool ret = TimeAxisViewItem::set_position(pos, src) ;
199 // everything went ok with the standard stuff?
202 /* move each of our associated markers with this ImageFrameView */
203 for (MarkerViewList::iterator i = marker_view_list.begin(); i != marker_view_list.end(); ++i)
205 // calculate the offset of the marker
206 MarkerView* mv = (MarkerView*)*i ;
207 jack_nframes_t marker_old_pos = mv->get_position() ;
209 mv->set_position(pos + (marker_old_pos - old_pos), src) ;
217 * Sets the duration of this item
219 * @param dur the new duration of this item
220 * @param src the identity of the object that initiated the change
221 * @return true if the duration change was succesful, false otherwise
224 ImageFrameView::set_duration(jack_nframes_t dur, void* src)
226 /* do the standard stuff */
227 bool ret = TimeAxisViewItem::set_duration(dur, src) ;
229 // eveything went ok with the standard stuff?
232 /* handle setting the sizes of our canvas itesm based on the new duration */
233 gtk_canvas_item_set(imageframe, "drawwidth", (gdouble) trackview.editor.frame_to_pixel(get_duration()), NULL) ;
239 //---------------------------------------------------------------------------------------//
240 // Parent Component Methods
243 * Sets the parent ImageFrameTimeAxisGroup of thie item
244 * each Item must be part of exactly one group (or 'scene') upon the timeline
246 * @param group the new parent group
249 ImageFrameView::set_time_axis_group(ImageFrameTimeAxisGroup* group)
251 the_parent_group = group ;
255 * Returns the parent group of this item
257 * @return the parent group of this item
259 ImageFrameTimeAxisGroup*
260 ImageFrameView::get_time_axis_group()
262 return(the_parent_group) ;
266 //---------------------------------------------------------------------------------------//
270 * Set the height of this item
272 * @param h the new height
275 ImageFrameView::set_height (gdouble h)
277 // set the image size
278 // @todo might have to re-get the image data, for a large height...hmmm.
279 double im_ratio = (double)image_data_width/(double)image_data_height ;
280 int im_width = (int)((double)(h - TimeAxisViewItem::NAME_Y_OFFSET) * im_ratio) ;
281 gtk_canvas_item_set(imageframe, "width", (gdouble)im_width, NULL) ;
282 gtk_canvas_item_set(imageframe, "height",(gdouble) (h - TimeAxisViewItem::NAME_Y_OFFSET), NULL) ;
285 gtk_canvas_item_raise_to_top(frame) ;
286 gtk_canvas_item_raise_to_top(imageframe) ;
287 gtk_canvas_item_raise_to_top(name_highlight) ;
288 gtk_canvas_item_raise_to_top(name_text) ;
289 gtk_canvas_item_raise_to_top(frame_handle_start) ;
290 gtk_canvas_item_raise_to_top(frame_handle_end) ;
292 gtk_canvas_item_set (name_text, "y", h - TimeAxisViewItem::NAME_Y_OFFSET, NULL);
293 gtk_canvas_item_set (frame, "y2", h, NULL);
295 gtk_canvas_item_set (name_highlight, "y1", (gdouble) h - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE, "y2", (gdouble) h - 1.0, NULL);
299 //---------------------------------------------------------------------------------------//
300 // MarkerView methods
303 * Adds a markerView to the list of marker views associated with this item
305 * @param item the marker item to add
306 * @param src the identity of the object that initiated the change
309 ImageFrameView::add_marker_view_item(MarkerView* item, void* src)
311 marker_view_list.push_back(item) ;
313 item->GoingAway.connect(bind(slot(*this, &ImageFrameView::remove_marker_view_item), (void*)this));
315 MarkerViewAdded(item, src) ; /* EMIT_SIGNAL */
319 * Removes the named marker view from the list of marker view associated with this item
320 * The Marker view is not destroyed on removal, so the caller must handle the item themself
322 * @param markId the id/name of the item to remove
323 * @param src the identity of the object that initiated the change
324 * @return the removed marker item
327 ImageFrameView::remove_named_marker_view_item(std::string markerId, void* src)
330 MarkerViewList::iterator i = marker_view_list.begin() ;
332 while(i != marker_view_list.end())
334 if (((MarkerView*)*i)->get_item_name() == markerId)
338 marker_view_list.erase(i) ;
340 MarkerViewRemoved(mv,src) ; /* EMIT_SIGNAL */
342 // iterator is now invalid, but since we should only ever have
343 // one item with the specified name, things are ok, and we can
344 // break from the while loop
354 * Removes item from the list of marker views assocaited with this item
355 * This method will do nothing if item if not assiciated with this item
357 * @param item the item to remove
358 * @param src the identity of the object that initiated the change
361 ImageFrameView::remove_marker_view_item(MarkerView* mv, void* src)
363 ENSURE_GUI_THREAD(bind (slot (*this, &ImageFrameView::remove_marker_view_item), mv, src));
365 MarkerViewList::iterator i ;
367 if((i = find (marker_view_list.begin(), marker_view_list.end(), mv)) != marker_view_list.end()) {
368 marker_view_list.erase(i) ;
369 MarkerViewRemoved (mv, src) ; /* EMIT_SIGNAL */
374 * Determines if the named marker is one of those associated with this item
376 * @param markId the id/name of the item to search for
379 ImageFrameView::has_marker_view_item(std::string mname)
381 bool result = false ;
383 for (MarkerViewList::iterator ci = marker_view_list.begin(); ci != marker_view_list.end(); ++ci)
385 if (((MarkerView*)*ci)->get_item_name() == mname)
389 // found the item, so we can break the for loop