make PluginUIWindow inherit from ArdourWindow not GtkWindow
[ardour.git] / gtk2_ardour / editor_imageframe.cc
1 /*
2     Copyright (C) 2000-2003 Paul Davis
3     Written by Colin Law, CMT, Glasgow
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include "imageframe_view.h"
22 #include "imageframe_time_axis.h"
23 #include "imageframe_time_axis_view.h"
24 #include "imageframe_time_axis_group.h"
25 #include "marker_time_axis_view.h"
26 #include "marker_time_axis.h"
27 #include "marker_view.h"
28 #include "editor.h"
29 #include "i18n.h"
30 #include "canvas_impl.h"
31
32 #include <gtkmm2ext/gtk_ui.h>
33 #include "pbd/error.h"
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <unistd.h>
39 #include <arpa/inet.h>
40
41 #include "imageframe_socket_handler.h"
42 #include "ardour_image_compositor_socket.h"
43 #include "public_editor.h"
44 #include "gui_thread.h"
45
46 using namespace Gtk;
47 using namespace PBD;
48 using namespace std;
49
50 TimeAxisView*
51 Editor::get_named_time_axis(const string & name)
52 {
53         TimeAxisView* tav = 0 ;
54
55         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i)
56         {
57                 if (((TimeAxisView*)*i)->name() == name)
58                 {
59                         tav = ((TimeAxisView*)*i) ;
60                         break ;
61                 }
62         }
63         return(tav) ;
64 }
65
66 /* <CMT Additions file="editor.cc"> */
67
68 void
69 Editor::add_imageframe_time_axis(const string & track_name, void* src)
70 {
71         // check for duplicate name
72         if(get_named_time_axis(track_name))
73         {
74                 warning << "Repeated time axis name" << std::endl ;
75         }
76         else
77         {
78                 Gtkmm2ext::UI::instance()->call_slot (boost::bind (&Editor::handle_new_imageframe_time_axis_view, this,track_name, src));
79         }
80 }
81
82 void
83 Editor::connect_to_image_compositor()
84 {
85         if(image_socket_listener == 0)
86         {
87                 image_socket_listener = ImageFrameSocketHandler::create_instance(*this) ;
88         }
89
90         if(image_socket_listener->is_connected() == true)
91         {
92                 return ;
93         }
94
95         // XXX should really put this somewhere safe
96         const char * host_ip = "127.0.0.1" ;
97
98         bool retcode = image_socket_listener->connect(host_ip, ardourvis::DEFAULT_PORT) ;
99
100         if(retcode == false)
101         {
102                 // XXX need to get some return status here
103                 warning << "Image Compositor Connection attempt failed" << std::endl ;
104                 return ;
105         }
106
107         // add the socket to the gui loop, and keep the retuned tag value of the input
108         gint tag = gdk_input_add(image_socket_listener->get_socket_descriptor(), GDK_INPUT_READ,ImageFrameSocketHandler::image_socket_callback,image_socket_listener) ;
109         image_socket_listener->set_gdk_input_tag(tag) ;
110 }
111
112 void
113 Editor::scroll_timeaxis_to_imageframe_item(const TimeAxisViewItem* item)
114 {
115         // GTK2FIX
116         //framepos_t offset = static_cast<framepos_t>(frames_per_unit * (edit_hscroll_slider_width/2)) ;
117         framepos_t offset = 0;
118
119         framepos_t x_pos = 0 ;
120
121         if (item->get_position() < offset) {
122                 x_pos = 0 ;
123         } else {
124                 x_pos = item->get_position() - offset + (item->get_duration() / 2);
125         }
126
127         reset_x_origin (x_pos);
128 }
129
130 void
131 Editor::add_imageframe_marker_time_axis(const string & track_name, TimeAxisView* marked_track, void* src)
132 {
133         // Can we only sigc::bind 2 data Items?
134         // @todo we really want to sigc::bind the src attribute too, for the moment tracks can only be added remotely,
135         //       so this is not too much of an issue, however will need to be looked at again
136         Gtkmm2ext::UI::instance()->call_slot (boost::bind (&Editor::handle_new_imageframe_marker_time_axis_view, this, track_name, marked_track));
137 }
138
139 void
140 Editor::popup_imageframe_edit_menu(int button, int32_t time, ArdourCanvas::Item* ifv, bool with_item)
141 {
142         ImageFrameTimeAxis* ifta = dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview) ;
143
144         if(ifta)
145         {
146                 ImageFrameTimeAxisGroup* iftag = ifta->get_view()->get_selected_imageframe_group() ;
147
148                 if(iftag)
149                 {
150                         ImageFrameView* selected_ifv = ifta->get_view()->get_selected_imageframe_view() ;
151                         ifta->popup_imageframe_edit_menu(button, time, selected_ifv, with_item) ;
152                 }
153         }
154 }
155
156 void
157 Editor::popup_marker_time_axis_edit_menu(int button, int32_t time, ArdourCanvas::Item* ifv, bool with_item)
158 {
159         MarkerTimeAxis* mta = dynamic_cast<MarkerTimeAxis*>(clicked_axisview) ;
160
161         if(mta)
162         {
163                 MarkerView* selected_mv = mta->get_view()->get_selected_time_axis_item() ;
164                 if(selected_mv)
165                 {
166                         mta->popup_marker_time_axis_edit_menu(button,time, selected_mv, with_item) ;
167                 }
168         }
169 }
170 /* </CMT Additions file="editor.cc"> */
171
172 /* <CMT Additions file="editor_canvas_events.cc"> */
173 bool
174 Editor::canvas_imageframe_item_view_event (GdkEvent *event, ArdourCanvas::Item* item, ImageFrameView *ifv)
175 {
176         gint ret = FALSE ;
177         ImageFrameTimeAxisGroup* iftag = 0 ;
178
179         switch (event->type)
180         {
181                 case GDK_BUTTON_PRESS:
182                 case GDK_2BUTTON_PRESS:
183                 case GDK_3BUTTON_PRESS:
184                         clicked_axisview = &ifv->get_time_axis_view();
185                         iftag = ifv->get_time_axis_group() ;
186                         dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview)->get_view()->set_selected_imageframe_view(iftag, ifv);
187                         ret = button_press_handler (item, event, ImageFrameItem) ;
188                         break ;
189                 case GDK_BUTTON_RELEASE:
190                         ret = button_release_handler (item, event, ImageFrameItem) ;
191                         break ;
192                 case GDK_MOTION_NOTIFY:
193                         ret = motion_handler (item, event, ImageFrameItem) ;
194                         break ;
195                 default:
196                         break ;
197         }
198         return(ret) ;
199 }
200
201 bool
202 Editor::canvas_imageframe_start_handle_event (GdkEvent *event, ArdourCanvas::Item* item, ImageFrameView *ifv)
203 {
204         gint ret = FALSE ;
205         ImageFrameTimeAxisGroup* iftag = 0 ;
206
207         switch (event->type)
208         {
209                 case GDK_BUTTON_PRESS:
210                 case GDK_2BUTTON_PRESS:
211                 case GDK_3BUTTON_PRESS:
212                         clicked_axisview = &ifv->get_time_axis_view() ;
213                         iftag = ifv->get_time_axis_group() ;
214                         dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview)->get_view()->set_selected_imageframe_view(iftag, ifv);
215
216                         ret = button_press_handler (item, event, ImageFrameHandleStartItem) ;
217                         break ;
218                 case GDK_BUTTON_RELEASE:
219                         ret = button_release_handler (item, event, ImageFrameHandleStartItem) ;
220                         break;
221                 case GDK_MOTION_NOTIFY:
222                         ret = motion_handler (item, event, ImageFrameHandleStartItem) ;
223                         break ;
224                 case GDK_ENTER_NOTIFY:
225                         ret = enter_handler (item, event, ImageFrameHandleStartItem) ;
226                         break ;
227                 case GDK_LEAVE_NOTIFY:
228                         ret = leave_handler (item, event, ImageFrameHandleStartItem) ;
229                         break ;
230                 default:
231                         break ;
232         }
233         return(ret) ;
234 }
235
236 bool
237 Editor::canvas_imageframe_end_handle_event (GdkEvent *event, ArdourCanvas::Item* item, ImageFrameView *ifv)
238 {
239         gint ret = FALSE ;
240         ImageFrameTimeAxisGroup* iftag = 0 ;
241
242         switch (event->type)
243         {
244                 case GDK_BUTTON_PRESS:
245                 case GDK_2BUTTON_PRESS:
246                 case GDK_3BUTTON_PRESS:
247                         clicked_axisview = &ifv->get_time_axis_view() ;
248                         iftag = ifv->get_time_axis_group() ;
249                         dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview)->get_view()->set_selected_imageframe_view(iftag, ifv);
250
251                         ret = button_press_handler (item, event, ImageFrameHandleEndItem) ;
252                         break ;
253                 case GDK_BUTTON_RELEASE:
254                         ret = button_release_handler (item, event, ImageFrameHandleEndItem) ;
255                         break ;
256                 case GDK_MOTION_NOTIFY:
257                         ret = motion_handler (item, event, ImageFrameHandleEndItem) ;
258                         break ;
259                 case GDK_ENTER_NOTIFY:
260                         ret = enter_handler (item, event, ImageFrameHandleEndItem) ;
261                         break ;
262                 case GDK_LEAVE_NOTIFY:
263                         ret = leave_handler (item, event, ImageFrameHandleEndItem);
264                         break ;
265                 default:
266                         break ;
267         }
268         return(ret) ;
269 }
270
271 bool
272 Editor::canvas_imageframe_view_event (GdkEvent* event, ArdourCanvas::Item* item, ImageFrameTimeAxis* ifta)
273 {
274         gint ret = FALSE ;
275         switch (event->type)
276         {
277                 case GDK_BUTTON_PRESS:
278                 case GDK_2BUTTON_PRESS:
279                 case GDK_3BUTTON_PRESS:
280                         clicked_axisview = ifta ;
281                         ret = button_press_handler (item, event, ImageFrameTimeAxisItem) ;
282                         break ;
283                 case GDK_BUTTON_RELEASE:
284                         ret = button_release_handler (item, event, ImageFrameTimeAxisItem) ;
285                         break ;
286                 case GDK_MOTION_NOTIFY:
287                         break ;
288                 default:
289                         break ;
290         }
291         return(ret) ;
292 }
293
294 bool
295 Editor::canvas_marker_time_axis_view_event (GdkEvent* event, ArdourCanvas::Item* item, MarkerTimeAxis* mta)
296 {
297         gint ret = FALSE ;
298         switch (event->type)
299         {
300                 case GDK_BUTTON_PRESS:
301                 case GDK_2BUTTON_PRESS:
302                 case GDK_3BUTTON_PRESS:
303                         clicked_axisview = mta ;
304                         ret = button_press_handler(item, event, MarkerTimeAxisItem) ;
305                         break ;
306                 case GDK_BUTTON_RELEASE:
307                         ret = button_release_handler(item, event, MarkerTimeAxisItem) ;
308                         break ;
309                 case GDK_MOTION_NOTIFY:
310                 default:
311                         break ;
312         }
313         return(ret) ;
314 }
315
316
317 bool
318 Editor::canvas_markerview_item_view_event (GdkEvent* event, ArdourCanvas::Item* item, MarkerView* mta)
319 {
320         gint ret = FALSE ;
321         switch (event->type)
322         {
323                 case GDK_BUTTON_PRESS:
324                 case GDK_2BUTTON_PRESS:
325                 case GDK_3BUTTON_PRESS:
326                         clicked_axisview = &mta->get_time_axis_view() ;
327                         dynamic_cast<MarkerTimeAxis*>(clicked_axisview)->get_view()->set_selected_time_axis_item(mta);
328                         ret = button_press_handler(item, event, MarkerViewItem) ;
329                         break ;
330                 case GDK_BUTTON_RELEASE:
331                         ret = button_release_handler(item, event, MarkerViewItem) ;
332                         break ;
333                 case GDK_MOTION_NOTIFY:
334                         ret = motion_handler(item, event, MarkerViewItem) ;
335                         break ;
336                 default:
337                         break ;
338         }
339         return(ret) ;
340 }
341
342 bool
343 Editor::canvas_markerview_start_handle_event (GdkEvent* event, ArdourCanvas::Item* item, MarkerView* mta)
344 {
345         gint ret = FALSE ;
346         switch (event->type)
347         {
348                 case GDK_BUTTON_PRESS:
349                 case GDK_2BUTTON_PRESS:
350                 case GDK_3BUTTON_PRESS:
351                         clicked_axisview = &mta->get_time_axis_view() ;
352                         dynamic_cast<MarkerTimeAxis*>(clicked_axisview)->get_view()->set_selected_time_axis_item(mta) ;
353                         ret = button_press_handler(item, event, MarkerViewHandleStartItem) ;
354                         break ;
355                 case GDK_BUTTON_RELEASE:
356                         ret = button_release_handler(item, event, MarkerViewHandleStartItem) ;
357                         break ;
358                 case GDK_MOTION_NOTIFY:
359                         ret = motion_handler(item, event, MarkerViewHandleStartItem) ;
360                         break ;
361                 case GDK_ENTER_NOTIFY:
362                         ret = enter_handler(item, event, MarkerViewHandleStartItem) ;
363                         break ;
364                 case GDK_LEAVE_NOTIFY:
365                         ret = leave_handler(item, event, MarkerViewHandleStartItem) ;
366                         break ;
367                 default:
368                         break ;
369         }
370         return(ret) ;
371 }
372
373 bool
374 Editor::canvas_markerview_end_handle_event (GdkEvent* event, ArdourCanvas::Item* item, MarkerView* mta)
375 {
376         gint ret = FALSE ;
377         switch (event->type)
378         {
379                 case GDK_BUTTON_PRESS:
380                 case GDK_2BUTTON_PRESS:
381                 case GDK_3BUTTON_PRESS:
382                         clicked_axisview = &mta->get_time_axis_view() ;
383                         dynamic_cast<MarkerTimeAxis*>(clicked_axisview)->get_view()->set_selected_time_axis_item(mta) ;
384                         ret = button_press_handler(item, event, MarkerViewHandleEndItem) ;
385                         break ;
386                 case GDK_BUTTON_RELEASE:
387                         ret = button_release_handler(item, event, MarkerViewHandleEndItem) ;
388                         break ;
389                 case GDK_MOTION_NOTIFY:
390                         ret = motion_handler(item, event, MarkerViewHandleEndItem) ;
391                         break ;
392                 case GDK_ENTER_NOTIFY:
393                         ret = enter_handler(item, event, MarkerViewHandleEndItem) ;
394                         break ;
395                 case GDK_LEAVE_NOTIFY:
396                         ret = leave_handler(item, event, MarkerViewHandleEndItem) ;
397                         break ;
398                 default:
399                         break ;
400         }
401         return(ret) ;
402 }
403
404
405 /* </CMT Additions file="editor_canvas_events.cc"> */
406
407
408 /*
409         ---------------------------------------------------------------------------------------------------
410         ---------------------------------------------------------------------------------------------------
411         ---------------------------------------------------------------------------------------------------
412 */
413
414
415
416 /* <CMT Additions file="editor_mouse.cc"> */
417
418 void
419 Editor::start_imageframe_grab(ArdourCanvas::Item* item, GdkEvent* event)
420 {
421         ImageFrameView* ifv = ((ImageFrameTimeAxis*)clicked_axisview)->get_view()->get_selected_imageframe_view() ;
422         drag_info.copy = false ;
423         drag_info.item = item ;
424         drag_info.data = ifv ;
425         drag_info.motion_callback = &Editor::imageframe_drag_motion_callback;
426         drag_info.finished_callback = &Editor::timeaxis_item_drag_finished_callback;
427         drag_info.last_frame_position = ifv->get_position() ;
428
429         drag_info.source_trackview = &ifv->get_time_axis_view() ;
430         drag_info.dest_trackview = drag_info.source_trackview;
431
432         /* this is subtle. raising the regionview itself won't help,
433            because raise_to_top() just puts the item on the top of
434            its parent's stack. so, we need to put the trackview canvas_display group
435            on the top, since its parent is the whole canvas.
436
437            however, this hides the measure bars within that particular trackview,
438            so move them to the top afterwards.
439         */
440
441         drag_info.item->raise_to_top();
442         drag_info.source_trackview->canvas_display->raise_to_top();
443         //time_line_group->raise_to_top();
444         cursor_group->raise_to_top ();
445
446         start_grab(event) ;
447
448         drag_info.pointer_frame_offset = pixel_to_frame(drag_info.grab_x) - drag_info.last_frame_position;
449 }
450
451
452 void
453 Editor::start_markerview_grab(ArdourCanvas::Item* item, GdkEvent* event)
454 {
455         MarkerView* mv = ((MarkerTimeAxis*)clicked_axisview)->get_view()->get_selected_time_axis_item() ;
456         drag_info.copy = false ;
457         drag_info.item = item ;
458         drag_info.data = mv ;
459         drag_info.motion_callback = &Editor::markerview_drag_motion_callback;
460         drag_info.finished_callback = &Editor::timeaxis_item_drag_finished_callback;
461         drag_info.last_frame_position = mv->get_position() ;
462
463         drag_info.source_trackview = &mv->get_time_axis_view() ;
464         drag_info.dest_trackview = drag_info.source_trackview;
465
466         /* this is subtle. raising the regionview itself won't help,
467            because raise_to_top() just puts the item on the top of
468            its parent's stack. so, we need to put the trackview canvas_display group
469            on the top, since its parent is the whole canvas.
470
471            however, this hides the measure bars within that particular trackview,
472            so move them to the top afterwards.
473         */
474
475         drag_info.item->raise_to_top();
476         drag_info.source_trackview->canvas_display->raise_to_top();
477         //time_line_group->raise_to_top();
478         cursor_group->raise_to_top ();
479
480         start_grab(event) ;
481
482         drag_info.pointer_frame_offset = pixel_to_frame(drag_info.grab_x) - drag_info.last_frame_position ;
483 }
484
485
486 void
487 Editor::markerview_drag_motion_callback(ArdourCanvas::Item*, GdkEvent* event)
488 {
489         double cx, cy ;
490
491         MarkerView* mv = reinterpret_cast<MarkerView*>(drag_info.data) ;
492         framepos_t pending_region_position ;
493         framepos_t pointer_frame ;
494
495         pointer_frame = event_frame(event, &cx, &cy) ;
496
497         snap_to(pointer_frame) ;
498
499         if (pointer_frame > (framepos_t) drag_info.pointer_frame_offset)
500         {
501                 pending_region_position = pointer_frame - drag_info.pointer_frame_offset ;
502                 snap_to(pending_region_position) ;
503
504                 // we dont allow marker items to extend beyond, or in front of the marked items so
505                 // cap the value to the marked items position and duration
506                 if((pending_region_position + mv->get_duration()) >= ((mv->get_marked_item()->get_position()) + (mv->get_marked_item()->get_duration())))
507                 {
508                         pending_region_position = (mv->get_marked_item()->get_position() + mv->get_marked_item()->get_duration()) - (mv->get_duration()) ;
509                 }
510                 else if(pending_region_position <= mv->get_marked_item()->get_position())
511                 {
512                         pending_region_position = mv->get_marked_item()->get_position() ;
513                 }
514         }
515         else
516         {
517                 pending_region_position = mv->get_marked_item()->get_position() ;
518         }
519
520         drag_info.last_frame_position = pending_region_position ;
521
522         // we treat this as a special case, usually we want to send the identitiy of the caller
523         // but in this case, that would trigger our socket handler to handle the event, sending
524         // notification to the image compositor. This would be fine, except that we have not
525         // finished the drag, we therefore do not want to sent notification until we have
526         // completed the drag, only then do we want the image compositor notofied.
527         // We therefore set the caller identity to the special case of 0
528         mv->set_position(pending_region_position, 0) ;
529
530         show_verbose_time_cursor(pending_region_position) ;
531 }
532
533 void
534 Editor::imageframe_drag_motion_callback(ArdourCanvas::Item*, GdkEvent* event)
535 {
536         double cx, cy ;
537
538         ImageFrameView* ifv = reinterpret_cast<ImageFrameView*>(drag_info.data) ;
539
540         framepos_t pending_region_position;
541         framepos_t pointer_frame;
542
543         pointer_frame = event_frame(event, &cx, &cy) ;
544
545         snap_to(pointer_frame) ;
546
547         if (pointer_frame > (framepos_t) drag_info.pointer_frame_offset)
548         {
549                 pending_region_position = pointer_frame - drag_info.pointer_frame_offset ;
550                 snap_to(pending_region_position) ;
551         }
552         else
553         {
554                 pending_region_position = 0 ;
555         }
556
557         drag_info.grab_x = cx;
558         //drag_info.last_frame_position = pending_region_position ;
559         drag_info.current_pointer_frame = pending_region_position ;
560
561         // we treat this as a special case, usually we want to send the identitiy of the caller
562         // but in this case, that would trigger our socket handler to handle the event, sending
563         // notification to the image compositor. This would be fine, except that we have not
564         // finished the drag, we therefore do not want to sent notification until we have
565         // completed the drag, only then do we want the image compositor notofied.
566         // We therefore set the caller identity to the special case of 0
567         ifv->set_position(pending_region_position, 0) ;
568
569         show_verbose_time_cursor(pending_region_position) ;
570 }
571
572 void
573 Editor::timeaxis_item_drag_finished_callback(ArdourCanvas::Item*, GdkEvent* event)
574 {
575         framepos_t where ;
576         TimeAxisViewItem* tavi = reinterpret_cast<TimeAxisViewItem*>(drag_info.data) ;
577
578         bool item_x_movement = (drag_info.last_frame_position != tavi->get_position()) ;
579
580         hide_verbose_canvas_cursor() ;
581
582         /* no x or y movement either means the regionview hasn't been moved, or has been moved
583            but is back in it's original position/trackview.*/
584
585         if(!item_x_movement && event && event->type == GDK_BUTTON_RELEASE)
586         {
587                 /* No motion: either set the current region, or align the clicked region
588                    with the current one.
589                  */
590                  return;
591         }
592
593         if(item_x_movement)
594         {
595                 /* base the new region position on the current position of the regionview.*/
596                 where = drag_info.current_pointer_frame ;
597
598                 // final call to set position after the motion to tell interested parties of the new position
599                 tavi->set_position(where, this) ;
600         }
601         else
602         {
603                 //where = tavi->get_position() ;
604         }
605
606 /*
607         //locate so user can audition the edit
608         if ( !session->transport_rolling() && Config->get_always_play_range()) {
609                 locate_with_edit_preroll ( arv->region()->position() );
610         }
611 */
612 }
613
614
615 void
616 Editor::imageframe_start_handle_op(ArdourCanvas::Item* item, GdkEvent* event)
617 {
618         // get the selected item from the parent time axis
619         ImageFrameTimeAxis* ifta = dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview) ;
620         if(ifta)
621         {
622                 ImageFrameView* ifv = ifta->get_view()->get_selected_imageframe_view() ;
623
624                 if (ifv == 0) {
625                         fatal << _("programming error: no ImageFrameView selected") << endmsg;
626                         /*NOTREACHED*/
627                         return ;
628                 }
629
630                 drag_info.item = ifv->get_canvas_frame() ;
631                 drag_info.data = ifv;
632                 drag_info.grab_x = event->motion.x;
633                 drag_info.cumulative_x_drag = 0;
634                 drag_info.motion_callback = &Editor::imageframe_start_handle_trim_motion ;
635                 drag_info.finished_callback = &Editor::imageframe_start_handle_end_trim ;
636
637                 start_grab(event) ;
638
639                 show_verbose_time_cursor(ifv->get_position(), 10) ;
640         }
641 }
642
643 void
644 Editor::imageframe_end_handle_op(ArdourCanvas::Item* item, GdkEvent* event)
645 {
646         // get the selected item from the parent time axis
647         ImageFrameTimeAxis* ifta = dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview) ;
648
649         if(ifta)
650         {
651                 ImageFrameView* ifv = ifta->get_view()->get_selected_imageframe_view() ;
652
653                 if (ifv == 0)
654                 {
655                         fatal << _("programming error: no ImageFrameView selected") << endmsg ;
656                         /*NOTREACHED*/
657                         return ;
658                 }
659
660                 drag_info.item = ifv->get_canvas_frame() ;
661                 drag_info.data = ifv ;
662                 drag_info.grab_x = event->motion.x ;
663                 drag_info.cumulative_x_drag = 0 ;
664                 drag_info.motion_callback = &Editor::imageframe_end_handle_trim_motion ;
665                 drag_info.finished_callback = &Editor::imageframe_end_handle_end_trim ;
666
667                 start_grab(event, trimmer_cursor) ;
668
669                 show_verbose_time_cursor(ifv->get_position() + ifv->get_duration(), 10) ;
670         }
671 }
672
673 void
674 Editor::imageframe_start_handle_trim_motion(ArdourCanvas::Item* item, GdkEvent* event)
675 {
676         ImageFrameView* ifv = reinterpret_cast<ImageFrameView*> (drag_info.data) ;
677
678         framepos_t start = 0 ;
679         framepos_t end = 0 ;
680         framepos_t pointer_frame = event_frame(event) ;
681
682         // chekc th eposition of the item is not locked
683         if(!ifv->get_position_locked()) {
684                 snap_to(pointer_frame) ;
685
686                 if(pointer_frame != drag_info.last_pointer_frame) {
687                         start = ifv->get_position() ;
688                         end = ifv->get_position() + ifv->get_duration() ;
689
690                         if (pointer_frame > end) {
691                                 start = end ;
692                         } else {
693                                 start = pointer_frame ;
694                         }
695
696                         // are we getting bigger or smaller?
697                         framepos_t new_dur_val = end - start ;
698
699                         // start handle, so a smaller pointer frame increases our component size
700                         if(pointer_frame <= drag_info.grab_frame)
701                         {
702                                 if(ifv->get_max_duration_active() && (new_dur_val > ifv->get_max_duration()))
703                                 {
704                                         new_dur_val = ifv->get_max_duration() ;
705                                         start = end - new_dur_val ;
706                                 }
707                                 else
708                                 {
709                                         // current values are ok
710                                 }
711                         }
712                         else
713                         {
714                                 if(ifv->get_min_duration_active() && (new_dur_val < ifv->get_min_duration()))
715                                 {
716                                         new_dur_val = ifv->get_min_duration() ;
717                                         start = end - new_dur_val ;
718                                 }
719                                 else
720                                 {
721                                         // current values are ok
722                                 }
723                         }
724
725                         drag_info.last_pointer_frame = pointer_frame ;
726
727                         /* re-calculatethe duration and position of the imageframeview */
728                         drag_info.cumulative_x_drag = new_dur_val ;
729
730                         // we treat this as a special case, usually we want to send the identitiy of the caller
731                         // but in this case, that would trigger our socket handler to handle the event, sending
732                         // notification to the image compositor. This would be fine, except that we have not
733                         // finished the drag, we therefore do not want to sent notification until we have
734                         // completed the drag, only then do we want the image compositor notofied.
735                         // We therefore set the caller identity to the special case of 0
736                         ifv->set_duration(new_dur_val, 0) ;
737                         ifv->set_position(start, 0) ;
738                 }
739         }
740
741         show_verbose_time_cursor(start, 10) ;
742 }
743
744 void
745 Editor::imageframe_start_handle_end_trim(ArdourCanvas::Item* item, GdkEvent* event)
746 {
747         ImageFrameView* ifv = reinterpret_cast<ImageFrameView *> (drag_info.data) ;
748
749         if (drag_info.cumulative_x_drag == 0)
750         {
751                 /* just a click */
752         }
753         else
754         {
755                 framepos_t temp = ifv->get_position() + ifv->get_duration() ;
756
757                 ifv->set_position((framepos_t) (temp - drag_info.cumulative_x_drag), this) ;
758                 ifv->set_duration((framepos_t) drag_info.cumulative_x_drag, this) ;
759         }
760 }
761
762 void
763 Editor::imageframe_end_handle_trim_motion(ArdourCanvas::Item* item, GdkEvent* event)
764 {
765         ImageFrameView* ifv = reinterpret_cast<ImageFrameView *> (drag_info.data) ;
766
767         framepos_t start = 0 ;
768         framepos_t end = 0 ;
769         framepos_t pointer_frame = event_frame(event) ;
770         framepos_t new_dur_val = 0 ;
771
772         snap_to(pointer_frame) ;
773
774         if (pointer_frame != drag_info.last_pointer_frame)
775         {
776                 start = ifv->get_position() ;
777                 end = ifv->get_position() + ifv->get_duration() ;
778                 if (pointer_frame < start)
779                 {
780                         end = start ;
781                 }
782                 else
783                 {
784                         end = pointer_frame ;
785                 }
786
787                 new_dur_val = end - start ;
788
789                 // are we getting bigger or smaller?
790                 if(pointer_frame >= drag_info.last_pointer_frame)
791                 {
792                         if(ifv->get_max_duration_active() && (new_dur_val > ifv->get_max_duration()))
793                         {
794                                 new_dur_val = ifv->get_max_duration() ;
795                         }
796                 }
797                 else
798                 {
799                         if(ifv->get_min_duration_active() && (new_dur_val < ifv->get_min_duration()))
800                         {
801                                 new_dur_val = ifv->get_min_duration() ;
802                         }
803                 }
804
805                 drag_info.last_pointer_frame = pointer_frame ;
806                 drag_info.cumulative_x_drag = new_dur_val ;
807
808                 // we treat this as a special case, usually we want to send the identitiy of the caller
809                 // but in this case, that would trigger our socket handler to handle the event, sending
810                 // notification to the image compositor. This would be fine, except that we have not
811                 // finished the drag, we therefore do not want to sent notification until we have
812                 // completed the drag, only then do we want the image compositor notofied.
813                 // We therefore set the caller identity to the special case of 0
814                 ifv->set_duration(new_dur_val, 0) ;
815         }
816
817         show_verbose_time_cursor(new_dur_val, 10) ;
818 }
819
820
821 void
822 Editor::imageframe_end_handle_end_trim (ArdourCanvas::Item* item, GdkEvent* event)
823 {
824         ImageFrameView* ifv = reinterpret_cast<ImageFrameView *> (drag_info.data) ;
825
826         if (drag_info.cumulative_x_drag == 0)
827         {
828                 /* just a click */
829         }
830         else
831         {
832                 framepos_t new_duration = (framepos_t)drag_info.cumulative_x_drag ;
833                 if((new_duration <= ifv->get_max_duration()) && (new_duration >= ifv->get_min_duration()))
834                 {
835                         ifv->set_duration(new_duration, this) ;
836                 }
837         }
838 }
839
840
841 void
842 Editor::markerview_item_start_handle_op(ArdourCanvas::Item* item, GdkEvent* event)
843 {
844         MarkerView* mv = reinterpret_cast<MarkerTimeAxis*>(clicked_axisview)->get_view()->get_selected_time_axis_item() ;
845
846         if (mv == 0)
847         {
848                 fatal << _("programming error: no MarkerView selected") << endmsg ;
849                 /*NOTREACHED*/
850                 return ;
851         }
852
853         drag_info.item = mv->get_canvas_frame() ;
854         drag_info.data = mv;
855         drag_info.grab_x = event->motion.x;
856
857         drag_info.cumulative_x_drag = 0 ;
858         drag_info.motion_callback = &Editor::markerview_start_handle_trim_motion ;
859         drag_info.finished_callback = &Editor::markerview_start_handle_end_trim ;
860
861         start_grab(event, trimmer_cursor) ;
862 }
863
864 void
865 Editor::markerview_item_end_handle_op(ArdourCanvas::Item* item, GdkEvent* event)
866 {
867         MarkerView* mv = reinterpret_cast<MarkerTimeAxis*>(clicked_axisview)->get_view()->get_selected_time_axis_item() ;
868         if (mv == 0)
869         {
870                 fatal << _("programming error: no MarkerView selected") << endmsg ;
871                 /*NOTREACHED*/
872                 return ;
873         }
874
875         drag_info.item = mv->get_canvas_frame() ;
876         drag_info.data = mv ;
877         drag_info.grab_x = event->motion.x ;
878         drag_info.cumulative_x_drag = 0 ;
879
880         drag_info.motion_callback = &Editor::markerview_end_handle_trim_motion ;
881         drag_info.finished_callback = &Editor::markerview_end_handle_end_trim ;
882
883         start_grab(event, trimmer_cursor) ;
884 }
885
886
887 void
888 Editor::markerview_start_handle_trim_motion(ArdourCanvas::Item* item, GdkEvent* event)
889 {
890         MarkerView* mv = reinterpret_cast<MarkerView*> (drag_info.data) ;
891
892         framepos_t start = 0 ;
893         framepos_t end = 0 ;
894         framepos_t pointer_frame = event_frame(event) ;
895
896         // chekc th eposition of the item is not locked
897         if(!mv->get_position_locked())
898         {
899                 snap_to(pointer_frame) ;
900                 if(pointer_frame != drag_info.last_pointer_frame)
901                 {
902                         start = mv->get_position() ;
903                         end = mv->get_position() + mv->get_duration() ;
904
905                         if (pointer_frame > end)
906                         {
907                                 start = end ;
908                         }
909                         else
910                         {
911                                 start = pointer_frame ;
912                         }
913
914                         // are we getting bigger or smaller?
915                         framepos_t new_dur_val = end - start ;
916
917                         if(pointer_frame <= drag_info.grab_frame)
918                         {
919                                 if(mv->get_max_duration_active() && (new_dur_val > mv->get_max_duration()))
920                                 {
921                                         new_dur_val = mv->get_max_duration() ;
922                                         start = end - new_dur_val ;
923                                 }
924                                 else
925                                 {
926                                         // current values are ok
927                                 }
928                         }
929                         else
930                         {
931                                 if(mv->get_min_duration_active() && (new_dur_val < mv->get_min_duration()))
932                                 {
933                                         new_dur_val = mv->get_min_duration() ;
934                                         start = end - new_dur_val ;
935                                 }
936                                 else
937                                 {
938                                         // current values are ok
939                                 }
940                         }
941
942                         drag_info.last_pointer_frame = pointer_frame ;
943
944                         /* re-calculatethe duration and position of the imageframeview */
945                         drag_info.cumulative_x_drag = new_dur_val ;
946
947                         // we treat this as a special case, usually we want to send the identitiy of the caller
948                         // but in this case, that would trigger our socket handler to handle the event, sending
949                         // notification to the image compositor. This would be fine, except that we have not
950                         // finished the drag, we therefore do not want to sent notification until we have
951                         // completed the drag, only then do we want the image compositor notofied.
952                         // We therefore set the caller identity to the special case of 0
953                         mv->set_duration(new_dur_val, 0) ;
954                         mv->set_position(start, 0) ;
955                 }
956         }
957
958         show_verbose_time_cursor(start, 10) ;
959 }
960
961 void
962 Editor::markerview_start_handle_end_trim(ArdourCanvas::Item* item, GdkEvent* event)
963 {
964         MarkerView* mv = reinterpret_cast<MarkerView*> (drag_info.data) ;
965
966         if (drag_info.cumulative_x_drag == 0)
967         {
968                 /* just a click */
969         }
970         else
971         {
972                 framepos_t temp = mv->get_position() + mv->get_duration() ;
973
974                 mv->set_position((framepos_t) (temp - drag_info.cumulative_x_drag), this) ;
975                 mv->set_duration((framepos_t) drag_info.cumulative_x_drag, this) ;
976         }
977 }
978
979 void
980 Editor::markerview_end_handle_trim_motion(ArdourCanvas::Item* item, GdkEvent* event)
981 {
982         MarkerView* mv = reinterpret_cast<MarkerView*> (drag_info.data) ;
983
984         framepos_t start = 0 ;
985         framepos_t end = 0 ;
986         framepos_t pointer_frame = event_frame(event) ;
987         framepos_t new_dur_val = 0 ;
988
989         snap_to(pointer_frame) ;
990
991         if (pointer_frame != drag_info.last_pointer_frame)
992         {
993                 start = mv->get_position() ;
994                 end = mv->get_position() + mv->get_duration() ;
995
996                 if(pointer_frame < start)
997                 {
998                         end = start ;
999                 }
1000                 else
1001                 {
1002                         end = pointer_frame ;
1003                 }
1004
1005                 new_dur_val = end - start ;
1006
1007                 // are we getting bigger or smaller?
1008                 if(pointer_frame >= drag_info.last_pointer_frame)
1009                 {
1010                         // we cant extend beyond the item we are marking
1011                         ImageFrameView* marked_item = mv->get_marked_item() ;
1012                         framepos_t marked_end = marked_item->get_position() + marked_item->get_duration() ;
1013
1014                         if(mv->get_max_duration_active() && (new_dur_val > mv->get_max_duration()))
1015                         {
1016                                 if((start + mv->get_max_duration()) > marked_end)
1017                                 {
1018                                         new_dur_val = marked_end - start ;
1019                                 }
1020                                 else
1021                                 {
1022                                         new_dur_val = mv->get_max_duration() ;
1023                                 }
1024                         }
1025                         else if(end > marked_end)
1026                         {
1027                                 new_dur_val = marked_end - start ;
1028                         }
1029                 }
1030                 else
1031                 {
1032                         if(mv->get_min_duration_active() && (new_dur_val < mv->get_min_duration()))
1033                         {
1034                                 new_dur_val = mv->get_min_duration() ;
1035                         }
1036                 }
1037
1038
1039                 drag_info.last_pointer_frame = pointer_frame ;
1040                 drag_info.cumulative_x_drag = new_dur_val ;
1041
1042                 // we treat this as a special case, usually we want to send the identitiy of the caller
1043                 // but in this case, that would trigger our socket handler to handle the event, sending
1044                 // notification to the image compositor. This would be fine, except that we have not
1045                 // finished the drag, we therefore do not want to sent notification until we have
1046                 // completed the drag, only then do we want the image compositor notofied.
1047                 // We therefore set the caller identity to the special case of 0
1048                 mv->set_duration(new_dur_val, 0) ;
1049         }
1050
1051         show_verbose_time_cursor(new_dur_val, 10) ;
1052 }
1053
1054
1055 void
1056 Editor::markerview_end_handle_end_trim (ArdourCanvas::Item* item, GdkEvent* event)
1057 {
1058         MarkerView* mv = reinterpret_cast<MarkerView*> (drag_info.data) ;
1059
1060         if (drag_info.cumulative_x_drag == 0)
1061         {
1062                 /* just a click */
1063         }
1064         else
1065         {
1066                 framepos_t new_duration = (framepos_t)drag_info.cumulative_x_drag ;
1067                 mv->set_duration(new_duration, this) ;
1068         }
1069 }
1070
1071
1072 /* </CMT Additions file="editor_mouse.cc"> */
1073
1074
1075
1076
1077
1078
1079
1080 /* <CMT Additions file="editor_route_list.cc"> */
1081
1082 void
1083 Editor::handle_new_imageframe_time_axis_view(const string & track_name, void* src)
1084 {
1085         ImageFrameTimeAxis* iftav ;
1086         iftav = new ImageFrameTimeAxis(track_name, *this, *session, *track_canvas) ;
1087         iftav->set_time_axis_name(track_name, this) ;
1088         track_views.push_back(iftav) ;
1089
1090         TreeModel::Row row = *(route_display_model->append());
1091
1092         row[route_display_columns.text] = iftav->name();
1093         row[route_display_columns.tv] = iftav;
1094         route_list_display.get_selection()->select (row);
1095
1096         iftav->gui_changed.connect(sigc::mem_fun(*this, &Editor::handle_gui_changes)) ;
1097 }
1098
1099 void
1100 Editor::handle_new_imageframe_marker_time_axis_view(const string & track_name, TimeAxisView* marked_track)
1101 {
1102         MarkerTimeAxis* mta = new MarkerTimeAxis (*this, *this->session(), *track_canvas, track_name, marked_track) ;
1103         ((ImageFrameTimeAxis*)marked_track)->add_marker_time_axis(mta, this) ;
1104         track_views.push_back(mta) ;
1105
1106         TreeModel::Row row = *(route_display_model->append());
1107
1108         row[route_display_columns.text] = mta->name();
1109         row[route_display_columns.tv] = mta;
1110         route_list_display.get_selection()->select (row);
1111 }
1112
1113
1114 /* </CMT Additions file="editor_route_list.cc"> */