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