13
0

new mono panner widget; make stereo panner respond to changes in colors immediately

git-svn-id: svn://localhost/ardour2/branches/3.0@8474 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2011-01-07 17:36:01 +00:00
parent 603d07a80b
commit 7d252dbbb9
11 changed files with 655 additions and 77 deletions

View File

@ -102,10 +102,17 @@
<Option name="selected waveform outline" value="0f0f0fcc"/> <Option name="selected waveform outline" value="0f0f0fcc"/>
<Option name="selection rect" value="e8f4d377"/> <Option name="selection rect" value="e8f4d377"/>
<Option name="selection" value="636363b2"/> <Option name="selection" value="636363b2"/>
<Option name="mono panner outline" value="6a6565ff"/>
<Option name="mono panner fill" value="7e6f6fc9"/>
<Option name="mono panner text" value="000000ff"/>
<Option name="mono panner bg" value="2d2828ff"/>
<Option name="mono panner position fill" value="7a89b3ff"/>
<Option name="mono panner position outline" value="001cfeff"/>
<Option name="stereo panner outline" value="001cfeff"/> <Option name="stereo panner outline" value="001cfeff"/>
<Option name="stereo panner fill" value="8ea2d7c9"/> <Option name="stereo panner fill" value="8ea2d7c9"/>
<Option name="stereo panner text" value="000000ff"/> <Option name="stereo panner text" value="000000ff"/>
<Option name="stereo panner bg" value="2e2929ff"/> <Option name="stereo panner bg" value="2e2929ff"/>
<Option name="stereo panner rule" value="b5a594ff"/>
<Option name="stereo panner mono outline" value="a05600ff"/> <Option name="stereo panner mono outline" value="a05600ff"/>
<Option name="stereo panner mono fill" value="e99668ca"/> <Option name="stereo panner mono fill" value="e99668ca"/>
<Option name="stereo panner mono text" value="000000ff"/> <Option name="stereo panner mono text" value="000000ff"/>

View File

@ -96,10 +96,17 @@ CANVAS_VARIABLE(canvasvar_SelectionRect, "selection rect")
CANVAS_VARIABLE(canvasvar_Selection, "selection") CANVAS_VARIABLE(canvasvar_Selection, "selection")
CANVAS_VARIABLE(canvasvar_Silence, "silence") CANVAS_VARIABLE(canvasvar_Silence, "silence")
CANVAS_VARIABLE(canvasvar_SilenceText, "silence text") CANVAS_VARIABLE(canvasvar_SilenceText, "silence text")
CANVAS_VARIABLE(canvasvar_MonoPannerOutline, "mono panner outline")
CANVAS_VARIABLE(canvasvar_MonoPannerFill, "mono panner fill")
CANVAS_VARIABLE(canvasvar_MonoPannerText, "mono panner text")
CANVAS_VARIABLE(canvasvar_MonoPannerBackground, "mono panner bg")
CANVAS_VARIABLE(canvasvar_MonoPannerPositionFill, "mono panner position fill")
CANVAS_VARIABLE(canvasvar_MonoPannerPositionOutline, "mono panner position outline")
CANVAS_VARIABLE(canvasvar_StereoPannerOutline, "stereo panner outline") CANVAS_VARIABLE(canvasvar_StereoPannerOutline, "stereo panner outline")
CANVAS_VARIABLE(canvasvar_StereoPannerFill, "stereo panner fill") CANVAS_VARIABLE(canvasvar_StereoPannerFill, "stereo panner fill")
CANVAS_VARIABLE(canvasvar_StereoPannerText, "stereo panner text") CANVAS_VARIABLE(canvasvar_StereoPannerText, "stereo panner text")
CANVAS_VARIABLE(canvasvar_StereoPannerBackground, "stereo panner bg") CANVAS_VARIABLE(canvasvar_StereoPannerBackground, "stereo panner bg")
CANVAS_VARIABLE(canvasvar_StereoPannerRule, "stereo panner rule")
CANVAS_VARIABLE(canvasvar_StereoPannerMonoOutline, "stereo panner mono outline") CANVAS_VARIABLE(canvasvar_StereoPannerMonoOutline, "stereo panner mono outline")
CANVAS_VARIABLE(canvasvar_StereoPannerMonoFill, "stereo panner mono fill") CANVAS_VARIABLE(canvasvar_StereoPannerMonoFill, "stereo panner mono fill")
CANVAS_VARIABLE(canvasvar_StereoPannerMonoText, "stereo panner mono text") CANVAS_VARIABLE(canvasvar_StereoPannerMonoText, "stereo panner mono text")

484
gtk2_ardour/mono_panner.cc Normal file
View File

