make all of dialog visible for add_route_dialog
[ardour.git] / gtk2_ardour / editor_canvas.cc
1 /*
2     Copyright (C) 2005 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <libgnomecanvasmm/init.h>
22 #include <jack/types.h>
23
24 #include "ardour_ui.h"
25 #include "editor.h"
26 #include "waveview.h"
27 #include "simplerect.h"
28 #include "simpleline.h"
29 #include "imageframe.h"
30 #include "waveview_p.h"
31 #include "simplerect_p.h"
32 #include "simpleline_p.h"
33 #include "imageframe_p.h"
34 #include "canvas_impl.h"
35 #include "editing.h"
36 #include "rgb_macros.h"
37 #include "utils.h"
38 #include "time_axis_view.h"
39
40 #include "i18n.h"
41
42 using namespace std;
43 using namespace sigc;
44 using namespace ARDOUR;
45 using namespace Gtk;
46 using namespace Glib;
47 using namespace Gtkmm2ext;
48 using namespace Editing;
49
50 /* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */
51
52 const double max_canvas_coordinate = (double) JACK_MAX_FRAMES;
53
54 extern "C"
55 {
56
57 GType gnome_canvas_simpleline_get_type(void);
58 GType gnome_canvas_simplerect_get_type(void);
59 GType gnome_canvas_waveview_get_type(void);
60 GType gnome_canvas_imageframe_get_type(void);
61
62 }
63
64 static void ardour_canvas_type_init() 
65 {
66         // Map gtypes to gtkmm wrapper-creation functions:
67         
68         Glib::wrap_register(gnome_canvas_simpleline_get_type(), &Gnome::Canvas::SimpleLine_Class::wrap_new);
69         Glib::wrap_register(gnome_canvas_simplerect_get_type(), &Gnome::Canvas::SimpleRect_Class::wrap_new);
70         Glib::wrap_register(gnome_canvas_waveview_get_type(), &Gnome::Canvas::WaveView_Class::wrap_new);
71         Glib::wrap_register(gnome_canvas_imageframe_get_type(), &Gnome::Canvas::ImageFrame_Class::wrap_new);
72         
73         // Register the gtkmm gtypes:
74
75         (void) Gnome::Canvas::WaveView::get_type();
76         (void) Gnome::Canvas::SimpleLine::get_type();
77         (void) Gnome::Canvas::SimpleRect::get_type();
78         (void) Gnome::Canvas::ImageFrame::get_type();
79
80
81 void
82 Editor::initialize_canvas ()
83 {
84         ArdourCanvas::init ();
85         ardour_canvas_type_init ();
86
87         /* don't try to center the canvas */
88
89         track_canvas.set_center_scroll_region (false);
90
91         track_canvas.signal_event().connect (bind (mem_fun (*this, &Editor::track_canvas_event), (ArdourCanvas::Item*) 0));
92         track_canvas.set_name ("EditorMainCanvas");
93         track_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
94         track_canvas.signal_leave_notify_event().connect (mem_fun(*this, &Editor::left_track_canvas));
95         
96         /* set up drag-n-drop */
97         vector<Gtk::TargetEntry> target_table;
98         
99         target_table.push_back (TargetEntry ("STRING"));
100         target_table.push_back (TargetEntry ("text/plain"));
101         target_table.push_back (TargetEntry ("text/uri-list"));
102         target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
103
104         // GTK2FIX
105         // track_canvas.drag_dest_set (target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
106         // track_canvas.signal_drag_data_received().connect (mem_fun(*this, &Editor::track_canvas_drag_data_received));
107
108         /* stuff for the verbose canvas cursor */
109
110         Pango::FontDescription font = get_font_for_style (N_("VerboseCanvasCursor"));
111
112         verbose_canvas_cursor = new ArdourCanvas::Text (*track_canvas.root());
113         verbose_canvas_cursor->property_font_desc() = font;
114         // GTK2FIX
115         // verbose_canvas_cursor->property_anchor() = GTK_ANCHOR_NW;
116         verbose_canvas_cursor->property_fill_color_rgba() = color_map[cVerboseCanvasCursor];
117         
118         verbose_cursor_visible = false;
119         
120         /* a group to hold time (measure) lines */
121         
122         time_line_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
123         cursor_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
124         
125         time_canvas.set_name ("EditorTimeCanvas");
126         time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
127         
128         meter_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0);
129         tempo_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0);
130         marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 2.0);
131         range_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 3.0);
132         transport_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 4.0);
133         
134         tempo_bar = new ArdourCanvas::SimpleRect (*tempo_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
135         tempo_bar->property_fill_color_rgba() = color_map[cTempoBar];
136         tempo_bar->property_outline_pixels() = 0;
137         
138         meter_bar = new ArdourCanvas::SimpleRect (*meter_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
139         meter_bar->property_fill_color_rgba() = color_map[cMeterBar];
140         meter_bar->property_outline_pixels() = 0;
141         
142         marker_bar = new ArdourCanvas::SimpleRect (*marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
143         marker_bar->property_fill_color_rgba() = color_map[cMarkerBar];
144         marker_bar->property_outline_pixels() = 0;
145         
146         range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
147         range_marker_bar->property_fill_color_rgba() = color_map[cRangeMarkerBar];
148         range_marker_bar->property_outline_pixels() = 0;
149         
150         transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
151         transport_marker_bar->property_fill_color_rgba() = color_map[cTransportMarkerBar];
152         transport_marker_bar->property_outline_pixels() = 0;
153         
154         range_bar_drag_rect = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
155         range_bar_drag_rect->property_fill_color_rgba() = color_map[cRangeDragBarRectFill];
156         range_bar_drag_rect->property_outline_color_rgba() = color_map[cRangeDragBarRect];
157         range_bar_drag_rect->property_outline_pixels() = 0;
158         range_bar_drag_rect->hide ();
159         
160         transport_bar_drag_rect = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
161         transport_bar_drag_rect ->property_fill_color_rgba() = color_map[cTransportDragRectFill];
162         transport_bar_drag_rect->property_outline_color_rgba() = color_map[cTransportDragRect];
163         transport_bar_drag_rect->property_outline_pixels() = 0;
164         transport_bar_drag_rect->hide ();
165         
166         marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0));
167         marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0));
168
169         marker_drag_line = new ArdourCanvas::Line (*track_canvas.root());
170         marker_drag_line->property_width_pixels() = 1;
171         marker_drag_line->property_fill_color_rgba() = color_map[cMarkerDragLine];
172         marker_drag_line->property_points() = marker_drag_line_points;
173         marker_drag_line->hide();
174
175         range_marker_drag_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
176         range_marker_drag_rect->property_fill_color_rgba() = color_map[cRangeDragRectFill];
177         range_marker_drag_rect->property_outline_color_rgba() = color_map[cRangeDragRect];
178         range_marker_drag_rect->hide ();
179         
180         transport_loop_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
181         transport_loop_range_rect->property_fill_color_rgba() = color_map[cTransportLoopRectFill];
182         transport_loop_range_rect->property_outline_color_rgba() = color_map[cTransportLoopRect];
183         transport_loop_range_rect->property_outline_pixels() = 1;
184         transport_loop_range_rect->hide();
185
186         transport_punch_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
187         transport_punch_range_rect->property_fill_color_rgba() = color_map[cTransportPunchRectFill];
188         transport_punch_range_rect->property_outline_color_rgba() = color_map[cTransportPunchRect];
189         transport_punch_range_rect->property_outline_pixels() = 0;
190         transport_punch_range_rect->hide();
191         
192         transport_loop_range_rect->lower_to_bottom (); // loop on the bottom
193
194         transport_punchin_line = new ArdourCanvas::SimpleLine (*time_line_group);
195         transport_punchin_line->property_x1() = 0.0;
196         transport_punchin_line->property_y1() = 0.0;
197         transport_punchin_line->property_x2() = 0.0;
198         transport_punchin_line->property_y2() = 0.0;
199         transport_punchin_line->property_color_rgba() = color_map[cPunchInLine];
200         transport_punchin_line->hide ();
201         
202         transport_punchout_line  = new ArdourCanvas::SimpleLine (*time_line_group);
203         transport_punchout_line->property_x1() = 0.0;
204         transport_punchout_line->property_y1() = 0.0;
205         transport_punchout_line->property_x2() = 0.0;
206         transport_punchout_line->property_y2() = 0.0;
207         transport_punchout_line->property_color_rgba() = color_map[cPunchOutLine];
208         transport_punchout_line->hide();
209         
210         // used to show zoom mode active zooming
211         zoom_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
212         zoom_rect->property_fill_color_rgba() = color_map[cZoomRectFill];
213         zoom_rect->property_outline_color_rgba() = color_map[cZoomRect];
214         zoom_rect->property_outline_pixels() = 1;
215         zoom_rect->hide();
216         
217         zoom_rect->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
218         
219         // used as rubberband rect
220         rubberband_rect = new ArdourCanvas::SimpleRect (*track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
221         rubberband_rect->property_outline_color_rgba() = color_map[cRubberBandRect];
222         rubberband_rect->property_fill_color_rgba() = (guint32) color_map[cRubberBandRectFill];
223         rubberband_rect->property_outline_pixels() = 1;
224         rubberband_rect->hide();
225         
226         tempo_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
227         meter_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
228         marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
229         range_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
230         transport_marker_bar->signal_event().connect (bind (mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
231         
232         /* separator lines */
233         
234         tempo_line = new ArdourCanvas::SimpleLine (*tempo_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
235         tempo_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
236
237         meter_line = new ArdourCanvas::SimpleLine (*meter_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
238         meter_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
239
240         marker_line = new ArdourCanvas::SimpleLine (*marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
241         marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
242         
243         range_marker_line = new ArdourCanvas::SimpleLine (*range_marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
244         range_marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
245
246         transport_marker_line = new ArdourCanvas::SimpleLine (*transport_marker_group, 0, timebar_height, max_canvas_coordinate, timebar_height);
247         transport_marker_line->property_color_rgba() = RGBA_TO_UINT (0,0,0,255);
248
249         ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_loop_range_view), false));
250         ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_punch_range_view), false));
251         
252         double time_height = timebar_height * 5;
253         double time_width = FLT_MAX/frames_per_unit;
254         time_canvas.set_scroll_region(0.0, 0.0, time_width, time_height);
255         
256         edit_cursor = new Cursor (*this, "blue", &Editor::canvas_edit_cursor_event);
257         playhead_cursor = new Cursor (*this, "red", &Editor::canvas_playhead_cursor_event);
258         
259         track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate));
260 }
261
262 void
263 Editor::track_canvas_allocate (Gtk::Allocation alloc)
264 {
265         static bool first_time = true;
266
267         canvas_width = alloc.get_width();
268         canvas_height = alloc.get_height();
269
270         if (session == 0 && !ARDOUR_UI::instance()->will_create_new_session_automatically()) {
271
272                 Pango::FontDescription font = get_font_for_style (N_("FirstActionMessage"));
273
274                 cerr << "font for style = "
275                      << font.get_family() << ' '
276                      << font.get_size() << ' '
277                      << font.get_weight() << ' '
278                      << font.get_variant() << ' '
279                      << endmsg;
280
281                 const char *txt1 = _("Start a new session\n");
282                 const char *txt2 = _("via Session menu");
283
284                 /* this mess of code is here to find out how wide this text is and
285                    position the message in the center of the editor window. there
286                    are two lines, so we use the longer of the the lines to
287                    compute width, and multiply the height by 2.
288                 */
289                         
290                 int pixel_height;
291                 int pixel_width;
292                 
293                 /* this is a dummy widget that exists so that we can get the
294                    style from the RC file. 
295                 */
296                 
297                 Label foo (_(txt2));
298                 Glib::RefPtr<Pango::Layout> layout;
299
300                 top_hbox.pack_start (foo);
301                 foo.set_name ("FirstActionMessage");
302                 foo.ensure_style ();
303
304                 layout = foo.create_pango_layout (_(txt2));
305                 layout->set_font_description (font);
306                 layout->set_font_description (font);
307                 layout->get_pixel_size (pixel_width, pixel_height);
308                         
309                 top_hbox.remove (foo);
310
311                 if (first_action_message == 0) {
312                         
313                         char txt[strlen(txt1)+strlen(txt2)+1];
314                         
315                         /* merge both lines */
316                         
317                         strcpy (txt, _(txt1));
318                         strcat (txt, _(txt2));
319                         
320                         first_action_message = new ArdourCanvas::Text (*track_canvas.root());
321                         first_action_message->property_font_desc() = font;
322                         first_action_message->property_fill_color_rgba() = color_map[cFirstActionMessage];
323                         first_action_message->property_x() = (gdouble) (canvas_width - pixel_width) / 2.0;
324                         first_action_message->property_y() = (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height));
325                         first_action_message->property_anchor() = ANCHOR_NORTH_WEST;
326                         first_action_message->property_text() = ustring (txt);
327                         
328                 } else {
329
330                         /* center it */
331                         first_action_message->property_x() = (gdouble) (canvas_width - pixel_width) / 2.0;
332                         first_action_message->property_y() = (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height));
333                 }
334         }
335
336         zoom_range_clock.set ((jack_nframes_t) (canvas_width * frames_per_unit));
337         edit_cursor->set_position (edit_cursor->current_frame);
338         playhead_cursor->set_position (playhead_cursor->current_frame);
339         reset_scrolling_region (&alloc);
340
341         if (edit_cursor) edit_cursor->set_length (canvas_height);
342         if (playhead_cursor) playhead_cursor->set_length (canvas_height);
343
344         if (marker_drag_line) {
345                 marker_drag_line_points.back().set_x(canvas_height);
346                 marker_drag_line->property_points() = marker_drag_line_points;
347         }
348
349         if (range_marker_drag_rect) {
350                 range_marker_drag_rect->property_y1() = 0.0;
351                 range_marker_drag_rect->property_y2() = (double) canvas_height;
352         }
353
354         if (transport_loop_range_rect) {
355                 transport_loop_range_rect->property_y1() = 0.0;
356                 transport_loop_range_rect->property_y2() = (double) canvas_height;
357         }
358
359         if (transport_punch_range_rect) {
360                 transport_punch_range_rect->property_y1() = 0.0;
361                 transport_punch_range_rect->property_y2() = (double) canvas_height;
362         }
363
364         if (transport_punchin_line) {
365                 transport_punchin_line->property_y1() = 0.0;
366                 transport_punchin_line->property_y2() = (double) canvas_height;
367         }
368
369         if (transport_punchout_line) {
370                 transport_punchout_line->property_y1() = 0.0;
371                 transport_punchout_line->property_y2() = (double) canvas_height;
372         }
373                 
374         update_fixed_rulers ();
375
376         if (is_visible() && first_time) {
377                 tempo_map_changed (Change (0));
378                 first_time = false;
379         } else {
380                 redisplay_tempo ();
381         }
382         
383         Resized (); /* EMIT_SIGNAL */
384 }
385
386 void
387 Editor::reset_scrolling_region (Gtk::Allocation* alloc)
388 {
389         guint32 last_canvas_unit;
390         double height;
391         guint32 canvas_alloc_height, canvas_alloc_width;
392         TrackViewList::iterator i;
393
394         /* We need to make sure that the canvas always has its
395            scrolling region set to larger of:
396
397            - the size allocated for it (within the container its packed in)
398            - the size required to see the entire session
399
400            If we don't ensure at least the first of these, the canvas
401            does some wierd and in my view unnecessary stuff to center
402            itself within the allocated area, which causes bad, bad
403            results.
404            
405            XXX GnomeCanvas has fixed this, and has an option to
406            control the centering behaviour.
407         */
408
409 #if 0
410         last_canvas_unit = (guint32) ceil ((float) max_frames / frames_per_unit);
411
412         height = 0;
413
414         if (session) {
415                 for (i = track_views.begin(); i != track_views.end(); ++i) {
416                         if ((*i)->control_parent) {
417                                 height += (*i)->effective_height;
418                                 height += track_spacing;
419                         }
420                 }
421                 
422                 if (height) {
423                         height -= track_spacing;
424                 }
425         }
426
427         canvas_height = (guint32) height;
428 #endif
429         
430         if (alloc) {
431                 canvas_alloc_height = alloc->get_height();
432                 canvas_alloc_width = alloc->get_width();
433         } else {
434                 canvas_alloc_height = track_canvas.get_height();
435                 canvas_alloc_width = track_canvas.get_width();
436         }
437
438         canvas_height = 0;
439         canvas_height = max (canvas_height, canvas_alloc_height);
440         track_canvas.set_scroll_region ( 0.0, 0.0, max (last_canvas_unit, canvas_alloc_width), canvas_height);
441 }
442
443 bool
444 Editor::track_canvas_map_handler (GdkEventAny* ev)
445 {
446         track_canvas_scroller.get_window()->set_cursor (*current_canvas_cursor);
447         return false;
448 }
449
450 bool
451 Editor::time_canvas_map_handler (GdkEventAny* ev)
452 {
453         time_canvas_scroller.get_window()->set_cursor (*timebar_cursor);
454         return false;
455 }
456