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.
24 #include <gtkmm2ext/gtk_ui.h>
26 #include "imageframe_time_axis.h"
27 #include "imageframe_time_axis_group.h"
28 #include "marker_time_axis.h"
29 #include "marker_time_axis_view.h"
30 #include "public_editor.h"
32 #include "imageframe_view.h"
33 #include "imageframe.h"
34 #include "canvas_impl.h"
35 #include "gui_thread.h"
37 using namespace ARDOUR ;
40 sigc::signal<void,ImageFrameView*> ImageFrameView::GoingAway;
43 * Constructs a new ImageFrameView upon the canvas
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
57 ImageFrameView::ImageFrameView(const string & item_id,
58 ArdourCanvas::Group *parent,
59 ImageFrameTimeAxis* tv,
60 ImageFrameTimeAxisGroup* item_group,
62 Gdk::Color& basic_color,
65 unsigned char* rgb_data,
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))
76 the_parent_group = item_group ;
77 set_name_text(item_id) ;
79 image_data_width = width ;
80 image_data_height = height ;
81 image_data_num_channels = num_channels ;
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)) ;
88 pbuf = art_pixbuf_new_rgba(the_rgb_data, width, height, (num_channels * width));
91 //calculate our image width based on the track height
92 double im_ratio = (double)width/(double)height ;
93 double im_width = ((double)(trackview.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE) * im_ratio) ;
95 imageframe = new ImageFrame (*group, pbuf, 1.0, 1.0, ANCHOR_NW, im_width, (trackview.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE));
97 frame_handle_start->signal_event().connect (sigc::bind (sigc::mem_fun (trackview.editor, &PublicEditor::canvas_imageframe_start_handle_event), frame_handle_start, this));
98 frame_handle_end->signal_event().connect (sigc::bind (sigc::mem_fun (trackview.editor, &PublicEditor::canvas_imageframe_end_handle_event), frame_handle_end, this));
99 group->signal_event().connect (sigc::bind (sigc::mem_fun (trackview.editor, &PublicEditor::canvas_imageframe_item_view_event), imageframe, this));
101 frame_handle_start->raise_to_top();
102 frame_handle_end->raise_to_top();
104 set_position(start, this) ;
105 set_duration(duration, this) ;
110 * Reposible for removing and destroying all marker items associated with this item
112 ImageFrameView::~ImageFrameView()
116 // destroy any marker items we have associated with this item
118 for(MarkerViewList::iterator iter = marker_view_list.begin(); iter != marker_view_list.end(); ++iter)
120 MarkerView* mv = (*iter) ;
122 MarkerViewList::iterator next = iter ;
125 // remove the item from our marker list
126 // the current iterator becomes invalid after this point, so we cannot call next upon it
127 // luckily enough, we already have next
128 marker_view_list.erase(iter) ;
130 // remove the item from the marker time axis
131 MarkerTimeAxisView* mtav = dynamic_cast<MarkerTimeAxis*>(&mv->get_time_axis_view())->get_view() ;
134 mtav->remove_marker_view(mv, this) ;
137 mv->set_marked_item(0) ;
141 // set our iterator to next, as we have invalided the current iterator with the call to erase
145 // if we are the currently selected item withi the parent track, we need to se-select
148 if(the_parent_group->get_view().get_selected_imageframe_view() == this)
150 the_parent_group->get_view().clear_selected_imageframe_item(false) ;
159 //---------------------------------------------------------------------------------------//
160 // Position and duration Accessors/Mutators
163 * Set the position of this item to the specified value
165 * @param pos the new position
166 * @param src the identity of the object that initiated the change
167 * @return true if the position change was a success, false otherwise
170 ImageFrameView::set_position(nframes64_t pos, void* src, double* delta)
172 nframes64_t old_pos = frame_position ;
174 // do the standard stuff
175 bool ret = TimeAxisViewItem::set_position(pos, src, delta) ;
177 // everything went ok with the standard stuff?
179 /* move each of our associated markers with this ImageFrameView */
180 for (MarkerViewList::iterator i = marker_view_list.begin(); i != marker_view_list.end(); ++i)
182 // calculate the offset of the marker
183 MarkerView* mv = (MarkerView*)*i ;
184 nframes64_t marker_old_pos = mv->get_position() ;
186 mv->set_position(pos + (marker_old_pos - old_pos), src) ;
194 * Sets the duration of this item
196 * @param dur the new duration of this item
197 * @param src the identity of the object that initiated the change
198 * @return true if the duration change was succesful, false otherwise
201 ImageFrameView::set_duration(nframes64_t dur, void* src)
203 /* do the standard stuff */
204 bool ret = TimeAxisViewItem::set_duration(dur, src) ;
206 // eveything went ok with the standard stuff?
209 /* handle setting the sizes of our canvas itesm based on the new duration */
210 imageframe->property_drawwidth() = trackview.editor.frame_to_pixel(get_duration());
216 //---------------------------------------------------------------------------------------//
217 // Parent Component Methods
220 * Sets the parent ImageFrameTimeAxisGroup of thie item
221 * each Item must be part of exactly one group (or 'scene') upon the timeline
223 * @param group the new parent group
226 ImageFrameView::set_time_axis_group(ImageFrameTimeAxisGroup* group)
228 the_parent_group = group ;
232 * Returns the parent group of this item
234 * @return the parent group of this item
236 ImageFrameTimeAxisGroup*
237 ImageFrameView::get_time_axis_group()
239 return(the_parent_group) ;
243 //---------------------------------------------------------------------------------------//
247 * Set the height of this item
249 * @param h the new height
252 ImageFrameView::set_height (gdouble h)
254 // set the image size
255 // @todo might have to re-get the image data, for a large height...hmmm.
256 double im_ratio = (double)image_data_width/(double)image_data_height ;
258 imageframe->property_width() = (h - TimeAxisViewItem::NAME_Y_OFFSET) * im_ratio;
259 imageframe->property_height() = h - TimeAxisViewItem::NAME_Y_OFFSET;
261 frame->raise_to_top();
262 imageframe->raise_to_top();
263 name_highlight->raise_to_top();
264 name_pixbuf->raise_to_top();
265 frame_handle_start->raise_to_top();
266 frame_handle_end->raise_to_top();
268 name_pixbuf->property_y() = h - TimeAxisViewItem::NAME_Y_OFFSET;
269 frame->property_y2() = h;
271 name_highlight->property_y1() = (gdouble) h - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE;
272 name_highlight->property_y2() = (gdouble) h - 1.0;
276 //---------------------------------------------------------------------------------------//
277 // MarkerView methods
280 * Adds a markerView to the list of marker views associated with this item
282 * @param item the marker item to add
283 * @param src the identity of the object that initiated the change
286 ImageFrameView::add_marker_view_item(MarkerView* item, void* src)
288 marker_view_list.push_back(item) ;
290 scoped_connect (item->GoingAway, boost::bind (&ImageFrameView::remove_marker_view_item, this, (void*)this));
292 MarkerViewAdded(item, src) ; /* EMIT_SIGNAL */
296 * Removes the named marker view from the list of marker view associated with this item
297 * The Marker view is not destroyed on removal, so the caller must handle the item themself
299 * @param markId the id/name of the item to remove
300 * @param src the identity of the object that initiated the change
301 * @return the removed marker item
304 ImageFrameView::remove_named_marker_view_item(const string & markerId, void* src)
307 MarkerViewList::iterator i = marker_view_list.begin() ;
309 while(i != marker_view_list.end())
311 if (((MarkerView*)*i)->get_item_name() == markerId)
315 marker_view_list.erase(i) ;
317 MarkerViewRemoved(mv,src) ; /* EMIT_SIGNAL */
319 // iterator is now invalid, but since we should only ever have
320 // one item with the specified name, things are ok, and we can
321 // break from the while loop
331 * Removes item from the list of marker views assocaited with this item
332 * This method will do nothing if item if not assiciated with this item
334 * @param item the item to remove
335 * @param src the identity of the object that initiated the change
338 ImageFrameView::remove_marker_view_item(MarkerView* mv, void* src)
340 ENSURE_GUI_THREAD (*this, &ImageFrameView::remove_marker_view_item, mv, src)
342 MarkerViewList::iterator i ;
344 if((i = find (marker_view_list.begin(), marker_view_list.end(), mv)) != marker_view_list.end()) {
345 marker_view_list.erase(i) ;
346 MarkerViewRemoved (mv, src) ; /* EMIT_SIGNAL */
351 * Determines if the named marker is one of those associated with this item
353 * @param markId the id/name of the item to search for
356 ImageFrameView::has_marker_view_item(const string & mname)
358 bool result = false ;
360 for (MarkerViewList::const_iterator ci = marker_view_list.begin(); ci != marker_view_list.end(); ++ci)
362 if (((MarkerView*)*ci)->get_item_name() == mname)
366 // found the item, so we can break the for loop