diff --git a/gtk2_ardour/icons/horizontal_zoom_fader_face.png b/gtk2_ardour/icons/horizontal_zoom_fader_face.png new file mode 100644 index 0000000000..37e503c071 Binary files /dev/null and b/gtk2_ardour/icons/horizontal_zoom_fader_face.png differ diff --git a/gtk2_ardour/icons/tool_waveform_zoom.png b/gtk2_ardour/icons/tool_waveform_zoom.png index 464a765d46..a0b8345aa0 100644 Binary files a/gtk2_ardour/icons/tool_waveform_zoom.png and b/gtk2_ardour/icons/tool_waveform_zoom.png differ diff --git a/gtk2_ardour/icons/tool_waveform_zoom_active.png b/gtk2_ardour/icons/tool_waveform_zoom_active.png index 7fa207886e..5160bd0bb3 100644 Binary files a/gtk2_ardour/icons/tool_waveform_zoom_active.png and b/gtk2_ardour/icons/tool_waveform_zoom_active.png differ diff --git a/gtk2_ardour/icons/tool_waveform_zoom_prelight.png b/gtk2_ardour/icons/tool_waveform_zoom_prelight.png index 5e1b5d83a2..a216e71967 100644 Binary files a/gtk2_ardour/icons/tool_waveform_zoom_prelight.png and b/gtk2_ardour/icons/tool_waveform_zoom_prelight.png differ diff --git a/gtk2_ardour/icons/zoom_fader_face.png b/gtk2_ardour/icons/vertical_zoom_fader_face.png similarity index 70% rename from gtk2_ardour/icons/zoom_fader_face.png rename to gtk2_ardour/icons/vertical_zoom_fader_face.png index c7785f656b..257acac33e 100644 Binary files a/gtk2_ardour/icons/zoom_fader_face.png and b/gtk2_ardour/icons/vertical_zoom_fader_face.png differ diff --git a/gtk2_ardour/ui/editor_window.xml b/gtk2_ardour/ui/editor_window.xml index 98816f2664..c5cbe05b57 100644 --- a/gtk2_ardour/ui/editor_window.xml +++ b/gtk2_ardour/ui/editor_window.xml @@ -123,6 +123,23 @@ activeicon="tool_zoom_active" prelighticon="tool_zoom_prelight"/> + + + - diff --git a/gtk2_ardour/waves_ui.cc b/gtk2_ardour/waves_ui.cc index 2d9dc4e03e..89c1d095e8 100644 --- a/gtk2_ardour/waves_ui.cc +++ b/gtk2_ardour/waves_ui.cc @@ -88,21 +88,24 @@ WavesUI::create_widget (const XMLNode& definition, const XMLNodeMap& styles, Wid dbg_msg("Fader's handlesource NOT SPECIFIED!"); throw std::exception(); } + std::string active_handle_image = xml_property (definition, "activehandlesource", styles, handle_image); + if (handle_image.empty()) { + dbg_msg("Fader's handlesource NOT SPECIFIED!"); + throw std::exception(); + } std::string adjustment_id = xml_property (definition, "adjustment", styles, ""); if (adjustment_id.empty()) { dbg_msg("Fader's adjustment_id NOT SPECIFIED!"); throw std::exception(); } + int minposx = xml_property (definition, "minposx", styles, -1); + int minposy = xml_property (definition, "minposy", styles, -1); + int maxposx = xml_property (definition, "maxposx", styles, minposx); + int maxposy = xml_property (definition, "maxposy", styles, minposy); Gtk::Adjustment& adjustment = named_widgets.get_adjustment(adjustment_id.c_str()); - child = manage (new Gtkmm2ext::Fader(adjustment, - face_image, - handle_image, - xml_property (definition, "minposx", styles, -1), - xml_property (definition, "minposy", styles, -1), - xml_property (definition, "maxposx", styles, -1), - xml_property (definition, "maxposy", styles, -1))); + child = manage (new Gtkmm2ext::Fader(adjustment, face_image, handle_image, active_handle_image, minposx, minposy, maxposx, maxposy)); } else if (widget_type == "ADJUSTMENT") { - dbg_msg("Creating ADJUSTMENT"); + //dbg_msg("Creating ADJUSTMENT"); double min_value = xml_property (definition, "minvalue", styles, 0.0); double max_value = xml_property (definition, "maxvalue", styles, 100.0); double initial_value = xml_property (definition, "initialvalue", styles, min_value); diff --git a/libs/gtkmm2ext/fader.cc b/libs/gtkmm2ext/fader.cc index 3b58102f0d..83241cae69 100755 --- a/libs/gtkmm2ext/fader.cc +++ b/libs/gtkmm2ext/fader.cc @@ -40,9 +40,33 @@ using namespace std; #define CORNER_OFFSET 1 #define FADER_RESERVE 5 + +static void get_closest_point_on_line(double xa, double ya, double xb, double yb, double xp, double yp, double& xl, double& yl ) +{ + // Finding the vector from A to B + // This step can be combined with the next + double a_to_b_x = xb - xa; + double a_to_b_y = yb - yb; + + // The vector perpendicular to a_to_b; + // This step can also be combined with the next + double perpendicular_x = -a_to_b_y; + double perpendicular_y = a_to_b_x; + + // Finding Q, the point "in the right direction" + // If you want a mess, you can also combine this + // with the next step. + double xq = xp + perpendicular_x; + double yq = yp + perpendicular_y; + + xl = ((xa*yb - ya*xb)*(xp - xq) - (xa-xb)*(xp*yq - yp*xq)) / ((xa - xb)*(yp-yq) - (ya - yb)*(yp-yq)); + yl = ((xa*yb - ya*xb)*(yp - yq) - (ya-yb)*(xp*yq - yp*xq)) / ((xa - xb)*(yp-yq) - (ya - yb)*(yp-yq)); +} + Fader::Fader (Gtk::Adjustment& adj, const std::string& face_image_file, const std::string& handle_image_file, + const std::string& active_handle_image_file, int min_pos_x, int min_pos_y, int max_pos_x, @@ -53,6 +77,7 @@ Fader::Fader (Gtk::Adjustment& adj, , _max_pos_x (max_pos_x) , _max_pos_y (max_pos_y) , _default_value (adjustment.get_value()) + , _dragging (false) { PBD::Searchpath spath(ARDOUR::ardour_data_search_path()); @@ -71,6 +96,11 @@ Fader::Fader (Gtk::Adjustment& adj, } else { throw failed_constructor(); } + if (PBD::find_file_in_search_path (spath, active_handle_image_file, data_file_path)) { + _active_handle_pixbuf = Gdk::Pixbuf::create_from_file (data_file_path); + } else { + throw failed_constructor(); + } update_unity_position (); @@ -98,10 +128,17 @@ Fader::on_expose_event (GdkEventExpose* ev) get_handle_position (_last_drawn_x, _last_drawn_y); cairo_rectangle (cr, 0, 0, get_width(), get_height()); - gdk_cairo_set_source_pixbuf (cr, - _handle_pixbuf->gobj(), - _last_drawn_x - _handle_pixbuf->get_width()/2.0, - _last_drawn_y - _handle_pixbuf->get_height()/2.0); + if (_dragging) { + gdk_cairo_set_source_pixbuf (cr, + _active_handle_pixbuf->gobj(), + _last_drawn_x - _active_handle_pixbuf->get_width()/2.0, + _last_drawn_y - _active_handle_pixbuf->get_height()/2.0); + } else { + gdk_cairo_set_source_pixbuf (cr, + _handle_pixbuf->gobj(), + _last_drawn_x - _handle_pixbuf->get_width()/2.0, + _last_drawn_y - _handle_pixbuf->get_height()/2.0); + } cairo_fill (cr); return true; @@ -132,11 +169,35 @@ Fader::on_button_press_event (GdkEventButton* ev) return false; } + double hx; + double hy; + get_handle_position (hx, hy); + + double hw = _handle_pixbuf->get_width(); + double hh = _handle_pixbuf->get_height(); + + if ((ev->x < (hx - hw/2)) || (ev->x > (hx + hw/2)) || (ev->y < (hy - hh/2)) || (ev->y > (hy + hh/2))) { + return false; + } + + double ev_pos_x; + double ev_pos_y; + + get_closest_point_on_line(_min_pos_x, _min_pos_y, + _max_pos_x, _max_pos_y, + ev->x, ev->y, + ev_pos_x, ev_pos_y ); + _grab_loc_x = ev_pos_x; + _grab_loc_y = ev_pos_y; + add_modal_grab (); - _grab_start_x = _grab_loc_x = ev->x; - _grab_start_y = _grab_loc_y = ev->y; + + _grab_start_x = _grab_loc_x = ev_pos_x; + _grab_start_y = _grab_loc_y = ev_pos_y; + _grab_window = ev->window; _dragging = true; + gdk_pointer_grab(ev->window,false, GdkEventMask (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK), NULL, @@ -146,6 +207,8 @@ Fader::on_button_press_event (GdkEventButton* ev) if (ev->button == 2) { set_adjustment_from_event (ev); } + + queue_draw(); return true; } @@ -153,6 +216,62 @@ Fader::on_button_press_event (GdkEventButton* ev) bool Fader::on_button_release_event (GdkEventButton* ev) { + if (_dragging) { //temp + remove_modal_grab(); + _dragging = false; + gdk_pointer_ungrab (GDK_CURRENT_TIME); + queue_draw (); + } + /* + double const ev_pos_x = ev->x; + double const ev_posyx = ev->y; + + switch (ev->button) { + case 1: + if (dragging) { + remove_modal_grab(); + dragging = false; + gdk_pointer_ungrab (GDK_CURRENT_TIME); + + if (!_hovering) { + Keyboard::magic_widget_drop_focus(); + queue_draw (); + } + + if ((ev_pos_x == grab_start_x) && (ev_pos_y == grab_start_y)) { + + // no motion - just a click + if (ev->state & Keyboard::TertiaryModifier) { + adjustment.set_value (_default_value); + } else if (ev->state & Keyboard::GainFineScaleModifier) { + adjustment.set_value (adjustment.get_lower()); + } else if ((_orien == VERT && ev_pos < display_span()) || (_orien == HORIZ && ev_pos > display_span())) { + // above the current display height, remember X Window coords + adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment()); + } else { + adjustment.set_value (adjustment.get_value() - adjustment.get_step_increment()); + } + } + return true; + } + break; + + case 2: + if (dragging) { + remove_modal_grab(); + dragging = false; + set_adjustment_from_event (ev); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + return true; + } + break; + + default: + break; + } +*/ + return false; + /* double const ev_pos = (_orien == VERT) ? ev->y : ev->x; @@ -241,42 +360,40 @@ Fader::on_scroll_event (GdkEventScroll* ev) bool Fader::on_motion_notify_event (GdkEventMotion* ev) { - /* if (_dragging) { - double scale = 1.0; - double const ev_pos = (_orien == VERT) ? ev->y : ev->x; + double ev_pos_x; + double ev_pos_y; - if (ev->window != grab_window) { - grab_loc = ev_pos; - grab_window = ev->window; + get_closest_point_on_line(_min_pos_x, _min_pos_y, + _max_pos_x, _max_pos_y, + ev->x, ev->y, + ev_pos_x, ev_pos_y ); + + if (((_min_pos_x != _max_pos_x) && + ((ev_pos_x < _min_pos_x) && (ev_pos_x < _max_pos_x) || + (ev_pos_x > _max_pos_x) && (ev_pos_x > _min_pos_x))) || + ((_min_pos_x != _max_pos_x) && + ((ev_pos_y < _min_pos_x) && (ev_pos_y < _max_pos_y) || + (ev_pos_y > _max_pos_x) && (ev_pos_y > _min_pos_y)))) { + return true; + } + + _grab_loc_x = ev_pos_x; + _grab_loc_y = ev_pos_y; + + if (ev->window != _grab_window) { + _grab_window = ev->window; return true; } - if (ev->state & Keyboard::GainFineScaleModifier) { - if (ev->state & Keyboard::GainExtraFineScaleModifier) { - scale = 0.05; - } else { - scale = 0.1; - } - } + double const fract = sqrt((ev_pos_x - _min_pos_x) * (ev_pos_x - _min_pos_x) + + (ev_pos_y - _min_pos_y) * (ev_pos_y - _min_pos_y)) / + sqrt((_max_pos_x - _min_pos_x) * (_max_pos_x - _min_pos_x) + + (_max_pos_y - _min_pos_y) * (_max_pos_y - _min_pos_y)); - double const delta = ev_pos - grab_loc; - grab_loc = ev_pos; - - double fract = (delta / span); - - fract = min (1.0, fract); - fract = max (-1.0, fract); - - // X Window is top->bottom for 0..Y - if (_orien == VERT) { - fract = -fract; - } - - adjustment.set_value (adjustment.get_value() + scale * fract * (adjustment.get_upper() - adjustment.get_lower())); + adjustment.set_value (adjustment.get_lower() + (adjustment.get_upper() - adjustment.get_lower()) * fract); } -*/ return true; } diff --git a/libs/gtkmm2ext/gtkmm2ext/fader.h b/libs/gtkmm2ext/gtkmm2ext/fader.h index 48cdc6d00c..2eeed75de5 100755 --- a/libs/gtkmm2ext/gtkmm2ext/fader.h +++ b/libs/gtkmm2ext/gtkmm2ext/fader.h @@ -37,6 +37,7 @@ class LIBGTKMM2EXT_API Fader : public Gtk::DrawingArea Fader (Gtk::Adjustment& adjustment, const std::string& face_image_file, const std::string& handle_image_file, + const std::string& active_handle_image_file, int min_pos_x, int min_pos_y, int max_pos_x, @@ -62,6 +63,7 @@ class LIBGTKMM2EXT_API Fader : public Gtk::DrawingArea private: Glib::RefPtr _handle_pixbuf; + Glib::RefPtr _active_handle_pixbuf; Glib::RefPtr _face_pixbuf; Gtk::Adjustment& adjustment; int _min_pos_x;