A canceled load or import does not erase the song.
[epichord.git] / src / pianoroll.cpp
blob16ab62a9295c393834a9bb18ab7a13b86f353719
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 int prevt;
92 switch(event){
93 case fltk::ENTER:
94 return 1;
95 case fltk::FOCUS:
96 return 1;
97 case fltk::SHORTCUT:
98 if(event_key()==fltk::DeleteKey){
99 apply_delete();
100 delete_flag = 0;
101 redraw();
102 resize_arrow = 0;
103 ui->event_edit->redraw();
104 return 1;
106 if(event_state(CTRL) && event_key()=='c'){
107 //printf("roll copy\n");
108 return 1;
110 if(zoom_out_key(event_key(),event_state())){
111 if(zoom_n > 1){
112 prevt = xpix2tick(scrollx);
113 zoom_n--;
114 set_zoom(30*(1<<zoom_n)/16);
115 ui->pattern_timeline->zoom = zoom;
116 //ui->pattern_timeline->update(get_play_position());
117 //ui->pattern_timeline->redraw();
118 ui->event_edit->zoom = zoom;
119 scrollTo(tick2xpix(prevt),scrolly);
120 //ui->event_edit->redraw();
122 redraw();
123 return 1;
125 if(zoom_in_key(event_key(),event_state())){
126 if(zoom_n < 8){
127 prevt = xpix2tick(scrollx);
128 zoom_n++;
129 set_zoom(30*(1<<zoom_n)/16);
130 ui->pattern_timeline->zoom = zoom;
131 //ui->pattern_timeline->update(get_play_position());
132 //ui->pattern_timeline->redraw();
133 ui->event_edit->zoom = zoom;
134 scrollTo(tick2xpix(prevt),scrolly);
135 //ui->event_edit->redraw();
137 redraw();
138 return 1;
140 return 0;
141 case fltk::PUSH:
142 take_focus();
143 e = over_note();
144 if(event_button()==1){//left mouse
145 if(e==NULL){//new note init
146 if(event_state()&fltk::SHIFT){//begin box
147 box_flag = 1;
148 box_x1=X;
149 box_x2=X;
150 box_y1=Y;
151 box_y2=Y;
152 box_t1=xpix2tick(X+scrollx);
153 box_t2=box_t1;
154 box_n1=ypix2note(Y+scrolly,1);
155 box_n2=box_n1;
157 else{//begin insert
158 insert_flag = 1;
159 insert_torig = quantize(xpix2tick(X+scrollx));
160 insert_toffset = q_tick;
161 //new_orig_t = new_left_t;
162 insert_note = ypix2note(Y+scrolly,1);
164 last_note = insert_note;
165 if(config.playinsert){
166 ui->keyboard->play_note(last_note,0);
171 else{
173 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
174 unselect_all();
176 e->selected = 1;
177 ui->event_edit->select_flag = 1;
178 resize_arrow_color = fltk::color(128,128,0);
180 if(over_rhandle(e)){//resize
181 rresize_flag = 1;
182 rresize_torig = e->tick+e->dur;
183 rresize_toffset = 0;
185 else if(over_lhandle(e)){//resize move
186 lresize_flag = 1;
187 lresize_torig = e->tick;
188 lresize_toffset = 0;
190 else{//begin move
191 move_flag = 1;
193 move_torig = e->tick;
194 move_qoffset = e->tick - quantize(e->tick);
196 move_toffset = -move_qoffset;
198 //move_offset = quantize(xpix2tick(X)) - move_torig - move_qoffset;
199 //move_toffset = 0;
200 move_offset = X - tick2xpix(e->tick);
201 move_norig = ypix2note(Y+scrolly,1);
202 move_noffset = 0;
204 last_note = move_norig;
205 if(config.playmove){
206 ui->keyboard->play_note(last_note,0);
211 else if(event_button()==2){//middle mouse
212 //button initiates paste
214 else if(event_button()==3){//right mouse
215 if(e==NULL){
216 unselect_all();
218 ui->event_edit->redraw();
220 else{//set up for deletion
221 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
222 unselect_all();
224 e->selected = 1;
225 delete_flag = 1;
226 resize_arrow_color = fltk::color(120,60,58);
229 redraw();
230 return 1;
231 case fltk::DRAG:
232 ui->keyboard->highlight_clear();
233 if(box_flag){
234 box_x2 = X;
235 box_y2 = Y;
236 box_t2 = xpix2tick(X+scrollx);
237 box_n2 = ypix2note(Y+scrolly,1);
239 else if(insert_flag){
240 insert_toffset = quantize(xpix2tick(X+scrollx)+q_tick) - insert_torig;
241 if(insert_toffset<=0){
242 insert_toffset -= q_tick;
244 insert_note = ypix2note(Y+scrolly,1);
245 if(insert_note != last_note){
246 if(config.playinsert){//play on insert
247 ui->keyboard->release_note(last_note,0);
248 ui->keyboard->play_note(insert_note,0);
250 last_note = insert_note;
253 else if(move_flag){
254 move_toffset = quantize(xpix2tick(X - move_offset)) - move_torig;
255 move_noffset = ypix2note(Y+scrolly,1) - move_norig;
256 int N = move_norig+move_noffset;
257 if(N != last_note){
258 if(config.playmove){//play on move
259 ui->keyboard->release_note(last_note,0);
260 ui->keyboard->play_note(N,0);
262 last_note = N;
265 else if(rresize_flag){
266 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_tick-rresize_torig;
268 else if(lresize_flag){
269 lresize_toffset = quantize(xpix2tick(X+scrollx)) - lresize_torig;
271 redraw();
272 return 1;
273 case fltk::RELEASE:
274 e = over_note();
275 if(event_button()==1){
276 if(box_flag){
277 apply_box();
278 ui->event_edit->redraw();
279 box_flag=0;
281 else if(rresize_flag){
282 apply_rresize();
283 rresize_flag = 0;
284 resize_arrow = 0;
285 ui->event_edit->redraw();
287 else if(lresize_flag){
288 apply_lresize();
289 lresize_flag = 0;
290 resize_arrow = 0;
291 ui->event_edit->redraw();
293 else if(insert_flag){
294 apply_insert();
296 insert_flag = 0;
298 ui->keyboard->release_note(insert_note,0);
299 ui->keyboard->redraw();
300 ui->event_edit->has[0]=1;
301 ui->event_edit->has[1]=1;
302 ui->event_edit->redraw();
303 ui->event_menu->redraw();
305 else if(move_flag){
306 apply_move();
307 move_flag = 0;
309 midi_track_off(cur_seqpat->track);
310 ui->keyboard->release_note(last_note,0);
311 ui->keyboard->release_note(move_norig+move_noffset,0);
312 ui->keyboard->redraw();
313 ui->event_edit->redraw();
315 insert_flag=0;
316 move_flag=0;
318 if(event_button()==3){
319 mevent* over_n = over_note();
320 if(delete_flag && over_n){
321 if(over_n->selected){
322 apply_delete();
323 midi_track_off(cur_seqpat->track);
324 ui->event_edit->redraw();
327 delete_flag=0;
328 resize_arrow = 0;
330 redraw();
332 return 1;
334 case fltk::MOVE:
335 ui->keyboard->highlight_note(ypix2note(Y+scrolly,1));
336 e = over_note();
337 if(e){
338 if(over_rhandle(e)){
339 if(resize_e != e || resize_arrow != 1){
340 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
341 else{resize_arrow_color = fltk::color(95,58,119);}
342 resize_e = e;
343 resize_arrow = 1;
344 resize_x = tick2xpix(e->tick + e->dur)-scrollx-resize_handle_width;
345 resize_y = note2ypix(e->value1)-scrolly;
346 redraw();
349 else if(over_lhandle(e)){
350 if(resize_e != e || resize_arrow != 1){
351 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
352 else{resize_arrow_color = fltk::color(95,58,119);}
353 resize_e = e;
354 resize_arrow = -1;
355 resize_x = tick2xpix(e->tick)+1 - scrollx;
356 resize_y = note2ypix(e->value1) - scrolly;
357 redraw();
360 else{
361 if(resize_e != e || resize_arrow != 0){
362 resize_e = e;
363 resize_arrow = 0;
364 redraw();
368 else{
369 if(resize_arrow != 0){
370 resize_arrow = 0;
371 redraw();
375 return 1;
378 case fltk::LEAVE:
379 ui->keyboard->highlight_clear();
380 return 1;
382 return 0;
385 void PianoRoll::draw(){
387 fltk::push_clip(0,0,w(),h());
389 fltk::setcolor(fltk::GRAY05);
390 fltk::fillrect(0,0,w(),h());
392 fltk::setcolor(fltk::GRAY20);
393 for(int i=12-scrolly; i<h(); i+=12){
394 if(i>=0){
395 fltk::fillrect(0,i,w(),1);
398 for(int i=zoom-scrollx; i<w(); i+=zoom){
399 if(i>=0){
400 fltk::fillrect(i,0,1,h());
404 fltk::setcolor(fltk::GRAY30);
405 for(int i=12*5-scrolly; i<h(); i+=12*7){
406 if(i>=0){
407 fltk::fillrect(0,i,w(),1);
411 fltk::setcolor(fltk::GRAY50);
412 for(int i=zoom*4-scrollx; i<w(); i+=zoom*4){
413 if(i>=0){
414 fltk::fillrect(i,0,1,h());
418 fltk::setcolor(fltk::WHITE);
419 int M = config.beats_per_measure;
420 for(int i=zoom*4*M-scrollx; i<w(); i+=zoom*4*M){
421 if(i>=0){
422 fltk::fillrect(i,0,1,h());
426 fltk::setcolor(fltk::color(128,0,0));
427 int rightend = tick2xpix(cur_seqpat->dur)-scrollx;
428 if(rightend >=0 && rightend < w()){
429 fltk::fillrect(rightend,0,1,h());
432 fltk::setcolor(fltk::color(128,128,0));
433 fltk::fillrect(0,12*40-scrolly,w(),1);
435 int tmp;
436 if(insert_flag){
437 fltk::setcolor(fltk::BLUE);
438 int T1 = insert_torig;
439 int T2 = T1 + insert_toffset;
440 if(T1>T2){SWAP(T1,T2);}
441 int X = tick2xpix(T1)+1 - scrollx;
442 int Y = note2ypix(insert_note) - scrolly;
443 int W = tick2xpix(T2)-scrollx - X;
444 fltk::fillrect(X,Y,W,11);
447 if(move_flag){
448 fltk::setcolor(fltk::MAGENTA);
449 mevent* ptr = cur_seqpat->p->events->next;
450 while(ptr){
451 if(ptr->type == MIDI_NOTE_ON && ptr->selected){
452 int X = tick2xpix(ptr->tick+move_toffset)+1-scrollx;
453 int Y = note2ypix(ptr->value1+move_noffset)-scrolly;
454 int W = tick2xpix(ptr->dur);
455 fltk::fillrect(X,Y,W-1,1);
456 fltk::fillrect(X,Y+11,W-1,1);
457 fltk::fillrect(X,Y,1,11);
458 fltk::fillrect(X+W-2,Y,1,11);
460 ptr=ptr->next;
466 //draw all notes
467 mevent* e = cur_seqpat->p->events->next;
469 fltk::Color c1,c2,c3;
471 while(e){
472 if(e->type == MIDI_NOTE_ON){
473 //fltk::fillrect(tick2xpix(e->tick),note2ypix(e->value),e->dur,11);
475 int R1 = rresize_flag&&e->selected ? rresize_toffset : 0;
476 int R2 = lresize_flag&&e->selected ? lresize_toffset : 0;
478 int T1 = e->tick + R2;
479 int T2 = e->tick+e->dur + R1;
481 if(T1 >= T2-q_tick && e->selected){
482 if(rresize_flag){
483 T1 = e->tick;
484 T2 = T1 + q_tick;
486 else if(lresize_flag){
487 T2 = e->tick + e->dur;
488 T1 = T2 - q_tick;
492 int X = tick2xpix(T1) + 1 - scrollx;
493 int Y = note2ypix(e->value1) - scrolly;
495 int W = tick2xpix(T2)-scrollx - X;
496 get_event_color(e,&c1,&c2,&c3);
498 if(!(X+W<0 || X > w())){
500 fltk::setcolor(c1);
501 fltk::fillrect(X+1,Y+1,W-1,10);
503 fltk::setcolor(c2);
504 fltk::fillrect(X,Y+11,W,1);
505 fltk::fillrect(X+W-1,Y+1,1,11);
507 fltk::setcolor(c3);
508 fltk::fillrect(X,Y,W,1);
509 fltk::fillrect(X,Y,1,11);
512 e=e->next;
516 if(!rresize_flag && !lresize_flag){
517 if(resize_arrow > 0){
518 setcolor(resize_arrow_color);
520 int W = resize_handle_width;
521 int H = 12;
522 int X = resize_x;
523 int Y = resize_y;
525 addvertex(X,Y);
526 addvertex(X,Y+H);
527 addvertex(X+W,Y+H/2);
528 fillpath();
530 else if(resize_arrow < 0){
531 setcolor(resize_arrow_color);
533 int W = resize_handle_width;
534 int H = 12;
535 int X = resize_x;
536 int Y = resize_y;
538 addvertex(X+W,Y);
539 addvertex(X+W,Y+H);
540 addvertex(X,Y+H/2);
541 fillpath();
546 if(box_flag){
547 fltk::setcolor(fltk::GREEN);
548 int X1,X2,Y1,Y2;
549 if(box_x1>box_x2){
550 X1=box_x2;
551 X2=box_x1;
553 else{
554 X1=box_x1;
555 X2=box_x2;
557 if(box_y1>box_y2){
558 Y1=box_y2;
559 Y2=box_y1;
561 else{
562 Y1=box_y1;
563 Y2=box_y2;
565 fltk::fillrect(X1,Y1,X2-X1,1);
566 fltk::fillrect(X1,Y1,1,Y2-Y1);
567 fltk::fillrect(X2,Y1,1,Y2-Y1);
568 fltk::fillrect(X1,Y2,X2-X1,1);
571 fltk::pop_clip();
577 void PianoRoll::scrollTo(int X, int Y){
579 if(!cur_seqpat){
580 return;
583 if(is_backend_playing() && config.follow){
584 int pos = tick2xpix(get_play_position() - cur_seqpat->tick);
585 if(pos < cur_seqpat->tick){
587 else if(pos < X || pos > X + w() - 30 - 30){
588 ui->pattern_hscroll->value(scrollx);
589 return;
593 scrollx = X;
594 scrolly = Y;
595 cur_seqpat->scrollx = X;
596 cur_seqpat->scrolly = Y;
598 redraw();
599 ui->pattern_hscroll->value(X);
600 ui->pattern_hscroll->redraw();
601 ui->pattern_vscroll->value(Y);
602 ui->pattern_timeline->scroll = X;
603 ui->pattern_timeline->redraw();
604 ui->event_edit->scroll = X;
605 ui->event_edit->redraw();
606 ui->keyboard->scroll = Y;
607 ui->keyboard->redraw();
610 static int kludge=2;
611 void PianoRoll::layout(){
612 if(kludge!=0){
613 kludge--;
614 return;
616 fakeh = 900;
617 if(fakeh<h()){
618 fakeh = h();
621 fltk::Scrollbar* sb = ui->pattern_vscroll;
623 sb->maximum(0);
624 sb->minimum(fakeh-h());
626 if(sb->value() > sb->minimum()){
627 scrollTo(scrollx,900-h());
629 int M = h() - 30;
630 int newsize = M-(fakeh-h());
631 if(newsize<20){
632 newsize=20;
634 ui->song_vscroll->slider_size(60);
637 void PianoRoll::load(seqpat* s){
638 cur_seqpat = s;
639 scrollTo(s->scrollx,s->scrolly);
640 cur_track = tracks[s->track];
641 ui->pattern_timeline->ticks_offset = s->tick;
646 int PianoRoll::note2ypix(int note){
647 int udy = 6*(note + (note+7)/12 + note/12) + 12;
648 return 900 - udy + 1;
651 int PianoRoll::tick2xpix(int tick){
652 return tick*zoom*4 / 128;
655 int PianoRoll::xpix2tick(int xpix){
656 return xpix*128 / (zoom*4);
659 int PianoRoll::quantize(int tick){
660 return tick/q_tick * q_tick;
664 void PianoRoll::set_zoom(int z){
665 zoom = z;
666 relayout();
670 mevent* PianoRoll::over_note(){
671 mevent* e = cur_seqpat->p->events->next;
673 int X = event_x()+scrollx;
674 int Y = event_y()+scrolly;
676 int cy, lx, rx;
677 while(e){
678 if(e->type == MIDI_NOTE_ON){
679 cy = note2ypix(e->value1);
680 lx = tick2xpix(e->tick);
681 rx = tick2xpix(e->tick+e->dur);
682 if(X > lx && X < rx &&
683 Y < cy+12 && Y > cy){
684 return e;
687 e = e->next;
690 return NULL;
695 void PianoRoll::update(int pos){
696 if(!is_backend_playing() || !cur_seqpat){
697 return;
699 if(pos < cur_seqpat->tick){
700 return;
702 int X1 = tick2xpix(pos-cur_seqpat->tick);
703 int X2 = X1 - scrollx;
704 if(X2 < 0){
705 scrollTo(X1-50<0?0:X1-50,scrolly);
707 if(X2 > w()-30){
708 scrollTo(X1-50,scrolly);
713 void PianoRoll::unselect_all(){
714 mevent* e = cur_seqpat->p->events;
715 while(e){
716 if(e->type == MIDI_NOTE_ON && e->selected==1){
717 e->selected = 0;
719 e = e->next;
725 void PianoRoll::get_event_color(mevent* e, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3){
727 int T1,T2;
728 int tmp;
729 if(delete_flag){
730 if(e->selected){
731 *c1 = fltk::color(229,79,75);
732 *c2 = fltk::color(120,60,58);
733 *c3 = fltk::color(225,131,109);
734 return;
738 if(box_flag){
739 T1=box_t1;
740 T2=box_t2;
741 int N1 = box_n1;
742 int N2 = box_n2;
743 int N = e->value1;
744 if(T1>T2){SWAP(T1,T2);}
745 if(N1<N2){SWAP(N1,N2);}
746 if(e->tick+e->dur > T1 && e->tick < T2 && N >= N2 && N <= N1){
747 *c1 = fltk::color(108,229,75);
748 *c2 = fltk::color(71,120,59);
749 *c3 = fltk::color(108,229,75);
750 return;
754 if(e->selected){
755 *c1 = fltk::color(255,248,47);
756 *c2 = fltk::color(140,137,46);
757 *c3 = fltk::color(232,255,37);
758 return;
761 *c1 = fltk::color(169,75,229);
762 *c2 = fltk::color(95,58,119);
763 *c3 = fltk::color(198,109,225);
767 void PianoRoll::apply_box(){
768 mevent* e = cur_seqpat->p->events->next;
769 int tmp;
770 int T1=box_t1;
771 int T2=box_t2;
772 int N1 = box_n1;
773 int N2 = box_n2;
775 if(T1>T2){SWAP(T1,T2);}
776 if(N1<N2){SWAP(N1,N2);}
777 while(e){
778 int N = e->value1;
779 if(e->type == MIDI_NOTE_ON &&
780 e->tick+e->dur > T1 && e->tick < T2 &&
781 N >= N2 && N <= N1){
782 e->selected = 1;
784 e = e->next;
788 void PianoRoll::apply_insert(){
789 if(insert_note > 127 || insert_note < 0){
790 return;
793 int tmp;
794 int T1 = insert_torig;
795 int T2 = T1 + insert_toffset;
796 if(T1>T2){SWAP(T1,T2);}
798 if(T1 < 0){
799 return;
802 pattern* p = cur_seqpat->p;
803 Command* c=new CreateNote(p,insert_note,config.defaultvelocity,T1,T2-T1);
804 set_undo(c);
805 undo_push(1);
807 cur_track->restate();
810 void PianoRoll::apply_delete(){
811 Command* c;
812 mevent* e;
813 mevent* next;
814 pattern* p = cur_seqpat->p;
815 int N=0;
817 e = cur_seqpat->p->events->next;
818 while(e){
819 next = e->next;
820 if(e->selected && e->type == MIDI_NOTE_ON){
821 c=new DeleteNote(p,e);
822 set_undo(c);
823 N++;
825 e = next;
827 undo_push(N);
829 cur_track->restate();
832 void PianoRoll::apply_move(){
833 if(move_toffset==0 && move_noffset==0){
834 return;
837 pattern* p = cur_seqpat->p;
838 mevent* e = p->events->next;
839 while(e){
840 int K = e->value1+move_noffset;
841 int T = e->tick+move_toffset;
842 if(e->type == MIDI_NOTE_ON && e->selected && (T<0 || K < 0 || K > 127)){
843 return;
845 e = e->next;
849 Command* c;
850 e = p->events->next;
852 mevent* next;
853 int M=0;
854 for(int i=0; i<tracks.size(); i++){
855 e = p->events->next;
856 while(e){
857 next = e->next;
858 if(e->selected && e->modified == 0){
859 int K = e->value1 + move_noffset;
860 int T = e->tick + move_toffset;
861 e->modified = 1;
862 c=new MoveNote(p,e,T,K);
863 set_undo(c);
864 M++;
866 e = next;
869 undo_push(M);
871 e = p->events->next;
872 while(e){
873 if(e->modified){e->modified=0;}
874 e = e->next;
877 cur_track->restate();
880 void PianoRoll::apply_paste(){
886 void PianoRoll::apply_rresize(){
887 if(rresize_toffset==0){
888 return;
891 Command* c;
892 mevent* e;
893 mevent* next;
894 pattern* p = cur_seqpat->p;
895 int tmp;
896 int N=0;
898 e = p->events->next;
899 while(e){
900 next = e->next;
901 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
902 e->modified = 1;
903 int W = e->dur;
904 int R = rresize_toffset;
905 if(W+R < q_tick){
906 R = q_tick-W;
908 c=new ResizeNote(p,e,W+R);
909 set_undo(c);
910 N++;
912 e = next;
915 e = p->events->next;
916 while(e){
917 if(e->modified){e->modified=0;}
918 e = e->next;
921 cur_track->restate();
922 undo_push(N);
925 void PianoRoll::apply_lresize(){
926 if(lresize_toffset==0){
927 return;
930 Command* c;
931 mevent* e;
932 mevent* next;
933 pattern* p = cur_seqpat->p;
934 int tmp;
935 int N=0;
937 e = p->events->next;
938 while(e){
939 if(e->type == MIDI_NOTE_ON && e->selected){
940 if(e->tick + lresize_toffset < 0){
941 return;
944 e = e->next;
947 e = p->events->next;
948 while(e){
949 next = e->next;
950 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
951 e->modified = 1;
952 int T = e->tick;
953 int W = e->dur;
954 int R = lresize_toffset;
956 if(R > W-q_tick){
957 R = W-q_tick;
960 mevent* etmp = e->prev;
961 c=new ResizeNote(p,e,W-R);
962 set_undo(c);
964 e = etmp->next;
965 c=new MoveNote(p,e,T+R,e->value1);
966 set_undo(c);
968 N+=2;
970 e = next;
973 e = p->events->next;
974 while(e){
975 if(e->modified){e->modified=0;}
976 e = e->next;
979 cur_track->restate();
980 undo_push(N);
991 int PianoRoll::over_rhandle(mevent* e){
992 int X = event_x()+scrollx;
993 int Y = event_y()+scrolly;
994 int X1 = tick2xpix(e->tick);
995 int X2 = X1 + tick2xpix(e->dur);
996 int Y1 = note2ypix(e->value1);
997 int Y2 = Y1 + 12;
999 if(X2-X1 < resize_handle_width*3){
1000 return 0;
1003 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - resize_handle_width);
1006 int PianoRoll::over_lhandle(mevent* e){
1007 int X = event_x()+scrollx;
1008 int Y = event_y()+scrolly;
1009 int X1 = tick2xpix(e->tick);
1010 int X2 = X1 + tick2xpix(e->dur);
1011 int Y1 = note2ypix(e->value1);
1012 int Y2 = Y1 + 12;
1014 if(X2-X1 < resize_handle_width*3){
1015 return 0;
1018 return (Y > Y1 && Y < Y2 && X < X1+ resize_handle_width +1 && X > X1 + 1);