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 ();
58 _sorted_marker_lists
.clear ();
62 Editor::add_new_location (Location
*location
)
64 ENSURE_GUI_THREAD (*this, &Editor::add_new_location
, location
);
66 ArdourCanvas::Group
* group
= add_new_location_internal (location
);
68 /* Do a full update of the markers in this group */
69 update_marker_labels (group
);
72 /** Add a new location, without a time-consuming update of all marker labels;
73 * the caller must call update_marker_labels () after calling this.
74 * @return canvas group that the location's marker was added to.
77 Editor::add_new_location_internal (Location
* location
)
79 LocationMarkers
*lam
= new LocationMarkers
;
82 /* make a note here of which group this marker ends up in */
83 ArdourCanvas::Group
* group
= 0;
85 if (location
->is_cd_marker()) {
86 color
= location_cd_marker_color
;
87 } else if (location
->is_mark()) {
88 color
= location_marker_color
;
89 } else if (location
->is_auto_loop()) {
90 color
= location_loop_color
;
91 } else if (location
->is_auto_punch()) {
92 color
= location_punch_color
;
94 color
= location_range_color
;
97 if (location
->is_mark()) {
99 if (location
->is_cd_marker() && ruler_cd_marker_action
->get_active()) {
100 lam
->start
= new Marker (*this, *cd_marker_group
, color
, location
->name(), Marker::Mark
, location
->start());
101 group
= cd_marker_group
;
103 lam
->start
= new Marker (*this, *marker_group
, color
, location
->name(), Marker::Mark
, location
->start());
104 group
= marker_group
;
109 } else if (location
->is_auto_loop()) {
112 lam
->start
= new Marker (*this, *transport_marker_group
, color
,
113 location
->name(), Marker::LoopStart
, location
->start());
114 lam
->end
= new Marker (*this, *transport_marker_group
, color
,
115 location
->name(), Marker::LoopEnd
, location
->end());
116 group
= transport_marker_group
;
118 } else if (location
->is_auto_punch()) {
121 lam
->start
= new Marker (*this, *transport_marker_group
, color
,
122 location
->name(), Marker::PunchIn
, location
->start());
123 lam
->end
= new Marker (*this, *transport_marker_group
, color
,
124 location
->name(), Marker::PunchOut
, location
->end());
125 group
= transport_marker_group
;
127 } else if (location
->is_session_range()) {
130 lam
->start
= new Marker (*this, *marker_group
, color
, _("start"), Marker::SessionStart
, location
->start());
131 lam
->end
= new Marker (*this, *marker_group
, color
, _("end"), Marker::SessionEnd
, location
->end());
132 group
= marker_group
;
136 if (location
->is_cd_marker() && ruler_cd_marker_action
->get_active()) {
137 lam
->start
= new Marker (*this, *cd_marker_group
, color
,
138 location
->name(), Marker::RangeStart
, location
->start());
139 lam
->end
= new Marker (*this, *cd_marker_group
, color
,
140 location
->name(), Marker::RangeEnd
, location
->end());
141 group
= cd_marker_group
;
143 lam
->start
= new Marker (*this, *range_marker_group
, color
,
144 location
->name(), Marker::RangeStart
, location
->start());
145 lam
->end
= new Marker (*this, *range_marker_group
, color
,
146 location
->name(), Marker::RangeEnd
, location
->end());
147 group
= range_marker_group
;
151 if (location
->is_hidden ()) {
157 location
->start_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
158 location
->end_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
159 location
->changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
160 location
->name_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
161 location
->FlagsChanged
.connect (*this, invalidator (*this), ui_bind (&Editor::location_flags_changed
, this, _1
, _2
), gui_context());
163 pair
<Location
*,LocationMarkers
*> newpair
;
165 newpair
.first
= location
;
166 newpair
.second
= lam
;
168 location_markers
.insert (newpair
);
170 if (select_new_marker
&& location
->is_mark()) {
171 selection
->set (lam
->start
);
172 select_new_marker
= false;
175 lam
->canvas_height_set (_canvas_height
);
176 lam
->set_show_lines (_show_marker_lines
);
178 /* Add these markers to the appropriate sorted marker lists, which will render
179 them unsorted until a call to update_marker_labels() sorts them out.
181 _sorted_marker_lists
[group
].push_back (lam
->start
);
183 _sorted_marker_lists
[group
].push_back (lam
->end
);
190 Editor::location_changed (Location
*location
)
192 ENSURE_GUI_THREAD (*this, &Editor::location_changed
, location
)
194 LocationMarkers
*lam
= find_location_markers (location
);
197 /* a location that isn't "marked" with markers */
201 lam
->set_name (location
->name ());
202 lam
->set_position (location
->start(), location
->end());
204 if (location
->is_auto_loop()) {
205 update_loop_range_view ();
206 } else if (location
->is_auto_punch()) {
207 update_punch_range_view ();
210 check_marker_label (lam
->start
);
212 check_marker_label (lam
->end
);
216 /** Look at a marker and check whether its label, and those of the previous and next markers,
217 * need to have their labels updated (in case those labels need to be shortened or can be
221 Editor::check_marker_label (Marker
* m
)
223 /* Get a time-ordered list of markers from the last time anything changed */
224 std::list
<Marker
*>& sorted
= _sorted_marker_lists
[m
->get_parent()];
226 list
<Marker
*>::iterator i
= find (sorted
.begin(), sorted
.end(), m
);
228 list
<Marker
*>::iterator prev
= sorted
.end ();
229 list
<Marker
*>::iterator next
= i
;
232 /* Look to see if the previous marker is still behind `m' in time */
233 if (i
!= sorted
.begin()) {
238 if ((*prev
)->position() > m
->position()) {
239 /* This marker is no longer in the correct order with the previous one, so
240 * update all the markers in this group.
242 update_marker_labels (m
->get_parent ());
247 /* Look to see if the next marker is still ahead of `m' in time */
248 if (next
!= sorted
.end() && (*next
)->position() < m
->position()) {
249 /* This marker is no longer in the correct order with the next one, so
250 * update all the markers in this group.
252 update_marker_labels (m
->get_parent ());
256 if (prev
!= sorted
.end()) {
258 /* Update just the available space between the previous marker and this one */
260 double const p
= frame_to_pixel (m
->position() - (*prev
)->position());
262 if (m
->label_on_left()) {
263 (*prev
)->set_right_label_limit (p
/ 2);
265 (*prev
)->set_right_label_limit (p
);
268 if ((*prev
)->label_on_left ()) {
269 m
->set_left_label_limit (p
);
271 m
->set_left_label_limit (p
/ 2);
275 if (next
!= sorted
.end()) {
277 /* Update just the available space between this marker and the next */
279 double const p
= frame_to_pixel ((*next
)->position() - m
->position());
281 if ((*next
)->label_on_left()) {
282 m
->set_right_label_limit (p
/ 2);
284 m
->set_right_label_limit (p
);
287 if (m
->label_on_left()) {
288 (*next
)->set_left_label_limit (p
);
290 (*next
)->set_left_label_limit (p
/ 2);
295 struct MarkerComparator
{
296 bool operator() (Marker
const * a
, Marker
const * b
) {
297 return a
->position() < b
->position();
301 /** Update all marker labels in all groups */
303 Editor::update_marker_labels ()
305 for (std::map
<ArdourCanvas::Group
*, std::list
<Marker
*> >::iterator i
= _sorted_marker_lists
.begin(); i
!= _sorted_marker_lists
.end(); ++i
) {
306 update_marker_labels (i
->first
);
310 /** Look at all markers in a group and update label widths */
312 Editor::update_marker_labels (ArdourCanvas::Group
* group
)
314 list
<Marker
*>& sorted
= _sorted_marker_lists
[group
];
316 if (sorted
.empty()) {
320 /* We sort the list of markers and then set up the space available between each one */
322 sorted
.sort (MarkerComparator ());
324 list
<Marker
*>::iterator i
= sorted
.begin ();
326 list
<Marker
*>::iterator prev
= sorted
.end ();
327 list
<Marker
*>::iterator next
= i
;
330 while (i
!= sorted
.end()) {
332 if (prev
!= sorted
.end()) {
333 double const p
= frame_to_pixel ((*i
)->position() - (*prev
)->position());
335 if ((*prev
)->label_on_left()) {
336 (*i
)->set_left_label_limit (p
);
338 (*i
)->set_left_label_limit (p
/ 2);
343 if (next
!= sorted
.end()) {
344 double const p
= frame_to_pixel ((*next
)->position() - (*i
)->position());
346 if ((*next
)->label_on_left()) {
347 (*i
)->set_right_label_limit (p
/ 2);
349 (*i
)->set_right_label_limit (p
);
360 Editor::location_flags_changed (Location
*location
, void*)
362 ENSURE_GUI_THREAD (*this, &Editor::location_flags_changed
, location
, src
)
364 LocationMarkers
*lam
= find_location_markers (location
);
367 /* a location that isn't "marked" with markers */
371 // move cd markers to/from cd marker bar as appropriate
372 ensure_cd_marker_updated (lam
, location
);
374 if (location
->is_cd_marker()) {
375 lam
->set_color_rgba (location_cd_marker_color
);
376 } else if (location
->is_mark()) {
377 lam
->set_color_rgba (location_marker_color
);
378 } else if (location
->is_auto_punch()) {
379 lam
->set_color_rgba (location_punch_color
);
380 } else if (location
->is_auto_loop()) {
381 lam
->set_color_rgba (location_loop_color
);
383 lam
->set_color_rgba (location_range_color
);
386 if (location
->is_hidden()) {
393 void Editor::update_cd_marker_display ()
395 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
396 LocationMarkers
* lam
= i
->second
;
397 Location
* location
= i
->first
;
399 ensure_cd_marker_updated (lam
, location
);
403 void Editor::ensure_cd_marker_updated (LocationMarkers
* lam
, Location
* location
)
405 if (location
->is_cd_marker()
406 && (ruler_cd_marker_action
->get_active() && lam
->start
->get_parent() != cd_marker_group
))
408 //cerr << "reparenting non-cd marker so it can be relocated: " << location->name() << endl;
410 lam
->start
->reparent (*cd_marker_group
);
413 lam
->end
->reparent (*cd_marker_group
);
416 else if ( (!location
->is_cd_marker() || !ruler_cd_marker_action
->get_active())
417 && (lam
->start
->get_parent() == cd_marker_group
))
419 //cerr << "reparenting non-cd marker so it can be relocated: " << location->name() << endl;
420 if (location
->is_mark()) {
422 lam
->start
->reparent (*marker_group
);
425 lam
->end
->reparent (*marker_group
);
430 lam
->start
->reparent (*range_marker_group
);
433 lam
->end
->reparent (*range_marker_group
);
439 Editor::LocationMarkers::~LocationMarkers ()
445 Editor::LocationMarkers
*
446 Editor::find_location_markers (Location
*location
) const
448 LocationMarkerMap::const_iterator i
;
450 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
451 if ((*i
).first
== location
) {
460 Editor::find_location_from_marker (Marker
*marker
, bool& is_start
) const
462 LocationMarkerMap::const_iterator i
;
464 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
465 LocationMarkers
*lm
= (*i
).second
;
466 if (lm
->start
== marker
) {
469 } else if (lm
->end
== marker
) {
479 Editor::refresh_location_display_internal (Locations::LocationList
& locations
)
483 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
484 i
->second
->valid
= false;
489 for (Locations::LocationList::iterator i
= locations
.begin(); i
!= locations
.end(); ++i
) {
491 LocationMarkerMap::iterator x
;
493 if ((x
= location_markers
.find (*i
)) != location_markers
.end()) {
494 x
->second
->valid
= true;
498 add_new_location_internal (*i
);
501 /* remove dead ones */
503 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ) {
505 LocationMarkerMap::iterator tmp
;
510 if (!i
->second
->valid
) {
512 remove_sorted_marker (i
->second
->start
);
513 if (i
->second
->end
) {
514 remove_sorted_marker (i
->second
->end
);
517 LocationMarkers
* m
= i
->second
;
518 location_markers
.erase (i
);
525 update_punch_range_view (false);
526 update_loop_range_view (false);
530 Editor::refresh_location_display ()
532 ENSURE_GUI_THREAD (*this, &Editor::refresh_location_display
)
535 _session
->locations()->apply (*this, &Editor::refresh_location_display_internal
);
538 update_marker_labels ();
542 Editor::LocationMarkers::hide()
551 Editor::LocationMarkers::show()
560 Editor::LocationMarkers::canvas_height_set (double h
)
562 start
->canvas_height_set (h
);
564 end
->canvas_height_set (h
);
569 Editor::LocationMarkers::set_name (const string
& str
)
571 /* XXX: hack: don't change names of session start/end markers */
573 if (start
->type() != Marker::SessionStart
) {
574 start
->set_name (str
);
577 if (end
&& end
->type() != Marker::SessionEnd
) {
583 Editor::LocationMarkers::set_position (framepos_t startf
,
586 start
->set_position (startf
);
588 end
->set_position (endf
);
593 Editor::LocationMarkers::set_color_rgba (uint32_t rgba
)
595 start
->set_color_rgba (rgba
);
597 end
->set_color_rgba (rgba
);
602 Editor::LocationMarkers::set_show_lines (bool s
)
604 start
->set_show_line (s
);
606 end
->set_show_line (s
);
611 Editor::LocationMarkers::set_selected (bool s
)
613 start
->set_selected (s
);
615 end
->set_selected (s
);
620 Editor::LocationMarkers::setup_lines ()
622 start
->setup_line ();
629 Editor::mouse_add_new_marker (framepos_t where
, bool is_cd
, bool is_xrun
)
631 string markername
, markerprefix
;
632 int flags
= (is_cd
? Location::IsCDMarker
|Location::IsMark
: Location::IsMark
);
635 markerprefix
= "xrun";
636 flags
= Location::IsMark
;
638 markerprefix
= "mark";
642 _session
->locations()->next_available_name(markername
, markerprefix
);
643 if (!is_xrun
&& !choose_new_marker_name(markername
)) {
646 Location
*location
= new Location (*_session
, where
, where
, markername
, (Location::Flags
) flags
);
647 _session
->begin_reversible_command (_("add marker"));
648 XMLNode
&before
= _session
->locations()->get_state();
649 _session
->locations()->add (location
, true);
650 XMLNode
&after
= _session
->locations()->get_state();
651 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
652 _session
->commit_reversible_command ();
654 /* find the marker we just added */
656 LocationMarkers
*lam
= find_location_markers (location
);
658 /* make it the selected marker */
659 selection
->set (lam
->start
);
665 Editor::remove_marker (ArdourCanvas::Item
& item
, GdkEvent
*)
670 if ((marker
= static_cast<Marker
*> (item
.get_data ("marker"))) == 0) {
671 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
675 if (entered_marker
== marker
) {
676 entered_marker
= NULL
;
679 Location
* loc
= find_location_from_marker (marker
, is_start
);
681 if (_session
&& loc
) {
682 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker
), loc
));
687 Editor::really_remove_marker (Location
* loc
)
689 _session
->begin_reversible_command (_("remove marker"));
690 XMLNode
&before
= _session
->locations()->get_state();
691 _session
->locations()->remove (loc
);
692 XMLNode
&after
= _session
->locations()->get_state();
693 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
694 _session
->commit_reversible_command ();
699 Editor::location_gone (Location
*location
)
701 ENSURE_GUI_THREAD (*this, &Editor::location_gone
, location
)
703 LocationMarkerMap::iterator i
;
705 if (location
== transport_loop_location()) {
706 update_loop_range_view (true);
709 if (location
== transport_punch_location()) {
710 update_punch_range_view (true);
713 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
714 if (i
->first
== location
) {
716 remove_sorted_marker (i
->second
->start
);
717 if (i
->second
->end
) {
718 remove_sorted_marker (i
->second
->end
);
721 LocationMarkers
* m
= i
->second
;
722 location_markers
.erase (i
);
730 Editor::tempo_or_meter_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
* item
)
732 marker_menu_item
= item
;
736 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
738 bool can_remove
= false;
741 can_remove
= mm
->meter().movable ();
743 can_remove
= tm
->tempo().movable ();
748 delete tempo_or_meter_marker_menu
;
749 build_tempo_or_meter_marker_menu (can_remove
);
750 tempo_or_meter_marker_menu
->popup (1, ev
->time
);
754 Editor::marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
* item
)
757 if ((marker
= reinterpret_cast<Marker
*> (item
->get_data("marker"))) == 0) {
758 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
763 Location
* loc
= find_location_from_marker (marker
, is_start
);
765 if (loc
== transport_loop_location() || loc
== transport_punch_location() || loc
->is_session_range ()) {
767 if (transport_marker_menu
== 0) {
768 build_range_marker_menu (true);
771 marker_menu_item
= item
;
772 transport_marker_menu
->popup (1, ev
->time
);
774 } else if (loc
->is_mark()) {
777 build_marker_menu (loc
);
779 // GTK2FIX use action group sensitivity
781 if (children
.size() >= 3) {
782 MenuItem
* loopitem
= &children
[2];
784 if (loc
->is_mark()) {
785 loopitem
->set_sensitive(false);
788 loopitem
->set_sensitive(true);
793 marker_menu_item
= item
;
794 marker_menu
->popup (1, ev
->time
);
796 } else if (loc
->is_range_marker()) {
797 if (range_marker_menu
== 0) {
798 build_range_marker_menu (false);
800 marker_menu_item
= item
;
801 range_marker_menu
->popup (1, ev
->time
);
806 Editor::new_transport_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
*)
808 if (new_transport_marker_menu
== 0) {
809 build_new_transport_marker_menu ();
812 new_transport_marker_menu
->popup (1, ev
->time
);
817 Editor::transport_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
*)
819 if (transport_marker_menu
== 0) {
820 build_range_marker_menu (true);
823 transport_marker_menu
->popup (1, ev
->time
);
827 Editor::build_marker_menu (Location
* loc
)
829 using namespace Menu_Helpers
;
831 marker_menu
= new Menu
;
832 MenuList
& items
= marker_menu
->items();
833 marker_menu
->set_name ("ArdourContextMenu");
835 items
.push_back (MenuElem (_("Locate to Here"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead
)));
836 items
.push_back (MenuElem (_("Play from Here"), sigc::mem_fun(*this, &Editor::marker_menu_play_from
)));
837 items
.push_back (MenuElem (_("Move Mark to Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead
)));
839 items
.push_back (SeparatorElem());
841 items
.push_back (MenuElem (_("Create Range to Next Marker"), sigc::mem_fun(*this, &Editor::marker_menu_range_to_next
)));
843 items
.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &Editor::marker_menu_hide
)));
844 items
.push_back (MenuElem (_("Rename"), sigc::mem_fun(*this, &Editor::marker_menu_rename
)));
846 items
.push_back (CheckMenuElem (_("Lock")));
847 CheckMenuItem
* lock_item
= static_cast<CheckMenuItem
*> (&items
.back());
848 if (loc
->locked ()) {
849 lock_item
->set_active ();
851 lock_item
->signal_activate().connect (sigc::mem_fun (*this, &Editor::toggle_marker_menu_lock
));
853 items
.push_back (CheckMenuElem (_("Glue to Bars and Beats")));
854 CheckMenuItem
* glue_item
= static_cast<CheckMenuItem
*> (&items
.back());
855 if (loc
->position_lock_style() == MusicTime
) {
856 glue_item
->set_active ();
858 glue_item
->signal_activate().connect (sigc::mem_fun (*this, &Editor::toggle_marker_menu_glue
));
860 items
.push_back (SeparatorElem());
862 items
.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
866 Editor::build_range_marker_menu (bool loop_or_punch_or_session
)
868 using namespace Menu_Helpers
;
870 Menu
*markerMenu
= new Menu
;
871 if (loop_or_punch_or_session
) {
872 transport_marker_menu
= markerMenu
;
874 range_marker_menu
= markerMenu
;
876 MenuList
& items
= markerMenu
->items();
877 markerMenu
->set_name ("ArdourContextMenu");
879 items
.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::marker_menu_play_range
)));
880 items
.push_back (MenuElem (_("Locate to Range Mark"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead
)));
881 items
.push_back (MenuElem (_("Play from Range Mark"), sigc::mem_fun(*this, &Editor::marker_menu_play_from
)));
882 if (!loop_or_punch_or_session
) {
883 items
.push_back (MenuElem (_("Loop Range"), sigc::mem_fun(*this, &Editor::marker_menu_loop_range
)));
885 items
.push_back (MenuElem (_("Set Range Mark from Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead
)));
886 if (!Profile
->get_sae()) {
887 items
.push_back (MenuElem (_("Set Range from Range Selection"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_selection
)));
890 items
.push_back (SeparatorElem());
891 items
.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_range
)));
892 items
.push_back (SeparatorElem());
894 if (!loop_or_punch_or_session
) {
895 items
.push_back (MenuElem (_("Hide Range"), sigc::mem_fun(*this, &Editor::marker_menu_hide
)));
896 items
.push_back (MenuElem (_("Rename Range"), sigc::mem_fun(*this, &Editor::marker_menu_rename
)));
897 items
.push_back (MenuElem (_("Remove Range"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
898 items
.push_back (SeparatorElem());
901 items
.push_back (MenuElem (_("Separate Regions in Range"), sigc::mem_fun(*this, &Editor::marker_menu_separate_regions_using_location
)));
902 items
.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range
)));
903 if (!Profile
->get_sae()) {
904 items
.push_back (MenuElem (_("Select Range"), sigc::mem_fun(*this, &Editor::marker_menu_select_using_range
)));
909 Editor::build_tempo_or_meter_marker_menu (bool can_remove
)
911 using namespace Menu_Helpers
;
913 tempo_or_meter_marker_menu
= new Menu
;
914 MenuList
& items
= tempo_or_meter_marker_menu
->items();
915 tempo_or_meter_marker_menu
->set_name ("ArdourContextMenu");
917 items
.push_back (MenuElem (_("Edit..."), sigc::mem_fun(*this, &Editor::marker_menu_edit
)));
918 items
.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
920 items
.back().set_sensitive (can_remove
);
924 Editor::build_new_transport_marker_menu ()
926 using namespace Menu_Helpers
;
928 new_transport_marker_menu
= new Menu
;
929 MenuList
& items
= new_transport_marker_menu
->items();
930 new_transport_marker_menu
->set_name ("ArdourContextMenu");
932 items
.push_back (MenuElem (_("Set Loop Range"), sigc::mem_fun(*this, &Editor::new_transport_marker_menu_set_loop
)));
933 items
.push_back (MenuElem (_("Set Punch Range"), sigc::mem_fun(*this, &Editor::new_transport_marker_menu_set_punch
)));
935 new_transport_marker_menu
->signal_unmap().connect ( sigc::mem_fun(*this, &Editor::new_transport_marker_menu_popdown
));
939 Editor::marker_menu_hide ()
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) {
952 l
->set_hidden (true, this);
957 Editor::marker_menu_select_using_range ()
961 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
962 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
969 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
970 set_selection_from_range (*l
);
975 Editor::marker_menu_select_all_selectables_using_range ()
979 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
980 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
987 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
988 select_all_within (l
->start(), l
->end() - 1, 0, DBL_MAX
, track_views
, Selection::Set
, false);
994 Editor::marker_menu_separate_regions_using_location ()
998 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
999 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1006 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
1007 separate_regions_using_location (*l
);
1013 Editor::marker_menu_play_from ()
1017 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1018 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1025 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1028 _session
->request_locate (l
->start(), true);
1031 //_session->request_bounded_roll (l->start(), l->end());
1034 _session
->request_locate (l
->start(), true);
1036 _session
->request_locate (l
->end(), true);
1043 Editor::marker_menu_set_playhead ()
1047 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1048 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1055 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1058 _session
->request_locate (l
->start(), false);
1062 _session
->request_locate (l
->start(), false);
1064 _session
->request_locate (l
->end(), false);
1071 Editor::marker_menu_range_to_next ()
1078 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1079 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1086 if ((l
= find_location_from_marker (marker
, is_start
)) == 0) {
1092 _session
->locations()->marks_either_side (marker
->position(), start
, end
);
1094 if (end
!= max_framepos
) {
1095 string range_name
= l
->name();
1096 range_name
+= "-range";
1098 Location
* newrange
= new Location (*_session
, marker
->position(), end
, range_name
, Location::IsRangeMarker
);
1099 _session
->locations()->add (newrange
);
1104 Editor::marker_menu_set_from_playhead ()
1108 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1109 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1116 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1119 l
->set_start (_session
->audible_frame ());
1123 l
->set_start (_session
->audible_frame ());
1125 l
->set_end (_session
->audible_frame ());
1132 Editor::marker_menu_set_from_selection ()
1136 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1137 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1144 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1151 /* if range selection use first to last */
1153 if (mouse_mode
== Editing::MouseRange
) {
1154 if (!selection
->time
.empty()) {
1155 l
->set_start (selection
->time
.start());
1156 l
->set_end (selection
->time
.end_frame());
1160 if (!selection
->regions
.empty()) {
1161 l
->set_start (selection
->regions
.start());
1162 l
->set_end (selection
->regions
.end_frame());
1171 Editor::marker_menu_play_range ()
1175 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1176 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1183 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1186 _session
->request_locate (l
->start(), true);
1189 _session
->request_bounded_roll (l
->start(), l
->end());
1196 Editor::marker_menu_loop_range ()
1200 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1201 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1208 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1210 if ((l2
= transport_loop_location()) != 0) {
1211 l2
->set (l
->start(), l
->end());
1213 // enable looping, reposition and start rolling
1214 _session
->request_play_loop(true);
1215 _session
->request_locate (l2
->start(), true);
1221 Editor::dynamic_cast_marker_object (void* p
, MeterMarker
** m
, TempoMarker
** t
) const
1223 Marker
* marker
= reinterpret_cast<Marker
*> (p
);
1225 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1229 *m
= dynamic_cast<MeterMarker
*> (marker
);
1230 *t
= dynamic_cast<TempoMarker
*> (marker
);
1234 Editor::marker_menu_edit ()
1238 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
1241 edit_meter_section (&mm
->meter());
1243 edit_tempo_section (&tm
->tempo());
1248 Editor::marker_menu_remove ()
1252 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
1255 remove_meter_marker (marker_menu_item
);
1257 remove_tempo_marker (marker_menu_item
);
1259 remove_marker (*marker_menu_item
, (GdkEvent
*) 0);
1264 Editor::toggle_marker_menu_lock ()
1268 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1269 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1276 loc
= find_location_from_marker (marker
, ignored
);
1282 if (loc
->locked()) {
1290 Editor::marker_menu_rename ()
1294 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1295 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1302 loc
= find_location_from_marker (marker
, is_start
);
1306 ArdourPrompter
dialog (true);
1309 dialog
.set_prompt (_("New Name:"));
1311 if (loc
->is_mark()) {
1312 dialog
.set_title (_("Rename Mark"));
1314 dialog
.set_title (_("Rename Range"));
1317 dialog
.set_name ("MarkRenameWindow");
1318 dialog
.set_size_request (250, -1);
1319 dialog
.set_position (Gtk::WIN_POS_MOUSE
);
1321 dialog
.add_button (_("Rename"), RESPONSE_ACCEPT
);
1322 dialog
.set_response_sensitive (Gtk::RESPONSE_ACCEPT
, false);
1323 dialog
.set_initial_text (loc
->name());
1327 switch (dialog
.run ()) {
1328 case RESPONSE_ACCEPT
:
1334 begin_reversible_command ( _("rename marker") );
1335 XMLNode
&before
= _session
->locations()->get_state();
1337 dialog
.get_result(txt
);
1338 loc
->set_name (txt
);
1340 XMLNode
&after
= _session
->locations()->get_state();
1341 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
1342 commit_reversible_command ();
1346 Editor::new_transport_marker_menu_popdown ()
1349 transport_bar_drag_rect
->hide();
1355 Editor::new_transport_marker_menu_set_loop ()
1357 set_loop_range (temp_location
->start(), temp_location
->end(), _("set loop range"));
1361 Editor::new_transport_marker_menu_set_punch ()
1363 set_punch_range (temp_location
->start(), temp_location
->end(), _("set punch range"));
1367 Editor::update_loop_range_view (bool visibility
)
1369 if (_session
== 0) {
1375 if (_session
->get_play_loop() && ((tll
= transport_loop_location()) != 0)) {
1377 double x1
= frame_to_pixel (tll
->start());
1378 double x2
= frame_to_pixel (tll
->end());
1380 transport_loop_range_rect
->property_x1() = x1
;
1381 transport_loop_range_rect
->property_x2() = x2
;
1384 transport_loop_range_rect
->show();
1387 } else if (visibility
) {
1388 transport_loop_range_rect
->hide();
1393 Editor::update_punch_range_view (bool visibility
)
1395 if (_session
== 0) {
1401 if ((_session
->config
.get_punch_in() || _session
->config
.get_punch_out()) && ((tpl
= transport_punch_location()) != 0)) {
1402 guint track_canvas_width
,track_canvas_height
;
1403 track_canvas
->get_size(track_canvas_width
,track_canvas_height
);
1404 if (_session
->config
.get_punch_in()) {
1405 transport_punch_range_rect
->property_x1() = frame_to_pixel (tpl
->start());
1406 transport_punch_range_rect
->property_x2() = (_session
->config
.get_punch_out() ? frame_to_pixel (tpl
->end()) : frame_to_pixel (JACK_MAX_FRAMES
));
1408 transport_punch_range_rect
->property_x1() = 0;
1409 transport_punch_range_rect
->property_x2() = (_session
->config
.get_punch_out() ? frame_to_pixel (tpl
->end()) : track_canvas_width
);
1413 transport_punch_range_rect
->show();
1415 } else if (visibility
) {
1416 transport_punch_range_rect
->hide();
1421 Editor::marker_selection_changed ()
1423 if (_session
&& _session
->deletion_in_progress()) {
1427 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
1428 i
->second
->set_selected (false);
1431 for (MarkerSelection::iterator x
= selection
->markers
.begin(); x
!= selection
->markers
.end(); ++x
) {
1432 (*x
)->set_selected (true);
1436 struct SortLocationsByPosition
{
1437 bool operator() (Location
* a
, Location
* b
) {
1438 return a
->start() < b
->start();
1443 Editor::goto_nth_marker (int n
)
1448 const Locations::LocationList
& l (_session
->locations()->list());
1449 Locations::LocationList ordered
;
1452 SortLocationsByPosition cmp
;
1455 for (Locations::LocationList::iterator i
= ordered
.begin(); n
>= 0 && i
!= ordered
.end(); ++i
) {
1456 if ((*i
)->is_mark() && !(*i
)->is_hidden() && !(*i
)->is_session_range()) {
1458 _session
->request_locate ((*i
)->start(), _session
->transport_rolling());
1467 Editor::toggle_marker_menu_glue ()
1471 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1472 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1479 loc
= find_location_from_marker (marker
, ignored
);
1485 if (loc
->position_lock_style() == MusicTime
) {
1486 loc
->set_position_lock_style (AudioTime
);
1488 loc
->set_position_lock_style (MusicTime
);
1494 Editor::toggle_marker_lines ()
1496 _show_marker_lines
= !_show_marker_lines
;
1498 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
1499 i
->second
->set_show_lines (_show_marker_lines
);
1504 Editor::remove_sorted_marker (Marker
* m
)
1506 for (std::map
<ArdourCanvas::Group
*, std::list
<Marker
*> >::iterator i
= _sorted_marker_lists
.begin(); i
!= _sorted_marker_lists
.end(); ++i
) {
1507 i
->second
.remove (m
);