Restored pattern editor functionality.
[epichord.git] / src / pianoroll.cpp
blobc3317f76620c342b7771ab15619c7566e5b8d826
1 /*
2 Epichord - a midi sequencer
3 Copyright (C) 2008 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
23 #include <vector>
24 #include <fltk/Group.h>
25 #include <fltk/Widget.h>
26 #include <fltk/events.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include "ui.h"
32 #include "util.h"
34 #include "backend.h"
36 #include "uihelper.h"
38 extern UI* ui;
39 extern std::vector<track*> tracks;
41 extern struct conf config;
43 using namespace fltk;
45 #define SWAP(X,Y) tmp=X; X=Y; Y=tmp;
47 PianoRoll::PianoRoll(int x, int y, int w, int h, const char* label = 0) : fltk::Widget(x, y, w, h, label) {
48 wkeyh = 12;
49 bkeyh = 7;
50 cur_seqpat = NULL;
52 zoom = 15;
53 zoom_n = 3;
55 q_tick = 32;
57 box_flag = 0;
59 move_toffset = 0;
62 lresize_flag = 0;
63 rresize_flag = 0;
65 resize_arrow = 0;
66 resize_e = NULL;
67 resize_handle_width = 4;
69 fakeh = wkeyh*75;
70 fakehmin = wkeyh*75;
71 if(fakeh < h){fakeh = h;}
74 int PianoRoll::handle(int event){
75 Command* c;
76 pattern* p;
77 mevent* e;
79 int X = event_x();
80 int Y = event_y();
82 switch(event){
83 case fltk::ENTER:
84 return 1;
85 case fltk::FOCUS:
86 return 1;
87 case fltk::SHORTCUT:
88 if(event_key()==fltk::DeleteKey){
89 apply_delete();
90 delete_flag = 0;
91 redraw();
92 resize_arrow = 0;
93 ui->event_edit->redraw();
94 return 1;
96 if(event_state(CTRL) && event_key()=='c'){
97 //printf("roll copy\n");
98 return 1;
100 if(zoom_out_key(event_key(),event_state())){
101 if(zoom_n > 1){
102 zoom_n--;
103 set_zoom(30*(1<<zoom_n)/16);
104 ui->pattern_timeline->zoom = zoom;
105 ui->pattern_timeline->update(get_play_position());
106 ui->pattern_timeline->redraw();
107 ui->event_edit->zoom = zoom;
108 ui->event_edit->redraw();
110 redraw();
111 return 1;
113 if(zoom_in_key(event_key(),event_state())){
114 if(zoom_n < 8){
115 zoom_n++;
116 set_zoom(30*(1<<zoom_n)/16);
117 ui->pattern_timeline->zoom = zoom;
118 ui->pattern_timeline->update(get_play_position());
119 ui->pattern_timeline->redraw();
120 ui->event_edit->zoom = zoom;
121 ui->event_edit->redraw();
123 redraw();
124 return 1;
126 return 0;
127 case fltk::PUSH:
128 take_focus();
129 e = over_note();
130 if(event_button()==1){//left mouse
131 if(e==NULL){//new note init
132 if(event_state()&fltk::SHIFT){//begin box
133 box_flag = 1;
134 box_x1=X;
135 box_x2=X;
136 box_y1=Y;
137 box_y2=Y;
138 box_t1=xpix2tick(X+scrollx);
139 box_t2=box_t1;
140 box_n1=ypix2note(Y+scrolly,1);
141 box_n2=box_n1;
143 else{//begin insert
144 insert_flag = 1;
145 insert_torig = quantize(xpix2tick(X+scrollx));
146 insert_toffset = q_tick;
147 //new_orig_t = new_left_t;
148 insert_note = ypix2note(Y+scrolly,1);
150 last_note = insert_note;
151 if(config.playinsert){
152 ui->keyboard->play_note(last_note,0);
157 else{
159 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
160 unselect_all();
162 e->selected = 1;
163 resize_arrow_color = fltk::color(128,128,0);
165 if(over_rhandle(e)){//resize
166 rresize_flag = 1;
167 rresize_torig = e->tick+e->dur;
168 rresize_toffset = 0;
170 else if(over_lhandle(e)){//resize move
171 lresize_flag = 1;
172 lresize_torig = e->tick;
173 lresize_toffset = 0;
175 else{//begin move
176 move_flag = 1;
178 move_torig = e->tick;
179 move_qoffset = e->tick - quantize(e->tick);
181 move_toffset = -move_qoffset;
183 //move_offset = quantize(xpix2tick(X)) - move_torig - move_qoffset;
184 //move_toffset = 0;
185 move_offset = X - tick2xpix(e->tick);
186 move_norig = ypix2note(Y+scrolly,1);
187 move_noffset = 0;
189 last_note = move_norig;
190 if(config.playmove){
191 ui->keyboard->play_note(last_note,0);
196 else if(event_button()==2){//middle mouse
197 //button initiates paste
199 else if(event_button()==3){//right mouse
200 if(e==NULL){
201 unselect_all();
203 ui->event_edit->redraw();
205 else{//set up for deletion
206 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
207 unselect_all();
209 e->selected = 1;
210 delete_flag = 1;
211 resize_arrow_color = fltk::color(120,60,58);
215 redraw();
216 return 1;
217 case fltk::DRAG:
219 if(box_flag){
220 box_x2 = X;
221 box_y2 = Y;
222 box_t2 = xpix2tick(X+scrollx);
223 box_n2 = ypix2note(Y+scrolly,1);
225 else if(insert_flag){
226 insert_toffset = quantize(xpix2tick(X+scrollx)+q_tick) - insert_torig;
227 if(insert_toffset<=0){
228 insert_toffset -= q_tick;
230 insert_note = ypix2note(Y+scrolly,1);
231 if(insert_note != last_note){
232 if(config.playinsert){//play on insert
233 ui->keyboard->release_note(last_note,0);
234 ui->keyboard->play_note(insert_note,0);
236 last_note = insert_note;
239 else if(move_flag){
240 move_toffset = quantize(xpix2tick(X - move_offset)) - move_torig;
241 move_noffset = ypix2note(Y+scrolly,1) - move_norig;
242 int N = move_norig+move_noffset;
243 if(N != last_note){
244 if(config.playmove){//play on move
245 ui->keyboard->release_note(last_note,0);
246 ui->keyboard->play_note(N,0);
248 last_note = N;
251 else if(rresize_flag){
252 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_tick-rresize_torig;
254 else if(lresize_flag){
255 lresize_toffset = quantize(xpix2tick(X+scrollx)) - lresize_torig;
257 redraw();
258 return 1;
259 case fltk::RELEASE:
260 e = over_note();
261 if(event_button()==1){
262 if(box_flag){
263 apply_box();
264 ui->event_edit->redraw();
265 box_flag=0;
267 else if(rresize_flag){
268 apply_rresize();
269 rresize_flag = 0;
270 resize_arrow = 0;
271 ui->event_edit->redraw();
273 else if(lresize_flag){
274 apply_lresize();
275 lresize_flag = 0;
276 resize_arrow = 0;
277 ui->event_edit->redraw();
279 else if(insert_flag){
280 apply_insert();
282 insert_flag = 0;
284 ui->keyboard->release_note(insert_note,0);
285 ui->keyboard->redraw();
286 ui->event_edit->has[0]=1;
287 ui->event_edit->has[1]=1;
288 ui->event_edit->redraw();
289 ui->event_menu->redraw();
291 else if(move_flag){
292 apply_move();
293 move_flag = 0;
295 midi_track_off(cur_seqpat->track);
296 ui->keyboard->release_note(last_note,0);
297 ui->keyboard->release_note(move_norig+move_noffset,0);
298 ui->keyboard->redraw();
299 ui->event_edit->redraw();
301 insert_flag=0;
302 move_flag=0;
304 if(event_button()==3){
305 mevent* over_n = over_note();
306 if(delete_flag && over_n){
307 if(over_n->selected){
308 apply_delete();
309 midi_track_off(cur_seqpat->track);
310 ui->event_edit->redraw();
313 delete_flag=0;
314 resize_arrow = 0;
316 redraw();
318 return 1;
320 case fltk::MOVE:
321 e = over_note();
322 if(e){
323 if(over_rhandle(e)){
324 if(resize_e != e || resize_arrow != 1){
325 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
326 else{resize_arrow_color = fltk::color(95,58,119);}
327 resize_e = e;
328 resize_arrow = 1;
329 resize_x = tick2xpix(e->tick + e->dur)-scrollx-resize_handle_width;
330 resize_y = note2ypix(e->value1)-scrolly;
331 redraw();
334 else if(over_lhandle(e)){
335 if(resize_e != e || resize_arrow != 1){
336 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
337 else{resize_arrow_color = fltk::color(95,58,119);}
338 resize_e = e;
339 resize_arrow = -1;
340 resize_x = tick2xpix(e->tick)+1 - scrollx;
341 resize_y = note2ypix(e->value1) - scrolly;
342 redraw();
345 else{
346 if(resize_e != e || resize_arrow != 0){
347 resize_e = e;
348 resize_arrow = 0;
349 redraw();
353 else{
354 if(resize_arrow != 0){
355 resize_arrow = 0;
356 redraw();
360 return 1;
362 return 0;
365 void PianoRoll::draw(){
367 fltk::push_clip(0,0,w(),h());
369 fltk::setcolor(fltk::GRAY05);
370 fltk::fillrect(0,0,w(),h());
372 fltk::setcolor(fltk::GRAY20);
373 for(int i=12-scrolly; i<h(); i+=12){
374 if(i>=0){
375 fltk::fillrect(0,i,w(),1);
378 for(int i=zoom-scrollx; i<w(); i+=zoom){
379 if(i>=0){
380 fltk::fillrect(i,0,1,h());
384 fltk::setcolor(fltk::GRAY30);
385 for(int i=12*5-scrolly; i<h(); i+=12*7){
386 if(i>=0){
387 fltk::fillrect(0,i,w(),1);
391 fltk::setcolor(fltk::GRAY50);
392 for(int i=zoom*4-scrollx; i<w(); i+=zoom*4){
393 if(i>=0){
394 fltk::fillrect(i,0,1,h());
398 fltk::setcolor(fltk::WHITE);
399 int M = config.beats_per_measure;
400 for(int i=zoom*4*M-scrollx; i<w(); i+=zoom*4*M){
401 if(i>=0){
402 fltk::fillrect(i,0,1,h());
406 fltk::setcolor(fltk::color(128,0,0));
407 int rightend = tick2xpix(cur_seqpat->dur)-scrollx;
408 if(rightend >=0 && rightend < w()){
409 fltk::fillrect(rightend,0,1,h());
412 fltk::setcolor(fltk::color(128,128,0));
413 fltk::fillrect(0,12*40-scrolly,w(),1);
415 int tmp;
416 if(insert_flag){
417 fltk::setcolor(fltk::BLUE);
418 int T1 = insert_torig;
419 int T2 = T1 + insert_toffset;
420 if(T1>T2){SWAP(T1,T2);}
421 int X = tick2xpix(T1)+1 - scrollx;
422 int Y = note2ypix(insert_note) - scrolly;
423 int W = tick2xpix(T2)-scrollx - X;
424 fltk::fillrect(X,Y,W,11);
427 if(move_flag){
428 fltk::setcolor(fltk::MAGENTA);
429 mevent* ptr = cur_seqpat->p->events->next;
430 while(ptr){
431 if(ptr->type == MIDI_NOTE_ON && ptr->selected){
432 int X = tick2xpix(ptr->tick+move_toffset)+1-scrollx;
433 int Y = note2ypix(ptr->value1+move_noffset)-scrolly;
434 int W = tick2xpix(ptr->dur);
435 fltk::fillrect(X,Y,W-1,1);
436 fltk::fillrect(X,Y+11,W-1,1);
437 fltk::fillrect(X,Y,1,11);
438 fltk::fillrect(X+W-2,Y,1,11);
440 ptr=ptr->next;
446 //draw all notes
447 mevent* e = cur_seqpat->p->events->next;
449 fltk::Color c1,c2,c3;
451 while(e){
452 if(e->type == MIDI_NOTE_ON){
453 //fltk::fillrect(tick2xpix(e->tick),note2ypix(e->value),e->dur,11);
455 int R1 = rresize_flag&&e->selected ? rresize_toffset : 0;
456 int R2 = lresize_flag&&e->selected ? lresize_toffset : 0;
458 int T1 = e->tick + R2;
459 int T2 = e->tick+e->dur + R1;
461 if(T1 >= T2-q_tick && e->selected){
462 if(rresize_flag){
463 T1 = e->tick;
464 T2 = T1 + q_tick;
466 else if(lresize_flag){
467 T2 = e->tick + e->dur;
468 T1 = T2 - q_tick;
472 int X = tick2xpix(T1) + 1 - scrollx;
473 int Y = note2ypix(e->value1) - scrolly;
475 int W = tick2xpix(T2)-scrollx - X;
476 get_event_color(e,&c1,&c2,&c3);
478 fltk::setcolor(c1);
479 fltk::fillrect(X+1,Y+1,W-1,10);
481 fltk::setcolor(c2);
482 fltk::fillrect(X,Y+11,W,1);
483 fltk::fillrect(X+W-1,Y+1,1,11);
485 fltk::setcolor(c3);
486 fltk::fillrect(X,Y,W,1);
487 fltk::fillrect(X,Y,1,11);
489 e=e->next;
493 if(!rresize_flag && !lresize_flag){
494 if(resize_arrow > 0){
495 setcolor(resize_arrow_color);
497 int W = resize_handle_width;
498 int H = 12;
499 int X = resize_x;
500 int Y = resize_y;
502 addvertex(X,Y);
503 addvertex(X,Y+H);
504 addvertex(X+W,Y+H/2);
505 fillpath();
507 else if(resize_arrow < 0){
508 setcolor(resize_arrow_color);
510 int W = resize_handle_width;
511 int H = 12;
512 int X = resize_x;
513 int Y = resize_y;
515 addvertex(X+W,Y);
516 addvertex(X+W,Y+H);
517 addvertex(X,Y+H/2);
518 fillpath();
523 if(box_flag){
524 fltk::setcolor(fltk::GREEN);
525 int X1,X2,Y1,Y2;
526 if(box_x1>box_x2){
527 X1=box_x2;
528 X2=box_x1;
530 else{
531 X1=box_x1;
532 X2=box_x2;
534 if(box_y1>box_y2){
535 Y1=box_y2;
536 Y2=box_y1;
538 else{
539 Y1=box_y1;
540 Y2=box_y2;
542 fltk::fillrect(X1,Y1,X2-X1,1);
543 fltk::fillrect(X1,Y1,1,Y2-Y1);
544 fltk::fillrect(X2,Y1,1,Y2-Y1);
545 fltk::fillrect(X1,Y2,X2-X1,1);
548 fltk::pop_clip();
554 void PianoRoll::scrollTo(int X, int Y){
555 scrollx = X;
556 scrolly = Y;
557 redraw();
558 ui->pattern_timeline->scroll = X;
559 ui->pattern_timeline->redraw();
560 ui->event_edit->scroll = X;
561 ui->event_edit->redraw();
562 ui->keyboard->scroll = Y;
563 ui->keyboard->redraw();
568 void PianoRoll::load(seqpat* s){
570 //ui->pattern_scroll->scrollTo(0,300);
572 cur_seqpat = s;
573 cur_track = tracks[s->track];
574 int W = tick2xpix(s->dur);
575 resize(W+300,h());
577 ui->pattern_timeline->ticks_offset = s->tick;
582 int PianoRoll::note2ypix(int note){
583 int udy = 6*(note + (note+7)/12 + note/12) + 12;
584 return 900 - udy + 1;
587 int PianoRoll::tick2xpix(int tick){
588 return tick*zoom*4 / 128;
591 int PianoRoll::xpix2tick(int xpix){
592 return xpix*128 / (zoom*4);
595 int PianoRoll::quantize(int tick){
596 return tick/q_tick * q_tick;
600 void PianoRoll::set_zoom(int z){
601 zoom = z;
602 relayout();
603 //int W = tick2xpix(cur_seqpat->dur);
604 //resize(W+300,h());
608 mevent* PianoRoll::over_note(){
609 mevent* e = cur_seqpat->p->events->next;
611 int X = event_x()+scrollx;
612 int Y = event_y()+scrolly;
614 int cy, lx, rx;
615 while(e){
616 if(e->type == MIDI_NOTE_ON){
617 cy = note2ypix(e->value1);
618 lx = tick2xpix(e->tick);
619 rx = tick2xpix(e->tick+e->dur);
620 if(X > lx && X < rx &&
621 Y < cy+12 && Y > cy){
622 return e;
625 e = e->next;
628 return NULL;
633 void PianoRoll::update(int pos){
634 if(!is_backend_playing() || !cur_seqpat){
635 return;
637 int X1 = tick2xpix(pos-cur_seqpat->tick);
638 int X2 = X1 - scrollx;
639 if(X2 < 0){
640 scrollTo(X1-50<0?0:X1-50,scrolly);
642 if(X2 > w()-30){
643 scrollTo(X1-50,scrolly);
648 void PianoRoll::unselect_all(){
649 mevent* e = cur_seqpat->p->events;
650 while(e){
651 if(e->type == MIDI_NOTE_ON && e->selected==1){
652 e->selected = 0;
654 e = e->next;
660 void PianoRoll::get_event_color(mevent* e, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3){
662 int T1,T2;
663 int tmp;
664 if(delete_flag){
665 if(e->selected){
666 *c1 = fltk::color(229,79,75);
667 *c2 = fltk::color(120,60,58);
668 *c3 = fltk::color(225,131,109);
669 return;
673 if(box_flag){
674 T1=box_t1;
675 T2=box_t2;
676 int N1 = box_n1;
677 int N2 = box_n2;
678 int N = e->value1;
679 if(T1>T2){SWAP(T1,T2);}
680 if(N1<N2){SWAP(N1,N2);}
681 if(e->tick+e->dur > T1 && e->tick < T2 && N >= N2 && N <= N1){
682 *c1 = fltk::color(108,229,75);
683 *c2 = fltk::color(71,120,59);
684 *c3 = fltk::color(108,229,75);
685 return;
689 if(e->selected){
690 *c1 = fltk::color(255,248,47);
691 *c2 = fltk::color(140,137,46);
692 *c3 = fltk::color(232,255,37);
693 return;
696 *c1 = fltk::color(169,75,229);
697 *c2 = fltk::color(95,58,119);
698 *c3 = fltk::color(198,109,225);
702 void PianoRoll::apply_box(){
703 mevent* e = cur_seqpat->p->events->next;
704 int tmp;
705 int T1=box_t1;
706 int T2=box_t2;
707 int N1 = box_n1;
708 int N2 = box_n2;
710 if(T1>T2){SWAP(T1,T2);}
711 if(N1<N2){SWAP(N1,N2);}
712 while(e){
713 int N = e->value1;
714 if(e->type == MIDI_NOTE_ON &&
715 e->tick+e->dur > T1 && e->tick < T2 &&
716 N >= N2 && N <= N1){
717 e->selected = 1;
719 e = e->next;
723 void PianoRoll::apply_insert(){
724 if(insert_note > 127 || insert_note < 0){
725 return;
728 int tmp;
729 int T1 = insert_torig;
730 int T2 = T1 + insert_toffset;
731 if(T1>T2){SWAP(T1,T2);}
733 if(T1 < 0){
734 return;
737 pattern* p = cur_seqpat->p;
738 Command* c=new CreateNote(p,insert_note,config.defaultvelocity,T1,T2-T1);
739 set_undo(c);
740 undo_push(1);
742 cur_track->restate();
745 void PianoRoll::apply_delete(){
746 Command* c;
747 mevent* e;
748 mevent* next;
749 pattern* p = cur_seqpat->p;
750 int N=0;
752 e = cur_seqpat->p->events->next;
753 while(e){
754 next = e->next;
755 if(e->selected && e->type == MIDI_NOTE_ON){
756 c=new DeleteNote(p,e);
757 set_undo(c);
758 N++;
760 e = next;
762 undo_push(N);
764 cur_track->restate();
767 void PianoRoll::apply_move(){
768 if(move_toffset==0 && move_noffset==0){
769 return;
772 pattern* p = cur_seqpat->p;
773 mevent* e = p->events->next;
774 while(e){
775 int K = e->value1+move_noffset;
776 int T = e->tick+move_toffset;
777 if(e->type == MIDI_NOTE_ON && e->selected && (T<0 || K < 0 || K > 127)){
778 return;
780 e = e->next;
784 Command* c;
785 e = p->events->next;
787 mevent* next;
788 int M=0;
789 for(int i=0; i<tracks.size(); i++){
790 e = p->events->next;
791 while(e){
792 next = e->next;
793 if(e->selected && e->modified == 0){
794 int K = e->value1 + move_noffset;
795 int T = e->tick + move_toffset;
796 e->modified = 1;
797 c=new MoveNote(p,e,T,K);
798 set_undo(c);
799 M++;
801 e = next;
804 undo_push(M);
806 e = p->events->next;
807 while(e){
808 if(e->modified){e->modified=0;}
809 e = e->next;
812 cur_track->restate();
815 void PianoRoll::apply_paste(){
821 void PianoRoll::apply_rresize(){
822 if(rresize_toffset==0){
823 return;
826 Command* c;
827 mevent* e;
828 mevent* next;
829 pattern* p = cur_seqpat->p;
830 int tmp;
831 int N=0;
833 e = p->events->next;
834 while(e){
835 next = e->next;
836 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
837 e->modified = 1;
838 int W = e->dur;
839 int R = rresize_toffset;
840 if(W+R < q_tick){
841 R = q_tick-W;
843 c=new ResizeNote(p,e,W+R);
844 set_undo(c);
845 N++;
847 e = next;
850 e = p->events->next;
851 while(e){
852 if(e->modified){e->modified=0;}
853 e = e->next;
856 cur_track->restate();
857 undo_push(N);
860 void PianoRoll::apply_lresize(){
861 if(lresize_toffset==0){
862 return;
865 Command* c;
866 mevent* e;
867 mevent* next;
868 pattern* p = cur_seqpat->p;
869 int tmp;
870 int N=0;
872 e = p->events->next;
873 while(e){
874 if(e->type == MIDI_NOTE_ON && e->selected){
875 if(e->tick + lresize_toffset < 0){
876 return;
879 e = e->next;
882 e = p->events->next;
883 while(e){
884 next = e->next;
885 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
886 e->modified = 1;
887 int T = e->tick;
888 int W = e->dur;
889 int R = lresize_toffset;
891 if(R > W-q_tick){
892 R = W-q_tick;
895 mevent* etmp = e->prev;
896 c=new ResizeNote(p,e,W-R);
897 set_undo(c);
899 e = etmp->next;
900 c=new MoveNote(p,e,T+R,e->value1);
901 set_undo(c);
903 N+=2;
905 e = next;
908 e = p->events->next;
909 while(e){
910 if(e->modified){e->modified=0;}
911 e = e->next;
914 cur_track->restate();
915 undo_push(N);
926 int PianoRoll::over_rhandle(mevent* e){
927 int X = event_x()+scrollx;
928 int Y = event_y()+scrolly;
929 int X1 = tick2xpix(e->tick);
930 int X2 = X1 + tick2xpix(e->dur);
931 int Y1 = note2ypix(e->value1);
932 int Y2 = Y1 + 12;
934 if(X2-X1 < resize_handle_width*3){
935 return 0;
938 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - resize_handle_width);
941 int PianoRoll::over_lhandle(mevent* e){
942 int X = event_x()+scrollx;
943 int Y = event_y()+scrolly;
944 int X1 = tick2xpix(e->tick);
945 int X2 = X1 + tick2xpix(e->dur);
946 int Y1 = note2ypix(e->value1);
947 int Y2 = Y1 + 12;
949 if(X2-X1 < resize_handle_width*3){
950 return 0;
953 return (Y > Y1 && Y < Y2 && X < X1+ resize_handle_width +1 && X > X1 + 1);