~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to gtk2_ardour/editor.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2000-2009 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
*/
 
19
 
 
20
/* Note: public Editor methods are documented in public_editor.h */
 
21
 
 
22
#include <stdint.h>
 
23
#include <unistd.h>
 
24
#include <cstdlib>
 
25
#include <cmath>
 
26
#include <string>
 
27
#include <algorithm>
 
28
#include <map>
 
29
 
 
30
#include "ardour_ui.h"
 
31
/*
 
32
 * ardour_ui.h include was moved to the top of the list
 
33
 * due to a conflicting definition of 'Style' between
 
34
 * Apple's MacTypes.h and BarController.
 
35
 */
 
36
 
 
37
#include <boost/none.hpp>
 
38
 
 
39
#include <sigc++/bind.h>
 
40
 
 
41
#include "pbd/convert.h"
 
42
#include "pbd/error.h"
 
43
#include "pbd/enumwriter.h"
 
44
#include "pbd/memento_command.h"
 
45
#include "pbd/unknown_type.h"
 
46
#include "pbd/unwind.h"
 
47
#include "pbd/stacktrace.h"
 
48
 
 
49
#include <glibmm/miscutils.h>
 
50
#include <gtkmm/image.h>
 
51
#include <gdkmm/color.h>
 
52
#include <gdkmm/bitmap.h>
 
53
 
 
54
#include "gtkmm2ext/bindings.h"
 
55
#include "gtkmm2ext/grouped_buttons.h"
 
56
#include "gtkmm2ext/gtk_ui.h"
 
57
#include "gtkmm2ext/tearoff.h"
 
58
#include "gtkmm2ext/utils.h"
 
59
#include "gtkmm2ext/window_title.h"
 
60
#include "gtkmm2ext/choice.h"
 
61
#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
 
62
 
 
63
#include "ardour/audio_track.h"
 
64
#include "ardour/audioengine.h"
 
65
#include "ardour/audioregion.h"
 
66
#include "ardour/location.h"
 
67
#include "ardour/profile.h"
 
68
#include "ardour/route_group.h"
 
69
#include "ardour/session_playlists.h"
 
70
#include "ardour/tempo.h"
 
71
#include "ardour/utils.h"
 
72
 
 
73
#include "control_protocol/control_protocol.h"
 
74
 
 
75
#include "actions.h"
 
76
#include "actions.h"
 
77
#include "analysis_window.h"
 
78
#include "audio_clock.h"
 
79
#include "audio_region_view.h"
 
80
#include "audio_streamview.h"
 
81
#include "audio_time_axis.h"
 
82
#include "automation_time_axis.h"
 
83
#include "bundle_manager.h"
 
84
#include "canvas-noevent-text.h"
 
85
#include "canvas_impl.h"
 
86
#include "crossfade_edit.h"
 
87
#include "debug.h"
 
88
#include "editing.h"
 
89
#include "editor.h"
 
90
#include "editor_cursors.h"
 
91
#include "editor_drag.h"
 
92
#include "editor_group_tabs.h"
 
93
#include "editor_locations.h"
 
94
#include "editor_regions.h"
 
95
#include "editor_route_groups.h"
 
96
#include "editor_routes.h"
 
97
#include "editor_snapshots.h"
 
98
#include "editor_summary.h"
 
99
#include "global_port_matrix.h"
 
100
#include "gui_object.h"
 
101
#include "gui_thread.h"
 
102
#include "keyboard.h"
 
103
#include "marker.h"
 
104
#include "midi_time_axis.h"
 
105
#include "mixer_strip.h"
 
106
#include "mixer_ui.h"
 
107
#include "mouse_cursors.h"
 
108
#include "playlist_selector.h"
 
109
#include "public_editor.h"
 
110
#include "region_layering_order_editor.h"
 
111
#include "rgb_macros.h"
 
112
#include "rhythm_ferret.h"
 
113
#include "selection.h"
 
114
#include "sfdb_ui.h"
 
115
#include "simpleline.h"
 
116
#include "tempo_lines.h"
 
117
#include "time_axis_view.h"
 
118
#include "utils.h"
 
119
 
 
120
#include "i18n.h"
 
121
 
 
122
using namespace std;
 
123
using namespace ARDOUR;
 
124
using namespace PBD;
 
125
using namespace Gtk;
 
126
using namespace Glib;
 
127
using namespace Gtkmm2ext;
 
128
using namespace Editing;
 
129
 
 
130
using PBD::internationalize;
 
131
using PBD::atoi;
 
132
using Gtkmm2ext::Keyboard;
 
133
 
 
134
const double Editor::timebar_height = 15.0;
 
135
 
 
136
static const gchar *_snap_type_strings[] = {
 
137
        N_("CD Frames"),
 
138
        N_("Timecode Frames"),
 
139
        N_("Timecode Seconds"),
 
140
        N_("Timecode Minutes"),
 
141
        N_("Seconds"),
 
142
        N_("Minutes"),
 
143
        N_("Beats/128"),
 
144
        N_("Beats/64"),
 
145
        N_("Beats/32"),
 
146
        N_("Beats/28"),
 
147
        N_("Beats/24"),
 
148
        N_("Beats/20"),
 
149
        N_("Beats/16"),
 
150
        N_("Beats/14"),
 
151
        N_("Beats/12"),
 
152
        N_("Beats/10"),
 
153
        N_("Beats/8"),
 
154
        N_("Beats/7"),
 
155
        N_("Beats/6"),
 
156
        N_("Beats/5"),
 
157
        N_("Beats/4"),
 
158
        N_("Beats/3"),
 
159
        N_("Beats/2"),
 
160
        N_("Beats"),
 
161
        N_("Bars"),
 
162
        N_("Marks"),
 
163
        N_("Region starts"),
 
164
        N_("Region ends"),
 
165
        N_("Region syncs"),
 
166
        N_("Region bounds"),
 
167
        0
 
168
};
 
169
 
 
170
static const gchar *_snap_mode_strings[] = {
 
171
        N_("No Grid"),
 
172
        N_("Grid"),
 
173
        N_("Magnetic"),
 
174
        0
 
175
};
 
176
 
 
177
static const gchar *_edit_point_strings[] = {
 
178
        N_("Playhead"),
 
179
        N_("Marker"),
 
180
        N_("Mouse"),
 
181
        0
 
182
};
 
183
 
 
184
static const gchar *_zoom_focus_strings[] = {
 
185
        N_("Left"),
 
186
        N_("Right"),
 
187
        N_("Center"),
 
188
        N_("Playhead"),
 
189
        N_("Mouse"),
 
190
        N_("Edit point"),
 
191
        0
 
192
};
 
193
 
 
194
#ifdef USE_RUBBERBAND
 
195
static const gchar *_rb_opt_strings[] = {
 
196
        N_("Mushy"),
 
197
        N_("Smooth"),
 
198
        N_("Balanced multitimbral mixture"),
 
199
        N_("Unpitched percussion with stable notes"),
 
200
        N_("Crisp monophonic instrumental"),
 
201
        N_("Unpitched solo percussion"),
 
202
        N_("Resample without preserving pitch"),
 
203
        0
 
204
};
 
205
#endif
 
206
 
 
207
static void
 
208
pane_size_watcher (Paned* pane)
 
209
{
 
210
        /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
 
211
           it is:
 
212
 
 
213
              X: hard to access
 
214
              Quartz: impossible to access
 
215
              
 
216
           so stop that by preventing it from ever getting too narrow. 35
 
217
           pixels is basically a rough guess at the tab width.
 
218
 
 
219
           ugh.
 
220
        */
 
221
 
 
222
        int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
 
223
 
 
224
        gint pos = pane->get_position ();
 
225
 
 
226
        if (pos > max_width_of_lhs) {
 
227
                pane->set_position (max_width_of_lhs);
 
228
        }
 
229
}
 
230
 
 
231
Editor::Editor ()
 
232
        : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
 
233
 
 
234
          /* time display buttons */
 
235
        , minsec_label (_("Mins:Secs"))
 
236
        , bbt_label (_("Bars:Beats"))
 
237
        , timecode_label (_("Timecode"))
 
238
        , samples_label (_("Samples"))
 
239
        , tempo_label (_("Tempo"))
 
240
        , meter_label (_("Meter"))
 
241
        , mark_label (_("Location Markers"))
 
242
        , range_mark_label (_("Range Markers"))
 
243
        , transport_mark_label (_("Loop/Punch Ranges"))
 
244
        , cd_mark_label (_("CD Markers"))
 
245
        , videotl_label (_("Video Timeline"))
 
246
        , edit_packer (4, 4, true)
 
247
 
 
248
          /* the values here don't matter: layout widgets
 
249
             reset them as needed.
 
250
          */
 
251
 
 
252
        , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
 
253
 
 
254
          /* tool bar related */
 
255
 
 
256
        , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
 
257
 
 
258
        , toolbar_selection_clock_table (2,3)
 
259
 
 
260
        , automation_mode_button (_("mode"))
 
261
 
 
262
        , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
 
263
 
 
264
          /* nudge */
 
265
 
 
266
        , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
 
267
        , meters_running(false)
 
268
        , _pending_locate_request (false)
 
269
        , _pending_initial_locate (false)
 
270
        , _last_cut_copy_source_track (0)
 
271
 
 
272
        , _region_selection_change_updates_region_list (true)
 
273
        , _following_mixer_selection (false)
 
274
        , _control_point_toggled_on_press (false)
 
275
        , _stepping_axis_view (0)
 
276
{
 
277
        constructed = false;
 
278
 
 
279
        /* we are a singleton */
 
280
 
 
281
        PublicEditor::_instance = this;
 
282
 
 
283
        _have_idled = false;
 
284
 
 
285
        selection = new Selection (this);
 
286
        cut_buffer = new Selection (this);
 
287
 
 
288
        clicked_regionview = 0;
 
289
        clicked_axisview = 0;
 
290
        clicked_routeview = 0;
 
291
        clicked_control_point = 0;
 
292
        last_update_frame = 0;
 
293
        pre_press_cursor = 0;
 
294
        _drags = new DragManager (this);
 
295
        current_mixer_strip = 0;
 
296
        tempo_lines = 0;
 
297
 
 
298
        snap_type_strings =  I18N (_snap_type_strings);
 
299
        snap_mode_strings =  I18N (_snap_mode_strings);
 
300
        zoom_focus_strings = I18N (_zoom_focus_strings);
 
301
        edit_point_strings = I18N (_edit_point_strings);
 
302
#ifdef USE_RUBBERBAND
 
303
        rb_opt_strings = I18N (_rb_opt_strings);
 
304
        rb_current_opt = 4;
 
305
#endif
 
306
 
 
307
        snap_threshold = 5.0;
 
308
        bbt_beat_subdivision = 4;
 
309
        _canvas_width = 0;
 
310
        _canvas_height = 0;
 
311
        last_autoscroll_x = 0;
 
312
        last_autoscroll_y = 0;
 
313
        autoscroll_active = false;
 
314
        autoscroll_timeout_tag = -1;
 
315
        logo_item = 0;
 
316
 
 
317
        analysis_window = 0;
 
318
 
 
319
        current_interthread_info = 0;
 
320
        _show_measures = true;
 
321
        _maximised = false;
 
322
        show_gain_after_trim = false;
 
323
 
 
324
        have_pending_keyboard_selection = false;
 
325
        _follow_playhead = true;
 
326
        _stationary_playhead = false;
 
327
        editor_ruler_menu = 0;
 
328
        no_ruler_shown_update = false;
 
329
        marker_menu = 0;
 
330
        range_marker_menu = 0;
 
331
        marker_menu_item = 0;
 
332
        tempo_or_meter_marker_menu = 0;
 
333
        transport_marker_menu = 0;
 
334
        new_transport_marker_menu = 0;
 
335
        editor_mixer_strip_width = Wide;
 
336
        show_editor_mixer_when_tracks_arrive = false;
 
337
        region_edit_menu_split_multichannel_item = 0;
 
338
        region_edit_menu_split_item = 0;
 
339
        temp_location = 0;
 
340
        leftmost_frame = 0;
 
341
        current_stepping_trackview = 0;
 
342
        entered_track = 0;
 
343
        entered_regionview = 0;
 
344
        entered_marker = 0;
 
345
        clear_entered_track = false;
 
346
        current_timefx = 0;
 
347
        playhead_cursor = 0;
 
348
        button_release_can_deselect = true;
 
349
        _dragging_playhead = false;
 
350
        _dragging_edit_point = false;
 
351
        select_new_marker = false;
 
352
        rhythm_ferret = 0;
 
353
        layering_order_editor = 0;
 
354
        no_save_visual = false;
 
355
        resize_idle_id = -1;
 
356
        within_track_canvas = false;
 
357
 
 
358
        scrubbing_direction = 0;
 
359
 
 
360
        sfbrowser = 0;
 
361
 
 
362
        location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
 
363
        location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
 
364
        location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
 
365
        location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
 
366
        location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
 
367
 
 
368
        _edit_point = EditAtMouse;
 
369
        _internal_editing = false;
 
370
        current_canvas_cursor = 0;
 
371
 
 
372
        frames_per_unit = 2048; /* too early to use reset_zoom () */
 
373
 
 
374
        _scroll_callbacks = 0;
 
375
 
 
376
        zoom_focus = ZoomFocusLeft;
 
377
        set_zoom_focus (ZoomFocusLeft);
 
378
        zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
 
379
 
 
380
        bbt_label.set_name ("EditorRulerLabel");
 
381
        bbt_label.set_size_request (-1, (int)timebar_height);
 
382
        bbt_label.set_alignment (1.0, 0.5);
 
383
        bbt_label.set_padding (5,0);
 
384
        bbt_label.hide ();
 
385
        bbt_label.set_no_show_all();
 
386
        minsec_label.set_name ("EditorRulerLabel");
 
387
        minsec_label.set_size_request (-1, (int)timebar_height);
 
388
        minsec_label.set_alignment (1.0, 0.5);
 
389
        minsec_label.set_padding (5,0);
 
390
        minsec_label.hide ();
 
391
        minsec_label.set_no_show_all();
 
392
        timecode_label.set_name ("EditorRulerLabel");
 
393
        timecode_label.set_size_request (-1, (int)timebar_height);
 
394
        timecode_label.set_alignment (1.0, 0.5);
 
395
        timecode_label.set_padding (5,0);
 
396
        timecode_label.hide ();
 
397
        timecode_label.set_no_show_all();
 
398
        samples_label.set_name ("EditorRulerLabel");
 
399
        samples_label.set_size_request (-1, (int)timebar_height);
 
400
        samples_label.set_alignment (1.0, 0.5);
 
401
        samples_label.set_padding (5,0);
 
402
        samples_label.hide ();
 
403
        samples_label.set_no_show_all();
 
404
 
 
405
        tempo_label.set_name ("EditorRulerLabel");
 
406
        tempo_label.set_size_request (-1, (int)timebar_height);
 
407
        tempo_label.set_alignment (1.0, 0.5);
 
408
        tempo_label.set_padding (5,0);
 
409
        tempo_label.hide();
 
410
        tempo_label.set_no_show_all();
 
411
 
 
412
        meter_label.set_name ("EditorRulerLabel");
 
413
        meter_label.set_size_request (-1, (int)timebar_height);
 
414
        meter_label.set_alignment (1.0, 0.5);
 
415
        meter_label.set_padding (5,0);
 
416
        meter_label.hide();
 
417
        meter_label.set_no_show_all();
 
418
 
 
419
        mark_label.set_name ("EditorRulerLabel");
 
420
        mark_label.set_size_request (-1, (int)timebar_height);
 
421
        mark_label.set_alignment (1.0, 0.5);
 
422
        mark_label.set_padding (5,0);
 
423
        mark_label.hide();
 
424
        mark_label.set_no_show_all();
 
425
 
 
426
        cd_mark_label.set_name ("EditorRulerLabel");
 
427
        cd_mark_label.set_size_request (-1, (int)timebar_height);
 
428
        cd_mark_label.set_alignment (1.0, 0.5);
 
429
        cd_mark_label.set_padding (5,0);
 
430
        cd_mark_label.hide();
 
431
        cd_mark_label.set_no_show_all();
 
432
 
 
433
        videotl_bar_height = 4;
 
434
        videotl_label.set_name ("EditorRulerLabel");
 
435
        videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
 
436
        videotl_label.set_alignment (1.0, 0.5);
 
437
        videotl_label.set_padding (5,0);
 
438
        videotl_label.hide();
 
439
        videotl_label.set_no_show_all();
 
440
 
 
441
        range_mark_label.set_name ("EditorRulerLabel");
 
442
        range_mark_label.set_size_request (-1, (int)timebar_height);
 
443
        range_mark_label.set_alignment (1.0, 0.5);
 
444
        range_mark_label.set_padding (5,0);
 
445
        range_mark_label.hide();
 
446
        range_mark_label.set_no_show_all();
 
447
 
 
448
        transport_mark_label.set_name ("EditorRulerLabel");
 
449
        transport_mark_label.set_size_request (-1, (int)timebar_height);
 
450
        transport_mark_label.set_alignment (1.0, 0.5);
 
451
        transport_mark_label.set_padding (5,0);
 
452
        transport_mark_label.hide();
 
453
        transport_mark_label.set_no_show_all();
 
454
 
 
455
        initialize_rulers ();
 
456
        initialize_canvas ();
 
457
 
 
458
        _summary = new EditorSummary (this);
 
459
 
 
460
        selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
 
461
        selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
 
462
 
 
463
        editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
 
464
 
 
465
        selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
 
466
        selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
 
467
 
 
468
        edit_controls_vbox.set_spacing (0);
 
469
        vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
 
470
        track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
 
471
 
 
472
        HBox* h = manage (new HBox);
 
473
        _group_tabs = new EditorGroupTabs (this);
 
474
        h->pack_start (*_group_tabs, PACK_SHRINK);
 
475
        h->pack_start (edit_controls_vbox);
 
476
        controls_layout.add (*h);
 
477
 
 
478
        controls_layout.set_name ("EditControlsBase");
 
479
        controls_layout.add_events (Gdk::SCROLL_MASK);
 
480
        controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
 
481
 
 
482
        controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
 
483
        controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
 
484
 
 
485
        _cursors = new MouseCursors;
 
486
 
 
487
        ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
 
488
        ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
 
489
                        0.0, 1.0, 100.0, 1.0));
 
490
 
 
491
        pad_line_1->property_color_rgba() = 0xFF0000FF;
 
492
        pad_line_1->show();
 
493
 
 
494
        time_pad->show();
 
495
 
 
496
        time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
 
497
        time_canvas_vbox.set_size_request (-1, -1);
 
498
 
 
499
        ruler_label_event_box.add (ruler_label_vbox);
 
500
        ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
 
501
        ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
 
502
 
 
503
        time_button_event_box.add (time_button_vbox);
 
504
        time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
 
505
        time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
 
506
 
 
507
        /* these enable us to have a dedicated window (for cursor setting, etc.)
 
508
           for the canvas areas.
 
509
        */
 
510
 
 
511
        track_canvas_event_box.add (*track_canvas);
 
512
 
 
513
        time_canvas_event_box.add (time_canvas_vbox);
 
514
        time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
 
515
 
 
516
        edit_packer.set_col_spacings (0);
 
517
        edit_packer.set_row_spacings (0);
 
518
        edit_packer.set_homogeneous (false);
 
519
        edit_packer.set_border_width (0);
 
520
        edit_packer.set_name ("EditorWindow");
 
521
 
 
522
        /* labels for the rulers */
 
523
        edit_packer.attach (ruler_label_event_box,   1, 2, 0, 1,    FILL,        SHRINK, 0, 0);
 
524
        /* labels for the marker "tracks" */
 
525
        edit_packer.attach (time_button_event_box,   1, 2, 1, 2,    FILL,        SHRINK, 0, 0);
 
526
        /* the rulers */
 
527
        edit_packer.attach (time_canvas_event_box,   2, 3, 0, 1,    FILL|EXPAND, FILL, 0, 0);
 
528
        /* track controls */
 
529
        edit_packer.attach (controls_layout,         0, 2, 2, 3,    FILL,        FILL|EXPAND, 0, 0);
 
530
        /* main canvas */
 
531
        edit_packer.attach (track_canvas_event_box,  2, 3, 1, 3,    FILL|EXPAND, FILL|EXPAND, 0, 0);
 
532
 
 
533
        bottom_hbox.set_border_width (2);
 
534
        bottom_hbox.set_spacing (3);
 
535
 
 
536
        _route_groups = new EditorRouteGroups (this);
 
537
        _routes = new EditorRoutes (this);
 
538
        _regions = new EditorRegions (this);
 
539
        _snapshots = new EditorSnapshots (this);
 
540
        _locations = new EditorLocations (this);
 
541
 
 
542
        add_notebook_page (_("Regions"), _regions->widget ());
 
543
        add_notebook_page (_("Tracks & Busses"), _routes->widget ());
 
544
        add_notebook_page (_("Snapshots"), _snapshots->widget ());
 
545
        add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
 
546
        add_notebook_page (_("Ranges & Marks"), _locations->widget ());
 
547
 
 
548
        _the_notebook.set_show_tabs (true);
 
549
        _the_notebook.set_scrollable (true);
 
550
        _the_notebook.popup_disable ();
 
551
        _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
 
552
        _the_notebook.show_all ();
 
553
 
 
554
        _notebook_shrunk = false;
 
555
 
 
556
        editor_summary_pane.pack1(edit_packer);
 
557
 
 
558
        Button* summary_arrows_left_left = manage (new Button);
 
559
        summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
 
560
        summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
 
561
        summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
 
562
 
 
563
        Button* summary_arrows_left_right = manage (new Button);
 
564
        summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
 
565
        summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
 
566
        summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
 
567
 
 
568
        VBox* summary_arrows_left = manage (new VBox);
 
569
        summary_arrows_left->pack_start (*summary_arrows_left_left);
 
570
        summary_arrows_left->pack_start (*summary_arrows_left_right);
 
571
 
 
572
        Button* summary_arrows_right_up = manage (new Button);
 
573
        summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
 
574
        summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
 
575
        summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
 
576
 
 
577
        Button* summary_arrows_right_down = manage (new Button);
 
578
        summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
 
579
        summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
 
580
        summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
 
581
 
 
582
        VBox* summary_arrows_right = manage (new VBox);
 
583
        summary_arrows_right->pack_start (*summary_arrows_right_up);
 
584
        summary_arrows_right->pack_start (*summary_arrows_right_down);
 
585
 
 
586
        Frame* summary_frame = manage (new Frame);
 
587
        summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
 
588
 
 
589
        summary_frame->add (*_summary);
 
590
        summary_frame->show ();
 
591
 
 
592
        _summary_hbox.pack_start (*summary_arrows_left, false, false);
 
593
        _summary_hbox.pack_start (*summary_frame, true, true);
 
594
        _summary_hbox.pack_start (*summary_arrows_right, false, false);
 
595
 
 
596
        editor_summary_pane.pack2 (_summary_hbox);
 
597
 
 
598
        edit_pane.pack1 (editor_summary_pane, true, true);
 
599
        edit_pane.pack2 (_the_notebook, false, true);
 
600
 
 
601
        editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
 
602
 
 
603
        /* XXX: editor_summary_pane might need similar to the edit_pane */
 
604
 
 
605
        edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
 
606
 
 
607
        Glib::PropertyProxy<int> proxy = edit_pane.property_position();
 
608
        proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
 
609
 
 
610
        top_hbox.pack_start (toolbar_frame);
 
611
 
 
612
        HBox *hbox = manage (new HBox);
 
613
        hbox->pack_start (edit_pane, true, true);
 
614
 
 
615
        global_vpacker.pack_start (top_hbox, false, false);
 
