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