3 notable patches from lincoln (a) non-layered track mode (NOTE: this is broken for...
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 20 Apr 2009 21:02:46 +0000 (21:02 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 20 Apr 2009 21:02:46 +0000 (21:02 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@4994 d708f5d6-7413-0410-9779-e7cbd77b26cf

24 files changed:
gtk2_ardour/add_route_dialog.cc
gtk2_ardour/ardour.menus.in
gtk2_ardour/audio_streamview.cc
gtk2_ardour/audio_time_axis.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_actions.cc
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_time_axis.h
gtk2_ardour/streamview.cc
libs/ardour/ardour/audio_diskstream.h
libs/ardour/ardour/configuration_vars.h
libs/ardour/ardour/diskstream.h
libs/ardour/ardour/playlist.h
libs/ardour/ardour/types.h
libs/ardour/audio_diskstream.cc
libs/ardour/audio_playlist.cc
libs/ardour/audio_track.cc
libs/ardour/configuration.cc
libs/ardour/enums.cc
libs/ardour/midi_playlist.cc
libs/ardour/playlist.cc
wscript

index d5856fa4e6ca0b31a92940b1e328fbf56a4326ea..9baa8f3cd20c4d1c1c0c848255525ebc1477349a 100644 (file)
@@ -56,6 +56,7 @@ static const char* channel_setup_names[] = {
 
 static const char* track_mode_names[] = {
        N_("Normal"),
+       N_("Non Layered"),
        N_("Tape"),
        0
 };
@@ -273,6 +274,8 @@ AddRouteDialog::mode ()
        Glib::ustring str = track_mode_combo.get_active_text();
        if (str == _("Normal")) {
                return ARDOUR::Normal;
+       } else if (str == _("Non Layered")){
+               return ARDOUR::NonLayered;
        } else if (str == _("Tape")) {
                return ARDOUR::Destructive;
        } else {
index eb0968da4ade5ed97eebd86dace71ce36bad08a4..c754590102e679c6fdcdfe25d1a9a3bc49db0240 100644 (file)
                   <menuitem action='crop'/>
                   <menuitem action='trim-region-to-loop'/>
                   <menuitem action='trim-region-to-punch'/>
+                  <menuitem action='trim-to-previous-region'/>
+                  <menuitem action='trim-to-next-region'/>
               </menu>
               <menu action="FadeMenu">
                   <menuitem action='set-fade-in-length'/>
index ed56651e5f31c2003ee13d986768a32e40c01064..8dcee5aaab1bf4d10f25c9bc8bb68578de0898ea 100644 (file)
@@ -134,6 +134,8 @@ AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wai
        }
 
        switch (_trackview.audio_track()->mode()) {
+       
+       case NonLayered:
        case Normal:
                if (recording) {
                        region_view = new AudioRegionView (canvas_group, _trackview, region, 
@@ -519,6 +521,7 @@ AudioStreamView::setup_rec_box ()
 
                        switch (_trackview.audio_track()->mode()) {
                        case Normal:
+                       case NonLayered:
                                xend = xstart;
                                fill_color = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
                                break;
index 609d7b7d6ca380ba98fc7619a99730ee7a688aaf..b774182a88d4d5edc33cc8e35c242c7f6aac03f3 100644 (file)
@@ -245,9 +245,15 @@ AudioTimeAxisView::build_mode_menu()
        mode_menu->set_name ("ArdourContextMenu");
 
        RadioMenuItem::Group mode_group;
+
        items.push_back (RadioMenuElem (mode_group, _("Normal"),
                                bind (mem_fun (*this, &AudioTimeAxisView::set_track_mode), ARDOUR::Normal)));
        normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
+
+       items.push_back (RadioMenuElem (mode_group, _("Non Overlapping"),
+                               bind (mem_fun (*this, &AudioTimeAxisView::set_track_mode), ARDOUR::NonLayered)));
+       non_layered_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
+
        items.push_back (RadioMenuElem (mode_group, _("Tape"),
                                bind (mem_fun (*this, &AudioTimeAxisView::set_track_mode), ARDOUR::Destructive)));
        destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
@@ -256,6 +262,9 @@ AudioTimeAxisView::build_mode_menu()
                case ARDOUR::Destructive:
                        destructive_track_mode_item->set_active ();
                        break;
+               case ARDOUR::NonLayered:
+                       non_layered_track_mode_item->set_active ();
+                       break;
                case ARDOUR::Normal:
                        normal_track_mode_item->set_active ();
                        break;
index 1c04c76504d72c604366cfe5dd2317c67b3252b2..82f63792fc63b1a8f801dd3bdef620c8184521ee 100644 (file)
@@ -1997,8 +1997,8 @@ public:
        void point_trim (GdkEvent*);
        void trim_motion_callback (ArdourCanvas::Item*, GdkEvent*);
        void single_contents_trim (RegionView&, nframes64_t, bool, bool, bool);
-       void single_start_trim (RegionView&, nframes64_t, bool, bool);
-       void single_end_trim (RegionView&, nframes64_t, bool, bool);
+       void single_start_trim (RegionView&, nframes64_t, bool, bool, bool);
+       void single_end_trim (RegionView&, nframes64_t, bool, bool, bool);
 
        void trim_finished_callback (ArdourCanvas::Item*, GdkEvent*);
        void thaw_region_after_trim (RegionView& rv);
@@ -2013,6 +2013,10 @@ public:
        void trim_region_to_punch ();
        void trim_region_to_location (const ARDOUR::Location&, const char* cmd);
 
+       void trim_to_region(bool forward);
+       void trim_region_to_previous_region_end();
+       void trim_region_to_next_region_start();
+
        bool show_gain_after_trim;
 
        /* Drag-n-Drop */
index 9606540b6e542d55ffb4aca9481a96f99bcf6846..f1c4e4b18470593e65d8e004803daab69bb57210 100644 (file)
@@ -386,6 +386,13 @@ Editor::register_actions ()
        ActionManager::session_sensitive_actions.push_back (act);
        ActionManager::region_selection_sensitive_actions.push_back (act);
 
+       act = ActionManager::register_action (editor_actions, "trim-to-previous-region", _("Trim to Previous"), mem_fun(*this, &Editor::trim_region_to_previous_region_end));
+       ActionManager::session_sensitive_actions.push_back (act);
+       ActionManager::region_selection_sensitive_actions.push_back (act);
+       act = ActionManager::register_action (editor_actions, "trim-to-next-region", _("Trim to Next"), mem_fun(*this, &Editor::trim_region_to_next_region_start));
+       ActionManager::session_sensitive_actions.push_back (act);
+       ActionManager::region_selection_sensitive_actions.push_back (act);
+
        act = ActionManager::register_action (editor_actions, "set-loop-from-edit-range", _("Set Loop from Edit Range"), bind (mem_fun(*this, &Editor::set_loop_from_edit_range), false));
        ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_action (editor_actions, "set-loop-from-region", _("Set Loop from Region"), bind (mem_fun(*this, &Editor::set_loop_from_region), false));
index 7db90c1ac7d699068d6fa8572ef1a827ab57327b..6cc92a2f744a7eee0e048db4d068197a6db8fa97 100644 (file)
@@ -4340,6 +4340,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                if (changed_tracks || drag_info.copy) {
 
                        boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
+                       
                        if (!to_playlist) {
                                ++i;
                                continue;
@@ -4350,6 +4351,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                        sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
                        
                        insert_result = modified_playlists.insert (to_playlist);
+                       
                        if (insert_result.second) {
                                session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
                        }
@@ -4380,11 +4382,13 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                        boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
 
                        insert_result = modified_playlists.insert (playlist);
+                       
                        if (insert_result.second) {
                                session->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
                        }
                        /* freeze to avoid lots of relayering in the case of a multi-region drag */
                        frozen_insert_result = frozen_playlists.insert(playlist);
+                       
                        if (frozen_insert_result.second) {
                                playlist->freeze();
                        }
@@ -4416,6 +4420,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                        /* remove the region from the old playlist */
 
                        insert_result = modified_playlists.insert (from_playlist);
+                       
                        if (insert_result.second) {
                                session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
                        }
@@ -4478,13 +4483,13 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
                        session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));      
                }
+
                commit_reversible_command ();
        }
 
        for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
                delete *x;
        }
-
 }
        
 void
@@ -4807,6 +4812,7 @@ Editor::cancel_selection ()
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                (*i)->hide_selection ();
        }
+
        selection->clear ();
        clicked_selection = 0;
 }      
@@ -5075,6 +5081,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 {
        RegionView* rv = clicked_regionview;
        nframes64_t frame_delta = 0;
+
        bool left_direction;
        bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
 
@@ -5129,11 +5136,14 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                        (*i)->region()->freeze ();
                
                        AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
-                       if (arv)
+
+                       if (arv){
                                arv->temporarily_hide_envelope ();
+                       }
 
                        boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
                        insert_result = motion_frozen_playlists.insert (pl);
+
                        if (insert_result.second) {
                                session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
                                pl->freeze();
@@ -5147,13 +5157,20 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                frame_delta = (drag_info.current_pointer_frame - drag_info.last_pointer_frame);
        }
 
+       bool non_overlap_trim = false;
+
+       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
+               non_overlap_trim = true;
+       }
+
        switch (trim_op) {              
        case StartTrim:
                if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region()->first_frame()/speed)) {
                        break;
                } else {
+
                        for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
-                               single_start_trim (**i, frame_delta, left_direction, obey_snap);
+                               single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
                        }
                        break;
                }
