Added unclone tool. Adjusted GUI. Added icons.
[epichord.git] / src / pianoroll.cpp
blob6e6c3ed5a724ee36b110deb7d4d8aa8bcad331cc
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 resize_arrow_color = fltk::color(128,128,0);
173 if(over_rhandle(e)){//resize
174 rresize_flag = 1;
175 rresize_torig = e->tick+e->dur;
176 rresize_toffset = 0;
178 else if(over_lhandle(e)){//resize move
179 lresize_flag = 1;
180 lresize_torig = e->tick;
181 lresize_toffset = 0;
183 else{//begin move
184 move_flag = 1;
186 move_torig = e->tick;
187 move_qoffset = e->tick - quantize(e->tick);
189 move_toffset = -move_qoffset;
191 //move_offset = quantize(xpix2tick(X)) - move_torig - move_qoffset;
192 //move_toffset = 0;
193 move_offset = X - tick2xpix(e->tick);
194 move_norig = ypix2note(Y+scrolly,1);
195 move_noffset = 0;
197 last_note = move_norig;
198 if(config.playmove){
199 ui->keyboard->play_note(last_note,0);
204 else if(event_button()==2){//middle mouse
205 //button initiates paste
207 else if(event_button()==3){//right mouse
208 if(e==NULL){
209 unselect_all();
211 ui->event_edit->redraw();
213 else{//set up for deletion
214 if(!(e->selected) && !(event_state()&fltk::SHIFT)){
215 unselect_all();
217 e->selected = 1;
218 delete_flag = 1;
219 resize_arrow_color = fltk::color(120,60,58);
222 redraw();
223 return 1;
224 case fltk::DRAG:
226 if(box_flag){
227 box_x2 = X;
228 box_y2 = Y;
229 box_t2 = xpix2tick(X+scrollx);
230 box_n2 = ypix2note(Y+scrolly,1);
232 else if(insert_flag){
233 insert_toffset = quantize(xpix2tick(X+scrollx)+q_tick) - insert_torig;
234 if(insert_toffset<=0){
235 insert_toffset -= q_tick;
237 insert_note = ypix2note(Y+scrolly,1);
238 if(insert_note != last_note){
239 if(config.playinsert){//play on insert
240 ui->keyboard->release_note(last_note,0);
241 ui->keyboard->play_note(insert_note,0);
243 last_note = insert_note;
246 else if(move_flag){
247 move_toffset = quantize(xpix2tick(X - move_offset)) - move_torig;
248 move_noffset = ypix2note(Y+scrolly,1) - move_norig;
249 int N = move_norig+move_noffset;
250 if(N != last_note){
251 if(config.playmove){//play on move
252 ui->keyboard->release_note(last_note,0);
253 ui->keyboard->play_note(N,0);
255 last_note = N;
258 else if(rresize_flag){
259 rresize_toffset = quantize(xpix2tick(X+scrollx))+q_tick-rresize_torig;
261 else if(lresize_flag){
262 lresize_toffset = quantize(xpix2tick(X+scrollx)) - lresize_torig;
264 redraw();
265 return 1;
266 case fltk::RELEASE:
267 e = over_note();
268 if(event_button()==1){
269 if(box_flag){
270 apply_box();
271 ui->event_edit->redraw();
272 box_flag=0;
274 else if(rresize_flag){
275 apply_rresize();
276 rresize_flag = 0;
277 resize_arrow = 0;
278 ui->event_edit->redraw();
280 else if(lresize_flag){
281 apply_lresize();
282 lresize_flag = 0;
283 resize_arrow = 0;
284 ui->event_edit->redraw();
286 else if(insert_flag){
287 apply_insert();
289 insert_flag = 0;
291 ui->keyboard->release_note(insert_note,0);
292 ui->keyboard->redraw();
293 ui->event_edit->has[0]=1;
294 ui->event_edit->has[1]=1;
295 ui->event_edit->redraw();
296 ui->event_menu->redraw();
298 else if(move_flag){
299 apply_move();
300 move_flag = 0;
302 midi_track_off(cur_seqpat->track);
303 ui->keyboard->release_note(last_note,0);
304 ui->keyboard->release_note(move_norig+move_noffset,0);
305 ui->keyboard->redraw();
306 ui->event_edit->redraw();
308 insert_flag=0;
309 move_flag=0;
311 if(event_button()==3){
312 mevent* over_n = over_note();
313 if(delete_flag && over_n){
314 if(over_n->selected){
315 apply_delete();
316 midi_track_off(cur_seqpat->track);
317 ui->event_edit->redraw();
320 delete_flag=0;
321 resize_arrow = 0;
323 redraw();
325 return 1;
327 case fltk::MOVE:
328 e = over_note();
329 if(e){
330 if(over_rhandle(e)){
331 if(resize_e != e || resize_arrow != 1){
332 if(e->selected){resize_arrow_color = fltk::color(128,128,0);}
333 else{resize_arrow_color = fltk::color(95,58,119);}
334 resize_e = e;
335 resize_arrow = 1;
336 resize_x = tick2xpix(e->tick + e->dur)-scrollx-resize_handle_width;
337 resize_y = note2ypix(e->value1)-scrolly;
338 redraw();
341 else if(over_lhandle(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)+1 - scrollx;
348 resize_y = note2ypix(e->value1) - scrolly;
349 redraw();
352 else{
353 if(resize_e != e || resize_arrow != 0){
354 resize_e = e;
355 resize_arrow = 0;
356 redraw();
360 else{
361 if(resize_arrow != 0){
362 resize_arrow = 0;
363 redraw();
367 return 1;
369 return 0;
372 void PianoRoll::draw(){
374 fltk::push_clip(0,0,w(),h());
376 fltk::setcolor(fltk::GRAY05);
377 fltk::fillrect(0,0,w(),h());
379 fltk::setcolor(fltk::GRAY20);
380 for(int i=12-scrolly; i<h(); i+=12){
381 if(i>=0){
382 fltk::fillrect(0,i,w(),1);
385 for(int i=zoom-scrollx; i<w(); i+=zoom){
386 if(i>=0){
387 fltk::fillrect(i,0,1,h());
391 fltk::setcolor(fltk::GRAY30);
392 for(int i=12*5-scrolly; i<h(); i+=12*7){
393 if(i>=0){
394 fltk::fillrect(0,i,w(),1);
398 fltk::setcolor(fltk::GRAY50);
399 for(int i=zoom*4-scrollx; i<w(); i+=zoom*4){
400 if(i>=0){
401 fltk::fillrect(i,0,1,h());
405 fltk::setcolor(fltk::WHITE);
406 int M = config.beats_per_measure;
407 for(int i=zoom*4*M-scrollx; i<w(); i+=zoom*4*M){
408 if(i>=0){
409 fltk::fillrect(i,0,1,h());
413 fltk::setcolor(fltk::color(128,0,0));
414 int rightend = tick2xpix(cur_seqpat->dur)-scrollx;
415 if(rightend >=0 && rightend < w()){
416 fltk::fillrect(rightend,0,1,h());
419 fltk::setcolor(fltk::color(128,128,0));
420 fltk::fillrect(0,12*40-scrolly,w(),1);
422 int tmp;
423 if(insert_flag){
424 fltk::setcolor(fltk::BLUE);
425 int T1 = insert_torig;
426 int T2 = T1 + insert_toffset;
427 if(T1>T2){SWAP(T1,T2);}
428 int X = tick2xpix(T1)+1 - scrollx;
429 int Y = note2ypix(insert_note) - scrolly;
430 int W = tick2xpix(T2)-scrollx - X;
431 fltk::fillrect(X,Y,W,11);
434 if(move_flag){
435 fltk::setcolor(fltk::MAGENTA);
436 mevent* ptr = cur_seqpat->p->events->next;
437 while(ptr){
438 if(ptr->type == MIDI_NOTE_ON && ptr->selected){
439 int X = tick2xpix(ptr->tick+move_toffset)+1-scrollx;
440 int Y = note2ypix(ptr->value1+move_noffset)-scrolly;
441 int W = tick2xpix(ptr->dur);
442 fltk::fillrect(X,Y,W-1,1);
443 fltk::fillrect(X,Y+11,W-1,1);
444 fltk::fillrect(X,Y,1,11);
445 fltk::fillrect(X+W-2,Y,1,11);
447 ptr=ptr->next;
453 //draw all notes
454 mevent* e = cur_seqpat->p->events->next;
456 fltk::Color c1,c2,c3;
458 while(e){
459 if(e->type == MIDI_NOTE_ON){
460 //fltk::fillrect(tick2xpix(e->tick),note2ypix(e->value),e->dur,11);
462 int R1 = rresize_flag&&e->selected ? rresize_toffset : 0;
463 int R2 = lresize_flag&&e->selected ? lresize_toffset : 0;
465 int T1 = e->tick + R2;
466 int T2 = e->tick+e->dur + R1;
468 if(T1 >= T2-q_tick && e->selected){
469 if(rresize_flag){
470 T1 = e->tick;
471 T2 = T1 + q_tick;
473 else if(lresize_flag){
474 T2 = e->tick + e->dur;
475 T1 = T2 - q_tick;
479 int X = tick2xpix(T1) + 1 - scrollx;
480 int Y = note2ypix(e->value1) - scrolly;
482 int W = tick2xpix(T2)-scrollx - X;
483 get_event_color(e,&c1,&c2,&c3);
485 if(!(X+W<0 || X > w())){
487 fltk::setcolor(c1);
488 fltk::fillrect(X+1,Y+1,W-1,10);
490 fltk::setcolor(c2);
491 fltk::fillrect(X,Y+11,W,1);
492 fltk::fillrect(X+W-1,Y+1,1,11);
494 fltk::setcolor(c3);
495 fltk::fillrect(X,Y,W,1);
496 fltk::fillrect(X,Y,1,11);
499 e=e->next;
503 if(!rresize_flag && !lresize_flag){
504 if(resize_arrow > 0){
505 setcolor(resize_arrow_color);
507 int W = resize_handle_width;
508 int H = 12;
509 int X = resize_x;
510 int Y = resize_y;
512 addvertex(X,Y);
513 addvertex(X,Y+H);
514 addvertex(X+W,Y+H/2);
515 fillpath();
517 else 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+W,Y);
526 addvertex(X+W,Y+H);
527 addvertex(X,Y+H/2);
528 fillpath();
533 if(box_flag){
534 fltk::setcolor(fltk::GREEN);
535 int X1,X2,Y1,Y2;
536 if(box_x1>box_x2){
537 X1=box_x2;
538 X2=box_x1;
540 else{
541 X1=box_x1;
542 X2=box_x2;
544 if(box_y1>box_y2){
545 Y1=box_y2;
546 Y2=box_y1;
548 else{
549 Y1=box_y1;
550 Y2=box_y2;
552 fltk::fillrect(X1,Y1,X2-X1,1);
553 fltk::fillrect(X1,Y1,1,Y2-Y1);
554 fltk::fillrect(X2,Y1,1,Y2-Y1);
555 fltk::fillrect(X1,Y2,X2-X1,1);
558 fltk::pop_clip();
564 void PianoRoll::scrollTo(int X, int Y){
566 if(!cur_seqpat){
567 return;
570 if(is_backend_playing() && config.follow){
571 int pos = tick2xpix(get_play_position()) - cur_seqpat->tick;
572 if(pos < X || pos > X + w() - 30 - 30){
573 ui->pattern_hscroll->value(scrollx);
574 return;
578 scrollx = X;
579 scrolly = Y;
580 cur_seqpat->scrollx = X;
581 cur_seqpat->scrolly = Y;
583 redraw();
584 ui->pattern_hscroll->value(X);
585 ui->pattern_hscroll->redraw();
586 ui->pattern_vscroll->value(Y);
587 ui->pattern_timeline->scroll = X;
588 ui->pattern_timeline->redraw();
589 ui->event_edit->scroll = X;
590 ui->event_edit->redraw();
591 ui->keyboard->scroll = Y;
592 ui->keyboard->redraw();
595 static int kludge=2;
596 void PianoRoll::layout(){
597 if(kludge!=0){
598 kludge--;
599 return;
601 fakeh = 900;
602 if(fakeh<h()){
603 fakeh = h();
606 fltk::Scrollbar* sb = ui->pattern_vscroll;
608 sb->maximum(0);
609 sb->minimum(fakeh-h());
611 if(sb->value() > sb->minimum()){
612 scrollTo(scrollx,900-h());
614 int M = h() - 30;
615 int newsize = M-(fakeh-h());
616 if(newsize<20){
617 newsize=20;
619 ui->song_vscroll->slider_size(60);
622 void PianoRoll::load(seqpat* s){
623 cur_seqpat = s;
624 scrollTo(s->scrollx,s->scrolly);
625 cur_track = tracks[s->track];
626 ui->pattern_timeline->ticks_offset = s->tick;
631 int PianoRoll::note2ypix(int note){
632 int udy = 6*(note + (note+7)/12 + note/12) + 12;
633 return 900 - udy + 1;
636 int PianoRoll::tick2xpix(int tick){
637 return tick*zoom*4 / 128;
640 int PianoRoll::xpix2tick(int xpix){
641 return xpix*128 / (zoom*4);
644 int PianoRoll::quantize(int tick){
645 return tick/q_tick * q_tick;
649 void PianoRoll::set_zoom(int z){
650 zoom = z;
651 relayout();
655 mevent* PianoRoll::over_note(){
656 mevent* e = cur_seqpat->p->events->next;
658 int X = event_x()+scrollx;
659 int Y = event_y()+scrolly;
661 int cy, lx, rx;
662 while(e){
663 if(e->type == MIDI_NOTE_ON){
664 cy = note2ypix(e->value1);
665 lx = tick2xpix(e->tick);
666 rx = tick2xpix(e->tick+e->dur);
667 if(X > lx && X < rx &&
668 Y < cy+12 && Y > cy){
669 return e;
672 e = e->next;
675 return NULL;
680 void PianoRoll::update(int pos){
681 if(!is_backend_playing() || !cur_seqpat){
682 return;
684 int X1 = tick2xpix(pos-cur_seqpat->tick);
685 int X2 = X1 - scrollx;
686 if(X2 < 0){
687 scrollTo(X1-50<0?0:X1-50,scrolly);
689 if(X2 > w()-30){
690 scrollTo(X1-50,scrolly);
695 void PianoRoll::unselect_all(){
696 mevent* e = cur_seqpat->p->events;
697 while(e){
698 if(e->type == MIDI_NOTE_ON && e->selected==1){
699 e->selected = 0;
701 e = e->next;
707 void PianoRoll::get_event_color(mevent* e, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3){
709 int T1,T2;
710 int tmp;
711 if(delete_flag){
712 if(e->selected){
713 *c1 = fltk::color(229,79,75);
714 *c2 = fltk::color(120,60,58);
715 *c3 = fltk::color(225,131,109);
716 return;
720 if(box_flag){
721 T1=box_t1;
722 T2=box_t2;
723 int N1 = box_n1;
724 int N2 = box_n2;
725 int N = e->value1;
726 if(T1>T2){SWAP(T1,T2);}
727 if(N1<N2){SWAP(N1,N2);}
728 if(e->tick+e->dur > T1 && e->tick < T2 && N >= N2 && N <= N1){
729 *c1 = fltk::color(108,229,75);
730 *c2 = fltk::color(71,120,59);
731 *c3 = fltk::color(108,229,75);
732 return;
736 if(e->selected){
737 *c1 = fltk::color(255,248,47);
738 *c2 = fltk::color(140,137,46);
739 *c3 = fltk::color(232,255,37);
740 return;
743 *c1 = fltk::color(169,75,229);
744 *c2 = fltk::color(95,58,119);
745 *c3 = fltk::color(198,109,225);
749 void PianoRoll::apply_box(){
750 mevent* e = cur_seqpat->p->events->next;
751 int tmp;
752 int T1=box_t1;
753 int T2=box_t2;
754 int N1 = box_n1;
755 int N2 = box_n2;
757 if(T1>T2){SWAP(T1,T2);}
758 if(N1<N2){SWAP(N1,N2);}
759 while(e){
760 int N = e->value1;
761 if(e->type == MIDI_NOTE_ON &&
762 e->tick+e->dur > T1 && e->tick < T2 &&
763 N >= N2 && N <= N1){
764 e->selected = 1;
766 e = e->next;
770 void PianoRoll::apply_insert(){
771 if(insert_note > 127 || insert_note < 0){
772 return;
775 int tmp;
776 int T1 = insert_torig;
777 int T2 = T1 + insert_toffset;
778 if(T1>T2){SWAP(T1,T2);}
780 if(T1 < 0){
781 return;
784 pattern* p = cur_seqpat->p;
785 Command* c=new CreateNote(p,insert_note,config.defaultvelocity,T1,T2-T1);
786 set_undo(c);
787 undo_push(1);
789 cur_track->restate();
792 void PianoRoll::apply_delete(){
793 Command* c;
794 mevent* e;
795 mevent* next;
796 pattern* p = cur_seqpat->p;
797 int N=0;
799 e = cur_seqpat->p->events->next;
800 while(e){
801 next = e->next;
802 if(e->selected && e->type == MIDI_NOTE_ON){
803 c=new DeleteNote(p,e);
804 set_undo(c);
805 N++;
807 e = next;
809 undo_push(N);
811 cur_track->restate();
814 void PianoRoll::apply_move(){
815 if(move_toffset==0 && move_noffset==0){
816 return;
819 pattern* p = cur_seqpat->p;
820 mevent* e = p->events->next;
821 while(e){
822 int K = e->value1+move_noffset;
823 int T = e->tick+move_toffset;
824 if(e->type == MIDI_NOTE_ON && e->selected && (T<0 || K < 0 || K > 127)){
825 return;
827 e = e->next;
831 Command* c;
832 e = p->events->next;
834 mevent* next;
835 int M=0;
836 for(int i=0; i<tracks.size(); i++){
837 e = p->events->next;
838 while(e){
839 next = e->next;
840 if(e->selected && e->modified == 0){
841 int K = e->value1 + move_noffset;
842 int T = e->tick + move_toffset;
843 e->modified = 1;
844 c=new MoveNote(p,e,T,K);
845 set_undo(c);
846 M++;
848 e = next;
851 undo_push(M);
853 e = p->events->next;
854 while(e){
855 if(e->modified){e->modified=0;}
856 e = e->next;
859 cur_track->restate();
862 void PianoRoll::apply_paste(){
868 void PianoRoll::apply_rresize(){
869 if(rresize_toffset==0){
870 return;
873 Command* c;
874 mevent* e;
875 mevent* next;
876 pattern* p = cur_seqpat->p;
877 int tmp;
878 int N=0;
880 e = p->events->next;
881 while(e){
882 next = e->next;
883 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
884 e->modified = 1;
885 int W = e->dur;
886 int R = rresize_toffset;
887 if(W+R < q_tick){
888 R = q_tick-W;
890 c=new ResizeNote(p,e,W+R);
891 set_undo(c);
892 N++;
894 e = next;
897 e = p->events->next;
898 while(e){
899 if(e->modified){e->modified=0;}
900 e = e->next;
903 cur_track->restate();
904 undo_push(N);
907 void PianoRoll::apply_lresize(){
908 if(lresize_toffset==0){
909 return;
912 Command* c;
913 mevent* e;
914 mevent* next;
915 pattern* p = cur_seqpat->p;
916 int tmp;
917 int N=0;
919 e = p->events->next;
920 while(e){
921 if(e->type == MIDI_NOTE_ON && e->selected){
922 if(e->tick + lresize_toffset < 0){
923 return;
926 e = e->next;
929 e = p->events->next;
930 while(e){
931 next = e->next;
932 if(e->type == MIDI_NOTE_ON && e->selected && e->modified == 0){
933 e->modified = 1;
934 int T = e->tick;
935 int W = e->dur;
936 int R = lresize_toffset;
938 if(R > W-q_tick){
939 R = W-q_tick;
942 mevent* etmp = e->prev;
943 c=new ResizeNote(p,e,W-R);
944 set_undo(c);
946 e = etmp->next;
947 c=new MoveNote(p,e,T+R,e->value1);
948 set_undo(c);
950 N+=2;
952 e = next;
955 e = p->events->next;
956 while(e){
957 if(e->modified){e->modified=0;}
958 e = e->next;
961 cur_track->restate();
962 undo_push(N);
973 int PianoRoll::over_rhandle(mevent* e){
974 int X = event_x()+scrollx;
975 int Y = event_y()+scrolly;
976 int X1 = tick2xpix(e->tick);
977 int X2 = X1 + tick2xpix(e->dur);
978 int Y1 = note2ypix(e->value1);
979 int Y2 = Y1 + 12;
981 if(X2-X1 < resize_handle_width*3){
982 return 0;
985 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - resize_handle_width);
988 int PianoRoll::over_lhandle(mevent* e){
989 int X = event_x()+scrollx;
990 int Y = event_y()+scrolly;
991 int X1 = tick2xpix(e->tick);
992 int X2 = X1 + tick2xpix(e->dur);
993 int Y1 = note2ypix(e->value1);
994 int Y2 = Y1 + 12;
996 if(X2-X1 < resize_handle_width*3){
997 return 0;
1000 return (Y > Y1 && Y < Y2 && X < X1+ resize_handle_width +1 && X > X1 + 1);