[Summary] Implementing the panners with KNOB

This commit is contained in:
VKamyshniy 2014-07-09 10:28:47 +03:00
parent af40d1620a
commit 252edfad87
7 changed files with 139 additions and 485 deletions

View file

@ -51,17 +51,6 @@ using namespace std;
using namespace Gtk;
using namespace Gtkmm2ext;
static const int pos_box_size = 9;
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;
Pango::AttrList MonoPanner::panner_font_attributes;
bool MonoPanner::have_font = false;
MonoPanner::MonoPanner (boost::shared_ptr<ARDOUR::PannerShell> p)
: PannerInterface (p->panner())
, _panner_shell (p)
@ -73,27 +62,16 @@ MonoPanner::MonoPanner (boost::shared_ptr<ARDOUR::PannerShell> p)
, position_binder (position_control)
, _dragging (false)
{
if (!have_colors) {
set_colors ();
have_colors = true;
}
if (!have_font) {
Pango::FontDescription font;
Pango::AttrFontDesc* font_attr;
font = Pango::FontDescription ("ArdourMono");
font.set_weight (Pango::WEIGHT_BOLD);
font.set_size(9 * PANGO_SCALE);
font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font));
panner_font_attributes.change(*font_attr);
delete font_attr;
have_font = true;
if (_knob_image[0] == 0) {
for (size_t i=0; i < (sizeof(_knob_image)/sizeof(_knob_image[0])); i++) {
_knob_image[i] = load_pixbuf (_knob_image_files[i]);
}
}
position_control->Changed.connect (panvalue_connections, invalidator(*this), boost::bind (&MonoPanner::value_change, this), gui_context());
_panner_shell->Changed.connect (panshell_connections, invalidator (*this), boost::bind (&MonoPanner::bypass_handler, this), gui_context());
_panner_shell->PannableChanged.connect (panshell_connections, invalidator (*this), boost::bind (&MonoPanner::pannable_handler, this), gui_context());
ColorsChanged.connect (sigc::mem_fun (*this, &MonoPanner::color_handler));
set_tooltip ();
}
@ -130,149 +108,16 @@ MonoPanner::set_tooltip ()
bool
MonoPanner::on_expose_event (GdkEventExpose*)
{
Glib::RefPtr<Gdk::Window> win (get_window());
Glib::RefPtr<Gdk::GC> gc (get_style()->get_base_gc (get_state()));
Cairo::RefPtr<Cairo::Context> context = get_window()->create_cairo_context();
unsigned pos = (unsigned)(rint (100.0 * position_control->get_value ())); /* 0..100 */
int width, height;
double pos = position_control->get_value (); /* 0..1 */
uint32_t o, f, t, b, pf, po;
const double corner_radius = 5;
double x = (get_width() - _knob_image[pos]->get_width())/2.0;
double y = (get_height() - _knob_image[pos]->get_height())/2.0;
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;
if (_panner_shell->bypassed()) {
b = 0x20202040;
f = 0x404040ff;
o = 0x606060ff;
po = 0x606060ff;
pf = 0x404040ff;
t = 0x606060ff;
}
/* background */
context->set_source_rgba (UINT_RGBA_R_FLT(b), UINT_RGBA_G_FLT(b), UINT_RGBA_B_FLT(b), UINT_RGBA_A_FLT(b));
context->rectangle (0, 0, width, height);
context->fill ();
double usable_width = width - pos_box_size;
/* compute the centers of the L/R boxes based on the current stereo width */
if (fmod (usable_width,2.0) == 0) {
usable_width -= 1.0;
}
const double half_lr_box = lr_box_size/2.0;
const double left = 4 + half_lr_box; // center of left box
const double right = width - 4 - half_lr_box; // center of right box
/* center line */
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->set_line_width (1.0);
context->move_to ((pos_box_size/2.0) + (usable_width/2.0), 0);
context->line_to ((pos_box_size/2.0) + (usable_width/2.0), height);
context->stroke ();
context->set_line_width (1.0);
/* left box */
rounded_left_half_rectangle (context,
left - half_lr_box + .5,
half_lr_box + step_down,
lr_box_size, lr_box_size, corner_radius);
context->set_source_rgba (UINT_RGBA_R_FLT(f), UINT_RGBA_G_FLT(f), UINT_RGBA_B_FLT(f), UINT_RGBA_A_FLT(f));
context->fill_preserve ();
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->stroke();
/* add text */
int tw, th;
Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(get_pango_context());
layout->set_attributes (panner_font_attributes);
layout->set_text (_("L"));
layout->get_pixel_size(tw, th);
context->move_to (rint(left - tw/2), rint(lr_box_size + step_down - th/2));
context->set_source_rgba (UINT_RGBA_R_FLT(t), UINT_RGBA_G_FLT(t), UINT_RGBA_B_FLT(t), UINT_RGBA_A_FLT(t));
pango_cairo_show_layout (context->cobj(), layout->gobj());
/* right box */
rounded_right_half_rectangle (context,
right - half_lr_box - .5,
half_lr_box + step_down,
lr_box_size, lr_box_size, corner_radius);
context->set_source_rgba (UINT_RGBA_R_FLT(f), UINT_RGBA_G_FLT(f), UINT_RGBA_B_FLT(f), UINT_RGBA_A_FLT(f));
context->fill_preserve ();
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->stroke();
/* add text */
layout->set_text (_("R"));
layout->get_pixel_size(tw, th);
context->move_to (rint(right - tw/2), rint(lr_box_size + step_down - th/2));
context->set_source_rgba (UINT_RGBA_R_FLT(t), UINT_RGBA_G_FLT(t), UINT_RGBA_B_FLT(t), UINT_RGBA_A_FLT(t));
pango_cairo_show_layout (context->cobj(), layout->gobj());
/* 2 lines that connect them both */
context->set_line_width (1.0);
if (_panner_shell->panner_gui_uri() != "http://ardour.org/plugin/panner_balance#ui") {
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->move_to (left + half_lr_box, half_lr_box + step_down);
context->line_to (right - half_lr_box, half_lr_box + step_down);
context->stroke ();
context->move_to (left + half_lr_box, half_lr_box+step_down+lr_box_size);
context->line_to (right - half_lr_box, half_lr_box+step_down+lr_box_size);
context->stroke ();
} else {
context->move_to (left + half_lr_box, half_lr_box+step_down+lr_box_size);
context->line_to (left + half_lr_box, half_lr_box + step_down);
context->line_to ((pos_box_size/2.0) + (usable_width/2.0), half_lr_box+step_down+lr_box_size);
context->line_to (right - half_lr_box, half_lr_box + step_down);
context->line_to (right - half_lr_box, half_lr_box+step_down+lr_box_size);
context->close_path();
context->set_source_rgba (UINT_RGBA_R_FLT(f), UINT_RGBA_G_FLT(f), UINT_RGBA_B_FLT(f), UINT_RGBA_A_FLT(f));
context->fill_preserve ();
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->stroke ();
}
/* draw the position indicator */
double spos = (pos_box_size/2.0) + (usable_width * pos);
context->set_line_width (2.0);
context->move_to (spos + (pos_box_size/2.0), top_step); /* top right */
context->rel_line_to (0.0, pos_box_size); /* lower right */
context->rel_line_to (-pos_box_size/2.0, 4.0); /* bottom point */
context->rel_line_to (-pos_box_size/2.0, -4.0); /* lower left */
context->rel_line_to (0.0, -pos_box_size); /* upper left */
context->close_path ();
context->set_source_rgba (UINT_RGBA_R_FLT(po), UINT_RGBA_G_FLT(po), UINT_RGBA_B_FLT(po), UINT_RGBA_A_FLT(po));
context->stroke_preserve ();
context->set_source_rgba (UINT_RGBA_R_FLT(pf), UINT_RGBA_G_FLT(pf), UINT_RGBA_B_FLT(pf), UINT_RGBA_A_FLT(pf));
context->fill ();
/* marker line */
context->set_line_width (1.0);
context->move_to (spos, pos_box_size + 5);
context->rel_line_to (0, half_lr_box+step_down);
context->set_source_rgba (UINT_RGBA_R_FLT(po), UINT_RGBA_G_FLT(po), UINT_RGBA_B_FLT(po), UINT_RGBA_A_FLT(po));
context->stroke ();
/* done */
cairo_rectangle (context->cobj(), x, y, _knob_image[pos]->get_width(), _knob_image[pos]->get_height());
gdk_cairo_set_source_pixbuf (context->cobj(), _knob_image[pos]->gobj(), x, y);
cairo_fill (context->cobj());
return true;
}
@ -482,24 +327,6 @@ MonoPanner::on_key_press_event (GdkEventKey* ev)
return true;
}
void
MonoPanner::set_colors ()
{
colors.fill = ARDOUR_UI::config()->get_canvasvar_MonoPannerFill();
colors.outline = ARDOUR_UI::config()->get_canvasvar_MonoPannerOutline();
colors.text = ARDOUR_UI::config()->get_canvasvar_MonoPannerText();
colors.background = ARDOUR_UI::config()->get_canvasvar_MonoPannerBackground();
colors.pos_outline = ARDOUR_UI::config()->get_canvasvar_MonoPannerPositionOutline();
colors.pos_fill = ARDOUR_UI::config()->get_canvasvar_MonoPannerPositionFill();
}
void
MonoPanner::color_handler ()
{
set_colors ();
queue_draw ();
}
void
MonoPanner::bypass_handler ()
{

View file

@ -42,7 +42,7 @@ class MonoPanner : public PannerInterface
MonoPanner (boost::shared_ptr<ARDOUR::PannerShell>);
~MonoPanner ();
boost::shared_ptr<PBD::Controllable> get_controllable() const { return position_control; }
boost::shared_ptr<PBD::Controllable> get_controllable() const { return position_control; }
sigc::signal<void> StartGesture;
sigc::signal<void> StopGesture;
@ -52,43 +52,27 @@ class MonoPanner : public PannerInterface
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_scroll_event (GdkEventScroll*);
bool on_key_press_event (GdkEventKey*);
private:
PannerEditor* editor ();
boost::shared_ptr<ARDOUR::PannerShell> _panner_shell;
boost::shared_ptr<PBD::Controllable> position_control;
PBD::ScopedConnectionList panvalue_connections;
PBD::ScopedConnectionList panshell_connections;
int drag_start_x;
int last_drag_x;
double accumulated_delta;
bool detented;
boost::shared_ptr<PBD::Controllable> position_control;
PBD::ScopedConnectionList panvalue_connections;
PBD::ScopedConnectionList panshell_connections;
int drag_start_x;
int last_drag_x;
double accumulated_delta;
bool detented;
BindingProxy position_binder;
BindingProxy position_binder;
void set_tooltip ();
struct ColorScheme {
uint32_t outline;
uint32_t fill;
uint32_t text;
uint32_t background;
uint32_t pos_outline;
uint32_t pos_fill;
};
void set_tooltip ();
bool _dragging;
static Pango::AttrList panner_font_attributes;
static bool have_font;
static ColorScheme colors;
static void set_colors ();
static bool have_colors;
void color_handler ();
void bypass_handler ();
void pannable_handler ();
};

