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