partial patch/partial by-hand merge of 2.X commits 3169&3170 to 3.X codebase

git-svn-id: svn://localhost/ardour2/branches/3.0@4300 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2008-12-08 16:07:28 +00:00
parent a9bb336fc4
commit 3be16e8afb
35 changed files with 1399 additions and 932 deletions

View File

@ -194,6 +194,7 @@ lineset.cc
location_ui.cc
main.cc
marker.cc
matrix.cc
midi_channel_selector.cc
midi_port_dialog.cc
midi_region_view.cc

View File

@ -1736,8 +1736,8 @@ ARDOUR_UI::engine_halted ()
_("\
JACK has either been shutdown or it\n\
disconnected Ardour because Ardour\n\
was not fast enough. You can save the\n\
session and/or try to reconnect to JACK ."));
was not fast enough. Try to restart\n\
JACK, reconnect and save the session."));
pop_back_splash ();
msg.run ();
}

View File

@ -196,6 +196,10 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
setup_fade_handle_positions ();
if (!Config->get_show_region_fades()) {
set_fade_visibility (false);
}
string line_name = _region->name();
line_name += ':';
line_name += "gain";
@ -410,8 +414,10 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
fade_in_handle->hide();
fade_out_handle->hide();
} else {
fade_in_handle->show();
fade_out_handle->show();
if (Config->get_show_region_fades()) {
fade_in_handle->show();
fade_out_handle->show();
}
}
}
}

View File

@ -294,6 +294,7 @@ class Editor : public PublicEditor
Width editor_mixer_strip_width;
void maybe_add_mixer_strip_width (XMLNode&);
void show_editor_mixer (bool yn);
void create_editor_mixer ();
void show_editor_list (bool yn);
void set_selected_mixer_strip (TimeAxisView&);
void hide_track_in_display (TimeAxisView& tv, bool temporary = false);

View File

@ -57,13 +57,6 @@ Editor::editor_list_button_toggled ()
}
}
void
Editor::cms_new (boost::shared_ptr<ARDOUR::Route> r)
{
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(), *session, r);
current_mixer_strip->GoingAway.connect (mem_fun (*this, &Editor::cms_deleted));
}
void
Editor::cms_deleted ()
{
@ -73,77 +66,109 @@ Editor::cms_deleted ()
void
Editor::show_editor_mixer (bool yn)
{
boost::shared_ptr<ARDOUR::Route> r;
show_editor_mixer_when_tracks_arrive = false;
if (!session) {
show_editor_mixer_when_tracks_arrive = yn;
return;
}
if (yn) {
if (current_mixer_strip == 0) {
if (selection->tracks.empty()) {
if (track_views.empty()) {
show_editor_mixer_when_tracks_arrive = true;
return;
}
if (selection->tracks.empty()) {
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
AudioTimeAxisView* atv;
if (track_views.empty()) {
show_editor_mixer_when_tracks_arrive = true;
return;
}
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
cms_new (atv->route ());
break;
}
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
r = atv->route();
break;
}
} else {
sort_track_selection ();
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
cms_new (atv->route ());
break;
}
}
}
} else {
sort_track_selection ();
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
r = atv->route();
break;
}
}
}
if (r) {
bool created;
if (current_mixer_strip == 0) {
return;
}
create_editor_mixer ();
created = true;
} else {
created = false;
}
current_mixer_strip->set_route (r);
if (created) {
current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
}
}
if (current_mixer_strip->get_parent() == 0) {
current_mixer_strip->set_embedded (true);
current_mixer_strip->Hiding.connect (mem_fun(*this, &Editor::current_mixer_strip_hidden));
current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::current_mixer_strip_removed));
current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
global_hpacker.pack_start (*current_mixer_strip, Gtk::PACK_SHRINK );
global_hpacker.reorder_child (*current_mixer_strip, 0);
current_mixer_strip->show_all ();
}
} else {
if (current_mixer_strip) {
editor_mixer_strip_width = current_mixer_strip->get_width ();
if (current_mixer_strip->get_parent() != 0) {
global_hpacker.remove (*current_mixer_strip);
}
}
}
#ifdef GTKOSX
/* XXX gtk problem here */
ruler_label_event_box.queue_draw ();
time_button_event_box.queue_draw ();
controls_layout.queue_draw ();
ensure_all_elements_drawn();
#endif
}
#ifdef GTKOSX
void
Editor::ensure_all_elements_drawn ()
{
controls_layout.queue_draw ();
ruler_label_event_box.queue_draw ();
time_button_event_box.queue_draw ();
}
#endif
void
Editor::create_editor_mixer ()
{
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
*session,
false);
current_mixer_strip->Hiding.connect (mem_fun(*this, &Editor::current_mixer_strip_hidden));
current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::current_mixer_strip_removed));
#ifdef GTKOSX
current_mixer_strip->WidthChanged.connect (mem_fun(*this, &Editor::ensure_all_elements_drawn));
#endif
current_mixer_strip->set_embedded (true);
}
void
Editor::show_editor_list (bool yn)
{
@ -157,38 +182,52 @@ Editor::show_editor_list (bool yn)
void
Editor::set_selected_mixer_strip (TimeAxisView& view)
{
RouteTimeAxisView* rt;
AudioTimeAxisView* at;
bool show = false;
bool created;
if (!session || (rt = dynamic_cast<RouteTimeAxisView*>(&view)) == 0) {
if (!session || (at = dynamic_cast<AudioTimeAxisView*>(&view)) == 0) {
return;
}
Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
if (act) {
Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(act);
if (!tact || !tact->get_active()) {
/* not showing mixer strip presently */
return;
}
}
if (current_mixer_strip == 0) {
create_editor_mixer ();
created = true;
} else {
created = false;
}
/* might be nothing to do */
if (current_mixer_strip->route() == at->route()) {
return;
}
if (current_mixer_strip) {
/* might be nothing to do */
if (current_mixer_strip->route() == rt->route()) {
return;
}
if (current_mixer_strip->get_parent()) {
show = true;
}
delete current_mixer_strip;
current_mixer_strip = 0;
if (current_mixer_strip->get_parent()) {
show = true;
}
current_mixer_strip->set_route (at->route());
if (created) {
current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
}
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
*session,
rt->route(), false);
current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::cms_deleted));
if (show) {
show_editor_mixer (true);
}
}
double current = 0.0;
bool currentInitialized = 0;
@ -276,7 +315,7 @@ void
Editor::current_mixer_strip_removed ()
{
if (current_mixer_strip) {
/* it is being deleted */
/* it is being deleted elsewhere */
current_mixer_strip = 0;
}
}

View File