View file

@ -20,6 +20,12 @@
#include <gtkmm.h>
#include "gtkmm2ext/keyboard.h"
#include "gtkmm2ext/persistent_tooltip.h"
#include "pbd/file_utils.h"
#include "pbd/error.h"
#include "ardour/filesystem_paths.h"
#include "panner_interface.h"
#include "panner_editor.h"
#include "global_signals.h"
@ -31,19 +37,59 @@ using namespace Gtk;
using namespace ARDOUR;
using namespace Gtkmm2ext;
const char* PannerInterface::_knob_image_files[101] = {
"001.png", "002.png", "003.png", "004.png", "005.png", "006.png", "007.png", "008.png", "009.png", "010.png",
"011.png", "012.png", "013.png", "014.png", "015.png", "016.png", "017.png", "018.png", "019.png", "020.png",
"021.png", "022.png", "023.png", "024.png", "025.png", "026.png", "027.png", "028.png", "029.png", "030.png",
"031.png", "032.png", "033.png", "034.png", "035.png", "036.png", "037.png", "038.png", "039.png", "040.png",
"041.png", "042.png", "043.png", "044.png", "045.png", "046.png", "047.png", "048.png", "049.png", "050.png",
"051.png", "052.png", "053.png", "054.png", "055.png", "056.png", "057.png", "058.png", "059.png", "060.png",
"061.png", "062.png", "063.png", "064.png", "065.png", "066.png", "067.png", "068.png", "069.png", "070.png",
"071.png", "072.png", "073.png", "074.png", "075.png", "076.png", "077.png", "078.png", "079.png", "080.png",
"081.png", "082.png", "083.png", "084.png", "085.png", "086.png", "087.png", "088.png", "089.png", "090.png",
"091.png", "092.png", "093.png", "094.png", "095.png", "096.png", "097.png", "098.png", "099.png", "100.png",
"101.png"
};
Glib::RefPtr<Gdk::Pixbuf> PannerInterface::_knob_image[101];
Glib::RefPtr<Gdk::Pixbuf>
PannerInterface::load_pixbuf (const std::string& name)
{
PBD::Searchpath spath(ARDOUR::ardour_data_search_path());
spath.add_subdirectory_to_paths("icons/stereo_panner");
std::string data_file_path;
if (!PBD::find_file_in_search_path (spath, name, data_file_path)) {
PBD::fatal << string_compose (_("cannot find icon image for %1 using %2"), name, spath.to_string()) << endmsg;
}
Glib::RefPtr<Gdk::Pixbuf> img;
try {
img = Gdk::Pixbuf::create_from_file (data_file_path);
} catch (const Gdk::PixbufError &e) {
cerr << "Caught PixbufError: " << e.what() << endl;
} catch (...) {
PBD::error << string_compose (_("Caught exception while loading icon named %1"), name) << endmsg;
}
return img;
}
PannerInterface::PannerInterface (boost::shared_ptr<Panner> p)
: _panner (p)
, _tooltip (this)
, _editor (0)
{
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);
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);
}
PannerInterface::~PannerInterface ()

