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<Gdk::GC> m_gc;
     Glib::RefPtr<Gdk::Window> 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<Gdk::Drawable> a_draw, int a_sequence );
     void draw_background_on( Glib::RefPtr<Gdk::Drawable> 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 <number>: 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, &note, 
-                            &tick_f, &note );
+                        /* get the box that selected elements are in */
+                        ths.m_seq->get_selected_box( &tick_s, &note,
+                                &tick_f, &note );
 
-                    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( &current_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, &note,
+                            &tick_f, &note );
+
+                    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<Gdk::GC> m_gc;
     Glib::RefPtr<Gdk::Window> 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, &note_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, &note_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, &note_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, &note_h, 
-                                &tick_f, &note_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, &note_h );
-
-                        m_growing = true;
-
-                        /* get the box that selected elements are in */
-                        m_seq->get_selected_box( &tick_s, &note_h, 
-                                    &tick_f, &note_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, &note_h );
-            convert_xy( x+w, y+h, &tick_f, &note_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, &note );
-	
-    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, &note );
-
-        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, &note_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, &note_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, &note_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, &note_h,
+                                &tick_f, &note_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, &note_h,
+                                    &tick_f, &note_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, &note_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, &current_tick, &current_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, &note_h );
+            ths.convert_xy( x+w, y+h, &tick_f, &note_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, &note );
+
+    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, &note );
+
+        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, &note );
+        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, &note_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, &note_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, &note_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, &note_h,
+                                &tick_f, &note_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, &note_h );
+
+                        ths.m_growing = true;
+
+                        /* get the box that selected elements are in */
+                        ths.m_seq->get_selected_box( &tick_s, &note_h,
+                                    &tick_f, &note_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, &note_h );
+            ths.convert_xy( x+w, y+h, &tick_f, &note_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, &note );
+
+    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, &note );
+
+        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<Gdk::GC> m_gc;
     Glib::RefPtr<Gdk::Window>   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<event>::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<event>::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<event>::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<event>::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<event>::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<event>::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<event>::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<trigger>::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<event>::iterator on = m_list_event.begin();
+    list<event>::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<event>::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<trigger>::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<char> *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<char> *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<event>::iterator i;
@@ -3359,28 +3558,28 @@ sequence::fill_list( list<char> *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<event>::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
