705c68586cdb4e3c019dab0876920b6346dc43e8
[ardour.git] / gtk2_ardour / editor_imageframe.cc
1 /*
2     Copyright (C) 2000-2003 Paul Davis
3     Written by Colin Law, CMT, Glasgow
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include "imageframe_view.h"
22 #include "imageframe_time_axis.h"
23 #include "imageframe_time_axis_view.h"
24 #include "imageframe_time_axis_group.h"
25 #include "marker_time_axis_view.h"
26 #include "marker_time_axis.h"
27 #include "marker_view.h"
28 #include "editor.h"
29 #include "i18n.h"
30 #include "canvas_impl.h"
31
32 #include <gtkmm2ext/gtk_ui.h>
33 #include "pbd/error.h"
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <unistd.h>
39 #include <arpa/inet.h>
40
41 #include "imageframe_socket_handler.h"
42 #include "ardour_image_compositor_socket.h"
43 #include "public_editor.h"
44
45 using namespace Gtk;
46 using namespace PBD;
47 using namespace std;
48
49 TimeAxisView*
50 Editor::get_named_time_axis(const string & name)
51 {
52         TimeAxisView* tav = 0 ;
53
54         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i)
55         {
56                 if (((TimeAxisView*)*i)->name() == name)
57                 {
58                         tav = ((TimeAxisView*)*i) ;
59                         break ;
60                 }
61         }
62         return(tav) ;
63 }
64
65 /* <CMT Additions file="editor.cc"> */
66
67 void
68 Editor::add_imageframe_time_axis(const string & track_name, void* src)
69 {
70         // check for duplicate name
71         if(get_named_time_axis(track_name))
72         {
73                 warning << "Repeated time axis name" << std::endl ;
74         }
75         else
76         {
77                 Gtkmm2ext::UI::instance()->call_slot (boost::bind (&Editor::handle_new_imageframe_time_axis_view, this,track_name, src));
78         }
79 }
80
81 void
82 Editor::connect_to_image_compositor()
83 {
84         if(image_socket_listener == 0)
85         {
86                 image_socket_listener = ImageFrameSocketHandler::create_instance(*this) ;
87         }
88
89         if(image_socket_listener->is_connected() == true)
90         {
91                 return ;
92         }
93
94         // XXX should really put this somewhere safe
95         const char * host_ip = "127.0.0.1" ;
96
97         bool retcode = image_socket_listener->connect(host_ip, ardourvis::DEFAULT_PORT) ;
98
99         if(retcode == false)
100         {
101                 // XXX need to get some return status here
102                 warning << "Image Compositor Connection attempt failed" << std::endl ;
103                 return ;
104         }
105
106         // add the socket to the gui loop, and keep the retuned tag value of the input
107         gint tag = gdk_input_add(image_socket_listener->get_socket_descriptor(), GDK_INPUT_READ,ImageFrameSocketHandler::image_socket_callback,image_socket_listener) ;
108         image_socket_listener->set_gdk_input_tag(tag) ;
109 }
110
111 void
112 Editor::scroll_timeaxis_to_imageframe_item(const TimeAxisViewItem* item)
113 {
114         // GTK2FIX
115         //nframes64_t offset = static_cast<nframes64_t>(frames_per_unit * (edit_hscroll_slider_width/2)) ;
116         nframes64_t offset = 0;
117
118         nframes64_t x_pos = 0 ;
119
120         if (item->get_position() < offset) {
121                 x_pos = 0 ;
122         } else {
123                 x_pos = item->get_position() - offset + (item->get_duration() / 2);
124         }
125
126         reset_x_origin (x_pos);
127 }
128
129 void
130 Editor::add_imageframe_marker_time_axis(const string & track_name, TimeAxisView* marked_track, void* src)
131 {
132         // Can we only sigc::bind 2 data Items?
133         // @todo we really want to sigc::bind the src attribute too, for the moment tracks can only be added remotely,
134         //       so this is not too much of an issue, however will need to be looked at again
135         Gtkmm2ext::UI::instance()->call_slot (boost::bind (&Editor::handle_new_imageframe_marker_time_axis_view, this, track_name, marked_track));
136 }
137
138 void
139 Editor::popup_imageframe_edit_menu(int button, int32_t time, ArdourCanvas::Item* ifv, bool with_item)
140 {
141         ImageFrameTimeAxis* ifta = dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview) ;
142
143         if(ifta)
144         {
145                 ImageFrameTimeAxisGroup* iftag = ifta->get_view()->get_selected_imageframe_group() ;
146
147                 if(iftag)
148                 {
149                         ImageFrameView* selected_ifv = ifta->get_view()->get_selected_imageframe_view() ;
150                         ifta->popup_imageframe_edit_menu(button, time, selected_ifv, with_item) ;
151                 }
152         }
153 }
154
155 void
156 Editor::popup_marker_time_axis_edit_menu(int button, int32_t time, ArdourCanvas::Item* ifv, bool with_item)
157 {
158         MarkerTimeAxis* mta = dynamic_cast<MarkerTimeAxis*>(clicked_axisview) ;
159
160         if(mta)
161         {
162                 MarkerView* selected_mv = mta->get_view()->get_selected_time_axis_item() ;
163                 if(selected_mv)
164                 {
165                         mta->popup_marker_time_axis_edit_menu(button,time, selected_mv, with_item) ;
166                 }
167         }
168 }
169 /* </CMT Additions file="editor.cc"> */
170
171
172
173
174
175
176 /* <CMT Additions file="editor_canvas_events.cc"> */
177 bool
178 Editor::canvas_imageframe_item_view_event (GdkEvent *event, ArdourCanvas::Item* item, ImageFrameView *ifv)
179 {
180         gint ret = FALSE ;
181         ImageFrameTimeAxisGroup* iftag = 0 ;
182
183         switch (event->type)
184         {
185                 case GDK_BUTTON_PRESS:
186                 case GDK_2BUTTON_PRESS:
187                 case GDK_3BUTTON_PRESS:
188                         clicked_axisview = &ifv->get_time_axis_view();
189                         iftag = ifv->get_time_axis_group() ;
190                         dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview)->get_view()->set_selected_imageframe_view(iftag, ifv);
191                         ret = button_press_handler (item, event, ImageFrameItem) ;
192                         break ;
193                 case GDK_BUTTON_RELEASE:
194                         ret = button_release_handler (item, event, ImageFrameItem) ;
195                         break ;
196                 case GDK_MOTION_NOTIFY:
197                         ret = motion_handler (item, event, ImageFrameItem) ;
198                         break ;
199                 default:
200                         break ;
201         }
202         return(ret) ;
203 }
204
205 bool
206 Editor::canvas_imageframe_start_handle_event (GdkEvent *event, ArdourCanvas::Item* item, ImageFrameView *ifv)
207 {
208         gint ret = FALSE ;
209         ImageFrameTimeAxisGroup* iftag = 0 ;
210
211         switch (event->type)
212         {
213                 case GDK_BUTTON_PRESS:
214                 case GDK_2BUTTON_PRESS:
215                 case GDK_3BUTTON_PRESS:
216                         clicked_axisview = &ifv->get_time_axis_view() ;
217                         iftag = ifv->get_time_axis_group() ;
218                         dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview)->get_view()->set_selected_imageframe_view(iftag, ifv);
219
220                         ret = button_press_handler (item, event, ImageFrameHandleStartItem) ;
221                         break ;
222                 case GDK_BUTTON_RELEASE:
223                         ret = button_release_handler (item, event, ImageFrameHandleStartItem) ;
224                         break;
225                 case GDK_MOTION_NOTIFY:
226                         ret = motion_handler (item, event, ImageFrameHandleStartItem) ;
227                         break ;
228                 case GDK_ENTER_NOTIFY:
229                         ret = enter_handler (item, event, ImageFrameHandleStartItem) ;
230                         break ;
231                 case GDK_LEAVE_NOTIFY:
232                         ret = leave_handler (item, event, ImageFrameHandleStartItem) ;
233                         break ;
234                 default:
235                         break ;
236         }
237         return(ret) ;
238 }
239
240 bool
241 Editor::canvas_imageframe_end_handle_event (GdkEvent *event, ArdourCanvas::Item* item, ImageFrameView *ifv)
242 {
243         gint ret = FALSE ;
244         ImageFrameTimeAxisGroup* iftag = 0 ;
245
246         switch (event->type)
247         {
248                 case GDK_BUTTON_PRESS:
249                 case GDK_2BUTTON_PRESS:
250                 case GDK_3BUTTON_PRESS:
251                         clicked_axisview = &ifv->get_time_axis_view() ;
252                         iftag = ifv->get_time_axis_group() ;
253                         dynamic_cast<ImageFrameTimeAxis*>(clicked_axisview)->get_view()->set_selected_imageframe_view(iftag, ifv);
254
255                         ret = button_press_handler (item, event, ImageFrameHandleEndItem) ;
256                         break ;
257                 case GDK_BUTTON_RELEASE:
258                         ret = button_release_handler (item, event, ImageFrameHandleEndItem) ;
259                         break ;
260                 case GDK_MOTION_NOTIFY:
261                         ret = motion_handler (item, event, ImageFrameHandleEndItem) ;
262                         break ;
263                 case GDK_ENTER_NOTIFY:
264                         ret = enter_handler (item, event, ImageFrameHandleEndItem) ;
265                         break ;
266                 case GDK_LEAVE_NOTIFY:
267                         ret = leave_handler (item, event, ImageFrameHandleEndItem);
268                         break ;
269                 default:
270                         break ;
271         }
272         return(ret) ;
273 }
274
275 bool
276 Editor::canvas_imageframe_view_event (GdkEvent* event, ArdourCanvas::Item* item, ImageFrameTimeAxis* ifta)
277 {
278         gint ret = FALSE ;
279         switch (event->type)
280         {
281                 case GDK_BUTTON_PRESS:
282                 case GDK_2BUTTON_PRESS:
283                 case GDK_3BUTTON_PRESS:
284                         clicked_axisview = ifta ;
285                         ret = button_press_handler (item, event, ImageFrameTimeAxisItem) ;
286                         break ;
287                 case GDK_BUTTON_RELEASE:
288                         ret = button_release_handler (item, event, ImageFrameTimeAxisItem) ;
289                         break ;
290                 case GDK_MOTION_NOTIFY:
291                         break ;
292                 default:
293                         break ;
294         }
295         return(ret) ;
296 }
297
298 bool
299 Editor::canvas_marker_time_axis_view_event (GdkEvent* event, ArdourCanvas::Item* item, MarkerTimeAxis* mta)
300 {
301         gint ret = FALSE ;
302         switch (event->type)
303         {
304                 case GDK_BUTTON_PRESS:
305                 case GDK_2BUTTON_PRESS:
306                 case GDK_3BUTTON_PRESS:
307                         clicked_axisview = mta ;
308                         ret = button_press_handler(item, event, MarkerTimeAxisItem) ;
309                         break ;
310                 case GDK_BUTTON_RELEASE:
311                         ret = button_release_handler(item, event, MarkerTimeAxisItem) ;
312                         break ;
313                 case GDK_MOTION_NOTIFY:
314                 default:
315                         break ;
316         }
317         return(ret) ;
318 }
319
320
321 bool
322 Editor::canvas_markerview_item_view_event (GdkEvent* event, ArdourCanvas::Item* item, MarkerView* mta)
323 {
324         gint ret = FALSE ;
325         switch (event->type)
326         {
327                 case GDK_BUTTON_PRESS:
328                 case GDK_2BUTTON_PRESS:
329                 case GDK_3BUTTON_PRESS:
330                         clicked_axisview = &mta->get_time_axis_view() ;
331                         dynamic_cast<MarkerTimeAxis*>(clicked_axisview)->get_view()->set_selected_time_axis_item(mta);
332                         ret = button_press_handler(item, event, MarkerViewItem) ;
333                         break ;
334                 case GDK_BUTTON_RELEASE:
335                         ret = button_release_handler(item, event, MarkerViewItem) ;
336                         break ;
337                 case GDK_MOTION_NOTIFY:
338                         ret = motion_handler(item, event, MarkerViewItem) ;
339                         break ;
340                 default:
341                         break ;
342         }
343         return(ret) ;
344 }
345
346 bool
347 Editor::canvas_markerview_start_handle_event (GdkEvent* event, ArdourCanvas::Item* item, MarkerView* mta)
348 {
349         gint ret = FALSE ;
350         switch (event->type)
351         {
352                 case GDK_BUTTON_PRESS:
353                 case GDK_2BUTTON_PRESS:
354                 case GDK_3BUTTON_PRESS:
355                         clicked_axisview = &mta->get_time_axis_view() ;
356                         dynamic_cast<MarkerTimeAxis*>(clicked_axisview)->get_view()->set_selected_time_axis_item(mta) ;
357                         ret = button_press_handler(item, event, MarkerViewHandleStartItem) ;
358                         break ;
359                 case GDK_BUTTON_RELEASE:
360                         ret = button_release_handler(item, event, MarkerViewHandleStartItem) ;
361                         break ;
362                 case GDK_MOTION_NOTIFY:
363                         ret = motion_handler(item, event, MarkerViewHandleStartItem) ;
364                         break ;
365                 case GDK_ENTER_NOTIFY:
366                         ret = enter_handler(item, event, MarkerViewHandleStartItem) ;
367                         break ;
368                 case GDK_LEAVE_NOTIFY:
369                         ret = leave_handler(item, event, MarkerViewHandleStartItem) ;
370                         break ;
371                 default:
372                         break ;
373         }
374         return(ret) ;
375 }
376
377 bool
378 Editor::canvas_markerview_end_handle_event (GdkEvent* event, ArdourCanvas::Item* item, MarkerView* mta)
379 {
380         gint ret = FALSE ;
381         switch (event->type)
382         {
383                 case GDK_BUTTON_PRESS:
384                 case GDK_2BUTTON_PRESS:
385                 case GDK_3BUTTON_PRESS:
386                         clicked_axisview = &mta->get_time_axis_view() ;
387                         dynamic_cast<MarkerTimeAxis*>(clicked_axisview)->get_view()->set_selected_time_axis_item(mta) ;
388                         ret = button_press_handler(item, event, MarkerViewHandleEndItem) ;
389                         break ;
390                 case GDK_BUTTON_RELEASE:
391                         ret = button_release_handler(item, event, MarkerViewHandleEndItem) ;
392                         break ;
393                 case GDK_MOTION_NOTIFY:
394                         ret = motion_handler(item, event, MarkerViewHandleEndItem) ;
395                         break ;
396                 case GDK_ENTER_NOTIFY:
397                         ret = enter_handler(item, event, MarkerViewHandleEndItem) ;
398                         break ;
399                 case GDK_LEAVE_NOTIFY:
400                         ret = leave_handler(item, event, MarkerViewHandleEndItem) ;
401                         break ;
402                 default:
403                         break ;
404         }
405         return(ret) ;
406 }
407
408
409 /* </CMT Additions file="editor_canvas_events.cc"> */
410
411
412 /*
413         ---------------------------------------------------------------------------------------------------
414         ---------------------------------------------------------------------------------------------------
415         ---------------------------------------------------------------------------------------------------
416 */
417
418
419
420 /* <CMT Additions file="editor_mouse.cc"> */
421
422 void
423 Editor::start_imageframe_grab(ArdourCanvas::Item* item, GdkEvent* event)
424 {
425         ImageFrameView* ifv = ((ImageFrameTimeAxis*)clicked_axisview)->get_view()->get_selected_imageframe_view() ;
426         drag_info.copy = false ;
427         drag_info.item = item ;
428         drag_info.data = ifv ;
429         drag_info.motion_callback = &Editor::imageframe_drag_motion_callback;
430         drag_info.finished_callback = &Editor::timeaxis_item_drag_finished_callback;
431         drag_info.last_frame_position = ifv->get_position() ;
432
433         drag_info.source_trackview = &ifv->get_time_axis_view() ;
434         drag_info.dest_trackview = drag_info.source_trackview;
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.source_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.source_trackview = &mv->get_time_axis_view() ;
468         drag_info.dest_trackview = drag_info.source_trackview;
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.source_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         nframes64_t pending_region_position ;
497         nframes64_t pointer_frame ;
498
499         pointer_frame = event_frame(event, &cx, &cy) ;
500
501         snap_to(pointer_frame) ;
502
503         if (pointer_frame > (nframes64_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         nframes64_t pending_region_position;
545         nframes64_t pointer_frame;
546
547         pointer_frame = event_frame(event, &cx, &cy) ;
548
549         snap_to(pointer_frame) ;
550
551         if (pointer_frame > (nframes64_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         nframes64_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_axisview) ;
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_axisview) ;
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         nframes64_t start = 0 ;
678         nframes64_t end = 0 ;
679         nframes64_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                         nframes64_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                 nframes64_t temp = ifv->get_position() + ifv->get_duration() ;
755
756                 ifv->set_position((nframes64_t) (temp - drag_info.cumulative_x_drag), this) ;
757                 ifv->set_duration((nframes64_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         nframes64_t start = 0 ;
767         nframes64_t end = 0 ;
768         nframes64_t pointer_frame = event_frame(event) ;
769         nframes64_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                 nframes64_t new_duration = (nframes64_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_axisview)->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_axisview)->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         nframes64_t start = 0 ;
892         nframes64_t end = 0 ;
893         nframes64_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                         nframes64_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                 nframes64_t temp = mv->get_position() + mv->get_duration() ;
972
973                 mv->set_position((nframes64_t) (temp - drag_info.cumulative_x_drag), this) ;
974                 mv->set_duration((nframes64_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         nframes64_t start = 0 ;
984         nframes64_t end = 0 ;
985         nframes64_t pointer_frame = event_frame(event) ;
986         nframes64_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                         nframes64_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                 nframes64_t new_duration = (nframes64_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         scoped_connect (iftav->GoingAway, boost::bind (&Editor::remove_route, this, (TimeAxisView*)iftav));
1096         iftav->gui_changed.connect(sigc::mem_fun(*this, &Editor::handle_gui_changes)) ;
1097 }
1098
1099 void
1100 Editor::handle_new_imageframe_marker_time_axis_view(const string & track_name, TimeAxisView* marked_track)
1101 {
1102         MarkerTimeAxis* mta = new MarkerTimeAxis (*this, *this->session(), *track_canvas, track_name, marked_track) ;
1103         ((ImageFrameTimeAxis*)marked_track)->add_marker_time_axis(mta, this) ;
1104         track_views.push_back(mta) ;
1105
1106         TreeModel::Row row = *(route_display_model->append());
1107
1108         row[route_display_columns.text] = mta->name();
1109         row[route_display_columns.tv] = mta;
1110         route_list_display.get_selection()->select (row);
1111
1112         scoped_connect (mta->GoingAway, boost::bind (&Editor::remove_route, this, (TimeAxisView*)mta));
1113  }
1114
1115
1116 /* </CMT Additions file="editor_route_list.cc"> */