lots of debug code still in place, but get a much improved structure for MIDI automation menus actually working. tweaks to follow

git-svn-id: svn://localhost/ardour2/branches/3.0@6470 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2010-01-09 02:36:47 +00:00
parent c115b3d71c
commit ca2f505ec1
8 changed files with 303 additions and 253 deletions

View File

@ -454,8 +454,10 @@ AutomationTimeAxisView::set_height (uint32_t h)
}
if (changed) {
/* only emit the signal if the height really changed */
_route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
if (canvas_item_visible (_canvas_display)) {
/* only emit the signal if the height really changed and we were visible */
_route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
}
}
}
@ -928,3 +930,14 @@ AutomationTimeAxisView::hide ()
TimeAxisView::hide ();
}
bool
AutomationTimeAxisView::set_visibility (bool yn)
{
bool changed = TimeAxisView::set_visibility (yn);
if (changed) {
get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));
}
return changed;
}

View File

@ -69,6 +69,7 @@ class AutomationTimeAxisView : public TimeAxisView {
virtual void set_height (uint32_t);
void set_samples_per_unit (double);
bool set_visibility (bool yn);
std::string name() const { return _name; }
void add_automation_event (ArdourCanvas::Item *item, GdkEvent *event, nframes_t, double);

View File

@ -89,6 +89,7 @@
using namespace ARDOUR;
using namespace PBD;
using namespace Gtk;
using namespace Gtkmm2ext;
using namespace Editing;
// Minimum height at which a control is displayed
@ -112,13 +113,13 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
, _step_edit_item (0)
, _midi_thru_item (0)
, default_channel_menu (0)
, controller_menu (0)
{
subplugin_menu.set_name ("ArdourContextMenu");
_view = new MidiStreamView (*this);
ignore_toggle = false;
_ignore_toggle_parameter = false;
mute_button->set_active (false);
solo_button->set_active (false);
@ -200,6 +201,8 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
diskstream->get_channel_mask());
_channel_selector.mode_changed.connect(
sigc::mem_fun(*midi_track()->midi_diskstream(), &MidiDiskstream::set_channel_mode));
_channel_selector.mode_changed.connect(
sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
XMLProperty *prop;
if ((prop = xml_node->property ("color-mode")) != 0) {
@ -215,8 +218,6 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
_percussion_mode_item->set_active (_note_mode == Percussive);
}
}
build_controller_menu ();
}
MidiTimeAxisView::~MidiTimeAxisView ()
@ -381,22 +382,161 @@ MidiTimeAxisView::build_automation_action_menu ()
RouteTimeAxisView::build_automation_action_menu ();
MenuList& automation_items = automation_action_menu->items();
uint16_t selected_channels = _channel_selector.get_selected_channels();
automation_items.push_back (SeparatorElem());
if (selected_channels != 0) {
add_basic_parameter_menu_item (automation_items, _("Program Change"), Evoral::Parameter (MidiPgmChangeAutomation));
add_basic_parameter_menu_item (automation_items, _("Bender"), Evoral::Parameter (MidiPitchBenderAutomation));
add_basic_parameter_menu_item (automation_items, _("Pressure"), Evoral::Parameter (MidiChannelPressureAutomation));
automation_items.push_back (SeparatorElem());
if (controller_menu) {
/* these 3 MIDI "command" types are semantically more like automation than note data,
but they are not MIDI controllers. We give them special status in this menu, since
they will not show up in the controller list and anyone who actually knows
something about MIDI (!) would not expect to find them there.
*/
if (controller_menu->gobj()) {
if (controller_menu->get_attach_widget()) {
controller_menu->detach();
add_channel_command_menu_item (automation_items, _("Program Change"), MidiPgmChangeAutomation, MIDI_CMD_PGM_CHANGE);
add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, MIDI_CMD_BENDER);
add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, MIDI_CMD_CHANNEL_PRESSURE);
/* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
since it might need to be updated after a channel mode change or other change. Also detach it
first in case it has been used anywhere else.
*/
build_controller_menu ();
detach_menu (*controller_menu);
automation_items.push_back (SeparatorElem());
automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
} else {
automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
}
}
void
MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
{
uint16_t selected_channels = _channel_selector.get_selected_channels();
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
RouteAutomationNode* node = automation_track (fully_qualified_param);
if (node && node->menu_item) {
node->menu_item->set_active (yn);
}
}
}
}
automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
void
MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
{
using namespace Menu_Helpers;
/* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
*/
uint16_t selected_channels = _channel_selector.get_selected_channels();
int chn_cnt = 0;
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
if (++chn_cnt > 1) {
break;
}
}
}
if (chn_cnt > 1) {
/* multiple channels - create a submenu, with 1 item per channel */
Menu* chn_menu = manage (new Menu);
MenuList& chn_items (chn_menu->items());
Evoral::Parameter param_without_channel (auto_type, 0, cmd);
/* add a couple of items to hide/show all of them */
chn_items.push_back (MenuElem (_("Hide all channels"),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
false, param_without_channel)));
chn_items.push_back (MenuElem (_("Show all channels"),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
true, param_without_channel)));
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
/* for each selected channel, add a menu item for this controller */
Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
fully_qualified_param)));
RouteAutomationNode* node = automation_track (fully_qualified_param);
bool visible = false;
if (node) {
if (node->track->marked_for_display()) {
visible = true;
}
}
CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
if (node) {
node->menu_item = cmi;
}
cmi->set_active (visible);
parameter_menu_map[fully_qualified_param] = cmi;
}
}
/* now create an item in the parent menu that has the per-channel list as a submenu */
items.push_back (MenuElem (label, *chn_menu));
} else {
/* just one channel - create a single menu item for this command+channel combination*/
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
items.push_back (CheckMenuElem (label,
sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
fully_qualified_param)));
RouteAutomationNode* node = automation_track (fully_qualified_param);
bool visible = false;
if (node) {
if (node->track->marked_for_display()) {
visible = true;
}
}
CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
if (node) {
node->menu_item = cmi;
}
cmi->set_active (visible);
parameter_menu_map[fully_qualified_param] = cmi;
/* one channel only */
break;
}
}
}
}
@ -405,7 +545,12 @@ MidiTimeAxisView::build_controller_menu ()
{
using namespace Menu_Helpers;
controller_menu = new Menu; // not managed
if (controller_menu) {
/* it exists and has not been invalidated by a channel mode change, so just return it */
return;
}
controller_menu = new Menu; // explicitly managed by us
MenuList& items (controller_menu->items());
/* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu
@ -427,13 +572,17 @@ MidiTimeAxisView::build_controller_menu ()
}
}
/* loop over all 127 MIDI controllers, in groups of 16 */
for (int i = 0; i < 127; i += 16) {
Menu* ctl_menu = manage (new Menu);
MenuList& ctl_items (ctl_menu->items());
for (int ctl = i; ctl < i+16; ++ctl) {
/* for each controller, consider whether to create a submenu or a single item */
for (int ctl = i; ctl < i+16; ++ctl) {
if (chn_cnt > 1) {
@ -442,6 +591,16 @@ MidiTimeAxisView::build_controller_menu ()
Menu* chn_menu = manage (new Menu);
MenuList& chn_items (chn_menu->items());
/* add a couple of items to hide/show this controller on all channels */
Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
chn_items.push_back (MenuElem (_("Hide all channels"),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
false, param_without_channel)));
chn_items.push_back (MenuElem (_("Show all channels"),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
true, param_without_channel)));
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
@ -449,9 +608,9 @@ MidiTimeAxisView::build_controller_menu ()
Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_parameter_track),
sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
fully_qualified_param)));
RouteAutomationNode* node = automation_track (fully_qualified_param);
bool visible = false;
@ -462,6 +621,11 @@ MidiTimeAxisView::build_controller_menu ()
}
CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
if (node) {
node->menu_item = cmi;
}
cmi->set_active (visible);
parameter_menu_map[fully_qualified_param] = cmi;
@ -481,7 +645,7 @@ MidiTimeAxisView::build_controller_menu ()
Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_parameter_track),
sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
fully_qualified_param)));
RouteAutomationNode* node = automation_track (fully_qualified_param);
@ -494,8 +658,13 @@ MidiTimeAxisView::build_controller_menu ()
}
CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
if (node) {
node->menu_item = cmi;
}
cmi->set_active (visible);
parameter_menu_map[fully_qualified_param] = cmi;
/* one channel only */
break;
@ -510,51 +679,6 @@ MidiTimeAxisView::build_controller_menu ()
}
}
void
MidiTimeAxisView::add_basic_parameter_menu_item (Menu_Helpers::MenuList& items, const string& label, Evoral::Parameter param)
{
items.push_back (Menu_Helpers::CheckMenuElem
(label, sigc::bind (sigc::mem_fun
(*this, &MidiTimeAxisView::toggle_parameter_track), param)));
// cerr << "Create a new menu item from " << param.type() << '/' << param.id() << '/' << (int) param.channel() << endl;
uint16_t selected_channels = _channel_selector.get_selected_channels();
bool visible = false;
for (uint8_t i = 0; i < 16; i++) {
if (selected_channels & (0x0001 << i)) {
Evoral::Parameter param_with_channel(param.type(), i, param.id());
// cerr << "\tChecking on channel " << (int) i << " via " << param_with_channel.type() << '/' << param_with_channel.id() << endl;
RouteAutomationNode* node = automation_track (param_with_channel);
if (node) {
if (node->track->marked_for_display()) {
visible = true;
// cerr << "\tGot a track, and it appears visible\n";
break;
} else {
// cerr << "\tGot a track, and it appears hidden\n";
}
} else {
// cerr << "\tno track found\n";
}
}
}
CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
cmi->set_active (visible);
pair<ParameterMenuMap::iterator,bool> result;
result = parameter_menu_map.insert (pair<Evoral::Parameter,CheckMenuItem*> (param, cmi));
if (!result.second) {
/* it already exists, but we're asssigning a new menu item to it */
result.first->second = cmi;
}
}
Gtk::Menu*
MidiTimeAxisView::build_note_mode_menu()
{
@ -683,82 +807,6 @@ MidiTimeAxisView::show_existing_automation ()
RouteTimeAxisView::show_existing_automation ();
}
/** Prompt for a controller with a dialog and add an automation track for it
*/
void
MidiTimeAxisView::add_cc_track()
{
int response;
Evoral::Parameter param(0, 0, 0);
{
AddMidiCCTrackDialog dialog;
dialog.set_transient_for (_editor);
response = dialog.run();
if (response == Gtk::RESPONSE_ACCEPT)
param = dialog.parameter();
}
if (param.type() != 0 && response == Gtk::RESPONSE_ACCEPT)
create_automation_child(param, true);
}
/** Toggle an automation track for the given parameter (pitch bend, channel pressure).
* Will add track if necessary.
*/
void
MidiTimeAxisView::toggle_parameter_track(const Evoral::Parameter& param)
{
if (_ignore_toggle_parameter) {
return;
}
cerr << "CHANGE VISIBILITY OF " << param.type() << '/' << param.id() << '/' << (int) param.channel() << endl;
if ( !EventTypeMap::instance().is_midi_parameter(param) ) {
error << "MidiTimeAxisView: unknown automation child "
<< ARDOUR::EventTypeMap::instance().to_symbol(param) << endmsg;
return;
}
map<Evoral::Parameter,CheckMenuItem*>::iterator x = parameter_menu_map.find (param);
if (x == parameter_menu_map.end()) {
cerr << "Param not found in pm map\n";
return;
}
bool yn = x->second->get_active ();
cerr << "Menu item state for " << param.type() << '/' << param.id() << '/' << (int) param.channel() << ' ' << yn << endl;
cerr << "toggle param " << param.type() << '/' << param.id() << '/' << (int) param.channel() << " from " << !yn << " to " << yn << endl;
// create the parameter lane for each selected channel
uint16_t selected_channels = _channel_selector.get_selected_channels();
for (uint8_t i = 0; i < 16; i++) {
if (selected_channels & (0x0001 << i)) {
Evoral::Parameter param_with_channel(param.type(), i, param.id());
RouteAutomationNode* node = automation_track (param_with_channel);
if (!node) {
cerr << "\tNO EXISTING TRACK FOR chn " << (int) i << endl;
if (yn) {
create_automation_child (param_with_channel, true);
}
} else {
cerr << "\tTRACK EXISTS, set its menu item to " << yn << " to change its visibilty\n";
node->menu_item->set_active (yn);
}
}
}
_ignore_toggle_parameter = true;
x->second->set_active (yn);
_ignore_toggle_parameter = false;
}
/** Hide an automation track for the given parameter (pitch bend, channel pressure).
*/
void
@ -772,14 +820,16 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
return;
}
AutomationTracks::iterator existing = _automation_tracks.find(param);
if (existing != _automation_tracks.end())
AutomationTracks::iterator existing = _automation_tracks.find (param);
if (existing != _automation_tracks.end()) {
return;
}
boost::shared_ptr<AutomationControl> c = _route->get_control (param);
assert(c);
cerr << "Create new ATAV\n";
boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
_route, boost::shared_ptr<ARDOUR::Automatable>(), c,
_editor,
@ -788,7 +838,8 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
parent_canvas,
_route->describe_parameter(param)));
add_automation_child(param, track, show);
cerr << "Adding new automation child\n";
add_automation_child (param, track, show);
}
@ -1007,3 +1058,11 @@ MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t not
{
dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
}
void
MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
{
/* invalidate the controller menu, so that we rebuilt it next time */
delete controller_menu;
controller_menu = 0;
}