@ -0,0 +1,484 @@
/*
Copyright (C) 2000-2007 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cmath>
#include <gtkmm/window.h>
#include "pbd/controllable.h"
#include "pbd/compose.h"
#include "gtkmm2ext/gui_thread.h"
#include "gtkmm2ext/gtk_ui.h"
#include "gtkmm2ext/keyboard.h"
#include "ardour/panner.h"
#include "ardour_ui.h"
#include "global_signals.h"
#include "mono_panner.h"
#include "rgb_macros.h"
#include "utils.h"
#include "i18n.h"
using namespace std;
using namespace Gtk;
using namespace Gtkmm2ext;
static const int pos_box_size = 10;
static const int lr_box_size = 15;
static const int step_down = 10;
static const int top_step = 2;
MonoPanner::ColorScheme MonoPanner::colors;
bool MonoPanner::have_colors = false;
MonoPanner::MonoPanner (boost::shared_ptr<PBD::Controllable> position)
: position_control (position)
, dragging (false)
, drag_start_x (0)
, last_drag_x (0)
, accumulated_delta (0)
, detented (false)
, drag_data_window (0)
, drag_data_label (0)
, position_binder (position)
{
if (!have_colors) {
set_colors ();
have_colors = true;
}
position_control->Changed.connect (connections, invalidator(*this), boost::bind (&MonoPanner::value_change, this), gui_context());
set_flags (Gtk::CAN_FOCUS);
add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|
Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|
Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|
Gdk::SCROLL_MASK|
Gdk::POINTER_MOTION_MASK);
ColorsChanged.connect (sigc::mem_fun (*this, &MonoPanner::color_handler));
}
MonoPanner::~MonoPanner ()
{
delete drag_data_window;
}
void
MonoPanner::set_drag_data ()
{
if (!drag_data_label) {
return;
}
double pos = position_control->get_value(); // 0..1
/* We show the position of the center of the image relative to the left & right.
This is expressed as a pair of percentage values that ranges from (100,0)
(hard left) through (50,50) (hard center) to (0,100) (hard right).
This is pretty wierd, but its the way audio engineers expect it. Just remember that
the center of the USA isn't Kansas, its (50LA, 50NY) and it will all make sense.
*/
drag_data_label->set_markup (string_compose (_("L:%1 R:%2"),
(int) rint (100.0 * (1.0 - pos)),
(int) rint (100.0 * pos)));
}
void
MonoPanner::value_change ()
{
set_drag_data ();
queue_draw ();
}
bool
MonoPanner::on_expose_event (GdkEventExpose* ev)
{
Glib::RefPtr<Gdk::Window> win (get_window());
Glib::RefPtr<Gdk::GC> gc (get_style()->get_base_gc (get_state()));
cairo_t* cr = gdk_cairo_create (win->gobj());
int width, height;
double pos = position_control->get_value (); /* 0..1 */
uint32_t o, f, t, b, pf, po;
width = get_width();
height = get_height ();
o = colors.outline;
f = colors.fill;
t = colors.text;
b = colors.background;
pf = colors.pos_fill;
po = colors.pos_outline;
/* background */
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(b), UINT_RGBA_G_FLT(b), UINT_RGBA_B_FLT(b), UINT_RGBA_A_FLT(b));
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
/* the usable width is reduced from the real width, because we need space for
the two halves of LR boxes that will extend past the actual left/right
positions (indicated by the vertical line segment above them).
*/
double usable_width = width - lr_box_size;
/* compute the centers of the L/R boxes based on the current stereo width */
if (fmod (usable_width,2.0) == 0) {
/* even width, but we need odd, so that there is an exact center.
So, offset cairo by 1, and reduce effective width by 1
*/
usable_width -= 1.0;
cairo_translate (cr, 1.0, 0.0);
}
double center = (lr_box_size/2.0) + (usable_width * pos);
const double half_lr_box = lr_box_size/2.0;
double left;
double right;
left = 4 + half_lr_box; // center of left box
right = width - 4 - half_lr_box; // center of right box
/* center line */
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
cairo_set_line_width (cr, 1.0);
cairo_move_to (cr, width/2.0, 0);
cairo_line_to (cr, width/2.0, height);
cairo_stroke (cr);
/* left box */
cairo_rectangle (cr,
left - half_lr_box,
half_lr_box+step_down,
lr_box_size, lr_box_size);
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
cairo_stroke_preserve (cr);
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(f), UINT_RGBA_G_FLT(f), UINT_RGBA_B_FLT(f), UINT_RGBA_A_FLT(f));
cairo_fill (cr);
/* add text */
cairo_move_to (cr,
left - half_lr_box + 3,
(lr_box_size/2) + step_down + 13);
cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(t), UINT_RGBA_G_FLT(t), UINT_RGBA_B_FLT(t), UINT_RGBA_A_FLT(t));
cairo_show_text (cr, _("L"));
/* right box */
cairo_rectangle (cr,
right - half_lr_box,
half_lr_box+step_down,
lr_box_size, lr_box_size);
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
cairo_stroke_preserve (cr);
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(f), UINT_RGBA_G_FLT(f), UINT_RGBA_B_FLT(f), UINT_RGBA_A_FLT(f));
cairo_fill (cr);
/* add text */
cairo_move_to (cr,
right - half_lr_box + 3,
(lr_box_size/2)+step_down + 13);
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(t), UINT_RGBA_G_FLT(t), UINT_RGBA_B_FLT(t), UINT_RGBA_A_FLT(t));
cairo_show_text (cr, _("R"));
/* 2 lines that connect them both */
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
cairo_set_line_width (cr, 1.0);
cairo_move_to (cr, left + half_lr_box, half_lr_box+step_down);
cairo_line_to (cr, right - half_lr_box, half_lr_box+step_down);
cairo_stroke (cr);
cairo_move_to (cr, left + half_lr_box, half_lr_box+step_down+lr_box_size);
cairo_line_to (cr, right - half_lr_box, half_lr_box+step_down+lr_box_size);
cairo_stroke (cr);
/* draw the position indicator */
cairo_set_line_width (cr, 2.0);
cairo_rectangle (cr, lrint (center - (pos_box_size/2.0)), top_step, pos_box_size, pos_box_size);
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(po), UINT_RGBA_G_FLT(po), UINT_RGBA_B_FLT(po), UINT_RGBA_A_FLT(po));
cairo_stroke_preserve (cr);
cairo_set_source_rgba (cr, UINT_RGBA_R_FLT(pf), UINT_RGBA_G_FLT(pf), UINT_RGBA_B_FLT(pf), UINT_RGBA_A_FLT(pf));
cairo_fill (cr);
/* done */
cairo_destroy (cr);
return true;
}
bool
MonoPanner::on_button_press_event (GdkEventButton* ev)
{
drag_start_x = ev->x;
last_drag_x = ev->x;
dragging = false;
accumulated_delta = 0;
detented = false;
/* Let the binding proxies get first crack at the press event
*/
if (ev->y < 20) {
if (position_binder.button_press_handler (ev)) {
return true;
}
}
if (ev->button != 1) {
return false;
}
if (ev->type == GDK_2BUTTON_PRESS) {
int width = get_width();
if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
/* handled by button release */
return true;
}
if (ev->x <= width/3) {
/* left side dbl click */
position_control->set_value (0);
} else if (ev->x > 2*width/3) {
position_control->set_value (1.0);
} else {
position_control->set_value (0.5);
}
dragging = false;
} else if (ev->type == GDK_BUTTON_PRESS) {
if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
/* handled by button release */
return true;
}
dragging = true;
}
return true;
}
bool
MonoPanner::on_button_release_event (GdkEventButton* ev)
{
if (ev->button != 1) {
return false;
}
dragging = false;
accumulated_delta = 0;
detented = false;
if (drag_data_window) {
drag_data_window->hide ();
}
if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
/* reset to default */
position_control->set_value (0.5);
}
return true;
}
bool
MonoPanner::on_scroll_event (GdkEventScroll* ev)
{
double one_degree = 1.0/180.0; // one degree as a number from 0..1, since 180 degrees is the full L/R axis
double pv = position_control->get_value(); // 0..1.0 ; 0 = left
double step;
if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
step = one_degree;
} else {
step = one_degree * 5.0;
}
switch (ev->direction) {
case GDK_SCROLL_UP:
case GDK_SCROLL_LEFT:
pv -= step;
position_control->set_value (pv);
break;
case GDK_SCROLL_DOWN:
case GDK_SCROLL_RIGHT:
pv += step;
position_control->set_value (pv);
break;
}
return true;
}
bool
MonoPanner::on_motion_notify_event (GdkEventMotion* ev)
{
if (!dragging) {
return false;
}
if (!drag_data_window) {
drag_data_window = new Window (WINDOW_POPUP);
drag_data_window->set_position (WIN_POS_MOUSE);
drag_data_window->set_decorated (false);
drag_data_label = manage (new Label);
drag_data_label->set_use_markup (true);
drag_data_window->set_border_width (6);
drag_data_window->add (*drag_data_label);
drag_data_label->show ();
Window* toplevel = dynamic_cast<Window*> (get_toplevel());
if (toplevel) {
drag_data_window->set_transient_for (*toplevel);
}
}
if (!drag_data_window->is_visible ()) {
/* move the window a little away from the mouse */
drag_data_window->move (ev->x_root+30, ev->y_root+30);
drag_data_window->present ();
}
int w = get_width();
double delta = (ev->x - last_drag_x) / (double) w;
/* create a detent close to the center */
if (!detented && ARDOUR::Panner::equivalent (position_control->get_value(), 0.5)) {
detented = true;
/* snap to center */
position_control->set_value (0.5);
}
if (detented) {
accumulated_delta += delta;
/* have we pulled far enough to escape ? */
if (fabs (accumulated_delta) >= 0.025) {
position_control->set_value (position_control->get_value() + accumulated_delta);
detented = false;
accumulated_delta = false;
}
} else {
double pv = position_control->get_value(); // 0..1.0 ; 0 = left
position_control->set_value (pv + delta);
}
last_drag_x = ev->x;
return true;
}
bool
MonoPanner::on_key_press_event (GdkEventKey* ev)
{
double one_degree = 1.0/180.0;
double pv = position_control->get_value(); // 0..1.0 ; 0 = left
double step;
if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
step = one_degree;
} else {
step = one_degree * 5.0;
}
/* up/down control width because we consider pan position more "important"
(and thus having higher "sense" priority) than width.
*/
switch (ev->keyval) {
case GDK_Left:
pv -= step;
position_control->set_value (pv);
break;
case GDK_Right:
pv += step;
position_control->set_value (pv);
break;
default:
return false;
}
return true;
}
bool
MonoPanner::on_key_release_event (GdkEventKey* ev)
{
return false;
}
bool
MonoPanner::on_enter_notify_event (GdkEventCrossing* ev)
{
grab_focus ();
Keyboard::magic_widget_grab_focus ();
return false;
}
bool
MonoPanner::on_leave_notify_event (GdkEventCrossing*)
{
Keyboard::magic_widget_drop_focus ();
return false;
}
void
MonoPanner::set_colors ()
{
colors.fill = ARDOUR_UI::config()->canvasvar_MonoPannerFill.get();
colors.outline = ARDOUR_UI::config()->canvasvar_MonoPannerOutline.get();
colors.text = ARDOUR_UI::config()->canvasvar_MonoPannerText.get();
colors.background = ARDOUR_UI::config()->canvasvar_MonoPannerBackground.get();
colors.pos_outline = ARDOUR_UI::config()->canvasvar_MonoPannerPositionOutline.get();
colors.pos_fill = ARDOUR_UI::config()->canvasvar_MonoPannerPositionFill.get();
}
void
MonoPanner::color_handler ()
{
set_colors ();
queue_draw ();
}

