From 38eb5f4539786e0edafc31e275ed598bd4e4164b Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Tue, 29 Apr 2008 21:58:05 +0000 Subject: * renamed canvas-midi-event.* into canvas-note-event.* * make MidiModel keep track of its CanvasProgramChange instances git-svn-id: svn://localhost/ardour2/branches/3.0@3297 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/SConscript | 2 +- gtk2_ardour/canvas-midi-event.cc | 353 ----------------------------------- gtk2_ardour/canvas-midi-event.h | 102 ---------- gtk2_ardour/canvas-note-event.cc | 353 +++++++++++++++++++++++++++++++++++ gtk2_ardour/canvas-note-event.h | 102 ++++++++++ gtk2_ardour/canvas-note.h | 2 +- gtk2_ardour/canvas-program-change.cc | 3 +- gtk2_ardour/canvas-program-change.h | 9 +- gtk2_ardour/diamond.h | 2 +- gtk2_ardour/editor_canvas_events.cc | 2 +- gtk2_ardour/midi_region_view.cc | 16 +- gtk2_ardour/midi_region_view.h | 3 +- libs/ardour/midi_model.cc | 7 +- 13 files changed, 479 insertions(+), 477 deletions(-) delete mode 100644 gtk2_ardour/canvas-midi-event.cc delete mode 100644 gtk2_ardour/canvas-midi-event.h create mode 100644 gtk2_ardour/canvas-note-event.cc create mode 100644 gtk2_ardour/canvas-note-event.h diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index aceb587998..2d39c0b772 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -132,7 +132,7 @@ automation_time_axis.cc axis_view.cc bundle_manager.cc canvas-program-change.cc -canvas-midi-event.cc +canvas-note-event.cc canvas-note.cc canvas-simpleline.c canvas-simplerect.c diff --git a/gtk2_ardour/canvas-midi-event.cc b/gtk2_ardour/canvas-midi-event.cc deleted file mode 100644 index d9b5713183..0000000000 --- a/gtk2_ardour/canvas-midi-event.cc +++ /dev/null @@ -1,353 +0,0 @@ -/* - Copyright (C) 2007 Paul Davis - Author: Dave Robillard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include "canvas-midi-event.h" -#include "midi_region_view.h" -#include "public_editor.h" -#include "editing_syms.h" -#include "keyboard.h" - -using namespace std; -using ARDOUR::MidiModel; - -namespace Gnome { -namespace Canvas { - - -CanvasNoteEvent::CanvasNoteEvent(MidiRegionView& region, Item* item, - const boost::shared_ptr note) - : _region(region) - , _item(item) - , _text(0) - , _channel_selector_widget() - , _state(None) - , _note(note) - , _selected(false) -{ - _text = new Text(*(item->property_parent())); -} - -CanvasNoteEvent::~CanvasNoteEvent() -{ - if(_text) delete _text; - if(_channel_selector_widget) delete _channel_selector_widget; -} - -void -CanvasNoteEvent::move_event(double dx, double dy) -{ - _item->move(dx, dy); - _text->move(dx, dy); -} - -void -CanvasNoteEvent::show_velocity(void) -{ - _text->property_x() = (x1() + x2()) /2; - _text->property_y() = (y1() + y2()) /2; - ostringstream velo(ios::ate); - velo << int(_note->velocity()); - _text->property_text() = velo.str(); - _text->property_justification() = Gtk::JUSTIFY_CENTER; - _text->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(); - _text->show(); - _text->lower_to_bottom(); - _text->raise(2); -} - -void -CanvasNoteEvent::hide_velocity(void) -{ - _text->hide(); -} - -void -CanvasNoteEvent::on_channel_selection_change(uint16_t selection) -{ - // make note change its color if its channel is not marked active - if( (selection & (1 << _note->channel())) == 0 ) { - set_fill_color(ARDOUR_UI::config()->canvasvar_MidiNoteFillInactiveChannel.get()); - set_outline_color(ARDOUR_UI::config()->canvasvar_MidiNoteOutlineInactiveChannel.get()); - } else { - set_fill_color(note_fill_color(_note->velocity())); - set_outline_color(note_outline_color(_note->velocity())); - } - // this forces the item to update..... maybe slow... - _item->hide(); - _item->show(); -} - -void -CanvasNoteEvent::on_channel_change(uint8_t channel) -{ - _region.note_selected(this, true); - hide_channel_selector(); - _region.change_channel(channel); -} - -void -CanvasNoteEvent::show_channel_selector(void) -{ - if(_channel_selector_widget == 0) { - cerr << "Note has channel: " << int(_note->channel()) << endl; - SingleMidiChannelSelector* _channel_selector = new SingleMidiChannelSelector(_note->channel()); - _channel_selector->show_all(); - _channel_selector->channel_selected.connect( - sigc::mem_fun(this, &CanvasNoteEvent::on_channel_change)); - - _channel_selector_widget = - new Widget(*(_item->property_parent()), - x1(), - y2() + 2, - (Gtk::Widget &) *_channel_selector); - - _channel_selector_widget->hide(); - _channel_selector_widget->property_height() = 100; - _channel_selector_widget->property_width() = 100; - _channel_selector_widget->raise_to_top(); - _channel_selector_widget->show(); - } else { - hide_channel_selector(); - } -} - -void -CanvasNoteEvent::hide_channel_selector(void) -{ - if(_channel_selector_widget) { - _channel_selector_widget->hide(); - delete _channel_selector_widget; - _channel_selector_widget = 0; - } -} - -void -CanvasNoteEvent::selected(bool yn) -{ - if (!_note) { - return; - } else if (yn) { - set_fill_color(UINT_INTERPOLATE(note_fill_color(_note->velocity()), - ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 0.1)); - set_outline_color(ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get()); - show_velocity(); - } else { - set_fill_color(note_fill_color(_note->velocity())); - set_outline_color(note_outline_color(_note->velocity())); - hide_velocity(); - } - - _selected = yn; -} - - -bool -CanvasNoteEvent::on_event(GdkEvent* ev) -{ - MidiStreamView *streamview = _region.midi_stream_view(); - static uint8_t drag_delta_note = 0; - static double drag_delta_x = 0; - static double last_x, last_y; - double event_x, event_y, dx, dy; - bool select_mod; - uint8_t d_velocity = 10; - - if (_region.get_time_axis_view().editor.current_mouse_mode() != Editing::MouseNote) - return false; - - switch (ev->type) { - case GDK_SCROLL: - if (Keyboard::modifier_state_equals (ev->scroll.state, Keyboard::Level4Modifier)) { - d_velocity = 1; - } - - if(ev->scroll.direction == GDK_SCROLL_UP) { - _region.note_selected(this, true); - if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) { - // TODO: absolute velocity - } else { - _region.change_velocity(d_velocity, true); - } - return true; - } else if(ev->scroll.direction == GDK_SCROLL_DOWN) { - _region.note_selected(this, true); - if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) { - // TODO: absolute velocity - } else { - _region.change_velocity(-d_velocity, true); - } - return true; - } else { - return false; - } - - case GDK_KEY_PRESS: - if (_note && ev->key.keyval == GDK_Delete) { - selected(true); - _region.start_delta_command(); - _region.command_remove_note(this); - } - break; - - case GDK_KEY_RELEASE: - if (ev->key.keyval == GDK_Delete) { - _region.apply_command(); - } - break; - - case GDK_ENTER_NOTIFY: - _region.note_entered(this); - _item->grab_focus(); - show_velocity(); - Keyboard::magic_widget_grab_focus(); - break; - - case GDK_LEAVE_NOTIFY: - Keyboard::magic_widget_drop_focus(); - if(! selected()) { - hide_velocity(); - } - _region.get_canvas_group()->grab_focus(); - break; - - case GDK_BUTTON_PRESS: - if (ev->button.button == 1) { - _state = Pressed; - } else if (ev->button.button == 3) { - show_channel_selector(); - } - return true; - - case GDK_MOTION_NOTIFY: - event_x = ev->motion.x; - event_y = ev->motion.y; - - switch (_state) { - case Pressed: // Drag begin - if (_region.mouse_state() != MidiRegionView::SelectTouchDragging) { - _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, - Gdk::Cursor(Gdk::FLEUR), ev->motion.time); - _state = Dragging; - _item->property_parent().get_value()->w2i(event_x, event_y); - event_x = _region.snap_to_pixel(event_x); - last_x = event_x; - last_y = event_y; - drag_delta_x = 0; - drag_delta_note = 0; - _region.note_selected(this, true); - } - return true; - - case Dragging: // Drag motion - if (ev->motion.is_hint) { - int t_x; - int t_y; - GdkModifierType state; - gdk_window_get_pointer(ev->motion.window, &t_x, &t_y, &state); - event_x = t_x; - event_y = t_y; - } - _item->property_parent().get_value()->w2i(event_x, event_y); - - // Snap - event_x = _region.snap_to_pixel(event_x); - - dx = event_x - last_x; - dy = event_y - last_y; - - last_x = event_x; - - drag_delta_x += dx; - - // Snap to note rows - if (abs(dy) < streamview->note_height()) { - dy = 0.0; - } else { - int8_t this_delta_note; - if (dy > 0) { - this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0); - } else { - this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0); - } - drag_delta_note -= this_delta_note; - dy = streamview->note_height() * this_delta_note; - last_y = last_y + dy; - } - - _region.move_selection(dx, dy); - - return true; - default: - break; - } - break; - - case GDK_BUTTON_RELEASE: - select_mod = (ev->motion.state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)); - event_x = ev->button.x; - event_y = ev->button.y; - _item->property_parent().get_value()->w2i(event_x, event_y); - - if(ev->button.button == 3) { - return true; - } - - switch (_state) { - case Pressed: // Clicked - if (_region.midi_view()->editor.current_midi_edit_mode() == Editing::MidiEditSelect) { - _state = None; - - if (_selected && !select_mod && _region.selection_size() > 1) - _region.unique_select(this); - else if (_selected) - _region.note_deselected(this, select_mod); - else - _region.note_selected(this, select_mod); - } else if (_region.midi_view()->editor.current_midi_edit_mode() == Editing::MidiEditErase) { - _region.start_delta_command(); - _region.command_remove_note(this); - _region.apply_command(); - } - - return true; - case Dragging: // Dropped - _item->ungrab(ev->button.time); - _state = None; - - if (_note) - _region.note_dropped(this, - _region.midi_view()->editor.pixel_to_frame(abs(drag_delta_x)) - * ((drag_delta_x < 0.0) ? -1 : 1), - drag_delta_note); - return true; - default: - break; - } - - default: - break; - } - - return false; -} - -} // namespace Canvas -} // namespace Gnome - diff --git a/gtk2_ardour/canvas-midi-event.h b/gtk2_ardour/canvas-midi-event.h deleted file mode 100644 index f575808bb1..0000000000 --- a/gtk2_ardour/canvas-midi-event.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright (C) 2007 Paul Davis - Author: Dave Robillard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __gtk_ardour_canvas_midi_event_h__ -#define __gtk_ardour_canvas_midi_event_h__ - -#include "simplerect.h" -#include "midi_channel_selector.h" -#include -#include -#include - -class Editor; -class MidiRegionView; - -namespace Gnome { -namespace Canvas { - - -/** This manages all the event handling for any MIDI event on the canvas. - * - * This is not actually a canvas item itself to avoid the dreaded diamond, - * since various types of canvas items (Note (rect), Hit (diamond), etc) - * need to share this functionality but can't share an ancestor. - * - * Note: Because of this, derived classes need to manually bounce events to - * on_event, it won't happen automatically. - * - * A newer, better canvas should remove the need for all the ugly here. - */ -class CanvasNoteEvent : public sigc::trackable { -public: - CanvasNoteEvent( - MidiRegionView& region, - Item* item, - const boost::shared_ptr note = boost::shared_ptr()); - - virtual ~CanvasNoteEvent(); - - bool on_event(GdkEvent* ev); - - bool selected() const { return _selected; } - void selected(bool yn); - - void move_event(double dx, double dy); - - void show_velocity(); - void hide_velocity(); - - /** - * This slot is called, when a new channel is selected for the single event - * */ - void on_channel_change(uint8_t channel); - void on_channel_selection_change(uint16_t selection); - - void show_channel_selector(); - - void hide_channel_selector(); - - virtual void set_outline_color(uint32_t c) = 0; - virtual void set_fill_color(uint32_t c) = 0; - - virtual double x1() = 0; - virtual double y1() = 0; - virtual double x2() = 0; - virtual double y2() = 0; - - const boost::shared_ptr note() { return _note; } - -protected: - enum State { None, Pressed, Dragging }; - - MidiRegionView& _region; - Item* const _item; - Text* _text; - Widget* _channel_selector_widget; - State _state; - const boost::shared_ptr _note; - bool _own_note; - bool _selected; -}; - -} // namespace Gnome -} // namespace Canvas - -#endif /* __gtk_ardour_canvas_midi_event_h__ */ diff --git a/gtk2_ardour/canvas-note-event.cc b/gtk2_ardour/canvas-note-event.cc new file mode 100644 index 0000000000..d775514b1f --- /dev/null +++ b/gtk2_ardour/canvas-note-event.cc @@ -0,0 +1,353 @@ +/* + Copyright (C) 2007 Paul Davis + Author: Dave Robillard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include "canvas-note-event.h" +#include "midi_region_view.h" +#include "public_editor.h" +#include "editing_syms.h" +#include "keyboard.h" + +using namespace std; +using ARDOUR::MidiModel; + +namespace Gnome { +namespace Canvas { + + +CanvasNoteEvent::CanvasNoteEvent(MidiRegionView& region, Item* item, + const boost::shared_ptr note) + : _region(region) + , _item(item) + , _text(0) + , _channel_selector_widget() + , _state(None) + , _note(note) + , _selected(false) +{ + _text = new Text(*(item->property_parent())); +} + +CanvasNoteEvent::~CanvasNoteEvent() +{ + if(_text) delete _text; + if(_channel_selector_widget) delete _channel_selector_widget; +} + +void +CanvasNoteEvent::move_event(double dx, double dy) +{ + _item->move(dx, dy); + _text->move(dx, dy); +} + +void +CanvasNoteEvent::show_velocity(void) +{ + _text->property_x() = (x1() + x2()) /2; + _text->property_y() = (y1() + y2()) /2; + ostringstream velo(ios::ate); + velo << int(_note->velocity()); + _text->property_text() = velo.str(); + _text->property_justification() = Gtk::JUSTIFY_CENTER; + _text->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(); + _text->show(); + _text->lower_to_bottom(); + _text->raise(2); +} + +void +CanvasNoteEvent::hide_velocity(void) +{ + _text->hide(); +} + +void +CanvasNoteEvent::on_channel_selection_change(uint16_t selection) +{ + // make note change its color if its channel is not marked active + if( (selection & (1 << _note->channel())) == 0 ) { + set_fill_color(ARDOUR_UI::config()->canvasvar_MidiNoteFillInactiveChannel.get()); + set_outline_color(ARDOUR_UI::config()->canvasvar_MidiNoteOutlineInactiveChannel.get()); + } else { + set_fill_color(note_fill_color(_note->velocity())); + set_outline_color(note_outline_color(_note->velocity())); + } + // this forces the item to update..... maybe slow... + _item->hide(); + _item->show(); +} + +void +CanvasNoteEvent::on_channel_change(uint8_t channel) +{ + _region.note_selected(this, true); + hide_channel_selector(); + _region.change_channel(channel); +} + +void +CanvasNoteEvent::show_channel_selector(void) +{ + if(_channel_selector_widget == 0) { + cerr << "Note has channel: " << int(_note->channel()) << endl; + SingleMidiChannelSelector* _channel_selector = new SingleMidiChannelSelector(_note->channel()); + _channel_selector->show_all(); + _channel_selector->channel_selected.connect( + sigc::mem_fun(this, &CanvasNoteEvent::on_channel_change)); + + _channel_selector_widget = + new Widget(*(_item->property_parent()), + x1(), + y2() + 2, + (Gtk::Widget &) *_channel_selector); + + _channel_selector_widget->hide(); + _channel_selector_widget->property_height() = 100; + _channel_selector_widget->property_width() = 100; + _channel_selector_widget->raise_to_top(); + _channel_selector_widget->show(); + } else { + hide_channel_selector(); + } +} + +void +CanvasNoteEvent::hide_channel_selector(void) +{ + if(_channel_selector_widget) { + _channel_selector_widget->hide(); + delete _channel_selector_widget; + _channel_selector_widget = 0; + } +} + +void +CanvasNoteEvent::selected(bool yn) +{ + if (!_note) { + return; + } else if (yn) { + set_fill_color(UINT_INTERPOLATE(note_fill_color(_note->velocity()), + ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 0.1)); + set_outline_color(ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get()); + show_velocity(); + } else { + set_fill_color(note_fill_color(_note->velocity())); + set_outline_color(note_outline_color(_note->velocity())); + hide_velocity(); + } + + _selected = yn; +} + + +bool +CanvasNoteEvent::on_event(GdkEvent* ev) +{ + MidiStreamView *streamview = _region.midi_stream_view(); + static uint8_t drag_delta_note = 0; + static double drag_delta_x = 0; + static double last_x, last_y; + double event_x, event_y, dx, dy; + bool select_mod; + uint8_t d_velocity = 10; + + if (_region.get_time_axis_view().editor.current_mouse_mode() != Editing::MouseNote) + return false; + + switch (ev->type) { + case GDK_SCROLL: + if (Keyboard::modifier_state_equals (ev->scroll.state, Keyboard::Level4Modifier)) { + d_velocity = 1; + } + + if(ev->scroll.direction == GDK_SCROLL_UP) { + _region.note_selected(this, true); + if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) { + // TODO: absolute velocity + } else { + _region.change_velocity(d_velocity, true); + } + return true; + } else if(ev->scroll.direction == GDK_SCROLL_DOWN) { + _region.note_selected(this, true); + if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) { + // TODO: absolute velocity + } else { + _region.change_velocity(-d_velocity, true); + } + return true; + } else { + return false; + } + + case GDK_KEY_PRESS: + if (_note && ev->key.keyval == GDK_Delete) { + selected(true); + _region.start_delta_command(); + _region.command_remove_note(this); + } + break; + + case GDK_KEY_RELEASE: + if (ev->key.keyval == GDK_Delete) { + _region.apply_command(); + } + break; + + case GDK_ENTER_NOTIFY: + _region.note_entered(this); + _item->grab_focus(); + show_velocity(); + Keyboard::magic_widget_grab_focus(); + break; + + case GDK_LEAVE_NOTIFY: + Keyboard::magic_widget_drop_focus(); + if(! selected()) { + hide_velocity(); + } + _region.get_canvas_group()->grab_focus(); + break; + + case GDK_BUTTON_PRESS: + if (ev->button.button == 1) { + _state = Pressed; + } else if (ev->button.button == 3) { + show_channel_selector(); + } + return true; + + case GDK_MOTION_NOTIFY: + event_x = ev->motion.x; + event_y = ev->motion.y; + + switch (_state) { + case Pressed: // Drag begin + if (_region.mouse_state() != MidiRegionView::SelectTouchDragging) { + _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, + Gdk::Cursor(Gdk::FLEUR), ev->motion.time); + _state = Dragging; + _item->property_parent().get_value()->w2i(event_x, event_y); + event_x = _region.snap_to_pixel(event_x); + last_x = event_x; + last_y = event_y; + drag_delta_x = 0; + drag_delta_note = 0; + _region.note_selected(this, true); + } + return true; + + case Dragging: // Drag motion + if (ev->motion.is_hint) { + int t_x; + int t_y; + GdkModifierType state; + gdk_window_get_pointer(ev->motion.window, &t_x, &t_y, &state); + event_x = t_x; + event_y = t_y; + } + _item->property_parent().get_value()->w2i(event_x, event_y); + + // Snap + event_x = _region.snap_to_pixel(event_x); + + dx = event_x - last_x; + dy = event_y - last_y; + + last_x = event_x; + + drag_delta_x += dx; + + // Snap to note rows + if (abs(dy) < streamview->note_height()) { + dy = 0.0; + } else { + int8_t this_delta_note; + if (dy > 0) { + this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0); + } else { + this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0); + } + drag_delta_note -= this_delta_note; + dy = streamview->note_height() * this_delta_note; + last_y = last_y + dy; + } + + _region.move_selection(dx, dy); + + return true; + default: + break; + } + break; + + case GDK_BUTTON_RELEASE: + select_mod = (ev->motion.state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)); + event_x = ev->button.x; + event_y = ev->button.y; + _item->property_parent().get_value()->w2i(event_x, event_y); + + if(ev->button.button == 3) { + return true; + } + + switch (_state) { + case Pressed: // Clicked + if (_region.midi_view()->editor.current_midi_edit_mode() == Editing::MidiEditSelect) { + _state = None; + + if (_selected && !select_mod && _region.selection_size() > 1) + _region.unique_select(this); + else if (_selected) + _region.note_deselected(this, select_mod); + else + _region.note_selected(this, select_mod); + } else if (_region.midi_view()->editor.current_midi_edit_mode() == Editing::MidiEditErase) { + _region.start_delta_command(); + _region.command_remove_note(this); + _region.apply_command(); + } + + return true; + case Dragging: // Dropped + _item->ungrab(ev->button.time); + _state = None; + + if (_note) + _region.note_dropped(this, + _region.midi_view()->editor.pixel_to_frame(abs(drag_delta_x)) + * ((drag_delta_x < 0.0) ? -1 : 1), + drag_delta_note); + return true; + default: + break; + } + + default: + break; + } + + return false; +} + +} // namespace Canvas +} // namespace Gnome + diff --git a/gtk2_ardour/canvas-note-event.h b/gtk2_ardour/canvas-note-event.h new file mode 100644 index 0000000000..f575808bb1 --- /dev/null +++ b/gtk2_ardour/canvas-note-event.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2007 Paul Davis + Author: Dave Robillard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __gtk_ardour_canvas_midi_event_h__ +#define __gtk_ardour_canvas_midi_event_h__ + +#include "simplerect.h" +#include "midi_channel_selector.h" +#include +#include +#include + +class Editor; +class MidiRegionView; + +namespace Gnome { +namespace Canvas { + + +/** This manages all the event handling for any MIDI event on the canvas. + * + * This is not actually a canvas item itself to avoid the dreaded diamond, + * since various types of canvas items (Note (rect), Hit (diamond), etc) + * need to share this functionality but can't share an ancestor. + * + * Note: Because of this, derived classes need to manually bounce events to + * on_event, it won't happen automatically. + * + * A newer, better canvas should remove the need for all the ugly here. + */ +class CanvasNoteEvent : public sigc::trackable { +public: + CanvasNoteEvent( + MidiRegionView& region, + Item* item, + const boost::shared_ptr note = boost::shared_ptr()); + + virtual ~CanvasNoteEvent(); + + bool on_event(GdkEvent* ev); + + bool selected() const { return _selected; } + void selected(bool yn); + + void move_event(double dx, double dy); + + void show_velocity(); + void hide_velocity(); + + /** + * This slot is called, when a new channel is selected for the single event + * */ + void on_channel_change(uint8_t channel); + void on_channel_selection_change(uint16_t selection); + + void show_channel_selector(); + + void hide_channel_selector(); + + virtual void set_outline_color(uint32_t c) = 0; + virtual void set_fill_color(uint32_t c) = 0; + + virtual double x1() = 0; + virtual double y1() = 0; + virtual double x2() = 0; + virtual double y2() = 0; + + const boost::shared_ptr note() { return _note; } + +protected: + enum State { None, Pressed, Dragging }; + + MidiRegionView& _region; + Item* const _item; + Text* _text; + Widget* _channel_selector_widget; + State _state; + const boost::shared_ptr _note; + bool _own_note; + bool _selected; +}; + +} // namespace Gnome +} // namespace Canvas + +#endif /* __gtk_ardour_canvas_midi_event_h__ */ diff --git a/gtk2_ardour/canvas-note.h b/gtk2_ardour/canvas-note.h index 8f745bcbc8..de2d0ecb9d 100644 --- a/gtk2_ardour/canvas-note.h +++ b/gtk2_ardour/canvas-note.h @@ -23,7 +23,7 @@ #include #include "simplerect.h" -#include "canvas-midi-event.h" +#include "canvas-note-event.h" #include "midi_util.h" namespace Gnome { diff --git a/gtk2_ardour/canvas-program-change.cc b/gtk2_ardour/canvas-program-change.cc index 5883dd5b86..103bd7bb8d 100644 --- a/gtk2_ardour/canvas-program-change.cc +++ b/gtk2_ardour/canvas-program-change.cc @@ -1,7 +1,8 @@ #include "canvas-program-change.h" #include +#include "ardour_ui.h" -using namespace ArdourCanvas; +using namespace Gnome::Canvas; using namespace std; CanvasProgramChange::CanvasProgramChange( diff --git a/gtk2_ardour/canvas-program-change.h b/gtk2_ardour/canvas-program-change.h index cf99ca0715..37dc0cc8da 100644 --- a/gtk2_ardour/canvas-program-change.h +++ b/gtk2_ardour/canvas-program-change.h @@ -4,15 +4,14 @@ #include #include "simplerect.h" #include "simpleline.h" -#include "midi_region_view.h" #include #include #include -namespace Gnome -{ -namespace Canvas -{ +class MidiRegionView; + +namespace Gnome { +namespace Canvas { class CanvasProgramChange : public Group { diff --git a/gtk2_ardour/diamond.h b/gtk2_ardour/diamond.h index 32544f4880..da344fed29 100644 --- a/gtk2_ardour/diamond.h +++ b/gtk2_ardour/diamond.h @@ -21,7 +21,7 @@ #define __ardour_diamond_h__ #include -#include "canvas-midi-event.h" +#include "canvas-note-event.h" namespace Gnome { namespace Canvas { diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index 054be80bc6..0da0bfc487 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -40,7 +40,7 @@ #include "control_point.h" #include "canvas_impl.h" #include "simplerect.h" -#include "canvas-midi-event.h" +#include "canvas-note-event.h" #include "i18n.h" diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 09165bfcfd..d1b5f74990 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -431,6 +431,7 @@ MidiRegionView::clear_events() delete *i; _events.clear(); + _pgm_changes.clear(); } @@ -476,14 +477,8 @@ MidiRegionView::redisplay_model() } MidiModel::PgmChanges& pgm_changes = _model->pgm_changes(); - /* - for (MidiModel::PgmChanges::const_iterator i = pgm_changes.begin(); - i != pgm_changes.end(); - ++i) { - add_pgm_change() - } - */ - for_each(pgm_changes.begin(), pgm_changes.end(), sigc::mem_fun(this, &MidiRegionView::add_pgm_change)); + for_each(pgm_changes.begin(), pgm_changes.end(), + sigc::mem_fun(this, &MidiRegionView::add_pgm_change)); end_write(); @@ -820,8 +815,9 @@ MidiRegionView::add_pgm_change(boost::shared_ptr event) const double x = trackview.editor.frame_to_pixel((nframes_t)event->time() - _region->start()); double height = midi_stream_view()->contents_height(); - new CanvasProgramChange(*this, *group, event, height, x, 1.0); - //TODO : keep track of pgm changes + _pgm_changes.push_back( + boost::shared_ptr( + new CanvasProgramChange(*this, *group, event, height, x, 1.0))); } void diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index 7c545fa82a..1a37205bef 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -36,7 +36,7 @@ #include "enums.h" #include "canvas.h" #include "canvas-note.h" -#include "canvas-midi-event.h" +#include "canvas-note-event.h" #include "canvas-program-change.h" namespace ARDOUR { @@ -254,6 +254,7 @@ class MidiRegionView : public RegionView boost::shared_ptr _model; std::vector _events; + std::vector< boost::shared_ptr > _pgm_changes; ArdourCanvas::CanvasNote** _active_notes; ArdourCanvas::Group* _note_group; ARDOUR::MidiModel::DeltaCommand* _delta_command; diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 495991853a..23dff7f165 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -362,11 +362,13 @@ MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes assert(_read_iter->size() > 0); dst.write(_read_iter->time() + stamp_offset - negative_stamp_offset, _read_iter->size(), _read_iter->buffer()); + /* cerr << this << " MidiModel::read event @ " << _read_iter->time() << " type: " << hex << int(_read_iter->type()) << dec << " note: " << int(_read_iter->note()) << " velocity: " << int(_read_iter->velocity()) << endl; + */ ++_read_iter; ++read_events; @@ -573,7 +575,7 @@ MidiModel::append_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t void MidiModel::append_pgm_change_unlocked(uint8_t chan, double time, uint8_t number) { - cerr << "MidiModel::append_pgm_change_unlocked: channel " << int(chan) << " time: " << time << " program number: " << int(number) < note) for(Notes::iterator n = _notes.begin(); n != _notes.end(); ++n) { Note& _n = *(*n); const Note& _note = *note; + // TODO: There is still the issue, that after restarting ardour + // persisted undo does not work, because of rounding errors in the + // event times after saving/restoring to/from MIDI files cerr << "======================================= " << endl; cerr << int(_n.note()) << "@" << int(_n.time()) << "[" << int(_n.channel()) << "] --" << int(_n.duration()) << "-- #" << int(_n.velocity()) << endl; cerr << int(_note.note()) << "@" << int(_note.time()) << "[" << int(_note.channel()) << "] --" << int(_note.duration()) << "-- #" << int(_note.velocity()) << endl; -- cgit v1.2.3