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 sigc
;
38 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(const string
& item_id
,
59 ArdourCanvas::Group
*parent
,
60 ImageFrameTimeAxis
* tv
,
61 ImageFrameTimeAxisGroup
* item_group
,
63 Gdk::Color
& basic_color
,
66 unsigned char* rgb_data
,
69 uint32_t num_channels
)
70 : TimeAxisViewItem(item_id
, *parent
, *tv
, spu
, basic_color
, start
, duration
, false,
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
)) ;
90 pbuf
= art_pixbuf_new_rgb(the_rgb_data
, width
, height
, (num_channels
* width
));
91 else if (num_channels
==4)
92 pbuf
= art_pixbuf_new_rgba(the_rgb_data
, width
, height
, (num_channels
* width
));
94 ; // error unsupported image data format
95 art_free(the_rgb_data
);
96 std::cerr
<< "imageframe_view: unsupported image data format" << std::endl
;
101 //calculate our image width based on the track height
102 double im_ratio
= (double)width
/(double)height
;
103 double im_width
= ((double)(trackview
.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE
) * im_ratio
) ;
105 imageframe
= new ImageFrame (*group
, pbuf
, 1.0, 1.0, ANCHOR_NW
, im_width
, (trackview
.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE
));
107 frame_handle_start
->signal_event().connect (bind (mem_fun (trackview
.editor
, &PublicEditor::canvas_imageframe_start_handle_event
), frame_handle_start
, this));
108 frame_handle_end
->signal_event().connect (bind (mem_fun (trackview
.editor
, &PublicEditor::canvas_imageframe_end_handle_event
), frame_handle_end
, this));
109 group
->signal_event().connect (bind (mem_fun (trackview
.editor
, &PublicEditor::canvas_imageframe_item_view_event
), imageframe
, this));
111 frame_handle_start
->raise_to_top();
112 frame_handle_end
->raise_to_top();
114 set_position(start
, this) ;
115 set_duration(duration
, this) ;
120 * Reposible for removing and destroying all marker items associated with this item
122 ImageFrameView::~ImageFrameView()
126 // destroy any marker items we have associated with this item
128 for(MarkerViewList::iterator iter
= marker_view_list
.begin(); iter
!= marker_view_list
.end(); ++iter
)
130 MarkerView
* mv
= (*iter
) ;
132 MarkerViewList::iterator next
= iter
;
135 // remove the item from our marker list
136 // the current iterator becomes invalid after this point, so we cannot call next upon it
137 // luckily enough, we already have next
138 marker_view_list
.erase(iter
) ;
140 // remove the item from the marker time axis
141 MarkerTimeAxisView
* mtav
= dynamic_cast<MarkerTimeAxis
*>(&mv
->get_time_axis_view())->get_view() ;
144 mtav
->remove_marker_view(mv
, this) ;
147 mv
->set_marked_item(0) ;
151 // set our iterator to next, as we have invalided the current iterator with the call to erase
155 // if we are the currently selected item withi the parent track, we need to se-select
158 if(the_parent_group
->get_view().get_selected_imageframe_view() == this)
160 the_parent_group
->get_view().clear_selected_imageframe_item(false) ;
172 //---------------------------------------------------------------------------------------//
173 // Position and duration Accessors/Mutators
176 * Set the position of this item to the specified value
178 * @param pos the new position
179 * @param src the identity of the object that initiated the change
180 * @return true if the position change was a success, false otherwise
183 ImageFrameView::set_position(nframes_t pos
, void* src
, double* delta
)
185 nframes_t old_pos
= frame_position
;
187 // do the standard stuff
188 bool ret
= TimeAxisViewItem::set_position(pos
, src
, delta
) ;
190 // everything went ok with the standard stuff?
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
)
195 // calculate the offset of the marker
196 MarkerView
* mv
= (MarkerView
*)*i
;
197 nframes_t marker_old_pos
= mv
->get_position() ;
199 mv
->set_position(pos
+ (marker_old_pos
- old_pos
), src
) ;
207 * Sets the duration of this item
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
214 ImageFrameView::set_duration(nframes_t dur
, void* src
)
216 /* do the standard stuff */
217 bool ret
= TimeAxisViewItem::set_duration(dur
, src
) ;
219 // eveything went ok with the standard stuff?
222 /* handle setting the sizes of our canvas itesm based on the new duration */
223 imageframe
->property_drawwidth() = trackview
.editor
.frame_to_pixel(get_duration());
229 //---------------------------------------------------------------------------------------//
230 // Parent Component Methods
233 * Sets the parent ImageFrameTimeAxisGroup of thie item
234 * each Item must be part of exactly one group (or 'scene') upon the timeline
236 * @param group the new parent group
239 ImageFrameView::set_time_axis_group(ImageFrameTimeAxisGroup
* group
)
241 the_parent_group
= group
;
245 * Returns the parent group of this item
247 * @return the parent group of this item
249 ImageFrameTimeAxisGroup
*
250 ImageFrameView::get_time_axis_group()
252 return(the_parent_group
) ;
256 //---------------------------------------------------------------------------------------//
260 * Set the height of this item
262 * @param h the new height
265 ImageFrameView::set_height (gdouble h
)
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
;
271 imageframe
->property_width() = (h
- TimeAxisViewItem::NAME_Y_OFFSET
) * im_ratio
;
272 imageframe
->property_height() = h
- TimeAxisViewItem::NAME_Y_OFFSET
;
274 frame
->raise_to_top();
275 imageframe
->raise_to_top();
276 name_highlight
->raise_to_top();
277 name_pixbuf
->raise_to_top();
278 frame_handle_start
->raise_to_top();
279 frame_handle_end
->raise_to_top();
281 name_pixbuf
->property_y() = h
- TimeAxisViewItem::NAME_Y_OFFSET
;
282 frame
->property_y2() = h
;
284 name_highlight
->property_y1() = (gdouble
) h
- TimeAxisViewItem::NAME_HIGHLIGHT_SIZE
;
285 name_highlight
->property_y2() = (gdouble
) h
- 1.0;
289 //---------------------------------------------------------------------------------------//
290 // MarkerView methods
293 * Adds a markerView to the list of marker views associated with this item
295 * @param item the marker item to add
296 * @param src the identity of the object that initiated the change
299 ImageFrameView::add_marker_view_item(MarkerView
* item
, void* src
)
301 marker_view_list
.push_back(item
) ;
303 item
->GoingAway
.connect(bind(mem_fun(*this, &ImageFrameView::remove_marker_view_item
), (void*)this));
305 MarkerViewAdded(item
, src
) ; /* EMIT_SIGNAL */
309 * Removes the named marker view from the list of marker view associated with this item
310 * The Marker view is not destroyed on removal, so the caller must handle the item themself
312 * @param markId the id/name of the item to remove
313 * @param src the identity of the object that initiated the change
314 * @return the removed marker item
317 ImageFrameView::remove_named_marker_view_item(const string
& markerId
, void* src
)
320 MarkerViewList::iterator i
= marker_view_list
.begin() ;
322 while(i
!= marker_view_list
.end())
324 if (((MarkerView
*)*i
)->get_item_name() == markerId
)
328 marker_view_list
.erase(i
) ;
330 MarkerViewRemoved(mv
,src
) ; /* EMIT_SIGNAL */
332 // iterator is now invalid, but since we should only ever have
333 // one item with the specified name, things are ok, and we can
334 // break from the while loop
344 * Removes item from the list of marker views assocaited with this item
345 * This method will do nothing if item if not assiciated with this item
347 * @param item the item to remove
348 * @param src the identity of the object that initiated the change
351 ImageFrameView::remove_marker_view_item(MarkerView
* mv
, void* src
)
353 ENSURE_GUI_THREAD(bind (mem_fun(*this, &ImageFrameView::remove_marker_view_item
), mv
, src
));
355 MarkerViewList::iterator i
;
357 if((i
= find (marker_view_list
.begin(), marker_view_list
.end(), mv
)) != marker_view_list
.end()) {
358 marker_view_list
.erase(i
) ;
359 MarkerViewRemoved (mv
, src
) ; /* EMIT_SIGNAL */
364 * Determines if the named marker is one of those associated with this item
366 * @param markId the id/name of the item to search for
369 ImageFrameView::has_marker_view_item(const string
& mname
)
371 bool result
= false ;
373 for (MarkerViewList::const_iterator ci
= marker_view_list
.begin(); ci
!= marker_view_list
.end(); ++ci
)
375 if (((MarkerView
*)*ci
)->get_item_name() == mname
)
379 // found the item, so we can break the for loop