616
        global_vpacker.pack_start (*hbox, true, true);
 
617
 
 
618
        global_hpacker.pack_start (global_vpacker, true, true);
 
619
 
 
620
        set_name ("EditorWindow");
 
621
        add_accel_group (ActionManager::ui_manager->get_accel_group());
 
622
 
 
623
        status_bar_hpacker.show ();
 
624
 
 
625
        vpacker.pack_end (status_bar_hpacker, false, false);
 
626
        vpacker.pack_end (global_hpacker, true, true);
 
627
 
 
628
        /* register actions now so that set_state() can find them and set toggles/checks etc */
 
629
 
 
630
        register_actions ();
 
631
        /* when we start using our own keybinding system for the editor, this
 
632
         * will be uncommented
 
633
         */
 
634
        // load_bindings ();
 
635
 
 
636
        setup_toolbar ();
 
637
 
 
638
        _snap_type = SnapToBeat;
 
639
        set_snap_to (_snap_type);
 
640
        _snap_mode = SnapOff;
 
641
        set_snap_mode (_snap_mode);
 
642
        set_mouse_mode (MouseObject, true);
 
643
        pre_internal_mouse_mode = MouseObject;
 
644
        pre_internal_snap_type = _snap_type;
 
645
        pre_internal_snap_mode = _snap_mode;
 
646
        internal_snap_type = _snap_type;
 
647
        internal_snap_mode = _snap_mode;
 
648
        set_edit_point_preference (EditAtMouse, true);
 
649
 
 
650
        _playlist_selector = new PlaylistSelector();
 
651
        _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
 
652
 
 
653
        RegionView::RegionViewGoingAway.connect (*this, invalidator (*this),  boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
 
654
 
 
655
        /* nudge stuff */
 
656
 
 
657
        nudge_forward_button.set_name ("zoom button");
 
658
        nudge_forward_button.add_elements (ArdourButton::FlatFace);
 
659
        nudge_forward_button.set_image(::get_icon("nudge_right"));
 
660
 
 
661
        nudge_backward_button.set_name ("zoom button");
 
662
        nudge_backward_button.add_elements (ArdourButton::FlatFace);
 
663
        nudge_backward_button.set_image(::get_icon("nudge_left"));
 
664
 
 
665
        fade_context_menu.set_name ("ArdourContextMenu");
 
666
 
 
667
        /* icons, titles, WM stuff */
 
668
 
 
669
        list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
 
670
        Glib::RefPtr<Gdk::Pixbuf> icon;
 
671
 
 
672
        if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
 
673
                window_icons.push_back (icon);
 
674
        }
 
675
        if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
 
676
                window_icons.push_back (icon);
 
677
        }
 
678
        if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
 
679
                window_icons.push_back (icon);
 
680
        }
 
681
        if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
 
682
                window_icons.push_back (icon);
 
683
        }
 
684
        if (!window_icons.empty()) {
 
685
                // set_icon_list (window_icons);
 
686
                set_default_icon_list (window_icons);
 
687
        }
 
688
 
 
689
        WindowTitle title(Glib::get_application_name());
 
690
        title += _("Editor");
 
691
        set_title (title.get_string());
 
692
        set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
 
693
 
 
694
        add (vpacker);
 
695
        add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
 
696
 
 
697
        signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
 
698
        signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
 
699
 
 
700
        Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
 
701
        
 
702
        /* allow external control surfaces/protocols to do various things */
 
703
 
 
704
        ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
 
705
        ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
 
706
        ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
 
707
        ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
 
708
        ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
 
709
        ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
 
710
        ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
 
711
        ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
 
712
        ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
 
713
        ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
 
714
        ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
 
715
        ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
 
716
        ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
 
717
        ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
 
718
 
 
719
        ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
 
720
        ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
 
721
        ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
 
722
        ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
 
723
        ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
 
724
 
 
725
        BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
 
726
 
 
727
        /* problematic: has to return a value and thus cannot be x-thread */
 
728
 
 
729
        Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
 
730
 
 
731
        Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
 
732
 
 
733
        TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
 
734
 
 
735
        _ignore_region_action = false;
 
736
        _last_region_menu_was_main = false;
 
737
        _popup_region_menu_item = 0;
 
738
 
 
739
        _show_marker_lines = false;
 
740
        _over_region_trim_target = false;
 
741
 
 
742
        /* Button bindings */
 
743
 
 
744
        button_bindings = new Bindings;
 
745
 
 
746
        XMLNode* node = button_settings();
 
747
        if (node) {
 
748
                for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
 
749
                        button_bindings->load (**i);
 
750
                }
 
751
        }
 
752
 
 
753
        constructed = true;
 
754
        instant_save ();
 
755
 
 
756
        setup_fade_images ();
 
757
}
 
758
 
 
759
Editor::~Editor()
 
760
{
 
761
        delete button_bindings;
 
762
        delete _routes;
 
763
        delete _route_groups;
 
764
        delete track_canvas;
 
765
        delete _drags;
 
766
}
 
767
 
 
768
XMLNode*
 
769
Editor::button_settings () const
 
770
{
 
771
        XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
 
772
        XMLNode* node = find_named_node (*settings, X_("Buttons"));
 
773
 
 
774
        if (!node) {
 
775
                node = new XMLNode (X_("Buttons"));
 
776
        }
 
777
 
 
778
        return node;
 
779
}
 
780
 
 
781
void
 
782
Editor::add_toplevel_controls (Container& cont)
 
783
{
 
784
        vpacker.pack_start (cont, false, false);
 
785
        cont.show_all ();
 
786
}
 
787
 
 
788
bool
 
789
Editor::get_smart_mode () const
 
790
{
 
791
        return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
 
792
}
 
793
 
 
794
void
 
795
Editor::catch_vanishing_regionview (RegionView *rv)
 
796
{
 
797
        /* note: the selection will take care of the vanishing
 
798
           audioregionview by itself.
 
799
        */
 
800
 
 
801
        if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
 
802
                _drags->abort ();
 
803
        }
 
804
 
 
805
        if (clicked_regionview == rv) {
 
806
                clicked_regionview = 0;
 
807
        }
 
808
 
 
809
        if (entered_regionview == rv) {
 
810
                set_entered_regionview (0);
 
811
        }
 
812
 
 
813
        if (!_all_region_actions_sensitized) {
 
814
                sensitize_all_region_actions (true);
 
815
        }
 
816
 
 
817
        _over_region_trim_target = false;
 
818
}
 
819
 
 
820
void
 
821
Editor::set_entered_regionview (RegionView* rv)
 
822
{
 
823
        if (rv == entered_regionview) {
 
824
                return;
 
825
        }
 
826
 
 
827
        if (entered_regionview) {
 
828
                entered_regionview->exited ();
 
829
        }
 
830
 
 
831
        if ((entered_regionview = rv) != 0) {
 
832
                entered_regionview->entered (internal_editing ());
 
833
        }
 
834
 
 
835
        if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
 
836
                /* This RegionView entry might have changed what region actions
 
837
                   are allowed, so sensitize them all in case a key is pressed.
 
838
                */
 
839
                sensitize_all_region_actions (true);
 
840
        }
 
841
}
 
842
 
 
843
void
 
844
Editor::set_entered_track (TimeAxisView* tav)
 
845
{
 
846
        if (entered_track) {
 
847
                entered_track->exited ();
 
848
        }
 
849
 
 
850
        if ((entered_track = tav) != 0) {
 
851
                entered_track->entered ();
 
852
        }
 
853
}
 
854
 
 
855
void
 
856
Editor::show_window ()
 
857
{
 
858
        if (!is_visible ()) {
 
859
                show_all ();
 
860
 
 
861
                /* XXX: this is a bit unfortunate; it would probably
 
862
                   be nicer if we could just call show () above rather
 
863
                   than needing the show_all ()
 
864
                */
 
865
 
 
866
                /* re-hide stuff if necessary */
 
867
                editor_list_button_toggled ();
 
868
                parameter_changed ("show-summary");
 
869
                parameter_changed ("show-group-tabs");
 
870
                parameter_changed ("show-zoom-tools");
 
871
 
 
872
                /* now reset all audio_time_axis heights, because widgets might need
 
873
                   to be re-hidden
 
874
                */
 
875
 
 
876
                TimeAxisView *tv;
 
877
 
 
878
                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
 
879
                        tv = (static_cast<TimeAxisView*>(*i));
 
880
                        tv->reset_height ();
 
881
                }
 
882
 
 
883
                if (current_mixer_strip) {
 
884
                        current_mixer_strip->hide_things ();
 
885
                        current_mixer_strip->parameter_changed ("mixer-strip-visibility");
 
886
                }
 
887
        }
 
888
 
 
889
        present ();
 
890
}
 
891
 
 
892
void
 
893
Editor::instant_save ()
 
894
{
 
895
        if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
 
896
                return;
 
897
        }
 
898
 
 
899
        if (_session) {
 
900
                _session->add_instant_xml(get_state());
 
901
        } else {
 
902
                Config->add_instant_xml(get_state());
 
903
        }
 
904
}
 
905
 
 
906
void
 
907
Editor::zoom_adjustment_changed ()
 
908
{
 
909
        if (_session == 0) {
 
910
                return;
 
911
        }
 
912
 
 
913
        double fpu = zoom_range_clock->current_duration() / _canvas_width;
 
914
        bool clamped = clamp_frames_per_unit (fpu);
 
915
        
 
916
        if (clamped) {
 
917
                zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
 
918
        }
 
919
 
 
920
        temporal_zoom (fpu);
 
921
}
 
922
 
 
923
void
 
924
Editor::control_vertical_zoom_in_all ()
 
925
{
 
926
        tav_zoom_smooth (false, true);
 
927
}
 
928
 
 
929
void
 
930
Editor::control_vertical_zoom_out_all ()
 
931
{
 
932
        tav_zoom_smooth (true, true);
 
933
}
 
934
 
 
935
void
 
936
Editor::control_vertical_zoom_in_selected ()
 
937
{
 
938
        tav_zoom_smooth (false, false);
 
939
}
 
940
 
 
941
void
 
942
Editor::control_vertical_zoom_out_selected ()
 
943
{
 
944
        tav_zoom_smooth (true, false);
 
945
}
 
946
 
 
947
void
 
948
Editor::control_view (uint32_t view)
 
949
{
 
950
        goto_visual_state (view);
 
951
}
 
952
 
 
953
void
 
954
Editor::control_unselect ()
 
955
{
 
956
        selection->clear_tracks ();
 
957
}
 
958
 
 
959
void
 
960
Editor::control_select (uint32_t rid, Selection::Operation op) 
 
961
{
 
962
        /* handles the (static) signal from the ControlProtocol class that
 
963
         * requests setting the selected track to a given RID
 
964
         */
 
965
         
 
966
        if (!_session) {
 
967
                return;
 
968
        }
 
969
 
 
970
        boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
 
971
 
 
972
        if (!r) {
 
973
                return;
 
974
        }
 
975
 
 
976
        TimeAxisView* tav = axis_view_from_route (r);
 
977
 
 
978
        if (tav) {
 
979
                switch (op) {
 
980
                case Selection::Add:
 
981
                        selection->add (tav);
 
982
                        break;
 
983
                case Selection::Toggle:
 
984
                        selection->toggle (tav);
 
985
                        break;
 
986
                case Selection::Extend:
 
987
                        break;
 
988
                case Selection::Set:
 
989
                        selection->set (tav);
 
990
                        break;
 
991
                }
 
992
        } else {
 
993
                selection->clear_tracks ();
 
994
        }
 
995
}
 
996
 
 
997
void
 
998
Editor::control_step_tracks_up ()
 
999
{
 
1000
        scroll_tracks_up_line ();
 
1001
}
 
1002
 
 
1003
void
 
1004
Editor::control_step_tracks_down ()
 
1005
{
 
1006
        scroll_tracks_down_line ();
 
1007
}
 
1008
 
 
1009
void
 
1010
Editor::control_scroll (float fraction)
 
1011
{
 
1012
        ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
 
1013
 
 
1014
        if (!_session) {
 
1015
                return;
 
1016
        }
 
1017
 
 
1018
        double step = fraction * current_page_frames();
 
1019
 
 
1020
        /*
 
1021
                _control_scroll_target is an optional<T>
 
1022
 
 
1023
                it acts like a pointer to an framepos_t, with
 
1024
                a operator conversion to boolean to check
 
1025
                that it has a value could possibly use
 
1026
                playhead_cursor->current_frame to store the
 
1027
                value and a boolean in the class to know
 
1028
                when it's out of date
 
1029
        */
 
1030
 
 
1031
        if (!_control_scroll_target) {
 
1032
                _control_scroll_target = _session->transport_frame();
 
1033
                _dragging_playhead = true;
 
1034
        }
 
1035
 
 
1036
        if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
 
1037
                *_control_scroll_target = 0;
 
1038
        } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
 
1039
                *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
 
1040
        } else {
 
1041
                *_control_scroll_target += (framepos_t) floor (step);
 
1042
        }
 
1043
 
 
1044
        /* move visuals, we'll catch up with it later */
 
1045
 
 
1046
        playhead_cursor->set_position (*_control_scroll_target);
 
1047
        UpdateAllTransportClocks (*_control_scroll_target);
 
1048
 
 
1049
        if (*_control_scroll_target > (current_page_frames() / 2)) {
 
1050
                /* try to center PH in window */
 
1051
                reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
 
1052
        } else {
 
1053
                reset_x_origin (0);
 
1054
        }
 
1055
 
 
1056
        /*
 
1057
                Now we do a timeout to actually bring the session to the right place
 
1058
                according to the playhead. This is to avoid reading disk buffers on every
 
1059
                call to control_scroll, which is driven by ScrollTimeline and therefore
 
1060
                probably by a control surface wheel which can generate lots of events.
 
1061
        */
 
1062
        /* cancel the existing timeout */
 
1063
 
 
1064
        control_scroll_connection.disconnect ();
 
1065
 
 
1066
        /* add the next timeout */
 
1067
 
 
1068
        control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
 
1069
}
 
1070
 
 
1071
bool
 
1072
Editor::deferred_control_scroll (framepos_t /*target*/)
 
1073
{
 
1074
        _session->request_locate (*_control_scroll_target, _session->transport_rolling());
 
1075
        // reset for next stream
 
1076
        _control_scroll_target = boost::none;
 
1077
        _dragging_playhead = false;
 
1078
        return false;
 
1079
}
 
1080
 
 
1081
void
 
1082
Editor::access_action (std::string action_group, std::string action_item)
 
1083
{
 
1084
        if (!_session) {
 
1085
                return;
 
1086
        }
 
1087
 
 
1088
        ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
 
1089
 
 
1090
        RefPtr<Action> act;
 
1091
        act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
 
1092
 
 
1093
        if (act) {
 
1094
                act->activate();
 
1095
        }
 
1096
}
 
1097
 
 
1098
void
 
1099
Editor::on_realize ()
 
1100
{
 
1101
        Window::on_realize ();
 
1102
        Realized ();
 
1103
}
 
1104
 
 
1105
void
 
1106
Editor::map_position_change (framepos_t frame)
 
1107
{
 
1108
        ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
 
1109
 
 
1110
        if (_session == 0) {
 
1111
                return;
 
1112
        }
 
1113
 
 
1114
        if (_follow_playhead) {
 
1115
                center_screen (frame);
 
1116
        }
 
1117
 
 
1118
        playhead_cursor->set_position (frame);
 
1119
}
 
1120
 
 
1121
void
 
1122
Editor::center_screen (framepos_t frame)
 
1123
{
 
1124
        double page = _canvas_width * frames_per_unit;
 
1125
 
 
1126
        /* if we're off the page, then scroll.
 
1127
         */
 
1128
 
 
1129
        if (frame < leftmost_frame || frame >= leftmost_frame + page) {
 
1130
                center_screen_internal (frame, page);
 
1131
        }
 
1132
}
 
1133
 
 
1134
void
 
1135
Editor::center_screen_internal (framepos_t frame, float page)
 
1136
{
 
1137
        page /= 2;
 
1138
 
 
1139
        if (frame > page) {
 
1140
                frame -= (framepos_t) page;
 
1141
        } else {
 
1142
                frame = 0;
 
1143
        }
 
1144
 
 
1145
        reset_x_origin (frame);
 
1146
}
 
1147
 
 
1148
 
 
1149
void
 
1150
Editor::update_title ()
 
1151
{
 
1152
        ENSURE_GUI_THREAD (*this, &Editor::update_title)
 
1153
 
 
1154
        if (_session) {
 
1155
                bool dirty = _session->dirty();
 
1156
 
 
1157
                string session_name;
 
1158
 
 
1159
                if (_session->snap_name() != _session->name()) {
 
1160
                        session_name = _session->snap_name();
 
1161
                } else {
 
1162
                        session_name = _session->name();
 
1163
                }
 
1164
 
 
1165
                if (dirty) {
 
1166
                        session_name = "*" + session_name;
 
1167
                }
 
1168
 
 
1169
                WindowTitle title(session_name);
 
1170
                title += Glib::get_application_name();
 
1171
                set_title (title.get_string());
 
1172
        } else {
 
1173
                /* ::session_going_away() will have taken care of it */
 
1174
        }
 
1175
}
 
1176
 
 
1177
void
 
1178
Editor::set_session (Session *t)
 
1179
{
 
1180
        SessionHandlePtr::set_session (t);
 
1181
 
 
1182
        if (!_session) {
 
1183
                return;
 
1184
        }
 
1185
 
 
1186
        zoom_range_clock->set_session (_session);
 
1187
        _playlist_selector->set_session (_session);
 
1188
        nudge_clock->set_session (_session);
 
1189
        _summary->set_session (_session);
 
1190
        _group_tabs->set_session (_session);
 
1191
        _route_groups->set_session (_session);
 
1192
        _regions->set_session (_session);
 
1193
        _snapshots->set_session (_session);
 
1194
        _routes->set_session (_session);
 
1195
        _locations->set_session (_session);
 
1196
 
 
1197
        if (rhythm_ferret) {
 
1198
                rhythm_ferret->set_session (_session);
 
1199
        }
 
1200
 
 
1201
        if (analysis_window) {
 
1202
                analysis_window->set_session (_session);
 
1203
        }
 
1204
 
 
1205
        if (sfbrowser) {
 
1206
                sfbrowser->set_session (_session);
 
1207
        }
 
1208
 
 
1209
        compute_fixed_ruler_scale ();
 
1210
 
 
1211
        /* Make sure we have auto loop and auto punch ranges */
 
1212
 
 
1213
        Location* loc = _session->locations()->auto_loop_location();
 
1214
        if (loc == 0) {
 
1215
                loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
 
1216
 
 
1217
                if (loc->start() == loc->end()) {
 
1218
                        loc->set_end (loc->start() + 1);
 
1219
                }
 
1220
 
 
1221
                _session->locations()->add (loc, false);
 
1222
                _session->set_auto_loop_location (loc);
 
1223
        } else {
 
1224
                // force name
 
1225
                loc->set_name (_("Loop"));
 
1226
        }
 
1227
 
 
1228
        loc = _session->locations()->auto_punch_location();
 
1229
 
 
1230
        if (loc == 0) {
 
1231
                loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
 
1232
 
 
1233
                if (loc->start() == loc->end()) {
 
1234
                        loc->set_end (loc->start() + 1);
 
1235
                }
 
1236
 
 
1237
                _session->locations()->add (loc, false);
 
1238
                _session->set_auto_punch_location (loc);
 
1239
        } else {
 
1240
                // force name
 
1241
                loc->set_name (_("Punch"));
 
1242
        }
 
1243
 
 
1244
        refresh_location_display ();
 
1245
 
 
1246
        /* This must happen after refresh_location_display(), as (amongst other things) we restore
 
1247
           the selected Marker; this needs the LocationMarker list to be available.
 
1248
        */
 
1249
        XMLNode* node = ARDOUR_UI::instance()->editor_settings();
 
1250
        set_state (*node, Stateful::loading_state_version);
 
1251
 
 
1252
        /* catch up with the playhead */
 
1253
 
 
1254
        _session->request_locate (playhead_cursor->current_frame);
 
1255
        _pending_initial_locate = true;
 
1256
 
 
1257
        update_title ();
 
1258
 
 
1259
        /* These signals can all be emitted by a non-GUI thread. Therefore the
 
1260
           handlers for them must not attempt to directly interact with the GUI,
 
1261
           but use Gtkmm2ext::UI::instance()->call_slot();
 
1262
        */
 
1263
 
 
1264
        _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
 
1265
        _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
 
1266
        _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
 
1267
        _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
 
1268
        _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
 
1269
        _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
 
1270
        _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
 
1271
        _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
 
1272
        _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
 
1273
        _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
 
1274
        _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
 
1275
        _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
 
1276
        _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
 
1277
        _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
 
1278
 
 
1279
        playhead_cursor->canvas_item.show ();
 
1280
 
 
1281
        boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
 
1282
        Config->map_parameters (pc);
 
1283
        _session->config.map_parameters (pc);
 
1284
 
 
1285
        restore_ruler_visibility ();
 
1286
        //tempo_map_changed (PropertyChange (0));
 
1287
        _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
 
1288
 
 
1289
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
 
1290
                (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
 
1291
        }
 
1292
 
 
1293
        super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
 
1294
                sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
 
1295
                );
 
1296
 
 
1297
        switch (_snap_type) {
 
1298
        case SnapToRegionStart:
 
1299
        case SnapToRegionEnd:
 
1300
        case SnapToRegionSync:
 
1301
        case SnapToRegionBoundary:
 
1302
                build_region_boundary_cache ();
 
1303
                break;
 
1304
 
 
1305
        default:
 
1306
                break;
 
1307
        }
 
1308
 
 
1309
        /* register for undo history */
 
1310
        _session->register_with_memento_command_factory(id(), this);
 
1311
 
 
1312
        ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
 
1313
 
 
1314
        start_updating_meters ();
 
1315
}
 
1316
 
 
1317
void
 
1318
Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
 
1319
{
 
1320
        if (a->get_name() == "RegionMenu") {
 
1321
                /* When the main menu's region menu is opened, we setup the actions so that they look right
 
1322
                   in the menu.  I can't find a way of getting a signal when this menu is subsequently closed,
 
1323
                   so we resensitize all region actions when the entered regionview or the region selection
 
1324
                   changes.  HOWEVER we can't always resensitize on entered_regionview change because that
 
1325
                   happens after the region context menu is opened.  So we set a flag here, too.
 
1326
 
 
1327
                   What a carry on :(
 
1328
                */
 
1329
                sensitize_the_right_region_actions ();
 
1330
                _last_region_menu_was_main = true;
 
1331
        }
 
1332
}
 
1333
 
 
1334
void
 
1335
Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
 
1336
{
 
1337
        using namespace Menu_Helpers;
 
1338
 
 
1339
        void (Editor::*emf)(FadeShape);
 
1340
        std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
 
1341
 
 
1342
        if (start) {
 
1343
                images = &_xfade_in_images;
 
1344
                emf = &Editor::set_fade_in_shape;
 
1345
        } else {
 
1346
                images = &_xfade_out_images;
 
1347
                emf = &Editor::set_fade_out_shape;
 
1348
        }
 
1349
 
 
1350
        items.push_back (
 
1351
                ImageMenuElem (
 
1352
                        _("Linear (for highly correlated material)"),
 
1353
                        *(*images)[FadeLinear],
 
1354
                        sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
 
1355
                        )
 
1356
                );
 
1357
        
 
1358
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1359
        
 
1360
        items.push_back (
 
1361
                ImageMenuElem (
 
1362
                        _("Constant power"),
 
1363
                        *(*images)[FadeConstantPower],
 
1364
                        sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
 
1365
                        ));
 
1366
        
 
1367
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1368
        
 
1369
        items.push_back (
 
1370
                ImageMenuElem (
 
1371
                        _("Symmetric"),
 
1372
                        *(*images)[FadeSymmetric],
 
1373
                        sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
 
1374
                        )
 
1375
                );
 
1376
        
 
1377
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1378
        
 
1379
        items.push_back (
 
1380
                ImageMenuElem (
 
1381
                        _("Slow"),
 
1382
                        *(*images)[FadeSlow],
 
1383
                        sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
 
1384
                        ));
 
1385
        
 
1386
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1387
        
 
1388
        items.push_back (
 
1389
                ImageMenuElem (
 
1390
                        _("Fast"),
 
1391
                        *(*images)[FadeFast],
 
1392
                        sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
 
1393
                        ));
 
1394
        
 
1395
        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1396
}
 
