new trim cursors from chrisg, fix up hotspots for said cursors, make Editor cursors...
[ardour.git] / gtk2_ardour / editor.cc
index 57f0b1f42d40081df3b05ad793b622ceee0c3349..98287553bae85ad3e09d20c94d650dc08df15b50 100644 (file)
@@ -209,6 +209,8 @@ static const gchar *_rb_opt_strings[] = {
 Gdk::Cursor* Editor::cross_hair_cursor = 0;
 Gdk::Cursor* Editor::selector_cursor = 0;
 Gdk::Cursor* Editor::trimmer_cursor = 0;
+Gdk::Cursor* Editor::left_side_trim_cursor = 0;
+Gdk::Cursor* Editor::right_side_trim_cursor = 0;
 Gdk::Cursor* Editor::grabber_cursor = 0;
 Gdk::Cursor* Editor::grabber_edit_point_cursor = 0;
 Gdk::Cursor* Editor::zoom_cursor = 0;
@@ -399,6 +401,8 @@ Editor::Editor ()
 
        frames_per_unit = 2048; /* too early to use reset_zoom () */
 
+       _scroll_callbacks = 0;
+
        zoom_focus = ZoomFocusLeft;
        set_zoom_focus (ZoomFocusLeft);
        zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
@@ -574,27 +578,32 @@ Editor::Editor ()
        the_notebook.show_all ();
        
        post_maximal_editor_width = 0;
-       post_maximal_pane_position = 0;
+       post_maximal_horizontal_pane_position = 0;
+       post_maximal_editor_height = 0;
+       post_maximal_vertical_pane_position = 0;
 
-       VPaned *editor_summary_pane = manage(new VPaned());
-       editor_summary_pane->pack1(edit_packer);
+       editor_summary_pane.pack1(edit_packer);
 
        Button* summary_arrows_left_left = manage (new Button);
        summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
-       summary_arrows_left_left->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left));
+       summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
+       summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
        Button* summary_arrows_left_right = manage (new Button);
        summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
-       summary_arrows_left_right->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right));
+       summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
+       summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
        VBox* summary_arrows_left = manage (new VBox);
        summary_arrows_left->pack_start (*summary_arrows_left_left);
        summary_arrows_left->pack_start (*summary_arrows_left_right);
 
        Button* summary_arrows_right_left = manage (new Button);
        summary_arrows_right_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
-       summary_arrows_right_left->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left));
+       summary_arrows_right_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
+       summary_arrows_right_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
        Button* summary_arrows_right_right = manage (new Button);
        summary_arrows_right_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
-       summary_arrows_right_right->signal_clicked().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right));
+       summary_arrows_right_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
+       summary_arrows_right_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
        VBox* summary_arrows_right = manage (new VBox);
        summary_arrows_right->pack_start (*summary_arrows_right_left);
        summary_arrows_right->pack_start (*summary_arrows_right_right);
@@ -608,11 +617,15 @@ Editor::Editor ()
        _summary_hbox.pack_start (*summary_frame, true, true);
        _summary_hbox.pack_start (*summary_arrows_right, false, false);
        
-       editor_summary_pane->pack2 (_summary_hbox);
+       editor_summary_pane.pack2 (_summary_hbox);
 
-       edit_pane.pack1 (*editor_summary_pane, true, true);
+       edit_pane.pack1 (editor_summary_pane, true, true);
        edit_pane.pack2 (the_notebook, false, true);
 
+       editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
+
+       /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
+
        edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
 #ifdef GTKOSX
         Glib::PropertyProxy<int> proxy = edit_pane.property_position();
@@ -1229,6 +1242,17 @@ Editor::build_cursors ()
 
        cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
        trimmer_cursor =  new Gdk::Cursor (SB_H_DOUBLE_ARROW);
+
+       {
+               Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_left_cursor"));
+               left_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 5, 11);
+       }
+
+       {
+               Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_right_cursor"));
+               right_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 23, 11);
+       }
+
        selector_cursor = new Gdk::Cursor (XTERM);
        time_fx_cursor = new Gdk::Cursor (SIZING);
        wait_cursor = new Gdk::Cursor  (WATCH);
