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