View file

@ -65,8 +65,8 @@ protected:
void value_change ();
bool on_enter_notify_event (GdkEventCrossing *);
bool on_leave_notify_event (GdkEventCrossing *);
bool on_enter_notify_event (GdkEventCrossing *);
bool on_leave_notify_event (GdkEventCrossing *);
bool on_key_release_event (GdkEventKey *);
bool on_button_press_event (GdkEventButton*);
bool on_button_release_event (GdkEventButton*);
@ -74,6 +74,10 @@ protected:
boost::shared_ptr<ARDOUR::Panner> _panner;
PannerPersistentTooltip _tooltip;
static Glib::RefPtr<Gdk::Pixbuf> load_pixbuf (const std::string& name);
static Glib::RefPtr<Gdk::Pixbuf> _knob_image[101];
static const char* _knob_image_files[101];
private:
virtual PannerEditor* editor () = 0;
PannerEditor* _editor;

View file

@ -61,10 +61,10 @@ PannerUI::PannerUI (Session* s)
pan_astate_menu = 0;
pan_astyle_menu = 0;
in_pan_update = false;
_stereo_panner = 0;
_stereo_panner = 0;
_mono_panner = 0;
_ignore_width_change = false;
_ignore_position_change = false;
_ignore_width_change = false;
_ignore_position_change = false;
pan_automation_style_button.set_name ("MixerAutomationModeButton");
pan_automation_state_button.set_name ("MixerAutomationPlaybackButton");
@ -93,8 +93,8 @@ PannerUI::PannerUI (Session* s)
void
PannerUI::set_panner (boost::shared_ptr<PannerShell> ps, boost::shared_ptr<Panner> p)
{
/* note that the panshell might not change here (i.e. ps == _panshell)
*/
/* note that the panshell might not change here (i.e. ps == _panshell)
*/
connections.drop_connections ();
@ -104,17 +104,17 @@ PannerUI::set_panner (boost::shared_ptr<PannerShell> ps, boost::shared_ptr<Panne
delete pan_astate_menu;
pan_astate_menu = 0;
_panshell = ps;
_panshell = ps;
_panner = p;
delete twod_panner;
twod_panner = 0;
delete _stereo_panner;
_stereo_panner = 0;
delete _stereo_panner;
_stereo_panner = 0;
delete _mono_panner;
_mono_panner = 0;
delete _mono_panner;
_mono_panner = 0;
if (!_panner) {
return;
@ -122,13 +122,13 @@ PannerUI::set_panner (boost::shared_ptr<PannerShell> ps, boost::shared_ptr<Panne
_panshell->Changed.connect (connections, invalidator (*this), boost::bind (&PannerUI::panshell_changed, this), gui_context());
/* new panner object, force complete reset of panner GUI
*/
/* new panner object, force complete reset of panner GUI
*/
_current_nouts = 0;
_current_nins = 0;
_current_nouts = 0;
_current_nins = 0;
setup_pan ();
setup_pan ();
update_pan_sensitive ();
pan_automation_state_changed ();
}
@ -198,8 +198,8 @@ PannerUI::~PannerUI ()
delete pan_menu;
delete pan_astyle_menu;
delete pan_astate_menu;
delete _stereo_panner;
delete _mono_panner;
delete _stereo_panner;
delete _mono_panner;
}
void
@ -250,8 +250,8 @@ PannerUI::setup_pan ()
boost::shared_ptr<Pannable> pannable = _panner->pannable();
_stereo_panner = new StereoPanner (_panshell);
_stereo_panner->set_size_request (-1, pan_bar_height);
pan_vbox.pack_start (*_stereo_panner, false, false);
// _stereo_panner->set_size_request (-1, pan_bar_height);
pan_vbox.pack_start (*_stereo_panner, true, true);
boost::shared_ptr<AutomationControl> ac;
@ -285,10 +285,10 @@ PannerUI::setup_pan ()
_mono_panner->signal_button_release_event().connect (sigc::mem_fun(*this, &PannerUI::pan_button_event));
_mono_panner->set_size_request (-1, pan_bar_height);
// _mono_panner->set_size_request (-1, pan_bar_height);
update_pan_sensitive ();
pan_vbox.pack_start (*_mono_panner, false, false);
pan_vbox.pack_start (*_mono_panner, true, true);
}
else if (_current_uri == "http://ardour.org/plugin/panner_vbap#ui")
{

View file

@ -50,17 +50,6 @@ using namespace std;
using namespace Gtk;
using namespace Gtkmm2ext;
static const int pos_box_size = 8;
static const int lr_box_size = 15;
static const int step_down = 10;
static const int top_step = 2;
StereoPanner::ColorScheme StereoPanner::colors[3];
bool StereoPanner::have_colors = false;
Pango::AttrList StereoPanner::panner_font_attributes;
bool StereoPanner::have_font = false;
using namespace ARDOUR;
StereoPanner::StereoPanner (boost::shared_ptr<PannerShell> p)
@ -79,20 +68,10 @@ StereoPanner::StereoPanner (boost::shared_ptr<PannerShell> p)
, width_binder (width_control)
, _dragging (false)
{
if (!have_colors) {
set_colors ();
have_colors = true;
}
if (!have_font) {
Pango::FontDescription font;
Pango::AttrFontDesc* font_attr;
font = Pango::FontDescription ("ArdourMono");
font.set_weight (Pango::WEIGHT_BOLD);
font.set_size(9 * PANGO_SCALE);
font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font));
panner_font_attributes.change(*font_attr);
delete font_attr;
have_font = true;
if (_knob_image[0] == 0) {
for (size_t i=0; i < (sizeof(_knob_image)/sizeof(_knob_image[0])); i++) {
_knob_image[i] = load_pixbuf (_knob_image_files[i]);
}
}
position_control->Changed.connect (panvalue_connections, invalidator(*this), boost::bind (&StereoPanner::value_change, this), gui_context());
@ -101,8 +80,6 @@ StereoPanner::StereoPanner (boost::shared_ptr<PannerShell> p)
_panner_shell->Changed.connect (panshell_connections, invalidator (*this), boost::bind (&StereoPanner::bypass_handler, this), gui_context());
_panner_shell->PannableChanged.connect (panshell_connections, invalidator (*this), boost::bind (&StereoPanner::pannable_handler, this), gui_context());
ColorsChanged.connect (sigc::mem_fun (*this, &StereoPanner::color_handler));
set_tooltip ();
}
@ -138,155 +115,16 @@ StereoPanner::set_tooltip ()
bool
StereoPanner::on_expose_event (GdkEventExpose*)
{
Glib::RefPtr<Gdk::Window> win (get_window());
Glib::RefPtr<Gdk::GC> gc (get_style()->get_base_gc (get_state()));
Cairo::RefPtr<Cairo::Context> context = get_window()->create_cairo_context();
Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create(get_pango_context());
layout->set_attributes (panner_font_attributes);
unsigned pos = (unsigned)(rint (100.0 * position_control->get_value ())); /* 0..100 */
int tw, th;
int width, height;
const double pos = position_control->get_value (); /* 0..1 */
const double swidth = width_control->get_value (); /* -1..+1 */
const double fswidth = fabs (swidth);
const double corner_radius = 5.0;
uint32_t o, f, t, b, r;
State state;
double x = (get_width() - _knob_image[pos]->get_width())/2.0;
double y = (get_height() - _knob_image[pos]->get_height())/2.0;
width = get_width();
height = get_height ();
if (swidth == 0.0) {
state = Mono;
} else if (swidth < 0.0) {
state = Inverted;
} else {
state = Normal;
}
o = colors[state].outline;
f = colors[state].fill;
t = colors[state].text;
b = colors[state].background;
r = colors[state].rule;
if (_panner_shell->bypassed()) {
b = 0x20202040;
f = 0x404040ff;
o = 0x606060ff;
t = 0x606060ff;
r = 0x606060ff;
}
/* background */
context->set_source_rgba (UINT_RGBA_R_FLT(b), UINT_RGBA_G_FLT(b), UINT_RGBA_B_FLT(b), UINT_RGBA_A_FLT(b));
cairo_rectangle (context->cobj(), 0, 0, width, height);
context->fill_preserve ();
context->clip();
/* 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;
context->translate (1.0, 0.0);
}
const double half_lr_box = lr_box_size/2.0;
const double center = rint(half_lr_box + (usable_width * pos));
const double pan_spread = rint((fswidth * (usable_width-1.0))/2.0);
const double left = center - pan_spread;
const double right = center + pan_spread;
/* center line */
context->set_line_width (1.0);
context->move_to ((usable_width + lr_box_size)/2.0, 0);
context->rel_line_to (0, height);
context->set_source_rgba (UINT_RGBA_R_FLT(r), UINT_RGBA_G_FLT(r), UINT_RGBA_B_FLT(r), UINT_RGBA_A_FLT(r));
context->stroke ();
/* compute & draw the line through the box */
context->set_line_width (2);
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->move_to (left, top_step + (pos_box_size/2.0) + step_down + 1.0);
context->line_to (left, top_step + (pos_box_size/2.0));
context->line_to (right, top_step + (pos_box_size/2.0));
context->line_to (right, top_step + (pos_box_size/2.0) + step_down + 1.0);
context->stroke ();
context->set_line_width (1.0);
/* left box */
if (state != Mono) {
rounded_rectangle (context, left - half_lr_box,
half_lr_box+step_down,
lr_box_size, lr_box_size, corner_radius);
context->set_source_rgba (UINT_RGBA_R_FLT(f), UINT_RGBA_G_FLT(f), UINT_RGBA_B_FLT(f), UINT_RGBA_A_FLT(f));
context->fill_preserve();
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->stroke();
/* add text */
context->set_source_rgba (UINT_RGBA_R_FLT(t), UINT_RGBA_G_FLT(t), UINT_RGBA_B_FLT(t), UINT_RGBA_A_FLT(t));
if (swidth < 0.0) {
layout->set_text (_("R"));
} else {
layout->set_text (_("L"));
}
layout->get_pixel_size(tw, th);
context->move_to (rint(left - tw/2), rint(lr_box_size + step_down - th/2));
pango_cairo_show_layout (context->cobj(), layout->gobj());
}
/* right box */
rounded_rectangle (context, right - half_lr_box,
half_lr_box+step_down,
lr_box_size, lr_box_size, corner_radius);
context->set_source_rgba (UINT_RGBA_R_FLT(f), UINT_RGBA_G_FLT(f), UINT_RGBA_B_FLT(f), UINT_RGBA_A_FLT(f));
context->fill_preserve();
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->stroke();
/* add text */
context->set_source_rgba (UINT_RGBA_R_FLT(t), UINT_RGBA_G_FLT(t), UINT_RGBA_B_FLT(t), UINT_RGBA_A_FLT(t));
if (state == Mono) {
layout->set_text (_("M"));
} else {
if (swidth < 0.0) {
layout->set_text (_("L"));
} else {
layout->set_text (_("R"));
}
}
layout->get_pixel_size(tw, th);
context->move_to (rint(right - tw/2), rint(lr_box_size + step_down - th/2));
pango_cairo_show_layout (context->cobj(), layout->gobj());
/* draw the central box */
context->set_line_width (2.0);
context->move_to (center + (pos_box_size/2.0), top_step); /* top right */
context->rel_line_to (0.0, pos_box_size); /* lower right */
context->rel_line_to (-pos_box_size/2.0, 4.0); /* bottom point */
context->rel_line_to (-pos_box_size/2.0, -4.0); /* lower left */
context->rel_line_to (0.0, -pos_box_size); /* upper left */
context->close_path ();
context->set_source_rgba (UINT_RGBA_R_FLT(o), UINT_RGBA_G_FLT(o), UINT_RGBA_B_FLT(o), UINT_RGBA_A_FLT(o));
context->stroke_preserve ();
context->set_source_rgba (UINT_RGBA_R_FLT(f), UINT_RGBA_G_FLT(f), UINT_RGBA_B_FLT(f), UINT_RGBA_A_FLT(f));
context->fill ();
cairo_rectangle (context->cobj(), x, y, _knob_image[pos]->get_width(), _knob_image[pos]->get_height());
gdk_cairo_set_source_pixbuf (context->cobj(), _knob_image[pos]->gobj(), x, y);
cairo_fill (context->cobj());
return true;
}
@ -405,19 +243,18 @@ StereoPanner::on_button_press_event (GdkEventButton* ev)
double pos = position_control->get_value (); /* 0..1 */
double swidth = width_control->get_value (); /* -1..+1 */
double fswidth = fabs (swidth);
int usable_width = get_width() - lr_box_size;
double center = (lr_box_size/2.0) + (usable_width * pos);
int usable_width = get_width();
double center = usable_width * pos;
int left = lrint (center - (fswidth * usable_width / 2.0)); // center of leftmost box
int right = lrint (center + (fswidth * usable_width / 2.0)); // center of rightmost box
const int half_box = lr_box_size/2;
if (ev->x >= (left - half_box) && ev->x < (left + half_box)) {
if (ev->x >= left && ev->x < left) {
if (swidth < 0.0) {
dragging_right = true;
} else {
dragging_left = true;
}
} else if (ev->x >= (right - half_box) && ev->x < (right + half_box)) {
} else if (ev->x >= right && ev->x < right) {
if (swidth < 0.0) {
dragging_left = true;
} else {
@ -522,7 +359,7 @@ StereoPanner::on_motion_notify_event (GdkEventMotion* ev)
return false;
}
int usable_width = get_width() - lr_box_size;
int usable_width = get_width();
double delta = (ev->x - last_drag_x) / (double) usable_width;
double current_width = width_control->get_value ();
@ -660,35 +497,6 @@ StereoPanner::on_key_press_event (GdkEventKey* ev)
return true;
}
void
StereoPanner::set_colors ()
{
colors[Normal].fill = ARDOUR_UI::config()->get_canvasvar_StereoPannerFill();
colors[Normal].outline = ARDOUR_UI::config()->get_canvasvar_StereoPannerOutline();
colors[Normal].text = ARDOUR_UI::config()->get_canvasvar_StereoPannerText();
colors[Normal].background = ARDOUR_UI::config()->get_canvasvar_StereoPannerBackground();
colors[Normal].rule = ARDOUR_UI::config()->get_canvasvar_StereoPannerRule();
colors[Mono].fill = ARDOUR_UI::config()->get_canvasvar_StereoPannerMonoFill();
colors[Mono].outline = ARDOUR_UI::config()->get_canvasvar_StereoPannerMonoOutline();
colors[Mono].text = ARDOUR_UI::config()->get_canvasvar_StereoPannerMonoText();
colors[Mono].background = ARDOUR_UI::config()->get_canvasvar_StereoPannerMonoBackground();
colors[Mono].rule = ARDOUR_UI::config()->get_canvasvar_StereoPannerRule();
colors[Inverted].fill = ARDOUR_UI::config()->get_canvasvar_StereoPannerInvertedFill();
colors[Inverted].outline = ARDOUR_UI::config()->get_canvasvar_StereoPannerInvertedOutline();
colors[Inverted].text = ARDOUR_UI::config()->get_canvasvar_StereoPannerInvertedText();
colors[Inverted].background = ARDOUR_UI::config()->get_canvasvar_StereoPannerInvertedBackground();
colors[Inverted].rule = ARDOUR_UI::config()->get_canvasvar_StereoPannerRule();
}
void
StereoPanner::color_handler ()
{
set_colors ();
queue_draw ();
}
void
StereoPanner::bypass_handler ()
{

View file

@ -55,54 +55,39 @@ class StereoPanner : public PannerInterface
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_scroll_event (GdkEventScroll*);
bool on_key_press_event (GdkEventKey*);
private:
PannerEditor* editor ();
boost::shared_ptr<ARDOUR::PannerShell> _panner_shell;
boost::shared_ptr<PBD::Controllable> position_control;
boost::shared_ptr<PBD::Controllable> width_control;
PBD::ScopedConnectionList panvalue_connections;
PBD::ScopedConnectionList panshell_connections;
bool dragging;
bool dragging_position;
bool dragging_left;
bool dragging_right;
int drag_start_x;
int last_drag_x;
double accumulated_delta;
bool detented;
boost::shared_ptr<PBD::Controllable> position_control;
boost::shared_ptr<PBD::Controllable> width_control;
PBD::ScopedConnectionList panvalue_connections;
PBD::ScopedConnectionList panshell_connections;
bool dragging;
bool dragging_position;
bool dragging_left;
bool dragging_right;
int drag_start_x;
int last_drag_x;
double accumulated_delta;
bool detented;
BindingProxy position_binder;
BindingProxy width_binder;
BindingProxy position_binder;
BindingProxy width_binder;
void set_tooltip ();
void set_tooltip ();
struct ColorScheme {
uint32_t outline;
uint32_t fill;
uint32_t text;
uint32_t background;
uint32_t rule;
};
enum State {
Normal,
Mono,
Inverted
};
enum State {
Normal,
Mono,
Inverted
};
bool _dragging;
static Pango::AttrList panner_font_attributes;
static bool have_font;
static ColorScheme colors[3];
static void set_colors ();
static bool have_colors;
void color_handler ();
void bypass_handler ();
void pannable_handler ();
};