1397
 
 
1398
/** Pop up a context menu for when the user clicks on a start crossfade */
 
1399
void
 
1400
Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
 
1401
{
 
1402
        using namespace Menu_Helpers;
 
1403
 
 
1404
        MenuList& items (xfade_in_context_menu.items());
 
1405
 
 
1406
        if (items.empty()) {
 
1407
                fill_xfade_menu (items, true);
 
1408
        }
 
1409
 
 
1410
        xfade_in_context_menu.popup (button, time);
 
1411
}
 
1412
 
 
1413
/** Pop up a context menu for when the user clicks on an end crossfade */
 
1414
void
 
1415
Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
 
1416
{
 
1417
        using namespace Menu_Helpers;
 
1418
 
 
1419
        MenuList& items (xfade_out_context_menu.items());
 
1420
 
 
1421
        if (items.empty()) {
 
1422
                fill_xfade_menu (items, false);
 
1423
        }
 
1424
 
 
1425
        xfade_out_context_menu.popup (button, time);
 
1426
}
 
1427
 
 
1428
 
 
1429
/** Pop up a context menu for when the user clicks on a fade in or fade out */
 
1430
void
 
1431
Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
 
1432
{
 
1433
        using namespace Menu_Helpers;
 
1434
        AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
 
1435
 
 
1436
        if (arv == 0) {
 
1437
                fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
 
1438
                /*NOTREACHED*/
 
1439
        }
 
1440
 
 
1441
        MenuList& items (fade_context_menu.items());
 
1442
        items.clear ();
 
1443
 
 
1444
        switch (item_type) {
 
1445
        case FadeInItem:
 
1446
        case FadeInHandleItem:
 
1447
                if (arv->audio_region()->fade_in_active()) {
 
1448
                        items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
 
1449
                } else {
 
1450
                        items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
 
1451
                }
 
1452
                
 
1453
                items.push_back (SeparatorElem());
 
1454
                
 
1455
                if (Profile->get_sae()) {
 
1456
                        
 
1457
                        items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
 
1458
                        items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
 
1459
                        
 
1460
                } else {
 
1461
                        
 
1462
                        items.push_back (
 
1463
                                ImageMenuElem (
 
1464
                                        _("Linear"),
 
1465
                                        *_fade_in_images[FadeLinear],
 
1466
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
 
1467
                                        )
 
1468
                                );
 
1469
                                
 
1470
                        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1471
                                
 
1472
                        items.push_back (
 
1473
                                ImageMenuElem (
 
1474
                                        _("Slow"),
 
1475
                                        *_fade_in_images[FadeSlow],
 
1476
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
 
1477
                                        ));
 
1478
                                
 
1479
                        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1480
                                
 
1481
                        items.push_back (
 
1482
                                ImageMenuElem (
 
1483
                                        _("Fast"),
 
1484
                                        *_fade_in_images[FadeFast],
 
1485
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
 
1486
                                        ));
 
1487
                                
 
1488
                        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1489
                                
 
1490
                        items.push_back (
 
1491
                                ImageMenuElem (
 
1492
                                        _("Symmetric"),
 
1493
                                        *_fade_in_images[FadeSymmetric],
 
1494
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
 
1495
                                        ));
 
1496
                                
 
1497
                        items.push_back (
 
1498
                                ImageMenuElem (
 
1499
                                        _("Constant power"),
 
1500
                                        *_fade_in_images[FadeConstantPower],
 
1501
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
 
1502
                                        ));
 
1503
 
 
1504
                        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1505
                }
 
1506
 
 
1507
                break;
 
1508
 
 
1509
        case FadeOutItem:
 
1510
        case FadeOutHandleItem:
 
1511
                if (arv->audio_region()->fade_out_active()) {
 
1512
                        items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
 
1513
                } else {
 
1514
                        items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
 
1515
                }
 
1516
 
 
1517
                items.push_back (SeparatorElem());
 
1518
 
 
1519
                if (Profile->get_sae()) {
 
1520
                        items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
 
1521
                        items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
 
1522
                } else {
 
1523
 
 
1524
                        items.push_back (
 
1525
                                ImageMenuElem (
 
1526
                                        _("Linear"),
 
1527
                                        *_fade_out_images[FadeLinear],
 
1528
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
 
1529
                                        )
 
1530
                                );
 
1531
 
 
1532
                        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1533
 
 
1534
                        items.push_back (
 
1535
                                ImageMenuElem (
 
1536
                                        _("Slow"),
 
1537
                                        *_fade_out_images[FadeSlow],
 
1538
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
 
1539
                                        ));
 
1540
 
 
1541
                        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1542
 
 
1543
                        items.push_back (
 
1544
                                ImageMenuElem (
 
1545
                                        _("Fast"),
 
1546
                                        *_fade_out_images[FadeFast],
 
1547
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
 
1548
                                        ));
 
1549
 
 
1550
                        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1551
 
 
1552
                        items.push_back (
 
1553
                                ImageMenuElem (
 
1554
                                        _("Symmetric"),
 
1555
                                        *_fade_out_images[FadeSymmetric],
 
1556
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
 
1557
                                        ));
 
1558
 
 
1559
                        items.push_back (
 
1560
                                ImageMenuElem (
 
1561
                                        _("Constant power"),
 
1562
                                        *_fade_out_images[FadeConstantPower],
 
1563
                                        sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
 
1564
                                        ));
 
1565
 
 
1566
                        dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
 
1567
                }
 
1568
 
 
1569
                break;
 
1570
 
 
1571
        default:
 
1572
                fatal << _("programming error: ")
 
1573
                      << X_("non-fade canvas item passed to popup_fade_context_menu()")
 
1574
                      << endmsg;
 
1575
                /*NOTREACHED*/
 
1576
        }
 
1577
 
 
1578
        fade_context_menu.popup (button, time);
 
1579
}
 
1580
 
 
1581
void
 
1582
Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
 
1583
{
 
1584
        using namespace Menu_Helpers;
 
1585
        Menu* (Editor::*build_menu_function)();
 
1586
        Menu *menu;
 
1587
 
 
1588
        switch (item_type) {
 
1589
        case RegionItem:
 
1590
        case RegionViewName:
 
1591
        case RegionViewNameHighlight:
 
1592
        case LeftFrameHandle:
 
1593
        case RightFrameHandle:
 
1594
                if (with_selection) {
 
1595
                        build_menu_function = &Editor::build_track_selection_context_menu;
 
1596
                } else {
 
1597
                        build_menu_function = &Editor::build_track_region_context_menu;
 
1598
                }
 
1599
                break;
 
1600
 
 
1601
        case SelectionItem:
 
1602
                if (with_selection) {
 
1603
                        build_menu_function = &Editor::build_track_selection_context_menu;
 
1604
                } else {
 
1605
                        build_menu_function = &Editor::build_track_context_menu;
 
1606
                }
 
1607
                break;
 
1608
 
 
1609
        case StreamItem:
 
1610
                if (clicked_routeview->track()) {
 
1611
                        build_menu_function = &Editor::build_track_context_menu;
 
1612
                } else {
 
1613
                        build_menu_function = &Editor::build_track_bus_context_menu;
 
1614
                }
 
1615
                break;
 
1616
 
 
1617
        default:
 
1618
                /* probably shouldn't happen but if it does, we don't care */
 
1619
                return;
 
1620
        }
 
1621
 
 
1622
        menu = (this->*build_menu_function)();
 
1623
        menu->set_name ("ArdourContextMenu");
 
1624
 
 
1625
        /* now handle specific situations */
 
1626
 
 
1627
        switch (item_type) {
 
1628
        case RegionItem:
 
1629
        case RegionViewName:
 
1630
        case RegionViewNameHighlight:
 
1631
        case LeftFrameHandle:
 
1632
        case RightFrameHandle:
 
1633
                if (!with_selection) {
 
1634
                        if (region_edit_menu_split_item) {
 
1635
                                if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
 
1636
                                        ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
 
1637
                                } else {
 
1638
                                        ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
 
1639
                                }
 
1640
                        }
 
1641
                        if (region_edit_menu_split_multichannel_item) {
 
1642
                                if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
 
1643
                                        region_edit_menu_split_multichannel_item->set_sensitive (true);
 
1644
                                } else {
 
1645
                                        region_edit_menu_split_multichannel_item->set_sensitive (false);
 
1646
                                }
 
1647
                        }
 
1648
                }
 
1649
                break;
 
1650
 
 
1651
        case SelectionItem:
 
1652
                break;
 
1653
 
 
1654
        case StreamItem:
 
1655
                break;
 
1656
 
 
1657
        default:
 
1658
                /* probably shouldn't happen but if it does, we don't care */
 
1659
                return;
 
1660
        }
 
1661
 
 
1662
        if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
 
1663
 
 
1664
                /* Bounce to disk */
 
1665
 
 
1666
                using namespace Menu_Helpers;
 
1667
                MenuList& edit_items  = menu->items();
 
1668
 
 
1669
                edit_items.push_back (SeparatorElem());
 
1670
 
 
1671
                switch (clicked_routeview->audio_track()->freeze_state()) {
 
1672
                case AudioTrack::NoFreeze:
 
1673
                        edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
 
1674
                        break;
 
1675
 
 
1676
                case AudioTrack::Frozen:
 
1677
                        edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
 
1678
                        break;
 
1679
 
 
1680
                case AudioTrack::UnFrozen:
 
1681
                        edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
 
1682
                        break;
 
1683
                }
 
1684
 
 
1685
        }
 
1686
 
 
1687
        if (item_type == StreamItem && clicked_routeview) {
 
1688
                clicked_routeview->build_underlay_menu(menu);
 
1689
        }
 
1690
 
 
1691
        /* When the region menu is opened, we setup the actions so that they look right
 
1692
           in the menu.
 
1693
        */
 
1694
        sensitize_the_right_region_actions ();
 
1695
        _last_region_menu_was_main = false;
 
1696
 
 
1697
        menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
 
1698
        menu->popup (button, time);
 
1699
}
 
1700
 
 
1701
Menu*
 
1702
Editor::build_track_context_menu ()
 
1703
{
 
1704
        using namespace Menu_Helpers;
 
1705
 
 
1706
        MenuList& edit_items = track_context_menu.items();
 
1707
        edit_items.clear();
 
1708
 
 
1709
        add_dstream_context_items (edit_items);
 
1710
        return &track_context_menu;
 
1711
}
 
1712
 
 
1713
Menu*
 
1714
Editor::build_track_bus_context_menu ()
 
1715
{
 
1716
        using namespace Menu_Helpers;
 
1717
 
 
1718
        MenuList& edit_items = track_context_menu.items();
 
1719
        edit_items.clear();
 
1720
 
 
1721
        add_bus_context_items (edit_items);
 
1722
        return &track_context_menu;
 
1723
}
 
1724
 
 
1725
Menu*
 
1726
Editor::build_track_region_context_menu ()
 
1727
{
 
1728
        using namespace Menu_Helpers;
 
1729
        MenuList& edit_items  = track_region_context_menu.items();
 
1730
        edit_items.clear();
 
1731
 
 
1732
        /* we've just cleared the track region context menu, so the menu that these
 
1733
           two items were on will have disappeared; stop them dangling.
 
1734
        */
 
1735
        region_edit_menu_split_item = 0;
 
1736
        region_edit_menu_split_multichannel_item = 0;
 
1737
 
 
1738
        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
 
1739
 
 
1740
        if (rtv) {
 
1741
                boost::shared_ptr<Track> tr;
 
1742
                boost::shared_ptr<Playlist> pl;
 
1743
 
 
1744
                if ((tr = rtv->track())) {
 
1745
                        add_region_context_items (edit_items, tr);
 
1746
                }
 
1747
        }
 
1748
 
 
1749
        add_dstream_context_items (edit_items);
 
1750
 
 
1751
        return &track_region_context_menu;
 
1752
}
 
1753
 
 
1754
void
 
1755
Editor::analyze_region_selection ()
 
1756
{
 
1757
        if (analysis_window == 0) {
 
1758
                analysis_window = new AnalysisWindow();
 
1759
 
 
1760
                if (_session != 0)
 
1761
                        analysis_window->set_session(_session);
 
1762
 
 
1763
                analysis_window->show_all();
 
1764
        }
 
1765
 
 
1766
        analysis_window->set_regionmode();
 
1767
        analysis_window->analyze();
 
1768
 
 
1769
        analysis_window->present();
 
1770
}
 
1771
 
 
1772
void
 
1773
Editor::analyze_range_selection()
 
1774
{
 
1775
        if (analysis_window == 0) {
 
1776
                analysis_window = new AnalysisWindow();
 
1777
 
 
1778
                if (_session != 0)
 
1779
                        analysis_window->set_session(_session);
 
1780
 
 
1781
                analysis_window->show_all();
 
1782
        }
 
1783
 
 
1784
        analysis_window->set_rangemode();
 
1785
        analysis_window->analyze();
 
1786
 
 
1787
        analysis_window->present();
 
1788
}
 
1789
 
 
1790
Menu*
 
1791
Editor::build_track_selection_context_menu ()
 
1792
{
 
1793
        using namespace Menu_Helpers;
 
1794
        MenuList& edit_items  = track_selection_context_menu.items();
 
1795
        edit_items.clear ();
 
1796
 
 
1797
        add_selection_context_items (edit_items);
 
1798
        // edit_items.push_back (SeparatorElem());
 
1799
        // add_dstream_context_items (edit_items);
 
1800
 
 
1801
        return &track_selection_context_menu;
 
1802
}
 
1803
 
 
1804
void
 
1805
Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
 
1806
{
 
1807
        using namespace Menu_Helpers;
 
1808
 
 
1809
        /* OK, stick the region submenu at the top of the list, and then add
 
1810
           the standard items.
 
1811
        */
 
1812
 
 
1813
        RegionSelection rs = get_regions_from_selection_and_entered ();
 
1814
 
 
1815
        string::size_type pos = 0;
 
1816
        string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
 
1817
 
 
1818
        /* we have to hack up the region name because "_" has a special
 
1819
           meaning for menu titles.
 
1820
        */
 
1821
 
 
1822
        while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
 
1823
                menu_item_name.replace (pos, 1, "__");
 
1824
                pos += 2;
 
1825
        }
 
1826
 
 
1827
        if (_popup_region_menu_item == 0) {
 
1828
                _popup_region_menu_item = new MenuItem (menu_item_name);
 
1829
                _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
 
1830
                _popup_region_menu_item->show ();
 
1831
        } else {
 
1832
                _popup_region_menu_item->set_label (menu_item_name);
 
1833
        }
 
1834
 
 
1835
        const framepos_t position = get_preferred_edit_position (false, true);
 
1836
 
 
1837
        edit_items.push_back (*_popup_region_menu_item);
 
1838
        if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
 
1839
                edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
 
1840
        }
 
1841
        edit_items.push_back (SeparatorElem());
 
1842
}
 
1843
 
 
1844
/** Add context menu items relevant to selection ranges.
 
1845
 * @param edit_items List to add the items to.
 
1846
 */
 
1847
void
 
1848
Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
 
1849
{
 
1850
        using namespace Menu_Helpers;
 
1851
 
 
1852
        edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
 
1853
        edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
 
1854
 
 
1855
        edit_items.push_back (SeparatorElem());
 
1856
        edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
 
1857
 
 
1858
        edit_items.push_back (SeparatorElem());
 
1859
 
 
1860
        edit_items.push_back (
 
1861
                MenuElem (
 
1862
                        _("Move Range Start to Previous Region Boundary"),
 
1863
                        sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
 
1864
                        )
 
1865
                );
 
1866
 
 
1867
        edit_items.push_back (
 
1868
                MenuElem (
 
1869
                        _("Move Range Start to Next Region Boundary"),
 
1870
                        sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
 
1871
                        )
 
1872
                );
 
1873
 
 
1874
        edit_items.push_back (
 
1875
                MenuElem (
 
1876
                        _("Move Range End to Previous Region Boundary"),
 
1877
                        sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
 
1878
                        )
 
1879
                );
 
1880
 
 
1881
        edit_items.push_back (
 
1882
                MenuElem (
 
1883
                        _("Move Range End to Next Region Boundary"),
 
1884
                        sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
 
1885
                        )
 
1886
                );
 
1887
 
 
1888
        edit_items.push_back (SeparatorElem());
 
1889
        edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
 
1890
        edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
 
1891
 
 
1892
        edit_items.push_back (SeparatorElem());
 
1893
        edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
 
1894
 
 
1895
        edit_items.push_back (SeparatorElem());
 
1896
        edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
 
1897
        edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
 
1898
 
 
1899
        edit_items.push_back (SeparatorElem());
 
1900
        edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
 
1901
 
 
1902
        edit_items.push_back (SeparatorElem());
 
1903
        edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
 
1904
        edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
 
1905
        edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
 
1906
 
 
1907
        edit_items.push_back (SeparatorElem());
 
1908
        edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
 
1909
        edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
 
1910
        edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
 
1911
        edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
 
1912
        edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
 
1913
}
 
1914
 
 
1915
 
 
1916
void
 
1917
Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
 
1918
{
 
1919
        using namespace Menu_Helpers;
 
1920
 
 
1921
        /* Playback */
 
1922
 
 
1923
        Menu *play_menu = manage (new Menu);
 
1924
        MenuList& play_items = play_menu->items();
 
1925
        play_menu->set_name ("ArdourContextMenu");
 
1926
 
 
1927
        play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
 
1928
        play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
 
1929
        play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
 
1930
        play_items.push_back (SeparatorElem());
 
1931
        play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
 
1932
 
 
1933
        edit_items.push_back (MenuElem (_("Play"), *play_menu));
 
1934
 
 
1935
        /* Selection */
 
1936
 
 
1937
        Menu *select_menu = manage (new Menu);
 
1938
        MenuList& select_items = select_menu->items();
 
1939
        select_menu->set_name ("ArdourContextMenu");
 
1940
 
 
1941
        select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
 
1942
        select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
 
1943
        select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
 
1944
        select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
 
1945
        select_items.push_back (SeparatorElem());
 
1946
        select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
 
1947
        select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
 
1948
        select_items.push_back (SeparatorElem());
 
1949
        select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
 
1950
        select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
 
1951
        select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
 
1952
        select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
 
1953
        select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
 
1954
        select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
 
1955
        select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
 
1956
 
 
1957
        edit_items.push_back (MenuElem (_("Select"), *select_menu));
 
1958
 
 
1959
        /* Cut-n-Paste */
 
1960
 
 
1961
        Menu *cutnpaste_menu = manage (new Menu);
 
1962
        MenuList& cutnpaste_items = cutnpaste_menu->items();
 
1963
        cutnpaste_menu->set_name ("ArdourContextMenu");
 
1964
 
 
1965
        cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
 
1966
        cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
 
1967
        cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
 
1968
 
 
1969
        cutnpaste_items.push_back (SeparatorElem());
 
1970
 
 
1971
        cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
 
1972
        cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
 
1973
 
 
1974
        edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
 
1975
 
 
1976
        /* Adding new material */
 
1977
 
 
1978
        edit_items.push_back (SeparatorElem());
 
1979
        edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
 
1980
        edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
 
1981
 
 
1982
        /* Nudge track */
 
1983
 
 
1984
        Menu *nudge_menu = manage (new Menu());
 
1985
        MenuList& nudge_items = nudge_menu->items();
 
1986
        nudge_menu->set_name ("ArdourContextMenu");
 
1987
 
 
1988
        edit_items.push_back (SeparatorElem());
 
1989
        nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
 
1990
        nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
 
1991
        nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
 
1992
        nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
 
1993
 
 
1994
        edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
 
1995
}
 
1996
 
 
1997
void
 
1998
Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
 
1999
{
 
2000
        using namespace Menu_Helpers;
 
2001
 
 
2002
        /* Playback */
 
2003
 
 
2004
        Menu *play_menu = manage (new Menu);
 
2005
        MenuList& play_items = play_menu->items();
 
2006
        play_menu->set_name ("ArdourContextMenu");
 
2007
 
 
2008
        play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
 
2009
        play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
 
2010
        edit_items.push_back (MenuElem (_("Play"), *play_menu));
 
2011
 
 
2012
        /* Selection */
 
2013
 
 
2014
        Menu *select_menu = manage (new Menu);
 
2015
        MenuList& select_items = select_menu->items();
 
2016
        select_menu->set_name ("ArdourContextMenu");
 
2017
 
 
2018
        select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
 
2019
        select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
 
2020
        select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
 
2021
        select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
 
2022
        select_items.push_back (SeparatorElem());
 
2023
        select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
 
2024
        select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
 
2025
        select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
 
2026
        select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
 
2027
 
 
2028
        edit_items.push_back (MenuElem (_("Select"), *select_menu));
 
2029
 
 
2030
        /* Cut-n-Paste */
 
2031
 
 
2032
        Menu *cutnpaste_menu = manage (new Menu);
 
2033
        MenuList& cutnpaste_items = cutnpaste_menu->items();
 
2034
        cutnpaste_menu->set_name ("ArdourContextMenu");
 
2035
 
 
2036
        cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
 
2037
        cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
 
2038
        cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
 
2039
 
 
2040
        Menu *nudge_menu = manage (new Menu());
 
2041
        MenuList& nudge_items = nudge_menu->items();
 
2042
        nudge_menu->set_name ("ArdourContextMenu");
 
2043
 
 
2044
        edit_items.push_back (SeparatorElem());
 
2045
        nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
 
2046
        nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
 
2047
        nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
 
2048
        nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
 
2049
 
 
2050
        edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
 
2051
}
 
2052
 
 
2053
SnapType
 
2054
Editor::snap_type() const
 
2055
{
 
2056
        return _snap_type;
 
2057
}
 
2058
 
 
2059
SnapMode
 
2060
Editor::snap_mode() const
 
2061
{
 
2062
        return _snap_mode;
 
2063
}
 
2064
 
 
2065
void
 
2066
Editor::set_snap_to (SnapType st)
 
2067
{
 
2068
        unsigned int snap_ind = (unsigned int)st;
 
2069
 
 
2070
        _snap_type = st;
 
2071
 
 
2072
        if (snap_ind > snap_type_strings.size() - 1) {
 
2073
                snap_ind = 0;
 
2074
                _snap_type = (SnapType)snap_ind;
 
2075
        }
 
2076
 
 
2077
        string str = snap_type_strings[snap_ind];
 
2078
 
 
2079
        if (str != snap_type_selector.get_active_text()) {
 
2080
                snap_type_selector.set_active_text (str);
 
2081
        }
 
2082
 
 
2083
        instant_save ();
 
2084
 
 
2085
        switch (_snap_type) {
 
2086
        case SnapToBeatDiv128:
 
2087
        case SnapToBeatDiv64:
 
2088
        case SnapToBeatDiv32:
 
2089
        case SnapToBeatDiv28:
 
2090
        case SnapToBeatDiv24:
 
2091
        case SnapToBeatDiv20:
 
2092
        case SnapToBeatDiv16:
 
2093
        case SnapToBeatDiv14:
 
2094
        case SnapToBeatDiv12:
 
2095
        case SnapToBeatDiv10:
 
2096
        case SnapToBeatDiv8:
 
2097
        case SnapToBeatDiv7:
 
2098
        case SnapToBeatDiv6:
 
2099
        case SnapToBeatDiv5:
 
2100
        case SnapToBeatDiv4:
 
2101
        case SnapToBeatDiv3:
 
2102
        case SnapToBeatDiv2: {
 
2103
                ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
 
2104
                ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
 
2105
                
 
2106
                compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
 
2107
                                            current_bbt_points_begin, current_bbt_points_end);
 
2108
                compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
 
2109
                                         current_bbt_points_begin, current_bbt_points_end);
 
2110
                update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
 
2111
                break;
 
2112
        }
 