85
gtk2_ardour/mono_panner.h Normal file
View File

@ -0,0 +1,85 @@
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __gtk_ardour_mono_panner_h__
#define __gtk_ardour_mono_panner_h__
#include "pbd/signals.h"
#include <gtkmm/drawingarea.h>
#include <boost/shared_ptr.hpp>
#include "gtkmm2ext/binding_proxy.h"
namespace PBD {
class Controllable;
}
class MonoPanner : public Gtk::DrawingArea
{
public:
MonoPanner (boost::shared_ptr<PBD::Controllable> pos);
~MonoPanner ();
boost::shared_ptr<PBD::Controllable> get_controllable() const { return position_control; }
protected:
bool on_expose_event (GdkEventExpose*);
bool on_button_press_event (GdkEventButton*);
bool on_button_release_event (GdkEventButton*);
bool on_motion_notify_event (GdkEventMotion*);
bool on_scroll_event (GdkEventScroll*);
bool on_key_press_event (GdkEventKey*);
bool on_key_release_event (GdkEventKey*);
bool on_enter_notify_event (GdkEventCrossing* ev);
bool on_leave_notify_event (GdkEventCrossing* ev);
private:
boost::shared_ptr<PBD::Controllable> position_control;
PBD::ScopedConnectionList connections;
bool dragging;
int drag_start_x;
int last_drag_x;
double accumulated_delta;
bool detented;
Gtk::Window* drag_data_window;
Gtk::Label* drag_data_label;
BindingProxy position_binder;
void value_change ();
void set_drag_data ();
struct ColorScheme {
uint32_t outline;
uint32_t fill;
uint32_t text;
uint32_t background;
uint32_t pos_outline;
uint32_t pos_fill;
};
static ColorScheme colors;
static void set_colors ();
static bool have_colors;
void color_handler ();
};
#endif /* __gtk_ardour_mono_panner_h__ */

