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 LocationMarkers
*lam
= new LocationMarkers
;
69 /* make a note here of which group this marker ends up in */
70 ArdourCanvas::Group
* group
= 0;
72 if (location
->is_cd_marker()) {
73 color
= location_cd_marker_color
;
74 } else if (location
->is_mark()) {
75 color
= location_marker_color
;
76 } else if (location
->is_auto_loop()) {
77 color
= location_loop_color
;
78 } else if (location
->is_auto_punch()) {
79 color
= location_punch_color
;
81 color
= location_range_color
;
84 if (location
->is_mark()) {
86 if (location
->is_cd_marker() && ruler_cd_marker_action
->get_active()) {
87 lam
->start
= new Marker (*this, *cd_marker_group
, color
, location
->name(), Marker::Mark
, location
->start());
88 group
= cd_marker_group
;
90 lam
->start
= new Marker (*this, *marker_group
, color
, location
->name(), Marker::Mark
, location
->start());
96 } else if (location
->is_auto_loop()) {
99 lam
->start
= new Marker (*this, *transport_marker_group
, color
,
100 location
->name(), Marker::LoopStart
, location
->start());
101 lam
->end
= new Marker (*this, *transport_marker_group
, color
,
102 location
->name(), Marker::LoopEnd
, location
->end());
103 group
= transport_marker_group
;
105 } else if (location
->is_auto_punch()) {
108 lam
->start
= new Marker (*this, *transport_marker_group
, color
,
109 location
->name(), Marker::PunchIn
, location
->start());
110 lam
->end
= new Marker (*this, *transport_marker_group
, color
,
111 location
->name(), Marker::PunchOut
, location
->end());
112 group
= transport_marker_group
;
114 } else if (location
->is_session_range()) {
117 lam
->start
= new Marker (*this, *marker_group
, color
, _("start"), Marker::SessionStart
, location
->start());
118 lam
->end
= new Marker (*this, *marker_group
, color
, _("end"), Marker::SessionEnd
, location
->end());
119 group
= marker_group
;
123 if (location
->is_cd_marker() && ruler_cd_marker_action
->get_active()) {
124 lam
->start
= new Marker (*this, *cd_marker_group
, color
,
125 location
->name(), Marker::RangeStart
, location
->start());
126 lam
->end
= new Marker (*this, *cd_marker_group
, color
,
127 location
->name(), Marker::RangeEnd
, location
->end());
128 group
= cd_marker_group
;
130 lam
->start
= new Marker (*this, *range_marker_group
, color
,
131 location
->name(), Marker::RangeStart
, location
->start());
132 lam
->end
= new Marker (*this, *range_marker_group
, color
,
133 location
->name(), Marker::RangeEnd
, location
->end());
134 group
= range_marker_group
;
138 if (location
->is_hidden ()) {
144 location
->start_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
145 location
->end_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
146 location
->changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
147 location
->name_changed
.connect (*this, invalidator (*this), ui_bind (&Editor::location_changed
, this, _1
), gui_context());
148 location
->FlagsChanged
.connect (*this, invalidator (*this), ui_bind (&Editor::location_flags_changed
, this, _1
, _2
), gui_context());
150 pair
<Location
*,LocationMarkers
*> newpair
;
152 newpair
.first
= location
;
153 newpair
.second
= lam
;
155 location_markers
.insert (newpair
);
157 if (select_new_marker
&& location
->is_mark()) {
158 selection
->set (lam
->start
);
159 select_new_marker
= false;
162 lam
->canvas_height_set (_canvas_height
);
163 lam
->set_show_lines (_show_marker_lines
);
165 /* Add these markers to the appropriate sorted marker lists, which will render
166 them unsorted until the update_marker_labels() below sorts them out.
168 _sorted_marker_lists
[group
].push_back (lam
->start
);
170 _sorted_marker_lists
[group
].push_back (lam
->end
);
173 /* Do a full update of the markers in this group */
174 update_marker_labels (group
);
178 Editor::location_changed (Location
*location
)
180 ENSURE_GUI_THREAD (*this, &Editor::location_changed
, location
)
182 LocationMarkers
*lam
= find_location_markers (location
);
185 /* a location that isn't "marked" with markers */
189 lam
->set_name (location
->name ());
190 lam
->set_position (location
->start(), location
->end());
192 if (location
->is_auto_loop()) {
193 update_loop_range_view ();
194 } else if (location
->is_auto_punch()) {
195 update_punch_range_view ();
198 check_marker_label (lam
->start
);
200 check_marker_label (lam
->end
);
204 /** Look at a marker and check whether its label, and those of the previous and next markers,
205 * need to have their labels updated (in case those labels need to be shortened or can be
209 Editor::check_marker_label (Marker
* m
)
211 /* Get a time-ordered list of markers from the last time anything changed */
212 std::list
<Marker
*>& sorted
= _sorted_marker_lists
[m
->get_parent()];
214 list
<Marker
*>::iterator i
= find (sorted
.begin(), sorted
.end(), m
);
216 list
<Marker
*>::iterator prev
= sorted
.end ();
217 list
<Marker
*>::iterator next
= i
;
220 /* Look to see if the previous marker is still behind `m' in time */
221 if (i
!= sorted
.begin()) {
226 if ((*prev
)->position() > m
->position()) {
227 /* This marker is no longer in the correct order with the previous one, so
228 * update all the markers in this group.
230 update_marker_labels (m
->get_parent ());
235 /* Look to see if the next marker is still ahead of `m' in time */
236 if (next
!= sorted
.end() && (*next
)->position() < m
->position()) {
237 /* This marker is no longer in the correct order with the next one, so
238 * update all the markers in this group.
240 update_marker_labels (m
->get_parent ());
244 if (prev
!= sorted
.end()) {
246 /* Update just the available space between the previous marker and this one */
248 double const p
= frame_to_pixel (m
->position() - (*prev
)->position());
250 if (m
->label_on_left()) {
251 (*prev
)->set_right_label_limit (p
/ 2);
253 (*prev
)->set_right_label_limit (p
);
256 if ((*prev
)->label_on_left ()) {
257 m
->set_left_label_limit (p
);
259 m
->set_left_label_limit (p
/ 2);
263 if (next
!= sorted
.end()) {
265 /* Update just the available space between this marker and the next */
267 double const p
= frame_to_pixel ((*next
)->position() - m
->position());
269 if ((*next
)->label_on_left()) {
270 m
->set_right_label_limit (p
/ 2);
272 m
->set_right_label_limit (p
);
275 if (m
->label_on_left()) {
276 (*next
)->set_left_label_limit (p
);
278 (*next
)->set_left_label_limit (p
/ 2);
283 struct MarkerComparator
{
284 bool operator() (Marker
const * a
, Marker
const * b
) {
285 return a
->position() < b
->position();
289 /** Update all marker labels in all groups */
291 Editor::update_marker_labels ()
293 for (std::map
<ArdourCanvas::Group
*, std::list
<Marker
*> >::iterator i
= _sorted_marker_lists
.begin(); i
!= _sorted_marker_lists
.end(); ++i
) {
294 update_marker_labels (i
->first
);
298 /** Look at all markers in a group and update label widths */
300 Editor::update_marker_labels (ArdourCanvas::Group
* group
)
302 list
<Marker
*>& sorted
= _sorted_marker_lists
[group
];
304 if (sorted
.empty()) {
308 /* We sort the list of markers and then set up the space available between each one */
310 sorted
.sort (MarkerComparator ());
312 list
<Marker
*>::iterator i
= sorted
.begin ();
314 list
<Marker
*>::iterator prev
= sorted
.end ();
315 list
<Marker
*>::iterator next
= i
;
318 while (i
!= sorted
.end()) {
320 if (prev
!= sorted
.end()) {
321 double const p
= frame_to_pixel ((*i
)->position() - (*prev
)->position());
323 if ((*prev
)->label_on_left()) {
324 (*i
)->set_left_label_limit (p
);
326 (*i
)->set_left_label_limit (p
/ 2);
331 if (next
!= sorted
.end()) {
332 double const p
= frame_to_pixel ((*next
)->position() - (*i
)->position());
334 if ((*next
)->label_on_left()) {
335 (*i
)->set_right_label_limit (p
/ 2);
337 (*i
)->set_right_label_limit (p
);
348 Editor::location_flags_changed (Location
*location
, void*)
350 ENSURE_GUI_THREAD (*this, &Editor::location_flags_changed
, location
, src
)
352 LocationMarkers
*lam
= find_location_markers (location
);
355 /* a location that isn't "marked" with markers */
359 // move cd markers to/from cd marker bar as appropriate
360 ensure_cd_marker_updated (lam
, location
);
362 if (location
->is_cd_marker()) {
363 lam
->set_color_rgba (location_cd_marker_color
);
364 } else if (location
->is_mark()) {
365 lam
->set_color_rgba (location_marker_color
);
366 } else if (location
->is_auto_punch()) {
367 lam
->set_color_rgba (location_punch_color
);
368 } else if (location
->is_auto_loop()) {
369 lam
->set_color_rgba (location_loop_color
);
371 lam
->set_color_rgba (location_range_color
);
374 if (location
->is_hidden()) {
381 void Editor::update_cd_marker_display ()
383 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
384 LocationMarkers
* lam
= i
->second
;
385 Location
* location
= i
->first
;
387 ensure_cd_marker_updated (lam
, location
);
391 void Editor::ensure_cd_marker_updated (LocationMarkers
* lam
, Location
* location
)
393 if (location
->is_cd_marker()
394 && (ruler_cd_marker_action
->get_active() && lam
->start
->get_parent() != cd_marker_group
))
396 //cerr << "reparenting non-cd marker so it can be relocated: " << location->name() << endl;
398 lam
->start
->reparent (*cd_marker_group
);
401 lam
->end
->reparent (*cd_marker_group
);
404 else if ( (!location
->is_cd_marker() || !ruler_cd_marker_action
->get_active())
405 && (lam
->start
->get_parent() == cd_marker_group
))
407 //cerr << "reparenting non-cd marker so it can be relocated: " << location->name() << endl;
408 if (location
->is_mark()) {
410 lam
->start
->reparent (*marker_group
);
413 lam
->end
->reparent (*marker_group
);
418 lam
->start
->reparent (*range_marker_group
);
421 lam
->end
->reparent (*range_marker_group
);
427 Editor::LocationMarkers::~LocationMarkers ()
433 Editor::LocationMarkers
*
434 Editor::find_location_markers (Location
*location
) const
436 LocationMarkerMap::const_iterator i
;
438 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
439 if ((*i
).first
== location
) {
448 Editor::find_location_from_marker (Marker
*marker
, bool& is_start
) const
450 LocationMarkerMap::const_iterator i
;
452 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
453 LocationMarkers
*lm
= (*i
).second
;
454 if (lm
->start
== marker
) {
457 } else if (lm
->end
== marker
) {
467 Editor::refresh_location_display_internal (Locations::LocationList
& locations
)
471 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
472 i
->second
->valid
= false;
477 for (Locations::LocationList::iterator i
= locations
.begin(); i
!= locations
.end(); ++i
) {
479 LocationMarkerMap::iterator x
;
481 if ((x
= location_markers
.find (*i
)) != location_markers
.end()) {
482 x
->second
->valid
= true;
486 add_new_location (*i
);
489 /* remove dead ones */
491 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ) {
493 LocationMarkerMap::iterator tmp
;
498 if (!i
->second
->valid
) {
500 remove_sorted_marker (i
->second
->start
);
501 if (i
->second
->end
) {
502 remove_sorted_marker (i
->second
->end
);
506 location_markers
.erase (i
);
512 update_punch_range_view (false);
513 update_loop_range_view (false);
517 Editor::refresh_location_display ()
519 ENSURE_GUI_THREAD (*this, &Editor::refresh_location_display
)
522 _session
->locations()->apply (*this, &Editor::refresh_location_display_internal
);
527 Editor::refresh_location_display_s (const PropertyChange
&)
529 ENSURE_GUI_THREAD (*this, &Editor::refresh_location_display_s
, ignored
)
532 _session
->locations()->apply (*this, &Editor::refresh_location_display_internal
);
537 Editor::LocationMarkers::hide()
546 Editor::LocationMarkers::show()
555 Editor::LocationMarkers::canvas_height_set (double h
)
557 start
->canvas_height_set (h
);
559 end
->canvas_height_set (h
);
564 Editor::LocationMarkers::set_name (const string
& str
)
566 /* XXX: hack: don't change names of session start/end markers */
568 if (start
->type() != Marker::SessionStart
) {
569 start
->set_name (str
);
572 if (end
&& end
->type() != Marker::SessionEnd
) {
578 Editor::LocationMarkers::set_position (framepos_t startf
,
581 start
->set_position (startf
);
583 end
->set_position (endf
);
588 Editor::LocationMarkers::set_color_rgba (uint32_t rgba
)
590 start
->set_color_rgba (rgba
);
592 end
->set_color_rgba (rgba
);
597 Editor::LocationMarkers::set_show_lines (bool s
)
599 start
->set_show_line (s
);
601 end
->set_show_line (s
);
606 Editor::LocationMarkers::set_selected (bool s
)
608 start
->set_selected (s
);
610 end
->set_selected (s
);
615 Editor::LocationMarkers::setup_lines ()
617 start
->setup_line ();
624 Editor::mouse_add_new_marker (framepos_t where
, bool is_cd
, bool is_xrun
)
626 string markername
, markerprefix
;
627 int flags
= (is_cd
? Location::IsCDMarker
|Location::IsMark
: Location::IsMark
);
630 markerprefix
= "xrun";
631 flags
= Location::IsMark
;
633 markerprefix
= "mark";
637 _session
->locations()->next_available_name(markername
, markerprefix
);
638 if (!is_xrun
&& !choose_new_marker_name(markername
)) {
641 Location
*location
= new Location (*_session
, where
, where
, markername
, (Location::Flags
) flags
);
642 _session
->begin_reversible_command (_("add marker"));
643 XMLNode
&before
= _session
->locations()->get_state();
644 _session
->locations()->add (location
, true);
645 XMLNode
&after
= _session
->locations()->get_state();
646 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
647 _session
->commit_reversible_command ();
649 /* find the marker we just added */
651 LocationMarkers
*lam
= find_location_markers (location
);
653 /* make it the selected marker */
654 selection
->set (lam
->start
);
660 Editor::remove_marker (ArdourCanvas::Item
& item
, GdkEvent
*)
665 if ((marker
= static_cast<Marker
*> (item
.get_data ("marker"))) == 0) {
666 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
670 if (entered_marker
== marker
) {
671 entered_marker
= NULL
;
674 Location
* loc
= find_location_from_marker (marker
, is_start
);
676 if (_session
&& loc
) {
677 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker
), loc
));
682 Editor::really_remove_marker (Location
* loc
)
684 _session
->begin_reversible_command (_("remove marker"));
685 XMLNode
&before
= _session
->locations()->get_state();
686 _session
->locations()->remove (loc
);
687 XMLNode
&after
= _session
->locations()->get_state();
688 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
689 _session
->commit_reversible_command ();
694 Editor::location_gone (Location
*location
)
696 ENSURE_GUI_THREAD (*this, &Editor::location_gone
, location
)
698 LocationMarkerMap::iterator i
;
700 if (location
== transport_loop_location()) {
701 update_loop_range_view (true);
704 if (location
== transport_punch_location()) {
705 update_punch_range_view (true);
708 for (i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
709 if (i
->first
== location
) {
711 remove_sorted_marker (i
->second
->start
);
712 if (i
->second
->end
) {
713 remove_sorted_marker (i
->second
->end
);
718 location_markers
.erase (i
);
725 Editor::tempo_or_meter_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
* item
)
727 marker_menu_item
= item
;
731 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
733 bool can_remove
= false;
736 can_remove
= mm
->meter().movable ();
738 can_remove
= tm
->tempo().movable ();
743 delete tempo_or_meter_marker_menu
;
744 build_tempo_or_meter_marker_menu (can_remove
);
745 tempo_or_meter_marker_menu
->popup (1, ev
->time
);
749 Editor::marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
* item
)
752 if ((marker
= reinterpret_cast<Marker
*> (item
->get_data("marker"))) == 0) {
753 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
758 Location
* loc
= find_location_from_marker (marker
, is_start
);
760 if (loc
== transport_loop_location() || loc
== transport_punch_location() || loc
->is_session_range ()) {
762 if (transport_marker_menu
== 0) {
763 build_range_marker_menu (true);
766 marker_menu_item
= item
;
767 transport_marker_menu
->popup (1, ev
->time
);
769 } else if (loc
->is_mark()) {
772 build_marker_menu (loc
);
774 // GTK2FIX use action group sensitivity
776 if (children
.size() >= 3) {
777 MenuItem
* loopitem
= &children
[2];
779 if (loc
->is_mark()) {
780 loopitem
->set_sensitive(false);
783 loopitem
->set_sensitive(true);
788 marker_menu_item
= item
;
789 marker_menu
->popup (1, ev
->time
);
791 } else if (loc
->is_range_marker()) {
792 if (range_marker_menu
== 0) {
793 build_range_marker_menu (false);
795 marker_menu_item
= item
;
796 range_marker_menu
->popup (1, ev
->time
);
801 Editor::new_transport_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
*)
803 if (new_transport_marker_menu
== 0) {
804 build_new_transport_marker_menu ();
807 new_transport_marker_menu
->popup (1, ev
->time
);
812 Editor::transport_marker_context_menu (GdkEventButton
* ev
, ArdourCanvas::Item
*)
814 if (transport_marker_menu
== 0) {
815 build_range_marker_menu (true);
818 transport_marker_menu
->popup (1, ev
->time
);
822 Editor::build_marker_menu (Location
* loc
)
824 using namespace Menu_Helpers
;
826 marker_menu
= new Menu
;
827 MenuList
& items
= marker_menu
->items();
828 marker_menu
->set_name ("ArdourContextMenu");
830 items
.push_back (MenuElem (_("Locate to Here"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead
)));
831 items
.push_back (MenuElem (_("Play from Here"), sigc::mem_fun(*this, &Editor::marker_menu_play_from
)));
832 items
.push_back (MenuElem (_("Move Mark to Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead
)));
834 items
.push_back (SeparatorElem());
836 items
.push_back (MenuElem (_("Create Range to Next Marker"), sigc::mem_fun(*this, &Editor::marker_menu_range_to_next
)));
838 items
.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &Editor::marker_menu_hide
)));
839 items
.push_back (MenuElem (_("Rename"), sigc::mem_fun(*this, &Editor::marker_menu_rename
)));
841 items
.push_back (CheckMenuElem (_("Lock")));
842 CheckMenuItem
* lock_item
= static_cast<CheckMenuItem
*> (&items
.back());
843 if (loc
->locked ()) {
844 lock_item
->set_active ();
846 lock_item
->signal_activate().connect (sigc::mem_fun (*this, &Editor::toggle_marker_menu_lock
));
848 items
.push_back (CheckMenuElem (_("Glue to Bars and Beats")));
849 CheckMenuItem
* glue_item
= static_cast<CheckMenuItem
*> (&items
.back());
850 if (loc
->position_lock_style() == MusicTime
) {
851 glue_item
->set_active ();
853 glue_item
->signal_activate().connect (sigc::mem_fun (*this, &Editor::toggle_marker_menu_glue
));
855 items
.push_back (SeparatorElem());
857 items
.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
861 Editor::build_range_marker_menu (bool loop_or_punch_or_session
)
863 using namespace Menu_Helpers
;
865 Menu
*markerMenu
= new Menu
;
866 if (loop_or_punch_or_session
) {
867 transport_marker_menu
= markerMenu
;
869 range_marker_menu
= markerMenu
;
871 MenuList
& items
= markerMenu
->items();
872 markerMenu
->set_name ("ArdourContextMenu");
874 items
.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::marker_menu_play_range
)));
875 items
.push_back (MenuElem (_("Locate to Range Mark"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead
)));
876 items
.push_back (MenuElem (_("Play from Range Mark"), sigc::mem_fun(*this, &Editor::marker_menu_play_from
)));
877 if (!loop_or_punch_or_session
) {
878 items
.push_back (MenuElem (_("Loop Range"), sigc::mem_fun(*this, &Editor::marker_menu_loop_range
)));
880 items
.push_back (MenuElem (_("Set Range Mark from Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead
)));
881 if (!Profile
->get_sae()) {
882 items
.push_back (MenuElem (_("Set Range from Range Selection"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_selection
)));
885 items
.push_back (SeparatorElem());
886 items
.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_range
)));
887 items
.push_back (SeparatorElem());
889 if (!loop_or_punch_or_session
) {
890 items
.push_back (MenuElem (_("Hide Range"), sigc::mem_fun(*this, &Editor::marker_menu_hide
)));
891 items
.push_back (MenuElem (_("Rename Range"), sigc::mem_fun(*this, &Editor::marker_menu_rename
)));
892 items
.push_back (MenuElem (_("Remove Range"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
893 items
.push_back (SeparatorElem());
896 items
.push_back (MenuElem (_("Separate Regions in Range"), sigc::mem_fun(*this, &Editor::marker_menu_separate_regions_using_location
)));
897 items
.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range
)));
898 if (!Profile
->get_sae()) {
899 items
.push_back (MenuElem (_("Select Range"), sigc::mem_fun(*this, &Editor::marker_menu_select_using_range
)));
904 Editor::build_tempo_or_meter_marker_menu (bool can_remove
)
906 using namespace Menu_Helpers
;
908 tempo_or_meter_marker_menu
= new Menu
;
909 MenuList
& items
= tempo_or_meter_marker_menu
->items();
910 tempo_or_meter_marker_menu
->set_name ("ArdourContextMenu");
912 items
.push_back (MenuElem (_("Edit"), sigc::mem_fun(*this, &Editor::marker_menu_edit
)));
913 items
.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::marker_menu_remove
)));
915 items
.back().set_sensitive (can_remove
);
919 Editor::build_new_transport_marker_menu ()
921 using namespace Menu_Helpers
;
923 new_transport_marker_menu
= new Menu
;
924 MenuList
& items
= new_transport_marker_menu
->items();
925 new_transport_marker_menu
->set_name ("ArdourContextMenu");
927 items
.push_back (MenuElem (_("Set Loop Range"), sigc::mem_fun(*this, &Editor::new_transport_marker_menu_set_loop
)));
928 items
.push_back (MenuElem (_("Set Punch Range"), sigc::mem_fun(*this, &Editor::new_transport_marker_menu_set_punch
)));
930 new_transport_marker_menu
->signal_unmap().connect ( sigc::mem_fun(*this, &Editor::new_transport_marker_menu_popdown
));
934 Editor::marker_menu_hide ()
938 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
939 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
946 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
947 l
->set_hidden (true, this);
952 Editor::marker_menu_select_using_range ()
956 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
957 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
964 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
965 set_selection_from_range (*l
);
970 Editor::marker_menu_select_all_selectables_using_range ()
974 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
975 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
982 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
983 select_all_within (l
->start(), l
->end() - 1, 0, DBL_MAX
, track_views
, Selection::Set
, false);
989 Editor::marker_menu_separate_regions_using_location ()
993 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
994 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1001 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
1002 separate_regions_using_location (*l
);
1008 Editor::marker_menu_play_from ()
1012 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1013 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1020 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1023 _session
->request_locate (l
->start(), true);
1026 //_session->request_bounded_roll (l->start(), l->end());
1029 _session
->request_locate (l
->start(), true);
1031 _session
->request_locate (l
->end(), true);
1038 Editor::marker_menu_set_playhead ()
1042 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1043 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1050 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1053 _session
->request_locate (l
->start(), false);
1057 _session
->request_locate (l
->start(), false);
1059 _session
->request_locate (l
->end(), false);
1066 Editor::marker_menu_range_to_next ()
1073 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1074 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1081 if ((l
= find_location_from_marker (marker
, is_start
)) == 0) {
1087 _session
->locations()->marks_either_side (marker
->position(), start
, end
);
1089 if (end
!= max_framepos
) {
1090 string range_name
= l
->name();
1091 range_name
+= "-range";
1093 Location
* newrange
= new Location (*_session
, marker
->position(), end
, range_name
, Location::IsRangeMarker
);
1094 _session
->locations()->add (newrange
);
1099 Editor::marker_menu_set_from_playhead ()
1103 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1104 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1111 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1114 l
->set_start (_session
->audible_frame ());
1118 l
->set_start (_session
->audible_frame ());
1120 l
->set_end (_session
->audible_frame ());
1127 Editor::marker_menu_set_from_selection ()
1131 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1132 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1139 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1146 /* if range selection use first to last */
1148 if (mouse_mode
== Editing::MouseRange
) {
1149 if (!selection
->time
.empty()) {
1150 l
->set_start (selection
->time
.start());
1151 l
->set_end (selection
->time
.end_frame());
1155 if (!selection
->regions
.empty()) {
1156 l
->set_start (selection
->regions
.start());
1157 l
->set_end (selection
->regions
.end_frame());
1166 Editor::marker_menu_play_range ()
1170 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1171 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1178 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1181 _session
->request_locate (l
->start(), true);
1184 _session
->request_bounded_roll (l
->start(), l
->end());
1191 Editor::marker_menu_loop_range ()
1195 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1196 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1203 if ((l
= find_location_from_marker (marker
, is_start
)) != 0) {
1205 if ((l2
= transport_loop_location()) != 0) {
1206 l2
->set (l
->start(), l
->end());
1208 // enable looping, reposition and start rolling
1209 _session
->request_play_loop(true);
1210 _session
->request_locate (l2
->start(), true);
1216 Editor::dynamic_cast_marker_object (void* p
, MeterMarker
** m
, TempoMarker
** t
) const
1218 Marker
* marker
= reinterpret_cast<Marker
*> (p
);
1220 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1224 *m
= dynamic_cast<MeterMarker
*> (marker
);
1225 *t
= dynamic_cast<TempoMarker
*> (marker
);
1229 Editor::marker_menu_edit ()
1233 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
1236 edit_meter_section (&mm
->meter());
1238 edit_tempo_section (&tm
->tempo());
1243 Editor::marker_menu_remove ()
1247 dynamic_cast_marker_object (marker_menu_item
->get_data ("marker"), &mm
, &tm
);
1250 remove_meter_marker (marker_menu_item
);
1252 remove_tempo_marker (marker_menu_item
);
1254 remove_marker (*marker_menu_item
, (GdkEvent
*) 0);
1259 Editor::toggle_marker_menu_lock ()
1263 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1264 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1271 loc
= find_location_from_marker (marker
, ignored
);
1277 if (loc
->locked()) {
1285 Editor::marker_menu_rename ()
1289 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1290 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1297 loc
= find_location_from_marker (marker
, is_start
);
1301 ArdourPrompter
dialog (true);
1304 dialog
.set_prompt (_("New Name:"));
1306 if (loc
->is_mark()) {
1307 dialog
.set_title (_("Rename Mark"));
1309 dialog
.set_title (_("Rename Range"));
1312 dialog
.set_name ("MarkRenameWindow");
1313 dialog
.set_size_request (250, -1);
1314 dialog
.set_position (Gtk::WIN_POS_MOUSE
);
1316 dialog
.add_button (_("Rename"), RESPONSE_ACCEPT
);
1317 dialog
.set_response_sensitive (Gtk::RESPONSE_ACCEPT
, false);
1318 dialog
.set_initial_text (loc
->name());
1322 switch (dialog
.run ()) {
1323 case RESPONSE_ACCEPT
:
1329 begin_reversible_command ( _("rename marker") );
1330 XMLNode
&before
= _session
->locations()->get_state();
1332 dialog
.get_result(txt
);
1333 loc
->set_name (txt
);
1335 XMLNode
&after
= _session
->locations()->get_state();
1336 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
1337 commit_reversible_command ();
1341 Editor::new_transport_marker_menu_popdown ()
1344 transport_bar_drag_rect
->hide();
1350 Editor::new_transport_marker_menu_set_loop ()
1352 set_loop_range (temp_location
->start(), temp_location
->end(), _("set loop range"));
1356 Editor::new_transport_marker_menu_set_punch ()
1358 set_punch_range (temp_location
->start(), temp_location
->end(), _("set punch range"));
1362 Editor::update_loop_range_view (bool visibility
)
1364 if (_session
== 0) {
1370 if (_session
->get_play_loop() && ((tll
= transport_loop_location()) != 0)) {
1372 double x1
= frame_to_pixel (tll
->start());
1373 double x2
= frame_to_pixel (tll
->end());
1375 transport_loop_range_rect
->property_x1() = x1
;
1376 transport_loop_range_rect
->property_x2() = x2
;
1379 transport_loop_range_rect
->show();
1382 } else if (visibility
) {
1383 transport_loop_range_rect
->hide();
1388 Editor::update_punch_range_view (bool visibility
)
1390 if (_session
== 0) {
1396 if ((_session
->config
.get_punch_in() || _session
->config
.get_punch_out()) && ((tpl
= transport_punch_location()) != 0)) {
1397 guint track_canvas_width
,track_canvas_height
;
1398 track_canvas
->get_size(track_canvas_width
,track_canvas_height
);
1399 if (_session
->config
.get_punch_in()) {
1400 transport_punch_range_rect
->property_x1() = frame_to_pixel (tpl
->start());
1401 transport_punch_range_rect
->property_x2() = (_session
->config
.get_punch_out() ? frame_to_pixel (tpl
->end()) : frame_to_pixel (JACK_MAX_FRAMES
));
1403 transport_punch_range_rect
->property_x1() = 0;
1404 transport_punch_range_rect
->property_x2() = (_session
->config
.get_punch_out() ? frame_to_pixel (tpl
->end()) : track_canvas_width
);
1408 transport_punch_range_rect
->show();
1410 } else if (visibility
) {
1411 transport_punch_range_rect
->hide();
1416 Editor::marker_selection_changed ()
1418 if (_session
&& _session
->deletion_in_progress()) {
1422 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
1423 i
->second
->set_selected (false);
1426 for (MarkerSelection::iterator x
= selection
->markers
.begin(); x
!= selection
->markers
.end(); ++x
) {
1427 (*x
)->set_selected (true);
1431 struct SortLocationsByPosition
{
1432 bool operator() (Location
* a
, Location
* b
) {
1433 return a
->start() < b
->start();
1438 Editor::goto_nth_marker (int n
)
1443 const Locations::LocationList
& l (_session
->locations()->list());
1444 Locations::LocationList ordered
;
1447 SortLocationsByPosition cmp
;
1450 for (Locations::LocationList::iterator i
= ordered
.begin(); n
>= 0 && i
!= ordered
.end(); ++i
) {
1451 if ((*i
)->is_mark() && !(*i
)->is_hidden() && !(*i
)->is_session_range()) {
1453 _session
->request_locate ((*i
)->start(), _session
->transport_rolling());
1462 Editor::toggle_marker_menu_glue ()
1466 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
1467 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
1474 loc
= find_location_from_marker (marker
, ignored
);
1480 if (loc
->position_lock_style() == MusicTime
) {
1481 loc
->set_position_lock_style (AudioTime
);
1483 loc
->set_position_lock_style (MusicTime
);
1489 Editor::toggle_marker_lines ()
1491 _show_marker_lines
= !_show_marker_lines
;
1493 for (LocationMarkerMap::iterator i
= location_markers
.begin(); i
!= location_markers
.end(); ++i
) {
1494 i
->second
->set_show_lines (_show_marker_lines
);
1499 Editor::remove_sorted_marker (Marker
* m
)
1501 for (std::map
<ArdourCanvas::Group
*, std::list
<Marker
*> >::iterator i
= _sorted_marker_lists
.begin(); i
!= _sorted_marker_lists
.end(); ++i
) {
1502 i
->second
.remove (m
);