2113
 
 
2114
        case SnapToRegionStart:
 
2115
        case SnapToRegionEnd:
 
2116
        case SnapToRegionSync:
 
2117
        case SnapToRegionBoundary:
 
2118
                build_region_boundary_cache ();
 
2119
                break;
 
2120
 
 
2121
        default:
 
2122
                /* relax */
 
2123
                break;
 
2124
        }
 
2125
 
 
2126
        SnapChanged (); /* EMIT SIGNAL */
 
2127
}
 
2128
 
 
2129
void
 
2130
Editor::set_snap_mode (SnapMode mode)
 
2131
{
 
2132
        string str = snap_mode_strings[(int)mode];
 
2133
 
 
2134
        if (_internal_editing) {
 
2135
                internal_snap_mode = mode;
 
2136
        } else {
 
2137
                pre_internal_snap_mode = mode;
 
2138
        }
 
2139
 
 
2140
        _snap_mode = mode;
 
2141
 
 
2142
        if (str != snap_mode_selector.get_active_text ()) {
 
2143
                snap_mode_selector.set_active_text (str);
 
2144
        }
 
2145
 
 
2146
        instant_save ();
 
2147
}
 
2148
void
 
2149
Editor::set_edit_point_preference (EditPoint ep, bool force)
 
2150
{
 
2151
        bool changed = (_edit_point != ep);
 
2152
 
 
2153
        _edit_point = ep;
 
2154
        string str = edit_point_strings[(int)ep];
 
2155
 
 
2156
        if (str != edit_point_selector.get_active_text ()) {
 
2157
                edit_point_selector.set_active_text (str);
 
2158
        }
 
2159
 
 
2160
        set_canvas_cursor ();
 
2161
 
 
2162
        if (!force && !changed) {
 
2163
                return;
 
2164
        }
 
2165
 
 
2166
        const char* action=NULL;
 
2167
 
 
2168
        switch (_edit_point) {
 
2169
        case EditAtPlayhead:
 
2170
                action = "edit-at-playhead";
 
2171
                break;
 
2172
        case EditAtSelectedMarker:
 
2173
                action = "edit-at-marker";
 
2174
                break;
 
2175
        case EditAtMouse:
 
2176
                action = "edit-at-mouse";
 
2177
                break;
 
2178
        }
 
2179
 
 
2180
        Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
 
2181
        if (act) {
 
2182
                Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
 
2183
        }
 
2184
 
 
2185
        framepos_t foo;
 
2186
        bool in_track_canvas;
 
2187
 
 
2188
        if (!mouse_frame (foo, in_track_canvas)) {
 
2189
                in_track_canvas = false;
 
2190
        }
 
2191
 
 
2192
        reset_canvas_action_sensitivity (in_track_canvas);
 
2193
 
 
2194
        instant_save ();
 
2195
}
 
2196
 
 
2197
int
 
2198
Editor::set_state (const XMLNode& node, int /*version*/)
 
2199
{
 
2200
        const XMLProperty* prop;
 
2201
        XMLNode* geometry;
 
2202
        int x, y;
 
2203
        Gdk::Geometry g;
 
2204
 
 
2205
        set_id (node);
 
2206
 
 
2207
        g.base_width = default_width;
 
2208
        g.base_height = default_height;
 
2209
        x = 1;
 
2210
        y = 1;
 
2211
 
 
2212
        if ((geometry = find_named_node (node, "geometry")) != 0) {
 
2213
 
 
2214
                XMLProperty* prop;
 
2215
 
 
2216
                if ((prop = geometry->property("x_size")) == 0) {
 
2217
                        prop = geometry->property ("x-size");
 
2218
                }
 
2219
                if (prop) {
 
2220
                        g.base_width = atoi(prop->value());
 
2221
                }
 
2222
                if ((prop = geometry->property("y_size")) == 0) {
 
2223
                        prop = geometry->property ("y-size");
 
2224
                }
 
2225
                if (prop) {
 
2226
                        g.base_height = atoi(prop->value());
 
2227
                }
 
2228
 
 
2229
                if ((prop = geometry->property ("x_pos")) == 0) {
 
2230
                        prop = geometry->property ("x-pos");
 
2231
                }
 
2232
                if (prop) {
 
2233
                        x = atoi (prop->value());
 
2234
 
 
2235
                }
 
2236
                if ((prop = geometry->property ("y_pos")) == 0) {
 
2237
                        prop = geometry->property ("y-pos");
 
2238
                }
 
2239
                if (prop) {
 
2240
                        y = atoi (prop->value());
 
2241
                }
 
2242
        }
 
2243
 
 
2244
        set_default_size (g.base_width, g.base_height);
 
2245
        move (x, y);
 
2246
 
 
2247
        if (_session && (prop = node.property ("playhead"))) {
 
2248
                framepos_t pos;
 
2249
                sscanf (prop->value().c_str(), "%" PRIi64, &pos);
 
2250
                playhead_cursor->set_position (pos);
 
2251
        } else {
 
2252
                playhead_cursor->set_position (0);
 
2253
        }
 
2254
 
 
2255
        if ((prop = node.property ("mixer-width"))) {
 
2256
                editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
 
2257
        }
 
2258
 
 
2259
        if ((prop = node.property ("zoom-focus"))) {
 
2260
                set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
 
2261
        }
 
2262
 
 
2263
        if ((prop = node.property ("zoom"))) {
 
2264
                reset_zoom (PBD::atof (prop->value()));
 
2265
        } else {
 
2266
                reset_zoom (frames_per_unit);
 
2267
        }
 
2268
 
 
2269
        if ((prop = node.property ("snap-to"))) {
 
2270
                set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
 
2271
        }
 
2272
 
 
2273
        if ((prop = node.property ("snap-mode"))) {
 
2274
                set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
 
2275
        }
 
2276
 
 
2277
        if ((prop = node.property ("internal-snap-to"))) {
 
2278
                internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
 
2279
        }
 
2280
 
 
2281
        if ((prop = node.property ("internal-snap-mode"))) {
 
2282
                internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
 
2283
        }
 
2284
 
 
2285
        if ((prop = node.property ("pre-internal-snap-to"))) {
 
2286
                pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
 
2287
        }
 
2288
 
 
2289
 
 
2290
        if ((prop = node.property ("pre-internal-snap-mode"))) {
 
2291
                pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
 
2292
        }
 
2293
 
 
2294
        if ((prop = node.property ("mouse-mode"))) {
 
2295
                MouseMode m = str2mousemode(prop->value());
 
2296
                set_mouse_mode (m, true);
 
2297
        } else {
 
2298
                set_mouse_mode (MouseObject, true);
 
2299
        }
 
2300
 
 
2301
        if ((prop = node.property ("left-frame")) != 0) {
 
2302
                framepos_t pos;
 
2303
                if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
 
2304
                        if (pos < 0) {
 
2305
                                pos = 0;
 
2306
                        }
 
2307
                        reset_x_origin (pos);
 
2308
                }
 
2309
        }
 
2310
 
 
2311
        if ((prop = node.property ("y-origin")) != 0) {
 
2312
                reset_y_origin (atof (prop->value ()));
 
2313
        }
 
2314
 
 
2315
        if ((prop = node.property ("internal-edit"))) {
 
2316
                bool yn = string_is_affirmative (prop->value());
 
2317
                RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
 
2318
                if (act) {
 
2319
                        RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
2320
                        tact->set_active (!yn);
 
2321
                        tact->set_active (yn);
 
2322
                }
 
2323
        }
 
2324
 
 
2325
        if ((prop = node.property ("join-object-range"))) {
 
2326
                RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
 
2327
                bool yn = string_is_affirmative (prop->value());
 
2328
                if (act) {
 
2329
                        RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
2330
                        tact->set_active (!yn);
 
2331
                        tact->set_active (yn);
 
2332
                }
 
2333
                set_mouse_mode(mouse_mode, true);
 
2334
        }
 
2335
 
 
2336
        if ((prop = node.property ("edit-point"))) {
 
2337
                set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
 
2338
        }
 
2339
 
 
2340
        if ((prop = node.property ("show-measures"))) {
 
2341
                bool yn = string_is_affirmative (prop->value());
 
2342
                _show_measures = yn;
 
2343
                RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
 
2344
                if (act) {
 
2345
                        RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
2346
                        /* do it twice to force the change */
 
2347
                        tact->set_active (!yn);
 
2348
                        tact->set_active (yn);
 
2349
                }
 
2350
        }
 
2351
 
 
2352
        if ((prop = node.property ("follow-playhead"))) {
 
2353
                bool yn = string_is_affirmative (prop->value());
 
2354
                set_follow_playhead (yn);
 
2355
                RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
 
2356
                if (act) {
 
2357
                        RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
2358
                        if (tact->get_active() != yn) {
 
2359
                                tact->set_active (yn);
 
2360
                        }
 
2361
                }
 
2362
        }
 
2363
 
 
2364
        if ((prop = node.property ("stationary-playhead"))) {
 
2365
                bool yn = string_is_affirmative (prop->value());
 
2366
                set_stationary_playhead (yn);
 
2367
                RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
 
2368
                if (act) {
 
2369
                        RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
2370
                        if (tact->get_active() != yn) {
 
2371
                                tact->set_active (yn);
 
2372
                        }
 
2373
                }
 
2374
        }
 
2375
 
 
2376
        if ((prop = node.property ("region-list-sort-type"))) {
 
2377
                RegionListSortType st;
 
2378
                _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
 
2379
        }
 
2380
 
 
2381
        if ((prop = node.property ("show-editor-mixer"))) {
 
2382
 
 
2383
                Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
 
2384
                assert (act);
 
2385
 
 
2386
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
 
2387
                bool yn = string_is_affirmative (prop->value());
 
2388
 
 
2389
                /* do it twice to force the change */
 
2390
 
 
2391
                tact->set_active (!yn);
 
2392
                tact->set_active (yn);
 
2393
        }
 
2394
 
 
2395
        if ((prop = node.property ("show-editor-list"))) {
 
2396
 
 
2397
                Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
 
2398
                assert (act);
 
2399
 
 
2400
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
 
2401
                bool yn = string_is_affirmative (prop->value());
 
2402
 
 
2403
                /* do it twice to force the change */
 
2404
 
 
2405
                tact->set_active (!yn);
 
2406
                tact->set_active (yn);
 
2407
        }
 
2408
 
 
2409
        if ((prop = node.property (X_("editor-list-page")))) {
 
2410
                _the_notebook.set_current_page (atoi (prop->value ()));
 
2411
        }
 
2412
 
 
2413
        if ((prop = node.property (X_("show-marker-lines")))) {
 
2414
                Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
 
2415
                assert (act);
 
2416
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
 
2417
                bool yn = string_is_affirmative (prop->value ());
 
2418
 
 
2419
                tact->set_active (!yn);
 
2420
                tact->set_active (yn);
 
2421
        }
 
2422
 
 
2423
        XMLNodeList children = node.children ();
 
2424
        for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
 
2425
                selection->set_state (**i, Stateful::current_state_version);
 
2426
                _regions->set_state (**i);
 
2427
        }
 
2428
 
 
2429
        if ((prop = node.property ("maximised"))) {
 
2430
                bool yn = string_is_affirmative (prop->value());
 
2431
                if (yn) {
 
2432
                        ActionManager::do_action ("Common", "ToggleMaximalEditor");
 
2433
                }
 
2434
        }
 
2435
 
 
2436
        if ((prop = node.property ("nudge-clock-value"))) {
 
2437
                framepos_t f;
 
2438
                sscanf (prop->value().c_str(), "%" PRId64, &f);
 
2439
                nudge_clock->set (f);
 
2440
        } else {
 
2441
                nudge_clock->set_mode (AudioClock::Timecode);
 
2442
                nudge_clock->set (_session->frame_rate() * 5, true);
 
2443
        }
 
2444
 
 
2445
        return 0;
 
2446
}
 
2447
 
 
2448
XMLNode&
 
2449
Editor::get_state ()
 
2450
{
 
2451
        XMLNode* node = new XMLNode ("Editor");
 
2452
        char buf[32];
 
2453
 
 
2454
        id().print (buf, sizeof (buf));
 
2455
        node->add_property ("id", buf);
 
2456
 
 
2457
        if (is_realized()) {
 
2458
                Glib::RefPtr<Gdk::Window> win = get_window();
 
2459
 
 
2460
                int x, y, width, height;
 
2461
                win->get_root_origin(x, y);
 
2462
                win->get_size(width, height);
 
2463
 
 
2464
                XMLNode* geometry = new XMLNode ("geometry");
 
2465
 
 
2466
                snprintf(buf, sizeof(buf), "%d", width);
 
2467
                geometry->add_property("x-size", string(buf));
 
2468
                snprintf(buf, sizeof(buf), "%d", height);
 
2469
                geometry->add_property("y-size", string(buf));
 
2470
                snprintf(buf, sizeof(buf), "%d", x);
 
2471
                geometry->add_property("x-pos", string(buf));
 
2472
                snprintf(buf, sizeof(buf), "%d", y);
 
2473
                geometry->add_property("y-pos", string(buf));
 
2474
                snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
 
2475
                geometry->add_property("edit-horizontal-pane-pos", string(buf));
 
2476
                geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
 
2477
                snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
 
2478
                geometry->add_property("edit-vertical-pane-pos", string(buf));
 
2479
 
 
2480
                node->add_child_nocopy (*geometry);
 
2481
        }
 
2482
 
 
2483
        maybe_add_mixer_strip_width (*node);
 
2484
 
 
2485
        node->add_property ("zoom-focus", enum_2_string (zoom_focus));
 
2486
        snprintf (buf, sizeof(buf), "%f", frames_per_unit);
 
2487
        node->add_property ("zoom", buf);
 
2488
        node->add_property ("snap-to", enum_2_string (_snap_type));
 
2489
        node->add_property ("snap-mode", enum_2_string (_snap_mode));
 
2490
        node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
 
2491
        node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
 
2492
        node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
 
2493
        node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
 
2494
        node->add_property ("edit-point", enum_2_string (_edit_point));
 
2495
 
 
2496
        snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
 
2497
        node->add_property ("playhead", buf);
 
2498
        snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
 
2499
        node->add_property ("left-frame", buf);
 
2500
        snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
 
2501
        node->add_property ("y-origin", buf);
 
2502
 
 
2503
        node->add_property ("show-measures", _show_measures ? "yes" : "no");
 
2504
        node->add_property ("maximised", _maximised ? "yes" : "no");
 
2505
        node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
 
2506
        node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
 
2507
        node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
 
2508
        node->add_property ("mouse-mode", enum2str(mouse_mode));
 
2509
        node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
 
2510
        node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
 
2511
 
 
2512
        Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
 
2513
        if (act) {
 
2514
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
 
2515
                node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
 
2516
        }
 
2517
 
 
2518
        act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
 
2519
        if (act) {
 
2520
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
 
2521
                node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
 
2522
        }
 
2523
 
 
2524
        snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
 
2525
        node->add_property (X_("editor-list-page"), buf);
 
2526
 
 
2527
        if (button_bindings) {
 
2528
                XMLNode* bb = new XMLNode (X_("Buttons"));
 
2529
                button_bindings->save (*bb);
 
2530
                node->add_child_nocopy (*bb);
 
2531
        }
 
2532
 
 
2533
        node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
 
2534
 
 
2535
        node->add_child_nocopy (selection->get_state ());
 
2536
        node->add_child_nocopy (_regions->get_state ());
 
2537
 
 
2538
        snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
 
2539
        node->add_property ("nudge-clock-value", buf);
 
2540
 
 
2541
        return *node;
 
2542
}
 
2543
 
 
2544
 
 
2545
 
 
2546
/** @param y y offset from the top of all trackviews.
 
2547
 *  @return pair: TimeAxisView that y is over, layer index.
 
2548
 *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
 
2549
 *  in stacked or expanded region display mode, otherwise 0.
 
2550
 */
 
2551
std::pair<TimeAxisView *, double>
 
2552
Editor::trackview_by_y_position (double y)
 
2553
{
 
2554
        for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
 
2555
 
 
2556
                std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
 
2557
                if (r.first) {
 
2558
                        return r;
 
2559
                }
 
2560
        }
 
2561
 
 
2562
        return std::make_pair ( (TimeAxisView *) 0, 0);
 
2563
}
 
2564
 
 
2565
/** Snap a position to the grid, if appropriate, taking into account current
 
2566
 *  grid settings and also the state of any snap modifier keys that may be pressed.
 
2567
 *  @param start Position to snap.
 
2568
 *  @param event Event to get current key modifier information from, or 0.
 
2569
 */
 
2570
void
 
2571
Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
 
2572
{
 
2573
        if (!_session || !event) {
 
2574
                return;
 
2575
        }
 
2576
 
 
2577
        if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
 
2578
                if (_snap_mode == SnapOff) {
 
2579
                        snap_to_internal (start, direction, for_mark);
 
2580
                }
 
2581
        } else {
 
2582
                if (_snap_mode != SnapOff) {
 
2583
                        snap_to_internal (start, direction, for_mark);
 
2584
                }
 
2585
        }
 
2586
}
 
2587
 
 
2588
void
 
2589
Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
 
2590
{
 
2591
        if (!_session || _snap_mode == SnapOff) {
 
2592
                return;
 
2593
        }
 
2594
 
 
2595
        snap_to_internal (start, direction, for_mark);
 
2596
}
 
2597
 
 
2598
void
 
2599
Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
 
2600
{
 
2601
        const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
 
2602
        framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
 
2603
 
 
2604
        switch (_snap_type) {
 
2605
        case SnapToTimecodeFrame:
 
2606
                if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
 
2607
                        start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
 
2608
                } else {
 
2609
                        start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
 
2610
                }
 
2611
                break;
 
2612
 
 
2613
        case SnapToTimecodeSeconds:
 
2614
                if (_session->config.get_timecode_offset_negative()) {
 
2615
                        start += _session->config.get_timecode_offset ();
 
2616
                } else {
 
2617
                        start -= _session->config.get_timecode_offset ();
 
2618
                }
 
2619
                if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
 
2620
                        start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
 
2621
                } else {
 
2622
                        start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
 
2623
                }
 
2624
 
 
2625
                if (_session->config.get_timecode_offset_negative()) {
 
2626
                        start -= _session->config.get_timecode_offset ();
 
2627
                } else {
 
2628
                        start += _session->config.get_timecode_offset ();
 
2629
                }
 
2630
                break;
 
2631
 
 
2632
        case SnapToTimecodeMinutes:
 
2633
                if (_session->config.get_timecode_offset_negative()) {
 
2634
                        start += _session->config.get_timecode_offset ();
 
2635
                } else {
 
2636
                        start -= _session->config.get_timecode_offset ();
 
2637
                }
 
2638
                if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
 
2639
                        start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
 
2640
                } else {
 
2641
                        start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
 
2642
                }
 
2643
                if (_session->config.get_timecode_offset_negative()) {
 
2644
                        start -= _session->config.get_timecode_offset ();
 
2645
                } else {
 
2646
                        start += _session->config.get_timecode_offset ();
 
2647
                }
 
2648
                break;
 
2649
        default:
 
2650
                fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
 
2651
                /*NOTREACHED*/
 
2652
        }
 
2653
}
 
2654
 
 
2655
void
 
2656
Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
 
2657
{
 
2658
        const framepos_t one_second = _session->frame_rate();
 
2659
        const framepos_t one_minute = _session->frame_rate() * 60;
 
2660
        framepos_t presnap = start;
 
2661
        framepos_t before;
 
2662
        framepos_t after;
 
2663
 
 
2664
        switch (_snap_type) {
 
2665
        case SnapToTimecodeFrame:
 
2666
        case SnapToTimecodeSeconds:
 
2667
        case SnapToTimecodeMinutes:
 
2668
                return timecode_snap_to_internal (start, direction, for_mark);
 
2669
 
 
2670
        case SnapToCDFrame:
 
2671
                if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
 
2672
                        start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
 
2673
                } else {
 
2674
                        start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
 
2675
                }
 
2676
                break;
 
2677
 
 
2678
        case SnapToSeconds:
 
2679
                if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
 
2680
                        start = (framepos_t) ceil ((double) start / one_second) * one_second;
 
2681
                } else {
 
2682
                        start = (framepos_t) floor ((double) start / one_second) * one_second;
 
2683
                }
 
2684
                break;
 
2685
 
 
2686
        case SnapToMinutes:
 
2687
                if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
 
2688
                        start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
 
2689
                } else {
 
2690
                        start = (framepos_t) floor ((double) start / one_minute) * one_minute;
 
2691
                }
 
2692
                break;
 
2693
 
 
2694
        case SnapToBar:
 
2695
                start = _session->tempo_map().round_to_bar (start, direction);
 
2696
                break;
 
2697
 
 
2698
        case SnapToBeat:
 
2699
                start = _session->tempo_map().round_to_beat (start, direction);
 
2700
                break;
 
2701
 
 
2702
        case SnapToBeatDiv128:
 
2703
                start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
 
2704
                break;
 
2705
        case SnapToBeatDiv64:
 
2706
                start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
 
2707
                break;
 
2708
        case SnapToBeatDiv32:
 
2709
                start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
 
2710
                break;
 
2711
        case SnapToBeatDiv28:
 
2712
                start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
 
2713
                break;
 
2714
        case SnapToBeatDiv24:
 
2715
                start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
 
2716
                break;
 
2717
        case SnapToBeatDiv20:
 
2718
                start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
 
2719
                break;
 
2720
        case SnapToBeatDiv16:
 
2721
                start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
 
2722
                break;
 
2723
        case SnapToBeatDiv14:
 
2724
                start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
 
2725
                break;
 
2726
        case SnapToBeatDiv12:
 
2727
                start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
 
2728
                break;
 
2729
        case SnapToBeatDiv10:
 
2730
                start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
 
2731
                break;
 
2732
        case SnapToBeatDiv8:
 
2733
                start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
 
2734
                break;
 
2735
        case SnapToBeatDiv7:
 
2736
                start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
 
2737
                break;
 
2738
        case SnapToBeatDiv6:
 
2739
                start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
 
2740
                break;
 
2741
        case SnapToBeatDiv5:
 
2742
                start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
 
2743
                break;
 
2744
        case SnapToBeatDiv4:
 
2745
                start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
 
2746
                break;
 
2747
        case SnapToBeatDiv3:
 
2748
                start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
 
2749
                break;
 
2750
        case SnapToBeatDiv2:
 
2751
                start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
 
2752
                break;
 
2753
 
 
2754
        case SnapToMark:
 
2755
                if (for_mark) {
 
2756
                        return;
 
2757
                }
 
2758
 
 
2759
                _session->locations()->marks_either_side (start, before, after);
 