@ -72,17 +72,18 @@ GainMeter::setup_slider_pix ()
}
}
GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
GainMeterBase::GainMeterBase (Session& s,
const Glib::RefPtr<Gdk::Pixbuf>& pix,
bool horizontal)
: _io (io),
_session (s),
: _session (s),
// 0.781787 is the value needed for gain to be set to 0.
gain_adjustment (0.781787, 0.0, 1.0, 0.01, 0.1),
gain_automation_style_button (""),
gain_automation_state_button ("")
{
using namespace Menu_Helpers;
ignore_toggle = false;
meter_menu = 0;
next_release_selects = false;
@ -92,16 +93,14 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
if (horizontal) {
gain_slider = manage (new HSliderController (pix,
&gain_adjustment,
_io->gain_control(),
false));
} else {
gain_slider = manage (new VSliderController (pix,
&gain_adjustment,
_io->gain_control(),
false));
}
level_meter = new LevelMeter(_io, _session);
level_meter = new LevelMeter(_session);
gain_slider->signal_button_press_event().connect (mem_fun(*this, &GainMeter::start_gain_touch));
gain_slider->signal_button_release_event().connect (mem_fun(*this, &GainMeter::end_gain_touch));
@ -133,10 +132,40 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
gain_automation_state_button.set_size_request(15, 15);
gain_automation_style_button.set_size_request(15, 15);
gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
gain_astate_menu.set_name ("ArdourContextMenu");
gain_astyle_menu.set_name ("ArdourContextMenu");
gain_adjustment.signal_value_changed().connect (mem_fun(*this, &GainMeterBase::gain_adjusted));
peak_display.signal_button_release_event().connect (mem_fun(*this, &GainMeterBase::peak_button_release), false);
gain_display.signal_key_press_event().connect (mem_fun(*this, &GainMeterBase::gain_key_press), false);
ResetAllPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_peak_display));
ResetGroupPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_group_peak_display));
UI::instance()->theme_changed.connect (mem_fun(*this, &GainMeterBase::on_theme_changed));
ColorsChanged.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), false));
DPIReset.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), true));
}
GainMeterBase::~GainMeterBase ()
{
delete meter_menu;
delete level_meter;
}
void
GainMeterBase::set_io (boost::shared_ptr<IO> io)
{
connections.clear ();
_io = io;
level_meter->set_io (_io);
gain_slider->set_controllable (_io->gain_control());
boost::shared_ptr<Route> r;
@ -146,6 +175,8 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
using namespace Menu_Helpers;
gain_astate_menu.items().clear ();
gain_astate_menu.items().push_back (MenuElem (_("Manual"),
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Off)));
@ -159,50 +190,21 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Touch)));
gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
connections.push_back (gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false));
connections.push_back (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false));
gain_astate_menu.set_name ("ArdourContextMenu");
gain_astyle_menu.set_name ("ArdourContextMenu");
gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false);
gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false);
r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed));
r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed));
connections.push_back (r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed)));
connections.push_back (r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed)));
gain_automation_state_changed ();
}
}
_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed));
gain_adjustment.signal_value_changed().connect (mem_fun(*this, &GainMeterBase::gain_adjusted));
peak_display.signal_button_release_event().connect (mem_fun(*this, &GainMeterBase::peak_button_release), false);
gain_display.signal_key_press_event().connect (mem_fun(*this, &GainMeterBase::gain_key_press), false);
connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed)));
gain_changed ();
show_gain ();
update_gain_sensitive ();
ResetAllPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_peak_display));
ResetGroupPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_group_peak_display));
UI::instance()->theme_changed.connect (mem_fun(*this, &GainMeterBase::on_theme_changed));
ColorsChanged.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), false));
DPIReset.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), true));
}
GainMeterBase::~GainMeterBase ()
{
if (meter_menu) {
delete meter_menu;
}
if (level_meter) {
delete level_meter;
}
}
void
@ -752,10 +754,9 @@ GainMeterBase::on_theme_changed()
style_changed = true;
}
GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
: GainMeterBase (io, s, slider, false)
GainMeter::GainMeter (Session& s)
: GainMeterBase (s, slider, false)
{
gain_display_box.set_homogeneous (true);
gain_display_box.set_spacing (2);
gain_display_box.pack_start (gain_display, true, true);
@ -785,6 +786,31 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
hbox.set_spacing (2);
hbox.pack_start (*fader_vbox, true, true);
set_spacing (2);
pack_start (gain_display_box, Gtk::PACK_SHRINK);
pack_start (hbox, Gtk::PACK_SHRINK);
meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose));
}
void
GainMeter::set_io (boost::shared_ptr<IO> io)
{
if (level_meter->get_parent()) {
hbox.remove (*level_meter);
}
if (peak_display.get_parent()) {
gain_display_box.remove (peak_display);
}
if (gain_automation_state_button.get_parent()) {
fader_vbox->remove (gain_automation_state_button);
}
GainMeterBase::set_io (io);
boost::shared_ptr<Route> r;
if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
@ -801,16 +827,8 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
}
}
set_spacing (2);
pack_start (gain_display_box, Gtk::PACK_SHRINK);
pack_start (hbox, Gtk::PACK_SHRINK);
meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose));
}
int
GainMeter::get_gm_width ()
{

View File

@ -58,10 +58,12 @@ namespace Gtk {
class GainMeterBase : virtual public sigc::trackable
{
public:
GainMeterBase (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&, const Glib::RefPtr<Gdk::Pixbuf>& pix,
GainMeterBase ( ARDOUR::Session&, const Glib::RefPtr<Gdk::Pixbuf>& pix,
bool horizontal);
virtual ~GainMeterBase ();
virtual void set_io (boost::shared_ptr<ARDOUR::IO>);
void update_gain_sensitive ();
void update_meters ();
@ -82,6 +84,7 @@ class GainMeterBase : virtual public sigc::trackable
friend class MixerStrip;
boost::shared_ptr<ARDOUR::IO> _io;
ARDOUR::Session& _session;
std::vector<sigc::connection> connections;
bool ignore_toggle;
bool next_release_selects;
@ -169,9 +172,11 @@ class GainMeterBase : virtual public sigc::trackable
class GainMeter : public GainMeterBase, public Gtk::VBox
{
public:
GainMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&);
GainMeter (ARDOUR::Session&);
~GainMeter () {}
void set_io (boost::shared_ptr<ARDOUR::IO>);
int get_gm_width ();
void setup_meters (int len=0);

View File

@ -58,9 +58,8 @@ using namespace std;
//sigc::signal<void,RouteGroup*> LevelMeter::ResetGroupPeakDisplays;
LevelMeter::LevelMeter (boost::shared_ptr<IO> io, Session& s)
: _io (io),
_session (s)
LevelMeter::LevelMeter (Session& s)
: _session (s)
{
set_spacing (1);
@ -85,6 +84,12 @@ LevelMeter::~LevelMeter ()
}
}
void
LevelMeter::set_io (boost::shared_ptr<IO> io)
{
_io = io;
}
float
LevelMeter::update_meters ()
{
@ -144,6 +149,10 @@ LevelMeter::hide_all_meters ()
void
LevelMeter::setup_meters (int len, int initial_width)
{
if (!_io) {
return; /* do it later */
}
uint32_t nmeters = _io->n_outputs().n_total();
regular_meter_width = initial_width;

View File

@ -56,9 +56,11 @@ namespace Gtk {
class LevelMeter : public Gtk::HBox
{
public:
LevelMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&);
LevelMeter (ARDOUR::Session&);
~LevelMeter ();
virtual void set_io (boost::shared_ptr<ARDOUR::IO> io);
void update_gain_sensitive ();
float update_meters ();

View File

@ -117,7 +117,10 @@ fixup_bundle_environment ()
Glib::ustring path;
const char *cstr = getenv ("PATH");
/* ensure that we find any bundled executables (e.g. JACK) */
/* ensure that we find any bundled executables (e.g. JACK),
and find them before any instances of the same name
elsewhere in PATH
*/
path = dir_path;
if (cstr) {
@ -152,8 +155,10 @@ fixup_bundle_environment ()
if (cstr) {
path = cstr;
path += ':';
} else {
path = "";
}
path = dir_path;
path += dir_path;
path += "/../Plugins";
setenv ("LADSPA_PATH", path.c_str(), 1);
@ -162,8 +167,10 @@ fixup_bundle_environment ()
if (cstr) {
path = cstr;
path += ':';
} else {
path = "";
}
path = dir_path;
path += dir_path;
path += "/../Frameworks";
setenv ("VAMP_PATH", path.c_str(), 1);
@ -172,8 +179,10 @@ fixup_bundle_environment ()
if (cstr) {
path = cstr;
path += ':';
} else {
path = "";
}
path = dir_path;
path += dir_path;
path += "/../Surfaces";
setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
@ -182,8 +191,10 @@ fixup_bundle_environment ()
if (cstr) {
path = cstr;
path += ':';
} else {
path = "";
}
path = dir_path;
path += dir_path;
path += "/../Plugins";
setenv ("LV2_PATH", path.c_str(), 1);

427
gtk2_ardour/matrix.cc Normal file
View File

@ -0,0 +1,427 @@
#include <gtkmm.h>
#include <cairo/cairo.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <stdint.h>
#include <cmath>
#include <map>
#include <vector>
#include "matrix.h"
using namespace std;
using namespace Gtk;
using namespace ARDOUR;
Matrix::Matrix ()
{
alloc_width = 0;
alloc_height = 0;
line_width = 0;
line_height = 0;
labels_y_shift = 0;
labels_x_shift = 0;
arc_radius = 0;
xstep = 0;
ystep = 0;
pixmap = 0;
drawn = false;
angle_radians = M_PI/4.0;
motion_x = -1;
motion_y = -1;
add_events (Gdk::POINTER_MOTION_MASK|Gdk::LEAVE_NOTIFY_MASK);
}
void
Matrix::set_ports (const list<string>& ports)
{
ours = ports;
reset_size ();
}
void
Matrix::add_group (PortGroup& pg)
{
for (vector<string>::const_iterator s = pg.ports.begin(); s != pg.ports.end(); ++s) {
others.push_back (OtherPort (*s, pg));
}
reset_size ();
}
void
Matrix::remove_group (PortGroup& pg)
{
for (list<OtherPort>::iterator o = others.begin(); o != others.end(); ) {
if (&(*o).group() == &pg) {
o = others.erase (o);
} else {
++o;
}
}
reset_size ();
}
void
Matrix::hide_group (PortGroup& pg)
{
reset_size();
}
void
Matrix::show_group (PortGroup& pg)
{
reset_size ();
}
void
Matrix::setup_nodes ()
{
int n, x, y;
list<string>::iterator m;
list<OtherPort>::iterator s;
for (vector<MatrixNode*>::iterator p = nodes.begin(); p != nodes.end(); ++p) {
delete *p;
}
nodes.clear ();
list<OtherPort>::size_type visible_others = 0;
for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
if ((*s).visible()) {
++visible_others;
}
}
nodes.assign (ours.size() * visible_others, 0);
for (n = 0, y = 0, m = ours.begin(); m != ours.end(); ++m, ++y) {
for (x = 0, s = others.begin(); s != others.end(); ++s) {
if ((*s).visible()) {
nodes[n] = new MatrixNode (*m, *s, x, y);
n++;
x++;
}
}
}
}
void
Matrix::reset_size ()
{
list<OtherPort>::size_type visible_others = 0;
for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
if ((*s).visible()) {
++visible_others;
}
}
border = 10;
if (alloc_width > line_width) {
xstep = (alloc_width - labels_x_shift - (2 * border) - (2 * arc_radius)) / visible_others;
line_width = xstep * (others.size() - 1);
ystep = (alloc_height - labels_y_shift - (2 * border) - (2 * arc_radius)) / (ours.size() - 1);
line_height = ystep * (ours.size() - 1);
} else {
xstep = 20;
ystep = 20;
line_height = (ours.size() - 1) * ystep;
line_width = visible_others * xstep;
}
int half_step = min (ystep/2,xstep/2);
if (half_step > 3) {
arc_radius = half_step - 5;
} else {
arc_radius = 3;
}
arc_radius = min (arc_radius, 10);
/* scan all the port names that will be rotated, and compute
how much space we need for them
*/
float w = 0;
float w1;
float h = 0;
cairo_text_extents_t extents;
cairo_t* cr;
GdkPixmap* pm;
pm = gdk_pixmap_new (NULL, 1, 1, 24);
gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
cr = gdk_cairo_create (pm);
for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
if ((*s).visible()) {
cairo_text_extents (cr, (*s).name().c_str(), &extents);
w = max ((float) extents.width, w);
h = max ((float) extents.height, h);
}
}
cairo_destroy (cr);
gdk_pixmap_unref (pm);
/* transform */
w = fabs (w * cos (angle_radians) + h * sin (angle_radians));
h = fabs (w * sin (angle_radians) + h * cos (angle_radians));
labels_y_shift = (int) ceil (h) + 10;
labels_x_shift = (int) ceil (w);
setup_nodes ();
}
bool
Matrix::on_motion_notify_event (GdkEventMotion* ev)
{
motion_x = ev->x;
motion_y = ev->y;
queue_draw ();
return false;
}
bool
Matrix::on_leave_notify_event (GdkEventCrossing *ev)
{
motion_x = -1;
motion_y = -1;
queue_draw ();
return false;
}
void
Matrix::on_size_request (Requisition* req)
{
req->width = labels_x_shift + line_width + (2*border) + (2*arc_radius);
req->height = labels_y_shift + line_height + (2*border) + (2*arc_radius);
}
MatrixNode*
Matrix::get_node (int32_t x, int32_t y)
{
int half_xstep = xstep / 2;
int half_ystep = ystep / 2;
x -= labels_x_shift - border;
if (x < half_xstep) {
return 0;
}
y -= labels_y_shift - border;
if (y < half_ystep) {
return 0;
}
x = (x - half_xstep) / xstep;
y = (y - half_ystep) / ystep;
x = y*ours.size() + x;
if (x >= nodes.size()) {
return 0;
}
return nodes[x];
}
bool
Matrix::on_button_press_event (GdkEventButton* ev)
{
MatrixNode* node;
if ((node = get_node (ev->x, ev->y)) != 0) {
cerr << "Event in node " << node->our_name() << " x " << node->their_name () << endl;
node->set_connected (!node->connected());
drawn = false;
queue_draw();
}
}
void
Matrix::alloc_pixmap ()
{
if (pixmap) {
gdk_pixmap_unref (pixmap);
}
pixmap = gdk_pixmap_new (get_window()->gobj(),
alloc_width,
alloc_height,
-1);
drawn = false;
}
void
Matrix::on_size_allocate (Allocation& alloc)
{
EventBox::on_size_allocate (alloc);
alloc_width = alloc.get_width();
alloc_height = alloc.get_height();
if (is_realized()) {
alloc_pixmap ();
reset_size ();
#ifdef MATRIX_USE_BACKING_PIXMAP
redraw (pixmap, 0, 0, alloc_width, alloc_height);
#endif
}
}
void
Matrix::on_realize ()
{
EventBox::on_realize ();
alloc_pixmap ();
}
void
Matrix::redraw (GdkDrawable* drawable, GdkRectangle* rect)
{
list<string>::iterator o;
list<OtherPort>::iterator t;
int x, y;
uint32_t top_shift, bottom_shift, left_shift, right_shift;
cairo_t* cr;
cr = gdk_cairo_create (drawable);
cairo_set_source_rgb (cr, 0.83, 0.83, 0.83);
cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
cairo_fill (cr);
cairo_set_line_width (cr, 0.5);
top_shift = labels_y_shift + border;
left_shift = labels_x_shift + border;
bottom_shift = 0;
right_shift = 0;
/* horizontal grid lines and side labels */
for (y = top_shift, o = ours.begin(); o != ours.end(); ++o, y += ystep) {
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_move_to (cr, left_shift, y);
cairo_line_to (cr, left_shift+line_width, y);
cairo_stroke (cr);
#if 0
cairo_text_extents_t extents;
cairo_text_extents (cr, (*o).c_str(),&extents);
cairo_move_to (cr, border, y+extents.height/2);
cairo_show_text (cr, (*o).c_str());
#endif
}
/* vertical grid lines and rotated labels*/
for (x = left_shift, t = others.begin(); t != others.end(); ++t, x += xstep) {
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_move_to (cr, x, top_shift);
cairo_line_to (cr, x, top_shift+line_height);
cairo_stroke (cr);
cairo_move_to (cr, x-left_shift+12, border);
cairo_set_source_rgb (cr, 0, 0, 1.0);
cairo_save (cr);
cairo_rotate (cr, angle_radians);
cairo_show_text (cr, (*t).name().c_str());
cairo_restore (cr);
}
/* nodes */
for (vector<MatrixNode*>::iterator n = nodes.begin(); n != nodes.end(); ++n) {
x = (*n)->x() * xstep;
y = (*n)->y() * ystep;
cairo_new_path (cr);
if (arc_radius) {
cairo_arc (cr, left_shift+x, top_shift+y, arc_radius, 0, 2.0 * M_PI);
if ((*n)->connected()) {
cairo_set_source_rgba (cr, 1.0, 0, 0, 1.0);
cairo_stroke (cr);
} else {
cairo_set_source_rgba (cr, 1.0, 0, 0, 0.7);
cairo_fill (cr);
}
}
}
/* motion indicators */
if (motion_x >= left_shift && motion_y >= top_shift) {
int col_left = left_shift + ((motion_x - left_shift) / xstep) * xstep;
int row_top = top_shift + ((motion_y - top_shift) / ystep) * ystep;
cairo_set_line_width (cr, 5);
cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.3);
/* horizontal (row) */
cairo_line_to (cr, left_shift, row_top);
cairo_line_to (cr, left_shift + line_width, row_top);
cairo_stroke (cr);
/* vertical (col) */
cairo_move_to (cr, col_left, top_shift);
cairo_line_to (cr, col_left, top_shift + line_height);
cairo_stroke (cr);
}
cairo_destroy (cr);
#ifdef MATRIX_USE_BACKING_PIXMAP
drawn = true;
#endif
}
bool
Matrix::on_expose_event (GdkEventExpose* event)
{
#ifdef MATRIX_USE_BACKING_PIXMAP
if (!drawn) {
redraw (pixmap, 0, 0, alloc_width, alloc_height);
}
gdk_draw_drawable (get_window()->gobj(),
get_style()->get_fg_gc (STATE_NORMAL)->gobj(),
pixmap,
event->area.x,
event->area.y,
event->area.x,
event->area.y,
event->area.width,
event->area.height);
#else
redraw (get_window()->gobj(), &event->area);
#endif
return true;
}

106
gtk2_ardour/matrix.h Normal file
View File

@ -0,0 +1,106 @@
#ifndef __gtk_ardour_matrix_h__
#define __gtk_ardour_matrix_h__
#include <list>
#include <vector>
#include <string>
#include <stdint.h>
#include <gtkmm/eventbox.h>
#include <gtkmm/widget.h>
#include "port_group.h"
class OtherPort {
public:
OtherPort (const std::string& n, PortGroup& g)
: _name (n), _group (g) {}
std::string name() const { return _name; }
PortGroup& group() const { return _group; }
bool visible() const { return _group.visible; }
public:
std::string _name;
PortGroup& _group;
};
class MatrixNode {
public:
MatrixNode (std::string a, OtherPort o, int32_t x, int32_t y)
: _name (a), them (o), _connected (random()%3), _x(x), _y(y) {}
~MatrixNode() {}
PortGroup& get_group() const { return them.group(); }
std::string our_name() const { return _name; }
std::string their_name() const { return them.name(); }
bool connected() const { return _connected; }
void set_connected (bool yn) { _connected = yn; }
int32_t x() const { return _x; }
int32_t y() const { return _y; }
private:
std::string _name;
OtherPort them;
bool _connected;
int32_t _x;
int32_t _y;
};
class Matrix : public Gtk::EventBox
{
public:
Matrix();
void set_ports (const std::list<std::string>&);
void add_group (PortGroup&);
void remove_group (PortGroup&);
void hide_group (PortGroup&);
void show_group (PortGroup&);
int row_spacing () const { return xstep; }
protected:
bool on_button_press_event (GdkEventButton* ev);
bool on_expose_event (GdkEventExpose* ev);
void on_size_allocate (Gtk::Allocation&);
void on_size_request (Gtk::Requisition*);
void on_realize ();
bool on_motion_notify_event (GdkEventMotion*);
bool on_leave_notify_event (GdkEventCrossing*);
MatrixNode* get_node (int32_t x, int32_t y);
private:
int height;
int width;
int alloc_width;
int alloc_height;
bool drawn;
int labels_y_shift;
int labels_x_shift;
float angle_radians;
int border;
int ystep;
int xstep;
uint32_t line_height;
uint32_t line_width;
int arc_radius;
int32_t motion_x;
int32_t motion_y;
std::list<std::string> ours;
std::list<OtherPort> others;
std::vector<MatrixNode*> nodes;
void reset_size ();
void redraw (GdkDrawable*, GdkRectangle*);
void alloc_pixmap ();
void setup_nodes ();
GdkPixmap* pixmap;
};
#endif /* __gtk_ardour_matrix_h__ */

View File

@ -82,34 +82,56 @@ speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg)
}
#endif
MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer)
: AxisView(sess),
RouteUI (rt, sess, _("Mute"), _("Solo"), _("Record")),
_mixer(mx),
_mixer_owned (in_mixer),
pre_processor_box (PreFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
post_processor_box (PostFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
gpm (_route, sess),
panners (_route, sess),
button_table (3, 2),
middle_button_table (1, 2),
bottom_button_table (1, 2),
meter_point_label (_("pre")),
comment_button (_("Comments")),
speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1),
speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
: AxisView(sess)
, RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
,_mixer(mx)
, _mixer_owned (in_mixer)
, pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
, post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
, gpm (sess)
, panners (sess)
, button_table (3, 2)
, middle_button_table (1, 2)
, bottom_button_table (1, 2)
, meter_point_label (_("pre"))
, comment_button (_("Comments"))
, speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
, speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
{
if (set_color_from_route()) {
set_color (unique_random_color());
}
init ();
}
MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer)
: AxisView(sess)
, RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
,_mixer(mx)
, _mixer_owned (in_mixer)
, pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
, post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
, gpm (sess)
, panners (sess)
, button_table (3, 2)
, middle_button_table (1, 2)
, bottom_button_table (1, 2)
, meter_point_label (_("pre"))
, comment_button (_("Comments"))
, speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
, speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
{
init ();
set_route (rt);
}
void
MixerStrip::init ()
{
input_selector = 0;
output_selector = 0;
group_menu = 0;
if (!_route->is_hidden()) {
_marked_for_display = true;
}
_marked_for_display = false;
route_ops_menu = 0;
ignore_comment_edit = false;
ignore_toggle = false;
@ -118,40 +140,26 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
comment_area = 0;
_width_owner = 0;
Gtk::Image *width_icon = manage (new Gtk::Image (::get_icon("strip_width")));
Gtk::Image *hide_icon = manage (new Gtk::Image (::get_icon("hide")));
width_button.add (*width_icon);
hide_button.add (*hide_icon);
width_button.add (*(manage (new Gtk::Image (::get_icon("strip_width")))));
hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
input_label.set_text (_("Input"));
ARDOUR_UI::instance()->set_tip (&input_button, _("Click to choose inputs"), "");
input_button.add (input_label);
input_button.set_name ("MixerIOButton");
input_label.set_name ("MixerIOButtonLabel");
output_label.set_text (_("Output"));
ARDOUR_UI::instance()->set_tip (&output_button, _("Click to choose outputs"), "");
output_button.add (output_label);
output_button.set_name ("MixerIOButton");
output_label.set_name ("MixerIOButtonLabel");
_route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed));
ARDOUR_UI::instance()->set_tip (&meter_point_button, _("Select metering point"), "");
meter_point_button.add (meter_point_label);
meter_point_button.set_name ("MixerStripMeterPreButton");
meter_point_label.set_name ("MixerStripMeterPreButton");
switch (_route->meter_point()) {
case MeterInput:
meter_point_label.set_text (_("input"));
break;
case MeterPreFader:
meter_point_label.set_text (_("pre"));
break;
case MeterPostFader:
meter_point_label.set_text (_("post"));
break;
}
/* TRANSLATORS: this string should be longest of the strings
used to describe meter points. In english, it's "input".
*/
@ -183,56 +191,18 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
bottom_button_table.set_homogeneous (true);
bottom_button_table.attach (group_button, 0, 1, 0, 1);
if (is_audio_track()) {
boost::shared_ptr<AudioTrack> at = audio_track();
at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen));
#ifdef VARISPEED_IN_MIXER_STRIP
speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
speed_frame.set_name ("BaseFrame");
speed_frame.set_shadow_type (Gtk::SHADOW_IN);
speed_frame.add (speed_spinner);
speed_spinner.set_print_func (speed_printer, 0);
ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
button_table.attach (speed_frame, 0, 2, 5, 6);
#endif /* VARISPEED_IN_MIXER_STRIP */
}
if(rec_enable_button) {
rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
rec_enable_button->set_name ("MixerRecordEnableButton");
button_table.attach (*rec_enable_button, 0, 2, 2, 3);
}
name_button.add (name_label);
name_button.set_name ("MixerNameButton");
Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
name_label.set_name ("MixerNameButtonLabel");
if (_route->phase_invert()) {
name_label.set_text (X_("Ø ") + name_label.get_text());
} else {
name_label.set_text (_route->name());
}
ARDOUR_UI::instance()->set_tip (&group_button, _("Mix group"), "");
group_button.add (group_label);
group_button.set_name ("MixerGroupButton");
group_label.set_name ("MixerGroupButtonLabel");
comment_button.set_name ("MixerCommentButton");
ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment()=="" ?
_("Click to Add/Edit Comments"):
_route->comment());
comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked));
global_vpacker.set_border_width (0);
@ -269,19 +239,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
if (route()->is_master() || route()->is_control()) {
if (scrollbar_height == 0) {
HScrollbar scrollbar;
Gtk::Requisition requisition(scrollbar.size_request ());
scrollbar_height = requisition.height;
}
EventBox* spacer = manage (new EventBox);
spacer->set_size_request (-1, scrollbar_height);
global_vpacker.pack_start (*spacer, false, false);
}
global_frame.add (global_vpacker);
global_frame.set_shadow_type (Gtk::SHADOW_IN);
global_frame.set_name ("BaseFrame");
@ -298,22 +255,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
_session.engine().Stopped.connect (mem_fun(*this, &MixerStrip::engine_stopped));
_session.engine().Running.connect (mem_fun(*this, &MixerStrip::engine_running));
_route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed));
_route->output_changed.connect (mem_fun(*this, &MixerStrip::output_changed));
_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
_route->mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed));
_route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan));
if (is_audio_track()) {
audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed));
get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed));
}
_route->NameChanged.connect (mem_fun(*this, &RouteUI::name_changed));
_route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed));
_route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed));
input_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::input_press), false);
output_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::output_press), false);
@ -323,11 +264,22 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
/* we don't need this if its not an audio track, but we don't know that yet and it doesn't
hurt (much).
*/
rec_enable_button->set_name ("MixerRecordEnableButton");
rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
name_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::name_button_button_press), false);
group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false);
_width = (Width) -1;
set_stuff_from_route ();
/* start off as a passthru strip. we'll correct this, if necessary,
in update_diskstream_display().
*/
/* start off as a passthru strip. we'll correct this, if necessary,
in update_diskstream_display().
@ -338,6 +290,126 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
else
set_name ("AudioTrackStripBase");
add_events (Gdk::BUTTON_RELEASE_MASK);
}
MixerStrip::~MixerStrip ()
{
GoingAway(); /* EMIT_SIGNAL */
if (input_selector) {
delete input_selector;
}
if (output_selector) {
delete output_selector;
}
}
void
MixerStrip::set_route (boost::shared_ptr<Route> rt)
{
if (rec_enable_button->get_parent()) {
button_table.remove (*rec_enable_button);
}
#ifdef VARISPEED_IN_MIXER_STRIP
if (speed_frame->get_parent()) {
button_table.remove (*speed_frame);
}
#endif
RouteUI::set_route (rt);
panners.set_io (rt);
gpm.set_io (rt);
pre_processor_box.set_route (rt);
post_processor_box.set_route (rt);
if (set_color_from_route()) {
set_color (unique_random_color());
}
if (_mixer_owned && (route()->is_master() || route()->is_control())) {
if (scrollbar_height == 0) {
HScrollbar scrollbar;
Gtk::Requisition requisition(scrollbar.size_request ());
scrollbar_height = requisition.height;
}
EventBox* spacer = manage (new EventBox);
spacer->set_size_request (-1, scrollbar_height);
global_vpacker.pack_start (*spacer, false, false);
}
if (is_audio_track()) {
boost::shared_ptr<AudioTrack> at = audio_track();
connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)));
#ifdef VARISPEED_IN_MIXER_STRIP
speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
speed_frame.set_name ("BaseFrame");
speed_frame.set_shadow_type (Gtk::SHADOW_IN);
speed_frame.add (speed_spinner);
speed_spinner.set_print_func (speed_printer, 0);
ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
button_table.attach (speed_frame, 0, 2, 5, 6);
#endif /* VARISPEED_IN_MIXER_STRIP */
button_table.attach (*rec_enable_button, 0, 2, 2, 3);
}
if (_route->phase_invert()) {
name_label.set_text (X_("Ø ") + name_label.get_text());
} else {
name_label.set_text (_route->name());
}
switch (_route->meter_point()) {
case MeterInput:
meter_point_label.set_text (_("input"));
break;
case MeterPreFader:
meter_point_label.set_text (_("pre"));
break;
case MeterPostFader:
meter_point_label.set_text (_("post"));
break;
}
ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment().empty() ?
_("Click to Add/Edit Comments"):
_route->comment());
connections.push_back (_route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed)));
connections.push_back (_route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed)));
connections.push_back (_route->output_changed.connect (mem_fun(*this, &MixerStrip::output_changed)));
connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
connections.push_back (_route->mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed)));
connections.push_back (_route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan)));
if (is_audio_track()) {
connections.push_back (audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed)));
connections.push_back (get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed)));
}
connections.push_back (_route->NameChanged.connect (mem_fun(*this, &RouteUI::name_changed)));
connections.push_back (_route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed)));
connections.push_back (_route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed)));
set_stuff_from_route ();
/* now force an update of all the various elements */
pre_processor_box.update();
@ -362,11 +434,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
add_events (Gdk::BUTTON_RELEASE_MASK);
whvbox->show();
hide_icon->show();
width_icon->show();
gain_meter_alignment->show_all();
pre_processor_box.show();
if (!route()->is_master() && !route()->is_control()) {
@ -402,19 +469,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
show();
}
MixerStrip::~MixerStrip ()
{
GoingAway(); /* EMIT_SIGNAL */
if (input_selector) {
delete input_selector;
}
if (output_selector) {
delete output_selector;
}
}
void
MixerStrip::set_stuff_from_route ()
{
@ -796,6 +850,7 @@ MixerStrip::update_output_display ()
break;
}
}
gpm.setup_meters ();
panners.setup_pan ();
}
@ -1292,22 +1347,22 @@ MixerStrip::meter_changed (void *src)
ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
switch (_route->meter_point()) {
case MeterInput:
meter_point_label.set_text (_("input"));
break;
case MeterInput:
meter_point_label.set_text (_("input"));
break;
case MeterPreFader:
meter_point_label.set_text (_("pre"));
break;
case MeterPostFader:
meter_point_label.set_text (_("post"));
break;
case MeterPreFader:
meter_point_label.set_text (_("pre"));
break;
case MeterPostFader:
meter_point_label.set_text (_("post"));
break;
}
gpm.setup_meters ();
// reset peak when meter point changes
gpm.reset_peak_display();
set_width(_width, this);
// reset peak when meter point changes
gpm.reset_peak_display();
set_width(_width, this);
}

