Improved drawing performance.
[epichord.git] / src / pianoroll.cpp
blob657f144897a278431c0f817b7ad9ed7ee05edc6a
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>
27 #include <fltk/Scrollbar.h>
29 #include <fltk/events.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include "ui.h"
35 #include "util.h"
37 #include "backend.h"
39 #include "uihelper.h"
41 extern UI* ui;
42 extern std::vector<track*> tracks;
44 extern struct conf config;
46 using namespace fltk;
48 #define SWAP(X,Y) tmp=X; X=Y; Y=tmp;
50 PianoRoll::PianoRoll(int x, int y, int w, int h, const char* label = 0) : fltk::Widget(x, y, w, h, label) {
51 wkeyh = 12;
52 bkeyh = 7;
53 cur_seqpat = NULL;
55 zoom = 15;
56 zoom_n = 3;
58 q_tick = 32;
60 box_flag = 0;
62 move_toffset = 0;
65 lresize_flag = 0;
66 rresize_flag = 0;
68 resize_arrow = 0;
69 resize_e = NULL;
70 resize_handle_width = 4;
72 fakeh = wkeyh*75;
73 fakehmin = wkeyh*75;
74 if(fakeh < h){fakeh = h;}
76 scrollx=0;
77 scrolly=0;
80 int PianoRoll::handle(int event){
81 Command* c;
82 pattern* p;
83 mevent* e;
85 int X = event_x();
86 int Y = event_y();
88 switch(event){
89 case fltk::ENTER:
90 return 1;
91 case fltk::FOCUS:
92 return 1;
93 case fltk::SHORTCUT:
94 if(event_key()==fltk::DeleteKey){
95 apply_delete();
96 delete_flag = 0;
97 redraw();
98 resize_arrow = 0;
99 ui->event_edit->redraw();
100 return 1;
102 if(event_state(CTRL) && event_key()=='c'){
103 //printf("roll copy\n");
104 return 1;
106 if(zoom_out_key(event_key(),event_state())){
107 if(zoom_n > 1){
108 zoom_n--;
109 set_zoom(30*(1<<zoom_n)/16);
110 ui->pattern_timeline->zoom = zoom;
111 ui->pattern_timeline->update(get_play_position());
112 ui->pattern_timeline->redraw();
113 ui->event_edit->zoom = zoom;
114 ui->event_edit->redraw();
116 redraw();
117 return 1;
119 if(zoom_in_key(event_key(),event_state())){
120 if(zoom_n < 8){
121 zoom_n++;
122 set_zoom(30*(1<<zoom_n)/16);
123 ui->pattern_timeline->zoom = zoom;
124 ui->pattern_timeline->update(get_play_position());
125 ui->pattern_timeline->redraw();
126 ui->event_edit->zoom = zoom;
127 ui->event_edit->redraw();
129 redraw();
130 return 1;
132 return 0;
133 case fltk::PUSH:
134 take_focus();
135 e = over_note();
136 if(event_button()==1){//left mouse
137 if(e==NULL){//new note init
138 if(event_state()&fltk::SHIFT){//begin box
139 box_flag = 1;
140 box_x1=X;
141 box_x2=X;
142 box_y1=Y;
143 box_y2=Y;
144 box_t1=xpix2tick(X+scrollx);
145 box_t2=box_t1;
146 box_n1=ypix2note(Y+scrolly,1);
147 box_n2=box_n1;
149 else{//begin insert
150 insert_flag = 1;
151 insert_torig = quantize(xpix2tick(X+scrollx));
152 insert_toffset = q_tick;
153 //new_orig_t = new_left_t;
154 insert_note = ypix2note(Y+scrolly,1);
156 last_note = insert_note;
157 if(config.playinsert){
158 ui->keyboard->play_note(last_note,0);
163 else{
165 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
166 unselect_all();
168 e->selected = 1;
169 resize_arrow_color = fltk::color(128,128,0);
171 if(over_rhandle(e)){//resize
172 rresize_flag = 1;
173 rresize_torig = e->tick+e->dur;
174 rresize_toffset = 0;
176 else if(over_lhandle(e)){//resize move
177 lresize_flag = 1;
178 lresize_torig = e->tick;
179 lresize_toffset = 0;
181 else{//begin move
182 move_flag = 1;
184 move_torig = e->tick;
185 move_qoffset = e->tick - quantize(e->tick);
187 move_toffset = -move_qoffset;
189 //move_offset = quantize(xpix2tick(X)) - move_torig - move_qoffset;
190 //move_toffset = 0;
191 move_offset = X - tick2xpix(e->tick);
192 move_norig = ypix2note(Y+scrolly,1);
193 move_noffset = 0;
195 last_note = move_norig;
196 if(config.playmove){
197 ui->keyboard->play_note(last_note,0);
202 else if(event_button()==2){//middle mouse
203 //button initiates paste
205 else if(event_button()==3){//right mouse
206 if(e==NULL){
207 unselect_all();
209 ui->event_edit->redraw();
211 else{//set up for deletion
212 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
213 unselect_all();
215 e->selected = 1;
216 delete_flag = 1;
217 resize_arrow_color = fltk::color(120,60,58);
221 redraw();
222 return 1;
223 case fltk::DRAG:
225 if(box_flag){
226 box_x2 = X;
227 box_y2 = Y;
228 box_t2 = xpix2tick(X+scrollx);
229 box_n2 = ypix2note(Y+scrolly,1);
231 else if(insert_flag){
232 insert_toffset = quantize(xpix2tick(X+scrollx)+q_tick) - insert_torig;
233 if(insert_toffset<=0){
234 insert_toffset -= q_tick;
236 insert_note = ypix2note(Y+scrolly,1);
237 if(insert_note != last_note){
238 if(config.playinsert){//play on insert
239 ui->keyboard->release_note(last_note,0);
240 ui->keyboard->play_note(insert_note,0);
242 last_note = insert_note;
245 else if(move_flag){
246 move_toffset = quantize(xpix2tick(X - move_offset)) - move_torig;
247 move_noffset = ypix2note(Y+scrolly,1) - move_norig;
248 int N = move_norig+move_noffset;
249 if(N != last_note){
250 if(config.playmove){//play on move
251 ui->keyboard->release_note(last_note,0);
252 ui->keyboard->play_note(N,0);
254 last_note = N;
257 else if(rresize_flag){
258 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_tick-rresize_torig;
260 else if(lresize_flag){
261 lresize_toffset = quantize(xpix2tick(X+scrollx)) - lresize_torig;
263 redraw();
264 return 1;
265 case fltk::RELEASE:
266 e = over_note();
267 if(event_button()==1){
268 if(box_flag){
269 apply_box();
270 ui->event_edit->redraw();
271 box_flag=0;
273 else if(rresize_flag){
274 apply_rresize();
275 rresize_flag = 0;
276 resize_arrow = 0;
277 ui->event_edit->redraw();
279 else if(lresize_flag){
280 apply_lresize();
281 lresize_flag = 0;
282 resize_arrow = 0;
283 ui->event_edit->redraw();
285 else if(insert_flag){
286 apply_insert();
288 insert_flag = 0;
290 ui->keyboard->release_note(insert_note,0);
291 ui->keyboard->redraw();
292 ui->event_edit->has[0]=1;
293 ui->event_edit->has[1]=1;
294 ui->event_edit->redraw();
295 ui->event_menu->redraw();
297 else if(move_flag){
298 apply_move();
299 move_flag = 0;
301 midi_track_off(cur_seqpat->track);
302 ui->keyboard->release_note(last_note,0);
303 ui->keyboard->release_note(move_norig+move_noffset,0);
304 ui->keyboard->redraw();
305 ui->event_edit->redraw();
307 insert_flag=0;
308 move_flag=0;
310 if(event_button()==3){
311 mevent* over_n = over_note();
312 if(delete_flag && over_n){
313 if(over_n->selected){
314 apply_delete();
315 midi_track_off(cur_seqpat->track);
316 ui->event_edit->redraw();
319 delete_flag=0;
320 resize_arrow = 0;
322 redraw();
324 return 1;
326 case fltk::MOVE:
327 e = over_note();
328 if(e){
329 if(over_rhandle(e)){
330 if(resize_e != e || resize_arrow != 1){
331 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
332 else{resize_arrow_color = fltk::color(95,58,119);}
333 resize_e = e;
334 resize_arrow = 1;
335 resize_x = tick2xpix(e->tick + e->dur)-scrollx-resize_handle_width;
336 resize_y = note2ypix(e->value1)-scrolly;
337 redraw();
340 else if(over_lhandle(e)){
341 if(resize_e != e || resize_arrow != 1){
342 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
343 else{resize_arrow_color = fltk::color(95,58,119);}
344 resize_e = e;
345 resize_arrow = -1;
346 resize_x = tick2xpix(e->tick)+1 - scrollx;
347 resize_y = note2ypix(e->value1) - scrolly;
348 redraw();
351 else{
352 if(resize_e != e || resize_arrow != 0){
353 resize_e = e;
354 resize_arrow = 0;
355 redraw();
359 else{
360 if(resize_arrow != 0){
361 resize_arrow = 0;
362 redraw();
366 return 1;
368 return 0;
371 void PianoRoll::draw(){
373 fltk::push_clip(0,0,w(),h());
375 fltk::setcolor(fltk::GRAY05);
376 fltk::fillrect(0,0,w(),h());
378 fltk::setcolor(fltk::GRAY20);
379 for(int i=12-scrolly; i<h(); i+=12){
380 if(i>=0){
381 fltk::fillrect(0,i,w(),1);
384 for(int i=zoom-scrollx; i<w(); i+=zoom){
385 if(i>=0){
386 fltk::fillrect(i,0,1,h());
390 fltk::setcolor(fltk::GRAY30);
391 for(int i=12*5-scrolly; i<h(); i+=12*7){
392 if(i>=0){
393 fltk::fillrect(0,i,w(),1);
397 fltk::setcolor(fltk::GRAY50);
398 for(int i=zoom*4-scrollx; i<w(); i+=zoom*4){
399 if(i>=0){
400 fltk::fillrect(i,0,1,h());
404 fltk::setcolor(fltk::WHITE);
405 int M = config.beats_per_measure;
406 for(int i=zoom*4*M-scrollx; i<w(); i+=zoom*4*M){
407 if(i>=0){
408 fltk::fillrect(i,0,1,h());
412 fltk::setcolor(fltk::color(128,0,0));
413 int rightend = tick2xpix(cur_seqpat->dur)-scrollx;
414 if(rightend >=0 && rightend < w()){
415 fltk::fillrect(rightend,0,1,h());
418 fltk::setcolor(fltk::color(128,128,0));
419 fltk::fillrect(0,12*40-scrolly,w(),1);
421 int tmp;
422 if(insert_flag){
423 fltk::setcolor(fltk::BLUE);
424 int T1 = insert_torig;
425 int T2 = T1 + insert_toffset;
426 if(T1>T2){SWAP(T1,T2);}
427 int X = tick2xpix(T1)+1 - scrollx;
428 int Y = note2ypix(insert_note) - scrolly;
429 int W = tick2xpix(T2)-scrollx - X;
430 fltk::fillrect(X,Y,W,11);
433 if(move_flag){
434 fltk::setcolor(fltk::MAGENTA);
435 mevent* ptr = cur_seqpat->p->events->next;
436 while(ptr){
437 if(ptr->type == MIDI_NOTE_ON && ptr->selected){
438 int X = tick2xpix(ptr->tick+move_toffset)+1-scrollx;
439 int Y = note2ypix(ptr->value1+move_noffset)-scrolly;
440 int W = tick2xpix(ptr->dur);
441 fltk::fillrect(X,Y,W-1,1);
442 fltk::fillrect(X,Y+11,W-1,1);
443 fltk::fillrect(X,Y,1,11);
444 fltk::fillrect(X+W-2,Y,1,11);
446 ptr=ptr->next;
452 //draw all notes
453 mevent* e = cur_seqpat->p->events->next;
455 fltk::Color c1,c2,c3;
457 while(e){
458 if(e->type == MIDI_NOTE_ON){
459 //fltk::fillrect(tick2xpix(e->tick),note2ypix(e->value),e->dur,11);
461 int R1 = rresize_flag&&e->selected ? rresize_toffset : 0;
462 int R2 = lresize_flag&&e->selected ? lresize_toffset : 0;
464 int T1 = e->tick + R2;
465 int T2 = e->tick+e->dur + R1;
467 if(T1 >= T2-q_tick && e->selected){
468 if(rresize_flag){
469 T1 = e->tick;
470 T2 = T1 + q_tick;
472 else if(lresize_flag){
473 T2 = e->tick + e->dur;
474 T1 = T2 - q_tick;
478 int X = tick2xpix(T1) + 1 - scrollx;
479 int Y = note2ypix(e->value1) - scrolly;
481 int W = tick2xpix(T2)-scrollx - X;
482 get_event_color(e,&c1,&c2,&c3);
484 if(!(X+W<0 || X > w())){
486 fltk::setcolor(c1);
487 fltk::fillrect(X+1,Y+1,W-1,10);
489 fltk::setcolor(c2);
490 fltk::fillrect(X,Y+11,W,1);
491 fltk::fillrect(X+W-1,Y+1,1,11);
493 fltk::setcolor(c3);
494 fltk::fillrect(X,Y,W,1);
495 fltk::fillrect(X,Y,1,11);
498 e=e->next;
502 if(!rresize_flag && !lresize_flag){
503 if(resize_arrow > 0){
504 setcolor(resize_arrow_color);
506 int W = resize_handle_width;
507 int H = 12;
508 int X = resize_x;
509 int Y = resize_y;
511 addvertex(X,Y);
512 addvertex(X,Y+H);
513 addvertex(X+W,Y+H/2);
514 fillpath();
516 else if(resize_arrow < 0){
517 setcolor(resize_arrow_color);
519 int W = resize_handle_width;
520 int H = 12;
521 int X = resize_x;
522 int Y = resize_y;
524 addvertex(X+W,Y);
525 addvertex(X+W,Y+H);
526 addvertex(X,Y+H/2);
527 fillpath();
532 if(box_flag){
533 fltk::setcolor(fltk::GREEN);
534 int X1,X2,Y1,Y2;
535 if(box_x1>box_x2){
536 X1=box_x2;
537 X2=box_x1;
539 else{
540 X1=box_x1;
541 X2=box_x2;
543 if(box_y1>box_y2){
544 Y1=box_y2;
545 Y2=box_y1;
547 else{
548 Y1=box_y1;
549 Y2=box_y2;
551 fltk::fillrect(X1,Y1,X2-X1,1);
552 fltk::fillrect(X1,Y1,1,Y2-Y1);
553 fltk::fillrect(X2,Y1,1,Y2-Y1);
554 fltk::fillrect(X1,Y2,X2-X1,1);
557 fltk::pop_clip();
563 void PianoRoll::scrollTo(int X, int Y){
565 if(!cur_seqpat){
566 return;
569 if(is_backend_playing() && config.follow){
570 int pos = tick2xpix(get_play_position()) - cur_seqpat->tick;
571 if(pos < X || pos > X + w() - 30 - 30){
572 ui->pattern_hscroll->value(scrollx);
573 return;
577 scrollx = X;
578 scrolly = Y;
579 cur_seqpat->scrollx = X;
580 cur_seqpat->scrolly = Y;
582 redraw();
583 ui->pattern_hscroll->value(X);
584 ui->pattern_hscroll->redraw();
585 ui->pattern_vscroll->value(Y);
586 ui->pattern_timeline->scroll = X;
587 ui->pattern_timeline->redraw();
588 ui->event_edit->scroll = X;
589 ui->event_edit->redraw();
590 ui->keyboard->scroll = Y;
591 ui->keyboard->redraw();
594 static int kludge=2;
595 void PianoRoll::layout(){
596 if(kludge!=0){
597 kludge--;
598 return;
600 fakeh = 900;
601 if(fakeh<h()){
602 fakeh = h();
605 fltk::Scrollbar* sb = ui->pattern_vscroll;
607 sb->maximum(0);
608 sb->minimum(fakeh-h());
610 if(sb->value() > sb->minimum()){
611 scrollTo(scrollx,900-h());
613 int M = h() - 30;
614 int newsize = M-(fakeh-h());
615 if(newsize<20){
616 newsize=20;
618 ui->song_vscroll->slider_size(60);
621 void PianoRoll::load(seqpat* s){
622 cur_seqpat = s;
623 scrollTo(s->scrollx,s->scrolly);
624 cur_track = tracks[s->track];
625 ui->pattern_timeline->ticks_offset = s->tick;
630 int PianoRoll::note2ypix(int note){
631 int udy = 6*(note + (note+7)/12 + note/12) + 12;
632 return 900 - udy + 1;
635 int PianoRoll::tick2xpix(int tick){
636 return tick*zoom*4 / 128;
639 int PianoRoll::xpix2tick(int xpix){
640 return xpix*128 / (zoom*4);
643 int PianoRoll::quantize(int tick){
644 return tick/q_tick * q_tick;
648 void PianoRoll::set_zoom(int z){
649 zoom = z;
650 relayout();
654 mevent* PianoRoll::over_note(){
655 mevent* e = cur_seqpat->p->events->next;
657 int X = event_x()+scrollx;
658 int Y = event_y()+scrolly;
660 int cy, lx, rx;
661 while(e){
662 if(e->type == MIDI_NOTE_ON){
663 cy = note2ypix(e->value1);
664 lx = tick2xpix(e->tick);
665 rx = tick2xpix(e->tick+e->dur);
666 if(X > lx && X < rx &&
667 Y < cy+12 && Y > cy){
668 return e;
671 e = e->next;
674 return NULL;
679 void PianoRoll::update(int pos){
680 if(!is_backend_playing() || !cur_seqpat){
681 return;
683 int X1 = tick2xpix(pos-cur_seqpat->tick);
684 int X2 = X1 - scrollx;
685 if(X2 < 0){
686 scrollTo(X1-50<0?0:X1-50,scrolly);
688 if(X2 > w()-30){
689 scrollTo(X1-50,scrolly);
694 void PianoRoll::unselect_all(){
695 mevent* e = cur_seqpat->p->events;
696 while(e){
697 if(e->type == MIDI_NOTE_ON && e->selected==1){
698 e->selected = 0;
700 e = e->next;
706 void PianoRoll::get_event_color(mevent* e, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3){
708 int T1,T2;
709 int tmp;
710 if(delete_flag){
711 if(e->selected){
712 *c1 = fltk::color(229,79,75);
713 *c2 = fltk::color(120,60,58);
714 *c3 = fltk::color(225,131,109);
715 return;
719 if(box_flag){
720 T1=box_t1;
721 T2=box_t2;
722 int N1 = box_n1;
723 int N2 = box_n2;
724 int N = e->value1;
725 if(T1>T2){SWAP(T1,T2);}
726 if(N1<N2){SWAP(N1,N2);}
727 if(e->tick+e->dur > T1 && e->tick < T2 && N >= N2 && N <= N1){
728 *c1 = fltk::color(108,229,75);
729 *c2 = fltk::color(71,120,59);
730 *c3 = fltk::color(108,229,75);
731 return;
735 if(e->selected){
736 *c1 = fltk::color(255,248,47);
737 *c2 = fltk::color(140,137,46);
738 *c3 = fltk::color(232,255,37);
739 return;
742 *c1 = fltk::color(169,75,229);
743 *c2 = fltk::color(95,58,119);
744 *c3 = fltk::color(198,109,225);
748 void PianoRoll::apply_box(){
749 mevent* e = cur_seqpat->p->events->next;
750 int tmp;
751 int T1=box_t1;
752 int T2=box_t2;
753 int N1 = box_n1;
754 int N2 = box_n2;
756 if(T1>T2){SWAP(T1,T2);}
757 if(N1<N2){SWAP(N1,N2);}
758 while(e){
759 int N = e->value1;
760 if(e->type == MIDI_NOTE_ON &&
761 e->tick+e->dur > T1 && e->tick < T2 &&
762 N >= N2 && N <= N1){
763 e->selected = 1;
765 e = e->next;
769 void PianoRoll::apply_insert(){
770 if(insert_note > 127 || insert_note < 0){
771 return;
774 int tmp;
775 int T1 = insert_torig;
776 int T2 = T1 + insert_toffset;
777 if(T1>T2){SWAP(T1,T2);}
779 if(T1 < 0){
780 return;
783 pattern* p = cur_seqpat->p;
784 Command* c=new CreateNote(p,insert_note,config.defaultvelocity,T1,T2-T1);
785 set_undo(c);
786 undo_push(1);
788 cur_track->restate();
791 void PianoRoll::apply_delete(){
792 Command* c;
793 mevent* e;
794 mevent* next;
795 pattern* p = cur_seqpat->p;
796 int N=0;
798 e = cur_seqpat->p->events->next;
799 while(e){
800 next = e->next;
801 if(e->selected && e->type == MIDI_NOTE_ON){
802 c=new DeleteNote(p,e);
803 set_undo(c);
804 N++;
806 e = next;
808 undo_push(N);
810 cur_track->restate();
813 void PianoRoll::apply_move(){
814 if(move_toffset==0 && move_noffset==0){
815 return;
818 pattern* p = cur_seqpat->p;
819 mevent* e = p->events->next;
820 while(e){
821 int K = e->value1+move_noffset;
822 int T = e->tick+move_toffset;
823 if(e->type == MIDI_NOTE_ON && e->selected && (T<0 || K < 0 || K > 127)){
824 return;
826 e = e->next;
830 Command* c;
831 e = p->events->next;
833 mevent* next;
834 int M=0;
835 for(int i=0; i<tracks.size(); i++){
836 e = p->events->next;
837 while(e){
838 next = e->next;
839 if(e->selected && e->modified == 0){
840 int K = e->value1 + move_noffset;
841 int T = e->tick + move_toffset;
842 e->modified = 1;
843 c=new MoveNote(p,e,T,K);
844 set_undo(c);
845 M++;
847 e = next;
850 undo_push(M);
852 e = p->events->next;
853 while(e){
854 if(e->modified){e->modified=0;}
855 e = e->next;
858 cur_track->restate();
861 void PianoRoll::apply_paste(){
867 void PianoRoll::apply_rresize(){
868 if(rresize_toffset==0){
869 return;
872 Command* c;
873 mevent* e;
874 mevent* next;
875 pattern* p = cur_seqpat->p;
876 int tmp;
877 int N=0;
879 e = p->events->next;
880 while(e){
881 next = e->next;
882 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
883 e->modified = 1;
884 int W = e->dur;
885 int R = rresize_toffset;
886 if(W+R < q_tick){
887 R = q_tick-W;
889 c=new ResizeNote(p,e,W+R);
890 set_undo(c);
891 N++;
893 e = next;
896 e = p->events->next;
897 while(e){
898 if(e->modified){e->modified=0;}
899 e = e->next;
902 cur_track->restate();
903 undo_push(N);
906 void PianoRoll::apply_lresize(){
907 if(lresize_toffset==0){
908 return;
911 Command* c;
912 mevent* e;
913 mevent* next;
914 pattern* p = cur_seqpat->p;
915 int tmp;
916 int N=0;
918 e = p->events->next;
919 while(e){
920 if(e->type == MIDI_NOTE_ON && e->selected){
921 if(e->tick + lresize_toffset < 0){
922 return;
925 e = e->next;
928 e = p->events->next;
929 while(e){
930 next = e->next;
931 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
932 e->modified = 1;
933 int T = e->tick;
934 int W = e->dur;
935 int R = lresize_toffset;
937 if(R > W-q_tick){
938 R = W-q_tick;
941 mevent* etmp = e->prev;
942 c=new ResizeNote(p,e,W-R);
943 set_undo(c);
945 e = etmp->next;
946 c=new MoveNote(p,e,T+R,e->value1);
947 set_undo(c);
949 N+=2;
951 e = next;
954 e = p->events->next;
955 while(e){
956 if(e->modified){e->modified=0;}
957 e = e->next;
960 cur_track->restate();
961 undo_push(N);
972 int PianoRoll::over_rhandle(mevent* e){
973 int X = event_x()+scrollx;
974 int Y = event_y()+scrolly;
975 int X1 = tick2xpix(e->tick);
976 int X2 = X1 + tick2xpix(e->dur);
977 int Y1 = note2ypix(e->value1);
978 int Y2 = Y1 + 12;
980 if(X2-X1 < resize_handle_width*3){
981 return 0;
984 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - resize_handle_width);
987 int PianoRoll::over_lhandle(mevent* e){
988 int X = event_x()+scrollx;
989 int Y = event_y()+scrolly;
990 int X1 = tick2xpix(e->tick);
991 int X2 = X1 + tick2xpix(e->dur);
992 int Y1 = note2ypix(e->value1);
993 int Y2 = Y1 + 12;
995 if(X2-X1 < resize_handle_width*3){
996 return 0;
999 return (Y > Y1 && Y < Y2 && X < X1+ resize_handle_width +1 && X > X1 + 1);