Fixed right to left line tool in event editor. Again.
[epichord.git] / src / pianoroll.cpp
blobe493a37df4e84a6056fabdafc1032f06aedb8ce3
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;
64 insert_flag = 0;
65 move_flag = 0;
66 delete_flag=0;
67 lresize_flag = 0;
68 rresize_flag = 0;
70 resize_arrow = 0;
71 resize_e = NULL;
72 resize_handle_width = 4;
74 fakeh = wkeyh*75;
75 fakehmin = wkeyh*75;
76 if(fakeh < h){fakeh = h;}
78 scrollx=0;
79 scrolly=0;
82 int PianoRoll::handle(int event){
83 Command* c;
84 pattern* p;
85 mevent* e;
87 int X = event_x();
88 int Y = event_y();
90 switch(event){
91 case fltk::ENTER:
92 return 1;
93 case fltk::FOCUS:
94 return 1;
95 case fltk::SHORTCUT:
96 if(event_key()==fltk::DeleteKey){
97 apply_delete();
98 delete_flag = 0;
99 redraw();
100 resize_arrow = 0;
101 ui->event_edit->redraw();
102 return 1;
104 if(event_state(CTRL) && event_key()=='c'){
105 //printf("roll copy\n");
106 return 1;
108 if(zoom_out_key(event_key(),event_state())){
109 if(zoom_n > 1){
110 zoom_n--;
111 set_zoom(30*(1<<zoom_n)/16);
112 ui->pattern_timeline->zoom = zoom;
113 ui->pattern_timeline->update(get_play_position());
114 ui->pattern_timeline->redraw();
115 ui->event_edit->zoom = zoom;
116 ui->event_edit->redraw();
118 redraw();
119 return 1;
121 if(zoom_in_key(event_key(),event_state())){
122 if(zoom_n < 8){
123 zoom_n++;
124 set_zoom(30*(1<<zoom_n)/16);
125 ui->pattern_timeline->zoom = zoom;
126 ui->pattern_timeline->update(get_play_position());
127 ui->pattern_timeline->redraw();
128 ui->event_edit->zoom = zoom;
129 ui->event_edit->redraw();
131 redraw();
132 return 1;
134 return 0;
135 case fltk::PUSH:
136 take_focus();
137 e = over_note();
138 if(event_button()==1){//left mouse
139 if(e==NULL){//new note init
140 if(event_state()&fltk::SHIFT){//begin box
141 box_flag = 1;
142 box_x1=X;
143 box_x2=X;
144 box_y1=Y;
145 box_y2=Y;
146 box_t1=xpix2tick(X+scrollx);
147 box_t2=box_t1;
148 box_n1=ypix2note(Y+scrolly,1);
149 box_n2=box_n1;
151 else{//begin insert
152 insert_flag = 1;
153 insert_torig = quantize(xpix2tick(X+scrollx));
154 insert_toffset = q_tick;
155 //new_orig_t = new_left_t;
156 insert_note = ypix2note(Y+scrolly,1);
158 last_note = insert_note;
159 if(config.playinsert){
160 ui->keyboard->play_note(last_note,0);
165 else{
167 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
168 unselect_all();
170 e->selected = 1;
171 ui->event_edit->select_flag = 1;
172 resize_arrow_color = fltk::color(128,128,0);
174 if(over_rhandle(e)){//resize
175 rresize_flag = 1;
176 rresize_torig = e->tick+e->dur;
177 rresize_toffset = 0;
179 else if(over_lhandle(e)){//resize move
180 lresize_flag = 1;
181 lresize_torig = e->tick;
182 lresize_toffset = 0;
184 else{//begin move
185 move_flag = 1;
187 move_torig = e->tick;
188 move_qoffset = e->tick - quantize(e->tick);
190 move_toffset = -move_qoffset;
192 //move_offset = quantize(xpix2tick(X)) - move_torig - move_qoffset;
193 //move_toffset = 0;
194 move_offset = X - tick2xpix(e->tick);
195 move_norig = ypix2note(Y+scrolly,1);
196 move_noffset = 0;
198 last_note = move_norig;
199 if(config.playmove){
200 ui->keyboard->play_note(last_note,0);
205 else if(event_button()==2){//middle mouse
206 //button initiates paste
208 else if(event_button()==3){//right mouse
209 if(e==NULL){
210 unselect_all();
212 ui->event_edit->redraw();
214 else{//set up for deletion
215 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
216 unselect_all();
218 e->selected = 1;
219 delete_flag = 1;
220 resize_arrow_color = fltk::color(120,60,58);
223 redraw();
224 return 1;
225 case fltk::DRAG:
226 ui->keyboard->highlight_clear();
227 if(box_flag){
228 box_x2 = X;
229 box_y2 = Y;
230 box_t2 = xpix2tick(X+scrollx);
231 box_n2 = ypix2note(Y+scrolly,1);
233 else if(insert_flag){
234 insert_toffset = quantize(xpix2tick(X+scrollx)+q_tick) - insert_torig;
235 if(insert_toffset<=0){
236 insert_toffset -= q_tick;
238 insert_note = ypix2note(Y+scrolly,1);
239 if(insert_note != last_note){
240 if(config.playinsert){//play on insert
241 ui->keyboard->release_note(last_note,0);
242 ui->keyboard->play_note(insert_note,0);
244 last_note = insert_note;
247 else if(move_flag){
248 move_toffset = quantize(xpix2tick(X - move_offset)) - move_torig;
249 move_noffset = ypix2note(Y+scrolly,1) - move_norig;
250 int N = move_norig+move_noffset;
251 if(N != last_note){
252 if(config.playmove){//play on move
253 ui->keyboard->release_note(last_note,0);
254 ui->keyboard->play_note(N,0);
256 last_note = N;
259 else if(rresize_flag){
260 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_tick-rresize_torig;
262 else if(lresize_flag){
263 lresize_toffset = quantize(xpix2tick(X+scrollx)) - lresize_torig;
265 redraw();
266 return 1;
267 case fltk::RELEASE:
268 e = over_note();
269 if(event_button()==1){
270 if(box_flag){
271 apply_box();
272 ui->event_edit->redraw();
273 box_flag=0;
275 else if(rresize_flag){
276 apply_rresize();
277 rresize_flag = 0;
278 resize_arrow = 0;
279 ui->event_edit->redraw();
281 else if(lresize_flag){
282 apply_lresize();
283 lresize_flag = 0;
284 resize_arrow = 0;
285 ui->event_edit->redraw();
287 else if(insert_flag){
288 apply_insert();
290 insert_flag = 0;
292 ui->keyboard->release_note(insert_note,0);
293 ui->keyboard->redraw();
294 ui->event_edit->has[0]=1;
295 ui->event_edit->has[1]=1;
296 ui->event_edit->redraw();
297 ui->event_menu->redraw();
299 else if(move_flag){
300 apply_move();
301 move_flag = 0;
303 midi_track_off(cur_seqpat->track);
304 ui->keyboard->release_note(last_note,0);
305 ui->keyboard->release_note(move_norig+move_noffset,0);
306 ui->keyboard->redraw();
307 ui->event_edit->redraw();
309 insert_flag=0;
310 move_flag=0;
312 if(event_button()==3){
313 mevent* over_n = over_note();
314 if(delete_flag && over_n){
315 if(over_n->selected){
316 apply_delete();
317 midi_track_off(cur_seqpat->track);
318 ui->event_edit->redraw();
321 delete_flag=0;
322 resize_arrow = 0;
324 redraw();
326 return 1;
328 case fltk::MOVE:
329 ui->keyboard->highlight_note(ypix2note(Y+scrolly,1));
330 e = over_note();
331 if(e){
332 if(over_rhandle(e)){
333 if(resize_e != e || resize_arrow != 1){
334 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
335 else{resize_arrow_color = fltk::color(95,58,119);}
336 resize_e = e;
337 resize_arrow = 1;
338 resize_x = tick2xpix(e->tick + e->dur)-scrollx-resize_handle_width;
339 resize_y = note2ypix(e->value1)-scrolly;
340 redraw();
343 else if(over_lhandle(e)){
344 if(resize_e != e || resize_arrow != 1){
345 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
346 else{resize_arrow_color = fltk::color(95,58,119);}
347 resize_e = e;
348 resize_arrow = -1;
349 resize_x = tick2xpix(e->tick)+1 - scrollx;
350 resize_y = note2ypix(e->value1) - scrolly;
351 redraw();
354 else{
355 if(resize_e != e || resize_arrow != 0){
356 resize_e = e;
357 resize_arrow = 0;
358 redraw();
362 else{
363 if(resize_arrow != 0){
364 resize_arrow = 0;
365 redraw();
369 return 1;
372 case fltk::LEAVE:
373 ui->keyboard->highlight_clear();
374 return 1;
376 return 0;
379 void PianoRoll::draw(){
381 fltk::push_clip(0,0,w(),h());
383 fltk::setcolor(fltk::GRAY05);
384 fltk::fillrect(0,0,w(),h());
386 fltk::setcolor(fltk::GRAY20);
387 for(int i=12-scrolly; i<h(); i+=12){
388 if(i>=0){
389 fltk::fillrect(0,i,w(),1);
392 for(int i=zoom-scrollx; i<w(); i+=zoom){
393 if(i>=0){
394 fltk::fillrect(i,0,1,h());
398 fltk::setcolor(fltk::GRAY30);
399 for(int i=12*5-scrolly; i<h(); i+=12*7){
400 if(i>=0){
401 fltk::fillrect(0,i,w(),1);
405 fltk::setcolor(fltk::GRAY50);
406 for(int i=zoom*4-scrollx; i<w(); i+=zoom*4){
407 if(i>=0){
408 fltk::fillrect(i,0,1,h());
412 fltk::setcolor(fltk::WHITE);
413 int M = config.beats_per_measure;
414 for(int i=zoom*4*M-scrollx; i<w(); i+=zoom*4*M){
415 if(i>=0){
416 fltk::fillrect(i,0,1,h());
420 fltk::setcolor(fltk::color(128,0,0));
421 int rightend = tick2xpix(cur_seqpat->dur)-scrollx;
422 if(rightend >=0 && rightend < w()){
423 fltk::fillrect(rightend,0,1,h());
426 fltk::setcolor(fltk::color(128,128,0));
427 fltk::fillrect(0,12*40-scrolly,w(),1);
429 int tmp;
430 if(insert_flag){
431 fltk::setcolor(fltk::BLUE);
432 int T1 = insert_torig;
433 int T2 = T1 + insert_toffset;
434 if(T1>T2){SWAP(T1,T2);}
435 int X = tick2xpix(T1)+1 - scrollx;
436 int Y = note2ypix(insert_note) - scrolly;
437 int W = tick2xpix(T2)-scrollx - X;
438 fltk::fillrect(X,Y,W,11);
441 if(move_flag){
442 fltk::setcolor(fltk::MAGENTA);
443 mevent* ptr = cur_seqpat->p->events->next;
444 while(ptr){
445 if(ptr->type == MIDI_NOTE_ON && ptr->selected){
446 int X = tick2xpix(ptr->tick+move_toffset)+1-scrollx;
447 int Y = note2ypix(ptr->value1+move_noffset)-scrolly;
448 int W = tick2xpix(ptr->dur);
449 fltk::fillrect(X,Y,W-1,1);
450 fltk::fillrect(X,Y+11,W-1,1);
451 fltk::fillrect(X,Y,1,11);
452 fltk::fillrect(X+W-2,Y,1,11);
454 ptr=ptr->next;
460 //draw all notes
461 mevent* e = cur_seqpat->p->events->next;
463 fltk::Color c1,c2,c3;
465 while(e){
466 if(e->type == MIDI_NOTE_ON){
467 //fltk::fillrect(tick2xpix(e->tick),note2ypix(e->value),e->dur,11);
469 int R1 = rresize_flag&&e->selected ? rresize_toffset : 0;
470 int R2 = lresize_flag&&e->selected ? lresize_toffset : 0;
472 int T1 = e->tick + R2;
473 int T2 = e->tick+e->dur + R1;
475 if(T1 >= T2-q_tick && e->selected){
476 if(rresize_flag){
477 T1 = e->tick;
478 T2 = T1 + q_tick;
480 else if(lresize_flag){
481 T2 = e->tick + e->dur;
482 T1 = T2 - q_tick;
486 int X = tick2xpix(T1) + 1 - scrollx;
487 int Y = note2ypix(e->value1) - scrolly;
489 int W = tick2xpix(T2)-scrollx - X;
490 get_event_color(e,&c1,&c2,&c3);
492 if(!(X+W<0 || X > w())){
494 fltk::setcolor(c1);
495 fltk::fillrect(X+1,Y+1,W-1,10);
497 fltk::setcolor(c2);
498 fltk::fillrect(X,Y+11,W,1);
499 fltk::fillrect(X+W-1,Y+1,1,11);
501 fltk::setcolor(c3);
502 fltk::fillrect(X,Y,W,1);
503 fltk::fillrect(X,Y,1,11);
506 e=e->next;
510 if(!rresize_flag && !lresize_flag){
511 if(resize_arrow > 0){
512 setcolor(resize_arrow_color);
514 int W = resize_handle_width;
515 int H = 12;
516 int X = resize_x;
517 int Y = resize_y;
519 addvertex(X,Y);
520 addvertex(X,Y+H);
521 addvertex(X+W,Y+H/2);
522 fillpath();
524 else if(resize_arrow < 0){
525 setcolor(resize_arrow_color);
527 int W = resize_handle_width;
528 int H = 12;
529 int X = resize_x;
530 int Y = resize_y;
532 addvertex(X+W,Y);
533 addvertex(X+W,Y+H);
534 addvertex(X,Y+H/2);
535 fillpath();
540 if(box_flag){
541 fltk::setcolor(fltk::GREEN);
542 int X1,X2,Y1,Y2;
543 if(box_x1>box_x2){
544 X1=box_x2;
545 X2=box_x1;
547 else{
548 X1=box_x1;
549 X2=box_x2;
551 if(box_y1>box_y2){
552 Y1=box_y2;
553 Y2=box_y1;
555 else{
556 Y1=box_y1;
557 Y2=box_y2;
559 fltk::fillrect(X1,Y1,X2-X1,1);
560 fltk::fillrect(X1,Y1,1,Y2-Y1);
561 fltk::fillrect(X2,Y1,1,Y2-Y1);
562 fltk::fillrect(X1,Y2,X2-X1,1);
565 fltk::pop_clip();
571 void PianoRoll::scrollTo(int X, int Y){
573 if(!cur_seqpat){
574 return;
577 if(is_backend_playing() && config.follow){
578 int pos = tick2xpix(get_play_position()) - cur_seqpat->tick;
579 if(pos < X || pos > X + w() - 30 - 30){
580 ui->pattern_hscroll->value(scrollx);
581 return;
585 scrollx = X;
586 scrolly = Y;
587 cur_seqpat->scrollx = X;
588 cur_seqpat->scrolly = Y;
590 redraw();
591 ui->pattern_hscroll->value(X);
592 ui->pattern_hscroll->redraw();
593 ui->pattern_vscroll->value(Y);
594 ui->pattern_timeline->scroll = X;
595 ui->pattern_timeline->redraw();
596 ui->event_edit->scroll = X;
597 ui->event_edit->redraw();
598 ui->keyboard->scroll = Y;
599 ui->keyboard->redraw();
602 static int kludge=2;
603 void PianoRoll::layout(){
604 if(kludge!=0){
605 kludge--;
606 return;
608 fakeh = 900;
609 if(fakeh<h()){
610 fakeh = h();
613 fltk::Scrollbar* sb = ui->pattern_vscroll;
615 sb->maximum(0);
616 sb->minimum(fakeh-h());
618 if(sb->value() > sb->minimum()){
619 scrollTo(scrollx,900-h());
621 int M = h() - 30;
622 int newsize = M-(fakeh-h());
623 if(newsize<20){
624 newsize=20;
626 ui->song_vscroll->slider_size(60);
629 void PianoRoll::load(seqpat* s){
630 cur_seqpat = s;
631 scrollTo(s->scrollx,s->scrolly);
632 cur_track = tracks[s->track];
633 ui->pattern_timeline->ticks_offset = s->tick;
638 int PianoRoll::note2ypix(int note){
639 int udy = 6*(note + (note+7)/12 + note/12) + 12;
640 return 900 - udy + 1;
643 int PianoRoll::tick2xpix(int tick){
644 return tick*zoom*4 / 128;
647 int PianoRoll::xpix2tick(int xpix){
648 return xpix*128 / (zoom*4);
651 int PianoRoll::quantize(int tick){
652 return tick/q_tick * q_tick;
656 void PianoRoll::set_zoom(int z){
657 zoom = z;
658 relayout();
662 mevent* PianoRoll::over_note(){
663 mevent* e = cur_seqpat->p->events->next;
665 int X = event_x()+scrollx;
666 int Y = event_y()+scrolly;
668 int cy, lx, rx;
669 while(e){
670 if(e->type == MIDI_NOTE_ON){
671 cy = note2ypix(e->value1);
672 lx = tick2xpix(e->tick);
673 rx = tick2xpix(e->tick+e->dur);
674 if(X > lx && X < rx &&
675 Y < cy+12 && Y > cy){
676 return e;
679 e = e->next;
682 return NULL;
687 void PianoRoll::update(int pos){
688 if(!is_backend_playing() || !cur_seqpat){
689 return;
691 int X1 = tick2xpix(pos-cur_seqpat->tick);
692 int X2 = X1 - scrollx;
693 if(X2 < 0){
694 scrollTo(X1-50<0?0:X1-50,scrolly);
696 if(X2 > w()-30){
697 scrollTo(X1-50,scrolly);
702 void PianoRoll::unselect_all(){
703 mevent* e = cur_seqpat->p->events;
704 while(e){
705 if(e->type == MIDI_NOTE_ON && e->selected==1){
706 e->selected = 0;
708 e = e->next;
714 void PianoRoll::get_event_color(mevent* e, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3){
716 int T1,T2;
717 int tmp;
718 if(delete_flag){
719 if(e->selected){
720 *c1 = fltk::color(229,79,75);
721 *c2 = fltk::color(120,60,58);
722 *c3 = fltk::color(225,131,109);
723 return;
727 if(box_flag){
728 T1=box_t1;
729 T2=box_t2;
730 int N1 = box_n1;
731 int N2 = box_n2;
732 int N = e->value1;
733 if(T1>T2){SWAP(T1,T2);}
734 if(N1<N2){SWAP(N1,N2);}
735 if(e->tick+e->dur > T1 && e->tick < T2 && N >= N2 && N <= N1){
736 *c1 = fltk::color(108,229,75);
737 *c2 = fltk::color(71,120,59);
738 *c3 = fltk::color(108,229,75);
739 return;
743 if(e->selected){
744 *c1 = fltk::color(255,248,47);
745 *c2 = fltk::color(140,137,46);
746 *c3 = fltk::color(232,255,37);
747 return;
750 *c1 = fltk::color(169,75,229);
751 *c2 = fltk::color(95,58,119);
752 *c3 = fltk::color(198,109,225);
756 void PianoRoll::apply_box(){
757 mevent* e = cur_seqpat->p->events->next;
758 int tmp;
759 int T1=box_t1;
760 int T2=box_t2;
761 int N1 = box_n1;
762 int N2 = box_n2;
764 if(T1>T2){SWAP(T1,T2);}
765 if(N1<N2){SWAP(N1,N2);}
766 while(e){
767 int N = e->value1;
768 if(e->type == MIDI_NOTE_ON &&
769 e->tick+e->dur > T1 && e->tick < T2 &&
770 N >= N2 && N <= N1){
771 e->selected = 1;
773 e = e->next;
777 void PianoRoll::apply_insert(){
778 if(insert_note > 127 || insert_note < 0){
779 return;
782 int tmp;
783 int T1 = insert_torig;
784 int T2 = T1 + insert_toffset;
785 if(T1>T2){SWAP(T1,T2);}
787 if(T1 < 0){
788 return;
791 pattern* p = cur_seqpat->p;
792 Command* c=new CreateNote(p,insert_note,config.defaultvelocity,T1,T2-T1);
793 set_undo(c);
794 undo_push(1);
796 cur_track->restate();
799 void PianoRoll::apply_delete(){
800 Command* c;
801 mevent* e;
802 mevent* next;
803 pattern* p = cur_seqpat->p;
804 int N=0;
806 e = cur_seqpat->p->events->next;
807 while(e){
808 next = e->next;
809 if(e->selected && e->type == MIDI_NOTE_ON){
810 c=new DeleteNote(p,e);
811 set_undo(c);
812 N++;
814 e = next;
816 undo_push(N);
818 cur_track->restate();
821 void PianoRoll::apply_move(){
822 if(move_toffset==0 && move_noffset==0){
823 return;
826 pattern* p = cur_seqpat->p;
827 mevent* e = p->events->next;
828 while(e){
829 int K = e->value1+move_noffset;
830 int T = e->tick+move_toffset;
831 if(e->type == MIDI_NOTE_ON && e->selected && (T<0 || K < 0 || K > 127)){
832 return;
834 e = e->next;
838 Command* c;
839 e = p->events->next;
841 mevent* next;
842 int M=0;
843 for(int i=0; i<tracks.size(); i++){
844 e = p->events->next;
845 while(e){
846 next = e->next;
847 if(e->selected && e->modified == 0){
848 int K = e->value1 + move_noffset;
849 int T = e->tick + move_toffset;
850 e->modified = 1;
851 c=new MoveNote(p,e,T,K);
852 set_undo(c);
853 M++;
855 e = next;
858 undo_push(M);
860 e = p->events->next;
861 while(e){
862 if(e->modified){e->modified=0;}
863 e = e->next;
866 cur_track->restate();
869 void PianoRoll::apply_paste(){
875 void PianoRoll::apply_rresize(){
876 if(rresize_toffset==0){
877 return;
880 Command* c;
881 mevent* e;
882 mevent* next;
883 pattern* p = cur_seqpat->p;
884 int tmp;
885 int N=0;
887 e = p->events->next;
888 while(e){
889 next = e->next;
890 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
891 e->modified = 1;
892 int W = e->dur;
893 int R = rresize_toffset;
894 if(W+R < q_tick){
895 R = q_tick-W;
897 c=new ResizeNote(p,e,W+R);
898 set_undo(c);
899 N++;
901 e = next;
904 e = p->events->next;
905 while(e){
906 if(e->modified){e->modified=0;}
907 e = e->next;
910 cur_track->restate();
911 undo_push(N);
914 void PianoRoll::apply_lresize(){
915 if(lresize_toffset==0){
916 return;
919 Command* c;
920 mevent* e;
921 mevent* next;
922 pattern* p = cur_seqpat->p;
923 int tmp;
924 int N=0;
926 e = p->events->next;
927 while(e){
928 if(e->type == MIDI_NOTE_ON && e->selected){
929 if(e->tick + lresize_toffset < 0){
930 return;
933 e = e->next;
936 e = p->events->next;
937 while(e){
938 next = e->next;
939 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
940 e->modified = 1;
941 int T = e->tick;
942 int W = e->dur;
943 int R = lresize_toffset;
945 if(R > W-q_tick){
946 R = W-q_tick;
949 mevent* etmp = e->prev;
950 c=new ResizeNote(p,e,W-R);
951 set_undo(c);
953 e = etmp->next;
954 c=new MoveNote(p,e,T+R,e->value1);
955 set_undo(c);
957 N+=2;
959 e = next;
962 e = p->events->next;
963 while(e){
964 if(e->modified){e->modified=0;}
965 e = e->next;
968 cur_track->restate();
969 undo_push(N);
980 int PianoRoll::over_rhandle(mevent* e){
981 int X = event_x()+scrollx;
982 int Y = event_y()+scrolly;
983 int X1 = tick2xpix(e->tick);
984 int X2 = X1 + tick2xpix(e->dur);
985 int Y1 = note2ypix(e->value1);
986 int Y2 = Y1 + 12;
988 if(X2-X1 < resize_handle_width*3){
989 return 0;
992 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - resize_handle_width);
995 int PianoRoll::over_lhandle(mevent* e){
996 int X = event_x()+scrollx;
997 int Y = event_y()+scrolly;
998 int X1 = tick2xpix(e->tick);
999 int X2 = X1 + tick2xpix(e->dur);
1000 int Y1 = note2ypix(e->value1);
1001 int Y2 = Y1 + 12;
1003 if(X2-X1 < resize_handle_width*3){
1004 return 0;
1007 return (Y > Y1 && Y < Y2 && X < X1+ resize_handle_width +1 && X > X1 + 1);