2760
 
 
2761
                if (before == max_framepos && after == max_framepos) {
 
2762
                        /* No marks to snap to, so just don't snap */
 
2763
                        return;
 
2764
                } else if (before == max_framepos) {
 
2765
                        start = after;
 
2766
                } else if (after == max_framepos) {
 
2767
                        start = before;
 
2768
                } else if (before != max_framepos && after != max_framepos) {
 
2769
                        /* have before and after */
 
2770
                        if ((start - before) < (after - start)) {
 
2771
                                start = before;
 
2772
                        } else {
 
2773
                                start = after;
 
2774
                        }
 
2775
                }
 
2776
 
 
2777
                break;
 
2778
 
 
2779
        case SnapToRegionStart:
 
2780
        case SnapToRegionEnd:
 
2781
        case SnapToRegionSync:
 
2782
        case SnapToRegionBoundary:
 
2783
                if (!region_boundary_cache.empty()) {
 
2784
 
 
2785
                        vector<framepos_t>::iterator prev = region_boundary_cache.end ();
 
2786
                        vector<framepos_t>::iterator next = region_boundary_cache.end ();
 
2787
 
 
2788
                        if (direction > 0) {
 
2789
                                next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
 
2790
                        } else {
 
2791
                                next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
 
2792
                        }
 
2793
 
 
2794
                        if (next != region_boundary_cache.begin ()) {
 
2795
                                prev = next;
 
2796
                                prev--;
 
2797
                        }
 
2798
 
 
2799
                        framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
 
2800
                        framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
 
2801
 
 
2802
                        if (start > (p + n) / 2) {
 
2803
                                start = n;
 
2804
                        } else {
 
2805
                                start = p;
 
2806
                        }
 
2807
                }
 
2808
                break;
 
2809
        }
 
2810
 
 
2811
        switch (_snap_mode) {
 
2812
        case SnapNormal:
 
2813
                return;
 
2814
 
 
2815
        case SnapMagnetic:
 
2816
 
 
2817
                if (presnap > start) {
 
2818
                        if (presnap > (start + unit_to_frame(snap_threshold))) {
 
2819
                                start = presnap;
 
2820
                        }
 
2821
 
 
2822
                } else if (presnap < start) {
 
2823
                        if (presnap < (start - unit_to_frame(snap_threshold))) {
 
2824
                                start = presnap;
 
2825
                        }
 
2826
                }
 
2827
 
 
2828
        default:
 
2829
                /* handled at entry */
 
2830
                return;
 
2831
 
 
2832
        }
 
2833
}
 
2834
 
 
2835
 
 
2836
void
 
2837
Editor::setup_toolbar ()
 
2838
{
 
2839
        HBox* mode_box = manage(new HBox);
 
2840
        mode_box->set_border_width (2);
 
2841
        mode_box->set_spacing(4);
 
2842
 
 
2843
        HBox* mouse_mode_box = manage (new HBox);
 
2844
        HBox* mouse_mode_hbox = manage (new HBox);
 
2845
        VBox* mouse_mode_vbox = manage (new VBox);
 
2846
        Alignment* mouse_mode_align = manage (new Alignment);
 
2847
 
 
2848
        Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
 
2849
//      mouse_mode_size_group->add_widget (smart_mode_button);
 
2850
        mouse_mode_size_group->add_widget (mouse_move_button);
 
2851
        mouse_mode_size_group->add_widget (mouse_select_button);
 
2852
        mouse_mode_size_group->add_widget (mouse_zoom_button);
 
2853
        mouse_mode_size_group->add_widget (mouse_gain_button);
 
2854
        mouse_mode_size_group->add_widget (mouse_timefx_button);
 
2855
        mouse_mode_size_group->add_widget (mouse_audition_button);
 
2856
        mouse_mode_size_group->add_widget (mouse_draw_button);
 
2857
        mouse_mode_size_group->add_widget (internal_edit_button);
 
2858
 
 
2859
        /* make them just a bit bigger */
 
2860
        mouse_move_button.set_size_request (-1, 30);
 
2861
 
 
2862
        mouse_mode_hbox->set_spacing (2);
 
2863
 
 
2864
        mouse_mode_hbox->pack_start (smart_mode_button, false, false);
 
2865
        mouse_mode_hbox->pack_start (mouse_move_button, false, false);
 
2866
        mouse_mode_hbox->pack_start (mouse_select_button, false, false);
 
2867
        mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
 
2868
        mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
 
2869
        mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
 
2870
        mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
 
2871
        mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
 
2872
        mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
 
2873
 
 
2874
        mouse_mode_vbox->pack_start (*mouse_mode_hbox);
 
2875
 
 
2876
        mouse_mode_align->add (*mouse_mode_vbox);
 
2877
        mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
 
2878
 
 
2879
        mouse_mode_box->pack_start (*mouse_mode_align, false, false);
 
2880
 
 
2881
        edit_mode_strings.push_back (edit_mode_to_string (Slide));
 
2882
        if (!Profile->get_sae()) {
 
2883
                edit_mode_strings.push_back (edit_mode_to_string (Splice));
 
2884
        }
 
2885
        edit_mode_strings.push_back (edit_mode_to_string (Lock));
 
2886
 
 
2887
        edit_mode_selector.set_name ("EditModeSelector");
 
2888
        set_popdown_strings (edit_mode_selector, edit_mode_strings);
 
2889
        edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
 
2890
 
 
2891
        mode_box->pack_start (edit_mode_selector, false, false);
 
2892
        mode_box->pack_start (*mouse_mode_box, false, false);
 
2893
 
 
2894
        _mouse_mode_tearoff = manage (new TearOff (*mode_box));
 
2895
        _mouse_mode_tearoff->set_name ("MouseModeBase");
 
2896
        _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
 
2897
 
 
2898
        if (Profile->get_sae()) {
 
2899
                _mouse_mode_tearoff->set_can_be_torn_off (false);
 
2900
        }
 
2901
 
 
2902
        _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
 
2903
                                                         &_mouse_mode_tearoff->tearoff_window()));
 
2904
        _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
 
2905
                                                         &_mouse_mode_tearoff->tearoff_window(), 1));
 
2906
        _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
 
2907
                                                         &_mouse_mode_tearoff->tearoff_window()));
 
2908
        _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
 
2909
                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
 
2910
 
 
2911
        /* Zoom */
 
2912
 
 
2913
        _zoom_box.set_spacing (2);
 
2914
        _zoom_box.set_border_width (2);
 
2915
 
 
2916
        RefPtr<Action> act;
 
2917
 
 
2918
        zoom_in_button.set_name ("zoom button");
 
2919
        zoom_in_button.add_elements ( ArdourButton::FlatFace );
 
2920
        zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
 
2921
        zoom_in_button.set_image(::get_icon ("zoom_in"));
 
2922
        act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
 
2923
        zoom_in_button.set_related_action (act);
 
2924
 
 
2925
        zoom_out_button.set_name ("zoom button");
 
2926
        zoom_out_button.add_elements ( ArdourButton::FlatFace );
 
2927
        zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
 
2928
        zoom_out_button.set_image(::get_icon ("zoom_out"));
 
2929
        act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
 
2930
        zoom_out_button.set_related_action (act);
 
2931
 
 
2932
        zoom_out_full_button.set_name ("zoom button");
 
2933
        zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
 
2934
        zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
 
2935
        zoom_out_full_button.set_image(::get_icon ("zoom_full"));
 
2936
        act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
 
2937
        zoom_out_full_button.set_related_action (act);
 
2938
 
 
2939
        zoom_focus_selector.set_name ("ZoomFocusSelector");
 
2940
        set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
 
2941
        zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
 
2942
 
 
2943
        _zoom_box.pack_start (zoom_out_button, false, false);
 
2944
        _zoom_box.pack_start (zoom_in_button, false, false);
 
2945
        _zoom_box.pack_start (zoom_out_full_button, false, false);
 
2946
 
 
2947
        _zoom_box.pack_start (zoom_focus_selector, false, false);
 
2948
 
 
2949
        /* Track zoom buttons */
 
2950
        tav_expand_button.set_name ("zoom button");
 
2951
        tav_expand_button.add_elements ( ArdourButton::FlatFace );
 
2952
        tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
 
2953
        tav_expand_button.set_size_request (-1, 20);
 
2954
        tav_expand_button.set_image(::get_icon ("tav_exp"));
 
2955
        act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
 
2956
        tav_expand_button.set_related_action (act);
 
2957
 
 
2958
        tav_shrink_button.set_name ("zoom button");
 
2959
        tav_shrink_button.add_elements ( ArdourButton::FlatFace );
 
2960
        tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
 
2961
        tav_shrink_button.set_size_request (-1, 20);
 
2962
        tav_shrink_button.set_image(::get_icon ("tav_shrink"));
 
2963
        act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
 
2964
        tav_shrink_button.set_related_action (act);
 
2965
 
 
2966
        _zoom_box.pack_start (tav_shrink_button);
 
2967
        _zoom_box.pack_start (tav_expand_button);
 
2968
 
 
2969
        _zoom_tearoff = manage (new TearOff (_zoom_box));
 
2970
 
 
2971
        _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
 
2972
                                                   &_zoom_tearoff->tearoff_window()));
 
2973
        _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
 
2974
                                                   &_zoom_tearoff->tearoff_window(), 0));
 
2975
        _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
 
2976
                                                   &_zoom_tearoff->tearoff_window()));
 
2977
        _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
 
2978
                                                    &_zoom_tearoff->tearoff_window(), 0));
 
2979
 
 
2980
        snap_box.set_spacing (2);
 
2981
        snap_box.set_border_width (2);
 
2982
 
 
2983
        snap_type_selector.set_name ("SnapTypeSelector");
 
2984
        set_popdown_strings (snap_type_selector, snap_type_strings);
 
2985
        snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
 
2986
 
 
2987
        snap_mode_selector.set_name ("SnapModeSelector");
 
2988
        set_popdown_strings (snap_mode_selector, snap_mode_strings);
 
2989
        snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
 
2990
 
 
2991
        edit_point_selector.set_name ("EditPointSelector");
 
2992
        set_popdown_strings (edit_point_selector, edit_point_strings);
 
2993
        edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
 
2994
 
 
2995
        snap_box.pack_start (snap_mode_selector, false, false);
 
2996
        snap_box.pack_start (snap_type_selector, false, false);
 
2997
        snap_box.pack_start (edit_point_selector, false, false);
 
2998
 
 
2999
        /* Nudge */
 
3000
 
 
3001
        HBox *nudge_box = manage (new HBox);
 
3002
        nudge_box->set_spacing (2);
 
3003
        nudge_box->set_border_width (2);
 
3004
 
 
3005
        nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
 
3006
        nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
 
3007
 
 
3008
        nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
 
3009
        nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
 
3010
 
 
3011
        nudge_box->pack_start (nudge_backward_button, false, false);
 
3012
        nudge_box->pack_start (nudge_forward_button, false, false);
 
3013
        nudge_box->pack_start (*nudge_clock, false, false);
 
3014
 
 
3015
 
 
3016
        /* Pack everything in... */
 
3017
 
 
3018
        HBox* hbox = manage (new HBox);
 
3019
        hbox->set_spacing(10);
 
3020
 
 
3021
        _tools_tearoff = manage (new TearOff (*hbox));
 
3022
        _tools_tearoff->set_name ("MouseModeBase");
 
3023
        _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
 
3024
 
 
3025
        if (Profile->get_sae()) {
 
3026
                _tools_tearoff->set_can_be_torn_off (false);
 
3027
        }
 
3028
 
 
3029
        _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
 
3030
                                                    &_tools_tearoff->tearoff_window()));
 
3031
        _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
 
3032
                                                    &_tools_tearoff->tearoff_window(), 0));
 
3033
        _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
 
3034
                                                    &_tools_tearoff->tearoff_window()));
 
3035
        _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
 
3036
                                                     &_tools_tearoff->tearoff_window(), 0));
 
3037
 
 
3038
        toolbar_hbox.set_spacing (10);
 
3039
        toolbar_hbox.set_border_width (1);
 
3040
 
 
3041
        toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
 
3042
        toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
 
3043
        toolbar_hbox.pack_start (*_tools_tearoff, false, false);
 
3044
 
 
3045
        hbox->pack_start (snap_box, false, false);
 
3046
        if (!Profile->get_small_screen()) {
 
3047
                hbox->pack_start (*nudge_box, false, false);
 
3048
        } else {
 
3049
                ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
 
3050
        }
 
3051
        hbox->pack_start (panic_box, false, false);
 
3052
 
 
3053
        hbox->show_all ();
 
3054
 
 
3055
        toolbar_base.set_name ("ToolBarBase");
 
3056
        toolbar_base.add (toolbar_hbox);
 
3057
 
 
3058
        _toolbar_viewport.add (toolbar_base);
 
3059
        /* stick to the required height but allow width to vary if there's not enough room */
 
3060
        _toolbar_viewport.set_size_request (1, -1);
 
3061
 
 
3062
        toolbar_frame.set_shadow_type (SHADOW_OUT);
 
3063
        toolbar_frame.set_name ("BaseFrame");
 
3064
        toolbar_frame.add (_toolbar_viewport);
 
3065
}
 
3066
 
 
3067
void
 
3068
Editor::setup_tooltips ()
 
3069
{
 
3070
        ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
 
3071
        ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
 
3072
        ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
 
3073
        ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
 
3074
        ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
 
3075
        ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
 
3076
        ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
 
3077
        ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
 
3078
        ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
 
3079
        ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
 
3080
        ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
 
3081
        ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
 
3082
        ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
 
3083
        ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
 
3084
        ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
 
3085
        ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
 
3086
        ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
 
3087
        ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
 
3088
        ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
 
3089
        ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
 
3090
        ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
 
3091
        ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
 
3092
        ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
 
3093
}
 
3094
 
 
3095
int
 
3096
Editor::convert_drop_to_paths (
 
3097
                vector<string>&                paths,
 
3098
                const RefPtr<Gdk::DragContext>& /*context*/,
 
3099
                gint                            /*x*/,
 
3100
                gint                            /*y*/,
 
3101
                const SelectionData&            data,
 
3102
                guint                           /*info*/,
 
3103
                guint                           /*time*/)
 
3104
{
 
3105
        if (_session == 0) {
 
3106
                return -1;
 
3107
        }
 
3108
 
 
3109
        vector<string> uris = data.get_uris();
 
3110
 
 
3111
        if (uris.empty()) {
 
3112
 
 
3113
                /* This is seriously fucked up. Nautilus doesn't say that its URI lists
 
3114
                   are actually URI lists. So do it by hand.
 
3115
                */
 
3116
 
 
3117
                if (data.get_target() != "text/plain") {
 
3118
                        return -1;
 
3119
                }
 
3120
 
 
3121
                /* Parse the "uri-list" format that Nautilus provides,
 
3122
                   where each pathname is delimited by \r\n.
 
3123
 
 
3124
                   THERE MAY BE NO NULL TERMINATING CHAR!!!
 
3125
                */
 
3126
 
 
3127
                string txt = data.get_text();
 
3128
                char* p;
 
3129
                const char* q;
 
3130
 
 
3131
                p = (char *) malloc (txt.length() + 1);
 
3132
                txt.copy (p, txt.length(), 0);
 
3133
                p[txt.length()] = '\0';
 
3134
 
 
3135
                while (p)
 
3136
                {
 
3137
                        if (*p != '#')
 
3138
                        {
 
3139
                                while (g_ascii_isspace (*p))
 
3140
                                        p++;
 
3141
 
 
3142
                                q = p;
 
3143
                                while (*q && (*q != '\n') && (*q != '\r')) {
 
3144
                                        q++;
 
3145
                                }
 
3146
 
 
3147
                                if (q > p)
 
3148
                                {
 
3149
                                        q--;
 
3150
                                        while (q > p && g_ascii_isspace (*q))
 
3151
                                                q--;
 
3152
 
 
3153
                                        if (q > p)
 
3154
                                        {
 
3155
                                                uris.push_back (string (p, q - p + 1));
 
3156
                                        }
 
3157
                                }
 
3158
                        }
 
3159
                        p = strchr (p, '\n');
 
3160
                        if (p)
 
3161
                                p++;
 
3162
                }
 
3163
 
 
3164
                free ((void*)p);
 
3165
 
 
3166
                if (uris.empty()) {
 
3167
                        return -1;
 
3168
                }
 
3169
        }
 
3170
 
 
3171
        for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
 
3172
 
 
3173
                if ((*i).substr (0,7) == "file://") {
 
3174
 
 
3175
                        string const p = PBD::url_decode (*i);
 
3176
 
 
3177
                        // scan forward past three slashes
 
3178
 
 
3179
                        string::size_type slashcnt = 0;
 
3180
                        string::size_type n = 0;
 
3181
                        string::const_iterator x = p.begin();
 
3182
 
 
3183
                        while (slashcnt < 3 && x != p.end()) {
 
3184
                                if ((*x) == '/') {
 
3185
                                        slashcnt++;
 
3186
                                } else if (slashcnt == 3) {
 
3187
                                        break;
 
3188
                                }
 
3189
                                ++n;
 
3190
                                ++x;
 
3191
                        }
 
3192
 
 
3193
                        if (slashcnt != 3 || x == p.end()) {
 
3194
                                error << _("malformed URL passed to drag-n-drop code") << endmsg;
 
3195
                                continue;
 
3196
                        }
 
3197
 
 
3198
                        paths.push_back (p.substr (n - 1));
 
3199
                }
 
3200
        }
 
3201
 
 
3202
        return 0;
 
3203
}
 
3204
 
 
3205
void
 
3206
Editor::new_tempo_section ()
 
3207
 
 
3208
{
 
3209
}
 
3210
 
 
3211
void
 
3212
Editor::map_transport_state ()
 
3213
{
 
3214
        ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
 
3215
 
 
3216
        if (_session && _session->transport_stopped()) {
 
3217
                have_pending_keyboard_selection = false;
 
3218
        }
 
3219
 
 
3220
        update_loop_range_view (true);
 
3221
}
 
3222
 
 
3223
/* UNDO/REDO */
 
3224
 
 
3225
void
 
3226
Editor::begin_reversible_command (string name)
 
3227
{
 
3228
        if (_session) {
 
3229
                _session->begin_reversible_command (name);
 
3230
        }
 
3231
}
 
3232
 
 
3233
void
 
3234
Editor::begin_reversible_command (GQuark q)
 
3235
{
 
3236
        if (_session) {
 
3237
                _session->begin_reversible_command (q);
 
3238
        }
 
3239
}
 
3240
 
 
3241
void
 
3242
Editor::commit_reversible_command ()
 
3243
{
 
3244
        if (_session) {
 
3245
                _session->commit_reversible_command ();
 
3246
        }
 
3247
}
 
3248
 
 
3249
void
 
3250
Editor::history_changed ()
 
3251
{
 
3252
        string label;
 
3253
 
 
3254
        if (undo_action && _session) {
 
3255
                if (_session->undo_depth() == 0) {
 
3256
                        label = S_("Command|Undo");
 
3257
                } else {
 
3258
                        label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
 
3259
                }
 
3260
                undo_action->property_label() = label;
 
3261
        }
 
3262
 
 
3263
        if (redo_action && _session) {
 
3264
                if (_session->redo_depth() == 0) {
 
3265
                        label = _("Redo");
 
3266
                } else {
 
3267
                        label = string_compose(_("Redo (%1)"), _session->next_redo());
 
3268
                }
 
3269
                redo_action->property_label() = label;
 
3270
        }
 
3271
}
 
3272
 
 
3273
void
 
3274
Editor::duplicate_range (bool with_dialog)
 
3275
{
 
3276
        float times = 1.0f;
 
3277
 
 
3278
        RegionSelection rs = get_regions_from_selection_and_entered ();
 
3279
 
 
3280
        if ( selection->time.length() == 0 && rs.empty()) {
 
3281
                return;
 
3282
        }
 
3283
 
 
3284
        if (with_dialog) {
 
3285
 
 
3286
                ArdourDialog win (_("Duplicate"));
 
3287
                Label label (_("Number of duplications:"));
 
3288
                Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
 
3289
                SpinButton spinner (adjustment, 0.0, 1);
 
3290
                HBox hbox;
 
3291
 
 
3292
                win.get_vbox()->set_spacing (12);
 
3293
                win.get_vbox()->pack_start (hbox);
 
3294
                hbox.set_border_width (6);
 
3295
                hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
 
3296
 
 
3297
                /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
 
3298
                   place, visually. so do this by hand.
 
3299
                */
 
3300
 
 
3301
                hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
 
3302
                spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
 
3303
                spinner.grab_focus();
 
3304
 
 
3305
                hbox.show ();
 
3306
                label.show ();
 
3307
                spinner.show ();
 
3308
 
 
3309
                win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
 
3310
                win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
 
3311
                win.set_default_response (RESPONSE_ACCEPT);
 
3312
 
 
3313
                spinner.grab_focus ();
 
3314
 
 
3315
                switch (win.run ()) {
 
3316
                case RESPONSE_ACCEPT:
 
3317
                        break;
 
3318
                default:
 
3319
                        return;
 
3320
                }
 
3321
 
 
3322
                times = adjustment.get_value();
 
3323
        }
 
3324
 
 
3325
        if ((current_mouse_mode() == Editing::MouseRange)) {
 
3326
                if (selection->time.length()) {
 
3327
                        duplicate_selection (times);
 
3328
                }
 
3329
        } else if (get_smart_mode()) {
 
3330
                if (selection->time.length()) {
 
3331
                        duplicate_selection (times);
 
3332
                } else 
 
3333
                        duplicate_some_regions (rs, times);
 
3334
        } else {
 
3335
                duplicate_some_regions (rs, times);
 
3336
        }
 
3337
}
 
3338
 
 
3339
void
 
3340
Editor::set_edit_mode (EditMode m)
 
3341
{
 
3342
        Config->set_edit_mode (m);
 
3343
}
 
3344
 
 
3345
void
 
3346
Editor::cycle_edit_mode ()
 
3347
{
 
3348
        switch (Config->get_edit_mode()) {
 
3349
        case Slide:
 
3350
                if (Profile->get_sae()) {
 
3351
                        Config->set_edit_mode (Lock);
 
3352
                } else {
 
3353
                        Config->set_edit_mode (Splice);
 
3354
                }
 
3355
                break;
 
3356
        case Splice:
 
3357
                Config->set_edit_mode (Lock);
 
3358
                break;
 
3359
        case Lock:
 
3360
                Config->set_edit_mode (Slide);
 
3361
                break;
 
3362
        }
 
3363
}
 
3364
 
 
3365
void
 
3366
Editor::edit_mode_selection_done ()
 
3367
{
 
3368
        string s = edit_mode_selector.get_active_text ();
 
3369
 
 
3370
        if (!s.empty()) {
 
3371
                Config->set_edit_mode (string_to_edit_mode (s));
 
3372
        }
 
3373
}
 
3374
 
 
3375
void
 
3376
Editor::snap_type_selection_done ()
 