@@ -5162,8 +5179,9 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                if ((left_direction == true) && (drag_info.current_pointer_frame > (nframes64_t) (rv->region()->last_frame()/speed))) {
                        break;
                } else {
+
                        for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
-                               single_end_trim (**i, frame_delta, left_direction, obey_snap);
+                               single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
                        }
                        break;
                }
@@ -5242,7 +5260,7 @@ Editor::single_contents_trim (RegionView& rv, nframes64_t frame_delta, bool left
 }
 
 void
-Editor::single_start_trim (RegionView& rv, nframes64_t frame_delta, bool left_direction, bool obey_snap)
+Editor::single_start_trim (RegionView& rv, nframes64_t frame_delta, bool left_direction, bool obey_snap, bool no_overlap)
 {
        boost::shared_ptr<Region> region (rv.region()); 
 
@@ -5269,14 +5287,37 @@ Editor::single_start_trim (RegionView& rv, nframes64_t frame_delta, bool left_di
        if (obey_snap) {
                snap_to (new_bound, (left_direction ? 0 : 1));  
        }
+       
+       nframes64_t pre_trim_first_frame = region->first_frame();
 
        region->trim_front ((nframes64_t) (new_bound * speed), this);
+  
+       if (no_overlap) {
+               //Get the next region on the left of this region and shrink/expand it.
+               boost::shared_ptr<Playlist> playlist (region->playlist());
+               boost::shared_ptr<Region> region_left = playlist->find_next_region (pre_trim_first_frame, End, 0);
+               
+               bool regions_touching = false;
+
+               if (region_left != 0 && (pre_trim_first_frame == region_left->last_frame() + 1)){
+                   regions_touching = true;
+               }
+
+               //Only trim region on the left if the first frame has gone beyond the left region's last frame.
+               if (region_left != 0 && 
+                       (region_left->last_frame() > region->first_frame() || regions_touching)) 
+               {
+                       region_left->trim_end(region->first_frame(), this);
+               }
+       }
+
+       
 
        rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
 }
 
 void
-Editor::single_end_trim (RegionView& rv, nframes64_t frame_delta, bool left_direction, bool obey_snap)
+Editor::single_end_trim (RegionView& rv, nframes64_t frame_delta, bool left_direction, bool obey_snap, bool no_overlap)
 {
        boost::shared_ptr<Region> region (rv.region());
 
@@ -5293,7 +5334,7 @@ Editor::single_end_trim (RegionView& rv, nframes64_t frame_delta, bool left_dire
        if (tv && tv->is_track()) {
                speed = tv->get_diskstream()->speed();
        }
-       
+
        if (left_direction) {
                new_bound = (nframes64_t) ((region->last_frame() + 1)/speed) - frame_delta;
        } else {
@@ -5303,10 +5344,37 @@ Editor::single_end_trim (RegionView& rv, nframes64_t frame_delta, bool left_dire
        if (obey_snap) {
                snap_to (new_bound);
        }
+
+       nframes64_t pre_trim_last_frame = region->last_frame();
+
        region->trim_end ((nframes64_t) (new_bound * speed), this);
-       rv.region_changed (LengthChanged);
+
+       if (no_overlap) {
+               //Get the next region on the right of this region and shrink/expand it.
+               boost::shared_ptr<Playlist> playlist (region->playlist());
+               boost::shared_ptr<Region> region_right = playlist->find_next_region (pre_trim_last_frame, Start, 1);
+
+               bool regions_touching = false;
+
+               if (region_right != 0 && (pre_trim_last_frame == region_right->first_frame() - 1)){
+                   regions_touching = true;
+               }
+
+               //Only trim region on the right if the last frame has gone beyond the right region's first frame.
+               if (region_right != 0 &&
+                       (region_right->first_frame() < region->last_frame() || regions_touching)) 
+               {
+                       region_right->trim_front(region->last_frame() + 1, this);
+               }
+               
+               rv.region_changed (Change (LengthChanged|PositionChanged|StartChanged));
+       }
+       else {
+               rv.region_changed (LengthChanged);
+       }
 }
-       
+
+
 void
 Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
 {
@@ -5343,6 +5411,7 @@ void
 Editor::point_trim (GdkEvent* event)
 {
        RegionView* rv = clicked_regionview;
+
        nframes64_t new_bound = drag_info.current_pointer_frame;
 
        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
@@ -5356,25 +5425,29 @@ Editor::point_trim (GdkEvent* event)
                begin_reversible_command (_("Start point trim"));
 
                if (selection->selected (rv)) {
-
                        for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
                             i != selection->regions.by_layer().end(); ++i)
                        {
+                               if ( (*i) == NULL){
+                                   cerr << "region view contains null region" << endl;
+                               }
+
                                if (!(*i)->region()->locked()) {
                                        boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
                                        XMLNode &before = pl->get_state();
-                                       (*i)->region()->trim_front (new_bound, this);   
+
+                                       (*i)->region()->trim_front (new_bound, this);
+
                                        XMLNode &after = pl->get_state();
                                        session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
                                }
                        }
 
                } else {
-
                        if (!rv->region()->locked()) {
                                boost::shared_ptr<Playlist> pl = rv->region()->playlist();
                                XMLNode &before = pl->get_state();
-                               rv->region()->trim_front (new_bound, this);     
+                               rv->region()->trim_front (new_bound, this);
                                XMLNode &after = pl->get_state();
                                session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
                        }
index 1b5067e2ac1d1ccdd684a745f414f9940140b1ec..5826033072b8586c203d8c7171f4fd82f26b7300 100644 (file)
@@ -3476,6 +3476,49 @@ Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint poi
        session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
 }      
 
+void
+Editor::trim_region_front ()
+{
+       trim_region (true);
+}
+
+void
+Editor::trim_region_back ()
+{
+       trim_region (false);
+}
+
+void
+Editor::trim_region (bool front)
+{
+       nframes64_t where = get_preferred_edit_position();
+       RegionSelection rs;
+
+       get_regions_for_action (rs);
+
+       if (rs.empty()) {
+               return;
+       }
+
+       begin_reversible_command (front ? _("trim front") : _("trim back"));
+
+       for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
+               if (!(*i)->region()->locked()) {
+                       boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
+                       XMLNode &before = pl->get_state();
+                       if (front) {
+                               (*i)->region()->trim_front (where, this);       
+                       } else {
+                               (*i)->region()->trim_end (where, this); 
+                       }
+                       XMLNode &after = pl->get_state();
+                       session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
+               }
+       }
+
+       commit_reversible_command ();
+}
+
 /** Trim the end of the selected regions to the position of the edit cursor */
 void
 Editor::trim_region_to_loop ()
@@ -3622,6 +3665,85 @@ Editor::trim_region_from_edit_point ()
        commit_reversible_command ();
 }
 
+void
+Editor::trim_region_to_previous_region_end ()
+{
+       return trim_to_region(false);
+}
+
+void
+Editor::trim_region_to_next_region_start ()
+{
+       return trim_to_region(true);
+}
+
+void
+Editor::trim_to_region(bool forward)
+{
+       RegionSelection rs;
+
+       get_regions_for_action (rs);
+
+       begin_reversible_command (_("trim to region"));
+
+       boost::shared_ptr<Region> next_region;
+
+       for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
+
+               AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
+
+               if (!arv) {
+                       continue;
+               }
+
+               AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
+
+               if (!atav) {
+                       return;
+               }
+
+               float speed = 1.0;
+
+               if (atav->get_diskstream() != 0) {
+                       speed = atav->get_diskstream()->speed();
+               }
+
+               
+               boost::shared_ptr<Region> region = arv->region();
+               boost::shared_ptr<Playlist> playlist (region->playlist());
+               
+               XMLNode &before = playlist->get_state();
+
+               if(forward){
+
+                   next_region = playlist->find_next_region (region->first_frame(), Start, 1);
+
+                   if(!next_region){
+                       continue;
+                   }
+
+                   region->trim_end((nframes64_t) (next_region->first_frame() * speed), this);
+                   arv->region_changed (Change (LengthChanged));
+               }
+               else {
+
+                   next_region = playlist->find_next_region (region->first_frame(), Start, 0);
+
+                   if(!next_region){
+                       continue;
+                   }
+
+                   region->trim_front((nframes64_t) ((next_region->last_frame() + 1) * speed), this);              
+                   arv->region_changed (Change (LengthChanged|PositionChanged|StartChanged));
+               }
+
+               XMLNode &after = playlist->get_state();
+               session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+       }
+
+       commit_reversible_command ();
+}
+
 void
 Editor::unfreeze_route ()
 {
@@ -5207,49 +5329,6 @@ Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_ar
        }
 }
 
-void
-Editor::trim_region_front ()
-{
-       trim_region (true);
-}
-
-void
-Editor::trim_region_back ()
-{
-       trim_region (false);
-}
-
-void
-Editor::trim_region (bool front)
-{
-       nframes64_t where = get_preferred_edit_position();
-       RegionSelection rs;
-
-       get_regions_for_action (rs);
-
-       if (rs.empty()) {
-               return;
-       }
-
-       begin_reversible_command (front ? _("trim front") : _("trim back"));
-
-       for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
-               if (!(*i)->region()->locked()) {
-                       boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
-                       XMLNode &before = pl->get_state();
-                       if (front) {
-                               (*i)->region()->trim_front (where, this);       
-                       } else {
-                               (*i)->region()->trim_end (where, this); 
-                       }
-                       XMLNode &after = pl->get_state();
-                       session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
-               }
-       }
-
-       commit_reversible_command ();
-}
-
 struct EditorOrderRouteSorter {
     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
            /* use of ">" forces the correct sort order */
index a1f41adf6e51e0dad9183d5866ac919cbcf0cea8..2b622bda2822fc27665be00d7a07f519d83b6596 100644 (file)
@@ -128,6 +128,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
        no_redraw = false;
        destructive_track_mode_item = 0;
        normal_track_mode_item = 0;
+       non_layered_track_mode_item = 0;
 
        ignore_toggle = false;
 
@@ -165,8 +166,10 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
                /* use icon */
 
                rec_enable_button->remove ();
+
                switch (track()->mode()) {
                case ARDOUR::Normal:
+               case ARDOUR::NonLayered:
                        rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
                        break;
                case ARDOUR::Destructive:
@@ -554,10 +557,17 @@ RouteTimeAxisView::build_display_menu ()
                                        mem_fun (*this, &RouteTimeAxisView::set_track_mode),
                                        ARDOUR::Normal)));
                        normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
