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