View File

@ -71,8 +71,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
void show_all_automation ();
void show_existing_automation ();
void add_cc_track ();
void toggle_parameter_track (const Evoral::Parameter& param);
void create_automation_child (const Evoral::Parameter& param, bool show);
ARDOUR::NoteMode note_mode() const { return _note_mode; }
@ -141,14 +139,16 @@ class MidiTimeAxisView : public RouteTimeAxisView
void set_default_channel (int);
void toggle_midi_thru ();
void change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param);
void add_basic_parameter_menu_item (Gtk::Menu_Helpers::MenuList& items, const std::string& label, Evoral::Parameter param);
bool _ignore_toggle_parameter;
void add_channel_command_menu_item (Gtk::Menu_Helpers::MenuList& items, const std::string& label, ARDOUR::AutomationType auto_type, uint8_t cmd);
typedef std::map<Evoral::Parameter,Gtk::CheckMenuItem*> ParameterMenuMap;
ParameterMenuMap parameter_menu_map;
Gtk::Menu* controller_menu;
void build_controller_menu ();
void set_channel_mode (ARDOUR::ChannelMode, uint16_t);
void add_note_selection (uint8_t note);
void extend_note_selection (uint8_t note);

View File

@ -125,6 +125,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh
playlist_menu = 0;
playlist_action_menu = 0;
automation_action_menu = 0;
plugins_submenu_item = 0;
mode_menu = 0;
_view = 0;
@ -416,78 +417,27 @@ RouteTimeAxisView::build_automation_action_menu ()
{
using namespace Menu_Helpers;
automation_action_menu = manage (new Menu);
cerr << "New AAM @ " << automation_action_menu << endl;
MenuList& automation_items = automation_action_menu->items();
delete automation_action_menu;
automation_action_menu = new Menu;
MenuList& items = automation_action_menu->items();
automation_action_menu->set_name ("ArdourContextMenu");
items.push_back (MenuElem (_("Show all automation"),
sigc::mem_fun(*this, &RouteTimeAxisView::show_all_automation)));
items.push_back (MenuElem (_("Show existing automation"),
sigc::mem_fun(*this, &RouteTimeAxisView::show_existing_automation)));
items.push_back (MenuElem (_("Hide all automation"),
sigc::mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
/* attach the plugin submenu. It may have previously been used elsewhere, so we detach it first. */
automation_items.push_back (MenuElem (_("Show all automation"),
sigc::mem_fun(*this, &RouteTimeAxisView::show_all_automation)));
automation_items.push_back (MenuElem (_("Show existing automation"),
sigc::mem_fun(*this, &RouteTimeAxisView::show_existing_automation)));
automation_items.push_back (MenuElem (_("Hide all automation"),
sigc::mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
if (subplugin_menu.gobj()) {
/* this will break if the underlying GTK menu has never been set up, hence
the if() above. we have to do this
*/
if (subplugin_menu.get_attach_widget()) {
subplugin_menu.detach();
}
automation_items.push_back (MenuElem (_("Plugins..."), subplugin_menu));
} else {
automation_items.push_back (MenuElem (_("Plugins")));
}
automation_items.back().set_sensitive (!subplugin_menu.items().empty());
map<Evoral::Parameter, RouteAutomationNode*>::iterator i;
map<string,Menu*> param_menu_map;
for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
string desc = _route->describe_parameter(i->second->param);
string::size_type bracket = desc.find_first_of ('[');
if (bracket == string::npos) {
/* item gets its own entry in the menu */
automation_items.push_back (CheckMenuElem (desc, sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::toggle_automation_track), i->second->param)));
i->second->menu_item = static_cast<Gtk::CheckMenuItem*>(&automation_items.back());
i->second->menu_item->set_active (show_automation (i->second->param));
automation_items.push_back (SeparatorElem());
} else {
/* subgroup related items in their own submenu */
string first_part = desc.substr (0, bracket);
Menu* m;
map<string,Menu*>::iterator x;
if ((x = param_menu_map.find (first_part)) == param_menu_map.end()) {
m = manage (new Menu);
m->set_name ("ArdourContextMenu");
automation_items.push_back (MenuElem (first_part + "...", *m));
param_menu_map.insert (pair<string,Menu*>(first_part, m));
} else {
m = x->second;
}
MenuList& mi = m->items();
mi.push_back (CheckMenuElem (desc, sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::toggle_automation_track), i->second->param)));
i->second->menu_item = static_cast<Gtk::CheckMenuItem*>(&mi.back());
i->second->menu_item->set_active(show_automation(i->second->param));
}
}
detach_menu (subplugin_menu);
items.push_back (MenuElem (_("Plugins"), subplugin_menu));
items.back().set_sensitive (!subplugin_menu.items().empty());
}
void
@ -516,11 +466,9 @@ RouteTimeAxisView::build_display_menu ()
if (!Profile->get_sae()) {
items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
/* rebuild this every time */
cerr << "Build a new AAM, old was " << automation_action_menu << endl;
build_automation_action_menu ();
cerr << "Attach AAM @ " << automation_action_menu << endl;
detach_menu (*automation_action_menu);
items.push_back (MenuElem (_("Automation"), *automation_action_menu));
cerr << "Attachment is done\n";
items.push_back (SeparatorElem());
}
@ -1669,32 +1617,29 @@ RouteTimeAxisView::color_handler ()
reset_meter();
}
/** Toggle an automation track for a fully-specified Parameter (type,channel,id)
* Will add track if necessary.
*/
void
RouteTimeAxisView::toggle_automation_track (Evoral::Parameter param)
RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
{
cerr << "CHANGE VISIBILITY OF " << param.type() << '/' << param.id() << '/' << (int) param.channel() << endl;
RouteAutomationNode* node = automation_track(param);
if (!node) {
return;
}
bool showit = node->menu_item->get_active();
if (showit != node->track->marked_for_display()) {
if (showit) {
node->track->set_marked_for_display (true);
node->track->canvas_display()->show();
node->track->get_state_node()->add_property ("shown", X_("yes"));
} else {
node->track->set_marked_for_display (false);
node->track->hide ();
node->track->get_state_node()->add_property ("shown", X_("no"));
}
/* now trigger a redisplay */
if (!no_redraw) {
_route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
cerr << "\tNO EXISTING TRACK, create it\n";
/* add it */
create_automation_child (param, true);
} else {
if (node->track->set_visibility (node->menu_item->get_active())) {
/* we changed the visibility, now trigger a redisplay */
if (!no_redraw) {
_route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
}
}
}
}
@ -1983,7 +1928,7 @@ RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Pro
}
void
RouteTimeAxisView::add_automation_child(Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
{
using namespace Menu_Helpers;
@ -2004,20 +1949,25 @@ RouteTimeAxisView::add_automation_child(Evoral::Parameter param, boost::shared_p
}
}
_automation_tracks.insert(std::make_pair(param, new RouteAutomationNode(param, NULL, track)));
_automation_tracks.insert (std::make_pair (param, new RouteAutomationNode(param, NULL, track)));
if (hideit) {
track->hide ();
} else {
track->set_visibility (!hideit);
if (!hideit) {
_show_automation.insert (param);
if (!no_redraw) {
_route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
}
}
_route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
build_display_menu();
if (!EventTypeMap::instance().is_midi_parameter(param)) {
/* MIDI-related parameters are always in the menu, there's no
reason to rebuild the menu just because we added a automation
lane for one of them. But if we add a non-MIDI automation
lane, then we need to invalidate the display menu.
*/
delete display_menu;
display_menu = 0;
}
}

View File

@ -99,6 +99,8 @@ public:
TimeAxisView::Children get_child_list();
void toggle_automation_track (const Evoral::Parameter& param);
/* The editor calls these when mapping an operation across multiple tracks */
void use_new_playlist (bool prompt, std::vector<boost::shared_ptr<ARDOUR::Playlist> > const &);
void use_copy_playlist (bool prompt, std::vector<boost::shared_ptr<ARDOUR::Playlist> > const &);
@ -198,7 +200,7 @@ protected:
boost::shared_ptr<ARDOUR::Processor>);
void automation_track_hidden (Evoral::Parameter param);
RouteAutomationNode* automation_track(Evoral::Parameter param);
RouteAutomationNode* automation_track(ARDOUR::AutomationType type);
@ -243,7 +245,6 @@ protected:
void rename_current_playlist ();
void automation_click ();
void toggle_automation_track (Evoral::Parameter param);
virtual void show_all_automation ();
virtual void show_existing_automation ();
virtual void hide_all_automation ();
@ -277,6 +278,7 @@ protected:
Gtk::Menu subplugin_menu;
Gtk::Menu* automation_action_menu;
Gtk::MenuItem* plugins_submenu_item;
RouteGroupMenu* route_group_menu;
Gtk::RadioMenuItem* align_existing_item;
Gtk::RadioMenuItem* align_capture_item;