@@ -1323,6 +1347,8 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
        case RegionItem:
        case RegionViewName:
        case RegionViewNameHighlight:
+       case LeftFrameHandle:
+       case RightFrameHandle:
                if (with_selection) {
                        build_menu_function = &Editor::build_track_selection_context_menu;
                } else {
@@ -1364,6 +1390,8 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
        case RegionItem:
        case RegionViewName:
        case RegionViewNameHighlight:
+        case LeftFrameHandle:
+        case RightFrameHandle:
                if (!with_selection) {
                        if (region_edit_menu_split_item) {
                                if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
@@ -1925,7 +1953,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
        edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
        edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
        edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
-       edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_range)));
+       edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
 }
 
 
@@ -2406,10 +2434,6 @@ Editor::set_state (const XMLNode& node, int /*version*/)
                the_notebook.set_current_page (atoi (prop->value ()));
        }
 
-       if ((prop = node.property (X_("editor-pane-position")))) {
-               edit_pane.set_position (atoi (prop->value ()));
-       }
-
        return 0;
 }
 
@@ -2445,7 +2469,9 @@ Editor::get_state ()
                snprintf(buf, sizeof(buf), "%d", yoff);
                geometry->add_property("y-off", string(buf));
                snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
-               geometry->add_property("edit_pane_pos", string(buf));
+               geometry->add_property("edit-horizontal-pane-pos", string(buf));
+               snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
+               geometry->add_property("edit-vertical-pane-pos", string(buf));
 
                node->add_child_nocopy (*geometry);
        }
@@ -2494,9 +2520,6 @@ Editor::get_state ()
        snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ());
        node->add_property (X_("editor-list-page"), buf);
 
-       snprintf (buf, sizeof (buf), "%d", edit_pane.get_position ());
-       node->add_property (X_("editor-pane-position"), buf);
-
        return *node;
 }
 
@@ -3669,7 +3692,14 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
        char buf[32];
        XMLNode* node = ARDOUR_UI::instance()->editor_settings();
        int width, height;
-       static int32_t done;
+
+       enum Pane {
+               Horizontal = 0x1,
+               Vertical = 0x2
+       };
+
+       static Pane done;
+       
        XMLNode* geometry;
 
        width = default_width;
@@ -3677,15 +3707,11 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 
        if ((geometry = find_named_node (*node, "geometry")) != 0) {
 
-               if ((prop = geometry->property ("x_size")) == 0) {
-                       prop = geometry->property ("x-size");
-               }
+               prop = geometry->property ("x-size");
                if (prop) {
                        width = atoi (prop->value());
                }
-               if ((prop = geometry->property ("y_size")) == 0) {
-                       prop = geometry->property ("y-size");
-               }
+               prop = geometry->property ("y-size");
                if (prop) {
                        height = atoi (prop->value());
                }
@@ -3693,11 +3719,11 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 
        if (which == static_cast<Paned*> (&edit_pane)) {
 
-               if (done) {
+               if (done & Horizontal) {
                        return;
                }
 
-               if (!geometry || (prop = geometry->property ("edit-pane-pos")) == 0) {
+               if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
                        /* initial allocation is 90% to canvas, 10% to notebook */
                        pos = (int) floor (alloc.get_width() * 0.90f);
                        snprintf (buf, sizeof(buf), "%d", pos);
@@ -3705,10 +3731,33 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
                        pos = atoi (prop->value());
                }
 
-               if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
+               if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
                        edit_pane.set_position (pos);
-                       pre_maximal_pane_position = pos;
+                       pre_maximal_horizontal_pane_position = pos;
+               }
+
+               done = (Pane) (done | Horizontal);
+               
+       } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
+
+               if (done & Vertical) {
+                       return;
                }
+
+               if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
+                       /* initial allocation is 90% to canvas, 10% to summary */
+                       pos = (int) floor (alloc.get_height() * 0.90f);
+                       snprintf (buf, sizeof(buf), "%d", pos);
+               } else {
+                       pos = atoi (prop->value());
+               }
+
+               if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
+                       editor_summary_pane.set_position (pos);
+                       pre_maximal_vertical_pane_position = pos;
+               }
+
+               done = (Pane) (done | Vertical);
        }
 }
 