+
                        items.push_back (RadioMenuElem (mode_group, _("Tape mode"), bind (
                                        mem_fun (*this, &RouteTimeAxisView::set_track_mode),
                                        ARDOUR::Destructive)));
                        destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
+
+                       items.push_back (RadioMenuElem (mode_group, _("No layering mode"),
+                                                       bind (mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered)));
+                       non_layered_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
+
                        
                        switch (track()->mode()) {
                        case ARDOUR::Destructive:
@@ -566,6 +576,9 @@ RouteTimeAxisView::build_display_menu ()
                        case ARDOUR::Normal:
                                normal_track_mode_item->set_active ();
                                break;
+                       case ARDOUR::NonLayered:
+                               non_layered_track_mode_item->set_active ();
+                               break;
                        }
                }
 
@@ -597,9 +610,10 @@ RouteTimeAxisView::build_display_menu ()
        }
 }
 
-static bool __reset_item (RadioMenuItem* item)
+static bool __reset_item (RadioMenuItem* item, RadioMenuItem* item_2)
 {
        item->set_active ();
+       item_2->set_active ();
        return false;
 }
 
@@ -608,15 +622,23 @@ RouteTimeAxisView::set_track_mode (TrackMode mode)
 {
        RadioMenuItem* item;
        RadioMenuItem* other_item;
+       RadioMenuItem* other_item_2;
 
        switch (mode) {
        case ARDOUR::Normal:
                item = normal_track_mode_item;
-               other_item = destructive_track_mode_item;
+               other_item = non_layered_track_mode_item;
+               other_item_2 = destructive_track_mode_item;
+               break;
+       case ARDOUR::NonLayered:
+               item = non_layered_track_mode_item;
+               other_item = normal_track_mode_item;
+               other_item_2 = destructive_track_mode_item;
                break;
        case ARDOUR::Destructive:
                item = destructive_track_mode_item;
                other_item = normal_track_mode_item;
+               other_item_2 = non_layered_track_mode_item;
                break;
        default:
                fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", mode) << endmsg;
@@ -624,13 +646,13 @@ RouteTimeAxisView::set_track_mode (TrackMode mode)
                return;
        }
        
-       if (item && other_item && item->get_active () && track()->mode() != mode) {
-               _set_track_mode (track().get(), mode, other_item);
+       if (item && other_item && other_item_2 && item->get_active() && track()->mode() != mode) {
+               _set_track_mode (track().get(), mode, other_item, other_item_2);
        }
 }
 
 void
-RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem* reset_item)
+RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem* reset_item, RadioMenuItem* reset_item_2)
 {
        bool needs_bounce;
 
@@ -638,7 +660,7 @@ RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem*
 
                if (!needs_bounce) {
                        /* cannot be done */
-                       Glib::signal_idle().connect (bind (sigc::ptr_fun (__reset_item), reset_item));
+                       Glib::signal_idle().connect (bind (sigc::ptr_fun (__reset_item), reset_item, reset_item_2));
                        return;
                } else {
                        cerr << "would bounce this one\n";
@@ -649,7 +671,9 @@ RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem*
        track->set_mode (mode);
 
        rec_enable_button->remove ();
+
        switch (mode) {
+       case ARDOUR::NonLayered:
        case ARDOUR::Normal:
                rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
                break;
@@ -657,8 +681,8 @@ RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem*
                rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
                break;
        }
-       rec_enable_button->show_all ();
 
+       rec_enable_button->show_all ();
 }
 
 void
@@ -670,6 +694,9 @@ RouteTimeAxisView::track_mode_changed ()
        case ARDOUR::Normal:
                item = normal_track_mode_item;
                break;
+       case ARDOUR::NonLayered:
+               item = non_layered_track_mode_item;
+               break;
        case ARDOUR::Destructive:
                item = destructive_track_mode_item;
                break;
index cf1e86c0b43154f00889fc92c4194ac3a480daf8..9c386bafa3656dd394042015f96cb9aa0eb4b01d 100644 (file)
@@ -283,6 +283,7 @@ protected:
        Gtk::RadioMenuItem* align_existing_item;
        Gtk::RadioMenuItem* align_capture_item;
        Gtk::RadioMenuItem* normal_track_mode_item;
+       Gtk::RadioMenuItem* non_layered_track_mode_item;
        Gtk::RadioMenuItem* destructive_track_mode_item;
        Gtk::Menu*          playlist_menu;
        Gtk::Menu*          playlist_action_menu;
@@ -298,7 +299,7 @@ protected:
        ArdourCanvas::SimpleRect* timestretch_rect;
 
        void set_track_mode (ARDOUR::TrackMode);
-       void _set_track_mode (ARDOUR::Track* track, ARDOUR::TrackMode mode, Gtk::RadioMenuItem* reset_item);
+       void _set_track_mode (ARDOUR::Track* track, ARDOUR::TrackMode mode, Gtk::RadioMenuItem* reset_item, Gtk::RadioMenuItem* reset_item_2);
        void track_mode_changed ();
 
        list<ProcessorAutomationInfo*> processor_automation;
index 8d36427a0b0ce68de09fdf5260c33d15335de51e..27131fa3e37d928dd677e75f71493f35d5aef78d 100644 (file)
@@ -424,6 +424,8 @@ StreamView::update_rec_box ()
                double xend;
                
                switch (_trackview.track()->mode()) {
+               
+               case NonLayered:
                case Normal:
                        rect.length = at - rect.start;
                        xstart = _trackview.editor().frame_to_pixel (rect.start);
index 8acb3e280603a357448df4601bec9ec9c44710ba..4f22efd535f9c7504d67bcca1207b21d6953a69e 100644 (file)
@@ -78,6 +78,7 @@ class AudioDiskstream : public Diskstream
 
        void set_record_enabled (bool yn);
        int set_destructive (bool yn);
+       int set_non_layered (bool yn);
        bool can_become_destructive (bool& requires_bounce) const;
 
        float peak_power(uint32_t n = 0) { 
index 81985ff77acfc7a71dc26554c805ad8e4272e8a3..c91306d6dd1292e7dcb36cdf84f276826de73bf7 100644 (file)
@@ -172,6 +172,7 @@ CONFIG_VARIABLE (bool, default_narrow_ms, "default-narrow_ms", false)
 CONFIG_VARIABLE (bool, name_new_markers, "name-new-markers", false)
 CONFIG_VARIABLE (bool, rubberbanding_snaps_to_grid, "rubberbanding-snaps-to-grid", false)
 CONFIG_VARIABLE (long, font_scale, "font-scale", 102400)
+CONFIG_VARIABLE (std::string, default_session_parent_dir, "default-session-parent-dir", "~")
 
 /* denormal management */
 
index a835e4b57157f39280a7de130ced2527064e9124..a5a98338daefdb2902a0a3d3c41f044e9f3f1bdb 100644 (file)
@@ -64,7 +64,8 @@ class Diskstream : public SessionObject, public boost::noncopyable
        enum Flag {
                Recordable  = 0x1,
                Hidden      = 0x2,
-               Destructive = 0x4
+               Destructive = 0x4,
+               NonLayered   = 0x8
        };
 
        Diskstream (Session &, const string& name, Flag f = Recordable);
@@ -94,10 +95,12 @@ class Diskstream : public SessionObject, public boost::noncopyable
 
        bool destructive() const { return _flags & Destructive; }
        virtual int set_destructive (bool yn) { return -1; }
+       virtual int set_non_layered (bool yn) { return -1; }
        virtual bool can_become_destructive (bool& requires_bounce) const { return false; }
 
        bool           hidden()      const { return _flags & Hidden; }
        bool           recordable()  const { return _flags & Recordable; }
+       bool           non_layered()  const { return _flags & NonLayered; }
        bool           reversed()    const { return _actual_speed < 0.0f; }
        double         speed()       const { return _visible_speed; }
        
index a88687cbbbb81898d26006490711a1d52723bb2c..63edad8805a9c3102ab0770a3c0e7d4b6331a22d 100644 (file)
@@ -91,7 +91,7 @@ class Playlist : public SessionObject,
 
        /* Editing operations */
 
-       void add_region (boost::shared_ptr<Region>, nframes_t position, float times = 1);
+       void add_region (boost::shared_ptr<Region>, nframes_t position, float times = 1, bool auto_partition = false);
        void remove_region (boost::shared_ptr<Region>);
        void get_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
        void get_region_list_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
@@ -99,7 +99,7 @@ class Playlist : public SessionObject,
        void split_region (boost::shared_ptr<Region>, nframes_t position);
        void split (nframes64_t at);
        void shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue);
-       void partition (nframes_t start, nframes_t end, bool just_top_level);
+       void partition (nframes_t start, nframes_t end, bool cut = false);
        void duplicate (boost::shared_ptr<Region>, nframes_t position, float times);
        void nudge_after (nframes_t start, nframes_t distance, bool forwards);
        void shuffle (boost::shared_ptr<Region>, int dir);
@@ -187,7 +187,7 @@ class Playlist : public SessionObject,
        DataType        _type;
        mutable gint    block_notifications;
        mutable gint    ignore_state_changes;
-       mutable Glib::Mutex region_lock;
+       mutable Glib::RecMutex region_lock;
        std::set<boost::shared_ptr<Region> > pending_adds;
        std::set<boost::shared_ptr<Region> > pending_removes;
        RegionList       pending_bounds;
@@ -212,6 +212,7 @@ class Playlist : public SessionObject,
        PBD::ID         _orig_diskstream_id;
        uint64_t         layer_op_counter;
        nframes_t   freeze_length;
+       bool             auto_partition;
 
        void init (bool hide);
 
index b6b6321d4f0ee8d4f2ef0c5545b3494322ec71df..2ed5e0e36539068d29e04fe2a3a429f66ee958f3 100644 (file)
@@ -135,6 +135,7 @@ namespace ARDOUR {
 
        enum TrackMode {
                Normal,
+               NonLayered,
                Destructive
        };
 
index 4c36100c821f5c283e0e7756e27c53835678c3ca..94c52c5976557882e208f87fa53d22b695660800 100644 (file)
@@ -1687,7 +1687,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
                        _last_capture_regions.push_back (region);
                        
                        i_am_the_modifier++;
-                       _playlist->add_region (region, (*ci)->start);
+                       _playlist->add_region (region, (*ci)->start, 1, non_layered());
                        i_am_the_modifier--;
                        
                        buffer_position += (*ci)->frames;
@@ -2406,6 +2406,21 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
        return 0;
 }
 
+int
+AudioDiskstream::set_non_layered (bool yn)
+{
+       if (yn != non_layered()) {
+               
+               if (yn) {
+                       _flags = Flag (_flags | NonLayered);
+               } else {
+                       _flags = Flag (_flags & ~NonLayered);
+               }
+       }
+
+       return 0;
+}
+
 int
 AudioDiskstream::set_destructive (bool yn)
 {
index 4953cdf70278d783eae335d0ee49b4afe44d3adf..ef2cf281efcbfe1eda1d0485d6e08bc545edf9c7 100644 (file)
@@ -147,7 +147,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
           its OK to block (for short intervals).
        */
 
-       Glib::Mutex::Lock rm (region_lock);
+       Glib::RecMutex::Lock rm (region_lock);
 
        end =  start + cnt - 1;
        read_frames = 0;
index 8f37ea22393e0dee116b3dd86f99c5459dff56b9..25161ea249f49edd7d07ded6cff3d4d22482028a 100644 (file)
@@ -77,7 +77,10 @@ AudioTrack::use_new_diskstream ()
 
        if (_mode == Destructive) {
                dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Destructive);
+       } else if (_mode == NonLayered){
+               dflags = AudioDiskstream::Flag(dflags | AudioDiskstream::NonLayered);
        }
+    
 
        boost::shared_ptr<AudioDiskstream> ds (new AudioDiskstream (_session, name(), dflags));
        
@@ -94,7 +97,8 @@ AudioTrack::set_mode (TrackMode m)
                if (_diskstream->set_destructive (m == Destructive)) {
                        return -1;
                }
-
+               
+               _diskstream->set_non_layered (m == NonLayered);
                _mode = m;
                
                TrackModeChanged (); /* EMIT SIGNAL */
@@ -107,6 +111,7 @@ bool
 AudioTrack::can_use_mode (TrackMode m, bool& bounce_required)
 {
        switch (m) {
+       case NonLayered:
        case Normal:
                bounce_required = false;
                return true;
@@ -177,6 +182,7 @@ AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src)
        _diskstream = ds;
        _diskstream->set_io (*this);
        _diskstream->set_destructive (_mode == Destructive);
+       _diskstream->set_non_layered (_mode == NonLayered);
 
        if (audio_diskstream()->deprecated_io_node) {
 
index bf8facd1a47dc760fd38dd64afebbf8774797d0f..611ebddb59b7a006db5574681879d5fb8c63959f 100644 (file)
@@ -129,7 +129,8 @@ Configuration::load_state ()
                        "ardour.rc", user_rc_file))
        {
                XMLTree tree;
-               
+               found = true;
+
                string rcfile = user_rc_file.to_string();
 
                /* stupid XML parser hates empty files */
index c61f38c9223c618221065642f838639feb63c26a..841b2ad1858725e3d2ba6cd58efa8f2b7e8f2570 100644 (file)
@@ -152,6 +152,7 @@ setup_enum_writer ()
        REGISTER (_MeterPoint);
 
        REGISTER_ENUM (Normal);
+       REGISTER_ENUM (NonLayered);
        REGISTER_ENUM (Destructive);
        REGISTER (_TrackMode);
 
index 0e4c65ce3f0a3f83fdd4dd52079b8733e82bd2fc..bb3603b8a82551244bd3109dff8a28c97a843194 100644 (file)
@@ -130,7 +130,7 @@ MidiPlaylist::read (MidiRingBuffer<nframes_t>& dst, nframes_t start, nframes_t d
           its OK to block (for short intervals).
        */
 
-       Glib::Mutex::Lock rm (region_lock);
+       Glib::RecMutex::Lock rm (region_lock);
 
        nframes_t end = start + dur - 1;
 
@@ -271,7 +271,7 @@ MidiPlaylist::contained_automation()
           its OK to block (for short intervals).
        */
 
-       Glib::Mutex::Lock rm (region_lock);
+       Glib::RecMutex::Lock rm (region_lock);
 
        set<Evoral::Parameter> ret;
 
index f34e47b9dafc8c00367324fa182a3a0768d21223..a4a0a62e981d9916fecb047bcd02aeea77778a63 100644 (file)
@@ -474,7 +474,7 @@ Playlist::flush_notifications ()
  *************************************************************/
 
 void
-Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times) 
+Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition
 {
        RegionLock rlock (this);
        times = fabs (times);
@@ -482,6 +482,10 @@ Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, floa
        int itimes = (int) floor (times);
 
        nframes_t pos = position;
+
+       if(times == 1 && auto_partition){
+               partition(pos, (nframes_t) (pos + region->length()), true);
+       }
        
        if (itimes >= 1) {
                add_region_internal (region, pos);
@@ -510,7 +514,6 @@ Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, floa
                add_region_internal (sub, pos);
        }
 
-
        possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
 }
 
@@ -529,8 +532,9 @@ Playlist::set_region_ownership ()
 bool
 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
 {
-       if (region->data_type() != _type)
+       if (region->data_type() != _type){
                return false;
+       }
 
        RegionSortByPosition cmp;
        nframes_t old_length = 0;
@@ -674,11 +678,11 @@ Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, v
 }
 
 void
-Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
+Playlist::partition (nframes_t start, nframes_t end, bool cut)
 {
        RegionList thawlist;
 
-       partition_internal (start, end, false, thawlist);
+       partition_internal (start, end, cut, thawlist);
 
        for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
                (*i)->thaw ("separation");
@@ -692,6 +696,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
 
        {
                RegionLock rlock (this);
+
                boost::shared_ptr<Region> region;
                boost::shared_ptr<Region> current;
                string new_name;
@@ -708,16 +713,18 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                RegionList copy = regions;
                
                for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
-                       
+
                        tmp = i;
                        ++tmp;
                        
                        current = *i;
 
                        if (current->first_frame() >= start && current->last_frame() < end) {
+
                                if (cutting) {
                                        remove_region_internal (current);
                                }
+
                                continue;
                        }
                        
@@ -740,7 +747,6 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                        pos4 = current->last_frame();
                        
                        if (overlap == OverlapInternal) {
-                       
                                /* split: we need 3 new regions, the front, middle and end.
                                   cut:   we need 2 regions, the front and end.
                                */
@@ -757,7 +763,6 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                */
 
                                if (!cutting) {
-                               
                                        /* "middle" ++++++ */
                                        
                                        _session.region_name (new_name, current->name(), false);
@@ -772,7 +777,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                _session.region_name (new_name, current->name(), false);
                                region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name, 
                                                                regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
-                               
+
                                add_region_internal (region, end);
                                new_regions.push_back (region);
                                
@@ -781,9 +786,9 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                current->freeze ();
                                thawlist.push_back (current);
                                current->trim_end (pos2, this);
-                               
+
                        } else if (overlap == OverlapEnd) {
-                               
+
                                /*
                                                              start           end
                                    ---------------*************************------------
@@ -795,12 +800,13 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                */
                                
                                if (!cutting) {
-                                       
+
                                        /* end +++++ */
                                        
                                        _session.region_name (new_name, current->name(), false);
                                        region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
                                                                        Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
+
                                        add_region_internal (region, start);
                                        new_regions.push_back (region);
                                }
@@ -810,9 +816,9 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                current->freeze ();
                                thawlist.push_back (current);
                                current->trim_end (pos2, this);
-                               
+
                        } else if (overlap == OverlapStart) {
-                               
+
                                /* split: we need 2 regions: the front and the end.
                                   cut: just trim current to skip the cut area
                                */
@@ -830,11 +836,11 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                */
 
                                if (!cutting) {
-                               
                                        /* front **** */
                                        _session.region_name (new_name, current->name(), false);
                                        region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
                                                                        regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
+
                                        add_region_internal (region, pos1);
                                        new_regions.push_back (region);
                                } 
@@ -844,9 +850,8 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                current->freeze ();
                                thawlist.push_back (current);
                                current->trim_front (pos3, this);
-                               
                        } else if (overlap == OverlapExternal) {
-                               
+
                                /* split: no split required.
                                   cut: remove the region.
                                */
@@ -866,10 +871,11 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                if (cutting) {
                                        remove_region_internal (current);
                                }
+
                                new_regions.push_back (current);
                        }
                }
-               
+
                in_partition = false;
        }
 
@@ -1591,9 +1597,12 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
        boost::shared_ptr<Region> ret;
        nframes_t closest = max_frames;
 
+       bool end_iter = false;
 
        for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
 
+               if(end_iter) break;
+
                nframes_t distance;
                boost::shared_ptr<Region> r = (*i);
                nframes_t pos = 0;
@@ -1614,23 +1623,28 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
                switch (dir) {
                case 1: /* forwards */
 
-                       if (pos >= frame) {
+                       if (pos > frame) {
                                if ((distance = pos - frame) < closest) {
                                        closest = distance;
                                        ret = r;
+                                       end_iter = true;
                                }
                        }
 
                        break;
 
                default: /* backwards */
-
-                       if (pos <= frame) {
+                       
+                       if (pos < frame) {
                                if ((distance = frame - pos) < closest) {
                                        closest = distance;
                                        ret = r;
                                }
                        }
+                       else {
+                               end_iter = true;
+                       }
+
                        break;
                }
        }
@@ -1710,6 +1724,7 @@ Playlist::find_next_region_boundary (nframes64_t frame, int dir)
 
 
 
+
 void
 Playlist::mark_session_dirty ()
 {
diff --git a/wscript b/wscript
index f8001ca58ec678605896f2e0ef9f6b47c67ccab5..e42dbbea311abab4eec3d83a06326eecdf183856 100644 (file)
--- a/wscript
+++ b/wscript
@@ -110,7 +110,7 @@ def set_options(opt):
        opt.add_option('--wiimote', action='store_true', default=False, dest='wiimote',
                        help='Build the wiimote control surface')
        opt.add_option('--windows-key', type='string', dest='windows_key',
-                       help='Set X Modifier (Mod1,Mod2,Mod3,Mod4,Mod5) for "Windows" key [Default: Mod4]')
+                       help='Set X Modifier (Mod1,Mod2,Mod3,Mod4,Mod5) for "Windows" key [Default: Mod4]', default='Mod4><Super')
        for i in children:
                opt.sub_options(i)