3377
{
 
3378
        string choice = snap_type_selector.get_active_text();
 
3379
        SnapType snaptype = SnapToBeat;
 
3380
 
 
3381
        if (choice == _("Beats/2")) {
 
3382
                snaptype = SnapToBeatDiv2;
 
3383
        } else if (choice == _("Beats/3")) {
 
3384
                snaptype = SnapToBeatDiv3;
 
3385
        } else if (choice == _("Beats/4")) {
 
3386
                snaptype = SnapToBeatDiv4;
 
3387
        } else if (choice == _("Beats/5")) {
 
3388
                snaptype = SnapToBeatDiv5;
 
3389
        } else if (choice == _("Beats/6")) {
 
3390
                snaptype = SnapToBeatDiv6;
 
3391
        } else if (choice == _("Beats/7")) {
 
3392
                snaptype = SnapToBeatDiv7;
 
3393
        } else if (choice == _("Beats/8")) {
 
3394
                snaptype = SnapToBeatDiv8;
 
3395
        } else if (choice == _("Beats/10")) {
 
3396
                snaptype = SnapToBeatDiv10;
 
3397
        } else if (choice == _("Beats/12")) {
 
3398
                snaptype = SnapToBeatDiv12;
 
3399
        } else if (choice == _("Beats/14")) {
 
3400
                snaptype = SnapToBeatDiv14;
 
3401
        } else if (choice == _("Beats/16")) {
 
3402
                snaptype = SnapToBeatDiv16;
 
3403
        } else if (choice == _("Beats/20")) {
 
3404
                snaptype = SnapToBeatDiv20;
 
3405
        } else if (choice == _("Beats/24")) {
 
3406
                snaptype = SnapToBeatDiv24;
 
3407
        } else if (choice == _("Beats/28")) {
 
3408
                snaptype = SnapToBeatDiv28;
 
3409
        } else if (choice == _("Beats/32")) {
 
3410
                snaptype = SnapToBeatDiv32;
 
3411
        } else if (choice == _("Beats/64")) {
 
3412
                snaptype = SnapToBeatDiv64;
 
3413
        } else if (choice == _("Beats/128")) {
 
3414
                snaptype = SnapToBeatDiv128;
 
3415
        } else if (choice == _("Beats")) {
 
3416
                snaptype = SnapToBeat;
 
3417
        } else if (choice == _("Bars")) {
 
3418
                snaptype = SnapToBar;
 
3419
        } else if (choice == _("Marks")) {
 
3420
                snaptype = SnapToMark;
 
3421
        } else if (choice == _("Region starts")) {
 
3422
                snaptype = SnapToRegionStart;
 
3423
        } else if (choice == _("Region ends")) {
 
3424
                snaptype = SnapToRegionEnd;
 
3425
        } else if (choice == _("Region bounds")) {
 
3426
                snaptype = SnapToRegionBoundary;
 
3427
        } else if (choice == _("Region syncs")) {
 
3428
                snaptype = SnapToRegionSync;
 
3429
        } else if (choice == _("CD Frames")) {
 
3430
                snaptype = SnapToCDFrame;
 
3431
        } else if (choice == _("Timecode Frames")) {
 
3432
                snaptype = SnapToTimecodeFrame;
 
3433
        } else if (choice == _("Timecode Seconds")) {
 
3434
                snaptype = SnapToTimecodeSeconds;
 
3435
        } else if (choice == _("Timecode Minutes")) {
 
3436
                snaptype = SnapToTimecodeMinutes;
 
3437
        } else if (choice == _("Seconds")) {
 
3438
                snaptype = SnapToSeconds;
 
3439
        } else if (choice == _("Minutes")) {
 
3440
                snaptype = SnapToMinutes;
 
3441
        }
 
3442
 
 
3443
        RefPtr<RadioAction> ract = snap_type_action (snaptype);
 
3444
        if (ract) {
 
3445
                ract->set_active ();
 
3446
        }
 
3447
}
 
3448
 
 
3449
void
 
3450
Editor::snap_mode_selection_done ()
 
3451
{
 
3452
        string choice = snap_mode_selector.get_active_text();
 
3453
        SnapMode mode = SnapNormal;
 
3454
 
 
3455
        if (choice == _("No Grid")) {
 
3456
                mode = SnapOff;
 
3457
        } else if (choice == _("Grid")) {
 
3458
                mode = SnapNormal;
 
3459
        } else if (choice == _("Magnetic")) {
 
3460
                mode = SnapMagnetic;
 
3461
        }
 
3462
 
 
3463
        RefPtr<RadioAction> ract = snap_mode_action (mode);
 
3464
 
 
3465
        if (ract) {
 
3466
                ract->set_active (true);
 
3467
        }
 
3468
}
 
3469
 
 
3470
void
 
3471
Editor::cycle_edit_point (bool with_marker)
 
3472
{
 
3473
        switch (_edit_point) {
 
3474
        case EditAtMouse:
 
3475
                set_edit_point_preference (EditAtPlayhead);
 
3476
                break;
 
3477
        case EditAtPlayhead:
 
3478
                if (with_marker) {
 
3479
                        set_edit_point_preference (EditAtSelectedMarker);
 
3480
                } else {
 
3481
                        set_edit_point_preference (EditAtMouse);
 
3482
                }
 
3483
                break;
 
3484
        case EditAtSelectedMarker:
 
3485
                set_edit_point_preference (EditAtMouse);
 
3486
                break;
 
3487
        }
 
3488
}
 
3489
 
 
3490
void
 
3491
Editor::edit_point_selection_done ()
 
3492
{
 
3493
        string choice = edit_point_selector.get_active_text();
 
3494
        EditPoint ep = EditAtSelectedMarker;
 
3495
 
 
3496
        if (choice == _("Marker")) {
 
3497
                set_edit_point_preference (EditAtSelectedMarker);
 
3498
        } else if (choice == _("Playhead")) {
 
3499
                set_edit_point_preference (EditAtPlayhead);
 
3500
        } else {
 
3501
                set_edit_point_preference (EditAtMouse);
 
3502
        }
 
3503
 
 
3504
        RefPtr<RadioAction> ract = edit_point_action (ep);
 
3505
 
 
3506
        if (ract) {
 
3507
                ract->set_active (true);
 
3508
        }
 
3509
}
 
3510
 
 
3511
void
 
3512
Editor::zoom_focus_selection_done ()
 
3513
{
 
3514
        string choice = zoom_focus_selector.get_active_text();
 
3515
        ZoomFocus focus_type = ZoomFocusLeft;
 
3516
 
 
3517
        if (choice == _("Left")) {
 
3518
                focus_type = ZoomFocusLeft;
 
3519
        } else if (choice == _("Right")) {
 
3520
                focus_type = ZoomFocusRight;
 
3521
        } else if (choice == _("Center")) {
 
3522
                focus_type = ZoomFocusCenter;
 
3523
        } else if (choice == _("Playhead")) {
 
3524
                focus_type = ZoomFocusPlayhead;
 
3525
        } else if (choice == _("Mouse")) {
 
3526
                focus_type = ZoomFocusMouse;
 
3527
        } else if (choice == _("Edit point")) {
 
3528
                focus_type = ZoomFocusEdit;
 
3529
        }
 
3530
 
 
3531
        RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
 
3532
 
 
3533
        if (ract) {
 
3534
                ract->set_active ();
 
3535
        }
 
3536
}
 
3537
 
 
3538
bool
 
3539
Editor::edit_controls_button_release (GdkEventButton* ev)
 
3540
{
 
3541
        if (Keyboard::is_context_menu_event (ev)) {
 
3542
                ARDOUR_UI::instance()->add_route (this);
 
3543
        } else if (ev->button == 1) {
 
3544
                selection->clear_tracks ();
 
3545
        }
 
3546
 
 
3547
        return true;
 
3548
}
 
3549
 
 
3550
bool
 
3551
Editor::mouse_select_button_release (GdkEventButton* ev)
 
3552
{
 
3553
        /* this handles just right-clicks */
 
3554
 
 
3555
        if (ev->button != 3) {
 
3556
                return false;
 
3557
        }
 
3558
 
 
3559
        return true;
 
3560
}
 
3561
 
 
3562
void
 
3563
Editor::set_zoom_focus (ZoomFocus f)
 
3564
{
 
3565
        string str = zoom_focus_strings[(int)f];
 
3566
 
 
3567
        if (str != zoom_focus_selector.get_active_text()) {
 
3568
                zoom_focus_selector.set_active_text (str);
 
3569
        }
 
3570
 
 
3571
        if (zoom_focus != f) {
 
3572
                zoom_focus = f;
 
3573
                instant_save ();
 
3574
        }
 
3575
}
 
3576
 
 
3577
void
 
3578
Editor::cycle_zoom_focus ()
 
3579
{
 
3580
        switch (zoom_focus) {
 
3581
        case ZoomFocusLeft:
 
3582
                set_zoom_focus (ZoomFocusRight);
 
3583
                break;
 
3584
        case ZoomFocusRight:
 
3585
                set_zoom_focus (ZoomFocusCenter);
 
3586
                break;
 
3587
        case ZoomFocusCenter:
 
3588
                set_zoom_focus (ZoomFocusPlayhead);
 
3589
                break;
 
3590
        case ZoomFocusPlayhead:
 
3591
                set_zoom_focus (ZoomFocusMouse);
 
3592
                break;
 
3593
        case ZoomFocusMouse:
 
3594
                set_zoom_focus (ZoomFocusEdit);
 
3595
                break;
 
3596
        case ZoomFocusEdit:
 
3597
                set_zoom_focus (ZoomFocusLeft);
 
3598
                break;
 
3599
        }
 
3600
}
 
3601
 
 
3602
void
 
3603
Editor::ensure_float (Window& win)
 
3604
{
 
3605
        win.set_transient_for (*this);
 
3606
}
 
3607
 
 
3608
void
 
3609
Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 
3610
{
 
3611
        /* recover or initialize pane positions. do this here rather than earlier because
 
3612
           we don't want the positions to change the child allocations, which they seem to do.
 
3613
         */
 
3614
 
 
3615
        int pos;
 
3616
        XMLProperty* prop;
 
3617
        char buf[32];
 
3618
        XMLNode* node = ARDOUR_UI::instance()->editor_settings();
 
3619
 
 
3620
        enum Pane {
 
3621
                Horizontal = 0x1,
 
3622
                Vertical = 0x2
 
3623
        };
 
3624
 
 
3625
        static Pane done;
 
3626
 
 
3627
        XMLNode* geometry = find_named_node (*node, "geometry");
 
3628
 
 
3629
        if (which == static_cast<Paned*> (&edit_pane)) {
 
3630
 
 
3631
                if (done & Horizontal) {
 
3632
                        return;
 
3633
                }
 
3634
 
 
3635
                if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
 
3636
                        _notebook_shrunk = string_is_affirmative (prop->value ());
 
3637
                }
 
3638
 
 
3639
                if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
 
3640
                        /* initial allocation is 90% to canvas, 10% to notebook */
 
3641
                        pos = (int) floor (alloc.get_width() * 0.90f);
 
3642
                        snprintf (buf, sizeof(buf), "%d", pos);
 
3643
                } else {
 
3644
                        pos = atoi (prop->value());
 
3645
                }
 
3646
 
 
3647
                if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
 
3648
                        edit_pane.set_position (pos);
 
3649
                }
 
3650
 
 
3651
                done = (Pane) (done | Horizontal);
 
3652
 
 
3653
        } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
 
3654
 
 
3655
                if (done & Vertical) {
 
3656
                        return;
 
3657
                }
 
3658
 
 
3659
                if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
 
3660
                        /* initial allocation is 90% to canvas, 10% to summary */
 
3661
                        pos = (int) floor (alloc.get_height() * 0.90f);
 
3662
                        snprintf (buf, sizeof(buf), "%d", pos);
 
3663
                } else {
 
3664
 
 
3665
                        pos = atoi (prop->value());
 
3666
                }
 
3667
 
 
3668
                if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
 
3669
                        editor_summary_pane.set_position (pos);
 
3670
                }
 
3671
 
 
3672
                done = (Pane) (done | Vertical);
 
3673
        }
 
3674
}
 
3675
 
 
3676
void
 
3677
Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
 
3678
{
 
3679
        if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
 
3680
            (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
 
3681
            (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
 
3682
                top_hbox.remove (toolbar_frame);
 
3683
        }
 
3684
}
 
3685
 
 
3686
void
 
3687
Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
 
3688
{
 
3689
        if (toolbar_frame.get_parent() == 0) {
 
3690
                top_hbox.pack_end (toolbar_frame);
 
3691
        }
 
3692
}
 
3693
 
 
3694
void
 
3695
Editor::set_show_measures (bool yn)
 
3696
{
 
3697
        if (_show_measures != yn) {
 
3698
                hide_measures ();
 
3699
 
 
3700
                if ((_show_measures = yn) == true) {
 
3701
                        if (tempo_lines) {
 
3702
                                tempo_lines->show();
 
3703
                        }
 
3704
                        (void) redraw_measures ();
 
3705
                }
 
3706
                instant_save ();
 
3707
        }
 
3708
}
 
3709
 
 
3710
void
 
3711
Editor::toggle_follow_playhead ()
 
3712
{
 
3713
        RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
 
3714
        if (act) {
 
3715
                RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
3716
                set_follow_playhead (tact->get_active());
 
3717
        }
 
3718
}
 
3719
 
 
3720
/** @param yn true to follow playhead, otherwise false.
 
3721
 *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
 
3722
 */
 
3723
void
 
3724
Editor::set_follow_playhead (bool yn, bool catch_up)
 
3725
{
 
3726
        if (_follow_playhead != yn) {
 
3727
                if ((_follow_playhead = yn) == true && catch_up) {
 
3728
                        /* catch up */
 
3729
                        reset_x_origin_to_follow_playhead ();
 
3730
                }
 
3731
                instant_save ();
 
3732
        }
 
3733
}
 
3734
 
 
3735
void
 
3736
Editor::toggle_stationary_playhead ()
 
3737
{
 
3738
        RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
 
3739
        if (act) {
 
3740
                RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
 
3741
                set_stationary_playhead (tact->get_active());
 
3742
        }
 
3743
}
 
3744
 
 
3745
void
 
3746
Editor::set_stationary_playhead (bool yn)
 
3747
{
 
3748
        if (_stationary_playhead != yn) {
 
3749
                if ((_stationary_playhead = yn) == true) {
 
3750
                        /* catch up */
 
3751
                        // FIXME need a 3.0 equivalent of this 2.X call
 
3752
                        // update_current_screen ();
 
3753
                }
 
3754
                instant_save ();
 
3755
        }
 
3756
}
 
3757
 
 
3758
PlaylistSelector&
 
3759
Editor::playlist_selector () const
 
3760
{
 
3761
        return *_playlist_selector;
 
3762
}
 
3763
 
 
3764
Evoral::MusicalTime
 
3765
Editor::get_grid_type_as_beats (bool& success, framepos_t position)
 
3766
{
 
3767
        success = true;
 
3768
 
 
3769
        switch (_snap_type) {
 
3770
        case SnapToBeat:
 
3771
                return 1.0;
 
3772
                break;
 
3773
 
 
3774
        case SnapToBeatDiv128:
 
3775
                return 1.0/128.0;
 
3776
                break;
 
3777
        case SnapToBeatDiv64:
 
3778
                return 1.0/64.0;
 
3779
                break;
 
3780
        case SnapToBeatDiv32:
 
3781
                return 1.0/32.0;
 
3782
                break;
 
3783
        case SnapToBeatDiv28:
 
3784
                return 1.0/28.0;
 
3785
                break;
 
3786
        case SnapToBeatDiv24:
 
3787
                return 1.0/24.0;
 
3788
                break;
 
3789
        case SnapToBeatDiv20:
 
3790
                return 1.0/20.0;
 
3791
                break;
 
3792
        case SnapToBeatDiv16:
 
3793
                return 1.0/16.0;
 
3794
                break;
 
3795
        case SnapToBeatDiv14:
 
3796
                return 1.0/14.0;
 
3797
                break;
 
3798
        case SnapToBeatDiv12:
 
3799
                return 1.0/12.0;
 
3800
                break;
 
3801
        case SnapToBeatDiv10:
 
3802
                return 1.0/10.0;
 
3803
                break;
 
3804
        case SnapToBeatDiv8:
 
3805
                return 1.0/8.0;
 
3806
                break;
 
3807
        case SnapToBeatDiv7:
 
3808
                return 1.0/7.0;
 
3809
                break;
 
3810
        case SnapToBeatDiv6:
 
3811
                return 1.0/6.0;
 
3812
                break;
 
3813
        case SnapToBeatDiv5:
 
3814
                return 1.0/5.0;
 
3815
                break;
 
3816
        case SnapToBeatDiv4:
 
3817
                return 1.0/4.0;
 
3818
                break;
 
3819
        case SnapToBeatDiv3:
 
3820
                return 1.0/3.0;
 
3821
                break;
 
3822
        case SnapToBeatDiv2:
 
3823
                return 1.0/2.0;
 
3824
                break;
 
3825
 
 
3826
        case SnapToBar:
 
3827
                if (_session) {
 
3828
                        return _session->tempo_map().meter_at (position).divisions_per_bar();
 
3829
                }
 
3830
                break;
 
3831
 
 
3832
        case SnapToCDFrame:
 
3833
        case SnapToTimecodeFrame:
 
3834
        case SnapToTimecodeSeconds:
 
3835
        case SnapToTimecodeMinutes:
 
3836
        case SnapToSeconds:
 
3837
        case SnapToMinutes:
 
3838
        case SnapToRegionStart:
 
3839
        case SnapToRegionEnd:
 
3840
        case SnapToRegionSync:
 
3841
        case SnapToRegionBoundary:
 
3842
        default:
 
3843
                success = false;
 
3844
                break;
 
3845
        }
 
3846
 
 
3847
        return 0.0;
 
3848
}
 
3849
 
 
3850
framecnt_t
 
3851
Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
 
3852
{
 
3853
        framecnt_t ret;
 
3854
 
 
3855
        ret = nudge_clock->current_duration (pos);
 
3856
        next = ret + 1; /* XXXX fix me */
 
3857
 
 
3858
        return ret;
 
3859
}
 
3860
 
 
3861
int
 
3862
Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
 
3863
{
 
3864
        ArdourDialog dialog (_("Playlist Deletion"));
 
3865
        Label  label (string_compose (_("Playlist %1 is currently unused.\n"
 
3866
                                        "If it is kept, its audio files will not be cleaned.\n"
 
3867
                                        "If it is deleted, audio files used by it alone will be cleaned."),
 
3868
                                      pl->name()));
 
3869
 
 
3870
        dialog.set_position (WIN_POS_CENTER);
 
3871
        dialog.get_vbox()->pack_start (label);
 
3872
 
 
3873
        label.show ();
 
3874
 
 
3875
        dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
 
3876
        dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
 
3877
        dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
 
3878
 
 
3879
        switch (dialog.run ()) {
 
3880
        case RESPONSE_ACCEPT:
 
3881
                /* delete the playlist */
 
3882
                return 0;
 
3883
                break;
 
3884
 
 
3885
        case RESPONSE_REJECT:
 
3886
                /* keep the playlist */
 
3887
                return 1;
 
3888
                break;
 
3889
 
 
3890
        default:
 
3891
                break;
 
3892
        }
 
3893
 
 
3894
        return -1;
 
3895
}
 
3896
 
 
3897
bool
 
3898
Editor::audio_region_selection_covers (framepos_t where)
 
3899
{
 
3900
        for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
 
3901
                if ((*a)->region()->covers (where)) {
 
3902
                        return true;
 
3903
                }
 
3904
        }
 
3905
 
 
3906
        return false;
 
3907
}
 
3908
 
 
3909
void
 
3910
Editor::prepare_for_cleanup ()
 
3911
{
 
3912
        cut_buffer->clear_regions ();
 
3913
        cut_buffer->clear_playlists ();
 
3914
 
 
3915
        selection->clear_regions ();
 
3916
        selection->clear_playlists ();
 
3917
 
 
3918
        _regions->suspend_redisplay ();
 
3919
}
 
3920
 
 
3921
void
 
3922
Editor::finish_cleanup ()
 
3923
{
 
3924
        _regions->resume_redisplay ();
 
3925
}
 
3926
 
 
3927
Location*
 
3928
Editor::transport_loop_location()
 
3929
{
 
3930
        if (_session) {
 
3931
                return _session->locations()->auto_loop_location();
 
3932
        } else {
 
3933
                return 0;
 
3934
        }
 
3935
}
 
3936
 
 
3937
Location*
 
3938
Editor::transport_punch_location()
 
3939
{
 
3940
        if (_session) {
 
3941
                return _session->locations()->auto_punch_location();
 
3942
        } else {
 
3943
                return 0;
 
3944
        }
 
3945
}
 
3946
 
 
3947
bool
 
3948
Editor::control_layout_scroll (GdkEventScroll* ev)
 
3949
{
 
3950
        if (Keyboard::some_magic_widget_has_focus()) {
 
3951
                return false;
 
3952
        }
 
3953
 
 
3954
        switch (ev->direction) {
 
3955
        case GDK_SCROLL_UP:
 
3956
                scroll_tracks_up_line ();
 
3957
                return true;
 
3958
                break;
 
3959
 
 
3960
        case GDK_SCROLL_DOWN:
 
3961
                scroll_tracks_down_line ();
 
3962
                return true;
 
3963
 
 
3964
        default:
 
3965
                /* no left/right handling yet */
 
3966
                break;
 
3967
        }
 
3968
 
 
3969
        return false;
 
3970
}
 
3971
 
 
3972
void
 
3973
Editor::session_state_saved (string)
 
3974
{
 
3975
        update_title ();
 
3976
        _snapshots->redisplay ();
 
3977
}
 
3978
 
 
3979
void
 
3980
Editor::update_tearoff_visibility()
 
3981
{
 
3982
        bool visible = Config->get_keep_tearoffs();
 
3983
        _mouse_mode_tearoff->set_visible (visible);
 
3984
        _tools_tearoff->set_visible (visible);
 
3985
        _zoom_tearoff->set_visible (visible);
 
3986
}
 
3987
 
 
3988
void
 
3989
Editor::maximise_editing_space ()
 
3990
{
 
3991
        if (_maximised) {
 
3992
                return;
 
3993
        }
 
3994
 
 
3995
        fullscreen ();
 
3996
 
 
3997
        _maximised = true;
 
3998
}
 
3999
 
 
4000
void
 
4001
Editor::restore_editing_space ()
 
4002
{
 
4003
        if (!_maximised) {
 
4004
                return;
 
4005
        }
 
4006
 
 
4007
        unfullscreen();
 
4008
 
 
4009
        _maximised = false;
 
4010
}
 
4011
 
 
4012
/**
 
4013
 *  Make new playlists for a given track and also any others that belong
 
4014
 *  to the same active route group with the `select' property.
 
4015
 *  @param v Track.
 
4016
 */
 
4017
 
 
4018
void
 
4019
Editor::new_playlists (TimeAxisView* v)
 
4020
{
 
4021
        begin_reversible_command (_("new playlists"));
 
4022
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
 
4023
        _session->playlists->get (playlists);
 
4024
        mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
 
4025
        commit_reversible_command ();
 
4026
}
 
4027
 
 
4028
/**
 
4029
 *  Use a copy of the current playlist for a given track and also any others that belong
 
4030
 *  to the same active route group with the `select' property.
 
4031
 *  @param v Track.
 
4032
 */
 
4033
 
 
4034
void
 
4035
Editor::copy_playlists (TimeAxisView* v)
 
4036
{
 
4037
        begin_reversible_command (_("copy playlists"));
 
4038
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
 
4039
        _session->playlists->get (playlists);
 
4040
        mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
 
4041
        commit_reversible_command ();
 
4042
}
 
4043
 
 
4044
/** Clear the current playlist for a given track and also any others that belong
 
4045
 *  to the same active route group with the `select' property.
 
4046
 *  @param v Track.
 
4047
 */
 
4048
 
 
4049
void
 
4050
Editor::clear_playlists (TimeAxisView* v)
 
4051
{
 
4052
        begin_reversible_command (_("clear playlists"));
 
4053
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
 
4054
        _session->playlists->get (playlists);
 
4055
        mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
 
4056
        commit_reversible_command ();
 
4057
}
 
4058
 
 
4059
void
 
4060
Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
 
4061
{
 
4062
        atv.use_new_playlist (sz > 1 ? false : true, playlists);
 
4063
}
 
4064
 
 
4065
void
 
4066
Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
 
4067
{
 
4068
        atv.use_copy_playlist (sz > 1 ? false : true, playlists);
 
4069
}
 
4070
 
 
4071
void
 
4072
Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
 
4073
{
 
4074
        atv.clear_playlist ();
 
4075
}
 
4076
 
 
4077
bool
 
