2 Copyright (C) 2000 Paul Davis
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.
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.
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.
20 #include <sigc++/retype.h>
24 #include <libgnomecanvas/libgnomecanvas.h>
25 #include <gtkmm2ext/gtk_ui.h>
27 #include "ardour/session.h"
28 #include "ardour/location.h"
29 #include "ardour/profile.h"
30 #include "pbd/memento_command.h"
34 #include "selection.h"
36 #include "gui_thread.h"
37 #include "simplerect.h"
40 #include "editor_drag.h"
45 using namespace ARDOUR
;
48 using namespace Gtkmm2ext
;
51 Editor::clear_marker_display ()
53 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
57 location_markers
.clear ();
61 Editor::add_new_location (Location
*location
)
63 ENSURE_GUI_THREAD (*this, &Editor::add_new_location
, location
)
65 LocationMarkers
*lam
= new LocationMarkers
;
68 if (location
->is_cd_marker()) {
69 color
= location_cd_marker_color
;
70 } else if (location
->is_mark()) {
71 color
= location_marker_color
;
72 } else if (location
->is_auto_loop()) {
73 color
= location_loop_color
;
74 } else if (location
->is_auto_punch()) {
75 color
= location_punch_color
;
77 color
= location_range_color
;
80 if (location
->is_mark()) {
82 if (location
->is_cd_marker() && ruler_cd_marker_action
->get_active()) {
83 lam
->start
= new Marker (*this, *cd_marker_group
, color
, location
->name(), Marker::Mark
, location
->start());
86 lam
->start
= new Marker (*this, *marker_group
, color
, location
->name(), Marker::Mark
, location
->start());
90 } else if (location
->is_auto_loop()) {
92 lam
->start
= new Marker (*this, *transport_marker_group
, color
,
93 location
->name(), Marker::LoopStart
, location
->start());
94 lam
->end
= new Marker (*this, *transport_marker_group
, color
,
95 location
->name(), Marker::LoopEnd
, location
->end());
97 } else if (location
->is_auto_punch()) {
99 lam
->start
= new Marker (*this, *transport_marker_group
, color
,
100 location
->name(), Marker::PunchIn
, location
->start());
101 lam
->end
= new Marker (*this, *transport_marker_group
, color
,
102 location
->name(), Marker::PunchOut
, location
->end());
104 } else if (location
->is_session_range()) {
106 lam
->start
= new Marker (*this, *marker_group
, color
, _("start"), Marker::Start
, location
->start());
107 lam
->end
= new Marker (*this, *marker_group
, color
, _("end"), Marker::End
, location
->end());
111 if (location
->is_cd_marker() && ruler_cd_marker_action
->get_active()) {
112 lam
->start
= new Marker (*this, *cd_marker_group
, color
,
113 location
->name(), Marker::Start
, location
->start());
114 lam
->end
= new Marker (*this, *cd_marker_group
, color
,
115 location
->name(), Marker::End
, location
->end());
118 lam
->start
= new Marker (*this, *range_marker_group
, color
,
119 location
->name(), Marker::Start
, location
->start());
120 lam
->end
= new Marker (*this, *range_marker_group
, color
,
121 location
->name(), Marker::End
, location
->end());
125 if (location
->is_hidden ()) {
131 location
->start_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
132 location
->end_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
133 location
->changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
134 location
->name_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
135 location
->FlagsChanged
.connect (*this, invalidator (*this), ui_bind (&Editor::location_flags_changed
, this, _1
, _2
), gui_context());
137 pair
<Location
*,LocationMarkers
*> newpair
;
139 newpair
.first
= location
;
140 newpair
.second
= lam
;
142 location_markers
.insert (newpair
);
144 if (select_new_marker
&& location
->is_mark()) {
145 selection
->set (lam
->start
);
146 select_new_marker
= false;
151 Editor::location_changed (Location
*location
)
153 ENSURE_GUI_THREAD (*this, &Editor::location_changed
, location
)
155 LocationMarkers
*lam
= find_location_markers (location
);
158 /* a location that isn't "marked" with markers */
162 lam
->set_name (location
->name ());
163 lam
->set_position (location
->start(), location
->end());
165 if (location
->is_auto_loop()) {
166 update_loop_range_view ();
167 } else if (location
->is_auto_punch()) {
168 update_punch_range_view ();
173 Editor::location_flags_changed (Location
*location
, void*)
175 ENSURE_GUI_THREAD (*this, &Editor::location_flags_changed
, location
, src
)
177 LocationMarkers
*lam
= find_location_markers (location
);
180 /* a location that isn't "marked" with markers */
184 // move cd markers to/from cd marker bar as appropriate
185 ensure_cd_marker_updated (lam
, location
);
187 if (location
->is_cd_marker()) {
188 lam
->set_color_rgba (location_cd_marker_color
);
189 } else if (location
->is_mark()) {
190 lam
->set_color_rgba (location_marker_color
);
191 } else if (location
->is_auto_punch()) {
192 lam
->set_color_rgba (location_punch_color
);
193 } else if (location
->is_auto_loop()) {
194 lam
->set_color_rgba (location_loop_color
);
196 lam
->set_color_rgba (location_range_color
);
199 if (location
->is_hidden()) {
206 void Editor::update_cd_marker_display ()
208 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
209 LocationMarkers
* lam
= i
->second
;
210 Location
* location
= i
->first
;
212 ensure_cd_marker_updated (lam
, location
);
216 void Editor::ensure_cd_marker_updated (LocationMarkers
* lam
, Location
* location
)
218 if (location
->is_cd_marker()
219 && (ruler_cd_marker_action
->get_active() && lam
->start
->get_parent() != cd_marker_group
))
221 //cerr << "reparenting non-cd marker so it can be relocated: " << location->name() << endl;
223 lam
->start
->reparent (*cd_marker_group
);
226 lam
->end
->reparent (*cd_marker_group
);
229 else if ( (!location
->is_cd_marker() || !ruler_cd_marker_action
->get_active())
230 && (lam
->start
->get_parent() == cd_marker_group
))
232 //cerr << "reparenting non-cd marker so it can be relocated: " << location->name() << endl;
233 if (location
->is_mark()) {
235 lam
->start
->reparent (*marker_group
);
238 lam
->end
->reparent (*marker_group
);
243 lam
->start
->reparent (*range_marker_group
);
246 lam
->end
->reparent (*range_marker_group
);
252 Editor::LocationMarkers::~LocationMarkers ()
258 Editor::LocationMarkers
*
259 Editor::find_location_markers (Location
*location
) const
261 LocationMarkerMap::const_iterator i
;
263 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
264 if ((*i
).first
== location
) {
273 Editor::find_location_from_marker (Marker
*marker
, bool& is_start
) const
275 LocationMarkerMap::const_iterator i
;
277 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
278 LocationMarkers
*lm
= (*i
).second
;
279 if (lm
->start
== marker
) {
282 } else if (lm
->end
== marker
) {
292 Editor::refresh_location_display_internal (Locations::LocationList
& locations
)
296 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
297 i
->second
->valid
= false;
302 for (Locations::LocationList::iterator i
= locations
.begin(); i
!= locations
.end(); ++i
) {
304 LocationMarkerMap::iterator x
;
306 if ((x
= location_markers
.find (*i
)) != location_markers
.end()) {
307 x
->second
->valid
= true;
311 add_new_location (*i
);
314 /* remove dead ones */
316 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ) {
318 LocationMarkerMap::iterator tmp
;
323 if (!i
->second
->valid
) {
325 location_markers
.erase (i
);
331 update_punch_range_view (false);
332 update_loop_range_view (false);
336 Editor::refresh_location_display ()
338 ENSURE_GUI_THREAD (*this, &Editor::refresh_location_display
)
341 _session
->locations()->apply (*this, &Editor::refresh_location_display_internal
);
346 Editor::refresh_location_display_s (const PropertyChange
&)
348 ENSURE_GUI_THREAD (*this, &Editor::refresh_location_display_s
, ignored
)
351 _session
->locations()->apply (*this, &Editor::refresh_location_display_internal
);
356 Editor::LocationMarkers::hide()
359 if (end
) { end
->hide(); }
363 Editor::LocationMarkers::show()
366 if (end
) { end
->show(); }
370 Editor::LocationMarkers::set_name (const string
& str
)
372 /* XXX: hack: don't change names of session start/end markers */
374 if (start
->type() != Marker::Start
) {
375 start
->set_name (str
);
378 if (end
&& end
->type() != Marker::End
) {
384 Editor::LocationMarkers::set_position (nframes64_t startf
,
387 start
->set_position (startf
);
388 if (end
) { end
->set_position (endf
); }
392 Editor::LocationMarkers::set_color_rgba (uint32_t rgba
)
394 start
->set_color_rgba (rgba
);
395 if (end
) { end
->set_color_rgba (rgba
); }
399 Editor::mouse_add_new_marker (nframes64_t where
, bool is_cd
, bool is_xrun
)
401 string markername
, markerprefix
;
402 int flags
= (is_cd
? Location::IsCDMarker
|Location::IsMark
: Location::IsMark
);
405 markerprefix
= "xrun";
406 flags
= Location::IsMark
;
408 markerprefix
= "mark";
412 _session
->locations()->next_available_name(markername
, markerprefix
);
413 if (!is_xrun
&& !choose_new_marker_name(markername
)) {
416 Location
*location
= new Location (where
, where
, markername
, (Location::Flags
) flags
);
417 _session
->begin_reversible_command (_("add marker"));
418 XMLNode
&before
= _session
->locations()->get_state();
419 _session
->locations()->add (location
, true);
420 XMLNode
&after
= _session
->locations()->get_state();
421 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
422 _session
->commit_reversible_command ();
424 /* find the marker we just added */
426 LocationMarkers
*lam
= find_location_markers (location
);
428 /* make it the selected marker */
429 selection
->set (lam
->start
);
435 Editor::remove_marker (ArdourCanvas::Item
& item
, GdkEvent
*)
440 if ((marker
= static_cast<Marker
*> (item
.get_data ("marker"))) == 0) {
441 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
445 if (entered_marker
== marker
) {
446 entered_marker
= NULL
;
449 Location
* loc
= find_location_from_marker (marker
, is_start
);
451 if (_session
&& loc
) {
452 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker
), loc
));
457 Editor::really_remove_marker (Location
* loc
)
459 _session
->begin_reversible_command (_("remove marker"));
460 XMLNode
&before
= _session
->locations()->get_state();
461 _session
->locations()->remove (loc
);
462 XMLNode
&after
= _session
->locations()->get_state();
463 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
464 _session
->commit_reversible_command ();
469 Editor::location_gone (Location
*location
)
471 ENSURE_GUI_THREAD (*this, &Editor::location_gone
, location
)
473 LocationMarkerMap::iterator i
;
475 if (location
== transport_loop_location()) {
476 update_loop_range_view (true);
479 if (location
== transport_punch_location()) {
480 update_punch_range_view (true);
483 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
484 if ((*i
).first
== location
) {
486 location_markers
.erase (i
);
493 Editor::tempo_or_meter_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
* item
)
495 marker_menu_item
= item
;
499 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
501 bool can_remove
= false;
504 can_remove
= mm
->meter().movable ();
506 can_remove
= tm
->tempo().movable ();
511 delete tempo_or_meter_marker_menu
;
512 build_tempo_or_meter_marker_menu (can_remove
);
513 tempo_or_meter_marker_menu
->popup (1, ev
->time
);
517 Editor::marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
* item
)
520 if ((marker
= reinterpret_cast<Marker
*> (item
->get_data("marker"))) == 0) {
521 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
526 Location
* loc
= find_location_from_marker (marker
, is_start
);
527 if (loc
== transport_loop_location() || loc
== transport_punch_location()) {
528 if (transport_marker_menu
== 0) {
529 build_range_marker_menu (true);
531 marker_menu_item
= item
;
532 transport_marker_menu
->popup (1, ev
->time
);
535 if (loc
->is_mark()) {
537 if (loc
->is_session_range ()) {
538 if (session_range_marker_menu
== 0) {
539 build_marker_menu (true);
541 markerMenu
= session_range_marker_menu
;
543 if (marker_menu
== 0)
544 build_marker_menu (false);
545 markerMenu
= marker_menu
;
549 // GTK2FIX use action group sensitivity
551 if (children
.size() >= 3) {
552 MenuItem
* loopitem
= &children
[2];
554 if (loc
->is_mark()) {
555 loopitem
->set_sensitive(false);
558 loopitem
->set_sensitive(true);
563 marker_menu_item
= item
;
564 markerMenu
->popup (1, ev
->time
);
567 if (loc
->is_range_marker()) {
568 if (range_marker_menu
== 0){
569 build_range_marker_menu (false);
571 marker_menu_item
= item
;
572 range_marker_menu
->popup (1, ev
->time
);
578 Editor::new_transport_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
*)
580 if (new_transport_marker_menu
== 0) {
581 build_new_transport_marker_menu ();
584 new_transport_marker_menu
->popup (1, ev
->time
);
589 Editor::transport_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
*)
591 if (transport_marker_menu
== 0) {
592 build_range_marker_menu (true);
595 transport_marker_menu
->popup (1, ev
->time
);
599 Editor::build_marker_menu (bool session_range
)
601 using namespace Menu_Helpers
;
603 Menu
*markerMenu
= new Menu
;
605 session_range_marker_menu
= markerMenu
;
607 marker_menu
= markerMenu
;
609 MenuList
& items
= markerMenu
->items();
610 markerMenu
->set_name ("ArdourContextMenu");
612 items
.push_back (MenuElem (_("Locate to here"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead
)));
613 items
.push_back (MenuElem (_("Play from here"), sigc::mem_fun(*this, &Editor::marker_menu_play_from
)));
614 items
.push_back (MenuElem (_("Move Mark to Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead
)));
616 items
.push_back (SeparatorElem());
618 items
.push_back (MenuElem (_("Create range to next marker"), sigc::mem_fun(*this, &Editor::marker_menu_range_to_next
)));
620 items
.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &Editor::marker_menu_hide
)));
624 items
.push_back (MenuElem (_("Rename"), sigc::mem_fun(*this, &Editor::marker_menu_rename
)));
625 items
.push_back (MenuElem (_("Lock"), sigc::bind (sigc::mem_fun(*this, &Editor::marker_menu_lock
), true)));
626 items
.push_back (MenuElem (_("Unlock"), sigc::bind (sigc::mem_fun(*this, &Editor::marker_menu_lock
), false)));
628 items
.push_back (SeparatorElem());
630 items
.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
634 Editor::build_range_marker_menu (bool loop_or_punch
)
636 using namespace Menu_Helpers
;
638 Menu
*markerMenu
= new Menu
;
640 transport_marker_menu
= markerMenu
;
642 range_marker_menu
= markerMenu
;
644 MenuList
& items
= markerMenu
->items();
645 markerMenu
->set_name ("ArdourContextMenu");
647 items
.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::marker_menu_play_range
)));
648 items
.push_back (MenuElem (_("Locate to Range Mark"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead
)));
649 items
.push_back (MenuElem (_("Play from Range Mark"), sigc::mem_fun(*this, &Editor::marker_menu_play_from
)));
650 if (! loop_or_punch
) {
651 items
.push_back (MenuElem (_("Loop Range"), sigc::mem_fun(*this, &Editor::marker_menu_loop_range
)));
653 items
.push_back (MenuElem (_("Set Range Mark from Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead
)));
654 if (!Profile
->get_sae()) {
655 items
.push_back (MenuElem (_("Set Range from Range Selection"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_selection
)));
658 items
.push_back (SeparatorElem());
659 items
.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_range
)));
660 items
.push_back (SeparatorElem());
662 if (!loop_or_punch
) {
663 items
.push_back (MenuElem (_("Hide Range"), sigc::mem_fun(*this, &Editor::marker_menu_hide
)));
664 items
.push_back (MenuElem (_("Rename Range"), sigc::mem_fun(*this, &Editor::marker_menu_rename
)));
665 items
.push_back (MenuElem (_("Remove Range"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
666 items
.push_back (SeparatorElem());
669 items
.push_back (MenuElem (_("Separate Regions in Range"), sigc::mem_fun(*this, &Editor::marker_menu_separate_regions_using_location
)));
670 items
.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range
)));
671 if (!Profile
->get_sae()) {
672 items
.push_back (MenuElem (_("Select Range"), sigc::mem_fun(*this, &Editor::marker_menu_select_using_range
)));
677 Editor::build_tempo_or_meter_marker_menu (bool can_remove
)
679 using namespace Menu_Helpers
;
681 tempo_or_meter_marker_menu
= new Menu
;
682 MenuList
& items
= tempo_or_meter_marker_menu
->items();
683 tempo_or_meter_marker_menu
->set_name ("ArdourContextMenu");
685 items
.push_back (MenuElem (_("Edit"), sigc::mem_fun(*this, &Editor::marker_menu_edit
)));
686 items
.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
688 items
.back().set_sensitive (can_remove
);
692 Editor::build_new_transport_marker_menu ()
694 using namespace Menu_Helpers
;
696 new_transport_marker_menu
= new Menu
;
697 MenuList
& items
= new_transport_marker_menu
->items();
698 new_transport_marker_menu
->set_name ("ArdourContextMenu");
700 items
.push_back (MenuElem (_("Set Loop Range"), sigc::mem_fun(*this, &Editor::new_transport_marker_menu_set_loop
)));
701 items
.push_back (MenuElem (_("Set Punch Range"), sigc::mem_fun(*this, &Editor::new_transport_marker_menu_set_punch
)));
703 new_transport_marker_menu
->signal_unmap().connect ( sigc::mem_fun(*this, &Editor::new_transport_marker_menu_popdown
));
707 Editor::marker_menu_hide ()
711 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
712 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
719 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
720 l
->set_hidden (true, this);
725 Editor::marker_menu_select_using_range ()
729 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
730 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
737 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
738 set_selection_from_range (*l
);
743 Editor::marker_menu_select_all_selectables_using_range ()
747 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
748 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
755 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
756 select_all_within (l
->start(), l
->end() - 1, 0, DBL_MAX
, track_views
, Selection::Set
);
762 Editor::marker_menu_separate_regions_using_location ()
766 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
767 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
774 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
775 separate_regions_using_location (*l
);
781 Editor::marker_menu_play_from ()
785 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
786 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
793 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
796 _session
->request_locate (l
->start(), true);
799 //_session->request_bounded_roll (l->start(), l->end());
802 _session
->request_locate (l
->start(), true);
804 _session
->request_locate (l
->end(), true);
811 Editor::marker_menu_set_playhead ()
815 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
816 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
823 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
826 _session
->request_locate (l
->start(), false);
830 _session
->request_locate (l
->start(), false);
832 _session
->request_locate (l
->end(), false);
839 Editor::marker_menu_range_to_next ()
846 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
847 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
854 if ((l
= find_location_from_marker (marker
, is_start
)) == 0) {
860 _session
->locations()->marks_either_side (marker
->position(), start
, end
);
862 if (end
!= max_frames
) {
863 string range_name
= l
->name();
864 range_name
+= "-range";
866 Location
* newrange
= new Location (marker
->position(), end
, range_name
, Location::IsRangeMarker
);
867 _session
->locations()->add (newrange
);
872 Editor::marker_menu_set_from_playhead ()
876 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
877 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
884 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
887 l
->set_start (_session
->audible_frame ());
891 l
->set_start (_session
->audible_frame ());
893 l
->set_end (_session
->audible_frame ());
900 Editor::marker_menu_set_from_selection ()
904 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
905 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
912 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
919 /* if range selection use first to last */
921 if (mouse_mode
== Editing::MouseRange
) {
922 if (!selection
->time
.empty()) {
923 l
->set_start (selection
->time
.start());
924 l
->set_end (selection
->time
.end_frame());
928 if (!selection
->regions
.empty()) {
929 l
->set_start (selection
->regions
.start());
930 l
->set_end (selection
->regions
.end_frame());
939 Editor::marker_menu_play_range ()
943 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
944 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
951 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
954 _session
->request_locate (l
->start(), true);
957 _session
->request_bounded_roll (l
->start(), l
->end());
964 Editor::marker_menu_loop_range ()
968 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
969 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
976 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
978 if ((l2
= transport_loop_location()) != 0) {
979 l2
->set (l
->start(), l
->end());
981 // enable looping, reposition and start rolling
982 _session
->request_play_loop(true);
983 _session
->request_locate (l2
->start(), true);
989 Editor::dynamic_cast_marker_object (void* p
, MeterMarker
** m
, TempoMarker
** t
) const
991 Marker
* marker
= reinterpret_cast<Marker
*> (p
);
993 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
997 *m
= dynamic_cast<MeterMarker
*> (marker
);
998 *t
= dynamic_cast<TempoMarker
*> (marker
);
1002 Editor::marker_menu_edit ()
1006 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
1009 edit_meter_section (&mm
->meter());
1011 edit_tempo_section (&tm
->tempo());
1016 Editor::marker_menu_remove ()
1020 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
1023 remove_meter_marker (marker_menu_item
);
1025 remove_tempo_marker (marker_menu_item
);
1027 remove_marker (*marker_menu_item
, (GdkEvent
*) 0);
1032 Editor::marker_menu_lock (bool yn
)
1037 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1038 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1045 loc
= find_location_from_marker (marker
, ignored
);
1057 Editor::marker_menu_rename ()
1061 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1062 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1069 loc
= find_location_from_marker (marker
, is_start
);
1073 ArdourPrompter
dialog (true);
1076 dialog
.set_prompt (_("New Name:"));
1078 if (loc
->is_mark()) {
1079 dialog
.set_title (_("Rename Mark"));
1081 dialog
.set_title (_("Rename Range"));
1084 dialog
.set_name ("MarkRenameWindow");
1085 dialog
.set_size_request (250, -1);
1086 dialog
.set_position (Gtk::WIN_POS_MOUSE
);
1088 dialog
.add_button (_("Rename"), RESPONSE_ACCEPT
);
1089 dialog
.set_response_sensitive (Gtk::RESPONSE_ACCEPT
, false);
1090 dialog
.set_initial_text (loc
->name());
1094 switch (dialog
.run ()) {
1095 case RESPONSE_ACCEPT
:
1101 begin_reversible_command ( _("rename marker") );
1102 XMLNode
&before
= _session
->locations()->get_state();
1104 dialog
.get_result(txt
);
1105 loc
->set_name (txt
);
1107 XMLNode
&after
= _session
->locations()->get_state();
1108 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
1109 commit_reversible_command ();
1113 Editor::new_transport_marker_menu_popdown ()
1116 transport_bar_drag_rect
->hide();
1122 Editor::new_transport_marker_menu_set_loop ()
1124 set_loop_range (temp_location
->start(), temp_location
->end(), _("set loop range"));
1128 Editor::new_transport_marker_menu_set_punch ()
1130 set_punch_range (temp_location
->start(), temp_location
->end(), _("set punch range"));
1134 Editor::update_loop_range_view (bool visibility
)
1136 if (_session
== 0) {
1142 if (_session
->get_play_loop() && ((tll
= transport_loop_location()) != 0)) {
1144 double x1
= frame_to_pixel (tll
->start());
1145 double x2
= frame_to_pixel (tll
->end());
1147 transport_loop_range_rect
->property_x1() = x1
;
1148 transport_loop_range_rect
->property_x2() = x2
;
1151 transport_loop_range_rect
->show();
1154 } else if (visibility
) {
1155 transport_loop_range_rect
->hide();
1160 Editor::update_punch_range_view (bool visibility
)
1162 if (_session
== 0) {
1168 if ((_session
->config
.get_punch_in() || _session
->config
.get_punch_out()) && ((tpl
= transport_punch_location()) != 0)) {
1169 guint track_canvas_width
,track_canvas_height
;
1170 track_canvas
->get_size(track_canvas_width
,track_canvas_height
);
1171 if (_session
->config
.get_punch_in()) {
1172 transport_punch_range_rect
->property_x1() = frame_to_pixel (tpl
->start());
1173 transport_punch_range_rect
->property_x2() = (_session
->config
.get_punch_out() ? frame_to_pixel (tpl
->end()) : frame_to_pixel (JACK_MAX_FRAMES
));
1175 transport_punch_range_rect
->property_x1() = 0;
1176 transport_punch_range_rect
->property_x2() = (_session
->config
.get_punch_out() ? frame_to_pixel (tpl
->end()) : track_canvas_width
);
1180 transport_punch_range_rect
->show();
1182 } else if (visibility
) {
1183 transport_punch_range_rect
->hide();
1188 Editor::marker_selection_changed ()
1190 if (_session
&& _session
->deletion_in_progress()) {
1194 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
1195 LocationMarkers
* lam
= i
->second
;
1198 lam
->start
->hide_line();
1202 lam
->end
->hide_line();
1206 for (MarkerSelection::iterator x
= selection
->markers
.begin(); x
!= selection
->markers
.end(); ++x
) {
1207 (*x
)->add_line (cursor_group
, 0, _canvas_height
);
1212 struct SortLocationsByPosition
{
1213 bool operator() (Location
* a
, Location
* b
) {
1214 return a
->start() < b
->start();
1219 Editor::goto_nth_marker (int n
)
1224 const Locations::LocationList
& l (_session
->locations()->list());
1225 Locations::LocationList ordered
;
1228 SortLocationsByPosition cmp
;
1231 for (Locations::LocationList::iterator i
= ordered
.begin(); n
>= 0 && i
!= ordered
.end(); ++i
) {
1232 if ((*i
)->is_mark() && !(*i
)->is_hidden() && !(*i
)->is_session_range()) {
1234 _session
->request_locate ((*i
)->start(), _session
->transport_rolling());