View File

@ -29,9 +29,9 @@
#include "panner_ui.h" #include "panner_ui.h"
#include "panner2d.h" #include "panner2d.h"
#include "utils.h" #include "utils.h"
#include "panner.h"
#include "gui_thread.h" #include "gui_thread.h"
#include "stereo_panner.h" #include "stereo_panner.h"
#include "mono_panner.h"
#include "ardour/delivery.h" #include "ardour/delivery.h"
#include "ardour/session.h" #include "ardour/session.h"
@ -46,7 +46,7 @@ using namespace PBD;
using namespace Gtkmm2ext; using namespace Gtkmm2ext;
using namespace Gtk; using namespace Gtk;
const int PannerUI::pan_bar_height = 20; const int PannerUI::pan_bar_height = 40;
PannerUI::PannerUI (Session* s) PannerUI::PannerUI (Session* s)
: _current_nouts (-1) : _current_nouts (-1)
@ -307,7 +307,7 @@ PannerUI::~PannerUI ()
delete (*i); delete (*i);
} }
for (vector<PannerBar*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) { for (vector<MonoPanner*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) {
delete (*i); delete (*i);
} }
@ -431,7 +431,7 @@ PannerUI::setup_pan ()
_stereo_panner = new StereoPanner (_panner->direction_control(), _stereo_panner = new StereoPanner (_panner->direction_control(),
_panner->width_control()); _panner->width_control());
_stereo_panner->set_size_request (-1, 2 * pan_bar_height); _stereo_panner->set_size_request (-1, pan_bar_height);
panning_viewport.add (*_stereo_panner); panning_viewport.add (*_stereo_panner);
} else { } else {
@ -441,8 +441,8 @@ PannerUI::setup_pan ()
while ((asz = pan_adjustments.size()) < npans) { while ((asz = pan_adjustments.size()) < npans) {
float x, rx; float x, rx;
PannerBar* bc; MonoPanner* mp;
/* initialize adjustment with 0.0 (L) or 1.0 (R) for the first and second panners, /* initialize adjustment with 0.0 (L) or 1.0 (R) for the first and second panners,
which serves as a default, otherwise use current value */ which serves as a default, otherwise use current value */
@ -459,38 +459,29 @@ PannerUI::setup_pan ()
} }
pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.005, 0.05)); pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.005, 0.05));
bc = new PannerBar (*pan_adjustments[asz], mp = new MonoPanner (_panner->pan_control (asz));
boost::static_pointer_cast<PBD::Controllable>( _panner->pan_control( asz )) );
/* now set adjustment with current value of panner, then connect the signals */ /* now set adjustment with current value of panner, then connect the signals */
pan_adjustments.back()->set_value(rx); pan_adjustments.back()->set_value(rx);
pan_adjustments.back()->signal_value_changed().connect (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_adjustment_changed), (uint32_t) asz)); pan_adjustments.back()->signal_value_changed().connect (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_adjustment_changed), (uint32_t) asz));
connect_to_pan_control (asz);
bc->set_name ("PanSlider");
bc->set_shadow_type (Gtk::SHADOW_NONE);
boost::shared_ptr<AutomationControl> ac = _panner->pan_control (asz); boost::shared_ptr<AutomationControl> ac = _panner->pan_control (asz);
#if 0
if (asz) { if (asz) {
bc->StartGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch), bc->StartGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch),
boost::weak_ptr<AutomationControl> (ac))); boost::weak_ptr<AutomationControl> (ac)));
bc->StopGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch), bc->StopGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch),
boost::weak_ptr<AutomationControl>(ac))); boost::weak_ptr<AutomationControl>(ac)));
} }
#endif
char buf[64]; mp->signal_button_release_event().connect
snprintf (buf, sizeof (buf), _("panner for channel %zu"), asz + 1);
ARDOUR_UI::instance()->set_tip (bc->event_widget(), buf);
bc->event_widget().signal_button_release_event().connect
(sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_button_event), (uint32_t) asz)); (sigc::bind (sigc::mem_fun(*this, &PannerUI::pan_button_event), (uint32_t) asz));
bc->set_size_request (-1, pan_bar_height); mp->set_size_request (-1, pan_bar_height);
bc->SpinnerActive.connect (sigc::mem_fun (*this, &PannerUI::bar_spinner_activate));
pan_bars.push_back (bc); pan_bars.push_back (mp);
pan_bar_packer.pack_start (*bc, false, false); pan_bar_packer.pack_start (*mp, false, false);
} }
/* now that we actually have the pan bars, /* now that we actually have the pan bars,
@ -703,22 +694,7 @@ PannerUI::pan_value_changed (uint32_t which)
twod_panner->move_puck (which, _panner->streampanner(which).get_position()); twod_panner->move_puck (which, _panner->streampanner(which).get_position());
in_pan_update = false; in_pan_update = false;
} else if (_stereo_panner) { }
/* its taken care of */
} else if (_panner->npanners() > 0 && which < _panner->npanners()) {
AngularVector model = _panner->streampanner(which).get_position();
double fract = pan_adjustments[which]->get_value();
AngularVector view (BaseStereoPanner::lr_fract_to_azimuth (fract), 0.0);
if (!Panner::equivalent (model, view)) {
in_pan_update = true;
pan_adjustments[which]->set_value (BaseStereoPanner::azimuth_to_lr_fract (model.azi));
in_pan_update = false;
}
}
} }
void void
@ -765,7 +741,7 @@ PannerUI::update_pan_sensitive ()
case 1: case 1:
break; break;
case 2: case 2:
for (vector<PannerBar*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) { for (vector<MonoPanner*>::iterator i = pan_bars.begin(); i != pan_bars.end(); ++i) {
(*i)->set_sensitive (sensitive); (*i)->set_sensitive (sensitive);
} }
break; break;

