Added option to disable track init events.
[epichord.git] / src / pianoroll.cpp
blobb15b2891797191a237200c8ffdedcabc7b7fe6db
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_norig = e->value1;
203 move_noffset = 0;
205 last_note = e->value1;
206 if(config.playmove){
207 ui->keyboard->play_note(last_note,0);
208 ui->keyboard->highlight_note(last_note);
213 else if(event_button()==2){//middle mouse
214 //button initiates paste
216 else if(event_button()==3){//right mouse
217 if(e==NULL){
218 unselect_all();
220 ui->event_edit->redraw();
222 else{//set up for deletion
223 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
224 unselect_all();
226 e->selected = 1;
227 delete_flag = 1;
228 resize_arrow_color = fltk::color(120,60,58);
231 redraw();
232 return 1;
233 case fltk::DRAG:
234 ui->keyboard->highlight_clear();
235 if(box_flag){
236 box_x2 = X;
237 box_y2 = Y;
238 box_t2 = xpix2tick(X+scrollx);
239 box_n2 = ypix2note(Y+scrolly,1);
241 else if(insert_flag){
242 insert_toffset = quantize(xpix2tick(X+scrollx)+q_tick) - insert_torig;
243 if(insert_toffset<=0){
244 insert_toffset -= q_tick;
246 insert_note = ypix2note(Y+scrolly,1);
247 if(insert_note != last_note){
248 if(config.playinsert){//play on insert
249 ui->keyboard->release_note(last_note,0);
250 ui->keyboard->play_note(insert_note,0);
252 last_note = insert_note;
255 else if(move_flag){
256 move_toffset = quantize(xpix2tick(X - move_offset)) - move_torig;
257 move_noffset = ypix2note(Y+scrolly,1) - move_norig;
258 int N = move_norig+move_noffset;
259 if(N != last_note){
260 ui->keyboard->highlight_note(N);
261 if(config.playmove){//play on move
262 ui->keyboard->release_note(last_note,0);
263 ui->keyboard->play_note(N,0);
265 last_note = N;
268 else if(rresize_flag){
269 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_tick-rresize_torig;
271 else if(lresize_flag){
272 lresize_toffset = quantize(xpix2tick(X+scrollx)) - lresize_torig;
274 redraw();
275 return 1;
276 case fltk::RELEASE:
277 e = over_note();
278 if(event_button()==1){
279 if(box_flag){
280 apply_box();
281 ui->event_edit->redraw();
282 box_flag=0;
284 else if(rresize_flag){
285 apply_rresize();
286 rresize_flag = 0;
287 resize_arrow = 0;
288 ui->event_edit->redraw();
290 else if(lresize_flag){
291 apply_lresize();
292 lresize_flag = 0;
293 resize_arrow = 0;
294 ui->event_edit->redraw();
296 else if(insert_flag){
297 apply_insert();
299 insert_flag = 0;
301 ui->keyboard->release_note(insert_note,0);
302 ui->keyboard->redraw();
303 ui->event_edit->has[0]=1;
304 ui->event_edit->has[1]=1;
305 ui->event_edit->redraw();
306 ui->event_menu->redraw();
308 else if(move_flag){
309 apply_move();
310 move_flag = 0;
312 midi_track_off(cur_seqpat->track);
313 ui->keyboard->release_note(last_note,0);
314 ui->keyboard->release_note(move_norig+move_noffset,0);
315 ui->keyboard->redraw();
316 ui->event_edit->redraw();
318 insert_flag=0;
319 move_flag=0;
321 if(event_button()==3){
322 mevent* over_n = over_note();
323 if(delete_flag && over_n){
324 if(over_n->selected){
325 apply_delete();
326 midi_track_off(cur_seqpat->track);
327 ui->event_edit->redraw();
330 delete_flag=0;
331 resize_arrow = 0;
333 redraw();
335 return 1;
337 case fltk::MOVE:
338 ui->keyboard->highlight_note(ypix2note(Y+scrolly,1));
339 e = over_note();
340 if(e){
341 if(over_rhandle(e)){
342 if(resize_e != e || resize_arrow != 1){
343 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
344 else{resize_arrow_color = fltk::color(95,58,119);}
345 resize_e = e;
346 resize_arrow = 1;
347 resize_x = tick2xpix(e->tick + e->dur)-scrollx-resize_handle_width;
348 resize_y = note2ypix(e->value1)-scrolly;
349 redraw();
352 else if(over_lhandle(e)){
353 if(resize_e != e || resize_arrow != 1){
354 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
355 else{resize_arrow_color = fltk::color(95,58,119);}
356 resize_e = e;
357 resize_arrow = -1;
358 resize_x = tick2xpix(e->tick)+1 - scrollx;
359 resize_y = note2ypix(e->value1) - scrolly;
360 redraw();
363 else{
364 if(resize_e != e || resize_arrow != 0){
365 resize_e = e;
366 resize_arrow = 0;
367 redraw();
371 else{
372 if(resize_arrow != 0){
373 resize_arrow = 0;
374 redraw();
378 return 1;
381 case fltk::LEAVE:
382 ui->keyboard->highlight_clear();
383 return 1;
385 return 0;
388 void PianoRoll::draw(){
390 fltk::push_clip(0,0,w(),h());
392 fltk::setcolor(fltk::GRAY05);
393 fltk::fillrect(0,0,w(),h());
395 fltk::setcolor(fltk::GRAY20);
396 for(int i=12-scrolly; i<h(); i+=12){
397 if(i>=0){
398 fltk::fillrect(0,i,w(),1);
401 for(int i=zoom-scrollx; i<w(); i+=zoom){
402 if(i>=0){
403 fltk::fillrect(i,0,1,h());
407 fltk::setcolor(fltk::GRAY30);
408 for(int i=12*5-scrolly; i<h(); i+=12*7){
409 if(i>=0){
410 fltk::fillrect(0,i,w(),1);
414 fltk::setcolor(fltk::GRAY50);
415 for(int i=zoom*4-scrollx; i<w(); i+=zoom*4){
416 if(i>=0){
417 fltk::fillrect(i,0,1,h());
421 fltk::setcolor(fltk::WHITE);
422 int M = config.beats_per_measure;
423 for(int i=zoom*4*M-scrollx; i<w(); i+=zoom*4*M){
424 if(i>=0){
425 fltk::fillrect(i,0,1,h());
429 fltk::setcolor(fltk::color(128,0,0));
430 int rightend = tick2xpix(cur_seqpat->dur)-scrollx;
431 if(rightend >=0 && rightend < w()){
432 fltk::fillrect(rightend,0,1,h());
435 fltk::setcolor(fltk::color(128,128,0));
436 fltk::fillrect(0,12*40-scrolly,w(),1);
438 int tmp;
439 if(insert_flag){
440 fltk::setcolor(fltk::BLUE);
441 int T1 = insert_torig;
442 int T2 = T1 + insert_toffset;
443 if(T1>T2){SWAP(T1,T2);}
444 int X = tick2xpix(T1)+1 - scrollx;
445 int Y = note2ypix(insert_note) - scrolly;
446 int W = tick2xpix(T2)-scrollx - X;
447 fltk::fillrect(X,Y,W,11);
450 if(move_flag){
451 fltk::setcolor(fltk::MAGENTA);
452 mevent* ptr = cur_seqpat->p->events->next;
453 while(ptr){
454 if(ptr->type == MIDI_NOTE_ON && ptr->selected){
455 int X = tick2xpix(ptr->tick+move_toffset)+1-scrollx;
456 int Y = note2ypix(ptr->value1+move_noffset)-scrolly;
457 int W = tick2xpix(ptr->dur);
458 fltk::fillrect(X,Y,W-1,1);
459 fltk::fillrect(X,Y+11,W-1,1);
460 fltk::fillrect(X,Y,1,11);
461 fltk::fillrect(X+W-2,Y,1,11);
463 ptr=ptr->next;
469 //draw all notes
470 mevent* e = cur_seqpat->p->events->next;
472 fltk::Color c1,c2,c3;
474 while(e){
475 if(e->type == MIDI_NOTE_ON){
476 //fltk::fillrect(tick2xpix(e->tick),note2ypix(e->value),e->dur,11);
478 int R1 = rresize_flag&&e->selected ? rresize_toffset : 0;
479 int R2 = lresize_flag&&e->selected ? lresize_toffset : 0;
481 int T1 = e->tick + R2;
482 int T2 = e->tick+e->dur + R1;
484 if(T1 >= T2-q_tick && e->selected){
485 if(rresize_flag){
486 T1 = e->tick;
487 T2 = T1 + q_tick;
489 else if(lresize_flag){
490 T2 = e->tick + e->dur;
491 T1 = T2 - q_tick;
495 int X = tick2xpix(T1) + 1 - scrollx;
496 int Y = note2ypix(e->value1) - scrolly;
498 int W = tick2xpix(T2)-scrollx - X;
499 get_event_color(e,&c1,&c2,&c3);
501 if(!(X+W<0 || X > w())){
503 fltk::setcolor(c1);
504 fltk::fillrect(X+1,Y+1,W-1,10);
506 fltk::setcolor(c2);
507 fltk::fillrect(X,Y+11,W,1);
508 fltk::fillrect(X+W-1,Y+1,1,11);
510 fltk::setcolor(c3);
511 fltk::fillrect(X,Y,W,1);
512 fltk::fillrect(X,Y,1,11);
515 e=e->next;
519 if(!rresize_flag && !lresize_flag){
520 if(resize_arrow > 0){
521 setcolor(resize_arrow_color);
523 int W = resize_handle_width;
524 int H = 12;
525 int X = resize_x;
526 int Y = resize_y;
528 addvertex(X,Y);
529 addvertex(X,Y+H);
530 addvertex(X+W,Y+H/2);
531 fillpath();
533 else if(resize_arrow < 0){
534 setcolor(resize_arrow_color);
536 int W = resize_handle_width;
537 int H = 12;
538 int X = resize_x;
539 int Y = resize_y;
541 addvertex(X+W,Y);
542 addvertex(X+W,Y+H);
543 addvertex(X,Y+H/2);
544 fillpath();
549 if(box_flag){
550 fltk::setcolor(fltk::GREEN);
551 int X1,X2,Y1,Y2;
552 if(box_x1>box_x2){
553 X1=box_x2;
554 X2=box_x1;
556 else{
557 X1=box_x1;
558 X2=box_x2;
560 if(box_y1>box_y2){
561 Y1=box_y2;
562 Y2=box_y1;
564 else{
565 Y1=box_y1;
566 Y2=box_y2;
568 fltk::fillrect(X1,Y1,X2-X1,1);
569 fltk::fillrect(X1,Y1,1,Y2-Y1);
570 fltk::fillrect(X2,Y1,1,Y2-Y1);
571 fltk::fillrect(X1,Y2,X2-X1,1);
574 fltk::pop_clip();
580 void PianoRoll::scrollTo(int X, int Y){
582 if(!cur_seqpat){
583 return;
586 if(is_backend_playing() && config.follow){
587 int pos = tick2xpix(get_play_position() - cur_seqpat->tick);
588 if(pos < cur_seqpat->tick){
590 else if(pos < X || pos > X + w() - 30 - 30){
591 ui->pattern_hscroll->value(scrollx);
592 return;
596 scrollx = X;
597 scrolly = Y;
598 cur_seqpat->scrollx = X;
599 cur_seqpat->scrolly = Y;
601 redraw();
602 ui->pattern_hscroll->value(X);
603 ui->pattern_hscroll->redraw();
604 ui->pattern_vscroll->value(Y);
605 ui->pattern_timeline->scroll = X;
606 ui->pattern_timeline->redraw();
607 ui->event_edit->scroll = X;
608 ui->event_edit->redraw();
609 ui->keyboard->scroll = Y;
610 ui->keyboard->redraw();
613 static int kludge=2;
614 void PianoRoll::layout(){
615 if(kludge!=0){
616 kludge--;
617 return;
619 fakeh = 900;
620 if(fakeh<h()){
621 fakeh = h();
624 fltk::Scrollbar* sb = ui->pattern_vscroll;
626 sb->maximum(0);
627 sb->minimum(fakeh-h());
629 if(sb->value() > sb->minimum()){
630 scrollTo(scrollx,900-h());
632 int M = h() - 30;
633 int newsize = M-(fakeh-h());
634 if(newsize<20){
635 newsize=20;
637 ui->song_vscroll->slider_size(60);
640 void PianoRoll::load(seqpat* s){
641 cur_seqpat = s;
642 scrollTo(s->scrollx,s->scrolly);
643 cur_track = tracks[s->track];
644 ui->pattern_timeline->ticks_offset = s->tick;
649 int PianoRoll::note2ypix(int note){
650 int udy = 6*(note + (note+7)/12 + note/12) + 12;
651 return 900 - udy + 1;
654 int PianoRoll::tick2xpix(int tick){
655 return tick*zoom*4 / 128;
658 int PianoRoll::xpix2tick(int xpix){
659 return xpix*128 / (zoom*4);
662 int PianoRoll::quantize(int tick){
663 return tick/q_tick * q_tick;
667 void PianoRoll::set_zoom(int z){
668 zoom = z;
669 relayout();
673 mevent* PianoRoll::over_note(){
674 mevent* e = cur_seqpat->p->events->next;
676 int X = event_x()+scrollx;
677 int Y = event_y()+scrolly;
679 int cy, lx, rx;
680 while(e){
681 if(e->type == MIDI_NOTE_ON){
682 cy = note2ypix(e->value1);
683 lx = tick2xpix(e->tick);
684 rx = tick2xpix(e->tick+e->dur);
685 if(X > lx && X < rx &&
686 Y < cy+12 && Y > cy){
687 return e;
690 e = e->next;
693 return NULL;
698 void PianoRoll::update(int pos){
699 if(!is_backend_playing() || !cur_seqpat){
700 return;
702 if(pos < cur_seqpat->tick){
703 return;
705 int X1 = tick2xpix(pos-cur_seqpat->tick);
706 int X2 = X1 - scrollx;
707 if(X2 < 0){
708 scrollTo(X1-50<0?0:X1-50,scrolly);
710 if(X2 > w()-30){
711 scrollTo(X1-50,scrolly);
716 void PianoRoll::unselect_all(){
717 mevent* e = cur_seqpat->p->events;
718 while(e){
719 if(e->type == MIDI_NOTE_ON && e->selected==1){
720 e->selected = 0;
722 e = e->next;
728 void PianoRoll::get_event_color(mevent* e, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3){
730 int T1,T2;
731 int tmp;
732 if(delete_flag){
733 if(e->selected){
734 *c1 = fltk::color(229,79,75);
735 *c2 = fltk::color(120,60,58);
736 *c3 = fltk::color(225,131,109);
737 return;
741 if(box_flag){
742 T1=box_t1;
743 T2=box_t2;
744 int N1 = box_n1;
745 int N2 = box_n2;
746 int N = e->value1;
747 if(T1>T2){SWAP(T1,T2);}
748 if(N1<N2){SWAP(N1,N2);}
749 if(e->tick+e->dur > T1 && e->tick < T2 && N >= N2 && N <= N1){
750 *c1 = fltk::color(108,229,75);
751 *c2 = fltk::color(71,120,59);
752 *c3 = fltk::color(108,229,75);
753 return;
757 if(e->selected){
758 *c1 = fltk::color(255,248,47);
759 *c2 = fltk::color(140,137,46);
760 *c3 = fltk::color(232,255,37);
761 return;
764 *c1 = fltk::color(169,75,229);
765 *c2 = fltk::color(95,58,119);
766 *c3 = fltk::color(198,109,225);
770 void PianoRoll::apply_box(){
771 mevent* e = cur_seqpat->p->events->next;
772 int tmp;
773 int T1=box_t1;
774 int T2=box_t2;
775 int N1 = box_n1;
776 int N2 = box_n2;
778 if(T1>T2){SWAP(T1,T2);}
779 if(N1<N2){SWAP(N1,N2);}
780 while(e){
781 int N = e->value1;
782 if(e->type == MIDI_NOTE_ON &&
783 e->tick+e->dur > T1 && e->tick < T2 &&
784 N >= N2 && N <= N1){
785 e->selected = 1;
787 e = e->next;
791 void PianoRoll::apply_insert(){
792 if(insert_note > 127 || insert_note < 0){
793 return;
796 int tmp;
797 int T1 = insert_torig;
798 int T2 = T1 + insert_toffset;
799 if(T1>T2){SWAP(T1,T2);}
801 if(T1 < 0){
802 return;
805 pattern* p = cur_seqpat->p;
806 Command* c=new CreateNote(p,insert_note,config.defaultvelocity,T1,T2-T1);
807 set_undo(c);
808 undo_push(1);
810 cur_track->restate();
813 void PianoRoll::apply_delete(){
814 Command* c;
815 mevent* e;
816 mevent* next;
817 pattern* p = cur_seqpat->p;
818 int N=0;
820 e = cur_seqpat->p->events->next;
821 while(e){
822 next = e->next;
823 if(e->selected && e->type == MIDI_NOTE_ON){
824 c=new DeleteNote(p,e);
825 set_undo(c);
826 N++;
828 e = next;
830 undo_push(N);
832 cur_track->restate();
835 void PianoRoll::apply_move(){
836 if(move_toffset==0 && move_noffset==0){
837 return;
840 pattern* p = cur_seqpat->p;
841 mevent* e = p->events->next;
842 while(e){
843 int K = e->value1+move_noffset;
844 int T = e->tick+move_toffset;
845 if(e->type == MIDI_NOTE_ON && e->selected && (T<0 || K < 0 || K > 127)){
846 return;
848 e = e->next;
852 Command* c;
853 e = p->events->next;
855 mevent* next;
856 int M=0;
857 for(int i=0; i<tracks.size(); i++){
858 e = p->events->next;
859 while(e){
860 next = e->next;
861 if(e->selected && e->modified == 0){
862 int K = e->value1 + move_noffset;
863 int T = e->tick + move_toffset;
864 e->modified = 1;
865 c=new MoveNote(p,e,T,K);
866 set_undo(c);
867 M++;
869 e = next;
872 undo_push(M);
874 e = p->events->next;
875 while(e){
876 if(e->modified){e->modified=0;}
877 e = e->next;
880 cur_track->restate();
883 void PianoRoll::apply_paste(){
889 void PianoRoll::apply_rresize(){
890 if(rresize_toffset==0){
891 return;
894 Command* c;
895 mevent* e;
896 mevent* next;
897 pattern* p = cur_seqpat->p;
898 int tmp;
899 int N=0;
901 e = p->events->next;
902 while(e){
903 next = e->next;
904 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
905 e->modified = 1;
906 int W = e->dur;
907 int R = rresize_toffset;
908 if(W+R < q_tick){
909 R = q_tick-W;
911 c=new ResizeNote(p,e,W+R);
912 set_undo(c);
913 N++;
915 e = next;
918 e = p->events->next;
919 while(e){
920 if(e->modified){e->modified=0;}
921 e = e->next;
924 cur_track->restate();
925 undo_push(N);
928 void PianoRoll::apply_lresize(){
929 if(lresize_toffset==0){
930 return;
933 Command* c;
934 mevent* e;
935 mevent* next;
936 pattern* p = cur_seqpat->p;
937 int tmp;
938 int N=0;
940 e = p->events->next;
941 while(e){
942 if(e->type == MIDI_NOTE_ON && e->selected){
943 if(e->tick + lresize_toffset < 0){
944 return;
947 e = e->next;
950 e = p->events->next;
951 while(e){
952 next = e->next;
953 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
954 e->modified = 1;
955 int T = e->tick;
956 int W = e->dur;
957 int R = lresize_toffset;
959 if(R > W-q_tick){
960 R = W-q_tick;
963 mevent* etmp = e->prev;
964 c=new ResizeNote(p,e,W-R);
965 set_undo(c);
967 e = etmp->next;
968 c=new MoveNote(p,e,T+R,e->value1);
969 set_undo(c);
971 N+=2;
973 e = next;
976 e = p->events->next;
977 while(e){
978 if(e->modified){e->modified=0;}
979 e = e->next;
982 cur_track->restate();
983 undo_push(N);
994 int PianoRoll::over_rhandle(mevent* e){
995 int X = event_x()+scrollx;
996 int Y = event_y()+scrolly;
997 int X1 = tick2xpix(e->tick);
998 int X2 = X1 + tick2xpix(e->dur);
999 int Y1 = note2ypix(e->value1);
1000 int Y2 = Y1 + 12;
1002 if(X2-X1 < resize_handle_width*3){
1003 return 0;
1006 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - resize_handle_width);
1009 int PianoRoll::over_lhandle(mevent* e){
1010 int X = event_x()+scrollx;
1011 int Y = event_y()+scrolly;
1012 int X1 = tick2xpix(e->tick);
1013 int X2 = X1 + tick2xpix(e->dur);
1014 int Y1 = note2ypix(e->value1);
1015 int Y2 = Y1 + 12;
1017 if(X2-X1 < resize_handle_width*3){
1018 return 0;
1021 return (Y > Y1 && Y < Y2 && X < X1+ resize_handle_width +1 && X > X1 + 1);