Fixed three bugs in event editor.
[epichord.git] / src / pianoroll.cpp
blob06c95dbceb807566ac636315f71450d03935dc5c
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 = TICKS_PER_BEAT/4;
60 box_flag = 0;
62 trip_flag = 0;
64 move_toffset = 0;
66 insert_flag = 0;
67 move_flag = 0;
68 delete_flag=0;
69 lresize_flag = 0;
70 rresize_flag = 0;
72 resize_arrow = 0;
73 resize_e = NULL;
74 resize_handle_width = 4;
76 fakeh = wkeyh*75;
77 fakehmin = wkeyh*75;
78 if(fakeh < h){fakeh = h;}
80 scrollx=0;
81 scrolly=0;
84 int PianoRoll::handle(int event){
85 Command* c;
86 pattern* p;
87 mevent* e;
89 int X = event_x();
90 int Y = event_y();
91 int yprime;
92 int prevt;
94 switch(event){
95 case fltk::ENTER:
96 return 1;
97 case fltk::FOCUS:
98 return 1;
99 case fltk::MOUSEWHEEL:
100 yprime = scrolly+32*event_dy();
101 if(yprime<0){yprime=0;}
102 if(yprime>75*12 - h()){yprime = 75*12 - h();}
103 scrollTo(scrollx,yprime);
104 return 1;
105 case fltk::SHORTCUT:
106 if(event_key()==fltk::DeleteKey){
107 apply_delete();
108 delete_flag = 0;
109 redraw();
110 resize_arrow = 0;
111 ui->event_edit->redraw();
112 return 1;
114 if(event_state(CTRL) && event_key()=='c'){
115 //printf("roll copy\n");
116 return 1;
118 if(zoom_out_key(event_key(),event_state())){
119 if(zoom_n > 1){
120 prevt = xpix2tick(scrollx);
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 scrollTo(tick2xpix(prevt),scrolly);
128 //ui->event_edit->redraw();
130 redraw();
131 return 1;
133 if(zoom_in_key(event_key(),event_state())){
134 if(zoom_n < 8){
135 prevt = xpix2tick(scrollx);
136 zoom_n++;
137 set_zoom(30*(1<<zoom_n)/16);
138 ui->pattern_timeline->zoom = zoom;
139 //ui->pattern_timeline->update(get_play_position());
140 //ui->pattern_timeline->redraw();
141 ui->event_edit->zoom = zoom;
142 scrollTo(tick2xpix(prevt),scrolly);
143 //ui->event_edit->redraw();
145 redraw();
146 return 1;
148 return 0;
149 case fltk::PUSH:
150 take_focus();
151 e = over_note();
152 if(event_button()==1){//left mouse
153 if(e==NULL){//new note init
154 if(event_state()&fltk::SHIFT){//begin box
155 box_flag = 1;
156 box_x1=X;
157 box_x2=X;
158 box_y1=Y;
159 box_y2=Y;
160 box_t1=xpix2tick(X+scrollx);
161 box_t2=box_t1;
162 box_n1=ypix2note(Y+scrolly,1);
163 box_n2=box_n1;
165 else{//begin insert
166 insert_flag = 1;
167 insert_torig = quantize(xpix2tick(X+scrollx));
168 if(trip_flag){
169 insert_toffset = (q_tick*4) / 3;
171 else{
172 insert_toffset = q_tick;
174 //new_orig_t = new_left_t;
175 insert_note = ypix2note(Y+scrolly,1);
177 last_note = insert_note;
178 if(config.playinsert){
179 ui->keyboard->play_note(last_note,0);
184 else{
186 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
187 unselect_all();
189 e->selected = 1;
190 ui->event_edit->select_flag = 1;
191 resize_arrow_color = fltk::color(128,128,0);
193 if(over_rhandle(e)){//resize
194 rresize_flag = 1;
195 rresize_torig = e->tick+e->dur;
196 rresize_toffset = 0;
198 else if(over_lhandle(e)){//resize move
199 lresize_flag = 1;
200 lresize_torig = e->tick;
201 lresize_toffset = 0;
203 else{//begin move
204 move_flag = 1;
206 move_torig = e->tick;
207 move_qoffset = e->tick - quantize(e->tick);
209 move_toffset = -move_qoffset;
211 //move_offset = quantize(xpix2tick(X)) - move_torig - move_qoffset;
212 //move_toffset = 0;
213 move_offset = X - tick2xpix(e->tick);
214 //move_norig = ypix2note(Y+scrolly,1);
215 move_norig = e->value1;
216 move_noffset = 0;
218 last_note = e->value1;
219 if(config.playmove){
220 ui->keyboard->play_note(last_note,0);
221 ui->keyboard->highlight_note(last_note);
226 else if(event_button()==2){//middle mouse
227 //button initiates paste
229 else if(event_button()==3){//right mouse
230 if(e==NULL){
231 unselect_all();
232 ui->event_edit->redraw();
234 else{//set up for deletion
235 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
236 unselect_all();
238 e->selected = 1;
239 delete_flag = 1;
240 resize_arrow_color = fltk::color(120,60,58);
242 ui->event_edit->select_flag = 0;
244 redraw();
245 return 1;
246 case fltk::DRAG:
248 ui->keyboard->highlight_clear();
249 if(box_flag){
250 box_x2 = X;
251 box_y2 = Y;
252 box_t2 = xpix2tick(X+scrollx);
253 box_n2 = ypix2note(Y+scrolly,1);
255 else if(insert_flag){
256 if(trip_flag){
257 int q_trip = (q_tick*4) / 3;
258 insert_toffset = quantize(xpix2tick(X+scrollx)+q_trip) - insert_torig;
259 if(insert_toffset<=0){
260 insert_toffset -= q_trip;
263 else{
264 insert_toffset = quantize(xpix2tick(X+scrollx)+q_tick) - insert_torig;
265 if(insert_toffset<=0){
266 insert_toffset -= q_tick;
269 insert_note = ypix2note(Y+scrolly,1);
270 if(insert_note != last_note){
271 if(config.playinsert){//play on insert
272 ui->keyboard->release_note(last_note,0);
273 ui->keyboard->play_note(insert_note,0);
275 last_note = insert_note;
278 else if(move_flag){
279 move_toffset = quantize(xpix2tick(X - move_offset)) - move_torig;
280 move_noffset = ypix2note(Y+scrolly,1) - move_norig;
281 int N = move_norig+move_noffset;
282 if(N != last_note){
283 ui->keyboard->highlight_note(N);
284 if(config.playmove){//play on move
285 ui->keyboard->release_note(last_note,0);
286 ui->keyboard->play_note(N,0);
288 last_note = N;
291 else if(rresize_flag){
292 if(trip_flag){
293 int q_trip = (q_tick*4) / 3;
294 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_trip-rresize_torig;
296 else{
297 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_tick-rresize_torig;
300 else if(lresize_flag){
301 lresize_toffset = quantize(xpix2tick(X+scrollx)) - lresize_torig;
303 redraw();
304 return 1;
305 case fltk::RELEASE:
306 e = over_note();
307 if(event_button()==1){
308 if(box_flag){
309 apply_box();
310 ui->event_edit->redraw();
311 box_flag=0;
313 else if(rresize_flag){
314 apply_rresize();
315 rresize_flag = 0;
316 resize_arrow = 0;
317 ui->event_edit->redraw();
319 else if(lresize_flag){
320 apply_lresize();
321 lresize_flag = 0;
322 resize_arrow = 0;
323 ui->event_edit->redraw();
325 else if(insert_flag){
326 apply_insert();
328 insert_flag = 0;
330 ui->keyboard->release_note(insert_note,0);
331 ui->keyboard->redraw();
332 ui->event_edit->has[0]=1;
333 ui->event_edit->has[1]=1;
334 ui->event_edit->redraw();
335 ui->event_menu->redraw();
337 else if(move_flag){
338 apply_move();
339 move_flag = 0;
341 midi_track_off(cur_seqpat->track);
342 ui->keyboard->release_note(last_note,0);
343 ui->keyboard->release_note(move_norig+move_noffset,0);
344 ui->keyboard->redraw();
345 ui->event_edit->redraw();
347 insert_flag=0;
348 move_flag=0;
350 if(event_button()==3){
351 mevent* over_n = over_note();
352 if(delete_flag && over_n){
353 if(over_n->selected){
354 apply_delete();
355 midi_track_off(cur_seqpat->track);
356 ui->event_edit->redraw();
359 delete_flag=0;
360 resize_arrow = 0;
362 redraw();
364 return 1;
366 case fltk::MOVE:
367 ui->keyboard->highlight_note(ypix2note(Y+scrolly,1));
368 e = over_note();
369 if(e){
370 if(over_rhandle(e)){
371 if(resize_e != e || resize_arrow != 1){
372 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
373 else{resize_arrow_color = fltk::color(95,58,119);}
374 resize_e = e;
375 resize_arrow = 1;
376 resize_x = tick2xpix(e->tick + e->dur)-scrollx-resize_handle_width;
377 resize_y = note2ypix(e->value1)-scrolly;
378 redraw();
381 else if(over_lhandle(e)){
382 if(resize_e != e || resize_arrow != 1){
383 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
384 else{resize_arrow_color = fltk::color(95,58,119);}
385 resize_e = e;
386 resize_arrow = -1;
387 resize_x = tick2xpix(e->tick)+1 - scrollx;
388 resize_y = note2ypix(e->value1) - scrolly;
389 redraw();
392 else{
393 if(resize_e != e || resize_arrow != 0){
394 resize_e = e;
395 resize_arrow = 0;
396 redraw();
400 else{
401 if(resize_arrow != 0){
402 resize_arrow = 0;
403 redraw();
407 return 1;
410 case fltk::LEAVE:
411 ui->keyboard->highlight_clear();
412 return 1;
414 return 0;
417 void PianoRoll::draw(){
419 fltk::push_clip(0,0,w(),h());
421 fltk::setcolor(fltk::GRAY05);
422 fltk::fillrect(0,0,w(),h());
424 fltk::setcolor(fltk::GRAY20);
425 for(int i=12-scrolly; i<h(); i+=12){
426 if(i>=0){
427 fltk::fillrect(0,i,w(),1);
430 for(int i=zoom-scrollx; i<w(); i+=zoom){
431 if(i>=0){
432 fltk::fillrect(i,0,1,h());
436 fltk::setcolor(fltk::GRAY30);
437 for(int i=12*5-scrolly; i<h(); i+=12*7){
438 if(i>=0){
439 fltk::fillrect(0,i,w(),1);
443 fltk::setcolor(fltk::GRAY50);
444 for(int i=zoom*4-scrollx; i<w(); i+=zoom*4){
445 if(i>=0){
446 fltk::fillrect(i,0,1,h());
450 fltk::setcolor(fltk::WHITE);
451 int M = config.beats_per_measure;
452 for(int i=zoom*4*M-scrollx; i<w(); i+=zoom*4*M){
453 if(i>=0){
454 fltk::fillrect(i,0,1,h());
458 fltk::setcolor(fltk::color(128,0,0));
459 int rightend = tick2xpix(cur_seqpat->dur)-scrollx;
460 if(rightend >=0 && rightend < w()){
461 fltk::fillrect(rightend,0,1,h());
464 fltk::setcolor(fltk::color(128,128,0));
465 fltk::fillrect(0,12*40-scrolly,w(),1);
467 int tmp;
468 if(insert_flag){
469 fltk::setcolor(fltk::BLUE);
470 int T1 = insert_torig;
471 int T2 = T1 + insert_toffset;
472 if(T1>T2){SWAP(T1,T2);}
473 int X = tick2xpix(T1)+1 - scrollx;
474 int Y = note2ypix(insert_note) - scrolly;
475 int W = tick2xpix(T2)-scrollx - X;
476 fltk::fillrect(X,Y,W,11);
479 if(move_flag){
480 fltk::setcolor(fltk::MAGENTA);
481 mevent* ptr = cur_seqpat->p->events->next;
482 while(ptr){
483 if(ptr->type == MIDI_NOTE_ON && ptr->selected){
484 int X = tick2xpix(ptr->tick+move_toffset)+1-scrollx;
485 int Y = note2ypix(ptr->value1+move_noffset)-scrolly;
486 int W = tick2xpix(ptr->dur);
487 fltk::fillrect(X,Y,W-1,1);
488 fltk::fillrect(X,Y+11,W-1,1);
489 fltk::fillrect(X,Y,1,11);
490 fltk::fillrect(X+W-2,Y,1,11);
492 ptr=ptr->next;
498 //draw all notes
499 mevent* e = cur_seqpat->p->events->next;
501 fltk::Color c1,c2,c3;
503 while(e){
504 if(e->type == MIDI_NOTE_ON){
505 //fltk::fillrect(tick2xpix(e->tick),note2ypix(e->value),e->dur,11);
507 int R1 = rresize_flag&&e->selected ? rresize_toffset : 0;
508 int R2 = lresize_flag&&e->selected ? lresize_toffset : 0;
510 int T1 = e->tick + R2;
511 int T2 = e->tick+e->dur + R1;
513 if(T1 >= T2-q_tick && e->selected){
514 if(rresize_flag){
515 T1 = e->tick;
516 T2 = T1 + q_tick;
518 else if(lresize_flag){
519 T2 = e->tick + e->dur;
520 T1 = T2 - q_tick;
524 int X = tick2xpix(T1) + 1 - scrollx;
525 int Y = note2ypix(e->value1) - scrolly;
527 int W = tick2xpix(T2)-scrollx - X;
528 get_event_color(e,&c1,&c2,&c3);
530 if(!(X+W<0 || X > w())){
532 fltk::setcolor(c1);
533 fltk::fillrect(X+1,Y+1,W-1,10);
535 fltk::setcolor(c2);
536 fltk::fillrect(X,Y+11,W,1);
537 fltk::fillrect(X+W-1,Y+1,1,11);
539 fltk::setcolor(c3);
540 fltk::fillrect(X,Y,W,1);
541 fltk::fillrect(X,Y,1,11);
544 e=e->next;
548 if(!rresize_flag && !lresize_flag){
549 if(resize_arrow > 0){
550 setcolor(resize_arrow_color);
552 int W = resize_handle_width;
553 int H = 12;
554 int X = resize_x;
555 int Y = resize_y;
557 addvertex(X,Y);
558 addvertex(X,Y+H);
559 addvertex(X+W,Y+H/2);
560 fillpath();
562 else if(resize_arrow < 0){
563 setcolor(resize_arrow_color);
565 int W = resize_handle_width;
566 int H = 12;
567 int X = resize_x;
568 int Y = resize_y;
570 addvertex(X+W,Y);
571 addvertex(X+W,Y+H);
572 addvertex(X,Y+H/2);
573 fillpath();
578 if(box_flag){
579 fltk::setcolor(fltk::GREEN);
580 int X1,X2,Y1,Y2;
581 if(box_x1>box_x2){
582 X1=box_x2;
583 X2=box_x1;
585 else{
586 X1=box_x1;
587 X2=box_x2;
589 if(box_y1>box_y2){
590 Y1=box_y2;
591 Y2=box_y1;
593 else{
594 Y1=box_y1;
595 Y2=box_y2;
597 fltk::fillrect(X1,Y1,X2-X1,1);
598 fltk::fillrect(X1,Y1,1,Y2-Y1);
599 fltk::fillrect(X2,Y1,1,Y2-Y1);
600 fltk::fillrect(X1,Y2,X2-X1,1);
603 fltk::pop_clip();
609 void PianoRoll::scrollTo(int X, int Y){
611 if(!cur_seqpat){
612 return;
615 if(is_backend_playing() && config.follow){
616 int pos = tick2xpix(get_play_position() - cur_seqpat->tick);
617 if(pos < cur_seqpat->tick){
619 else if(pos < X || pos > X + w() - 30 - 30){
620 ui->pattern_hscroll->value(scrollx);
621 return;
625 scrollx = X;
626 scrolly = Y;
627 cur_seqpat->scrollx = X;
628 cur_seqpat->scrolly = Y;
630 redraw();
631 ui->pattern_hscroll->value(X);
632 ui->pattern_hscroll->redraw();
633 ui->pattern_vscroll->value(Y);
634 ui->pattern_timeline->scroll = X;
635 ui->pattern_timeline->redraw();
636 ui->event_edit->scroll = X;
637 ui->event_edit->redraw();
638 ui->keyboard->scroll = Y;
639 ui->keyboard->redraw();
642 static int kludge=2;
643 void PianoRoll::layout(){
644 if(kludge!=0){
645 kludge--;
646 return;
648 fakeh = 900;
649 if(fakeh<h()){
650 fakeh = h();
653 fltk::Scrollbar* sb = ui->pattern_vscroll;
655 sb->maximum(0);
656 sb->minimum(fakeh-h());
658 if(sb->value() > sb->minimum()){
659 scrollTo(scrollx,900-h());
661 int M = h() - 30;
662 int newsize = M-(fakeh-h());
663 if(newsize<20){
664 newsize=20;
666 ui->song_vscroll->slider_size(60);
669 void PianoRoll::load(seqpat* s){
670 cur_seqpat = s;
671 scrollTo(s->scrollx,s->scrolly);
672 cur_track = tracks[s->track];
673 ui->pattern_timeline->ticks_offset = s->tick;
678 int PianoRoll::note2ypix(int note){
679 int udy = 6*(note + (note+7)/12 + note/12) + 12;
680 return 900 - udy + 1;
683 int PianoRoll::tick2xpix(int tick){
684 return tick*zoom*4 / TICKS_PER_BEAT;
687 int PianoRoll::xpix2tick(int xpix){
688 return xpix*TICKS_PER_BEAT / (zoom*4);
691 int PianoRoll::quantize(int tick){
692 if(trip_flag){
693 int T = (q_tick*4) / 3;
694 int P = tick/(q_tick*4) * (q_tick*4);
695 int Q = (tick%(q_tick*4));
696 return P + Q / T * T;
698 else{
699 return tick/(q_tick) * q_tick;
704 void PianoRoll::set_zoom(int z){
705 zoom = z;
706 relayout();
710 mevent* PianoRoll::over_note(){
711 mevent* e = cur_seqpat->p->events->next;
713 int X = event_x()+scrollx;
714 int Y = event_y()+scrolly;
716 int cy, lx, rx;
717 while(e){
718 if(e->type == MIDI_NOTE_ON){
719 cy = note2ypix(e->value1);
720 lx = tick2xpix(e->tick);
721 rx = tick2xpix(e->tick+e->dur);
722 if(X > lx && X < rx &&
723 Y < cy+12 && Y > cy){
724 return e;
727 e = e->next;
730 return NULL;
735 void PianoRoll::update(int pos){
736 if(!is_backend_playing() || !cur_seqpat){
737 return;
739 if(pos < cur_seqpat->tick){
740 return;
742 int X1 = tick2xpix(pos-cur_seqpat->tick);
743 int X2 = X1 - scrollx;
744 if(X2 < 0){
745 scrollTo(X1-50<0?0:X1-50,scrolly);
747 if(X2 > w()-30){
748 scrollTo(X1-50,scrolly);
753 void PianoRoll::unselect_all(){
754 mevent* e = cur_seqpat->p->events;
755 while(e){
756 if(e->type == MIDI_NOTE_ON && e->selected==1){
757 e->selected = 0;
759 e = e->next;
765 void PianoRoll::get_event_color(mevent* e, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3){
767 int T1,T2;
768 int tmp;
769 if(delete_flag){
770 if(e->selected){
771 *c1 = fltk::color(229,79,75);
772 *c2 = fltk::color(120,60,58);
773 *c3 = fltk::color(225,131,109);
774 return;
778 if(box_flag){
779 T1=box_t1;
780 T2=box_t2;
781 int N1 = box_n1;
782 int N2 = box_n2;
783 int N = e->value1;
784 if(T1>T2){SWAP(T1,T2);}
785 if(N1<N2){SWAP(N1,N2);}
786 if(e->tick+e->dur > T1 && e->tick < T2 && N >= N2 && N <= N1){
787 *c1 = fltk::color(108,229,75);
788 *c2 = fltk::color(71,120,59);
789 *c3 = fltk::color(108,229,75);
790 return;
794 if(e->selected){
795 *c1 = fltk::color(255,248,47);
796 *c2 = fltk::color(140,137,46);
797 *c3 = fltk::color(232,255,37);
798 return;
801 *c1 = fltk::color(169,75,229);
802 *c2 = fltk::color(95,58,119);
803 *c3 = fltk::color(198,109,225);
807 void PianoRoll::apply_box(){
808 mevent* e = cur_seqpat->p->events->next;
809 int tmp;
810 int T1=box_t1;
811 int T2=box_t2;
812 int N1 = box_n1;
813 int N2 = box_n2;
815 if(T1>T2){SWAP(T1,T2);}
816 if(N1<N2){SWAP(N1,N2);}
817 while(e){
818 int N = e->value1;
819 if(e->type == MIDI_NOTE_ON &&
820 e->tick+e->dur > T1 && e->tick < T2 &&
821 N >= N2 && N <= N1){
822 ui->event_edit->select_flag = 1;
823 e->selected = 1;
825 e = e->next;
830 void PianoRoll::apply_insert(){
831 if(insert_note > 127 || insert_note < 0){
832 return;
835 int tmp;
836 int T1 = insert_torig;
837 int T2 = T1 + insert_toffset;
838 if(T1>T2){SWAP(T1,T2);}
840 if(T1 < 0){
841 return;
844 pattern* p = cur_seqpat->p;
845 Command* c=new CreateNote(p,insert_note,config.defaultvelocity,T1,T2-T1);
846 set_undo(c);
847 undo_push(1);
849 cur_track->restate();
852 void PianoRoll::apply_delete(){
853 Command* c;
854 mevent* e;
855 mevent* next;
856 pattern* p = cur_seqpat->p;
857 int N=0;
859 e = cur_seqpat->p->events->next;
860 while(e){
861 next = e->next;
862 if(e->selected && e->type == MIDI_NOTE_ON){
863 c=new DeleteNote(p,e);
864 set_undo(c);
865 N++;
867 e = next;
869 undo_push(N);
871 cur_track->restate();
874 void PianoRoll::apply_move(){
875 if(move_toffset==0 && move_noffset==0){
876 return;
879 pattern* p = cur_seqpat->p;
880 mevent* e = p->events->next;
881 while(e){
882 int K = e->value1+move_noffset;
883 int T = e->tick+move_toffset;
884 if(e->type == MIDI_NOTE_ON && e->selected && (T<0 || K < 0 || K > 127)){
885 return;
887 e = e->next;
891 Command* c;
892 e = p->events->next;
894 mevent* next;
895 int M=0;
896 for(int i=0; i<tracks.size(); i++){
897 e = p->events->next;
898 while(e){
899 next = e->next;
900 if(e->selected && e->modified == 0){
901 int K = e->value1 + move_noffset;
902 int T = e->tick + move_toffset;
903 e->modified = 1;
904 c=new MoveNote(p,e,T,K);
905 set_undo(c);
906 M++;
908 e = next;
911 undo_push(M);
913 e = p->events->next;
914 while(e){
915 if(e->modified){e->modified=0;}
916 e = e->next;
919 cur_track->restate();
922 void PianoRoll::apply_paste(){
928 void PianoRoll::apply_rresize(){
929 if(rresize_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 next = e->next;
943 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
944 e->modified = 1;
945 int W = e->dur;
946 int R = rresize_toffset;
947 if(W+R < q_tick){
948 R = q_tick-W;
950 c=new ResizeNote(p,e,W+R);
951 set_undo(c);
952 N++;
954 e = next;
957 e = p->events->next;
958 while(e){
959 if(e->modified){e->modified=0;}
960 e = e->next;
963 cur_track->restate();
964 undo_push(N);
967 void PianoRoll::apply_lresize(){
968 if(lresize_toffset==0){
969 return;
972 Command* c;
973 mevent* e;
974 mevent* next;
975 pattern* p = cur_seqpat->p;
976 int tmp;
977 int N=0;
979 e = p->events->next;
980 while(e){
981 if(e->type == MIDI_NOTE_ON && e->selected){
982 if(e->tick + lresize_toffset < 0){
983 return;
986 e = e->next;
989 e = p->events->next;
990 while(e){
991 next = e->next;
992 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
993 e->modified = 1;
994 int T = e->tick;
995 int W = e->dur;
996 int R = lresize_toffset;
998 if(R > W-q_tick){
999 R = W-q_tick;
1002 mevent* etmp = e->prev;
1003 c=new ResizeNote(p,e,W-R);
1004 set_undo(c);
1006 e = etmp->next;
1007 c=new MoveNote(p,e,T+R,e->value1);
1008 set_undo(c);
1010 N+=2;
1012 e = next;
1015 e = p->events->next;
1016 while(e){
1017 if(e->modified){e->modified=0;}
1018 e = e->next;
1021 cur_track->restate();
1022 undo_push(N);
1033 int PianoRoll::over_rhandle(mevent* e){
1034 int X = event_x()+scrollx;
1035 int Y = event_y()+scrolly;
1036 int X1 = tick2xpix(e->tick);
1037 int X2 = X1 + tick2xpix(e->dur);
1038 int Y1 = note2ypix(e->value1);
1039 int Y2 = Y1 + 12;
1041 if(X2-X1 < resize_handle_width*3){
1042 return 0;
1045 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - resize_handle_width);
1048 int PianoRoll::over_lhandle(mevent* e){
1049 int X = event_x()+scrollx;
1050 int Y = event_y()+scrolly;
1051 int X1 = tick2xpix(e->tick);
1052 int X2 = X1 + tick2xpix(e->dur);
1053 int Y1 = note2ypix(e->value1);
1054 int Y2 = Y1 + 12;
1056 if(X2-X1 < resize_handle_width*3){
1057 return 0;
1060 return (Y > Y1 && Y < Y2 && X < X1+ resize_handle_width +1 && X > X1 + 1);