Mouse wheel now scrolls horizontally in piano roll.
[epichord.git] / src / pianoroll.cpp
blobc4d365913cf6cd7ad70d350040c53807383a85d7
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/Cursor.h>
31 #include <fltk/events.h>
33 #include <stdio.h>
34 #include <unistd.h>
35 #include "ui.h"
37 #include "util.h"
39 #include "backend.h"
41 #include "uihelper.h"
43 extern UI* ui;
44 extern std::vector<track*> tracks;
46 extern struct conf config;
48 using namespace fltk;
50 #define SWAP(X,Y) tmp=X; X=Y; Y=tmp;
52 PianoRoll::PianoRoll(int x, int y, int w, int h, const char* label = 0) : fltk::Widget(x, y, w, h, label) {
53 wkeyh = 12;
54 bkeyh = 7;
55 cur_seqpat = NULL;
57 zoom = 15;
58 zoom_n = 3;
60 q_tick = TICKS_PER_BEAT/4;
62 box_flag = 0;
64 trip_flag = 0;
66 move_toffset = 0;
68 insert_flag = 0;
69 move_flag = 0;
70 delete_flag=0;
71 lresize_flag = 0;
72 rresize_flag = 0;
74 resize_arrow = 0;
75 resize_e = NULL;
76 resize_handle_width = 4;
78 fakeh = wkeyh*75;
79 fakehmin = wkeyh*75;
80 if(fakeh < h){fakeh = h;}
82 scrollx=0;
83 scrolly=0;
86 int PianoRoll::handle(int event){
87 Command* c;
88 pattern* p;
89 mevent* e;
91 int X = event_x();
92 int Y = event_y();
93 int yprime;
94 int xprime;
95 int prevt;
97 switch(event){
98 case fltk::ENTER:
99 return 1;
100 case fltk::FOCUS:
101 return 1;
102 case fltk::MOUSEWHEEL:
103 /*yprime = scrolly+32*event_dy();
104 if(yprime<0){yprime=0;}
105 if(yprime>75*12 - h()){yprime = 75*12 - h();}
106 scrollTo(scrollx,yprime);*/
108 xprime = scrollx+128*event_dy();
109 if(xprime < 0){xprime = 0;}
110 scrollTo(xprime,scrolly);
112 return 1;
113 case fltk::SHORTCUT:
114 if(event_key()==fltk::DeleteKey){
115 apply_delete();
116 delete_flag = 0;
117 redraw();
118 resize_arrow = 0;
119 cursor(fltk::CURSOR_DEFAULT);
120 ui->event_edit->redraw();
121 return 1;
123 if(event_state(CTRL) && event_key()=='c'){
124 //printf("roll copy\n");
125 return 1;
127 if(zoom_out_key(event_key(),event_state())){
128 if(zoom_n > 1){
129 prevt = xpix2tick(scrollx);
130 zoom_n--;
131 set_zoom(30*(1<<zoom_n)/16);
132 ui->pattern_timeline->zoom = zoom;
133 //ui->pattern_timeline->update(get_play_position());
134 //ui->pattern_timeline->redraw();
135 ui->event_edit->zoom = zoom;
136 scrollTo(tick2xpix(prevt),scrolly);
137 //ui->event_edit->redraw();
139 redraw();
140 return 1;
142 if(zoom_in_key(event_key(),event_state())){
143 if(zoom_n < 8){
144 prevt = xpix2tick(scrollx);
145 zoom_n++;
146 set_zoom(30*(1<<zoom_n)/16);
147 ui->pattern_timeline->zoom = zoom;
148 //ui->pattern_timeline->update(get_play_position());
149 //ui->pattern_timeline->redraw();
150 ui->event_edit->zoom = zoom;
151 scrollTo(tick2xpix(prevt),scrolly);
152 //ui->event_edit->redraw();
154 redraw();
155 return 1;
157 return 0;
158 case fltk::PUSH:
159 take_focus();
160 e = over_note();
161 if(event_button()==1){//left mouse
162 if(e==NULL){//new note init
163 if(event_state()&fltk::SHIFT){//begin box
164 box_flag = 1;
165 box_x1=X;
166 box_x2=X;
167 box_y1=Y;
168 box_y2=Y;
169 box_t1=xpix2tick(X+scrollx);
170 box_t2=box_t1;
171 box_n1=ypix2note(Y+scrolly,1);
172 box_n2=box_n1;
174 else{//begin insert
175 insert_flag = 1;
176 insert_torig = quantize(xpix2tick(X+scrollx));
177 if(trip_flag){
178 insert_toffset = (q_tick*2) / 3;
180 else{
181 insert_toffset = q_tick;
183 //new_orig_t = new_left_t;
184 insert_note = ypix2note(Y+scrolly,1);
186 last_note = insert_note;
187 if(config.playinsert){
188 ui->keyboard->play_note(last_note,0);
193 else{
195 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
196 unselect_all();
198 e->selected = 1;
199 ui->event_edit->select_flag = 1;
200 resize_arrow_color = fltk::color(128,128,0);
202 if(over_rhandle(e)){//resize
203 rresize_flag = 1;
204 rresize_torig = e->tick+e->dur;
205 rresize_toffset = 0;
207 else if(over_lhandle(e)){//resize move
208 lresize_flag = 1;
209 lresize_torig = e->tick;
210 lresize_toffset = 0;
212 else{//begin move
213 move_flag = 1;
214 cursor(fltk::CURSOR_MOVE);
215 move_torig = e->tick;
216 move_qoffset = e->tick - quantize(e->tick);
218 move_toffset = -move_qoffset;
220 //move_offset = quantize(xpix2tick(X)) - move_torig - move_qoffset;
221 //move_toffset = 0;
222 move_offset = X - tick2xpix(e->tick);
223 //move_norig = ypix2note(Y+scrolly,1);
224 move_norig = e->value1;
225 move_noffset = 0;
227 last_note = e->value1;
228 if(config.playmove){
229 ui->keyboard->play_note(last_note,0);
230 ui->keyboard->highlight_note(last_note);
235 else if(event_button()==2){//middle mouse
236 //button initiates paste
238 else if(event_button()==3){//right mouse
239 if(e==NULL){
240 unselect_all();
241 ui->event_edit->redraw();
243 else{//set up for deletion
244 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
245 unselect_all();
247 e->selected = 1;
248 delete_flag = 1;
249 resize_arrow_color = fltk::color(120,60,58);
251 ui->event_edit->select_flag = 0;
253 redraw();
254 return 1;
255 case fltk::DRAG:
257 ui->keyboard->highlight_clear();
258 if(box_flag){
259 box_x2 = X;
260 box_y2 = Y;
261 box_t2 = xpix2tick(X+scrollx);
262 box_n2 = ypix2note(Y+scrolly,1);
264 else if(insert_flag){
265 if(trip_flag){
266 int q_trip = (q_tick*2) / 3;
267 insert_toffset = quantize(xpix2tick(X+scrollx)+q_trip) - insert_torig;
268 if(insert_toffset<=0){
269 insert_toffset -= q_trip;
272 else{
273 insert_toffset = quantize(xpix2tick(X+scrollx)+q_tick) - insert_torig;
274 if(insert_toffset<=0){
275 insert_toffset -= q_tick;
278 insert_note = ypix2note(Y+scrolly,1);
279 if(insert_note != last_note){
280 if(config.playinsert){//play on insert
281 ui->keyboard->release_note(last_note,0);
282 ui->keyboard->play_note(insert_note,0);
284 last_note = insert_note;
287 else if(move_flag){
288 move_toffset = quantize(xpix2tick(X - move_offset)) - move_torig;
289 move_noffset = ypix2note(Y+scrolly,1) - move_norig;
290 int N = move_norig+move_noffset;
291 if(N != last_note){
292 ui->keyboard->highlight_note(N);
293 if(config.playmove){//play on move
294 ui->keyboard->release_note(last_note,0);
295 ui->keyboard->play_note(N,0);
297 last_note = N;
300 else if(rresize_flag){
301 if(trip_flag){
302 int q_trip = (q_tick*2) / 3;
303 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_trip-rresize_torig;
305 else{
306 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_tick-rresize_torig;
309 else if(lresize_flag){
310 lresize_toffset = quantize(xpix2tick(X+scrollx)) - lresize_torig;
312 redraw();
313 return 1;
314 case fltk::RELEASE:
315 e = over_note();
316 if(event_button()==1){
317 if(box_flag){
318 apply_box();
319 ui->event_edit->redraw();
320 box_flag=0;
322 else if(rresize_flag){
323 apply_rresize();
324 rresize_flag = 0;
325 resize_arrow = 0;
326 cursor(fltk::CURSOR_DEFAULT);
327 ui->event_edit->redraw();
329 else if(lresize_flag){
330 apply_lresize();
331 lresize_flag = 0;
332 resize_arrow = 0;
333 cursor(fltk::CURSOR_DEFAULT);
334 ui->event_edit->redraw();
336 else if(insert_flag){
337 apply_insert();
339 insert_flag = 0;
341 ui->keyboard->release_note(insert_note,0);
342 ui->keyboard->redraw();
343 ui->event_edit->has[0]=1;
344 ui->event_edit->has[1]=1;
345 ui->event_edit->redraw();
346 ui->event_menu->redraw();
348 else if(move_flag){
349 apply_move();
350 move_flag = 0;
351 cursor(fltk::CURSOR_DEFAULT);
352 midi_track_off(cur_seqpat->track);
354 ui->keyboard->release_note(last_note,0);
355 ui->keyboard->release_note(move_norig+move_noffset,0);
356 ui->keyboard->redraw();
357 ui->event_edit->redraw();
359 insert_flag=0;
360 move_flag=0;
362 if(event_button()==3){
363 mevent* over_n = over_note();
364 if(delete_flag && over_n){
365 if(over_n->selected){
366 apply_delete();
368 midi_track_off(cur_seqpat->track);
370 ui->event_edit->redraw();
373 delete_flag=0;
374 resize_arrow = 0;
375 cursor(fltk::CURSOR_DEFAULT);
377 redraw();
379 return 1;
381 case fltk::MOVE:
382 ui->keyboard->highlight_note(ypix2note(Y+scrolly,1));
383 e = over_note();
384 if(e){
385 if(over_rhandle(e)){
386 if(resize_e != e || resize_arrow != 1){
387 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
388 else{resize_arrow_color = fltk::color(95,58,119);}
389 resize_e = e;
390 resize_arrow = 1;
391 cursor(fltk::CURSOR_WE);
392 resize_x = tick2xpix(e->tick + e->dur)-scrollx-resize_handle_width;
393 resize_y = note2ypix(e->value1)-scrolly;
394 redraw();
397 else if(over_lhandle(e)){
398 if(resize_e != e || resize_arrow != 1){
399 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
400 else{resize_arrow_color = fltk::color(95,58,119);}
401 resize_e = e;
402 resize_arrow = -1;
403 cursor(fltk::CURSOR_WE);
404 resize_x = tick2xpix(e->tick)+1 - scrollx;
405 resize_y = note2ypix(e->value1) - scrolly;
406 redraw();
409 else{
410 if(resize_e != e || resize_arrow != 0){
411 resize_e = e;
412 resize_arrow = 0;
413 cursor(fltk::CURSOR_DEFAULT);
414 redraw();
418 else{
419 if(resize_arrow != 0){
420 resize_arrow = 0;
421 cursor(fltk::CURSOR_DEFAULT);
422 redraw();
426 return 1;
429 case fltk::LEAVE:
430 ui->keyboard->highlight_clear();
431 return 1;
433 return 0;
436 void PianoRoll::draw(){
438 fltk::push_clip(0,0,w(),h());
440 fltk::setcolor(fltk::GRAY05);
441 fltk::fillrect(0,0,w(),h());
443 fltk::setcolor(fltk::GRAY20);
444 for(int i=12-scrolly; i<h(); i+=12){
445 if(i>=0){
446 fltk::fillrect(0,i,w(),1);
449 for(int i=zoom-scrollx; i<w(); i+=zoom){
450 if(i>=0){
451 fltk::fillrect(i,0,1,h());
455 fltk::setcolor(fltk::GRAY30);
456 for(int i=12*5-scrolly; i<h(); i+=12*7){
457 if(i>=0){
458 fltk::fillrect(0,i,w(),1);
462 fltk::setcolor(fltk::GRAY50);
463 for(int i=zoom*4-scrollx; i<w(); i+=zoom*4){
464 if(i>=0){
465 fltk::fillrect(i,0,1,h());
469 fltk::setcolor(fltk::WHITE);
470 int M = config.beats_per_measure;
471 for(int i=zoom*4*M-scrollx; i<w(); i+=zoom*4*M){
472 if(i>=0){
473 fltk::fillrect(i,0,1,h());
477 fltk::setcolor(fltk::color(128,0,0));
478 int rightend = tick2xpix(cur_seqpat->dur)-scrollx;
479 if(rightend >=0 && rightend < w()){
480 fltk::fillrect(rightend,0,1,h());
483 fltk::setcolor(fltk::color(128,128,0));
484 fltk::fillrect(0,12*40-scrolly,w(),1);
486 int tmp;
487 if(insert_flag){
488 fltk::setcolor(fltk::BLUE);
489 int T1 = insert_torig;
490 int T2 = T1 + insert_toffset;
491 if(T1>T2){SWAP(T1,T2);}
492 int X = tick2xpix(T1)+1 - scrollx;
493 int Y = note2ypix(insert_note) - scrolly;
494 int W = tick2xpix(T2)-scrollx - X;
495 fltk::fillrect(X,Y,W,11);
498 if(move_flag){
499 fltk::setcolor(fltk::MAGENTA);
500 mevent* ptr = cur_seqpat->p->events->next;
501 while(ptr){
502 if(ptr->type == MIDI_NOTE_ON && ptr->selected){
503 int X = tick2xpix(ptr->tick+move_toffset)+1-scrollx;
504 int Y = note2ypix(ptr->value1+move_noffset)-scrolly;
505 int W = tick2xpix(ptr->dur);
506 fltk::fillrect(X,Y,W-1,1);
507 fltk::fillrect(X,Y+11,W-1,1);
508 fltk::fillrect(X,Y,1,11);
509 fltk::fillrect(X+W-2,Y,1,11);
511 ptr=ptr->next;
517 //draw all notes
518 mevent* e = cur_seqpat->p->events->next;
520 fltk::Color c1,c2,c3;
522 while(e){
523 if(e->type == MIDI_NOTE_ON){
524 //fltk::fillrect(tick2xpix(e->tick),note2ypix(e->value),e->dur,11);
526 int R1 = rresize_flag&&e->selected ? rresize_toffset : 0;
527 int R2 = lresize_flag&&e->selected ? lresize_toffset : 0;
529 int T1 = e->tick + R2;
530 int T2 = e->tick+e->dur + R1;
532 if(T1 >= T2-q_tick && e->selected){
533 if(rresize_flag){
534 T1 = e->tick;
535 T2 = T1 + q_tick;
537 else if(lresize_flag){
538 T2 = e->tick + e->dur;
539 T1 = T2 - q_tick;
543 int X = tick2xpix(T1) + 1 - scrollx;
544 int Y = note2ypix(e->value1) - scrolly;
546 int W = tick2xpix(T2)-scrollx - X;
547 get_event_color(e,&c1,&c2,&c3);
549 if(!(X+W<0 || X > w())){
551 fltk::setcolor(c1);
552 fltk::fillrect(X+1,Y+1,W-1,10);
554 fltk::setcolor(c2);
555 fltk::fillrect(X,Y+11,W,1);
556 fltk::fillrect(X+W-1,Y+1,1,11);
558 fltk::setcolor(c3);
559 fltk::fillrect(X,Y,W,1);
560 fltk::fillrect(X,Y,1,11);
563 e=e->next;
567 if(!rresize_flag && !lresize_flag){
568 if(resize_arrow > 0){
569 setcolor(resize_arrow_color);
571 int W = resize_handle_width;
572 int H = 12;
573 int X = resize_x;
574 int Y = resize_y;
576 //addvertex(X,Y);
577 //addvertex(X,Y+H);
578 //addvertex(X+W,Y+H/2);
579 //fillpath();
581 else if(resize_arrow < 0){
582 setcolor(resize_arrow_color);
584 int W = resize_handle_width;
585 int H = 12;
586 int X = resize_x;
587 int Y = resize_y;
589 //addvertex(X+W,Y);
590 //addvertex(X+W,Y+H);
591 //addvertex(X,Y+H/2);
592 //fillpath();
597 if(box_flag){
598 fltk::setcolor(fltk::GREEN);
599 int X1,X2,Y1,Y2;
600 if(box_x1>box_x2){
601 X1=box_x2;
602 X2=box_x1;
604 else{
605 X1=box_x1;
606 X2=box_x2;
608 if(box_y1>box_y2){
609 Y1=box_y2;
610 Y2=box_y1;
612 else{
613 Y1=box_y1;
614 Y2=box_y2;
616 fltk::fillrect(X1,Y1,X2-X1,1);
617 fltk::fillrect(X1,Y1,1,Y2-Y1);
618 fltk::fillrect(X2,Y1,1,Y2-Y1);
619 fltk::fillrect(X1,Y2,X2-X1,1);
622 fltk::pop_clip();
628 void PianoRoll::scrollTo(int X, int Y){
630 if(!cur_seqpat){
631 return;
634 if(is_backend_playing() && config.follow){
635 int pos = tick2xpix(get_play_position() - cur_seqpat->tick);
636 if(pos < cur_seqpat->tick){
638 else if(pos < X || pos > X + w() - 30 - 30){
639 ui->pattern_hscroll->value(scrollx);
640 return;
644 scrollx = X;
645 scrolly = Y;
646 cur_seqpat->scrollx = X;
647 cur_seqpat->scrolly = Y;
649 redraw();
650 ui->pattern_hscroll->value(X);
651 ui->pattern_hscroll->redraw();
652 ui->pattern_vscroll->value(Y);
653 ui->pattern_timeline->scroll = X;
654 ui->pattern_timeline->redraw();
655 ui->event_edit->scroll = X;
656 ui->event_edit->redraw();
657 ui->keyboard->scroll = Y;
658 ui->keyboard->redraw();
661 static int kludge=2;
662 void PianoRoll::layout(){
663 if(kludge!=0){
664 kludge--;
665 return;
667 fakeh = 900;
668 if(fakeh<h()){
669 fakeh = h();
672 fltk::Scrollbar* sb = ui->pattern_vscroll;
674 sb->maximum(0);
675 sb->minimum(fakeh-h());
677 if(sb->value() > sb->minimum()){
678 scrollTo(scrollx,900-h());
680 int M = h() - 30;
681 int newsize = M-(fakeh-h());
682 if(newsize<20){
683 newsize=20;
685 ui->song_vscroll->slider_size(60);
688 void PianoRoll::load(seqpat* s){
689 cur_seqpat = s;
690 scrollTo(s->scrollx,s->scrolly);
691 cur_track = tracks[s->track];
692 ui->pattern_timeline->ticks_offset = s->tick;
697 int PianoRoll::note2ypix(int note){
698 int udy = 6*(note + (note+7)/12 + note/12) + 12;
699 return 900 - udy + 1;
702 int PianoRoll::tick2xpix(int tick){
703 return tick*zoom*4 / TICKS_PER_BEAT;
706 int PianoRoll::xpix2tick(int xpix){
707 return xpix*TICKS_PER_BEAT / (zoom*4);
710 int PianoRoll::quantize(int tick){
711 if(trip_flag){
712 int W = (q_tick*2);
713 int T = W/3;
714 int P = tick/W * W;
715 int Q = (tick%W);
716 return P + Q / T * T;
718 else{
719 return tick/(q_tick) * q_tick;
724 void PianoRoll::set_zoom(int z){
725 zoom = z;
726 relayout();
730 mevent* PianoRoll::over_note(){
731 mevent* e = cur_seqpat->p->events->next;
733 int X = event_x()+scrollx;
734 int Y = event_y()+scrolly;
736 int cy, lx, rx;
737 while(e){
738 if(e->type == MIDI_NOTE_ON){
739 cy = note2ypix(e->value1);
740 lx = tick2xpix(e->tick);
741 rx = tick2xpix(e->tick+e->dur);
742 if(X > lx && X < rx &&
743 Y < cy+12 && Y > cy){
744 return e;
747 e = e->next;
750 return NULL;
755 void PianoRoll::update(int pos){
756 if(!is_backend_playing() || !cur_seqpat){
757 return;
759 if(pos < cur_seqpat->tick){
760 return;
762 int X1 = tick2xpix(pos-cur_seqpat->tick);
763 int X2 = X1 - scrollx;
764 if(X2 < 0){
765 scrollTo(X1-50<0?0:X1-50,scrolly);
767 if(X2 > w()-30){
768 scrollTo(X1-50,scrolly);
773 void PianoRoll::unselect_all(){
774 mevent* e = cur_seqpat->p->events;
775 while(e){
776 if(e->type == MIDI_NOTE_ON && e->selected==1){
777 e->selected = 0;
779 e = e->next;
785 void PianoRoll::get_event_color(mevent* e, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3){
787 int T1,T2;
788 int tmp;
789 if(delete_flag){
790 if(e->selected){
791 *c1 = fltk::color(229,79,75);
792 *c2 = fltk::color(120,60,58);
793 *c3 = fltk::color(225,131,109);
794 return;
798 if(box_flag){
799 T1=box_t1;
800 T2=box_t2;
801 int N1 = box_n1;
802 int N2 = box_n2;
803 int N = e->value1;
804 if(T1>T2){SWAP(T1,T2);}
805 if(N1<N2){SWAP(N1,N2);}
806 if(e->tick+e->dur > T1 && e->tick < T2 && N >= N2 && N <= N1){
807 *c1 = fltk::color(108,229,75);
808 *c2 = fltk::color(71,120,59);
809 *c3 = fltk::color(108,229,75);
810 return;
814 if(e->selected){
815 *c1 = fltk::color(255,248,47);
816 *c2 = fltk::color(140,137,46);
817 *c3 = fltk::color(232,255,37);
818 return;
821 *c1 = fltk::color(169,75,229);
822 *c2 = fltk::color(95,58,119);
823 *c3 = fltk::color(198,109,225);
827 void PianoRoll::apply_box(){
828 mevent* e = cur_seqpat->p->events->next;
829 int tmp;
830 int T1=box_t1;
831 int T2=box_t2;
832 int N1 = box_n1;
833 int N2 = box_n2;
835 if(T1>T2){SWAP(T1,T2);}
836 if(N1<N2){SWAP(N1,N2);}
837 while(e){
838 int N = e->value1;
839 if(e->type == MIDI_NOTE_ON &&
840 e->tick+e->dur > T1 && e->tick < T2 &&
841 N >= N2 && N <= N1){
842 ui->event_edit->select_flag = 1;
843 e->selected = 1;
845 e = e->next;
850 void PianoRoll::apply_insert(){
851 if(insert_note > 127 || insert_note < 0){
852 return;
855 int tmp;
856 int T1 = insert_torig;
857 int T2 = T1 + insert_toffset;
858 if(T1>T2){SWAP(T1,T2);}
860 if(T1 < 0){
861 return;
864 pattern* p = cur_seqpat->p;
865 Command* c=new CreateNote(p,insert_note,config.defaultvelocity,T1,T2-T1);
866 set_undo(c);
867 undo_push(1);
869 cur_track->restate();
872 void PianoRoll::apply_delete(){
873 Command* c;
874 mevent* e;
875 mevent* next;
876 pattern* p = cur_seqpat->p;
877 int N=0;
879 e = cur_seqpat->p->events->next;
880 while(e){
881 next = e->next;
882 if(e->selected && e->type == MIDI_NOTE_ON){
883 c=new DeleteNote(p,e);
884 set_undo(c);
885 N++;
887 e = next;
889 undo_push(N);
891 cur_track->restate();
894 void PianoRoll::apply_move(){
895 if(move_toffset==0 && move_noffset==0){
896 return;
899 pattern* p = cur_seqpat->p;
900 mevent* e = p->events->next;
901 while(e){
902 int K = e->value1+move_noffset;
903 int T = e->tick+move_toffset;
904 if(e->type == MIDI_NOTE_ON && e->selected && (T<0 || K < 0 || K > 127)){
905 return;
907 e = e->next;
911 Command* c;
912 e = p->events->next;
914 mevent* next;
915 int M=0;
916 for(int i=0; i<tracks.size(); i++){
917 e = p->events->next;
918 while(e){
919 next = e->next;
920 if(e->selected && e->modified == 0){
921 int K = e->value1 + move_noffset;
922 int T = e->tick + move_toffset;
923 e->modified = 1;
924 c=new MoveNote(p,e,T,K);
925 set_undo(c);
926 M++;
928 e = next;
931 undo_push(M);
933 e = p->events->next;
934 while(e){
935 if(e->modified){e->modified=0;}
936 e = e->next;
939 cur_track->restate();
942 void PianoRoll::apply_paste(){
948 void PianoRoll::apply_rresize(){
949 if(rresize_toffset==0){
950 return;
953 Command* c;
954 mevent* e;
955 mevent* next;
956 pattern* p = cur_seqpat->p;
957 int tmp;
958 int N=0;
960 e = p->events->next;
961 while(e){
962 next = e->next;
963 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
964 e->modified = 1;
965 int W = e->dur;
966 int R = rresize_toffset;
967 if(W+R < q_tick){
968 R = q_tick-W;
970 c=new ResizeNote(p,e,W+R);
971 set_undo(c);
972 N++;
974 e = next;
977 e = p->events->next;
978 while(e){
979 if(e->modified){e->modified=0;}
980 e = e->next;
983 cur_track->restate();
984 undo_push(N);
987 void PianoRoll::apply_lresize(){
988 if(lresize_toffset==0){
989 return;
992 Command* c;
993 mevent* e;
994 mevent* next;
995 pattern* p = cur_seqpat->p;
996 int tmp;
997 int N=0;
999 e = p->events->next;
1000 while(e){
1001 if(e->type == MIDI_NOTE_ON && e->selected){
1002 if(e->tick + lresize_toffset < 0){
1003 return;
1006 e = e->next;
1009 e = p->events->next;
1010 while(e){
1011 next = e->next;
1012 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
1013 e->modified = 1;
1014 int T = e->tick;
1015 int W = e->dur;
1016 int R = lresize_toffset;
1018 if(R > W-q_tick){
1019 R = W-q_tick;
1022 mevent* etmp = e->prev;
1023 c=new ResizeNote(p,e,W-R);
1024 set_undo(c);
1026 e = etmp->next;
1027 c=new MoveNote(p,e,T+R,e->value1);
1028 set_undo(c);
1030 N+=2;
1032 e = next;
1035 e = p->events->next;
1036 while(e){
1037 if(e->modified){e->modified=0;}
1038 e = e->next;
1041 cur_track->restate();
1042 undo_push(N);
1053 int PianoRoll::over_rhandle(mevent* e){
1054 int X = event_x()+scrollx;
1055 int Y = event_y()+scrolly;
1056 int X1 = tick2xpix(e->tick);
1057 int X2 = X1 + tick2xpix(e->dur);
1058 int Y1 = note2ypix(e->value1);
1059 int Y2 = Y1 + 12;
1061 if(X2-X1 < resize_handle_width*3){
1062 return 0;
1065 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - resize_handle_width);
1068 int PianoRoll::over_lhandle(mevent* e){
1069 int X = event_x()+scrollx;
1070 int Y = event_y()+scrolly;
1071 int X1 = tick2xpix(e->tick);
1072 int X2 = X1 + tick2xpix(e->dur);
1073 int Y1 = note2ypix(e->value1);
1074 int Y2 = Y1 + 12;
1076 if(X2-X1 < resize_handle_width*3){
1077 return 0;
1080 return (Y > Y1 && Y < Y2 && X < X1+ resize_handle_width +1 && X > X1 + 1);