diff -rupN seq24-rev48 adding win32/src/config.h seq24-rev48 win32 adding MouseInteraction/src/config.h --- seq24-rev48 adding win32/src/config.h 2009-05-20 20:54:39.640625000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/config.h 2009-05-20 20:54:43.796875000 -0500 @@ -36,7 +36,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "0.9.0-win32-beta-1" +#define VERSION "0.9.0-win32-beta-1a" /* gnu source */ #define _GNU_SOURCE 1 diff -rupN seq24-rev48 adding win32/src/config_win32.h seq24-rev48 win32 adding MouseInteraction/src/config_win32.h --- seq24-rev48 adding win32/src/config_win32.h 2009-05-20 20:54:57.171875000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/config_win32.h 2009-05-20 20:55:01.437500000 -0500 @@ -36,7 +36,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "0.9.0-win32-beta-1" +#define VERSION "0.9.0-win32-beta-1a" /* gnu source */ #define _GNU_SOURCE 1 diff -rupN seq24-rev48 adding win32/src/globals.h seq24-rev48 win32 adding MouseInteraction/src/globals.h --- seq24-rev48 adding win32/src/globals.h 2009-05-20 20:30:46.046875000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/globals.h 2009-05-20 20:30:50.281250000 -0500 @@ -127,8 +127,11 @@ const int c_normal = 1; const int c_paste = 2; /* redraw when recording ms */ +#ifdef __WIN32__ +const int c_redraw_ms = 20; +#else const int c_redraw_ms = 40; - +#endif /* consts for perform editor */ const int c_names_x = 6 * 24; @@ -296,5 +299,24 @@ enum mouse_action_e e_action_grow }; +enum interaction_method_e +{ + e_seq24_interaction, + e_fruity_interaction, + e_number_of_interactions // keep this one last... +}; +const char* const c_interaction_method_names[] = +{ + "seq24", + "fruity", + NULL +}; +const char* const c_interaction_method_descs[] = +{ + "original seq24 method", + "similar to a certain fruity sequencer we like", + NULL +}; +extern interaction_method_e global_interactionmethod; #endif diff -rupN seq24-rev48 adding win32/src/mainwnd.cpp seq24-rev48 win32 adding MouseInteraction/src/mainwnd.cpp --- seq24-rev48 adding win32/src/mainwnd.cpp 2009-05-20 20:30:46.234375000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/mainwnd.cpp 2009-05-20 20:30:50.484375000 -0500 @@ -711,10 +711,10 @@ mainwnd::on_key_press_event(GdkEventKey* { // control and modifier key combinations matching // menu items have first priority - if (Gtk::Window::on_key_press_event(a_ev)) - return true; + /*if (*/Gtk::Window::on_key_press_event(a_ev); + //return true; // on win32, it'd always return true here (i.e. for SPACE bar)... ? - else if ( m_entry_notes->has_focus()) { + /*else */if ( m_entry_notes->has_focus()) { m_entry_notes->event( (GdkEvent*) a_ev ); return false; } diff -rupN seq24-rev48 adding win32/src/options.cpp seq24-rev48 win32 adding MouseInteraction/src/options.cpp --- seq24-rev48 adding win32/src/options.cpp 2009-05-20 20:30:46.656250000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/options.cpp 2009-05-20 20:30:50.890625000 -0500 @@ -120,6 +120,30 @@ options::options (Gtk::Window & parent, clock_mod_adj->signal_value_changed().connect( sigc::bind(mem_fun(*this,&options::clock_mod_callback),clock_mod_adj)); + // add controls for input method + { + Adjustment *adj = new Adjustment( global_interactionmethod, 0, e_number_of_interactions-1, 1 ); + SpinButton *spin = new SpinButton( *adj ); + + HBox *hbox2 = manage (new HBox ()); + HBox *hbox3 = manage (new HBox ()); + + //m_spinbutton_bpm->set_editable( false ); + interaction_method_label = new Label( " Input Method " ); + hbox2->pack_start(*(manage( interaction_method_label )), false, false, 4); + hbox2->pack_start(*spin, false, false ); + + vbox->pack_start( *hbox2, false, false ); + + interaction_method_desc_label = new Label( " ----- " ); + hbox3->pack_start(*(manage( interaction_method_desc_label )), false, false, 4); + vbox->pack_start(*hbox3, false, false ); + + adj->signal_value_changed().connect( SigC::bind(mem_fun(*this,&options::interaction_method_callback),adj)); + + // force it to refresh. + interaction_method_callback( adj ); + } // Input Buses buses = m_perf->get_master_midi_bus ()->get_num_in_buses (); @@ -254,6 +278,21 @@ options::clock_mod_callback( Adjustment midibus::set_clock_mod((int)adj->get_value()); } +void +options::interaction_method_callback( Adjustment *adj ) +{ + global_interactionmethod = (interaction_method_e)(int)adj->get_value(); + std::string text = " Interaction Method ("; + text += c_interaction_method_names[(int)adj->get_value()]; + text += "): "; + interaction_method_label->set_text( text.c_str() ); + + text = " ("; + text += c_interaction_method_descs[(int)adj->get_value()]; + text += ") "; + interaction_method_desc_label->set_text( text.c_str() ); +} + void options::input_callback (int a_bus, Button * i_button) diff -rupN seq24-rev48 adding win32/src/options.h seq24-rev48 win32 adding MouseInteraction/src/options.h --- seq24-rev48 adding win32/src/options.h 2009-05-20 20:30:46.671875000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/options.h 2009-05-20 20:30:50.906250000 -0500 @@ -63,6 +63,8 @@ class options : public Gtk::Dialog perform *m_perf; Button *m_button_ok; + Label* interaction_method_label; + Label* interaction_method_desc_label; Table *m_table; @@ -85,6 +87,7 @@ class options : public Gtk::Dialog void clock_callback_mod( int a_bus, RadioButton *a_button ); void clock_mod_callback( Adjustment *adj ); + void interaction_method_callback( Adjustment *adj ); void input_callback( int a_bus, Button *a_button ); void transport_callback( button a_type, Button *a_button ); diff -rupN seq24-rev48 adding win32/src/optionsfile.cpp seq24-rev48 win32 adding MouseInteraction/src/optionsfile.cpp --- seq24-rev48 adding win32/src/optionsfile.cpp 2009-05-20 20:30:46.703125000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/optionsfile.cpp 2009-05-20 20:30:50.937500000 -0500 @@ -187,7 +187,12 @@ optionsfile::parse( perform *a_perf ) if (m_line[0] == '/') last_used_dir.assign(m_line); - + /* interaction method */ + long method = 0; + line_after( &file, "[interaction-method]" ); + sscanf( m_line, "%ld", &method ); + global_interactionmethod = (interaction_method_e)method; + file.close(); return true; @@ -305,6 +310,17 @@ optionsfile::write( perform *a_perf ) file << "# not connect to other clients\n"; file << global_manual_alsa_ports << "\n"; + /* interaction-method */ + int x = 0; + file << "\n\n\n[interaction-method]\n"; + while (c_interaction_method_names[x] && c_interaction_method_descs[x]) + { + file << "# " << x << " - '" << c_interaction_method_names[x] + << "' (" << c_interaction_method_descs[x] << ")\n"; + ++x; + } + file << global_interactionmethod << "\n"; + file << "\n\n\n[keyboard-control]\n"; diff -rupN seq24-rev48 adding win32/src/perform.h seq24-rev48 win32 adding MouseInteraction/src/perform.h --- seq24-rev48 adding win32/src/perform.h 2009-05-20 20:30:46.968750000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/perform.h 2009-05-20 20:30:51.203125000 -0500 @@ -109,7 +109,6 @@ class perform long m_tick; void set_running( bool a_running ); - bool is_running(); void set_playback_mode( bool a_playback_mode ); @@ -146,6 +145,7 @@ class perform void inner_stop(); public: + bool is_running(); unsigned int m_key_bpm_up; unsigned int m_key_bpm_dn; diff -rupN seq24-rev48 adding win32/src/perfroll.cpp seq24-rev48 win32 adding MouseInteraction/src/perfroll.cpp --- seq24-rev48 adding win32/src/perfroll.cpp 2009-05-20 20:30:47.031250000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/perfroll.cpp 2009-05-20 20:30:51.281250000 -0500 @@ -47,8 +47,6 @@ perfroll::perfroll( perform *a_perf, m_vadjust = a_vadjust; m_hadjust = a_hadjust; - m_adding = false; - m_adding_pressed = false; m_moving = false; m_growing = false; @@ -104,23 +102,6 @@ perfroll::change_vert( ) } } -/* popup menu calls this */ -void -perfroll::set_adding( bool a_adding ) -{ - if ( a_adding ){ - - get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL )); - m_adding = true; - - } else { - - get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); - m_adding = false; - } -} - - void perfroll::on_realize() { @@ -620,168 +601,50 @@ perfroll::draw_drawable_row( Glib::RefPt c_names_y ); } -bool -perfroll::on_button_press_event(GdkEventButton* a_ev) -{ - grab_focus( ); - - - if ( m_mainperf->is_active( m_drop_sequence )) - { - m_mainperf->get_sequence( m_drop_sequence )->unselect_triggers( ); - draw_background_on( m_pixmap, m_drop_sequence ); - draw_sequence_on( m_pixmap, m_drop_sequence ); - draw_drawable_row( m_window, m_pixmap, m_drop_y); - } - - m_drop_x = (int) a_ev->x; - m_drop_y = (int) a_ev->y; - - convert_xy( m_drop_x, m_drop_y, &m_drop_tick, &m_drop_sequence ); - - /* left mouse button */ - if ( a_ev->button == 1 ){ - - long tick = m_drop_tick; - - /* add a new note if we didnt select anything */ - if ( m_adding ){ - - m_adding_pressed = true; - - if ( m_mainperf->is_active( m_drop_sequence )){ - - long seq_length = m_mainperf->get_sequence( m_drop_sequence )->get_length( ); - - bool state = m_mainperf->get_sequence( m_drop_sequence )->get_trigger_state( tick ); - - if ( state ) - { - m_mainperf->push_trigger_undo(); - m_mainperf->get_sequence( m_drop_sequence )->del_trigger( tick ); - } - else - { - - // snap to length of sequence - tick = tick - (tick % seq_length); - m_adding_pressed_state = true; - - m_mainperf->push_trigger_undo(); - m_mainperf->get_sequence( m_drop_sequence )->add_trigger( tick, seq_length ); - draw_background_on( m_pixmap, m_drop_sequence ); - draw_sequence_on( m_pixmap, m_drop_sequence ); - draw_drawable_row( m_window, m_pixmap, m_drop_y); - - //m_drop_tick_last = (m_drop_tick + seq_length - 1); - } - } - } - else { - - if ( m_mainperf->is_active( m_drop_sequence )){ - - m_mainperf->push_trigger_undo(); - m_mainperf->get_sequence( m_drop_sequence )->select_trigger( tick ); - - long start_tick = m_mainperf->get_sequence( m_drop_sequence )->get_selected_trigger_start_tick(); - long end_tick = m_mainperf->get_sequence( m_drop_sequence )->get_selected_trigger_end_tick(); - - if ( tick >= start_tick && - tick <= start_tick + (c_perfroll_size_box_click_w * c_perf_scale_x) && - (m_drop_y % c_names_y) <= c_perfroll_size_box_click_w + 1 ) - { - m_growing = true; - m_grow_direction = true; - m_drop_tick_trigger_offset = m_drop_tick - - m_mainperf->get_sequence( m_drop_sequence )-> - get_selected_trigger_start_tick( ); - } - else - if ( tick >= end_tick - (c_perfroll_size_box_click_w * c_perf_scale_x) && - tick <= end_tick && - (m_drop_y % c_names_y) >= c_names_y - c_perfroll_size_box_click_w - 1 ) - { - m_growing = true; - m_grow_direction = false; - m_drop_tick_trigger_offset = - m_drop_tick - - m_mainperf->get_sequence( m_drop_sequence )->get_selected_trigger_end_tick( ); - } - else - { - m_moving = true; - m_drop_tick_trigger_offset = m_drop_tick - - m_mainperf->get_sequence( m_drop_sequence )-> - get_selected_trigger_start_tick( ); - } +void +perfroll::start_playing( void ) +{ + // keep in sync with perfedit's start_playing... wish i could call it directly... + m_mainperf->position_jack( true ); + m_mainperf->start_jack( ); + m_mainperf->start( true ); +} - draw_background_on( m_pixmap, m_drop_sequence ); - draw_sequence_on( m_pixmap, m_drop_sequence ); - draw_drawable_row( m_window, m_pixmap, m_drop_y); - } - } - } +void +perfroll::stop_playing( void ) +{ + // keep in sync with perfedit's stop_playing... wish i could call it directly... + m_mainperf->stop_jack(); + m_mainperf->stop(); +} - /* right mouse button */ - if ( a_ev->button == 3 ){ - set_adding( true ); - } - /* middle, split */ - if ( a_ev->button == 2 ) +bool +perfroll::on_button_press_event(GdkEventButton* a_ev) +{ + switch (global_interactionmethod) { - long tick = m_drop_tick; - - if ( m_mainperf->is_active( m_drop_sequence )){ - - bool state = m_mainperf->get_sequence( m_drop_sequence )->get_trigger_state( tick ); - - if ( state ) - { - m_mainperf->push_trigger_undo(); - - m_mainperf->get_sequence( m_drop_sequence )->split_trigger( tick ); - - draw_background_on( m_pixmap, m_drop_sequence ); - draw_sequence_on( m_pixmap, m_drop_sequence ); - draw_drawable_row( m_window, m_pixmap, m_drop_y); - } - } + case e_fruity_interaction: + return m_fruity_interaction.on_button_press_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_button_press_event(a_ev, *this); } - return true; + return false; } bool perfroll::on_button_release_event(GdkEventButton* a_ev) { - - if ( a_ev->button == 1 ){ - - if ( m_adding ){ - m_adding_pressed = false; - } - } - - else if ( a_ev->button == 3 ){ - m_adding_pressed = false; - set_adding( false ); - } - - m_moving = false; - m_growing = false; - m_adding_pressed = false; - - if ( m_mainperf->is_active( m_drop_sequence )){ - - draw_background_on( m_pixmap, m_drop_sequence ); - draw_sequence_on( m_pixmap, m_drop_sequence ); - draw_drawable_row( m_window, m_pixmap, m_drop_y ); + switch (global_interactionmethod) + { + case e_fruity_interaction: + return m_fruity_interaction.on_button_release_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_button_release_event(a_ev, *this); } - - return true; + return false; } bool @@ -824,59 +687,14 @@ perfroll::on_scroll_event( GdkEventScrol bool perfroll::on_motion_notify_event(GdkEventMotion* a_ev) { - - long tick; - int x = (int) a_ev->x; - - if ( m_adding && m_adding_pressed ){ - - convert_x( x, &tick ); - - if ( m_mainperf->is_active( m_drop_sequence )){ - - long seq_length = m_mainperf->get_sequence( m_drop_sequence )->get_length( ); - tick = tick - (tick % seq_length); - - /*long min_tick = (tick < m_drop_tick) ? tick : m_drop_tick;*/ - long length = seq_length; - - m_mainperf->get_sequence( m_drop_sequence )->grow_trigger( m_drop_tick, tick, length); - draw_background_on( m_pixmap, m_drop_sequence ); - draw_sequence_on( m_pixmap, m_drop_sequence ); - draw_drawable_row( m_window, m_pixmap, m_drop_y); - } - } - else if ( m_moving || m_growing ){ - - if ( m_mainperf->is_active( m_drop_sequence)){ - - convert_x( x, &tick ); - tick -= m_drop_tick_trigger_offset; - - tick = tick - tick % m_snap; - - if ( m_moving ) - { - m_mainperf->get_sequence( m_drop_sequence )->move_selected_triggers_to( tick, true ); - } - if ( m_growing ) - { - if ( m_grow_direction ) - m_mainperf->get_sequence( m_drop_sequence )->move_selected_triggers_to( tick, false, 0 ); - else - m_mainperf->get_sequence( m_drop_sequence )->move_selected_triggers_to( tick-1, false, 1 ); - } - - - draw_background_on( m_pixmap, m_drop_sequence ); - draw_sequence_on( m_pixmap, m_drop_sequence ); - draw_drawable_row( m_window, m_pixmap, m_drop_y); - } + switch (global_interactionmethod) + { + case e_fruity_interaction: + return m_fruity_interaction.on_motion_notify_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_motion_notify_event(a_ev, *this); } - - - - return true; + return false; } bool @@ -1013,3 +831,522 @@ void perfroll::on_size_request(GtkRequisition* a_r ) { } + + + + +////////////////////////// +// interaction methods +////////////////////////// + + +void FruityPerfInput::updateMousePtr( perfroll& ths ) +{ + // context sensitive mouse + long drop_tick; + int drop_sequence; + ths.convert_xy( m_current_x, m_current_y, &drop_tick, &drop_sequence ); + if (ths.m_mainperf->is_active( drop_sequence )) + { + long start, end; + if (ths.m_mainperf->get_sequence(drop_sequence)->intersectTriggers( drop_tick, start, end )) + { + if (start <= drop_tick && drop_tick <= start + (c_perfroll_size_box_click_w * c_perf_scale_x) && + (m_current_y % c_names_y) <= c_perfroll_size_box_click_w + 1) + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::RIGHT_PTR )); + } + else if (end - (c_perfroll_size_box_click_w * c_perf_scale_x) <= drop_tick && drop_tick <= end && + (m_current_y % c_names_y) >= c_names_y - c_perfroll_size_box_click_w - 1) + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); + } + else + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::CENTER_PTR )); + } + } + else + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL )); + } + } + else + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::CROSSHAIR )); + } +} + + +bool FruityPerfInput::on_button_press_event(GdkEventButton* a_ev, perfroll& ths) +{ + ths.grab_focus( ); + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )) + { + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->unselect_triggers( ); + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + + ths.m_drop_x = (int) a_ev->x; + ths.m_drop_y = (int) a_ev->y; + m_current_x = (int) a_ev->x; + m_current_y = (int) a_ev->y; + + + ths.convert_xy( ths.m_drop_x, ths.m_drop_y, &ths.m_drop_tick, &ths.m_drop_sequence ); + + /* left mouse button */ + if ( a_ev->button == 1 && !(a_ev->state & GDK_CONTROL_MASK)){ + + long tick = ths.m_drop_tick; + + /* add a new note if we didnt select anything */ + //if ( m_adding ) + { + + m_adding_pressed = true; + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + long seq_length = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_length( ); + + bool state = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_trigger_state( tick ); + + // resize the event, or move it, depending on where clicked. + if ( state ) + { + //m_adding = false; + m_adding_pressed = false; + ths.m_mainperf->push_trigger_undo(); + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->select_trigger( tick ); + + long start_tick = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_selected_trigger_start_tick(); + long end_tick = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_selected_trigger_end_tick(); + + if ( tick >= start_tick && + tick <= start_tick + (c_perfroll_size_box_click_w * c_perf_scale_x) && + (ths.m_drop_y % c_names_y) <= c_perfroll_size_box_click_w + 1 ) + { + // clicked left side: begin a grow/shrink for the left side + ths.m_growing = true; + ths.m_grow_direction = true; + ths.m_drop_tick_trigger_offset = ths.m_drop_tick - + ths.m_mainperf->get_sequence( ths.m_drop_sequence )-> + get_selected_trigger_start_tick( ); + } + else + if ( tick >= end_tick - (c_perfroll_size_box_click_w * c_perf_scale_x) && + tick <= end_tick && + (ths.m_drop_y % c_names_y) >= c_names_y - c_perfroll_size_box_click_w - 1 ) + { + // clicked right side: grow/shrink the right side + ths.m_growing = true; + ths.m_grow_direction = false; + ths.m_drop_tick_trigger_offset = + ths.m_drop_tick - + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_selected_trigger_end_tick( ); + } + else + { + // clicked in the middle - move it + ths.m_moving = true; + ths.m_drop_tick_trigger_offset = ths.m_drop_tick - + ths.m_mainperf->get_sequence( ths.m_drop_sequence )-> + get_selected_trigger_start_tick( ); + + } + + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + + // add an event: + else + { + + // snap to length of sequence + tick = tick - (tick % seq_length); + + ths.m_mainperf->push_trigger_undo(); + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->add_trigger( tick, seq_length ); + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + + //m_drop_tick_last = (m_drop_tick + seq_length - 1); + } + } + } + } + + /* right mouse button */ + if ( a_ev->button == 3 ){ + //set_adding( false ); + + long tick = ths.m_drop_tick; + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + long seq_length = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_length( ); + + bool state = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_trigger_state( tick ); + + if ( state ) + { + ths.m_mainperf->push_trigger_undo(); + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->del_trigger( tick ); + } + } + } + + /* left-ctrl, or middle: split */ + if ( a_ev->button == 2 || + a_ev->button == 1 && (a_ev->state & GDK_CONTROL_MASK) ) + { + long tick = ths.m_drop_tick; + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + bool state = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_trigger_state( tick ); + + if ( state ) + { + ths.m_mainperf->push_trigger_undo(); + + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->split_trigger( tick ); + + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + } + } + updateMousePtr( ths ); + return true; +} + +bool FruityPerfInput::on_button_release_event(GdkEventButton* a_ev, perfroll& ths) +{ + m_current_x = (int) a_ev->x; + m_current_y = (int) a_ev->y; + + if ( a_ev->button == 1 || a_ev->button == 3 ) + { + m_adding_pressed = false; + } + + ths.m_moving = false; + ths.m_growing = false; + m_adding_pressed = false; + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y ); + } + + updateMousePtr( ths ); + return true; +} + +bool FruityPerfInput::on_motion_notify_event(GdkEventMotion* a_ev, perfroll& ths) +{ + long tick; + int x = (int) a_ev->x; + m_current_x = (int) a_ev->x; + m_current_y = (int) a_ev->y; + + if ( m_adding_pressed ){ + + ths.convert_x( x, &tick ); + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + long seq_length = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_length( ); + tick = tick - (tick % seq_length); + + /*long min_tick = (tick < m_drop_tick) ? tick : m_drop_tick;*/ + long length = seq_length; + + ths.m_mainperf->get_sequence( ths.m_drop_sequence ) + ->grow_trigger( ths.m_drop_tick, tick, length); + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + } + else if ( ths.m_moving || ths.m_growing ) + { + if ( ths.m_mainperf->is_active( ths.m_drop_sequence)) + { + ths.convert_x( x, &tick ); + tick -= ths.m_drop_tick_trigger_offset; + + tick = tick - tick % ths.m_snap; + + if ( ths.m_moving ) + { + ths.m_mainperf->get_sequence( ths.m_drop_sequence ) + ->move_selected_triggers_to( tick, true ); + } + if ( ths.m_growing ) + { + if ( ths.m_grow_direction ) + ths.m_mainperf->get_sequence( ths.m_drop_sequence ) + ->move_selected_triggers_to( tick, false, 0 ); + else + ths.m_mainperf->get_sequence( ths.m_drop_sequence ) + ->move_selected_triggers_to( tick-1, false, 1 ); + } + + + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + } + + updateMousePtr( ths ); + return true; +} + + +/* popup menu calls this */ +void +Seq24PerfInput::set_adding( bool a_adding, perfroll& ths ) +{ + if ( a_adding ) + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL )); + m_adding = true; + } + else + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); + m_adding = false; + } +} + +bool +Seq24PerfInput::on_button_press_event(GdkEventButton* a_ev, perfroll& ths) +{ + ths.grab_focus( ); + + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )) + { + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->unselect_triggers( ); + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + + ths.m_drop_x = (int) a_ev->x; + ths.m_drop_y = (int) a_ev->y; + + ths.convert_xy( ths.m_drop_x, ths.m_drop_y, &ths.m_drop_tick, &ths.m_drop_sequence ); + + /* left mouse button */ + if ( a_ev->button == 1 ){ + + long tick = ths.m_drop_tick; + + /* add a new note if we didnt select anything */ + if ( m_adding ){ + + m_adding_pressed = true; + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + long seq_length = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_length( ); + + bool state = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_trigger_state( tick ); + + if ( state ) + { + ths.m_mainperf->push_trigger_undo(); + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->del_trigger( tick ); + } + else + { + + // snap to length of sequence + tick = tick - (tick % seq_length); + //m_adding_pressed_state = true; + + ths.m_mainperf->push_trigger_undo(); + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->add_trigger( tick, seq_length ); + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + + //m_drop_tick_last = (m_drop_tick + seq_length - 1); + } + } + } + else { + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + ths.m_mainperf->push_trigger_undo(); + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->select_trigger( tick ); + + long start_tick = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_selected_trigger_start_tick(); + long end_tick = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_selected_trigger_end_tick(); + + if ( tick >= start_tick && + tick <= start_tick + (c_perfroll_size_box_click_w * c_perf_scale_x) && + (ths.m_drop_y % c_names_y) <= c_perfroll_size_box_click_w + 1 ) + { + ths.m_growing = true; + ths.m_grow_direction = true; + ths.m_drop_tick_trigger_offset = ths.m_drop_tick - + ths.m_mainperf->get_sequence( ths.m_drop_sequence )-> + get_selected_trigger_start_tick( ); + } + else + if ( tick >= end_tick - (c_perfroll_size_box_click_w * c_perf_scale_x) && + tick <= end_tick && + (ths.m_drop_y % c_names_y) >= c_names_y - c_perfroll_size_box_click_w - 1 ) + { + ths.m_growing = true; + ths.m_grow_direction = false; + ths.m_drop_tick_trigger_offset = + ths.m_drop_tick - + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_selected_trigger_end_tick( ); + } + else + { + ths.m_moving = true; + ths.m_drop_tick_trigger_offset = ths.m_drop_tick - + ths.m_mainperf->get_sequence( ths.m_drop_sequence )-> + get_selected_trigger_start_tick( ); + + } + + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + } + } + + /* right mouse button */ + if ( a_ev->button == 3 ){ + set_adding( true, ths ); + } + + /* middle, split */ + if ( a_ev->button == 2 ) + { + long tick = ths.m_drop_tick; + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + bool state = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_trigger_state( tick ); + + if ( state ) + { + ths.m_mainperf->push_trigger_undo(); + + ths.m_mainperf->get_sequence( ths.m_drop_sequence )->split_trigger( tick ); + + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + } + } + return true; +} + +bool Seq24PerfInput::on_button_release_event(GdkEventButton* a_ev, perfroll& ths) +{ + if ( a_ev->button == 1 ){ + + if ( m_adding ){ + m_adding_pressed = false; + } + } + + if ( a_ev->button == 3 ){ + m_adding_pressed = false; + set_adding( false, ths ); + } + + ths.m_moving = false; + ths.m_growing = false; + m_adding_pressed = false; + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y ); + } + + return true; +} + +bool Seq24PerfInput::on_motion_notify_event(GdkEventMotion* a_ev, perfroll& ths) +{ + long tick; + int x = (int) a_ev->x; + + if ( m_adding && m_adding_pressed ){ + + ths.convert_x( x, &tick ); + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence )){ + + long seq_length = ths.m_mainperf->get_sequence( ths.m_drop_sequence )->get_length( ); + tick = tick - (tick % seq_length); + + /*long min_tick = (tick < m_drop_tick) ? tick : m_drop_tick;*/ + long length = seq_length; + + ths.m_mainperf->get_sequence( ths.m_drop_sequence ) + ->grow_trigger( ths.m_drop_tick, tick, length); + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + } + else if ( ths.m_moving || ths.m_growing ){ + + if ( ths.m_mainperf->is_active( ths.m_drop_sequence)){ + + ths.convert_x( x, &tick ); + tick -= ths.m_drop_tick_trigger_offset; + + tick = tick - tick % ths.m_snap; + + if ( ths.m_moving ) + { + ths.m_mainperf->get_sequence( ths.m_drop_sequence ) + ->move_selected_triggers_to( tick, true ); + } + if ( ths.m_growing ) + { + if ( ths.m_grow_direction ) + ths.m_mainperf->get_sequence( ths.m_drop_sequence ) + ->move_selected_triggers_to( tick, false, 0 ); + else + ths.m_mainperf->get_sequence( ths.m_drop_sequence ) + ->move_selected_triggers_to( tick-1, false, 1 ); + } + + + ths.draw_background_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_sequence_on( ths.m_pixmap, ths.m_drop_sequence ); + ths.draw_drawable_row( ths.m_window, ths.m_pixmap, ths.m_drop_y); + } + } + + return true; +} diff -rupN seq24-rev48 adding win32/src/perfroll.h seq24-rev48 win32 adding MouseInteraction/src/perfroll.h --- seq24-rev48 adding win32/src/perfroll.h 2009-05-20 20:30:47.046875000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/perfroll.h 2009-05-20 20:30:51.312500000 -0500 @@ -45,12 +45,41 @@ using namespace Gtk; +class perfroll; +struct FruityPerfInput +{ + FruityPerfInput() : m_adding_pressed( false ), m_current_x( 0 ), + m_current_y( 0 ) + {} + bool on_button_press_event(GdkEventButton* a_ev, perfroll& ths); + bool on_button_release_event(GdkEventButton* a_ev, perfroll& ths); + bool on_motion_notify_event(GdkEventMotion* a_ev, perfroll& ths); + void updateMousePtr(perfroll& ths); + bool m_adding_pressed; + long m_current_x, m_current_y; +}; +struct Seq24PerfInput +{ + Seq24PerfInput() : m_adding( false ), m_adding_pressed( false ) {} + bool on_button_press_event(GdkEventButton* a_ev, perfroll& ths); + bool on_button_release_event(GdkEventButton* a_ev, perfroll& ths); + bool on_motion_notify_event(GdkEventMotion* a_ev, perfroll& ths); + void set_adding( bool a_adding, perfroll& ths ); + bool m_adding; + bool m_adding_pressed; +}; /* performance roll */ class perfroll : public Gtk::DrawingArea { private: + friend struct FruityPerfInput; + FruityPerfInput m_fruity_interaction; + + friend struct Seq24PerfInput; + Seq24PerfInput m_seq24_interaction; + Glib::RefPtr m_gc; Glib::RefPtr m_window; @@ -86,9 +115,6 @@ class perfroll : public Gtk::DrawingArea Adjustment *m_vadjust; Adjustment *m_hadjust; - bool m_adding; - bool m_adding_pressed; - bool m_adding_pressed_state; bool m_moving; bool m_growing; bool m_grow_direction; @@ -113,6 +139,10 @@ class perfroll : public Gtk::DrawingArea void snap_x( int *a_x ); + void start_playing( void ); + void stop_playing( void ); + + void draw_sequence_on( Glib::RefPtr a_draw, int a_sequence ); void draw_background_on( Glib::RefPtr a_draw, int a_sequence ); @@ -136,8 +166,6 @@ class perfroll : public Gtk::DrawingArea void draw_progress(); - void set_adding( bool a_adding ); - void redraw_dirty_sequences( void ); perfroll( perform *a_perf, diff -rupN seq24-rev48 adding win32/src/seq24.cpp seq24-rev48 win32 adding MouseInteraction/src/seq24.cpp --- seq24-rev48 adding win32/src/seq24.cpp 2009-05-20 20:30:47.125000000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/seq24.cpp 2009-05-20 20:30:51.390625000 -0500 @@ -48,6 +48,7 @@ option long_options[] = { {"stats", 0, 0, 'S' }, {"priority", 0, 0, 'p' }, {"ignore",required_argument, 0, 'i'}, + {"interaction_method",required_argument, 0, 'x'}, {"jack_transport",0, 0, 'j'}, {"jack_master",0, 0, 'J'}, {"jack_master_cond",0,0,'C'}, @@ -71,6 +72,7 @@ Glib::ustring last_used_dir ="/"; std::string config_filename = ".seq24rc"; std::string user_filename = ".seq24usr"; bool global_print_keys = false; +interaction_method_e global_interactionmethod = e_seq24_interaction; bool global_with_jack_transport = false; bool global_with_jack_master = false; @@ -183,6 +185,7 @@ main (int argc, char *argv[]) printf( " --priority : runs higher priority with FIFO scheduler (must be root)\n" ); printf( " --pass_sysex : passes any incoming sysex messages to all outputs \n" ); printf( " --show_keys : prints pressed key value\n" ); + printf( " --interaction_method : see .seq24rc for methods to use\n" ); printf( " --jack_transport : seq24 will sync to jack transport\n" ); printf( " --jack_master : seq24 will try to be jack master\n" ); printf( " --jack_master_cond : jack master will fail if there is already a master\n" ); @@ -249,6 +252,10 @@ main (int argc, char *argv[]) global_device_ignore_num = atoi( optarg ); break; + case 'x': + global_interactionmethod = (interaction_method_e)atoi( optarg ); + break; + default: break; diff -rupN seq24-rev48 adding win32/src/seqevent.cpp seq24-rev48 win32 adding MouseInteraction/src/seqevent.cpp --- seq24-rev48 adding win32/src/seqevent.cpp 2009-05-20 20:30:47.375000000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/seqevent.cpp 2009-05-20 20:30:51.640625000 -0500 @@ -57,7 +57,6 @@ seqevent::seqevent(sequence *a_seq, m_moving = false; m_moving_init = false; m_growing = false; - m_adding = false; m_paste = false; m_painting = false; @@ -559,203 +558,409 @@ seqevent::convert_t( long a_ticks, int * } -/* popup menu calls this */ + + + +bool +seqevent::on_button_press_event(GdkEventButton* a_ev) +{ + switch (global_interactionmethod) + { + case e_fruity_interaction: + return m_fruity_interaction.on_button_press_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_button_press_event(a_ev, *this); + } + return false; +} + void -seqevent::set_adding( bool a_adding ) +seqevent::drop_event( long a_tick ) { - if ( a_adding ){ - - get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL )); - m_adding = true; + + unsigned char status = m_status; + unsigned char d0 = m_cc; + unsigned char d1 = 0x40; + + if ( m_status == EVENT_AFTERTOUCH ) + d0 = 0; + + if ( m_status == EVENT_PROGRAM_CHANGE ) + d0 = 0; /* d0 == new patch */ + + if ( m_status == EVENT_CHANNEL_PRESSURE ) + d0 = 0x40; /* d0 == pressure */ + + if ( m_status == EVENT_PITCH_WHEEL ) + d0 = 0; + + m_seq->add_event( a_tick, + status, + d0, + d1, true ); +} + + +bool +seqevent::on_button_release_event(GdkEventButton* a_ev) +{ + switch (global_interactionmethod) + { + case e_fruity_interaction: + return m_fruity_interaction.on_button_release_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_button_release_event(a_ev, *this); } - else { + return false; +} + + - get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); - m_adding = false; +bool +seqevent::on_motion_notify_event(GdkEventMotion* a_ev) +{ + switch (global_interactionmethod) + { + case e_fruity_interaction: + return m_fruity_interaction.on_motion_notify_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_motion_notify_event(a_ev, *this); } + return false; +} + + + +/* performs a 'snap' on y */ +void +seqevent::snap_y( int *a_y ) +{ + *a_y = *a_y - (*a_y % c_key_y); +} + +/* performs a 'snap' on x */ +void +seqevent::snap_x( int *a_x ) +{ + //snap = number pulses to snap to + //m_zoom = number of pulses per pixel + //so snap / m_zoom = number pixels to snap to + int mod = (m_snap / m_zoom); + if ( mod <= 0 ) + mod = 1; + + *a_x = *a_x - (*a_x % mod ); + } bool -seqevent::on_button_press_event(GdkEventButton* a_ev) +seqevent::on_focus_in_event(GdkEventFocus*) { - int x,w,numsel; + set_flags(Gtk::HAS_FOCUS); + return false; +} + +bool +seqevent::on_focus_out_event(GdkEventFocus*) +{ + unset_flags(Gtk::HAS_FOCUS); + return false; +} + +bool +seqevent::on_key_press_event(GdkEventKey* a_p0) +{ + bool ret = false; + + if ( a_p0->type == GDK_KEY_PRESS ){ + + if ( a_p0->keyval == GDK_Delete || a_p0->keyval == GDK_BackSpace ){ + + m_seq->push_undo(); + m_seq->mark_selected(); + m_seq->remove_marked(); + ret = true; + } + + if ( a_p0->state & GDK_CONTROL_MASK ){ + + /* cut */ + if ( a_p0->keyval == GDK_x || a_p0->keyval == GDK_X ){ + + m_seq->copy_selected(); + m_seq->mark_selected(); + m_seq->remove_marked(); + + ret = true; + } + /* copy */ + if ( a_p0->keyval == GDK_c || a_p0->keyval == GDK_C ){ + + m_seq->copy_selected(); + ret = true; + } + /* paste */ + if ( a_p0->keyval == GDK_v || a_p0->keyval == GDK_V ){ + + start_paste(); + ret = true; + } + /* Undo */ + if ( a_p0->keyval == GDK_z || a_p0->keyval == GDK_Z ){ + + m_seq->pop_undo(); + ret = true; + } + } + } + + if ( ret == true ){ + + redraw(); + m_seq->set_dirty(); + return true; + } + else + + return false; +} + + + + + +////////////////////////// +// interaction methods +////////////////////////// + + +void FruitySeqEventInput::updateMousePtr(seqevent& ths) +{ + // context sensitive mouse + long tick_s, tick_w, tick_f, pos; + ths.convert_x( ths.m_current_x, &tick_s ); + ths.convert_x( c_eventevent_x, &tick_w ); + tick_f = tick_s + tick_w; + if ( tick_s < 0 ) + tick_s = 0; // clamp to 0 + + + if (m_is_drag_pasting || ths.m_selecting || ths.m_moving || ths.m_paste) + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); + } + else if (ths.m_seq->intersectEvents( tick_s, tick_f, ths.m_status, pos )) + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::CENTER_PTR )); + } + else + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL )); + } +} + + +bool FruitySeqEventInput::on_button_press_event(GdkEventButton* a_ev, seqevent& ths) +{ + int x,w,numsel; long tick_s; long tick_f; long tick_w; - convert_x( c_eventevent_x, &tick_w ); + ths.convert_x( c_eventevent_x, &tick_w ); /* if it was a button press */ /* set values for dragging */ - m_drop_x = m_current_x = (int) a_ev->x + m_scroll_offset_x; + ths.m_drop_x = ths.m_current_x = (int) a_ev->x + ths.m_scroll_offset_x; /* reset box that holds dirty redraw spot */ - m_old.x = 0; - m_old.y = 0; - m_old.width = 0; - m_old.height = 0; - - if ( m_paste ){ - - snap_x( &m_current_x ); - convert_x( m_current_x, &tick_s ); - m_paste = false; - m_seq->push_undo(); - m_seq->paste_selected( tick_s, 0 ); + ths.m_old.x = 0; + ths.m_old.y = 0; + ths.m_old.width = 0; + ths.m_old.height = 0; + + if ( ths.m_paste ){ + + ths.snap_x( &ths.m_current_x ); + ths.convert_x( ths.m_current_x, &tick_s ); + ths.m_paste = false; + ths.m_seq->push_undo(); + ths.m_seq->paste_selected( tick_s, 0 ); } else { /* left mouse button */ - if ( a_ev->button == 1 ){ - + if ( a_ev->button == 1 ) + { /* turn x,y in to tick/note */ - convert_x( m_drop_x, &tick_s ); + ths.convert_x( ths.m_drop_x, &tick_s ); /* shift back a few ticks */ - tick_f = tick_s + (m_zoom); + tick_f = tick_s + (ths.m_zoom); tick_s -= (tick_w); - if ( tick_s < 0 ) + if ( tick_s < 0 ) tick_s = 0; - if ( m_adding ) + if ( ! ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_would_select ) && + !(a_ev->state & GDK_CONTROL_MASK) ) { - m_painting = true; + ths.m_painting = true; - snap_x( &m_drop_x ); + ths.snap_x( &ths.m_drop_x ); /* turn x,y in to tick/note */ - convert_x( m_drop_x, &tick_s ); - /* add note, length = little less than snap */ + ths.convert_x( ths.m_drop_x, &tick_s ); - if ( ! m_seq->select_events( tick_s, tick_f, - m_status, m_cc, sequence::e_would_select )) + /* add note, length = little less than snap */ + if ( ! ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_would_select )) { - m_seq->push_undo(); - drop_event( tick_s ); + ths.m_seq->push_undo(); + ths.drop_event( tick_s ); } } else /* selecting */ { - if ( ! m_seq->select_events( tick_s, tick_f, - m_status, m_cc, sequence::e_is_selected )) + if ( ! ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_is_selected )) { - if ( ! (a_ev->state & GDK_CONTROL_MASK) ) + // if clicking event... + if (ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_would_select ) ) { - m_seq->unselect(); - } - - numsel = m_seq->select_events( tick_s, tick_f, - m_status, - m_cc, sequence::e_select_one ); - - /* if we didnt select anyhing (user clicked empty space) - unselect all notes, and start selecting */ - - /* none selected, start selection box */ - if ( numsel == 0 ) - { - m_selecting = true; + if ( ! (a_ev->state & GDK_CONTROL_MASK) ) + ths.m_seq->unselect(); } + // if clicking empty space ... else { - /// needs update + // ... unselect all if ctrl-shift not held + if (! ((a_ev->state & GDK_CONTROL_MASK) && + (a_ev->state & GDK_SHIFT_MASK)) ) + ths.m_seq->unselect(); } + + /* on direct click select only one event */ + numsel = ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, + ths.m_cc, sequence::e_select_one ); + + // prevent deselect in button_release() + if (numsel) + m_justselected_one = true; + + // if nothing selected, start the selection box + if (numsel == 0 && (a_ev->state & GDK_CONTROL_MASK)) + ths.m_selecting = true; } - if ( m_seq->select_events( tick_s, tick_f, - m_status, m_cc, sequence::e_is_selected )) + // if event under cursor is selected + if ( ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_is_selected )) { - m_moving_init = true; - int note; + // grab/move the note + if ( !(a_ev->state & GDK_CONTROL_MASK) ) + { + ths.m_moving_init = true; + int note; - /* get the box that selected elements are in */ - m_seq->get_selected_box( &tick_s, ¬e, - &tick_f, ¬e ); + /* get the box that selected elements are in */ + ths.m_seq->get_selected_box( &tick_s, ¬e, + &tick_f, ¬e ); - tick_f += tick_w; + tick_f += tick_w; - /* convert box to X,Y values */ - convert_t( tick_s, &x ); - convert_t( tick_f, &w ); + /* convert box to X,Y values */ + ths.convert_t( tick_s, &x ); + ths.convert_t( tick_f, &w ); - /* w is actually corrids now, so we have to change */ - w = w-x; + /* w is actually corrids now, so we have to change */ + w = w-x; - /* set the m_selected rectangle to hold the - x,y,w,h of our selected events */ + /* set the m_selected rectangle to hold the + x,y,w,h of our selected events */ - m_selected.x = x; - m_selected.width=w; + ths.m_selected.x = x; + ths.m_selected.width=w; - m_selected.y = (c_eventarea_y - c_eventevent_y)/2; - m_selected.height = c_eventevent_y; + ths.m_selected.y = (c_eventarea_y - c_eventevent_y)/2; + ths.m_selected.height = c_eventevent_y; - /* save offset that we get from the snap above */ - int adjusted_selected_x = m_selected.x; - snap_x( &adjusted_selected_x ); - m_move_snap_offset_x = ( m_selected.x - adjusted_selected_x); + /* save offset that we get from the snap above */ + int adjusted_selected_x = ths.m_selected.x; + ths.snap_x( &adjusted_selected_x ); + ths.m_move_snap_offset_x = ( ths.m_selected.x - adjusted_selected_x); - /* align selection for drawing */ - snap_x( &m_selected.x ); - snap_x( &m_current_x ); - snap_x( &m_drop_x ); + /* align selection for drawing */ + ths.snap_x( &ths.m_selected.x ); + ths.snap_x( &ths.m_current_x ); + ths.snap_x( &ths.m_drop_x ); + } + // ctrl left click when stuff is already selected + else if ((a_ev->state & GDK_CONTROL_MASK) && + ths.m_seq->select_events( tick_s, tick_f, + ths. m_status, ths.m_cc, sequence::e_is_selected )) + { + m_is_drag_pasting_start = true; + } - } + } } } /* end if button == 1 */ - if ( a_ev->button == 3 ){ - - set_adding( true ); - } - } - - /* if they clicked, something changed */ - update_pixmap(); - draw_pixmap_on_window(); - - return true; - - -} - + if ( a_ev->button == 3 ) + { + /* turn x,y in to tick/note */ + ths.convert_x( ths.m_drop_x, &tick_s ); -void -seqevent::drop_event( long a_tick ) -{ + /* shift back a few ticks */ + tick_f = tick_s + (ths.m_zoom); + tick_s -= (tick_w); - unsigned char status = m_status; - unsigned char d0 = m_cc; - unsigned char d1 = 0x40; + if ( tick_s < 0 ) + tick_s = 0; - if ( m_status == EVENT_AFTERTOUCH ) - d0 = 0; + //erase event under cursor if there is one + if (ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_would_select )) + { + /* remove only the note under the cursor, + leave the selection intact */ + ths.m_seq->push_undo(); + ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_remove_one ); + ths.redraw(); + ths.m_seq->set_dirty(); + } + else /* selecting */ + { + if ( ! (a_ev->state & GDK_CONTROL_MASK) ) + ths.m_seq->unselect(); - if ( m_status == EVENT_PROGRAM_CHANGE ) - d0 = 0; /* d0 == new patch */ + // nothing selected, start the selection box + ths.m_selecting = true; + } + } + } - if ( m_status == EVENT_CHANNEL_PRESSURE ) - d0 = 0x40; /* d0 == pressure */ + /* if they clicked, something changed */ + ths.update_pixmap(); + ths.draw_pixmap_on_window(); - if ( m_status == EVENT_PITCH_WHEEL ) - d0 = 0; + updateMousePtr( ths ); - m_seq->add_event( a_tick, - status, - d0, - d1, true ); + return true; } - -bool -seqevent::on_button_release_event(GdkEventButton* a_ev) +bool FruitySeqEventInput::on_button_release_event(GdkEventButton* a_ev, seqevent& ths) { long tick_s; long tick_f; @@ -763,197 +968,420 @@ seqevent::on_button_release_event(GdkEve int x,w; int numsel; - grab_focus( ); + ths.grab_focus( ); - m_current_x = (int) a_ev->x + m_scroll_offset_x;; + ths.m_current_x = (int) a_ev->x + ths.m_scroll_offset_x;; - if ( m_moving ) - snap_x( &m_current_x ); + if ( ths.m_moving || m_is_drag_pasting ) + ths.snap_x( &ths.m_current_x ); - int delta_x = m_current_x - m_drop_x; + int delta_x = ths.m_current_x - ths.m_drop_x; long delta_tick; if ( a_ev->button == 1 ){ - if ( m_selecting ){ - - x_to_w( m_drop_x, m_current_x, &x, &w ); + int current_x = ths.m_current_x; + long t_s, t_f; + ths.snap_x( ¤t_x ); + ths.convert_x( current_x, &t_s ); + + /* shift back a few ticks */ + t_f = t_s + (ths.m_zoom); + if ( t_s < 0 ) + t_s = 0; + + // ctrl-left click button up for select/drag copy/paste + // left click button up for ending a move of selected notes + if ( m_is_drag_pasting ) + { + m_is_drag_pasting = false; + m_is_drag_pasting_start = false; - convert_x( x, &tick_s ); - convert_x( x+w, &tick_f ); + /* convert deltas into screen corridinates */ + ths.m_paste = false; + ths.m_seq->push_undo(); + ths.m_seq->paste_selected( t_s, 0 ); - numsel = m_seq->select_events( tick_s, tick_f, - m_status, - m_cc, sequence::e_select ); + //m_seq->unselect(); } + // ctrl-left click but without movement - select a note + if (m_is_drag_pasting_start) + { + m_is_drag_pasting_start = false; + + // if ctrl-left click without movement and + // if note under cursor is selected, and ctrl is held + // and buttondown didn't just select one + if (!m_justselected_one && + ths.m_seq->select_events( t_s, t_f, + ths.m_status, ths.m_cc, + sequence::e_is_selected ) && + (a_ev->state & GDK_CONTROL_MASK)) + { + // deselect the event + numsel = ths.m_seq->select_events( t_s, t_f, + ths.m_status, ths.m_cc, + sequence::e_deselect ); + } + } + m_justselected_one = false; // clear flag on left button up - if ( m_moving ){ + if ( ths.m_moving ){ /* adjust for snap */ - delta_x -= m_move_snap_offset_x; + delta_x -= ths.m_move_snap_offset_x; /* convert deltas into screen corridinates */ - convert_x( delta_x, &delta_tick ); + ths.convert_x( delta_x, &delta_tick ); /* not really notes, but still moves events */ - m_seq->push_undo(); - m_seq->move_selected_notes( delta_tick, 0 ); + ths.m_seq->push_undo(); + ths.m_seq->move_selected_notes( delta_tick, 0 ); } - - set_adding( m_adding ); } - if ( a_ev->button == 3 ){ + if ( a_ev->button == 3 || a_ev->button == 1 ){ + + if ( ths.m_selecting ){ + + ths.x_to_w( ths.m_drop_x, ths.m_current_x, &x, &w ); - set_adding( false ); + ths.convert_x( x, &tick_s ); + ths.convert_x( x+w, &tick_f ); + numsel = ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, + ths.m_cc, sequence::e_toggle_selection ); + } } /* turn off */ - m_selecting = false; - m_moving = false; - m_growing = false; - m_moving_init = false; - m_painting = false; + ths.m_selecting = false; + ths.m_moving = false; + ths.m_growing = false; + ths.m_moving_init = false; + ths.m_painting = false; - m_seq->unpaint_all(); + ths.m_seq->unpaint_all(); /* if they clicked, something changed */ - update_pixmap(); - draw_pixmap_on_window(); + ths.update_pixmap(); + ths.draw_pixmap_on_window(); + + updateMousePtr(ths); return true; } - - -bool -seqevent::on_motion_notify_event(GdkEventMotion* a_ev) +bool FruitySeqEventInput::on_motion_notify_event(GdkEventMotion* a_ev, seqevent& ths) { - long tick = 0; - - if ( m_moving_init ){ - m_moving_init = false; - m_moving = true; + ths.m_current_x = (int) a_ev->x + ths.m_scroll_offset_x; + + + if ( ths.m_moving_init ) + { + ths.m_moving_init = false; + ths.m_moving = true; } - if ( m_selecting || m_moving || m_paste ){ + // context sensitive mouse pointer... + updateMousePtr(ths); + + // ctrl-left click drag on selected note(s) starts a copy/unselect/paste + if ( m_is_drag_pasting_start ) + { + ths.m_seq->copy_selected(); + ths.m_seq->unselect(); + ths.start_paste(); + + m_is_drag_pasting_start = false; + m_is_drag_pasting = true; + } - m_current_x = (int) a_ev->x + m_scroll_offset_x;; + if ( ths.m_selecting || ths.m_moving || ths.m_paste ){ - if ( m_moving || m_paste ) - snap_x( &m_current_x ); + if ( ths.m_moving || ths.m_paste ) + ths.snap_x( &ths.m_current_x ); - draw_selection_on_window(); + ths.draw_selection_on_window(); } - if ( m_painting ) + if ( ths.m_painting ) { - m_current_x = (int) a_ev->x + m_scroll_offset_x;; - snap_x( &m_current_x ); - convert_x( m_current_x, &tick ); - drop_event( tick ); + ths.m_current_x = (int) a_ev->x + ths.m_scroll_offset_x;; + ths.snap_x( &ths.m_current_x ); + ths.convert_x( ths.m_current_x, &tick ); + ths.drop_event( tick ); } - + return true; } - -/* performs a 'snap' on y */ -void -seqevent::snap_y( int *a_y ) +void +Seq24SeqEventInput::set_adding( bool a_adding, seqevent& ths ) { - *a_y = *a_y - (*a_y % c_key_y); + if ( a_adding ) + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL ) ); + m_adding = true; + } + else + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR ) ); + m_adding = false; + } } -/* performs a 'snap' on x */ -void -seqevent::snap_x( int *a_x ) + +bool Seq24SeqEventInput::on_button_press_event(GdkEventButton* a_ev, seqevent& ths) { - //snap = number pulses to snap to - //m_zoom = number of pulses per pixel - //so snap / m_zoom = number pixels to snap to - int mod = (m_snap / m_zoom); - if ( mod <= 0 ) - mod = 1; - - *a_x = *a_x - (*a_x % mod ); - -} + int x,w,numsel; + long tick_s; + long tick_f; + long tick_w; -bool -seqevent::on_focus_in_event(GdkEventFocus*) -{ - set_flags(Gtk::HAS_FOCUS); - return false; -} + ths.convert_x( c_eventevent_x, &tick_w ); -bool -seqevent::on_focus_out_event(GdkEventFocus*) -{ - unset_flags(Gtk::HAS_FOCUS); - return false; + /* if it was a button press */ + + /* set values for dragging */ + ths.m_drop_x = ths.m_current_x = (int) a_ev->x + ths.m_scroll_offset_x; + + /* reset box that holds dirty redraw spot */ + ths.m_old.x = 0; + ths.m_old.y = 0; + ths.m_old.width = 0; + ths.m_old.height = 0; + + if ( ths.m_paste ){ + + ths.snap_x( &ths.m_current_x ); + ths.convert_x( ths.m_current_x, &tick_s ); + ths.m_paste = false; + ths.m_seq->push_undo(); + ths.m_seq->paste_selected( tick_s, 0 ); + + } else { + + /* left mouse button */ + if ( a_ev->button == 1 ){ + + /* turn x,y in to tick/note */ + ths.convert_x( ths.m_drop_x, &tick_s ); + + /* shift back a few ticks */ + tick_f = tick_s + (ths.m_zoom); + tick_s -= (tick_w); + + if ( tick_s < 0 ) + tick_s = 0; + + if ( m_adding ) + { + ths.m_painting = true; + + ths.snap_x( &ths.m_drop_x ); + /* turn x,y in to tick/note */ + ths.convert_x( ths.m_drop_x, &tick_s ); + /* add note, length = little less than snap */ + + if ( ! ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_would_select )) + { + ths.m_seq->push_undo(); + ths.drop_event( tick_s ); + } + + } + else /* selecting */ + { + if ( ! ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_is_selected )) + { + if ( ! (a_ev->state & GDK_CONTROL_MASK) ) + { + ths.m_seq->unselect(); + } + + numsel = ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, + ths.m_cc, sequence::e_select_one ); + + /* if we didnt select anyhing (user clicked empty space) + unselect all notes, and start selecting */ + + /* none selected, start selection box */ + if ( numsel == 0 ) + { + ths.m_selecting = true; + } + else + { + /// needs update + } + } + + if ( ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, ths.m_cc, sequence::e_is_selected )) + { + + ths.m_moving_init = true; + int note; + + /* get the box that selected elements are in */ + ths.m_seq->get_selected_box( &tick_s, ¬e, + &tick_f, ¬e ); + + tick_f += tick_w; + + /* convert box to X,Y values */ + ths.convert_t( tick_s, &x ); + ths.convert_t( tick_f, &w ); + + /* w is actually corrids now, so we have to change */ + w = w-x; + + /* set the m_selected rectangle to hold the + x,y,w,h of our selected events */ + + ths.m_selected.x = x; + ths.m_selected.width=w; + + ths.m_selected.y = (c_eventarea_y - c_eventevent_y)/2; + ths.m_selected.height = c_eventevent_y; + + + /* save offset that we get from the snap above */ + int adjusted_selected_x = ths.m_selected.x; + ths.snap_x( &adjusted_selected_x ); + ths.m_move_snap_offset_x = ( ths.m_selected.x - adjusted_selected_x); + + /* align selection for drawing */ + ths.snap_x( &ths.m_selected.x ); + ths.snap_x( &ths.m_current_x ); + ths.snap_x( &ths.m_drop_x ); + + } + } + + } /* end if button == 1 */ + + if ( a_ev->button == 3 ){ + + set_adding( true, ths ); + } + } + + /* if they clicked, something changed */ + ths.update_pixmap(); + ths.draw_pixmap_on_window(); + + return true; } -bool -seqevent::on_key_press_event(GdkEventKey* a_p0) +bool Seq24SeqEventInput::on_button_release_event(GdkEventButton* a_ev, seqevent& ths) { - bool ret = false; + long tick_s; + long tick_f; - if ( a_p0->type == GDK_KEY_PRESS ){ + int x,w; + int numsel; - if ( a_p0->keyval == GDK_Delete || a_p0->keyval == GDK_BackSpace ){ + ths.grab_focus( ); - m_seq->push_undo(); - m_seq->mark_selected(); - m_seq->remove_marked(); - ret = true; + ths.m_current_x = (int) a_ev->x + ths.m_scroll_offset_x;; + + if ( ths.m_moving ) + ths.snap_x( &ths.m_current_x ); + + int delta_x = ths.m_current_x - ths.m_drop_x; + + long delta_tick; + + if ( a_ev->button == 1 ){ + + if ( ths.m_selecting ){ + + ths.x_to_w( ths.m_drop_x, ths.m_current_x, &x, &w ); + + ths.convert_x( x, &tick_s ); + ths.convert_x( x+w, &tick_f ); + + numsel = ths.m_seq->select_events( tick_s, tick_f, + ths.m_status, + ths.m_cc, sequence::e_select ); } - if ( a_p0->state & GDK_CONTROL_MASK ){ + if ( ths.m_moving ){ - /* cut */ - if ( a_p0->keyval == GDK_x || a_p0->keyval == GDK_X ){ + /* adjust for snap */ + delta_x -= ths.m_move_snap_offset_x; - m_seq->copy_selected(); - m_seq->mark_selected(); - m_seq->remove_marked(); + /* convert deltas into screen corridinates */ + ths.convert_x( delta_x, &delta_tick ); - ret = true; - } - /* copy */ - if ( a_p0->keyval == GDK_c || a_p0->keyval == GDK_C ){ + /* not really notes, but still moves events */ + ths.m_seq->push_undo(); + ths.m_seq->move_selected_notes( delta_tick, 0 ); + } - m_seq->copy_selected(); - ret = true; - } - /* paste */ - if ( a_p0->keyval == GDK_v || a_p0->keyval == GDK_V ){ + set_adding( m_adding, ths ); + } - start_paste(); - ret = true; - } - /* Undo */ - if ( a_p0->keyval == GDK_z || a_p0->keyval == GDK_Z ){ + if ( a_ev->button == 3 ){ + + set_adding( false, ths ); - m_seq->pop_undo(); - ret = true; - } - } } - if ( ret == true ){ + /* turn off */ + ths.m_selecting = false; + ths.m_moving = false; + ths.m_growing = false; + ths.m_moving_init = false; + ths.m_painting = false; - redraw(); - m_seq->set_dirty(); - return true; + ths.m_seq->unpaint_all(); + + /* if they clicked, something changed */ + ths.update_pixmap(); + ths.draw_pixmap_on_window(); + + return true; +} + +bool Seq24SeqEventInput::on_motion_notify_event(GdkEventMotion* a_ev, seqevent& ths) +{ + long tick = 0; + + if ( ths.m_moving_init ){ + ths.m_moving_init = false; + ths.m_moving = true; } - else - return false; + if ( ths.m_selecting || ths.m_moving || ths.m_paste ){ + + ths.m_current_x = (int) a_ev->x + ths.m_scroll_offset_x;; + + if ( ths.m_moving || ths.m_paste ) + ths.snap_x( &ths.m_current_x ); + + ths.draw_selection_on_window(); + } + + + if ( ths.m_painting ) + { + ths.m_current_x = (int) a_ev->x + ths.m_scroll_offset_x;; + ths.snap_x( &ths.m_current_x ); + ths.convert_x( ths.m_current_x, &tick ); + ths.drop_event( tick ); + } + + return true; } diff -rupN seq24-rev48 adding win32/src/seqevent.h seq24-rev48 win32 adding MouseInteraction/src/seqevent.h --- seq24-rev48 adding win32/src/seqevent.h 2009-05-20 20:30:47.390625000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/seqevent.h 2009-05-20 20:30:51.671875000 -0500 @@ -45,11 +45,43 @@ using namespace Gtk; +// interaction methods +class seqevent; +struct FruitySeqEventInput +{ + FruitySeqEventInput() : m_justselected_one(false), + m_is_drag_pasting_start(false), + m_is_drag_pasting(false) + {} + bool m_justselected_one; + bool m_is_drag_pasting_start; + bool m_is_drag_pasting; + bool on_button_press_event(GdkEventButton* a_ev, seqevent& ths); + bool on_button_release_event(GdkEventButton* a_ev, seqevent& ths); + bool on_motion_notify_event(GdkEventMotion* a_ev, seqevent& ths); + void updateMousePtr(seqevent& ths); +}; +struct Seq24SeqEventInput +{ + Seq24SeqEventInput() : m_adding( false ) {} + bool on_button_press_event(GdkEventButton* a_ev, seqevent& ths); + bool on_button_release_event(GdkEventButton* a_ev, seqevent& ths); + bool on_motion_notify_event(GdkEventMotion* a_ev, seqevent& ths); + void set_adding( bool a_adding, seqevent& ths ); + bool m_adding; +}; + + /* piano event */ class seqevent : public Gtk::DrawingArea { private: + friend struct FruitySeqEventInput; + FruitySeqEventInput m_fruity_interaction; + + friend struct Seq24SeqEventInput; + Seq24SeqEventInput m_seq24_interaction; Glib::RefPtr m_gc; Glib::RefPtr m_window; @@ -81,7 +113,6 @@ class seqevent : public Gtk::DrawingArea bool m_moving_init; bool m_moving; bool m_growing; - bool m_adding; bool m_painting; bool m_paste; @@ -150,7 +181,6 @@ class seqevent : public Gtk::DrawingArea int idle_redraw(); - void set_adding( bool a_adding ); diff -rupN seq24-rev48 adding win32/src/seqroll.cpp seq24-rev48 win32 adding MouseInteraction/src/seqroll.cpp --- seq24-rev48 adding win32/src/seqroll.cpp 2009-05-20 20:30:47.578125000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/seqroll.cpp 2009-05-20 20:30:51.921875000 -0500 @@ -20,6 +20,14 @@ #include "event.h" #include "seqroll.h" +const long c_handlesize = 16; + +inline static long +clamp( long val, long low, long hi ) +{ + return val < low ? low : hi < val ? hi : val; +} + seqroll::seqroll(perform *a_perf, sequence *a_seq, @@ -74,9 +82,11 @@ seqroll::seqroll(perform *a_perf, m_moving = false; m_moving_init = false; m_growing = false; - m_adding = false; m_painting = false; m_paste = false; + m_is_drag_pasting = false; + m_is_drag_pasting_start = false; + m_justselected_one = false; m_old_progress_x = 0; @@ -126,21 +136,8 @@ seqroll::~seqroll( ) delete m_clipboard; } -/* popup menu calls this */ -void -seqroll::set_adding( bool a_adding ) -{ - if ( a_adding ){ - - get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL )); - m_adding = true; - } else { - get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); - m_adding = false; - } -} void @@ -342,23 +339,44 @@ seqroll::update_background() m_window_x, m_window_y ); + gint8 dash = 1; + m_gc->set_dashes( 0, &dash, 1 ); /* draw horz grey lines */ m_gc->set_foreground(m_grey); m_gc->set_line_attributes( 1, Gdk::LINE_ON_OFF_DASH, Gdk::CAP_NOT_LAST, Gdk::JOIN_MITER ); - gint8 dash = 1; - m_gc->set_dashes( 0, &dash, 1 ); for ( int i=0; i< (m_window_y / c_key_y) + 1; i++ ) { + if (global_interactionmethod == e_fruity_interaction) + { + if (0 == (((c_num_keys - i) - m_scroll_offset_key + ( 12 - m_key )) % 12)) + { + /* draw horz black lines at C */ + m_gc->set_foreground(m_dk_grey); + m_gc->set_line_attributes( 1, + Gdk::LINE_SOLID, + Gdk::CAP_NOT_LAST, + Gdk::JOIN_MITER ); + } + else if (11 == (((c_num_keys - i) - m_scroll_offset_key + ( 12 - m_key )) % 12)) + { + /* draw horz grey lines for the other notes */ + m_gc->set_foreground(m_grey); + m_gc->set_line_attributes( 1, + Gdk::LINE_ON_OFF_DASH, + Gdk::CAP_NOT_LAST, + Gdk::JOIN_MITER ); + } + } + m_background->draw_line(m_gc, 0, i * c_key_y, m_window_x, i * c_key_y ); - if ( m_scale != c_scale_off ){ if ( !c_scales_policy[m_scale][ ((c_num_keys - i) @@ -941,336 +959,42 @@ seqroll::start_paste( ) bool seqroll::on_button_press_event(GdkEventButton* a_ev) { - int numsel; - - long tick_s; - long tick_f; - int note_h; - int note_l; - - int norm_x, norm_y, snapped_x, snapped_y; - - grab_focus( ); - - bool needs_update = false; - - snapped_x = norm_x = (int) (a_ev->x + m_scroll_offset_x ); - snapped_y = norm_y = (int) (a_ev->y + m_scroll_offset_y ); - - snap_x( &snapped_x ); - snap_y( &snapped_y ); - - /* y is always snapped */ - m_current_y = m_drop_y = snapped_y; - - /* reset box that holds dirty redraw spot */ - m_old.x = 0; - m_old.y = 0; - m_old.width = 0; - m_old.height = 0; - - if ( m_paste ){ - - convert_xy( snapped_x, snapped_y, &tick_s, ¬e_h ); - m_paste = false; - m_seq->push_undo(); - m_seq->paste_selected( tick_s, note_h ); - - needs_update = true; - - } else { - - /* left mouse button */ - if ( a_ev->button == 1 || - a_ev->button == 2 ) - { - - /* selection, normal x */ - m_current_x = m_drop_x = norm_x; - - /* turn x,y in to tick/note */ - convert_xy( m_drop_x, m_drop_y, &tick_s, ¬e_h ); - - if ( m_adding ) - { - /* start the paint job */ - m_painting = true; - - /* adding, snapped x */ - m_current_x = m_drop_x = snapped_x; - convert_xy( m_drop_x, m_drop_y, &tick_s, ¬e_h ); - - // test if a note is already there - // fake select, if so, no add - if ( ! m_seq->select_note_events( tick_s, note_h, - tick_s, note_h, - sequence::e_would_select )) - { - - /* add note, length = little less than snap */ - m_seq->push_undo(); - m_seq->add_note( tick_s, m_note_length - 2, note_h, true ); - - needs_update = true; - } - - } - else /* selecting */ - { - - - if ( !m_seq->select_note_events( tick_s, note_h, - tick_s, note_h, - sequence::e_is_selected )) - { - if ( ! (a_ev->state & GDK_CONTROL_MASK) ) - { - m_seq->unselect(); - } - - - /* on direct click select only one event */ - numsel = m_seq->select_note_events( tick_s,note_h,tick_s,note_h, - sequence::e_select_one ); - - /* none selected, start selection box */ - if ( numsel == 0 ) - { - if ( a_ev->button == 1 ) - m_selecting = true; - } - else - { - needs_update = true; - } - } - - - if ( m_seq->select_note_events( tick_s, note_h, - tick_s, note_h, - sequence::e_is_selected )) - { - if ( a_ev->button == 1 ) - { - m_moving_init = true; - needs_update = true; - - - /* get the box that selected elements are in */ - m_seq->get_selected_box( &tick_s, ¬e_h, - &tick_f, ¬e_l ); - - - convert_tn_box_to_rect( tick_s, tick_f, note_h, note_l, - &m_selected.x, - &m_selected.y, - &m_selected.width, - &m_selected.height ); - - /* save offset that we get from the snap above */ - int adjusted_selected_x = m_selected.x; - snap_x( &adjusted_selected_x ); - m_move_snap_offset_x = ( m_selected.x - adjusted_selected_x); - - /* align selection for drawing */ - snap_x( &m_selected.x ); - - m_current_x = m_drop_x = snapped_x; - } - - /* middle mouse button */ - if ( a_ev->button == 2 ){ - - /* moving, normal x */ - //m_current_x = m_drop_x = norm_x; - //convert_xy( m_drop_x, m_drop_y, &tick_s, ¬e_h ); - - m_growing = true; - - /* get the box that selected elements are in */ - m_seq->get_selected_box( &tick_s, ¬e_h, - &tick_f, ¬e_l ); - - convert_tn_box_to_rect( tick_s, tick_f, note_h, note_l, - &m_selected.x, - &m_selected.y, - &m_selected.width, - &m_selected.height ); - - } - } - } - } - - /* right mouse button */ - if ( a_ev->button == 3 ){ - set_adding( true ); - } - - } - - /* if they clicked, something changed */ - if ( needs_update ){ - - ////printf( "needs update\n" ); - m_seq->set_dirty(); - //redraw_events(); + switch (global_interactionmethod) + { + case e_fruity_interaction: + return m_fruity_interaction.on_button_press_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_button_press_event(a_ev, *this); } - return true; - + return false; } bool seqroll::on_button_release_event(GdkEventButton* a_ev) { - long tick_s; - long tick_f; - int note_h; - int note_l; - int x,y,w,h; - int numsel; - - bool needs_update = false; - - m_current_x = (int) (a_ev->x + m_scroll_offset_x ); - m_current_y = (int) (a_ev->y + m_scroll_offset_y ); - - snap_y ( &m_current_y ); - - if ( m_moving ) - snap_x( &m_current_x ); - - int delta_x = m_current_x - m_drop_x; - int delta_y = m_current_y - m_drop_y; - - long delta_tick; - int delta_note; - - if ( a_ev->button == 1 ){ - - if ( m_selecting ){ - - xy_to_rect ( m_drop_x, - m_drop_y, - m_current_x, - m_current_y, - &x, &y, - &w, &h ); - - convert_xy( x, y, &tick_s, ¬e_h ); - convert_xy( x+w, y+h, &tick_f, ¬e_l ); - - numsel = m_seq->select_note_events( tick_s, note_h, tick_f, note_l, sequence::e_select ); - - needs_update = true; - } - - if ( m_moving ){ - - /* adjust for snap */ - delta_x -= m_move_snap_offset_x; - - /* convert deltas into screen corridinates */ - convert_xy( delta_x, delta_y, &delta_tick, &delta_note ); - - /* since delta_note was from delta_y, it will be filpped - ( delta_y[0] = note[127], etc.,so we have to adjust */ - delta_note = delta_note - (c_num_keys-1); - - m_seq->push_undo(); - m_seq->move_selected_notes( delta_tick, delta_note ); - needs_update = true; - } - - } - - if ( a_ev->button == 2 ){ - - if ( m_growing ){ - - /* convert deltas into screen corridinates */ - convert_xy( delta_x, delta_y, &delta_tick, &delta_note ); - m_seq->push_undo(); - - if ( a_ev->state & GDK_SHIFT_MASK ) - { - m_seq->stretch_selected( delta_tick ); - } - else - { - m_seq->grow_selected( delta_tick ); - } - - needs_update = true; - } - } - - if ( a_ev->button == 3 ){ - set_adding( false ); + switch (global_interactionmethod) + { + case e_fruity_interaction: + return m_fruity_interaction.on_button_release_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_button_release_event(a_ev, *this); } + return false; - /* turn off */ - m_selecting = false; - m_moving = false; - m_growing = false; - m_paste = false; - m_moving_init = false; - m_painting = false; - - m_seq->unpaint_all(); - - /* if they clicked, something changed */ - if ( needs_update ){ - - ////printf( "needs_update2\n" ); - m_seq->set_dirty(); - //redraw_events(); - } - return true; } bool seqroll::on_motion_notify_event(GdkEventMotion* a_ev) { - m_current_x = (int) (a_ev->x + m_scroll_offset_x ); - m_current_y = (int) (a_ev->y + m_scroll_offset_y ); - - int note; - long tick; - - if ( m_moving_init ){ - m_moving_init = false; - m_moving = true; - } - - - snap_y( &m_current_y ); - convert_xy( 0, m_current_y, &tick, ¬e ); - - m_seqkeys_wid->set_hint_key( note ); - - if ( m_selecting || m_moving || m_growing || m_paste ){ - - if ( m_moving || m_paste ){ - snap_x( &m_current_x ); - } - - draw_selection_on_window(); - return true; - - } - - if ( m_painting ) + switch (global_interactionmethod) { - snap_x( &m_current_x ); - convert_xy( m_current_x, m_current_y, &tick, ¬e ); - - m_seq->add_note( tick, m_note_length - 2, note, true ); - return true; + case e_fruity_interaction: + return m_fruity_interaction.on_motion_notify_event(a_ev, *this); + case e_seq24_interaction: + return m_seq24_interaction.on_motion_notify_event(a_ev, *this); } - return false; } @@ -1393,6 +1117,13 @@ seqroll::on_key_press_event(GdkEventKey* m_seq->pop_undo(); ret = true; } + + /* select all events */ + if ( a_p0->keyval == GDK_a || a_p0->keyval == GDK_A ){ + + m_seq->select_all(); + ret = true; + } } } @@ -1455,3 +1186,919 @@ seqroll::on_scroll_event( GdkEventScroll } + + + + + + +////////////////////////// +// interaction methods +////////////////////////// + + + +void FruitySeqRollInput::updateMousePtr(seqroll& ths) +{ + // context sensitive mouse + { + long drop_tick; + int drop_note; + ths.convert_xy( ths.m_current_x, ths.m_current_y, &drop_tick, &drop_note ); + long start, end, note; + if (ths.m_is_drag_pasting || ths.m_selecting || ths.m_moving || ths.m_growing || ths.m_paste) + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); + } + else if (!m_adding && + ths.m_seq->intersectNotes( drop_tick, drop_note, start, end, note ) && note == drop_note) + { + long handle_size = clamp( c_handlesize, 0, (end-start)/3 ); + if (start <= drop_tick && drop_tick <= start + handle_size) + { + //get_window()->set_cursor( Gdk::Cursor( Gdk::RIGHT_PTR )); + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::CENTER_PTR )); // not supported yet + } + else if (end - handle_size <= drop_tick && drop_tick <= end) + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); + } + else + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::CENTER_PTR )); + } + } + else + { + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL )); + } + } +} + + +bool FruitySeqRollInput::on_button_press_event(GdkEventButton* a_ev, seqroll& ths) +{ + int numsel; + + long tick_s; + long tick_f; + int note_h; + int note_l; + + int norm_x, norm_y, snapped_x, snapped_y; + + ths.grab_focus( ); + + bool needs_update = false; + + snapped_x = norm_x = (int) (a_ev->x + ths.m_scroll_offset_x ); + snapped_y = norm_y = (int) (a_ev->y + ths.m_scroll_offset_y ); + + ths.snap_x( &snapped_x ); + ths.snap_y( &snapped_y ); + + /* y is always snapped */ + ths.m_current_y = ths.m_drop_y = snapped_y; + + /* reset box that holds dirty redraw spot */ + ths.m_old.x = 0; + ths.m_old.y = 0; + ths.m_old.width = 0; + ths.m_old.height = 0; + + // ctrl-v pressed, we're waiting for a click to show where to paste + if ( ths.m_paste ){ + + ths.convert_xy( snapped_x, snapped_y, &tick_s, ¬e_h ); + ths.m_paste = false; + ths.m_seq->push_undo(); + ths.m_seq->paste_selected( tick_s, note_h ); + + needs_update = true; + + } else { + + /* left mouse button */ + if ( a_ev->button == 1) + { + + /* selection, normal x */ + ths.m_current_x = ths.m_drop_x = norm_x; + + /* turn x,y in to tick/note */ + ths.convert_xy( ths.m_drop_x, ths.m_drop_y, &tick_s, ¬e_h ); + + // if not on top of event then add one... + if ( m_canadd && ! ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_would_select ) && + !(a_ev->state & GDK_CONTROL_MASK) ) + { + /* start the paint job */ + ths.m_painting = true; + m_adding = true; + + /* adding, snapped x */ + ths.m_current_x = ths.m_drop_x = snapped_x; + ths.convert_xy( ths.m_drop_x, ths.m_drop_y, &tick_s, ¬e_h ); + + // test if a note is already there + // fake select, if so, no add + if ( ! ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_would_select )) + { + /* add note, length = little less than snap */ + ths.m_seq->push_undo(); + ths.m_seq->add_note( tick_s, ths.m_note_length - 2, note_h, true ); + + needs_update = true; + } + + } + else /* selecting */ + { + // if the under the cursor is not a selected note... + if ( !ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_is_selected )) + { + // if clicking a note ... + if (ths.m_seq->select_note_events( tick_s,note_h,tick_s,note_h, + sequence::e_would_select ) ) + { + // ... unselect all if ctrl not held + if (! (a_ev->state & GDK_CONTROL_MASK)) + ths.m_seq->unselect(); + } + // if clicking empty space ... + else + { + // ... unselect all if ctrl-shift not held + if (! ((a_ev->state & GDK_CONTROL_MASK) && + (a_ev->state & GDK_SHIFT_MASK)) ) + ths.m_seq->unselect(); + } + + /* on direct click select only one event */ + numsel = ths.m_seq->select_note_events( tick_s,note_h,tick_s,note_h, + sequence::e_select_one ); + // prevent deselect in button_release() + if (numsel) + ths.m_justselected_one = true; + + // if nothing selected, start the selection box + if (numsel == 0 && (a_ev->state & GDK_CONTROL_MASK)) + ths.m_selecting = true; + + needs_update = true; + } + + // if note under cursor is selected + if ( ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_is_selected )) + { + // context sensitive mouse + bool left_mouse_handle = false; + bool right_mouse_handle = false; + bool center_mouse_handle = false; + { + long drop_tick; + int drop_note; + ths.convert_xy( ths.m_drop_x, ths.m_drop_y, &drop_tick, &drop_note ); + long start, end, note; + if (ths.m_seq->intersectNotes( drop_tick, drop_note, start, end, note ) && note == drop_note) + { + long handle_size = clamp( c_handlesize, 0, (end-start)/3 ); // 16 wide unless very small... + if (start <= drop_tick && drop_tick <= start + handle_size) + { + //left_mouse_handle = true; // not supported yet + center_mouse_handle = true; + } + else if (end - handle_size <= drop_tick && drop_tick <= end) + { + right_mouse_handle = true; + } + else + { + center_mouse_handle = true; + } + } + } + + // grab/move the note + if ( center_mouse_handle && + a_ev->button == 1 && !(a_ev->state & GDK_CONTROL_MASK) ) + { + ths.m_moving_init = true; + needs_update = true; + + + /* get the box that selected elements are in */ + ths.m_seq->get_selected_box( &tick_s, ¬e_h, + &tick_f, ¬e_l ); + + + ths.convert_tn_box_to_rect( tick_s, tick_f, note_h, note_l, + &ths.m_selected.x, + &ths.m_selected.y, + &ths.m_selected.width, + &ths.m_selected.height ); + + /* save offset that we get from the snap above */ + int adjusted_selected_x = ths.m_selected.x; + ths.snap_x( &adjusted_selected_x ); + ths.m_move_snap_offset_x = ( ths.m_selected.x - adjusted_selected_x); + + /* align selection for drawing */ + ths.snap_x( &ths.m_selected.x ); + + ths.m_current_x = ths.m_drop_x = snapped_x; + } + // ctrl left click when stuff is already selected + else if (a_ev->button == 1 && (a_ev->state & GDK_CONTROL_MASK) && + ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_is_selected )) + { + ths.m_is_drag_pasting_start = true; + m_drag_paste_start_pos[0] = (long)a_ev->x; + m_drag_paste_start_pos[1] = (long)a_ev->y; + //printf( "start: %lf %lf\n", a_ev->x, a_ev->y ); + } + + /* left click on the right handle - grow/resize event */ + if ( (right_mouse_handle && + a_ev->button == 1 && ! (a_ev->state & GDK_CONTROL_MASK)) || + a_ev->button == 2 ){ + ths.m_growing = true; + + /* get the box that selected elements are in */ + ths.m_seq->get_selected_box( &tick_s, ¬e_h, + &tick_f, ¬e_l ); + + ths.convert_tn_box_to_rect( tick_s, tick_f, note_h, note_l, + &ths.m_selected.x, + &ths.m_selected.y, + &ths.m_selected.width, + &ths.m_selected.height ); + } + } + } + } + + + /* right click */ + if ( a_ev->button == 3 ){ + /* selection, normal x */ + ths.m_current_x = ths.m_drop_x = norm_x; + + /* turn x,y in to tick/note */ + ths.convert_xy( ths.m_drop_x, ths.m_drop_y, &tick_s, ¬e_h ); + + + // erase event(s) under cursor if there is one + if ( ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_would_select) ) + { + /* right ctrl click: remove all selected notes */ + if (a_ev->state & GDK_CONTROL_MASK) + { + ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_select_one ); + ths.m_seq->push_undo(); + ths.m_seq->mark_selected(); + ths.m_seq->remove_marked(); + } + /* right click: remove only the note under the cursor, + leave the selection intact */ + else + { + ths.m_seq->push_undo(); + ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_remove_one ); + } + + // hold down the right button, drag mouse around erasing notes: + m_erase_painting = true; + + // repaint... we've changed the notes. + needs_update = true; + } + else /* selecting */ + { + + if ( ! (a_ev->state & GDK_CONTROL_MASK) ) + ths.m_seq->unselect(); + + // nothing selected, start the selection box + ths.m_selecting = true; + + needs_update = true; + } + } + } + + // context sensative mouse pointer... + updateMousePtr( ths ); + + /* if they clicked, something changed */ + if ( needs_update ){ + ////printf( "needs update\n" ); + ths.m_seq->set_dirty(); + //redraw_events(); + } + return true; +} + +bool FruitySeqRollInput::on_button_release_event(GdkEventButton* a_ev, seqroll& ths) +{ + long tick_s; + long tick_f; + int note_h; + int note_l; + int x,y,w,h; + int numsel; + + bool needs_update = false; + + ths.m_current_x = (int) (a_ev->x + ths.m_scroll_offset_x ); + ths.m_current_y = (int) (a_ev->y + ths.m_scroll_offset_y ); + + ths.snap_y( &ths.m_current_y ); + + if ( ths.m_moving || ths.m_is_drag_pasting ) + ths.snap_x( &ths.m_current_x ); + + int delta_x = ths.m_current_x - ths.m_drop_x; + int delta_y = ths.m_current_y - ths.m_drop_y; + + long delta_tick; + int delta_note; + + // middle click, or ctrlleft click button up + if ( a_ev->button == 1 || + a_ev->button == 2 ){ + if ( ths.m_growing ) + { + /* convert deltas into screen corridinates */ + ths.convert_xy( delta_x, delta_y, &delta_tick, &delta_note ); + ths.m_seq->push_undo(); + + if ( a_ev->state & GDK_SHIFT_MASK ) + ths.m_seq->stretch_selected( delta_tick ); + else + ths.m_seq->grow_selected( delta_tick ); + + needs_update = true; + } + } + long int current_tick; + int current_note; + ths.convert_xy( ths.m_current_x, ths.m_current_y, ¤t_tick, ¤t_note ); + + + // ctrl-left click button up for select/drag copy/paste + // left click button up for ending a move of selected notes + if ( a_ev->button == 1 ){ + m_adding = false; + if ( ths.m_is_drag_pasting ) + { + ths.m_is_drag_pasting = false; + ths.m_is_drag_pasting_start = false; + + /* convert deltas into screen corridinates */ + ths.m_paste = false; + ths.m_seq->push_undo(); + ths.m_seq->paste_selected( current_tick, current_note ); + + needs_update = true; + + //m_seq->unselect(); + } + // ctrl-left click but without movement - select a note + if (ths.m_is_drag_pasting_start) + { + ths.m_is_drag_pasting_start = false; + + // if ctrl-left click without movement and + // if note under cursor is selected, and ctrl is held + // and buttondown didn't just select one + if (!ths.m_justselected_one && + ths.m_seq->select_note_events( current_tick, current_note, + current_tick, current_note, + sequence::e_is_selected ) && + (a_ev->state & GDK_CONTROL_MASK)) + { + // deselect the note + numsel = ths.m_seq->select_note_events( current_tick, current_note, + current_tick, current_note, + sequence::e_deselect ); + needs_update = true; + } + } + ths.m_justselected_one = false; // clear flag on left button up + + if ( ths.m_moving ){ + + /* adjust for snap */ + delta_x -= ths.m_move_snap_offset_x; + + /* convert deltas into screen corridinates */ + ths.convert_xy( delta_x, delta_y, &delta_tick, &delta_note ); + + /* since delta_note was from delta_y, it will be filpped + ( delta_y[0] = note[127], etc.,so we have to adjust */ + delta_note = delta_note - (c_num_keys-1); + + ths.m_seq->push_undo(); + ths.m_seq->move_selected_notes( delta_tick, delta_note ); + needs_update = true; + } + } + + // right click or leftctrl click button up for selection box + if ( a_ev->button == 3 || a_ev->button == 1 ){ + if ( ths.m_selecting ) + { + ths.xy_to_rect ( ths.m_drop_x, + ths.m_drop_y, + ths.m_current_x, + ths.m_current_y, + &x, &y, + &w, &h ); + + ths.convert_xy( x, y, &tick_s, ¬e_h ); + ths.convert_xy( x+w, y+h, &tick_f, ¬e_l ); + + numsel = ths.m_seq->select_note_events( tick_s, note_h, tick_f, note_l, sequence::e_toggle_selection ); + + needs_update = true; + } + } + if ( a_ev->button == 3 ) + { + m_erase_painting = false; + } + + /* turn off */ + ths.m_selecting = false; + ths.m_moving = false; + ths.m_growing = false; + ths.m_paste = false; + ths.m_moving_init = false; + ths.m_painting = false; + + ths.m_seq->unpaint_all(); + + // context sensative mouse pointer... + updateMousePtr( ths ); + + + /* if they clicked, something changed */ + if ( needs_update ){ + + ////printf( "needs_update2\n" ); + + ths.m_seq->set_dirty(); + //redraw_events(); + + } + return true; +} + +bool FruitySeqRollInput::on_motion_notify_event(GdkEventMotion* a_ev, seqroll& ths) +{ + ths.m_current_x = (int) (a_ev->x + ths.m_scroll_offset_x ); + ths.m_current_y = (int) (a_ev->y + ths.m_scroll_offset_y ); + + int note; + long tick; + + if ( ths.m_moving_init ){ + ths.m_moving_init = false; + ths.m_moving = true; + } + + // context sensitive mouse pointer... + updateMousePtr( ths ); + + // ctrl-left click drag on selected note(s) starts a copy/unselect/paste + // don't begin the paste until mouse moves a few pixels, filter out the unsteady hand + if ( ths.m_is_drag_pasting_start && + (6 <= abs(m_drag_paste_start_pos[0] - (long)a_ev->x) || + 6 <= abs(m_drag_paste_start_pos[1] - (long)a_ev->y)) ) + { + ths.m_seq->copy_selected(); + ths.m_seq->unselect(); + ths.start_paste(); + + ths.m_is_drag_pasting_start = false; + ths.m_is_drag_pasting = true; + } + + + + ths.snap_y( &ths.m_current_y ); + ths.convert_xy( 0, ths.m_current_y, &tick, ¬e ); + + ths.m_seqkeys_wid->set_hint_key( note ); + + if ( ths.m_selecting || ths.m_moving || ths.m_growing || ths.m_paste ){ + + if ( ths.m_moving || ths.m_paste ){ + ths.snap_x( &ths.m_current_x ); + } + + ths.draw_selection_on_window(); + return true; + + } + + if ( ths.m_painting ) + { + ths.snap_x( &ths.m_current_x ); + ths.convert_xy( ths.m_current_x, ths.m_current_y, &tick, ¬e ); + + ths.m_seq->add_note( tick, ths.m_note_length - 2, note, true ); + return true; + } + + if (m_erase_painting) + { + ths.convert_xy( ths.m_current_x, ths.m_current_y, &tick, ¬e ); + if ( ths.m_seq->select_note_events( tick, note, + tick, note, + sequence::e_would_select) ) + { + /* remove only the note under the cursor, + leave the selection intact */ + ths.m_seq->push_undo(); + ths.m_seq->select_note_events( tick, note, + tick, note, + sequence::e_remove_one ); + ths.m_seq->set_dirty(); + } + } + + + return false; +} + + + + + +/* popup menu calls this */ +void +Seq24SeqRollInput::set_adding( bool a_adding, seqroll& ths ) +{ + if ( a_adding ){ + + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::PENCIL )); + m_adding = true; + + } else { + + ths.get_window()->set_cursor( Gdk::Cursor( Gdk::LEFT_PTR )); + m_adding = false; + } +} + +bool Seq24SeqRollInput::on_button_press_event(GdkEventButton* a_ev, seqroll& ths) +{ + int numsel; + + long tick_s; + long tick_f; + int note_h; + int note_l; + + int norm_x, norm_y, snapped_x, snapped_y; + + ths.grab_focus( ); + + bool needs_update = false; + + snapped_x = norm_x = (int) (a_ev->x + ths.m_scroll_offset_x ); + snapped_y = norm_y = (int) (a_ev->y + ths.m_scroll_offset_y ); + + ths.snap_x( &snapped_x ); + ths.snap_y( &snapped_y ); + + /* y is always snapped */ + ths.m_current_y = ths.m_drop_y = snapped_y; + + /* reset box that holds dirty redraw spot */ + ths.m_old.x = 0; + ths.m_old.y = 0; + ths.m_old.width = 0; + ths.m_old.height = 0; + + if ( ths.m_paste ){ + + ths.convert_xy( snapped_x, snapped_y, &tick_s, ¬e_h ); + ths.m_paste = false; + ths.m_seq->push_undo(); + ths.m_seq->paste_selected( tick_s, note_h ); + + needs_update = true; + + } else { + + /* left mouse button */ + if ( a_ev->button == 1 || + a_ev->button == 2 ) + { + + /* selection, normal x */ + ths.m_current_x = ths.m_drop_x = norm_x; + + /* turn x,y in to tick/note */ + ths.convert_xy( ths.m_drop_x, ths.m_drop_y, &tick_s, ¬e_h ); + + if ( m_adding ) + { + /* start the paint job */ + ths.m_painting = true; + + /* adding, snapped x */ + ths.m_current_x = ths.m_drop_x = snapped_x; + ths.convert_xy( ths.m_drop_x, ths.m_drop_y, &tick_s, ¬e_h ); + + // test if a note is already there + // fake select, if so, no add + if ( ! ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_would_select )) + { + + /* add note, length = little less than snap */ + ths.m_seq->push_undo(); + ths.m_seq->add_note( tick_s, ths.m_note_length - 2, note_h, true ); + + needs_update = true; + } + + } + else /* selecting */ + { + + + if ( !ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_is_selected )) + { + if ( ! (a_ev->state & GDK_CONTROL_MASK) ) + { + ths.m_seq->unselect(); + } + + + /* on direct click select only one event */ + numsel = ths.m_seq->select_note_events( tick_s,note_h,tick_s,note_h, + sequence::e_select_one ); + + /* none selected, start selection box */ + if ( numsel == 0 ) + { + if ( a_ev->button == 1 ) + ths.m_selecting = true; + } + else + { + needs_update = true; + } + } + + + if ( ths.m_seq->select_note_events( tick_s, note_h, + tick_s, note_h, + sequence::e_is_selected )) + { + // moving - left click only + if ( a_ev->button == 1 && !(a_ev->state & GDK_CONTROL_MASK) ) + { + ths.m_moving_init = true; + needs_update = true; + + + /* get the box that selected elements are in */ + ths.m_seq->get_selected_box( &tick_s, ¬e_h, + &tick_f, ¬e_l ); + + + ths.convert_tn_box_to_rect( tick_s, tick_f, note_h, note_l, + &ths.m_selected.x, + &ths.m_selected.y, + &ths.m_selected.width, + &ths.m_selected.height ); + + /* save offset that we get from the snap above */ + int adjusted_selected_x = ths.m_selected.x; + ths.snap_x( &adjusted_selected_x ); + ths.m_move_snap_offset_x = ( ths.m_selected.x - adjusted_selected_x); + + /* align selection for drawing */ + ths.snap_x( &ths.m_selected.x ); + + ths.m_current_x = ths.m_drop_x = snapped_x; + } + + /* middle mouse button, or left-ctrl click (for 2button mice) */ + if ( a_ev->button == 2 || + (a_ev->button == 1 && (a_ev->state & GDK_CONTROL_MASK)) ){ + + /* moving, normal x */ + //m_current_x = m_drop_x = norm_x; + //convert_xy( m_drop_x, m_drop_y, &tick_s, ¬e_h ); + + ths.m_growing = true; + + /* get the box that selected elements are in */ + ths.m_seq->get_selected_box( &tick_s, ¬e_h, + &tick_f, ¬e_l ); + + ths.convert_tn_box_to_rect( tick_s, tick_f, note_h, note_l, + &ths.m_selected.x, + &ths.m_selected.y, + &ths.m_selected.width, + &ths.m_selected.height ); + + } + } + } + } + + /* right mouse button */ + if ( a_ev->button == 3 ){ + set_adding( true, ths ); + } + + } + + /* if they clicked, something changed */ + if ( needs_update ){ + + ////printf( "needs update\n" ); + ths.m_seq->set_dirty(); + //redraw_events(); + } + return true; +} + +bool Seq24SeqRollInput::on_button_release_event(GdkEventButton* a_ev, seqroll& ths) +{ + long tick_s; + long tick_f; + int note_h; + int note_l; + int x,y,w,h; + int numsel; + + bool needs_update = false; + + ths.m_current_x = (int) (a_ev->x + ths.m_scroll_offset_x ); + ths.m_current_y = (int) (a_ev->y + ths.m_scroll_offset_y ); + + ths.snap_y ( &ths.m_current_y ); + + if ( ths.m_moving ) + ths.snap_x( &ths.m_current_x ); + + int delta_x = ths.m_current_x - ths.m_drop_x; + int delta_y = ths.m_current_y - ths.m_drop_y; + + long delta_tick; + int delta_note; + + if ( a_ev->button == 1 ){ + + if ( ths.m_selecting ){ + + ths.xy_to_rect ( ths.m_drop_x, + ths.m_drop_y, + ths.m_current_x, + ths.m_current_y, + &x, &y, + &w, &h ); + + ths.convert_xy( x, y, &tick_s, ¬e_h ); + ths.convert_xy( x+w, y+h, &tick_f, ¬e_l ); + + numsel = ths.m_seq->select_note_events( tick_s, note_h, tick_f, note_l, sequence::e_select ); + + needs_update = true; + } + + if ( ths.m_moving ){ + + /* adjust for snap */ + delta_x -= ths.m_move_snap_offset_x; + + /* convert deltas into screen corridinates */ + ths.convert_xy( delta_x, delta_y, &delta_tick, &delta_note ); + + /* since delta_note was from delta_y, it will be filpped + ( delta_y[0] = note[127], etc.,so we have to adjust */ + delta_note = delta_note - (c_num_keys-1); + + ths.m_seq->push_undo(); + ths.m_seq->move_selected_notes( delta_tick, delta_note ); + needs_update = true; + } + + } + + if ( a_ev->button == 2 || a_ev->button == 1 ){ + + if ( ths.m_growing ){ + + /* convert deltas into screen corridinates */ + ths.convert_xy( delta_x, delta_y, &delta_tick, &delta_note ); + ths.m_seq->push_undo(); + + if ( a_ev->state & GDK_SHIFT_MASK ) + { + ths.m_seq->stretch_selected( delta_tick ); + } + else + { + ths.m_seq->grow_selected( delta_tick ); + } + + needs_update = true; + } + } + + if ( a_ev->button == 3 ){ + set_adding( false, ths ); + } + + /* turn off */ + ths.m_selecting = false; + ths.m_moving = false; + ths.m_growing = false; + ths.m_paste = false; + ths.m_moving_init = false; + ths.m_painting = false; + + ths.m_seq->unpaint_all(); + + /* if they clicked, something changed */ + if ( needs_update ){ + + ////printf( "needs_update2\n" ); + + ths.m_seq->set_dirty(); + //redraw_events(); + + } + return true; +} + +bool Seq24SeqRollInput::on_motion_notify_event(GdkEventMotion* a_ev, seqroll& ths) +{ + ths.m_current_x = (int) (a_ev->x + ths.m_scroll_offset_x ); + ths.m_current_y = (int) (a_ev->y + ths.m_scroll_offset_y ); + + int note; + long tick; + + if ( ths.m_moving_init ){ + ths.m_moving_init = false; + ths.m_moving = true; + } + + + ths.snap_y( &ths.m_current_y ); + ths.convert_xy( 0, ths.m_current_y, &tick, ¬e ); + + ths.m_seqkeys_wid->set_hint_key( note ); + + if ( ths.m_selecting || ths.m_moving || ths.m_growing || ths.m_paste ){ + + if ( ths.m_moving || ths.m_paste ){ + ths.snap_x( &ths.m_current_x ); + } + + ths.draw_selection_on_window(); + return true; + + } + + if ( ths.m_painting ) + { + ths.snap_x( &ths.m_current_x ); + ths.convert_xy( ths.m_current_x, ths.m_current_y, &tick, ¬e ); + + ths.m_seq->add_note( tick, ths.m_note_length - 2, note, true ); + return true; + } + + return false; +} diff -rupN seq24-rev48 adding win32/src/seqroll.h seq24-rev48 win32 adding MouseInteraction/src/seqroll.h --- seq24-rev48 adding win32/src/seqroll.h 2009-05-20 20:30:47.609375000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/seqroll.h 2009-05-20 20:30:51.937500000 -0500 @@ -53,12 +53,43 @@ class rect int x, y, height, width; }; +class seqroll; +struct FruitySeqRollInput +{ + FruitySeqRollInput() : m_adding( false ), m_canadd( true ), m_erase_painting( false ) + {} + bool on_button_press_event(GdkEventButton* a_ev, seqroll& ths); + bool on_button_release_event(GdkEventButton* a_ev, seqroll& ths); + bool on_motion_notify_event(GdkEventMotion* a_ev, seqroll& ths); + void updateMousePtr(seqroll& ths); + bool m_adding; + bool m_canadd; + bool m_erase_painting; + long m_drag_paste_start_pos[2]; +}; +struct Seq24SeqRollInput +{ + Seq24SeqRollInput() : m_adding( false ) + {} + bool on_button_press_event(GdkEventButton* a_ev, seqroll& ths); + bool on_button_release_event(GdkEventButton* a_ev, seqroll& ths); + bool on_motion_notify_event(GdkEventMotion* a_ev, seqroll& ths); + void set_adding( bool a_adding, seqroll& ths ); + bool m_adding; +}; + /* piano roll */ class seqroll : public Gtk::DrawingArea { private: + friend struct FruitySeqRollInput; + FruitySeqRollInput m_fruity_interaction; + + friend struct Seq24SeqRollInput; + Seq24SeqRollInput m_seq24_interaction; + Glib::RefPtr m_gc; Glib::RefPtr m_window; @@ -98,9 +129,11 @@ class seqroll : public Gtk::DrawingArea bool m_moving; bool m_moving_init; bool m_growing; - bool m_adding; bool m_painting; bool m_paste; + bool m_is_drag_pasting; + bool m_is_drag_pasting_start; + bool m_justselected_one; /* where the dragging started */ int m_drop_x; @@ -194,7 +227,6 @@ class seqroll : public Gtk::DrawingArea int idle_redraw(); void draw_progress_on_window(); - void set_adding( bool a_adding ); void start_paste( ); diff -rupN seq24-rev48 adding win32/src/sequence.cpp seq24-rev48 win32 adding MouseInteraction/src/sequence.cpp --- seq24-rev48 adding win32/src/sequence.cpp 2009-05-20 20:30:47.875000000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/sequence.cpp 2009-05-20 20:30:52.171875000 -0500 @@ -81,7 +81,7 @@ sequence::pop_undo( void ) lock(); if (m_list_undo.size() > 0 ){ - m_list_redo.push( m_list_event ); + m_list_redo.push( m_list_event ); m_list_event = m_list_undo.top(); m_list_undo.pop(); verify_and_link(); @@ -97,7 +97,7 @@ sequence::pop_redo( void ) lock(); if (m_list_redo.size() > 0 ){ - m_list_undo.push( m_list_event ); + m_list_undo.push( m_list_event ); m_list_event = m_list_redo.top(); m_list_redo.pop(); verify_and_link(); @@ -117,7 +117,7 @@ sequence::push_trigger_undo( void ) for ( i = m_list_trigger_undo.top().begin(); i != m_list_trigger_undo.top().end(); i++ ){ - (*i).m_selected = false; + (*i).m_selected = false; } @@ -132,7 +132,7 @@ sequence::pop_trigger_undo( void ) if (m_list_trigger_undo.size() > 0 ){ - m_list_trigger_redo.push( m_list_trigger ); + m_list_trigger_redo.push( m_list_trigger ); m_list_trigger = m_list_trigger_undo.top(); m_list_trigger_undo.pop(); } @@ -448,84 +448,84 @@ sequence::verify_and_link() lock(); for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ - (*i).clear_link(); + (*i).clear_link(); (*i).unmark(); } on = m_list_event.begin(); - + /* pair ons and offs */ while ( on != m_list_event.end() ){ - /* check for a note on, then look for its - note off */ - if ( (*on).is_note_on() ){ - - /* get next possible off node */ - off = on; off++; - end_found = false; - - while ( off != m_list_event.end() ){ - - /* is a off event, == notes, and isnt - markeded */ - if ( (*off).is_note_off() && - (*off).get_note() == (*on).get_note() && - ! (*off).is_marked() ){ - - /* link + mark */ - (*on).link( &(*off) ); - (*off).link( &(*on) ); - (*on).mark( ); - (*off).mark( ); - end_found = true; + /* check for a note on, then look for its + note off */ + if ( (*on).is_note_on() ){ + + /* get next possible off node */ + off = on; off++; + end_found = false; + + while ( off != m_list_event.end() ){ + + /* is a off event, == notes, and isnt + markeded */ + if ( (*off).is_note_off() && + (*off).get_note() == (*on).get_note() && + ! (*off).is_marked() ){ + + /* link + mark */ + (*on).link( &(*off) ); + (*off).link( &(*on) ); + (*on).mark( ); + (*off).mark( ); + end_found = true; - break; - } - off++; - } - if (!end_found) { - off = m_list_event.begin(); - while ( off != on){ - if ( (*off).is_note_off() && - (*off).get_note() == (*on).get_note() && - ! (*off).is_marked() ){ - - /* link + mark */ - (*on).link( &(*off) ); - (*off).link( &(*on) ); - (*on).mark( ); - (*off).mark( ); - end_found = true; - - break; - } - off++; - - } - } - } - on++; + break; + } + off++; + } + if (!end_found) { + off = m_list_event.begin(); + while ( off != on){ + if ( (*off).is_note_off() && + (*off).get_note() == (*on).get_note() && + ! (*off).is_marked() ){ + + /* link + mark */ + (*on).link( &(*off) ); + (*off).link( &(*on) ); + (*on).mark( ); + (*off).mark( ); + end_found = true; + + break; + } + off++; + + } + } + } + on++; } /* unmark all */ for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ - (*i).unmark(); + (*i).unmark(); } /* kill those not in range */ for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ - - /* if our current time stamp is greater then the length */ - if ( (*i).get_timestamp() >= m_length || - (*i).get_timestamp() < 0 ){ - - /* we have to prune it */ - (*i).mark(); - if ( (*i).is_linked() ) - (*i).get_linked()->mark(); - } + /* if our current time stamp is greater then the length */ + + if ( (*i).get_timestamp() >= m_length || + (*i).get_timestamp() < 0 ){ + + /* we have to prune it */ + (*i).mark(); + if ( (*i).is_linked() ) + (*i).get_linked()->mark(); + } } remove_marked( ); @@ -550,63 +550,99 @@ sequence::link_new( ) /* pair ons and offs */ while ( on != m_list_event.end()){ - /* check for a note on, then look for its - note off */ - if ( (*on).is_note_on() && - ! (*on).is_linked() ){ - - /* get next element */ - off = on; off++; - end_found = false; - while ( off != m_list_event.end()){ - - /* is a off event, == notes, and isnt - selected */ - if ( (*off).is_note_off() && - (*off).get_note() == (*on).get_note() && - ! (*off).is_linked() ){ - - /* link */ - (*on).link( &(*off) ); - (*off).link( &(*on) ); - end_found = true; - - break; - } - off++; - } + /* check for a note on, then look for its + note off */ + if ( (*on).is_note_on() && + ! (*on).is_linked() ){ + + /* get next element */ + off = on; off++; + end_found = false; + while ( off != m_list_event.end()){ + + /* is a off event, == notes, and isnt + selected */ + if ( (*off).is_note_off() && + (*off).get_note() == (*on).get_note() && + ! (*off).is_linked() ){ + + /* link */ + (*on).link( &(*off) ); + (*off).link( &(*on) ); + end_found = true; - if (!end_found) { + break; + } + off++; + } + + if (!end_found) { off = m_list_event.begin(); - while ( off != on){ + while ( off != on){ - /* is a off event, == notes, and isnt - selected */ - if ( (*off).is_note_off() && - (*off).get_note() == (*on).get_note() && - ! (*off).is_linked() ){ - - /* link */ - (*on).link( &(*off) ); - (*off).link( &(*on) ); - end_found = true; - - break; - } - off++; - } - } - } - on++; + /* is a off event, == notes, and isnt + selected */ + if ( (*off).is_note_off() && + (*off).get_note() == (*on).get_note() && + ! (*off).is_linked() ){ + + /* link */ + (*on).link( &(*off) ); + (*off).link( &(*on) ); + end_found = true; + + break; + } + off++; + } + } + } + on++; } unlock(); } +// helper function, does not lock/unlock, unsafe to call without them +// supply iterator from m_list_event... +// lock(); remove(); reset_draw_marker(); unlock() +void +sequence::remove(list::iterator i) +{ + /* if its a note off, and that note is currently + playing, send a note off */ + if ( (*i).is_note_off() && + m_playing_notes[ (*i).get_note()] > 0 ){ + + m_masterbus->play( m_bus, &(*i), m_midi_channel ); + m_playing_notes[(*i).get_note()]--; + } + m_list_event.erase(i); +} + +// helper function, does not lock/unlock, unsafe to call without them +// supply iterator from m_list_event... +// lock(); remove(); reset_draw_marker(); unlock() +// finds e in m_list_event, removes the first iterator matching that. +void +sequence::remove( event* e ) +{ + list::iterator i = m_list_event.begin(); + while( i != m_list_event.end() ) + { + if (e == &(*i)) + { + remove( i ); + return; + } + ++i; + } +} + void -sequence::remove_marked( ) +sequence::remove_marked() { list::iterator i, t; @@ -614,26 +650,17 @@ sequence::remove_marked( ) i = m_list_event.begin(); while( i != m_list_event.end() ){ - - if ((*i).is_marked()){ - - /* if its a note off, and that note is currently - playing, send a note off */ - if ( (*i).is_note_off() && - m_playing_notes[ (*i).get_note()] > 0 ){ - - m_masterbus->play( m_bus, &(*i), m_midi_channel ); - m_playing_notes[(*i).get_note()]--; - } - - t = i; t++; - m_list_event.erase(i); - i = t; - } - else { - i++; - } + if ((*i).is_marked()){ + + t = i; t++; + remove( i ); + i = t; + } + else { + + i++; + } } reset_draw_marker(); @@ -652,8 +679,8 @@ sequence::mark_selected( ) i = m_list_event.begin(); while( i != m_list_event.end() ){ - - if ((*i).is_selected()){ + + if ((*i).is_selected()){ (*i).mark(); } @@ -683,7 +710,7 @@ sequence::unpaint_all( ) /* returns the 'box' of the selected items */ void sequence::get_selected_box( long *a_tick_s, int *a_note_h, - long *a_tick_f, int *a_note_l ) + long *a_tick_f, int *a_note_l ) { list::iterator i; @@ -701,18 +728,20 @@ sequence::get_selected_box( long *a_tick for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ - if( (*i).is_selected() ){ - - time = (*i).get_timestamp(); - - if ((*i).is_note_on() && ( time < *a_tick_s )) *a_tick_s = time; - if ((*i).is_note_off() && (time > *a_tick_f )) *a_tick_f = time; - - note = (*i).get_note(); + if( (*i).is_selected() ){ - if ( note < *a_note_l ) *a_note_l = note; - if ( note > *a_note_h ) *a_note_h = note; - } + time = (*i).get_timestamp(); + + // can't check on/off here. screws up seqevent + // selection which has no "off" + if ( time < *a_tick_s ) *a_tick_s = time; + if ( time > *a_tick_f ) *a_tick_f = time; + + note = (*i).get_note(); + + if ( note < *a_note_l ) *a_note_l = note; + if ( note > *a_note_h ) *a_note_h = note; + } } unlock(); @@ -720,7 +749,7 @@ sequence::get_selected_box( long *a_tick void sequence::get_clipboard_box( long *a_tick_s, int *a_note_h, - long *a_tick_f, int *a_note_l ) + long *a_tick_f, int *a_note_l ) { list::iterator i; @@ -737,20 +766,20 @@ sequence::get_clipboard_box( long *a_tic lock(); if ( m_list_clipboard.size() == 0 ) { - *a_tick_s = *a_tick_f = *a_note_h = *a_note_l = 0; + *a_tick_s = *a_tick_f = *a_note_h = *a_note_l = 0; } for ( i = m_list_clipboard.begin(); i != m_list_clipboard.end(); i++ ){ - - time = (*i).get_timestamp(); - - if ( time < *a_tick_s ) *a_tick_s = time; - if ( time > *a_tick_f ) *a_tick_f = time; - - note = (*i).get_note(); - - if ( note < *a_note_l ) *a_note_l = note; - if ( note > *a_note_h ) *a_note_h = note; + + time = (*i).get_timestamp(); + + if ( time < *a_tick_s ) *a_tick_s = time; + if ( time > *a_tick_f ) *a_tick_f = time; + + note = (*i).get_note(); + + if ( note < *a_note_l ) *a_note_l = note; + if ( note > *a_note_h ) *a_note_h = note; } unlock(); @@ -828,32 +857,30 @@ sequence::select_note_events( long a_tic lock(); - for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ + for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ) { if( (*i).get_note() <= a_note_h && (*i).get_note() >= a_note_l ) { - - if ( (*i).is_linked() ) { + + if ( (*i).is_linked() ) { event *ev = (*i).get_linked(); - - if ( (*i).is_note_off() ) { - tick_s = ev->get_timestamp(); - tick_f = (*i).get_timestamp(); - } - - if ( (*i).is_note_on() ) { - tick_f = ev->get_timestamp(); - tick_s = (*i).get_timestamp(); - } - - if ( - ( (tick_s <= tick_f) && - ((tick_s <= a_tick_f) && (tick_f >= a_tick_s)) ) || - ( (tick_s > tick_f) && - ((tick_s <= a_tick_f) || (tick_f >= a_tick_s)) ) ) - - { - + + if ( (*i).is_note_off() ) { + tick_s = ev->get_timestamp(); + tick_f = (*i).get_timestamp(); + } + + if ( (*i).is_note_on() ) { + tick_f = ev->get_timestamp(); + tick_s = (*i).get_timestamp(); + } + + if ( + ( (tick_s <= tick_f) && + ((tick_s <= a_tick_f) && (tick_f >= a_tick_s)) ) || + ( (tick_s > tick_f) && + ((tick_s <= a_tick_f) || (tick_f >= a_tick_s)) ) ) + { if ( a_action == e_select || a_action == e_select_one ) { @@ -876,32 +903,89 @@ sequence::select_note_events( long a_tic ret = 1; break; } - - } - - - } else { - tick_s = tick_f = (*i).get_timestamp(); - if ( tick_s >= a_tick_s - 16 && tick_f <= a_tick_f) { - - if ( a_action == e_select || a_action == e_select_one ) { + if ( a_action == e_deselect ) + { + ret = 0; + (*i).unselect( ); + ev->unselect(); + //break; + } + if ( a_action == e_toggle_selection && + (*i).is_note_on()) // don't toggle twice + { + if ((*i).is_selected()) + { + (*i).unselect( ); + ev->unselect(); + ret ++; + } + else + { + (*i).select(); + ev->select(); + ret ++; + } + } + if ( a_action == e_remove_one ) + { + remove( &(*i) ); + remove( ev ); + reset_draw_marker(); + ret++; + break; + } + } + } else { + tick_s = tick_f = (*i).get_timestamp(); + if ( tick_s >= a_tick_s - 16 && tick_f <= a_tick_f) + { + if ( a_action == e_select || a_action == e_select_one ) + { (*i).select( ); ret++; if ( a_action == e_select_one ) break; } - if ( a_action == e_is_selected ) { - if ( (*i).is_selected()) { + if ( a_action == e_is_selected ) + { + if ( (*i).is_selected()) + { ret = 1; break; } } - if ( a_action == e_would_select ) { + if ( a_action == e_would_select ) + { ret = 1; break; } + if ( a_action == e_deselect ) + { + ret = 0; + (*i).unselect(); + } + if ( a_action == e_toggle_selection ) + { + if ((*i).is_selected()) + { + (*i).unselect(); + ret ++; + } + else + { + (*i).select(); + ret ++; + } + } + if ( a_action == e_remove_one ) + { + remove( &(*i) ); + reset_draw_marker(); + ret++; + break; + } } - } + } } } @@ -914,7 +998,7 @@ sequence::select_note_events( long a_tic selected */ int sequence::select_events( long a_tick_s, long a_tick_f, - unsigned char a_status, + unsigned char a_status, unsigned char a_cc, select_action_e a_action) { int ret=0; @@ -957,6 +1041,28 @@ sequence::select_events( long a_tick_s, ret = 1; break; } + if ( a_action == e_toggle_selection ) + { + if ( (*i).is_selected()) + { + (*i).unselect( ); + } + else + { + (*i).select( ); + } + } + if ( a_action == e_deselect ) + { + (*i).unselect( ); + } + if ( a_action == e_remove_one ) + { + remove( &(*i) ); + reset_draw_marker(); + ret++; + break; + } } } } @@ -1243,22 +1349,22 @@ sequence::increment_selected( unsigned c list::iterator i; for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ - + if ( (*i).is_selected() && (*i).get_status() == a_status ){ - + if ( a_status == EVENT_NOTE_ON || a_status == EVENT_NOTE_OFF || a_status == EVENT_AFTERTOUCH || a_status == EVENT_CONTROL_CHANGE || a_status == EVENT_PITCH_WHEEL ){ - + (*i).increment_data2(); } - + if ( a_status == EVENT_PROGRAM_CHANGE || a_status == EVENT_CHANNEL_PRESSURE ){ - + (*i).increment_data1(); } } @@ -1276,25 +1382,25 @@ sequence::decrement_selected(unsigned ch list::iterator i; for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ - + if ( (*i).is_selected() && (*i).get_status() == a_status ){ - + if ( a_status == EVENT_NOTE_ON || a_status == EVENT_NOTE_OFF || a_status == EVENT_AFTERTOUCH || a_status == EVENT_CONTROL_CHANGE || a_status == EVENT_PITCH_WHEEL ){ - + (*i).decrement_data2(); } - + if ( a_status == EVENT_PROGRAM_CHANGE || a_status == EVENT_CHANNEL_PRESSURE ){ - + (*i).decrement_data1(); } - + } } @@ -1345,7 +1451,7 @@ sequence::paste_selected( long a_tick, i if ((*clipboard.begin()).is_note_on() || (*clipboard.begin()).is_note_off() ){ - + for ( i = clipboard.begin(); i != clipboard.end(); i++ ) if ( (*i).get_note( ) > highest_note ) highest_note = (*i).get_note(); @@ -1390,7 +1496,7 @@ sequence::change_event_data_range( long for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ /* initially false */ - bool set = false; + bool set = false; (*i).get_data( &d0, &d1 ); /* correct status and not CC */ @@ -1465,7 +1571,7 @@ sequence::change_event_data_range( long d1 = newdata; (*i).set_data( d0, d1 ); - } + } } unlock(); @@ -1481,6 +1587,7 @@ sequence::add_note( long a_tick, long a_ lock(); event e; + bool ignore = false; if ( a_tick >= 0 && a_note >= 0 && @@ -1498,6 +1605,12 @@ sequence::add_note( long a_tick, long a_ (*i).is_note_on() && (*i).get_timestamp() == a_tick ) { + if ((*i).get_note() == a_note ) + { + ignore = true; + break; + } + (*i).mark(); if ( (*i).is_linked()) @@ -1512,6 +1625,8 @@ sequence::add_note( long a_tick, long a_ remove_marked(); } + if ( !ignore ) + { if ( a_paint ) e.paint(); @@ -1528,6 +1643,7 @@ sequence::add_note( long a_tick, long a_ add_event( &e ); } + } verify_and_link(); unlock(); @@ -1599,7 +1715,7 @@ sequence::stream_event( event *a_ev ) a_ev->mod_timestamp( m_length ); if ( m_recording ){ - + add_event( a_ev ); set_dirty(); } @@ -1613,10 +1729,10 @@ sequence::stream_event( event *a_ev ) if ( m_quanized_rec ){ if (a_ev->is_note_off()) { - select_note_events( a_ev->get_timestamp(), a_ev->get_note(), + select_note_events( a_ev->get_timestamp(), a_ev->get_note(), a_ev->get_timestamp(), a_ev->get_note(), e_select); quanize_events( EVENT_NOTE_ON, 0, m_snap_tick, 1 , true ); - + } } /* update view */ @@ -1818,6 +1934,89 @@ sequence::add_trigger( long a_tick, long unlock(); } +bool sequence::intersectTriggers( long position, long& start, long& end ) +{ + lock(); + + list::iterator i = m_list_trigger.begin(); + while ( i != m_list_trigger.end() ) + { + if ((*i).m_tick_start <= position && position <= (*i).m_tick_end) + { + start = (*i).m_tick_start; + end = (*i).m_tick_end; + unlock(); + return true; + } + ++i; + } + + unlock(); + return false; +} + +bool sequence::intersectNotes( long position, long position_note, long& start, long& end, long& note ) +{ + lock(); + + list::iterator on = m_list_event.begin(); + list::iterator off = m_list_event.begin(); + while ( on != m_list_event.end() ) + { + if (position_note == (*on).get_note() && + (*on).is_note_on()) + { + // find next "off" event for the note + off = on; ++off; + while (off != m_list_event.end() && + ((*on).get_note() != (*off).get_note() || (*off).is_note_on())) + { + ++off; + } + if ((*on).get_note() == (*off).get_note() && (*off).is_note_off() && + (*on).get_timestamp() <= position && position <= (*off).get_timestamp()) + { + start = (*on).get_timestamp(); + end = (*off).get_timestamp(); + note = (*on).get_note(); + unlock(); + return true; + } + + + } + ++on; + } + + unlock(); + return false; +} + +bool sequence::intersectEvents( long posstart, long posend, long status, long& start ) +{ + lock(); + + list::iterator on = m_list_event.begin(); + while ( on != m_list_event.end() ) + { + //printf( "intersect looking for:%ld found:%ld\n", status, (*on).get_status() ); + if (status == (*on).get_status()) + { + if ((*on).get_timestamp() <= posstart && posstart <= ((*on).get_timestamp()+(posend-posstart))) + { + start = (*on).get_timestamp(); + unlock(); + return true; + } + } + ++on; + } + + unlock(); + return false; +} + + void sequence::grow_trigger (long a_tick_from, long a_tick_to, long a_length) { @@ -2020,7 +2219,7 @@ L R lock(); move_triggers( a_start_tick, - a_distance, + a_distance, true ); list::iterator i = m_list_trigger.begin(); @@ -2098,7 +2297,7 @@ sequence::split_trigger( long a_tick ) void sequence::move_triggers( long a_start_tick, - long a_distance, + long a_distance, bool a_direction ) { @@ -2607,28 +2806,28 @@ sequence::get_next_note_event( long *a_t (*m_iterator_draw).is_linked() ){ *a_tick_f = (*m_iterator_draw).get_linked()->get_timestamp(); - + ret = DRAW_NORMAL_LINKED; m_iterator_draw++; return ret; } - + else if( (*m_iterator_draw).is_note_on() && (! (*m_iterator_draw).is_linked()) ){ - + ret = DRAW_NOTE_ON; m_iterator_draw++; return ret; } - + else if( (*m_iterator_draw).is_note_off() && (! (*m_iterator_draw).is_linked()) ){ - + ret = DRAW_NOTE_OFF; m_iterator_draw++; return ret; } - + /* keep going until we hit null or find a NoteOn */ m_iterator_draw++; } @@ -2665,20 +2864,20 @@ sequence::get_next_event( unsigned char bool *a_selected ) { while ( m_iterator_draw != m_list_event.end() ){ - + /* note on, so its linked */ if( (*m_iterator_draw).get_status() == a_status ){ - + (*m_iterator_draw).get_data( a_D0, a_D1 ); *a_tick = (*m_iterator_draw).get_timestamp(); *a_selected = (*m_iterator_draw).is_selected(); - + /* either we have a control chage with the right CC or its a different type of event */ if ( (a_status == EVENT_CONTROL_CHANGE && *a_D0 == a_cc ) || (a_status != EVENT_CONTROL_CHANGE) ){ - + /* we have a good one */ /* update and return */ m_iterator_draw++; @@ -2713,7 +2912,7 @@ sequence::remove_all( void ) { lock(); - + m_list_event.clear(); @@ -2728,7 +2927,7 @@ sequence::operator= (const sequence& a_r /* dont copy to self */ if (this != &a_rhs){ - + m_list_event = a_rhs.m_list_event; m_list_trigger = a_rhs.m_list_trigger; @@ -2858,7 +3057,7 @@ sequence::set_playing( bool a_p ) { if (a_p){ - + /* turn on */ m_playing = true; @@ -3011,14 +3210,14 @@ sequence::print_triggers() void sequence::put_event_on_bus( event *a_e ) -{ +{ lock(); unsigned char note = a_e->get_note(); bool skip = false; - + if ( a_e->is_note_on() ){ - + m_playing_notes[note]++; } if ( a_e->is_note_off() ){ @@ -3028,7 +3227,7 @@ sequence::put_event_on_bus( event *a_e ) } else { m_playing_notes[note]--; - } + } } if ( !skip ){ @@ -3050,14 +3249,14 @@ sequence::off_playing_notes() event e; for ( int x=0; x< c_midi_notes; x++ ){ - + while( m_playing_notes[x] > 0 ){ - + e.set_status( EVENT_NOTE_OFF ); e.set_data( x, 0 ); - + m_masterbus->play( m_bus, &e, m_midi_channel ); - + m_playing_notes[x]--; } } @@ -3089,20 +3288,20 @@ sequence::select_events( unsigned char a for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ /* initially false */ - bool set = false; + bool set = false; (*i).get_data( &d0, &d1 ); - + /* correct status and not CC */ if ( a_status != EVENT_CONTROL_CHANGE && (*i).get_status() == a_status ) set = true; - + /* correct status and correct cc */ if ( a_status == EVENT_CONTROL_CHANGE && (*i).get_status() == a_status && d0 == a_cc ) set = true; - + if ( set ){ if ( a_inverse ){ @@ -3114,7 +3313,7 @@ sequence::select_events( unsigned char a } else (*i).select( ); - } + } } unlock(); @@ -3144,7 +3343,7 @@ sequence::transpose_notes( int a_steps, } for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ - + /* is it being moved ? */ if ( ((*i).get_status() == EVENT_NOTE_ON || (*i).get_status() == EVENT_NOTE_OFF) && @@ -3207,14 +3406,14 @@ sequence::quanize_events( unsigned char for ( i = m_list_event.begin(); i != m_list_event.end(); i++ ){ /* initially false */ - bool set = false; + bool set = false; (*i).get_data( &d0, &d1 ); - + /* correct status and not CC */ if ( a_status != EVENT_CONTROL_CHANGE && (*i).get_status() == a_status ) set = true; - + /* correct status and correct cc */ if ( a_status == EVENT_CONTROL_CHANGE && (*i).get_status() == a_status && @@ -3223,7 +3422,7 @@ sequence::quanize_events( unsigned char if( !(*i).is_marked() ) set = false; - + if ( set ){ /* copy event */ @@ -3244,7 +3443,7 @@ sequence::quanize_events( unsigned char if ((timestamp_delta + timestamp) >= m_length) { timestamp_delta = - e.get_timestamp() ; } - + e.set_timestamp( e.get_timestamp() + timestamp_delta ); quantized_events.push_front(e); @@ -3290,7 +3489,7 @@ addListVar( list *a_list, long a_v } while (true){ - + a_list->push_front( (char) buffer & 0xFF ); if (buffer & 0x80) @@ -3337,7 +3536,7 @@ sequence::fill_list( list *a_list, a_list->push_front( length ); for ( int i=0; i< length; i++ ) - a_list->push_front( m_name.c_str()[i] ); + a_list->push_front( m_name.c_str()[i] ); long timestamp = 0, delta_time = 0, prev_timestamp = 0; list::iterator i; @@ -3359,28 +3558,28 @@ sequence::fill_list( list *a_list, switch( e.m_status & 0xF0 ){ - case 0x80: + case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: - + a_list->push_front( e.m_data[0] ); a_list->push_front( e.m_data[1] ); //printf ( "- d[%2X %2X]\n" , e.m_data[0], e.m_data[1] ); break; - + case 0xC0: case 0xD0: - + a_list->push_front( e.m_data[0] ); //printf ( "- d[%2X]\n" , e.m_data[0] ); break; - + default: break; } diff -rupN seq24-rev48 adding win32/src/sequence.h seq24-rev48 win32 adding MouseInteraction/src/sequence.h --- seq24-rev48 adding win32/src/sequence.h 2009-05-20 20:30:47.906250000 -0500 +++ seq24-rev48 win32 adding MouseInteraction/src/sequence.h 2009-05-20 20:30:52.203125000 -0500 @@ -174,6 +174,9 @@ class sequence void split_trigger( trigger &trig, long a_split_tick); void adjust_trigger_offsets_to_legnth( long a_new_len ); long adjust_offset( long a_offset ); + void remove( list::iterator i ); + void remove( event* e ); + public: @@ -298,6 +301,11 @@ class sequence bool select_trigger(long a_tick); bool unselect_triggers (void); + bool intersectTriggers( long position, long& start, long& end ); + bool intersectNotes( long position, long position_note, long& start, long& end, long& note ); + bool intersectEvents( long posstart, long posend, long status, long& start ); + + void del_selected_trigger( void ); void cut_selected_trigger( void ); void copy_selected_trigger( void ); @@ -327,7 +335,10 @@ class sequence e_select, e_select_one, e_is_selected, - e_would_select + e_would_select, + e_deselect, // deselect under cursor + e_toggle_selection, // sel/deselect under cursor + e_remove_one // remove one note under cursor }; /* select note events in range, returns number