View File

@ -89,6 +89,7 @@ TimeAxisView::TimeAxisView (ARDOUR::Session* sess, PublicEditor& ed, TimeAxisVie
}
_canvas_background = new Group (*ed.get_background_group (), 0.0, 0.0);
_canvas_display = new Group (*ed.get_trackview_group (), 0.0, 0.0);
_canvas_display->hide(); // reveal as needed
selection_group = new Group (*_canvas_display);
selection_group->hide();
@ -266,10 +267,15 @@ TimeAxisView::show_at (double y, int& nth, VBox *parent)
/* now show children */
cerr << name() << " has " << children.size() << " to show\n";
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
if (canvas_item_visible ((*i)->_canvas_display)) {
++nth;
_effective_height += (*i)->show_at (y + _effective_height, nth, parent);
cerr << "\tshowed " << (*i)->name() << " as " << nth << endl;
} else {
cerr << "\t" << (*i)->name() << " has an invisible canvas display\n";
}
}
@ -282,9 +288,11 @@ TimeAxisView::clip_to_viewport ()
if (_marked_for_display) {
if (_y_position + _effective_height < _editor.get_trackview_group_vertical_offset () || _y_position > _editor.get_trackview_group_vertical_offset () + _canvas_display->get_canvas()->get_height()) {
_canvas_background->hide ();
cerr << "Clip hides canvas display for " << name() << endl;
_canvas_display->hide ();
return;
}
cerr << "Clip shows canvas display for " << name() << endl;
_canvas_background->show ();
_canvas_display->show ();
}
@ -1357,3 +1365,19 @@ TimeAxisView::resizer_expose (GdkEventExpose* event)
return true;
}
bool
TimeAxisView::set_visibility (bool yn)
{
if (yn != marked_for_display()) {
if (yn) {
set_marked_for_display (true);
canvas_display()->show();
} else {
set_marked_for_display (false);
canvas_display()->hide ();
}
return true; // things changed
}
return false;
}

View File

@ -132,6 +132,7 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful
void show_name_label ();
void show_name_entry ();
virtual bool set_visibility (bool);
virtual guint32 show_at (double y, int& nth, Gtk::VBox *parent);
void clip_to_viewport ();