4078
Editor::on_key_press_event (GdkEventKey* ev)
 
4079
{
 
4080
        return key_press_focus_accelerator_handler (*this, ev);
 
4081
}
 
4082
 
 
4083
bool
 
4084
Editor::on_key_release_event (GdkEventKey* ev)
 
4085
{
 
4086
        return Gtk::Window::on_key_release_event (ev);
 
4087
        // return key_press_focus_accelerator_handler (*this, ev);
 
4088
}
 
4089
 
 
4090
/** Queue up a change to the viewport x origin.
 
4091
 *  @param frame New x origin.
 
4092
 */
 
4093
void
 
4094
Editor::reset_x_origin (framepos_t frame)
 
4095
{
 
4096
        pending_visual_change.add (VisualChange::TimeOrigin);
 
4097
        pending_visual_change.time_origin = frame;
 
4098
        ensure_visual_change_idle_handler ();
 
4099
}
 
4100
 
 
4101
void
 
4102
Editor::reset_y_origin (double y)
 
4103
{
 
4104
        pending_visual_change.add (VisualChange::YOrigin);
 
4105
        pending_visual_change.y_origin = y;
 
4106
        ensure_visual_change_idle_handler ();
 
4107
}
 
4108
 
 
4109
void
 
4110
Editor::reset_zoom (double fpu)
 
4111
{
 
4112
        clamp_frames_per_unit (fpu);
 
4113
 
 
4114
        if (fpu == frames_per_unit) {
 
4115
                return;
 
4116
        }
 
4117
 
 
4118
        pending_visual_change.add (VisualChange::ZoomLevel);
 
4119
        pending_visual_change.frames_per_unit = fpu;
 
4120
        ensure_visual_change_idle_handler ();
 
4121
}
 
4122
 
 
4123
void
 
4124
Editor::reposition_and_zoom (framepos_t frame, double fpu)
 
4125
{
 
4126
        reset_x_origin (frame);
 
4127
        reset_zoom (fpu);
 
4128
 
 
4129
        if (!no_save_visual) {
 
4130
                undo_visual_stack.push_back (current_visual_state(false));
 
4131
        }
 
4132
}
 
4133
 
 
4134
Editor::VisualState::VisualState (bool with_tracks)
 
4135
        : gui_state (with_tracks ? new GUIObjectState : 0)
 
4136
{
 
4137
}
 
4138
 
 
4139
Editor::VisualState::~VisualState ()
 
4140
{
 
4141
        delete gui_state;
 
4142
}
 
4143
 
 
4144
Editor::VisualState*
 
4145
Editor::current_visual_state (bool with_tracks)
 
4146
{
 
4147
        VisualState* vs = new VisualState (with_tracks);
 
4148
        vs->y_position = vertical_adjustment.get_value();
 
4149
        vs->frames_per_unit = frames_per_unit;
 
4150
        vs->leftmost_frame = leftmost_frame;
 
4151
        vs->zoom_focus = zoom_focus;
 
4152
 
 
4153
        if (with_tracks) {      
 
4154
                *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
 
4155
        }
 
4156
 
 
4157
        return vs;
 
4158
}
 
4159
 
 
4160
void
 
4161
Editor::undo_visual_state ()
 
4162
{
 
4163
        if (undo_visual_stack.empty()) {
 
4164
                return;
 
4165
        }
 
4166
 
 
4167
        VisualState* vs = undo_visual_stack.back();
 
4168
        undo_visual_stack.pop_back();
 
4169
 
 
4170
 
 
4171
        redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
 
4172
 
 
4173
        use_visual_state (*vs);
 
4174
}
 
4175
 
 
4176
void
 
4177
Editor::redo_visual_state ()
 
4178
{
 
4179
        if (redo_visual_stack.empty()) {
 
4180
                return;
 
4181
        }
 
4182
 
 
4183
        VisualState* vs = redo_visual_stack.back();
 
4184
        redo_visual_stack.pop_back();
 
4185
 
 
4186
        undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
 
4187
 
 
4188
        use_visual_state (*vs);
 
4189
}
 
4190
 
 
4191
void
 
4192
Editor::swap_visual_state ()
 
4193
{
 
4194
        if (undo_visual_stack.empty()) {
 
4195
                redo_visual_state ();
 
4196
        } else {
 
4197
                undo_visual_state ();
 
4198
        }
 
4199
}
 
4200
 
 
4201
void
 
4202
Editor::use_visual_state (VisualState& vs)
 
4203
{
 
4204
        PBD::Unwinder<bool> nsv (no_save_visual, true);
 
4205
 
 
4206
        _routes->suspend_redisplay ();
 
4207
 
 
4208
        vertical_adjustment.set_value (vs.y_position);
 
4209
 
 
4210
        set_zoom_focus (vs.zoom_focus);
 
4211
        reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
 
4212
        
 
4213
        if (vs.gui_state) {
 
4214
                *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
 
4215
                
 
4216
                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
 
4217
                        (*i)->reset_visual_state ();
 
4218
                }
 
4219
        }
 
4220
 
 
4221
        _routes->update_visibility ();
 
4222
        _routes->resume_redisplay ();
 
4223
}
 
4224
 
 
4225
/** This is the core function that controls the zoom level of the canvas. It is called
 
4226
 *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
 
4227
 *  @param fpu New frames per unit; should already have been clamped so that it is sensible.
 
4228
 */
 
4229
void
 
4230
Editor::set_frames_per_unit (double fpu)
 
4231
{
 
4232
        if (tempo_lines) {
 
4233
                tempo_lines->tempo_map_changed();
 
4234
        }
 
4235
 
 
4236
        frames_per_unit = fpu;
 
4237
 
 
4238
        /* convert fpu to frame count */
 
4239
 
 
4240
        framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
 
4241
 
 
4242
        if (frames_per_unit != zoom_range_clock->current_duration()) {
 
4243
                zoom_range_clock->set (frames);
 
4244
        }
 
4245
 
 
4246
        bool const showing_time_selection = selection->time.length() > 0;
 
4247
 
 
4248
        if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
 
4249
                for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
 
4250
                        (*i)->reshow_selection (selection->time);
 
4251
                }
 
4252
        }
 
4253
 
 
4254
        ZoomChanged (); /* EMIT_SIGNAL */
 
4255
 
 
4256
        //reset_scrolling_region ();
 
4257
 
 
4258
        if (playhead_cursor) {
 
4259
                playhead_cursor->set_position (playhead_cursor->current_frame);
 
4260
        }
 
4261
 
 
4262
        refresh_location_display();
 
4263
        _summary->set_overlays_dirty ();
 
4264
 
 
4265
        update_marker_labels ();
 
4266
 
 
4267
        instant_save ();
 
4268
}
 
4269
 
 
4270
void
 
4271
Editor::queue_visual_videotimeline_update ()
 
4272
{
 
4273
        /* TODO:
 
4274
         * pending_visual_change.add (VisualChange::VideoTimeline);
 
4275
         * or maybe even more specific: which videotimeline-image
 
4276
         * currently it calls update_video_timeline() to update
 
4277
         * _all outdated_ images on the video-timeline.
 
4278
         * see 'exposeimg()' in video_image_frame.cc
 
4279
         */
 
4280
        ensure_visual_change_idle_handler ();
 
4281
}
 
4282
 
 
4283
void
 
4284
Editor::ensure_visual_change_idle_handler ()
 
4285
{
 
4286
        if (pending_visual_change.idle_handler_id < 0) {
 
4287
                pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
 
4288
        }
 
4289
}
 
4290
 
 
4291
int
 
4292
Editor::_idle_visual_changer (void* arg)
 
4293
{
 
4294
        return static_cast<Editor*>(arg)->idle_visual_changer ();
 
4295
}
 
4296
 
 
4297
int
 
4298
Editor::idle_visual_changer ()
 
4299
{
 
4300
        /* set_horizontal_position() below (and maybe other calls) call
 
4301
           gtk_main_iteration(), so it's possible that a signal will be handled
 
4302
           half-way through this method.  If this signal wants an
 
4303
           idle_visual_changer we must schedule another one after this one, so
 
4304
           mark the idle_handler_id as -1 here to allow that.  Also make a note
 
4305
           that we are doing the visual change, so that changes in response to
 
4306
           super-rapid-screen-update can be dropped if we are still processing
 
4307
           the last one.
 
4308
        */
 
4309
 
 
4310
        pending_visual_change.idle_handler_id = -1;
 
4311
        pending_visual_change.being_handled = true;
 
4312
        
 
4313
        VisualChange::Type p = pending_visual_change.pending;
 
4314
        pending_visual_change.pending = (VisualChange::Type) 0;
 
4315
 
 
4316
        double const last_time_origin = horizontal_position ();
 
4317
 
 
4318
        if (p & VisualChange::ZoomLevel) {
 
4319
                set_frames_per_unit (pending_visual_change.frames_per_unit);
 
4320
 
 
4321
                compute_fixed_ruler_scale ();
 
4322
 
 
4323
                ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
 
4324
                ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
 
4325
                
 
4326
                compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
 
4327
                                            current_bbt_points_begin, current_bbt_points_end);
 
4328
                compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
 
4329
                                         current_bbt_points_begin, current_bbt_points_end);
 
4330
                update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
 
4331
        }
 
4332
 
 
4333
        if (p & VisualChange::ZoomLevel) {
 
4334
                update_video_timeline();
 
4335
        }
 
4336
 
 
4337
        if (p & VisualChange::TimeOrigin) {
 
4338
                set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
 
4339
        }
 
4340
 
 
4341
        if (p & VisualChange::YOrigin) {
 
4342
                vertical_adjustment.set_value (pending_visual_change.y_origin);
 
4343
        }
 
4344
 
 
4345
        if (last_time_origin == horizontal_position ()) {
 
4346
                /* changed signal not emitted */
 
4347
                update_fixed_rulers ();
 
4348
                redisplay_tempo (true);
 
4349
        }
 
4350
 
 
4351
        if (!(p & VisualChange::ZoomLevel)) {
 
4352
                update_video_timeline();
 
4353
        }
 
4354
 
 
4355
        _summary->set_overlays_dirty ();
 
4356
 
 
4357
        pending_visual_change.being_handled = false;
 
4358
        return 0; /* this is always a one-shot call */
 
4359
}
 
4360
 
 
4361
struct EditorOrderTimeAxisSorter {
 
4362
    bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
 
4363
            return a->order () < b->order ();
 
4364
    }
 
4365
};
 
4366
 
 
4367
void
 
4368
Editor::sort_track_selection (TrackViewList& sel)
 
4369
{
 
4370
        EditorOrderTimeAxisSorter cmp;
 
4371
        sel.sort (cmp);
 
4372
}
 
4373
 
 
4374
framepos_t
 
4375
Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
 
4376
{
 
4377
        bool ignored;
 
4378
        framepos_t where = 0;
 
4379
        EditPoint ep = _edit_point;
 
4380
 
 
4381
        if (from_context_menu && (ep == EditAtMouse)) {
 
4382
                return  event_frame (&context_click_event, 0, 0);
 
4383
        }
 
4384
 
 
4385
        if (entered_marker) {
 
4386
                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
 
4387
                return entered_marker->position();
 
4388
        }
 
4389
 
 
4390
        if (ignore_playhead && ep == EditAtPlayhead) {
 
4391
                ep = EditAtSelectedMarker;
 
4392
        }
 
4393
 
 
4394
        switch (ep) {
 
4395
        case EditAtPlayhead:
 
4396
                where = _session->audible_frame();
 
4397
                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
 
4398
                break;
 
4399
 
 
4400
        case EditAtSelectedMarker:
 
4401
                if (!selection->markers.empty()) {
 
4402
                        bool is_start;
 
4403
                        Location* loc = find_location_from_marker (selection->markers.front(), is_start);
 
4404
                        if (loc) {
 
4405
                                if (is_start) {
 
4406
                                        where =  loc->start();
 
4407
                                } else {
 
4408
                                        where = loc->end();
 
4409
                                }
 
4410
                                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
 
4411
                                break;
 
4412
                        }
 
4413
                }
 
4414
                /* fallthru */
 
4415
 
 
4416
        default:
 
4417
        case EditAtMouse:
 
4418
                if (!mouse_frame (where, ignored)) {
 
4419
                        /* XXX not right but what can we do ? */
 
4420
                        return 0;
 
4421
                }
 
4422
                snap_to (where);
 
4423
                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
 
4424
                break;
 
4425
        }
 
4426
 
 
4427
        return where;
 
4428
}
 
4429
 
 
4430
void
 
4431
Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
 
4432
{
 
4433
        if (!_session) return;
 
4434
 
 
4435
        begin_reversible_command (cmd);
 
4436
 
 
4437
        Location* tll;
 
4438
 
 
4439
        if ((tll = transport_loop_location()) == 0) {
 
4440
                Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
 
4441
                XMLNode &before = _session->locations()->get_state();
 
4442
                _session->locations()->add (loc, true);
 
4443
                _session->set_auto_loop_location (loc);
 
4444
                XMLNode &after = _session->locations()->get_state();
 
4445
                _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
 
4446
        } else {
 
4447
                XMLNode &before = tll->get_state();
 
4448
                tll->set_hidden (false, this);
 
4449
                tll->set (start, end);
 
4450
                XMLNode &after = tll->get_state();
 
4451
                _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
 
4452
        }
 
4453
 
 
4454
        commit_reversible_command ();
 
4455
}
 
4456
 
 
4457
void
 
4458
Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
 
4459
{
 
4460
        if (!_session) return;
 
4461
 
 
4462
        begin_reversible_command (cmd);
 
4463
 
 
4464
        Location* tpl;
 
4465
 
 
4466
        if ((tpl = transport_punch_location()) == 0) {
 
4467
                Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
 
4468
                XMLNode &before = _session->locations()->get_state();
 
4469
                _session->locations()->add (loc, true);
 
4470
                _session->set_auto_loop_location (loc);
 
4471
                XMLNode &after = _session->locations()->get_state();
 
4472
                _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
 
4473
        }
 
4474
        else {
 
4475
                XMLNode &before = tpl->get_state();
 
4476
                tpl->set_hidden (false, this);
 
4477
                tpl->set (start, end);
 
4478
                XMLNode &after = tpl->get_state();
 
4479
                _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
 
4480
        }
 
4481
 
 
4482
        commit_reversible_command ();
 
4483
}
 
4484
 
 
4485
/** Find regions which exist at a given time, and optionally on a given list of tracks.
 
4486
 *  @param rs List to which found regions are added.
 
4487
 *  @param where Time to look at.
 
4488
 *  @param ts Tracks to look on; if this is empty, all tracks are examined.
 
4489
 */
 
4490
void
 
4491
Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
 
4492
{
 
4493
        const TrackViewList* tracks;
 
4494
 
 
4495
        if (ts.empty()) {
 
4496
                tracks = &track_views;
 
4497
        } else {
 
4498
                tracks = &ts;
 
4499
        }
 
4500
 
 
4501
        for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
 
4502
 
 
4503
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
 
4504
 
 
4505
                if (rtv) {
 
4506
                        boost::shared_ptr<Track> tr;
 
4507
                        boost::shared_ptr<Playlist> pl;
 
4508
 
 
4509
                        if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
 
4510
 
 
4511
                                boost::shared_ptr<RegionList> regions = pl->regions_at (
 
4512
                                                (framepos_t) floor ( (double) where * tr->speed()));
 
4513
 
 
4514
                                for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
 
4515
                                        RegionView* rv = rtv->view()->find_view (*i);
 
4516
                                        if (rv) {
 
4517
                                                rs.add (rv);
 
4518
                                        }
 
4519
                                }
 
4520
                        }
 
4521
                }
 
4522
        }
 
4523
}
 
4524
 
 
4525
void
 
4526
Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
 
4527
{
 
4528
        const TrackViewList* tracks;
 
4529
 
 
4530
        if (ts.empty()) {
 
4531
                tracks = &track_views;
 
4532
        } else {
 
4533
                tracks = &ts;
 
4534
        }
 
4535
 
 
4536
        for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
 
4537
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
 
4538
                if (rtv) {
 
4539
                        boost::shared_ptr<Track> tr;
 
4540
                        boost::shared_ptr<Playlist> pl;
 
4541
 
 
4542
                        if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
 
4543
 
 
4544
                                boost::shared_ptr<RegionList> regions = pl->regions_touched (
 
4545
                                        (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
 
4546
 
 
4547
                                for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
 
4548
 
 
4549
                                        RegionView* rv = rtv->view()->find_view (*i);
 
4550
 
 
4551
                                        if (rv) {
 
4552
                                                rs.add (rv);
 
4553
                                        }
 
4554
                                }
 
4555
                        }
 
4556
                }
 
4557
        }
 
4558
}
 
4559
 
 
4560
/** Get regions using the following method:
 
4561
 *
 
4562
 *  Make a region list using the selected regions, unless
 
4563
 *  the edit point is `mouse' and the mouse is over an unselected
 
4564
 *  region.  In this case, use just that region.
 
4565
 *
 
4566
 *  If the edit point is not 'mouse', and there are no regions selected,
 
4567
 *  search the list of selected tracks and return regions that are under
 
4568
 *  the edit point on these tracks. If there are no selected tracks and
 
4569
 *  'No Selection = All Tracks' is active, search all tracks,
 
4570
 *
 
4571
 *  The rationale here is that the mouse edit point is special in that
 
4572
 *  its position describes both a time and a track; the other edit
 
4573
 *  modes only describe a time.  Hence if the edit point is `mouse' we
 
4574
 *  ignore selected tracks, as we assume the user means something by
 
4575
 *  pointing at a particular track.  Also in this case we take note of
 
4576
 *  the region directly under the edit point, as there is always just one
 
4577
 *  (rather than possibly several with non-mouse edit points).
 
4578
 */
 
4579
 
 
4580
RegionSelection
 
4581
Editor::get_regions_from_selection_and_edit_point ()
 
4582
{
 
4583
        RegionSelection regions;
 
4584
 
 
4585
        if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
 
4586
                regions.add (entered_regionview);
 
4587
        } else {
 
4588
                regions = selection->regions;
 
4589
        }
 
4590
 
 
4591
 
 
4592
        if (regions.empty() && _edit_point != EditAtMouse) {
 
4593
                TrackViewList tracks = selection->tracks;
 
4594
 
 
4595
                if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
 
4596
                        /* tracks is empty (no track selected), and 'No Selection = All Tracks'
 
4597
                         * is enabled, so consider all tracks
 
4598
                         */
 
4599
                        tracks = track_views; 
 
4600
                }
 
4601
 
 
4602
                if (!tracks.empty()) {
 
4603
                        /* no region selected or entered, but some selected tracks:
 
4604
                         * act on all regions on the selected tracks at the edit point
 
4605
                         */ 
 
4606
                        framepos_t const where = get_preferred_edit_position ();
 
4607
                        get_regions_at(regions, where, tracks);
 
4608
                }
 
4609
        }
 
4610
        return regions;
 
4611
}
 
4612
 
 
4613
/** Start with regions that are selected, or the entered regionview if none are selected.
 
4614
 *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
 
4615
 *  of the regions that we started with.
 
4616
 */
 
4617
 
 
4618
RegionSelection
 
4619
Editor::get_regions_from_selection_and_entered ()
 
4620
{
 
4621
        RegionSelection regions = selection->regions;
 
4622
 
 
4623
        if (regions.empty() && entered_regionview) {
 
4624
                regions.add (entered_regionview);
 
4625
        }
 
4626
 
 
4627
        return regions;
 
4628
}
 
4629
 
 
4630
void
 
4631
Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
 
4632
{
 
4633
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
 
4634
 
 
4635
                RouteTimeAxisView* tatv;
 
4636
 
 
4637
                if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
 
4638
 
 
4639
                        boost::shared_ptr<Playlist> pl;
 
4640
                        vector<boost::shared_ptr<Region> > results;
 
4641
                        RegionView* marv;
 
4642
                        boost::shared_ptr<Track> tr;
 
4643
 
 
4644
                        if ((tr = tatv->track()) == 0) {
 
4645
                                /* bus */
 
4646
                                continue;
 
4647
                        }
 
4648
 
 
4649
                        if ((pl = (tr->playlist())) != 0) {
 
4650
                                if (src_comparison) {
 
4651
                                        pl->get_source_equivalent_regions (region, results);
 
4652
                                } else {
 
4653
                                        pl->get_region_list_equivalent_regions (region, results);
 
4654
                                }
 
4655
                        }
 
4656
 
 
4657
                        for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
 
4658
                                if ((marv = tatv->view()->find_view (*ir)) != 0) {
 
4659
                                        regions.push_back (marv);
 
4660
                                }
 
4661
                        }
 
4662
 
 
4663
                }
 
4664
        }
 
4665
}
 
4666
 
 
4667
void
 
4668
Editor::show_rhythm_ferret ()
 
4669
{
 
4670
        if (rhythm_ferret == 0) {
 
4671
                rhythm_ferret = new RhythmFerret(*this);
 
4672
        }
 
4673
 
 
4674
        rhythm_ferret->set_session (_session);
 
4675
        rhythm_ferret->show ();
 
4676
        rhythm_ferret->present ();
 
4677
}
 
4678
 
 
4679
void
 
4680
Editor::first_idle ()
 
4681
{
 
4682
        MessageDialog* dialog = 0;
 
4683
        
 
4684
        if (track_views.size() > 1) {
 
4685
                dialog = new MessageDialog (
 
4686
                        *this,
 
4687
                        string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
 
4688
                        true
 
4689
                        );
 
4690
                dialog->present ();
 
4691
                ARDOUR_UI::instance()->flush_pending ();
 
4692
        }
 
4693
 
 
4694
        for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
 
4695
                (*t)->first_idle();
 
4696
        }
 
4697
 
 
4698
        // first idle adds route children (automation tracks), so we need to redisplay here
 
4699
        _routes->redisplay ();
 
4700
 
 
4701
        delete dialog;
 
4702
        _have_idled = true;
 
4703
}
 
4704
 
 
4705
gboolean
 
4706
Editor::_idle_resize (gpointer arg)
 
4707
{
 
4708
        return ((Editor*)arg)->idle_resize ();
 
4709
}
 
4710
 
 
4711
void
 
4712
Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
 
4713
{
 
4714
        if (resize_idle_id < 0) {
 
4715
                resize_idle_id = g_idle_add (_idle_resize, this);
 
4716
                _pending_resize_amount = 0;
 
4717
        }
 
4718
 
 
4719
        /* make a note of the smallest resulting height, so that we can clamp the
 
4720
           lower limit at TimeAxisView::hSmall */
 
4721
 
 
4722
        int32_t min_resulting = INT32_MAX;
 
4723
 
 
4724
        _pending_resize_amount += h;
 
4725
        _pending_resize_view = view;
 
4726
 
 
4727
        min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
 
4728
 
 
4729
        if (selection->tracks.contains (_pending_resize_view)) {
 
4730
                for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
 
4731
                        min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
 
4732
                }
 
4733
        }
 
4734
 
 
4735
        if (min_resulting < 0) {
 
4736
                min_resulting = 0;
 
4737
        }
 
4738
 
 
4739
        /* clamp */
 
4740
        if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
 
4741
                _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
 
4742
        }
 
4743
}
 
4744
 
 
4745
/** Handle pending resizing of tracks */
 
4746
bool
 
4747
Editor::idle_resize ()
 
4748
{
 
4749
        _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
 
4750
 
 
4751
        if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
 
4752
            selection->tracks.contains (_pending_resize_view)) {
 
4753
 
 
4754
                for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
 
4755
                        if (*i != _pending_resize_view) {
 
4756
                                (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
 
4757
                        }
 
4758
                }
 
4759
        }
 
4760
 
 
4761
        _pending_resize_amount = 0;
 
4762
        flush_canvas ();
 