View File

@ -83,6 +83,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
{
public:
MixerStrip (Mixer_UI&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, bool in_mixer = true);
MixerStrip (Mixer_UI&, ARDOUR::Session&, bool in_mixer = true);
~MixerStrip ();
void set_width (Width, void* owner);
@ -93,6 +94,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
void set_embedded (bool);
ARDOUR::RouteGroup* mix_group() const;
void set_route (boost::shared_ptr<ARDOUR::Route>);
protected:
friend class Mixer_UI;
@ -105,6 +107,8 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
private:
Mixer_UI& _mixer;
void init ();
bool _embedded;
bool _packed;
bool _mixer_owned;

View File

@ -1117,7 +1117,8 @@ OptionEditor::setup_click_editor ()
click_emphasis_path_entry.set_sensitive (true);
click_io_selector = new IOSelector (*session, session->click_io(), false);
click_gpm = new GainMeter (session->click_io(), *session);
click_gpm = new GainMeter (*session);
click_gpm->set_io (session->click_io());
click_hpacker.pack_start (*click_io_selector, false, false);
click_hpacker.pack_start (*click_gpm, false, false);
@ -1173,7 +1174,8 @@ void
OptionEditor::connect_audition_editor ()
{
auditioner_io_selector = new IOSelector (*session, session->the_auditioner(), false);
auditioner_gpm = new GainMeter (session->the_auditioner(), *session);
auditioner_gpm = new GainMeter (*session);
auditioner_gpm->set_io (session->the_auditioner());
audition_hpacker.pack_start (*auditioner_io_selector, false, false);
audition_hpacker.pack_start (*auditioner_gpm, false, false);

View File

@ -47,9 +47,8 @@ using namespace sigc;
const int PannerUI::pan_bar_height = 30;
PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
: _io (io),
_session (s),
PannerUI::PannerUI (Session& s)
: _session (s),
hAdjustment(0.0, 0.0, 0.0),
vAdjustment(0.0, 0.0, 0.0),
panning_viewport(hAdjustment, vAdjustment),
@ -61,6 +60,8 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
{
ignore_toggle = false;
pan_menu = 0;
pan_astate_menu = 0;
pan_astyle_menu = 0;
in_pan_update = false;
pan_automation_style_button.set_name ("MixerAutomationModeButton");
@ -84,22 +85,6 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
pan_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
pan_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
using namespace Menu_Helpers;
pan_astate_menu.items().push_back (MenuElem (_("Manual"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Off)));
pan_astate_menu.items().push_back (MenuElem (_("Play"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Play)));
pan_astate_menu.items().push_back (MenuElem (_("Write"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Write)));
pan_astate_menu.items().push_back (MenuElem (_("Touch"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Touch)));
pan_astyle_menu.items().push_back (MenuElem (_("Trim")));
pan_astyle_menu.items().push_back (MenuElem (_("Abs")));
pan_astate_menu.set_name ("ArdourContextMenu");
pan_astyle_menu.set_name ("ArdourContextMenu");
pan_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &PannerUI::pan_automation_style_button_event), false);
pan_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &PannerUI::pan_automation_state_button_event), false);
@ -141,16 +126,41 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
panner = 0;
set_width(Narrow);
_io->panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed));
_io->panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage));
_io->panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state));
}
void
PannerUI::set_io (boost::shared_ptr<IO> io)
{
connections.clear ();
if (pan_astyle_menu) {
delete pan_astyle_menu;
pan_astyle_menu = 0;
}
if (pan_astate_menu) {
delete pan_astate_menu;
pan_astate_menu = 0;
}
_io = io;
connections.push_back (_io->panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed)));
connections.push_back (_io->panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)));
connections.push_back (_io->panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)));
if (panner) {
delete panner;
panner = 0;
}
pan_changed (0);
update_pan_sensitive ();
update_pan_linkage ();
pan_automation_state_changed ();
#if WHERE_DOES_THIS_LIVE
pan_bar_packer.show();
panning_viewport.show();
panning_up.show();
@ -164,6 +174,46 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
pan_automation_style_button.show();
pan_automation_state_button.show();
show();
#endif
}
void
PannerUI::build_astate_menu ()
{
using namespace Menu_Helpers;
if (pan_astate_menu == 0) {
pan_astate_menu = new Menu;
pan_astate_menu->set_name ("ArdourContextMenu");
} else {
pan_astate_menu->items().clear ();
}
pan_astate_menu->items().push_back (MenuElem (_("Manual"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Off)));
pan_astate_menu->items().push_back (MenuElem (_("Play"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Play)));
pan_astate_menu->items().push_back (MenuElem (_("Write"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Write)));
pan_astate_menu->items().push_back (MenuElem (_("Touch"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Touch)));
}
void
PannerUI::build_astyle_menu ()
{
using namespace Menu_Helpers;
if (pan_astyle_menu == 0) {
pan_astyle_menu = new Menu;
pan_astyle_menu->set_name ("ArdourContextMenu");
} else {
pan_astyle_menu->items().clear();
}
pan_astyle_menu->items().push_back (MenuElem (_("Trim")));
pan_astyle_menu->items().push_back (MenuElem (_("Abs")));
}
boost::shared_ptr<PBD::Controllable>
@ -262,7 +312,14 @@ PannerUI::~PannerUI ()
if (pan_menu) {
delete pan_menu;
}
if (pan_astyle_menu) {
delete pan_astyle_menu;
}
if (pan_astate_menu) {
delete pan_astate_menu;
}
}
@ -662,7 +719,10 @@ PannerUI::pan_automation_state_button_event (GdkEventButton *ev)
switch (ev->button) {
case 1:
pan_astate_menu.popup (1, ev->time);
if (pan_astate_menu == 0) {
build_astate_menu ();
}
pan_astate_menu->popup (1, ev->time);
break;
default:
break;
@ -680,7 +740,10 @@ PannerUI::pan_automation_style_button_event (GdkEventButton *ev)
switch (ev->button) {
case 1:
pan_astyle_menu.popup (1, ev->time);
if (pan_astyle_menu == 0) {
build_astyle_menu ();
}
pan_astyle_menu->popup (1, ev->time);
break;
default:
break;

View File

@ -54,9 +54,11 @@ namespace Gtk {
class PannerUI : public Gtk::HBox
{
public:
PannerUI (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&);
PannerUI (ARDOUR::Session&);
~PannerUI ();
virtual void set_io (boost::shared_ptr<ARDOUR::IO>);
void pan_changed (void *);
void update_pan_sensitive ();
@ -75,6 +77,7 @@ class PannerUI : public Gtk::HBox
boost::shared_ptr<ARDOUR::IO> _io;
ARDOUR::Session& _session;
std::vector<sigc::connection> connections;
bool ignore_toggle;
bool in_pan_update;
@ -101,8 +104,8 @@ class PannerUI : public Gtk::HBox
bool panning_link_button_press (GdkEventButton*);
bool panning_link_button_release (GdkEventButton*);
Gtk::Menu pan_astate_menu;
Gtk::Menu pan_astyle_menu;
Gtk::Menu* pan_astate_menu;
Gtk::Menu* pan_astyle_menu;
Gtk::Button pan_automation_style_button;
Gtk::ToggleButton pan_automation_state_button;
@ -118,6 +121,8 @@ class PannerUI : public Gtk::HBox
void update_pan_bars (bool only_if_aplay);
void update_pan_linkage ();
void update_pan_state ();
void build_astate_menu ();
void build_astyle_menu ();
void panner_changed ();

90
gtk2_ardour/port_group.h Normal file
View File

@ -0,0 +1,90 @@
#ifndef __gtk_ardour_port_group_h__
#define __gtk_ardour_port_group_h__
#include <vector>
#include <string>
#include <gtkmm/widget.h>
#include <gtkmm/checkbutton.h>
#include <ardour/data_type.h>
namespace ARDOUR {
class Session;
class IO;
class PortInsert;
}
class PortMatrix;
/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
class PortGroup
{
public:
/** PortGroup constructor.
* @param n Name.
* @param p Port name prefix.
* @param v true if group should be visible in the UI, otherwise false.
*/
PortGroup (std::string const & n, std::string const & p, bool v) : name (n), prefix (p), visible (v) {}
void add (std::string const & p);
std::string name; ///< name for the group
std::string prefix; ///< prefix (before colon) e.g. "ardour:"
std::vector<std::string> ports; ///< port names
bool visible; ///< true if the group is visible in the UI
};
/// The UI for a PortGroup
class PortGroupUI
{
public:
PortGroupUI (PortMatrix&, PortGroup&);
Gtk::Widget& get_visibility_checkbutton ();
PortGroup& port_group () { return _port_group; }
void setup_visibility ();
private:
void port_checkbutton_toggled (Gtk::CheckButton*, int, int);
bool port_checkbutton_release (GdkEventButton* ev, Gtk::CheckButton* b, int r, int c);
void visibility_checkbutton_toggled ();
PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
PortGroup& _port_group; ///< the PortGroup that we are representing
bool _ignore_check_button_toggle;
Gtk::CheckButton _visibility_checkbutton;
};
/// A list of PortGroups
class PortGroupList : public std::list<PortGroup*>
{
public:
enum Mask {
BUSS = 0x1,
TRACK = 0x2,
SYSTEM = 0x4,
OTHER = 0x8
};
PortGroupList (ARDOUR::Session &, ARDOUR::DataType, bool, Mask);
void refresh ();
int n_visible_ports () const;
std::string get_port_by_index (int, bool with_prefix = true) const;
void set_type (ARDOUR::DataType);
void set_offer_inputs (bool);
private:
ARDOUR::Session& _session;
ARDOUR::DataType _type;
bool _offer_inputs;
PortGroup buss;
PortGroup track;
PortGroup system;
PortGroup other;
};
#endif /* __gtk_ardour_port_group_h__ */

View File

@ -69,59 +69,8 @@ PortGroupUI::PortGroupUI (PortMatrix& m, PortGroup& g)
, _ignore_check_button_toggle (false)
, _visibility_checkbutton (g.name)
{
int const ports = _port_group.ports.size();
int const rows = _port_matrix.n_rows ();
if (rows == 0 || ports == 0) {
return;
}
/* Sort out the table and the checkbuttons inside it */
_table.resize (rows, ports);
_port_checkbuttons.resize (rows);
for (int i = 0; i < rows; ++i) {
_port_checkbuttons[i].resize (ports);
}
for (int i = 0; i < rows; ++i) {
for (uint32_t j = 0; j < _port_group.ports.size(); ++j) {
CheckButton* b = new CheckButton;
b->signal_toggled().connect (
sigc::bind (sigc::mem_fun (*this, &PortGroupUI::port_checkbutton_toggled), b, i, j));
b->signal_button_release_event().connect (
sigc::bind (sigc::mem_fun (*this, &PortGroupUI::port_checkbutton_release), b, i, j), false);
_port_checkbuttons[i][j] = b;
cerr << this << " bind to " << &_port_checkbuttons << " via " << b
<< endl;
_table.attach (*b, j, j + 1, i, i + 1);
}
}
_table_box.add (_table);
_ignore_check_button_toggle = true;
/* Set the state of the check boxes according to current connections */
for (int i = 0; i < rows; ++i) {
for (uint32_t j = 0; j < _port_group.ports.size(); ++j) {
std::string const t = _port_group.prefix + _port_group.ports[j];
bool const s = _port_matrix.get_state (i, t);
_port_checkbuttons[i][j]->set_active (s);
if (s) {
_port_group.visible = true;
}
}
}
_port_group.visible = true;
_ignore_check_button_toggle = false;
_visibility_checkbutton.signal_toggled().connect (sigc::mem_fun (*this, &PortGroupUI::visibility_checkbutton_toggled));
}
@ -132,34 +81,6 @@ PortGroupUI::visibility_checkbutton_toggled ()
_port_group.visible = _visibility_checkbutton.get_active ();
}
/** @return Width and height of a single checkbutton in a port group table */
std::pair<int, int>
PortGroupUI::unit_size () const
{
if (_port_checkbuttons.empty() || _port_checkbuttons[0].empty())
{
return std::pair<int, int> (0, 0);
}
int r = 0;
/* We can't ask for row spacing unless there >1 rows, otherwise we get a warning */
if (_table.property_n_rows() > 1) {
r = _table.get_row_spacing (0);
}
return std::make_pair (
_port_checkbuttons[0][0]->get_width() + _table.get_col_spacing (0),
_port_checkbuttons[0][0]->get_height() + r
);
}
/** @return Table widget containing the port checkbuttons */
Widget&
PortGroupUI::get_table ()
{
return _table_box;
}
/** @return Checkbutton used to toggle visibility */
Widget&
PortGroupUI::get_visibility_checkbutton ()
@ -173,324 +94,37 @@ void
PortGroupUI::port_checkbutton_toggled (CheckButton* b, int r, int c)
{
if (_ignore_check_button_toggle == false) {
_port_matrix.set_state (r, _port_group.prefix + _port_group.ports[c], b->get_active(), 0);
// _port_matrix.hide_group (_port_group);
}
}
bool
PortGroupUI::port_checkbutton_release (GdkEventButton* ev, CheckButton* b, int r, int c)
{
cerr << this << " RELEASE on " << b << " state = " << ev->state << endl;
if (ev->state == 0) {
/* let usual toggle handler take care of it */
return false;
}
/* The fun starts here
*/
const size_t ports = _port_group.ports.size();
const size_t rows = _port_matrix.n_rows ();
if (rows == 0 || ports == 0) {
return true;
}
/* For each port in the group, change the state of
the connection for the corresponding "connector" port.
*/
for (size_t j = c; j < ports; ++j) {
/* we've got a port to connect, now lets find the thing to
connect it too ... (search "down" the rows)
*/
cerr << "we're going to connect port " << j << " of " << ports << endl;
for (size_t i = r; i < rows; ++i) {
cerr << this << " going to connect to row " << i << " of " << rows << endl;
cerr << "access [" << i << "][" << j << "]\n";
cerr << " @ " << &_port_checkbuttons << endl;
_port_checkbuttons[i][j]->set_active (!_port_checkbuttons[i][j]->get_active());
/* next time, get at least as far as this port before looking
for more.
*/
r = i + 1;
/* changed connection state, stop looking for more */
break;
}
}
return true;
}
/** Set up visibility of the port group according to PortGroup::visible */
void
PortGroupUI::setup_visibility ()
{
if (!_port_group.ports.empty() && _port_group.visible) {
_table_box.show ();
} else {
_table_box.hide ();
}
if (_visibility_checkbutton.get_active () != _port_group.visible) {
_visibility_checkbutton.set_active (_port_group.visible);
}
}
RotatedLabelSet::RotatedLabelSet (PortGroupList& g)
: Glib::ObjectBase ("RotatedLabelSet"), Widget (), _port_group_list (g), _base_width (128)
{
set_flags (NO_WINDOW);
if (getenv ("AD_ANGLE") != 0) {
set_angle (atoi (getenv ("AD_ANGLE")));
} else {
set_angle (45);
}
}
RotatedLabelSet::~RotatedLabelSet ()
{
}
/** Set the angle that the labels are drawn at.
* @param degrees New angle in degrees.
*/
void
RotatedLabelSet::set_angle (int degrees)
{
_angle_degrees = degrees;
_angle_radians = M_PI * _angle_degrees / 180;
queue_resize ();
}
void
RotatedLabelSet::on_size_request (Requisition* requisition)
{
*requisition = Requisition ();
if (_pango_layout == 0) {
return;
}
/* Our height is the highest label */
requisition->height = 0;
for (PortGroupList::const_iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
for (std::vector<std::string>::const_iterator j = (*i)->ports.begin(); j != (*i)->ports.end(); ++j) {
std::pair<int, int> const d = setup_layout (*j);
if (d.second > requisition->height) {
requisition->height = d.second;
}
}
}
/* And our width is the base plus the width of the last label */
requisition->width = _base_width;
int const n = _port_group_list.n_visible_ports ();
if (n > 0) {
std::pair<int, int> const d = setup_layout (_port_group_list.get_port_by_index (n - 1, false));
requisition->width += d.first;
}
cerr << "Labels will be " << requisition->width << " x " << requisition->height << endl;
}
void
RotatedLabelSet::on_size_allocate (Allocation& allocation)
{
set_allocation (allocation);
if (_gdk_window) {
_gdk_window->move_resize (allocation.get_x(), allocation.get_y(), allocation.get_width(), allocation.get_height());
}
}
void
RotatedLabelSet::on_realize ()
{
Widget::on_realize ();
Glib::RefPtr<Style> style = get_style ();
if (!_gdk_window) {
GdkWindowAttr attributes;
memset (&attributes, 0, sizeof (attributes));
Allocation allocation = get_allocation ();
attributes.x = allocation.get_x ();
attributes.y = allocation.get_y ();
attributes.width = allocation.get_width ();
attributes.height = allocation.get_height ();
attributes.event_mask = get_events () | Gdk::EXPOSURE_MASK;
attributes.window_type = GDK_WINDOW_CHILD;
attributes.wclass = GDK_INPUT_OUTPUT;
_gdk_window = Gdk::Window::create (get_window (), &attributes, GDK_WA_X | GDK_WA_Y);
unset_flags (NO_WINDOW);
set_window (_gdk_window);
_bg_colour = style->get_bg (STATE_NORMAL );
modify_bg (STATE_NORMAL, _bg_colour);
_fg_colour = style->get_fg (STATE_NORMAL);
_gdk_window->set_user_data (gobj ());
/* Set up Pango stuff */
_pango_context = create_pango_context ();
Pango::Matrix matrix = PANGO_MATRIX_INIT;
pango_matrix_rotate (&matrix, _angle_degrees);
_pango_context->set_matrix (matrix);
_pango_layout = Pango::Layout::create (_pango_context);
_gc = Gdk::GC::create (get_window ());
}
}
void
RotatedLabelSet::on_unrealize()
{
_gdk_window.clear ();
Widget::on_unrealize ();
}
/** Set up our Pango layout to plot a given string, and compute its dimensions once
* it has been rotated.
* @param s String to use.
* @return width and height of the rotated string, in pixels.
*/
std::pair<int, int>
RotatedLabelSet::setup_layout (std::string const & s)
{
_pango_layout->set_text (s);
/* Here's the unrotated size */
int w;
int h;
_pango_layout->get_pixel_size (w, h);
/* Rotate the width and height as appropriate. I thought Pango might be able
to do this for us, but I can't find out how...
*/
std::pair<int, int> d;
// cerr << "\"" << s << "\" was " << w << " x " << h << endl;
d.first = int (fabs (w * cos (_angle_radians) + h * sin (_angle_radians)));
d.second = int (fabs (w * sin (_angle_radians) + h * cos (_angle_radians)));
// cerr << "\trotated by " << _angle_degrees << " = " << d.first << " x " << d.second << endl;
return d;
}
bool
RotatedLabelSet::on_expose_event (GdkEventExpose* event)
{
if (!_gdk_window) {
return true;
}
int const height = get_allocation().get_height ();
double const spacing = double (_base_width) / _port_group_list.n_visible_ports();
/* Plot all the visible labels; really we should clip for efficiency */
int n = 0;
for (PortGroupList::const_iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
if ((*i)->visible) {
for (uint32_t j = 0; j < (*i)->ports.size(); ++j) {
std::pair<int, int> const d = setup_layout ((*i)->ports[j]);
int x, y;
if (getenv ("AD_X_SHIFT") != 0) {
x = atoi (getenv ("AD_X_SHIFT"));
} else {
x = 0;
}
if (getenv ("AD_Y_SHIFT") != 0) {
y = atoi (getenv ("AD_Y_SHIFT"));
} else {
y = 0;
}
get_window()->draw_layout (_gc, int ((n + 0.25) * spacing) + x, height - d.second + y, _pango_layout, _fg_colour, _bg_colour);
++n;
}
}
}
return true;
}
/** Set the `base width'. This is the width of the base of the label set, ie:
*
* L L L L
* E E E E
* B B B B
* A A A A
* L L L L
* <--w-->
*/
void
RotatedLabelSet::set_base_width (int w)
{
_base_width = w;
queue_resize ();
}
PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type, bool offer_inputs, PortGroupList::Mask mask)
: _offer_inputs (offer_inputs), _port_group_list (session, type, offer_inputs, mask), _type (type),
_column_labels (_port_group_list)
: _offer_inputs (offer_inputs), _port_group_list (session, type, offer_inputs, mask), _type (type)
{
_row_labels_vbox = 0;
_side_vbox_pad = 0;
_visibility_checkbutton_box.pack_start (*(manage (new Label (_("Connections displayed: ")))), false, false, 10);
pack_start (_visibility_checkbutton_box, false, false);
_scrolled_window.set_policy (POLICY_ALWAYS, POLICY_AUTOMATIC);
_scrolled_window.set_shadow_type (SHADOW_NONE);
VBox* b = manage (new VBox);
if (offer_inputs) {
b->pack_start (_port_group_hbox, false, false);
b->pack_start (_column_labels, false, false);
} else {
b->pack_start (_column_labels, false, false);
b->pack_start (_port_group_hbox, false, false);
}
b->pack_start (_port_group_hbox, false, false);
b->pack_start (_port_group_hbox, false, false);
Alignment* a;
if (offer_inputs) {
a = manage (new Alignment (1, 0, 0, 0));
} else {
a = manage (new Alignment (0, 1, 0, 0));
}
a->add (*b);
_scrolled_window.add (*a);
_scrolled_window.add (matrix);
if (offer_inputs) {
_overall_hbox.pack_start (_side_vbox, false, false, 6);
@ -535,7 +169,6 @@ PortMatrix::clear ()
}
for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
_port_group_hbox.remove ((*i)->get_table());
_visibility_checkbutton_box.remove ((*i)->get_visibility_checkbutton());
delete *i;
}
@ -550,46 +183,16 @@ PortMatrix::clear ()
void
PortMatrix::setup_dimensions ()
{
/* Get some dimensions from various places */
int const scrollbar_height = _scrolled_window.get_hscrollbar()->get_height();
std::pair<int, int> unit_size (0, 0);
int port_group_tables_height = 0;
for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
std::pair<int, int> const u = (*i)->unit_size ();
unit_size.first = std::max (unit_size.first, u.first);
unit_size.second = std::max (unit_size.second, u.second);
port_group_tables_height = std::max (
port_group_tables_height, (*i)->get_table().get_height()
);
}
/* Column labels */
_column_labels.set_base_width (_port_group_list.n_visible_ports () * unit_size.first);
/* Scrolled window */
/* XXX: really shouldn't set a minimum horizontal size here, but if we don't
the window starts up very small.
The constant value in the set_size_request() computation will control
how big the scrolled window will be if we fill the port matrix will a gajillion
ports.
*/
_scrolled_window.set_size_request (
std::min (_column_labels.get_width(), 400),
_column_labels.get_height() + port_group_tables_height + scrollbar_height + 16
);
/* Row labels */
for (std::vector<EventBox*>::iterator j = _row_labels.begin(); j != _row_labels.end(); ++j) {
(*j)->get_child()->set_size_request (-1, unit_size.second);
(*j)->get_child()->set_size_request (-1, matrix.row_spacing());
}
if (_side_vbox_pad) {
if (_offer_inputs) {
_side_vbox_pad->set_size_request (-1, unit_size.second / 4);
_side_vbox_pad->set_size_request (-1, matrix.row_spacing() / 4);
} else {
_side_vbox_pad->set_size_request (-1, scrollbar_height + unit_size.second / 4);
_side_vbox_pad->set_size_request (-1, matrix.row_spacing() / 4);
}
}
}
@ -647,7 +250,6 @@ PortMatrix::setup ()
PortGroupUI* t = new PortGroupUI (*this, **i);
_port_group_ui.push_back (t);
_port_group_hbox.pack_start (t->get_table(), false, false);
_visibility_checkbutton_box.pack_start (t->get_visibility_checkbutton(), false, false);
@ -666,23 +268,14 @@ PortMatrix::setup ()
void
PortMatrix::reset_visibility ()
{
/* now adjust visibility and coloring */
bool even = true;
Gdk::Color odd_bg (color_from_style ("OddPortGroups", STATE_NORMAL, "fg"));
Gdk::Color even_bg (color_from_style ("EvenPortGroups", STATE_NORMAL, "fg"));
for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
(*i)->setup_visibility ();
if ((*i)->port_group().visible) {
if (even) {
(*i)->get_table().modify_bg (STATE_NORMAL, even_bg);
} else {
(*i)->get_table().modify_bg (STATE_NORMAL, odd_bg);
}
even = !even;
matrix.show_group ((*i)->port_group());
} else {
matrix.hide_group ((*i)->port_group());
}
}
}