@@ -4053,39 +4102,58 @@ Editor::maximise_editing_space ()
        _mouse_mode_tearoff->set_visible (false);
        _tools_tearoff->set_visible (false);
 
-       pre_maximal_pane_position = edit_pane.get_position();
-       pre_maximal_editor_width = this->get_width();
+       pre_maximal_horizontal_pane_position = edit_pane.get_position ();
+       pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
+       pre_maximal_editor_width = this->get_width ();
+       pre_maximal_editor_height = this->get_height ();
 
-       if(post_maximal_pane_position == 0) {
-               post_maximal_pane_position = edit_pane.get_width();
+       if (post_maximal_horizontal_pane_position == 0) {
+               post_maximal_horizontal_pane_position = edit_pane.get_width();
        }
 
-       fullscreen();
+       if (post_maximal_vertical_pane_position == 0) {
+               post_maximal_vertical_pane_position = editor_summary_pane.get_height();
+       }
+       
+       fullscreen ();
 
-       if(post_maximal_editor_width) {
-               edit_pane.set_position (post_maximal_pane_position -
+       if (post_maximal_editor_width) {
+               edit_pane.set_position (post_maximal_horizontal_pane_position -
                        abs(post_maximal_editor_width - pre_maximal_editor_width));
        } else {
-               edit_pane.set_position (post_maximal_pane_position);
+               edit_pane.set_position (post_maximal_horizontal_pane_position);
+       }
+
+       if (post_maximal_editor_height) {
+               editor_summary_pane.set_position (post_maximal_vertical_pane_position -
+                       abs(post_maximal_editor_height - pre_maximal_editor_height));
+       } else {
+               editor_summary_pane.set_position (post_maximal_vertical_pane_position);
        }
 }
 
 void
 Editor::restore_editing_space ()
 {
-       // user changed width of pane during fullscreen
+       // user changed width/height of panes during fullscreen
 
-       if(post_maximal_pane_position != edit_pane.get_position()) {
-               post_maximal_pane_position = edit_pane.get_position();
+       if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
+               post_maximal_horizontal_pane_position = edit_pane.get_position();
        }
 
+       if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
+               post_maximal_vertical_pane_position = editor_summary_pane.get_position();
+       }
+       
        unfullscreen();
 
        _mouse_mode_tearoff->set_visible (true);
        _tools_tearoff->set_visible (true);
        post_maximal_editor_width = this->get_width();
+       post_maximal_editor_height = this->get_height();
 
-       edit_pane.set_position (pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
+       edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
+       editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
 }
 
 /**
@@ -5104,21 +5172,63 @@ Editor::check_step_edit ()
        return true; // do it again, till we stop
 }
 
-void
-Editor::horizontal_scroll_left ()
+bool
+Editor::horizontal_scroll_left_press ()
 {
+       ++_scroll_callbacks;
+       
+       if (_scroll_connection.connected() && _scroll_callbacks < 5) {
+               /* delay the first auto-repeat */
+               return true;
+       }
+               
        double x = leftmost_position() - current_page_frames() / 5;
        if (x < 0) {
                x = 0;
        }
        
        reset_x_origin (x);
+
+       /* do hacky auto-repeat */
+       if (!_scroll_connection.connected ()) {
+               _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press), 100);
+               _scroll_callbacks = 0;
+       }
+
+       return true;
 }
 
 void
-Editor::horizontal_scroll_right ()
+Editor::horizontal_scroll_left_release ()
 {
+       _scroll_connection.disconnect ();
+}
+
+bool
+Editor::horizontal_scroll_right_press ()
+{
+       ++_scroll_callbacks;
+       
+       if (_scroll_connection.connected() && _scroll_callbacks < 5) {
+               /* delay the first auto-repeat */
+               return true;
+       }
+
        reset_x_origin (leftmost_position() + current_page_frames() / 5);
+
+       /* do hacky auto-repeat */
+       if (!_scroll_connection.connected ()) {
+               _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press), 100);
+               _scroll_callbacks = 0;
+       }
+
+       return true;
+}
+
+void
+Editor::horizontal_scroll_right_release ()
+{
+       _scroll_connection.disconnect ();
 }
 
 /** Queue a change for the Editor viewport x origin to follow the playhead */