4763
        _group_tabs->set_dirty ();
 
4764
        resize_idle_id = -1;
 
4765
 
 
4766
        return false;
 
4767
}
 
4768
 
 
4769
void
 
4770
Editor::located ()
 
4771
{
 
4772
        ENSURE_GUI_THREAD (*this, &Editor::located);
 
4773
 
 
4774
        if (_session) {
 
4775
                playhead_cursor->set_position (_session->audible_frame ());
 
4776
                if (_follow_playhead && !_pending_initial_locate) {
 
4777
                        reset_x_origin_to_follow_playhead ();
 
4778
                }
 
4779
        }
 
4780
 
 
4781
        _pending_locate_request = false;
 
4782
        _pending_initial_locate = false;
 
4783
}
 
4784
 
 
4785
void
 
4786
Editor::region_view_added (RegionView *)
 
4787
{
 
4788
        _summary->set_dirty ();
 
4789
}
 
4790
 
 
4791
void
 
4792
Editor::region_view_removed ()
 
4793
{
 
4794
        _summary->set_dirty ();
 
4795
}
 
4796
 
 
4797
TimeAxisView*
 
4798
Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
 
4799
{
 
4800
        TrackViewList::const_iterator j = track_views.begin ();
 
4801
        while (j != track_views.end()) {
 
4802
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
 
4803
                if (rtv && rtv->route() == r) {
 
4804
                        return rtv;
 
4805
                }
 
4806
                ++j;
 
4807
        }
 
4808
 
 
4809
        return 0;
 
4810
}
 
4811
 
 
4812
 
 
4813
TrackViewList
 
4814
Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
 
4815
{
 
4816
        TrackViewList t;
 
4817
 
 
4818
        for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
 
4819
                TimeAxisView* tv = axis_view_from_route (*i);
 
4820
                if (tv) {
 
4821
                        t.push_back (tv);
 
4822
                }
 
4823
        }
 
4824
 
 
4825
        return t;
 
4826
}
 
4827
 
 
4828
void
 
4829
Editor::add_routes (RouteList& routes)
 
4830
{
 
4831
        ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
 
4832
 
 
4833
        RouteTimeAxisView *rtv;
 
4834
        list<RouteTimeAxisView*> new_views;
 
4835
 
 
4836
        for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
 
4837
                boost::shared_ptr<Route> route = (*x);
 
4838
 
 
4839
                if (route->is_auditioner() || route->is_monitor()) {
 
4840
                        continue;
 
4841
                }
 
4842
 
 
4843
                DataType dt = route->input()->default_type();
 
4844
 
 
4845
                if (dt == ARDOUR::DataType::AUDIO) {
 
4846
                        rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
 
4847
                        rtv->set_route (route);
 
4848
                } else if (dt == ARDOUR::DataType::MIDI) {
 
4849
                        rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
 
4850
                        rtv->set_route (route);
 
4851
                } else {
 
4852
                        throw unknown_type();
 
4853
                }
 
4854
 
 
4855
                new_views.push_back (rtv);
 
4856
                track_views.push_back (rtv);
 
4857
 
 
4858
                rtv->effective_gain_display ();
 
4859
 
 
4860
                if (internal_editing()) {
 
4861
                        rtv->enter_internal_edit_mode ();
 
4862
                } else {
 
4863
                        rtv->leave_internal_edit_mode ();
 
4864
                }
 
4865
 
 
4866
                rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
 
4867
                rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
 
4868
        }
 
4869
 
 
4870
        _routes->routes_added (new_views);
 
4871
        _summary->routes_added (new_views);
 
4872
 
 
4873
        if (show_editor_mixer_when_tracks_arrive) {
 
4874
                show_editor_mixer (true);
 
4875
        }
 
4876
 
 
4877
        editor_list_button.set_sensitive (true);
 
4878
}
 
4879
 
 
4880
void
 
4881
Editor::timeaxisview_deleted (TimeAxisView *tv)
 
4882
{
 
4883
        if (_session && _session->deletion_in_progress()) {
 
4884
                /* the situation is under control */
 
4885
                return;
 
4886
        }
 
4887
 
 
4888
        ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
 
4889
 
 
4890
        RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
 
4891
 
 
4892
        _routes->route_removed (tv);
 
4893
 
 
4894
        if (tv == entered_track) {
 
4895
                entered_track = 0;
 
4896
        }
 
4897
 
 
4898
        TimeAxisView::Children c = tv->get_child_list ();
 
4899
        for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
 
4900
                if (entered_track == i->get()) {
 
4901
                        entered_track = 0;
 
4902
                }
 
4903
        }
 
4904
 
 
4905
        /* remove it from the list of track views */
 
4906
 
 
4907
        TrackViewList::iterator i;
 
4908
 
 
4909
        if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
 
4910
                i = track_views.erase (i);
 
4911
        }
 
4912
 
 
4913
        /* update whatever the current mixer strip is displaying, if revelant */
 
4914
 
 
4915
        boost::shared_ptr<Route> route;
 
4916
 
 
4917
        if (rtav) {
 
4918
                route = rtav->route ();
 
4919
        }
 
4920
 
 
4921
        if (current_mixer_strip && current_mixer_strip->route() == route) {
 
4922
 
 
4923
                TimeAxisView* next_tv;
 
4924
 
 
4925
                if (track_views.empty()) {
 
4926
                        next_tv = 0;
 
4927
                } else if (i == track_views.end()) {
 
4928
                        next_tv = track_views.front();
 
4929
                } else {
 
4930
                        next_tv = (*i);
 
4931
                }
 
4932
 
 
4933
 
 
4934
                if (next_tv) {
 
4935
                        set_selected_mixer_strip (*next_tv);
 
4936
                } else {
 
4937
                        /* make the editor mixer strip go away setting the
 
4938
                         * button to inactive (which also unticks the menu option)
 
4939
                         */
 
4940
 
 
4941
                        ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
 
4942
                }
 
4943
        }
 
4944
}
 
4945
 
 
4946
void
 
4947
Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
 
4948
{
 
4949
        if (apply_to_selection) {
 
4950
                for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
 
4951
 
 
4952
                        TrackSelection::iterator j = i;
 
4953
                        ++j;
 
4954
 
 
4955
                        hide_track_in_display (*i, false);
 
4956
 
 
4957
                        i = j;
 
4958
                }
 
4959
        } else {
 
4960
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
 
4961
 
 
4962
                if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
 
4963
                        // this will hide the mixer strip
 
4964
                        set_selected_mixer_strip (*tv);
 
4965
                }
 
4966
 
 
4967
                _routes->hide_track_in_display (*tv);
 
4968
        }
 
4969
}
 
4970
 
 
4971
bool
 
4972
Editor::sync_track_view_list_and_routes ()
 
4973
{
 
4974
        track_views = TrackViewList (_routes->views ());
 
4975
 
 
4976
        _summary->set_dirty ();
 
4977
        _group_tabs->set_dirty ();
 
4978
 
 
4979
        return false; // do not call again (until needed)
 
4980
}
 
4981
 
 
4982
void
 
4983
Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
 
4984
{
 
4985
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
 
4986
                theslot (**i);
 
4987
        }
 
4988
}
 
4989
 
 
4990
/** Find a RouteTimeAxisView by the ID of its route */
 
4991
RouteTimeAxisView*
 
4992
Editor::get_route_view_by_route_id (const PBD::ID& id) const
 
4993
{
 
4994
        RouteTimeAxisView* v;
 
4995
 
 
4996
        for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
 
4997
                if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
 
4998
                        if(v->route()->id() == id) {
 
4999
                                return v;
 
5000
                        }
 
5001
                }
 
5002
        }
 
5003
 
 
5004
        return 0;
 
5005
}
 
5006
 
 
5007
void
 
5008
Editor::fit_route_group (RouteGroup *g)
 
5009
{
 
5010
        TrackViewList ts = axis_views_from_routes (g->route_list ());
 
5011
        fit_tracks (ts);
 
5012
}
 
5013
 
 
5014
void
 
5015
Editor::consider_auditioning (boost::shared_ptr<Region> region)
 
5016
{
 
5017
        boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
 
5018
 
 
5019
        if (r == 0) {
 
5020
                _session->cancel_audition ();
 
5021
                return;
 
5022
        }
 
5023
 
 
5024
        if (_session->is_auditioning()) {
 
5025
                _session->cancel_audition ();
 
5026
                if (r == last_audition_region) {
 
5027
                        return;
 
5028
                }
 
5029
        }
 
5030
 
 
5031
        _session->audition_region (r);
 
5032
        last_audition_region = r;
 
5033
}
 
5034
 
 
5035
 
 
5036
void
 
5037
Editor::hide_a_region (boost::shared_ptr<Region> r)
 
5038
{
 
5039
        r->set_hidden (true);
 
5040
}
 
5041
 
 
5042
void
 
5043
Editor::show_a_region (boost::shared_ptr<Region> r)
 
5044
{
 
5045
        r->set_hidden (false);
 
5046
}
 
5047
 
 
5048
void
 
5049
Editor::audition_region_from_region_list ()
 
5050
{
 
5051
        _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
 
5052
}
 
5053
 
 
5054
void
 
5055
Editor::hide_region_from_region_list ()
 
5056
{
 
5057
        _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
 
5058
}
 
5059
 
 
5060
void
 
5061
Editor::show_region_in_region_list ()
 
5062
{
 
5063
        _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
 
5064
}
 
5065
 
 
5066
void
 
5067
Editor::step_edit_status_change (bool yn)
 
5068
{
 
5069
        if (yn) {
 
5070
                start_step_editing ();
 
5071
        } else {
 
5072
                stop_step_editing ();
 
5073
        }
 
5074
}
 
5075
 
 
5076
void
 
5077
Editor::start_step_editing ()
 
5078
{
 
5079
        step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
 
5080
}
 
5081
 
 
5082
void
 
5083
Editor::stop_step_editing ()
 
5084
{
 
5085
        step_edit_connection.disconnect ();
 
5086
}
 
5087
 
 
5088
bool
 
5089
Editor::check_step_edit ()
 
5090
{
 
5091
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
 
5092
                MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
 
5093
                if (mtv) {
 
5094
                        mtv->check_step_edit ();
 
5095
                }
 
5096
        }
 
5097
 
 
5098
        return true; // do it again, till we stop
 
5099
}
 
5100
 
 
5101
bool
 
5102
Editor::scroll_press (Direction dir)
 
5103
{
 
5104
        ++_scroll_callbacks;
 
5105
 
 
5106
        if (_scroll_connection.connected() && _scroll_callbacks < 5) {
 
5107
                /* delay the first auto-repeat */
 
5108
                return true;
 
5109
        }
 
5110
 
 
5111
        switch (dir) {
 
5112
        case LEFT:
 
5113
                scroll_backward (1);
 
5114
                break;
 
5115
 
 
5116
        case RIGHT:
 
5117
                scroll_forward (1);
 
5118
                break;
 
5119
 
 
5120
        case UP:
 
5121
                scroll_tracks_up_line ();
 
5122
                break;
 
5123
 
 
5124
        case DOWN:
 
5125
                scroll_tracks_down_line ();
 
5126
                break;
 
5127
        }
 
5128
 
 
5129
        /* do hacky auto-repeat */
 
5130
        if (!_scroll_connection.connected ()) {
 
5131
 
 
5132
                _scroll_connection = Glib::signal_timeout().connect (
 
5133
                        sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
 
5134
                        );
 
5135
 
 
5136
                _scroll_callbacks = 0;
 
5137
        }
 
5138
 
 
5139
        return true;
 
5140
}
 
5141
 
 
5142
void
 
5143
Editor::scroll_release ()
 
5144
{
 
5145
        _scroll_connection.disconnect ();
 
5146
}
 
5147
 
 
5148
/** Queue a change for the Editor viewport x origin to follow the playhead */
 
5149
void
 
5150
Editor::reset_x_origin_to_follow_playhead ()
 
5151
{
 
5152
        framepos_t const frame = playhead_cursor->current_frame;
 
5153
 
 
5154
        if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
 
5155
 
 
5156
                if (_session->transport_speed() < 0) {
 
5157
 
 
5158
                        if (frame > (current_page_frames() / 2)) {
 
5159
                                center_screen (frame-(current_page_frames()/2));
 
5160
                        } else {
 
5161
                                center_screen (current_page_frames()/2);
 
5162
                        }
 
5163
 
 
5164
                } else {
 
5165
 
 
5166
                        framepos_t l = 0;
 
5167
                        
 
5168
                        if (frame < leftmost_frame) {
 
5169
                                /* moving left */
 
5170
                                if (_session->transport_rolling()) {
 
5171
                                        /* rolling; end up with the playhead at the right of the page */
 
5172
                                        l = frame - current_page_frames ();
 
5173
                                } else {
 
5174
                                        /* not rolling: end up with the playhead 1/4 of the way along the page */
 
5175
                                        l = frame - current_page_frames() / 4;
 
5176
                                }
 
5177
                        } else {
 
5178
                                /* moving right */
 
5179
                                if (_session->transport_rolling()) {
 
5180
                                        /* rolling: end up with the playhead on the left of the page */
 
5181
                                        l = frame;
 
5182
                                } else {
 
5183
                                        /* not rolling: end up with the playhead 3/4 of the way along the page */
 
5184
                                        l = frame - 3 * current_page_frames() / 4;
 
5185
                                }
 
5186
                        }
 
5187
 
 
5188
                        if (l < 0) {
 
5189
                                l = 0;
 
5190
                        }
 
5191
                        
 
5192
                        center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
 
5193
                }
 
5194
        }
 
5195
}
 
5196
 
 
5197
void
 
5198
Editor::super_rapid_screen_update ()
 
5199
{
 
5200
        if (!_session || !_session->engine().running()) {
 
5201
                return;
 
5202
        }
 
5203
 
 
5204
        /* METERING / MIXER STRIPS */
 
5205
 
 
5206
        /* update track meters, if required */
 
5207
        if (is_mapped() && meters_running) {
 
5208
                RouteTimeAxisView* rtv;
 
5209
                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
 
5210
                        if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
 
5211
                                rtv->fast_update ();
 
5212
                        }
 
5213
                }
 
5214
        }
 
5215
 
 
5216
        /* and any current mixer strip */
 
5217
        if (current_mixer_strip) {
 
5218
                current_mixer_strip->fast_update ();
 
5219
        }
 
5220
 
 
5221
        /* PLAYHEAD AND VIEWPORT */
 
5222
 
 
5223
        framepos_t const frame = _session->audible_frame();
 
5224
 
 
5225
        /* There are a few reasons why we might not update the playhead / viewport stuff:
 
5226
         *
 
5227
         * 1.  we don't update things when there's a pending locate request, otherwise
 
5228
         *     when the editor requests a locate there is a chance that this method
 
5229
         *     will move the playhead before the locate request is processed, causing
 
5230
         *     a visual glitch.
 
5231
         * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
 
5232
         * 3.  if we're still at the same frame that we were last time, there's nothing to do.
 
5233
         */
 
5234
 
 
5235
        if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
 
5236
 
 
5237
                last_update_frame = frame;
 
5238
 
 
5239
                if (!_dragging_playhead) {
 
5240
                        playhead_cursor->set_position (frame);
 
5241
                }
 
5242
 
 
5243
                if (!_stationary_playhead) {
 
5244
 
 
5245
                        if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
 
5246
                                /* We only do this if we aren't already
 
5247
                                   handling a visual change (ie if
 
5248
                                   pending_visual_change.being_handled is
 
5249
                                   false) so that these requests don't stack
 
5250
                                   up there are too many of them to handle in
 
5251
                                   time.
 
5252
                                */
 
5253
                                reset_x_origin_to_follow_playhead ();
 
5254
                        }
 
5255
 
 
5256
                } else {
 
5257
 
 
5258
                        /* don't do continuous scroll till the new position is in the rightmost quarter of the
 
5259
                           editor canvas
 
5260
                        */
 
5261
#if 0
 
5262
                        // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
 
5263
                        double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
 
5264
                        if (target <= 0.0) {
 
5265
                                target = 0.0;
 
5266
                        }
 
5267
                        if (fabs(target - current) < current_page_frames() / frames_per_unit) {
 
5268
                                target = (target * 0.15) + (current * 0.85);
 
5269
                        } else {
 
5270
                                /* relax */
 
5271
                        }
 
5272
 
 
5273
                        current = target;
 
5274
                        set_horizontal_position (current);
 
5275
#endif
 
5276
                }
 
5277
 
 
5278
        }
 
5279
}
 
5280
 
 
5281
 
 
5282
void
 
5283
Editor::session_going_away ()
 
5284
{
 
5285
        _have_idled = false;
 
5286
 
 
5287
        _session_connections.drop_connections ();
 
5288
 
 
5289
        super_rapid_screen_update_connection.disconnect ();
 
5290
 
 
5291
        selection->clear ();
 
5292
        cut_buffer->clear ();
 
5293
 
 
5294
        clicked_regionview = 0;
 
5295
        clicked_axisview = 0;
 
5296
        clicked_routeview = 0;
 
5297
        entered_regionview = 0;
 
5298
        entered_track = 0;
 
5299
        last_update_frame = 0;
 
5300
        _drags->abort ();
 
5301
 
 
5302
        playhead_cursor->canvas_item.hide ();
 
5303
 
 
5304
        /* rip everything out of the list displays */
 
5305
 
 
5306
        _regions->clear ();
 
5307
        _routes->clear ();
 
5308
        _route_groups->clear ();
 
5309
 
 
5310
        /* do this first so that deleting a track doesn't reset cms to null
 
5311
           and thus cause a leak.
 
5312
        */
 
5313
 
 
5314
        if (current_mixer_strip) {
 
5315
                if (current_mixer_strip->get_parent() != 0) {
 
5316
                        global_hpacker.remove (*current_mixer_strip);
 
5317
                }
 
5318
                delete current_mixer_strip;
 
5319
                current_mixer_strip = 0;
 
5320
        }
 
5321
 
 
5322
        /* delete all trackviews */
 
5323
 
 
5324
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
 
5325
                delete *i;
 
5326
        }
 
5327
        track_views.clear ();
 
5328
 
 
5329
        zoom_range_clock->set_session (0);
 
5330
        nudge_clock->set_session (0);
 
5331
 
 
5332
        editor_list_button.set_active(false);
 
5333
        editor_list_button.set_sensitive(false);
 
5334
 
 
5335
        /* clear tempo/meter rulers */
 
5336
        remove_metric_marks ();
 
5337
        hide_measures ();
 
5338
        clear_marker_display ();
 
5339
 
 
5340
        stop_step_editing ();
 
5341
        
 
5342
        /* get rid of any existing editor mixer strip */
 
5343
 
 
5344
        WindowTitle title(Glib::get_application_name());
 
5345
        title += _("Editor");
 
5346
 
 
5347
        set_title (title.get_string());
 
5348
 
 
5349
        SessionHandlePtr::session_going_away ();
 
5350
}
 
5351
 
 
5352
 
 
5353
void
 
5354
Editor::show_editor_list (bool yn)
 
5355
{
 
5356
        if (yn) {
 
5357
                _the_notebook.show ();
 
5358
        } else {
 
5359
                _the_notebook.hide ();
 
5360
        }
 
5361
}
 
5362
 
 
5363
void
 
5364
Editor::change_region_layering_order (bool from_context_menu)
 
5365
{
 
5366
        const framepos_t position = get_preferred_edit_position (false, from_context_menu);
 
5367
 
 
5368
        if (!clicked_routeview) {
 
5369
                if (layering_order_editor) {
 
5370
                        layering_order_editor->hide ();
 
5371
                }
 
5372
                return;
 
5373
        }
 
5374
 
 
5375
        boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
 
5376
 
 
5377
        if (!track) {
 
5378
                return;
 
5379
        }
 
5380
 
 
5381
        boost::shared_ptr<Playlist> pl = track->playlist();
 
5382
 
 
5383
        if (!pl) {
 
5384
                return;
 
5385
        }
 
5386
 
 
5387
        if (layering_order_editor == 0) {
 
5388
                layering_order_editor = new RegionLayeringOrderEditor (*this);
 
5389
        }
 
5390
 
 
5391
        layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
 
5392
        layering_order_editor->maybe_present ();
 
5393
}
 
5394
 
 
5395
void
 
5396
Editor::update_region_layering_order_editor ()
 
5397
{
 
5398
        if (layering_order_editor && layering_order_editor->is_visible ()) {
 
5399
                change_region_layering_order (true);
 
5400
        }
 
5401
}
 
5402
 
 
5403
void
 
5404
Editor::setup_fade_images ()
 
5405
{
 
5406
        _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
 
5407
        _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
 
5408
        _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
 
5409
        _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
 
5410
        _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
 
5411
 
 
5412
        _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
 
5413
        _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
 
5414
        _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
 
5415
        _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
 
5416
        _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
 
5417
        
 
5418
        _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
 
5419
        _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
 
5420
        _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
 
5421
        _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
 
5422
        _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
 
5423
 
 
5424
        _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
 
5425
        _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
 
5426
        _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
 
5427
        _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
 
5428
        _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
 
5429
 
 
5430
}
 
5431
 
 
5432
/** @return Gtk::manage()d menu item for a given action from `editor_actions' */
 
5433
Gtk::MenuItem&
 
5434
Editor::action_menu_item (std::string const & name)
 
5435
{
 
5436
        Glib::RefPtr<Action> a = editor_actions->get_action (name);
 
5437
        assert (a);
 
5438
 
 
5439
        return *manage (a->create_menu_item ());
 
5440
}
 
5441
 
 
5442
void
 
5443
Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
 
5444
{
 
5445
        EventBox* b = manage (new EventBox);
 
5446
        b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
 
5447
        Label* l = manage (new Label (name));
 
5448
        l->set_angle (-90);
 
5449
        b->add (*l);
 
5450
        b->show_all ();
 
5451
        _the_notebook.append_page (widget, *b);
 
5452
}
 
5453
 
 
5454
bool
 
5455
Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
 
5456
{
 
5457
        if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
 
5458
                _the_notebook.set_current_page (_the_notebook.page_num (*page));
 
5459
        }
 
5460
 
 
5461
        if (ev->type == GDK_2BUTTON_PRESS) {
 
5462
 
 
5463
                /* double-click on a notebook tab shrinks or expands the notebook */
 
5464
 
 
5465
                if (_notebook_shrunk) {
 
5466
                        if (pre_notebook_shrink_pane_width) {
 
5467
                                edit_pane.set_position (*pre_notebook_shrink_pane_width);
 
5468
                        }
 
5469
                        _notebook_shrunk = false;
 
5470
                } else {
 
5471
                        pre_notebook_shrink_pane_width = edit_pane.get_position();
 
5472
 
 
5473
                        /* this expands the LHS of the edit pane to cover the notebook
 
5474
                           PAGE but leaves the tabs visible.
 
5475
                         */
 
5476
                        edit_pane.set_position (edit_pane.get_position() + page->get_width());
 
5477
                        _notebook_shrunk = true;
 
5478
                }
 
5479
        }
 
5480
 
 
5481
        return true;
 
5482
}
 
5483
 
 
5484
void
 
5485
Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
 
5486
{
 
5487
        using namespace Menu_Helpers;
 
5488
        
 
5489
        MenuList& items = _control_point_context_menu.items ();
 
5490
        items.clear ();
 
5491
        
 
5492
        items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
 
5493
        items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
 
5494
        if (!can_remove_control_point (item)) {
 
5495
                items.back().set_sensitive (false);
 
5496
        }
 
5497
 
 
5498
        _control_point_context_menu.popup (event->button.button, event->button.time);
 
5499
}
 
5500
 
 
5501
void
 
5502
Editor::zoom_vertical_modifier_released()
 
5503
{
 
5504
        _stepping_axis_view = 0;
 
5505
}