View File

@ -28,6 +28,8 @@
#include <gtkmm/scrolledwindow.h>
#include "ardour_dialog.h"
#include "port_group.h"
#include "matrix.h"
namespace ARDOUR {
class Session;
@ -35,118 +37,6 @@ namespace ARDOUR {
class PortInsert;
}
class PortMatrix;
/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
class PortGroup
{
public:
/** PortGroup constructor.
* @param n Name.
* @param p Port name prefix.
* @param v true if group should be visible in the UI, otherwise false.
*/
PortGroup (std::string const & n, std::string const & p, bool v) : name (n), prefix (p), visible (v) {}
void add (std::string const & p);
std::string name; ///< name for the group
std::string prefix; ///< prefix (before colon) e.g. "ardour:"
std::vector<std::string> ports; ///< port names
bool visible; ///< true if the group is visible in the UI
};
/// The UI for a PortGroup
class PortGroupUI
{
public:
PortGroupUI (PortMatrix&, PortGroup&);
Gtk::Widget& get_table ();
Gtk::Widget& get_visibility_checkbutton ();
std::pair<int, int> unit_size () const;
PortGroup& port_group () { return _port_group; }
void setup_visibility ();
private:
void port_checkbutton_toggled (Gtk::CheckButton*, int, int);
bool port_checkbutton_release (GdkEventButton* ev, Gtk::CheckButton* b, int r, int c);
void visibility_checkbutton_toggled ();
PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
PortGroup& _port_group; ///< the PortGroup that we are representing
bool _ignore_check_button_toggle;
Gtk::Table _table;
Gtk::EventBox _table_box;
std::vector<std::vector<Gtk::CheckButton* > > _port_checkbuttons;
Gtk::CheckButton _visibility_checkbutton;
};
/// A list of PortGroups
class PortGroupList : public std::list<PortGroup*>
{
public:
enum Mask {
BUSS = 0x1,
TRACK = 0x2,
SYSTEM = 0x4,
OTHER = 0x8
};
PortGroupList (ARDOUR::Session &, ARDOUR::DataType, bool, Mask);
void refresh ();
int n_visible_ports () const;
std::string get_port_by_index (int, bool with_prefix = true) const;
void set_type (ARDOUR::DataType);
void set_offer_inputs (bool);
private:
ARDOUR::Session& _session;
ARDOUR::DataType _type;
bool _offer_inputs;
PortGroup buss;
PortGroup track;
PortGroup system;
PortGroup other;
};
/// A widget which provides a set of rotated text labels
class RotatedLabelSet : public Gtk::Widget {
public:
RotatedLabelSet (PortGroupList&);
virtual ~RotatedLabelSet ();
void set_angle (int);
void set_base_width (int);
void update_visibility ();
protected:
virtual void on_size_request (Gtk::Requisition*);
virtual void on_size_allocate (Gtk::Allocation&);
virtual void on_realize ();
virtual void on_unrealize ();
virtual bool on_expose_event (GdkEventExpose*);
Glib::RefPtr<Gdk::Window> _gdk_window;
private:
std::pair<int, int> setup_layout (std::string const &);
PortGroupList& _port_group_list; ///< list of ports to display
int _angle_degrees; ///< label rotation angle in degrees
double _angle_radians; ///< label rotation angle in radians
int _base_width; ///< width of labels; see set_base_width() for more details
Glib::RefPtr<Pango::Context> _pango_context;
Glib::RefPtr<Pango::Layout> _pango_layout;
Glib::RefPtr<Gdk::GC> _gc;
Gdk::Color _fg_colour;
Gdk::Color _bg_colour;
};
class PortMatrix : public Gtk::VBox {
public:
PortMatrix (ARDOUR::Session&, ARDOUR::DataType, bool, PortGroupList::Mask);
@ -184,10 +74,10 @@ class PortMatrix : public Gtk::VBox {
private:
PortGroupList _port_group_list;
ARDOUR::DataType _type;
Matrix matrix;
std::vector<PortGroupUI*> _port_group_ui;
std::vector<Gtk::EventBox*> _row_labels;
Gtk::VBox* _row_labels_vbox;
RotatedLabelSet _column_labels;
Gtk::HBox _overall_hbox;
Gtk::VBox _side_vbox;
Gtk::HBox _port_group_hbox;

View File

@ -82,10 +82,9 @@ bool ProcessorBox::get_colors = true;
Gdk::Color* ProcessorBox::active_processor_color;
Gdk::Color* ProcessorBox::inactive_processor_color;
ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, boost::shared_ptr<Route> rt, PluginSelector &plugsel,
RouteRedirectSelection & rsel, bool owner_is_mixer)
: _route(rt),
_session(sess),
ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel,
RouteRedirectSelection & rsel, bool owner_is_mixer)
: _session(sess),
_owner_is_mixer (owner_is_mixer),
_placement(pcmnt),
_plugin_selector(plugsel),
@ -138,27 +137,29 @@ ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, boost::shared_ptr<Ro
pack_start (processor_eventbox, true, true);
_route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors));
_route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away));
processor_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (ProcessorBox::enter_box), this));
processor_display.signal_button_press_event().connect (mem_fun(*this, &ProcessorBox::processor_button_press_event), false);
processor_display.signal_button_release_event().connect (mem_fun(*this, &ProcessorBox::processor_button_release_event));
/* start off as a passthru strip. we'll correct this, if necessary,
in update_diskstream_display().
*/
/* now force an update of all the various elements */
redisplay_processors ();
}
ProcessorBox::~ProcessorBox ()
{
}
void
ProcessorBox::set_route (boost::shared_ptr<Route> r)
{
connections.clear ();
_route = r;
connections.push_back (_route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors)));
connections.push_back (_route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away)));
redisplay_processors ();
}
void
ProcessorBox::route_going_away ()
{

View File

@ -68,10 +68,10 @@ namespace ARDOUR {
class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
{
public:
ProcessorBox (ARDOUR::Placement, ARDOUR::Session&,
boost::shared_ptr<ARDOUR::Route>, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false);
ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false);
~ProcessorBox ();
void set_route (boost::shared_ptr<ARDOUR::Route>);
void set_width (Width);
void update();
@ -87,14 +87,12 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
static void register_actions();
protected:
void set_stuff_from_route ();
private:
boost::shared_ptr<ARDOUR::Route> _route;
ARDOUR::Session & _session;
bool _owner_is_mixer;
bool ab_direction;
std::vector<sigc::connection> connections;
ARDOUR::Placement _placement;

View File

@ -229,8 +229,11 @@ RouteParams_UI::setup_processor_boxes()
cleanup_processor_boxes();
// construct new redirect boxes
pre_insert_box = new ProcessorBox(PreFader, *session, _route, *_plugin_selector, _rr_selection);
post_insert_box = new ProcessorBox(PostFader, *session, _route, *_plugin_selector, _rr_selection);
pre_insert_box = new ProcessorBox(PreFader, *session, *_plugin_selector, _rr_selection);
post_insert_box = new ProcessorBox(PostFader, *session, *_plugin_selector, _rr_selection);
pre_insert_box->set_route (_route);
post_insert_box->set_route (_route);
pre_redir_hpane.pack1 (*pre_insert_box);
post_redir_hpane.pack1 (*post_insert_box);

View File

@ -106,9 +106,9 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
size_button (_("h")), // height
automation_button (_("a")),
visual_button (_("v")),
gm (rt, sess, slider, true)
gm (sess, slider, true)
{
gm.set_io (rt);
gm.get_level_meter().set_no_show_all();
gm.get_level_meter().setup_meters(50);

View File

@ -54,13 +54,33 @@ using namespace Gtkmm2ext;
using namespace ARDOUR;
using namespace PBD;
RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, const char* m_name,
const char* s_name, const char* r_name)
: AxisView(sess),
_route(rt),
mute_button(0),
solo_button(0),
rec_enable_button(0)
RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
: AxisView(sess)
{
init ();
set_button_names (mute_name, solo_name, rec_name);
}
RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
: AxisView(sess)
{
init ();
set_button_names (mute_name, solo_name, rec_name);
set_route (rt);
}
RouteUI::~RouteUI()
{
GoingAway (); /* EMIT SIGNAL */
delete solo_menu;
delete mute_menu;
delete remote_control_menu;
}
void
RouteUI::init ()
{
xml_node = 0;
mute_menu = 0;
@ -73,27 +93,87 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
polarity_menu_item = 0;
denormal_menu_item = 0;
mute_button = manage (new BindableToggleButton (""));
mute_button->set_self_managed (true);
mute_button->set_name ("MuteButton");
solo_button = manage (new BindableToggleButton (""));
solo_button->set_self_managed (true);
solo_button->set_name ("SoloButton");
rec_enable_button = manage (new BindableToggleButton (""));
rec_enable_button->set_name ("RecordEnableButton");
rec_enable_button->set_self_managed (true);
_session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
}
void
RouteUI::reset ()
{
connections.clear ();
if (solo_menu) {
delete solo_menu;
solo_menu = 0;
}
if (mute_menu) {
delete mute_menu;
mute_menu = 0;
}
if (remote_control_menu) {
delete remote_control_menu;
remote_control_menu = 0;
}
if (xml_node) {
/* do not delete the node - its owned by the route */
xml_node = 0;
}
route_active_menu_item = 0;
polarity_menu_item = 0;
denormal_menu_item = 0;
}
void
RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
{
m_name = mute;
s_name = solo;
r_name = rec;
}
void
RouteUI::set_route (boost::shared_ptr<Route> rp)
{
reset ();
_route = rp;
if (set_color_from_route()) {
set_color (unique_random_color());
}
new PairedShiva<Route,RouteUI> (*_route, *this);
_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed));
mute_button = manage (new BindableToggleButton (_route->mute_control(), m_name ));
mute_button->set_self_managed (true);
solo_button = manage (new BindableToggleButton (_route->solo_control(), s_name ));
solo_button->set_self_managed (true);
mute_button->set_name ("MuteButton");
solo_button->set_name ("SoloButton");
_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
/* no, there is no memory leak here. This object cleans itself (and other stuff)
up when the route is destroyed.
*/
new PairedShiva<Route,RouteUI> (*_route, *this);
mute_button->set_controllable (_route->mute_control());
mute_button->set_label (m_name);
solo_button->set_controllable (_route->solo_control());
solo_button->set_label (s_name);
connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
/* when solo changes, update mute state too, in case the user wants us to display it */
_session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
@ -101,15 +181,13 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
if (is_track()) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed));
connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
rec_enable_button = manage (new BindableToggleButton (t->rec_enable_control(), r_name ));
rec_enable_button->set_name ("RecordEnableButton");
rec_enable_button->set_self_managed (true);
rec_enable_button->show();
rec_enable_button->set_controllable (t->rec_enable_control());
rec_enable_button->set_label (r_name);
update_rec_display ();
}
@ -119,19 +197,13 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
mute_button->show();
solo_button->show();
_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu));
connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
/* map the current state */
map_frozen ();
}
RouteUI::~RouteUI()
{
GoingAway (); /* EMIT SIGNAL */
delete mute_menu;
}
bool
RouteUI::mute_press(GdkEventButton* ev)
{

View File

@ -45,9 +45,14 @@ class BindableToggleButton;
class RouteUI : public virtual AxisView
{
public:
RouteUI(ARDOUR::Session&, const char*, const char*, const char*);
RouteUI(boost::shared_ptr<ARDOUR::Route>, ARDOUR::Session&, const char*, const char*, const char*);
virtual ~RouteUI();
virtual void set_route (boost::shared_ptr<ARDOUR::Route>);
void set_button_names (const char*, const char*, const char*);
bool is_track() const;
bool is_audio_track() const;
bool is_midi_track() const;
@ -161,6 +166,15 @@ class RouteUI : public virtual AxisView
void reversibly_apply_track_boolean (string name, void (ARDOUR::Track::*func)(bool, void*), bool, void *);
void adjust_latency ();
protected:
std::vector<sigc::connection> connections;
std::string s_name;
std::string m_name;
std::string r_name;
void init ();
void reset ();
};
#endif /* __ardour_route_ui__ */

View File

@ -30,11 +30,14 @@ using namespace ARDOUR;
using namespace PBD;
SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
: _send (s),
_session (se),
gpm (s->io(), se),
panners (s->io(), se)
: _send (s)
, _session (se)
, gpm (se)
, panners (se)
{
panners.set_io (s->io());
gpm.set_io (s->io());
hbox.pack_start (gpm, true, true);
set_name ("SendUIFrame");

View File

@ -596,7 +596,8 @@ SoundFileBrowser::add_gain_meter ()
delete gm;
}
gm = new GainMeter (session->the_auditioner(), *session);
gm = new GainMeter (*session);
gm->set_io (session->the_auditioner());
meter_packer.set_border_width (12);
meter_packer.pack_start (*gm, false, true);

View File

@ -153,12 +153,45 @@ PluginManager::refresh ()
void
PluginManager::ladspa_refresh ()
{
_ladspa_plugin_info.clear ();
if (ladspa_path.length() == 0) {
ladspa_path = "/usr/local/lib64/ladspa:/usr/local/lib/ladspa:/usr/lib64/ladspa:/usr/lib/ladspa:/Library/Audio/Plug-Ins/LADSPA";
}
_ladspa_plugin_info.clear ();
static const char *standard_paths[] = {
"/usr/local/lib64/ladspa",
"/usr/local/lib/ladspa",
"/usr/lib64/ladspa",
"/usr/lib/ladspa",
"/Library/Audio/Plug-Ins/LADSPA",
""
};
/* allow LADSPA_PATH to augment, not override standard locations */
/* Only add standard locations to ladspa_path if it doesn't
* already contain them. Check for trailing '/'s too.
*/
int i;
for (i = 0; standard_paths[i][0]; i++) {
size_t found = ladspa_path.find(standard_paths[i]);
if (found != ladspa_path.npos) {
switch (ladspa_path[found + strlen(standard_paths[i])]) {
case ':' :
case '\0':
continue;
case '/' :
if (ladspa_path[found + strlen(standard_paths[i]) + 1] == ':' ||
ladspa_path[found + strlen(standard_paths[i]) + 1] == '\0') {
continue;
}
}
}
if (!ladspa_path.empty())
ladspa_path += ":";
ladspa_path += standard_paths[i];
}
ladspa_discover_from_path (ladspa_path);
}

View File

@ -40,6 +40,14 @@ BindingProxy::BindingProxy (boost::shared_ptr<Controllable> c)
{
}
BindingProxy::BindingProxy ()
: prompter (0),
bind_button (2),
bind_statemask (Gdk::CONTROL_MASK)
{
}
BindingProxy::~BindingProxy ()
{
if (prompter) {
@ -47,6 +55,13 @@ BindingProxy::~BindingProxy ()
}
}
void
BindingProxy::set_controllable (boost::shared_ptr<Controllable> c)
{
learning_finished ();
controllable = c;
}
void
BindingProxy::set_bind_button_state (guint button, guint statemask)
{
@ -64,7 +79,7 @@ BindingProxy::get_bind_button_state (guint &button, guint &statemask)
bool
BindingProxy::button_press_handler (GdkEventButton *ev)
{
if ((ev->state & bind_statemask) && ev->button == bind_button) {
if (controllable && (ev->state & bind_statemask) && ev->button == bind_button) {
if (Controllable::StartLearning (controllable.get())) {
string prompt = _("operate controller now");
if (prompter == 0) {
@ -95,7 +110,9 @@ bool
BindingProxy::prompter_hiding (GdkEventAny *ev)
{
learning_connection.disconnect ();
Controllable::StopLearning (controllable.get());
if (controllable) {
Controllable::StopLearning (controllable.get());
}
return false;
}

View File

@ -63,7 +63,9 @@ class BarController : public Gtk::Frame
/* export this to allow direct connection to button events */
Gtk::Widget& event_widget() { return darea; }
boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
void set_controllable(boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable(c); }
protected:
Gtk::Adjustment& adjustment;

View File

@ -32,10 +32,8 @@ namespace PBD {
class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
{
public:
BindableToggleButton (boost::shared_ptr<PBD::Controllable> c) : binding_proxy (c) {}
explicit BindableToggleButton (boost::shared_ptr<PBD::Controllable> c, const std::string &label)
: Gtkmm2ext::StatefulToggleButton (label), binding_proxy (c) {}
BindableToggleButton (const std::string &label)
: Gtkmm2ext::StatefulToggleButton (label) {}
virtual ~BindableToggleButton() {}
@ -49,7 +47,8 @@ class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
}
boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
private:
BindingProxy binding_proxy;
};
@ -58,10 +57,6 @@ class BindableButton : public Gtkmm2ext::StatefulButton
{
public:
BindableButton (boost::shared_ptr<PBD::Controllable> c) : binding_proxy (c) {}
explicit BindableButton (boost::shared_ptr<PBD::Controllable> c, const std::string &label)
: Gtkmm2ext::StatefulButton (label), binding_proxy (c) {}
~BindableButton() {}
bool on_button_press_event (GdkEventButton *ev) {
@ -74,6 +69,7 @@ class BindableButton : public Gtkmm2ext::StatefulButton
}
boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
private:
BindingProxy binding_proxy;

View File

@ -34,6 +34,7 @@ class BindingProxy : public sigc::trackable
{
public:
BindingProxy (boost::shared_ptr<PBD::Controllable>);
BindingProxy ();
virtual ~BindingProxy();
void set_bind_button_state (guint button, guint statemask);
@ -42,6 +43,7 @@ class BindingProxy : public sigc::trackable
bool button_press_handler (GdkEventButton *);
boost::shared_ptr<PBD::Controllable> get_controllable() { return controllable; }
void set_controllable (boost::shared_ptr<PBD::Controllable>);
protected:
Gtkmm2ext::PopUp* prompter;

View File

@ -41,7 +41,6 @@ class SliderController : public Gtkmm2ext::PixFader
public:
SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment* adj, int orientation,
boost::shared_ptr<PBD::Controllable>,
bool with_numeric = true);
virtual ~SliderController () {}
@ -52,6 +51,8 @@ class SliderController : public Gtkmm2ext::PixFader
bool on_button_press_event (GdkEventButton *ev);
void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
protected:
BindingProxy binding_proxy;
Glib::RefPtr<Gdk::Pixbuf> slider;
@ -59,6 +60,8 @@ class SliderController : public Gtkmm2ext::PixFader
Gtk::SpinButton spin;
Gtk::Frame spin_frame;
Gtk::HBox spin_hbox;
void init ();
};
class VSliderController : public SliderController
@ -66,7 +69,6 @@ class VSliderController : public SliderController
public:
VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
boost::shared_ptr<PBD::Controllable>,
bool with_numeric = true);
};
@ -75,7 +77,6 @@ class HSliderController : public SliderController
public:
HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
boost::shared_ptr<PBD::Controllable>,
bool with_numeric = true);
};

View File

@ -30,11 +30,9 @@ using namespace PBD;
SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj, int orientation,
boost::shared_ptr<Controllable> c,
bool with_numeric)
: PixFader (image, *adj, orientation),
binding_proxy (c),
spin (*adj, 0, 2)
{
spin.set_name ("SliderControllerValue");
@ -55,15 +53,15 @@ SliderController::on_button_press_event (GdkEventButton *ev)
if (binding_proxy.button_press_handler (ev)) {
return true;
}
return PixFader::on_button_press_event (ev);
}
VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
boost::shared_ptr<Controllable> control,
bool with_numeric)
: SliderController (image, adj, VERT, control, with_numeric)
: SliderController (image, adj, VERT, with_numeric)
{
if (with_numeric) {
spin_frame.add (spin);
@ -76,10 +74,9 @@ VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
boost::shared_ptr<Controllable> control,
bool with_numeric)
: SliderController (image, adj, HORIZ, control, with_numeric)
: SliderController (image, adj, HORIZ, with_numeric)
{
if (with_numeric) {
spin_frame.add (spin);