View File

@ -41,6 +41,7 @@ class Panner2d;
class PannerBar; class PannerBar;
class Panner2dWindow; class Panner2dWindow;
class StereoPanner; class StereoPanner;
class MonoPanner;
namespace ARDOUR { namespace ARDOUR {
class Session; class Session;
@ -137,7 +138,8 @@ class PannerUI : public Gtk::HBox, public ARDOUR::SessionHandlePtr
void panning_link_direction_clicked (); void panning_link_direction_clicked ();
std::vector<Gtk::Adjustment*> pan_adjustments; std::vector<Gtk::Adjustment*> pan_adjustments;
std::vector<PannerBar*> pan_bars; //std::vector<PannerBar*> pan_bars;
std::vector<MonoPanner*> pan_bars;
void pan_adjustment_changed (uint32_t which); void pan_adjustment_changed (uint32_t which);
void pan_value_changed (uint32_t which); void pan_value_changed (uint32_t which);

View File

@ -37,6 +37,7 @@
using namespace std; using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
using namespace Gtk;
SessionImportDialog::SessionImportDialog (ARDOUR::Session* target) : SessionImportDialog::SessionImportDialog (ARDOUR::Session* target) :
ArdourDialog (_("Import From Session")), ArdourDialog (_("Import From Session")),
@ -65,7 +66,7 @@ SessionImportDialog::SessionImportDialog (ARDOUR::Session* target) :
get_vbox()->pack_start (file_frame, false, false); get_vbox()->pack_start (file_frame, false, false);
// Session browser // Session browser
session_tree = Gtk::TreeStore::create (sb_cols); session_tree = TreeStore::create (sb_cols);
session_browser.set_model (session_tree); session_browser.set_model (session_tree);
session_browser.set_name ("SessionBrowser"); session_browser.set_name ("SessionBrowser");
@ -74,23 +75,23 @@ SessionImportDialog::SessionImportDialog (ARDOUR::Session* target) :
session_browser.set_tooltip_column (3); session_browser.set_tooltip_column (3);
session_browser.get_column(0)->set_min_width (180); session_browser.get_column(0)->set_min_width (180);
session_browser.get_column(1)->set_min_width (40); session_browser.get_column(1)->set_min_width (40);
session_browser.get_column(1)->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); session_browser.get_column(1)->set_sizing (TREE_VIEW_COLUMN_AUTOSIZE);
session_scroll.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); session_scroll.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
session_scroll.add (session_browser); session_scroll.add (session_browser);
session_scroll.set_size_request (220, 400); session_scroll.set_size_request (220, 400);
// Connect signals // Connect signals
Gtk::CellRendererToggle *toggle = dynamic_cast<Gtk::CellRendererToggle *> (session_browser.get_column_cell_renderer (1)); CellRendererToggle *toggle = dynamic_cast<CellRendererToggle *> (session_browser.get_column_cell_renderer (1));
toggle->signal_toggled().connect(sigc::mem_fun (*this, &SessionImportDialog::update)); toggle->signal_toggled().connect(sigc::mem_fun (*this, &SessionImportDialog::update));
session_browser.signal_row_activated().connect(sigc::mem_fun (*this, &SessionImportDialog::show_info)); session_browser.signal_row_activated().connect(sigc::mem_fun (*this, &SessionImportDialog::show_info));
get_vbox()->pack_start (session_scroll, false, false); get_vbox()->pack_start (session_scroll, false, false);
// Buttons // Buttons
cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
cancel_button->signal_clicked().connect (sigc::mem_fun (*this, &SessionImportDialog::end_dialog)); cancel_button->signal_clicked().connect (sigc::mem_fun (*this, &SessionImportDialog::end_dialog));
ok_button = add_button (_("Import"), Gtk::RESPONSE_ACCEPT); ok_button = add_button (_("Import"), RESPONSE_ACCEPT);
ok_button->signal_clicked().connect (sigc::mem_fun (*this, &SessionImportDialog::do_merge)); ok_button->signal_clicked().connect (sigc::mem_fun (*this, &SessionImportDialog::do_merge));
// prompt signals XXX: problem - handlers to be in the same thread since they return values // prompt signals XXX: problem - handlers to be in the same thread since they return values
@ -124,7 +125,7 @@ SessionImportDialog::load_session (const string& filename)
if (ElementImportHandler::dirty()) { if (ElementImportHandler::dirty()) {
// Warn user // Warn user
string txt = _("Some elements had errors in them. Please see the log for details"); string txt = _("Some elements had errors in them. Please see the log for details");
Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true); MessageDialog msg (txt, false, MESSAGE_WARNING, BUTTONS_OK, true);
msg.run(); msg.run();
} }
} }
@ -137,8 +138,8 @@ SessionImportDialog::fill_list ()
// Loop through element types // Loop through element types
for (HandlerList::iterator handler = handlers.begin(); handler != handlers.end(); ++handler) { for (HandlerList::iterator handler = handlers.begin(); handler != handlers.end(); ++handler) {
Gtk::TreeModel::iterator iter = session_tree->append(); TreeModel::iterator iter = session_tree->append();
Gtk::TreeModel::Row row = *iter; TreeModel::Row row = *iter;
row[sb_cols.name] = (*handler)->get_info(); row[sb_cols.name] = (*handler)->get_info();
row[sb_cols.queued] = false; row[sb_cols.queued] = false;
row[sb_cols.element] = ElementPtr(); // "Null" pointer row[sb_cols.element] = ElementPtr(); // "Null" pointer
@ -147,7 +148,7 @@ SessionImportDialog::fill_list ()
ElementList &elements = (*handler)->elements; ElementList &elements = (*handler)->elements;
for (ElementList::iterator element = elements.begin(); element != elements.end(); ++element) { for (ElementList::iterator element = elements.begin(); element != elements.end(); ++element) {
iter = session_tree->append(row.children()); iter = session_tree->append(row.children());
Gtk::TreeModel::Row child = *iter; TreeModel::Row child = *iter;
child[sb_cols.name] = (*element)->get_name(); child[sb_cols.name] = (*element)->get_name();
child[sb_cols.queued] = false; child[sb_cols.queued] = false;
child[sb_cols.element] = *element; child[sb_cols.element] = *element;
@ -159,16 +160,22 @@ SessionImportDialog::fill_list ()
void void
SessionImportDialog::browse () SessionImportDialog::browse ()
{ {
Gtk::FileChooserDialog dialog(_("Import from session"), browse_action()); FileChooserDialog dialog(_("Import from session"), browse_action());
dialog.set_transient_for(*this); dialog.set_transient_for(*this);
dialog.set_filename (file_entry.get_text()); dialog.set_filename (file_entry.get_text());
dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); FileFilter session_filter;
dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); session_filter.add_pattern ("*.ardour");
session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
dialog.add_filter (session_filter);
dialog.set_filter (session_filter);
dialog.add_button(Stock::CANCEL, RESPONSE_CANCEL);
dialog.add_button(Stock::OK, RESPONSE_OK);
int result = dialog.run(); int result = dialog.run();
if (result == Gtk::RESPONSE_OK) { if (result == RESPONSE_OK) {
string filename = dialog.get_filename(); string filename = dialog.get_filename();
if (filename.length()) { if (filename.length()) {
@ -183,12 +190,12 @@ SessionImportDialog::do_merge ()
{ {
// element types // element types
Gtk::TreeModel::Children types = session_browser.get_model()->children(); TreeModel::Children types = session_browser.get_model()->children();
Gtk::TreeModel::Children::iterator ti; TreeModel::Children::iterator ti;
for (ti = types.begin(); ti != types.end(); ++ti) { for (ti = types.begin(); ti != types.end(); ++ti) {
// elements // elements
Gtk::TreeModel::Children elements = ti->children(); TreeModel::Children elements = ti->children();
Gtk::TreeModel::Children::iterator ei; TreeModel::Children::iterator ei;
for (ei = elements.begin(); ei != elements.end(); ++ei) { for (ei = elements.begin(); ei != elements.end(); ++ei) {
if ((*ei)[sb_cols.queued]) { if ((*ei)[sb_cols.queued]) {
ElementPtr element = (*ei)[sb_cols.element]; ElementPtr element = (*ei)[sb_cols.element];
@ -202,7 +209,7 @@ SessionImportDialog::do_merge ()
if (ElementImportHandler::errors()) { if (ElementImportHandler::errors()) {
// Warn user // Warn user
string txt = _("Some elements had errors in them. Please see the log for details"); string txt = _("Some elements had errors in them. Please see the log for details");
Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true); MessageDialog msg (txt, false, MESSAGE_WARNING, BUTTONS_OK, true);
msg.run(); msg.run();
} }
} }
@ -211,22 +218,22 @@ SessionImportDialog::do_merge ()
void void
SessionImportDialog::update (string path) SessionImportDialog::update (string path)
{ {
Gtk::TreeModel::iterator cell = session_browser.get_model()->get_iter (path); TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
// Select all elements if element type is selected // Select all elements if element type is selected
if (path.size() == 1) { if (path.size() == 1) {
{ {
// Prompt user for verification // Prompt user for verification
string txt = _("This will select all elements of this type!"); string txt = _("This will select all elements of this type!");
Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true); MessageDialog msg (txt, false, MESSAGE_QUESTION, BUTTONS_OK_CANCEL, true);
if (msg.run() == Gtk::RESPONSE_CANCEL) { if (msg.run() == RESPONSE_CANCEL) {
(*cell)[sb_cols.queued] = false; (*cell)[sb_cols.queued] = false;
return; return;
} }
} }
Gtk::TreeModel::Children elements = cell->children(); TreeModel::Children elements = cell->children();
Gtk::TreeModel::Children::iterator ei; TreeModel::Children::iterator ei;
for (ei = elements.begin(); ei != elements.end(); ++ei) { for (ei = elements.begin(); ei != elements.end(); ++ei) {
ElementPtr element = (*ei)[sb_cols.element]; ElementPtr element = (*ei)[sb_cols.element];
if (element->prepare_move()) { if (element->prepare_move()) {
@ -249,16 +256,16 @@ SessionImportDialog::update (string path)
} }
void void
SessionImportDialog::show_info(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*) SessionImportDialog::show_info(const TreeModel::Path& path, TreeViewColumn*)
{ {
if (path.size() == 1) { if (path.size() == 1) {
return; return;
} }
Gtk::TreeModel::iterator cell = session_browser.get_model()->get_iter (path); TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
string info = (*cell)[sb_cols.info]; string info = (*cell)[sb_cols.info];
Gtk::MessageDialog msg (info, false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, true); MessageDialog msg (info, false, MESSAGE_INFO, BUTTONS_OK, true);
msg.run(); msg.run();
} }
@ -278,11 +285,11 @@ SessionImportDialog::open_rename_dialog (string text, string name)
string new_name; string new_name;
prompter.set_name ("Prompter"); prompter.set_name ("Prompter");
prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); prompter.add_button (Stock::SAVE, RESPONSE_ACCEPT);
prompter.set_prompt (text); prompter.set_prompt (text);
prompter.set_initial_text (name); prompter.set_initial_text (name);
if (prompter.run() == Gtk::RESPONSE_ACCEPT) { if (prompter.run() == RESPONSE_ACCEPT) {
prompter.get_result (new_name); prompter.get_result (new_name);
if (new_name.length()) { if (new_name.length()) {
name = new_name; name = new_name;
@ -295,8 +302,8 @@ SessionImportDialog::open_rename_dialog (string text, string name)
bool bool
SessionImportDialog::open_prompt_dialog (string text) SessionImportDialog::open_prompt_dialog (string text)
{ {
Gtk::MessageDialog msg (text, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true); MessageDialog msg (text, false, MESSAGE_QUESTION, BUTTONS_OK_CANCEL, true);
if (msg.run() == Gtk::RESPONSE_OK) { if (msg.run() == RESPONSE_OK) {
return true; return true;
} }
return false; return false;

View File

@ -52,7 +52,6 @@ static const int top_step = 2;
StereoPanner::ColorScheme StereoPanner::colors[3]; StereoPanner::ColorScheme StereoPanner::colors[3];
bool StereoPanner::have_colors = false; bool StereoPanner::have_colors = false;
PBD::Signal0<void> StereoPanner::color_change;
StereoPanner::StereoPanner (boost::shared_ptr<PBD::Controllable> position, boost::shared_ptr<PBD::Controllable> width) StereoPanner::StereoPanner (boost::shared_ptr<PBD::Controllable> position, boost::shared_ptr<PBD::Controllable> width)
: position_control (position) : position_control (position)
@ -86,7 +85,7 @@ StereoPanner::StereoPanner (boost::shared_ptr<PBD::Controllable> position, boost
Gdk::SCROLL_MASK| Gdk::SCROLL_MASK|
Gdk::POINTER_MOTION_MASK); Gdk::POINTER_MOTION_MASK);
color_change.connect (connections, invalidator (*this), boost::bind (&DrawingArea::queue_draw, this), gui_context()); ColorsChanged.connect (sigc::mem_fun (*this, &StereoPanner::color_handler));
} }
StereoPanner::~StereoPanner () StereoPanner::~StereoPanner ()
@ -621,16 +620,24 @@ StereoPanner::set_colors ()
colors[Normal].outline = ARDOUR_UI::config()->canvasvar_StereoPannerOutline.get(); colors[Normal].outline = ARDOUR_UI::config()->canvasvar_StereoPannerOutline.get();
colors[Normal].text = ARDOUR_UI::config()->canvasvar_StereoPannerText.get(); colors[Normal].text = ARDOUR_UI::config()->canvasvar_StereoPannerText.get();
colors[Normal].background = ARDOUR_UI::config()->canvasvar_StereoPannerBackground.get(); colors[Normal].background = ARDOUR_UI::config()->canvasvar_StereoPannerBackground.get();
colors[Normal].rule = ARDOUR_UI::config()->canvasvar_StereoPannerRule.get();
colors[Mono].fill = ARDOUR_UI::config()->canvasvar_StereoPannerMonoFill.get(); colors[Mono].fill = ARDOUR_UI::config()->canvasvar_StereoPannerMonoFill.get();
colors[Mono].outline = ARDOUR_UI::config()->canvasvar_StereoPannerMonoOutline.get(); colors[Mono].outline = ARDOUR_UI::config()->canvasvar_StereoPannerMonoOutline.get();
colors[Mono].text = ARDOUR_UI::config()->canvasvar_StereoPannerMonoText.get(); colors[Mono].text = ARDOUR_UI::config()->canvasvar_StereoPannerMonoText.get();
colors[Mono].background = ARDOUR_UI::config()->canvasvar_StereoPannerMonoBackground.get(); colors[Mono].background = ARDOUR_UI::config()->canvasvar_StereoPannerMonoBackground.get();
colors[Mono].rule = ARDOUR_UI::config()->canvasvar_StereoPannerRule.get();
colors[Inverted].fill = ARDOUR_UI::config()->canvasvar_StereoPannerInvertedFill.get(); colors[Inverted].fill = ARDOUR_UI::config()->canvasvar_StereoPannerInvertedFill.get();
colors[Inverted].outline = ARDOUR_UI::config()->canvasvar_StereoPannerInvertedOutline.get(); colors[Inverted].outline = ARDOUR_UI::config()->canvasvar_StereoPannerInvertedOutline.get();
colors[Inverted].text = ARDOUR_UI::config()->canvasvar_StereoPannerInvertedText.get(); colors[Inverted].text = ARDOUR_UI::config()->canvasvar_StereoPannerInvertedText.get();
colors[Inverted].background = ARDOUR_UI::config()->canvasvar_StereoPannerInvertedBackground.get(); colors[Inverted].background = ARDOUR_UI::config()->canvasvar_StereoPannerInvertedBackground.get();
colors[Inverted].rule = ARDOUR_UI::config()->canvasvar_StereoPannerRule.get();
color_change (); /* EMIT SIGNAL */ }
void
StereoPanner::color_handler ()
{
set_colors ();
queue_draw ();
} }

View File

@ -75,6 +75,7 @@ class StereoPanner : public Gtk::DrawingArea
uint32_t fill; uint32_t fill;
uint32_t text; uint32_t text;
uint32_t background; uint32_t background;
uint32_t rule;
}; };
enum State { enum State {
@ -86,7 +87,7 @@ class StereoPanner : public Gtk::DrawingArea
static ColorScheme colors[3]; static ColorScheme colors[3];
static void set_colors (); static void set_colors ();
static bool have_colors; static bool have_colors;
static PBD::Signal0<void> color_change; void color_handler ();
}; };
#endif /* __gtk_ardour_stereo_panner_h__ */ #endif /* __gtk_ardour_stereo_panner_h__ */

View File

@ -148,6 +148,7 @@ gtk2_ardour_sources = [
'mixer_strip.cc', 'mixer_strip.cc',
'mixer_ui.cc', 'mixer_ui.cc',
'monitor_section.cc', 'monitor_section.cc',
'mono_panner.cc',
'mouse_cursors.cc', 'mouse_cursors.cc',
'nag.cc', 'nag.cc',
'new_plugin_preset_dialog.cc', 'new_plugin_preset_dialog.cc',

View File

@ -130,7 +130,8 @@ StreamPanner::PanControllable::set_value (double val)
} }
break; break;
default: default: /* positional */
val = max (min (val, 1.0), 0.0);
streampanner->set_position (AngularVector (direct_control_to_stereo_pan (val), 0.0)); streampanner->set_position (AngularVector (direct_control_to_stereo_pan (val), 0.0));
AutomationControl::set_value(val); AutomationControl::set_value(val);
break; break;