Fixed bug that crashed on saving after importing.
[epichord.git] / src / arranger.cpp
blob3f86e463e2ea81ccf08d7839aaab0bb52a384786
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 <stdio.h>
24 #include <vector>
25 #include <fltk/Group.h>
26 #include <fltk/Widget.h>
27 #include <fltk/events.h>
29 #include "ui.h"
31 #include "uihelper.h"
33 #include "util.h"
35 #include "backend.h"
37 extern UI* ui;
39 extern std::vector<track*> tracks;
41 extern struct conf config;
43 using namespace fltk;
45 #define SWAP(X,Y) tmp=X; X=Y; Y=tmp;
47 Arranger::Arranger(int x, int y, int w, int h, const char* label = 0) : fltk::Widget(x, y, w, h, label) {
48 new_default_w = 128*4;
49 delete_flag = 0;
50 move_flag = 0;
51 paste_flag = 0;
52 main_sel = NULL;
54 zoom = 30;
55 zoom_n = 4;
57 q_tick = 128*4;
59 xp_last = 0;
60 yp_last = 0;
62 insert_flag = 0;
63 box_flag = 0;
64 rresize_flag = 0;
65 lresize_flag = 0;
67 last_handle == NULL;
69 color_flag = 0;
71 maxt = 0;
75 int Arranger::handle(int event){
76 Command* c;
78 int X = event_x();
79 int Y = event_y();
81 seqpat* s;
83 switch(event){
84 case fltk::FOCUS:
85 return 1;
86 case fltk::ENTER:
87 return 1;
88 case fltk::KEYUP:
90 return 0;
91 case fltk::MOUSEWHEEL:
92 s = over_seqpat();
93 if(s){
94 s->autocomplete();
95 if(event_dy()>0){
96 s->prev_layer();
98 else if(event_dy()<0){
99 s->next_layer();
101 s->restate();
102 redraw();
104 return 1;
105 case fltk::SHORTCUT:
106 if(event_state() && event_key()=='c'){
108 return 1;
110 if(event_state() && event_key()=='v'){
112 return 1;
114 if(event_state() && event_key()=='z'){
116 return 1;
118 if(event_key()==fltk::DeleteKey){
119 apply_delete();
120 delete_flag = 0;
121 redraw();
122 return 1;
124 if(zoom_out_key(event_key(),event_state())){
125 //if(event_key()==fltk::LeftKey){
126 if(zoom_n > 1){
127 zoom_n--;
128 zoom = 30*(1<<zoom_n)/16;
129 ui->song_timeline->zoom = 30*(1<<zoom_n)/16;
130 ui->song_timeline->update(get_play_position());
131 ui->song_timeline->redraw();
132 relayout();
134 redraw();
135 return 1;
137 if(zoom_in_key(event_key(),event_state())){
138 //if(event_key()==fltk::RightKey){
139 if(zoom_n < 8){
140 zoom_n++;
141 zoom = 30*(1<<zoom_n)/16;
142 ui->song_timeline->zoom = 30*(1<<zoom_n)/16;
143 ui->song_timeline->update(get_play_position());
144 ui->song_timeline->redraw();
145 relayout();
147 redraw();
148 return 1;
150 return 0;
151 case fltk::PUSH:
152 take_focus();
153 if(event_button()==1){//left mouse
154 seqpat* s = over_seqpat();
155 if(s==NULL){
156 if(color_flag){//do nothing
158 else if(event_state()&fltk::SHIFT){//begin box
159 box_flag = 1;
160 box_x1=X;
161 box_x2=X;
162 box_y1=Y;
163 box_y2=Y;
164 box_t1=xpix2tick(X);
165 box_t2=box_t1;
166 box_k1=Y/30;
167 box_k2=box_k1;
169 else{//begin insert
170 insert_flag = 1;
171 insert_torig = xpix2tick(X)/q_tick*q_tick;
172 insert_toffset = q_tick;
173 insert_track = event_y() / 30;
176 else{
177 main_sel = s;
178 if(color_flag){
179 color_sel = s->p;
180 color_orig_x = event_x();
181 color_orig_y = event_y();
182 color_orig_h = color_sel->h;
183 color_orig_v = color_sel->v;
184 color_h = color_orig_h;
185 color_v = color_orig_v;
186 return 1;
188 if(!s->selected && !(event_state()&SHIFT)){
189 unselect_all();
191 s->selected = 1;
192 if(fltk::event_clicks() > 0){//'double click'
193 ui->piano_roll->load(s);
194 ui->event_edit->load(s);
195 ui->pattern_scroll->scrollTo(s->scrollx,s->scrolly);
196 ui->pattern_timeline->update(get_play_position());
197 ui->keyboard->cur_port = tracks[s->track]->port;
198 ui->keyboard->cur_chan = tracks[s->track]->chan;
199 ui->track_info->set_rec(s->track);
200 set_rec_track(s->track);
201 show_pattern_edit();
202 return 1;
205 if(over_lhandle(s,X,Y)){//begin resize
206 lresize_flag = 1;
207 lresize_torig = s->tick;
208 lresize_toffset = 0;
210 else if(over_rhandle(s,X,Y)){//begin resizemove
211 rresize_flag = 1;
212 rresize_torig = s->tick+s->dur;
213 rresize_toffset = 0;
216 else{//begin move
217 move_flag = 1;
218 move_torig = s->tick;
219 move_toffset = 0;
220 move_korig = s->track;
221 move_koffset = 0;
222 move_x = X;
223 move_y = Y;
224 move_offset = xpix2tick(X)/q_tick*q_tick - s->tick;
228 else if(event_button()==2){//middle mouse
229 seqpat* s = over_seqpat();
230 if(color_flag && s){
231 s->p->h = color_h;
232 s->p->v = color_v;
233 s->p->regen_colors();
234 redraw();
235 return 1;
237 if(main_sel){
238 paste_flag = 1;
239 paste_t = quantize(xpix2tick(event_x()));
240 paste_track = event_y() / 30;
243 else if(event_button()==3){//right mouse
244 seqpat* s = over_seqpat();
245 if(color_flag && s){
246 seqpat* ptr = tracks[s->track]->head->next;
247 while(ptr){
248 ptr->p->h = color_h;
249 ptr->p->v = color_v;
250 ptr->p->regen_colors();
251 ptr = ptr->next;
253 redraw();
254 return 1;
256 if(s==NULL){
257 unselect_all();
258 delete_sel = NULL;
259 main_sel = NULL;
260 color_sel = NULL;
262 else{//begin delete
263 delete_flag = 1;
264 delete_sel = s;//this line needs to be removed
265 if(!(s->selected)){
266 unselect_all();
268 s->selected = 1;
271 redraw();
272 return 1;
273 case fltk::DRAG:
274 if(box_flag){
275 box_x2 = X;
276 box_y2 = Y;
277 box_t2 = xpix2tick(X);
278 box_k2 = Y/30;
280 if(color_flag && color_sel){
281 color_sel->h = color_orig_h + (color_orig_x - event_x())/1.0;
282 color_sel->v = color_orig_v + (color_orig_y - event_y())/100.0;
283 color_sel->regen_colors();
284 color_h = color_sel->h;
285 color_v = color_sel->v;
286 set_default_hsv_value(color_v);
288 if(insert_flag){
289 insert_toffset = xpix2tick(X)/q_tick*q_tick + q_tick - insert_torig;
290 if(insert_toffset <=0){
291 insert_toffset -= q_tick;
293 insert_track = Y / 30;
295 else if(rresize_flag){
296 rresize_toffset = xpix2tick(X)/128*128 - rresize_torig;
298 else if(lresize_flag){
299 lresize_toffset = xpix2tick(X)/128*128 - lresize_torig;
301 else if(move_flag){
302 move_toffset = quantize(xpix2tick(X)) - move_torig - move_offset;
303 move_koffset = event_y() / 30 - move_korig;
305 else if(paste_flag){
306 paste_t = quantize(xpix2tick(event_x()));
307 paste_track = event_y() / 30;
309 redraw();
310 return 1;
311 case fltk::RELEASE:
312 if(event_button()==1){
313 if(box_flag){
314 apply_box();
315 box_flag = 0;
317 if(insert_flag){
318 apply_insert();
319 insert_flag = 0;
321 else if(move_flag){
322 apply_move();
323 move_flag = 0;
325 else if(rresize_flag){
326 apply_rresize();
327 rresize_flag = 0;
328 if(last_handle){
329 last_handle->lhandle = 0;
330 last_handle->rhandle = 0;
333 else if(lresize_flag){
334 apply_lresize();
335 lresize_flag = 0;
336 if(last_handle){
337 last_handle->lhandle = 0;
338 last_handle->rhandle = 0;
342 insert_flag=0;
343 color_sel = NULL;
345 else if(event_button()==2){
346 if(paste_flag){
347 apply_paste();
349 paste_flag=0;
351 else if(event_button()==3){
352 seqpat* over_s = over_seqpat();
353 if(delete_flag && over_s){
354 if(over_s->selected){
355 apply_delete();
358 delete_flag=0;
359 //last_handle==NULL;
364 redraw();
365 return 1;
366 case fltk::MOVE:
367 if(color_flag){break;}
368 seqpat* s = over_seqpat();
369 if(s){
370 if(over_rhandle(s,X,Y)){s->rhandle = 1;}
371 else{s->rhandle = 0;}
372 if(over_lhandle(s,X,Y)){s->lhandle = 1;}
373 else{s->lhandle = 0;}
374 if(s != last_handle){
375 if(last_handle){
376 last_handle->rhandle = 0;
377 last_handle->lhandle = 0;
379 last_handle = s;
381 redraw();
383 else if(last_handle){
384 last_handle->rhandle = 0;
385 last_handle->lhandle = 0;
386 last_handle = NULL;
387 redraw();
389 return 1;
392 return 0;
395 void Arranger::draw(){
397 fltk::setfont(fltk::HELVETICA,8);
399 fltk::setcolor(fltk::GRAY05);
400 fltk::fillrect(0,0,w(),h());
402 fltk::setcolor(fltk::GRAY20);
403 int M = config.beats_per_measure;
404 int I=0;
405 for(int i=1; I<w(); i++){
406 I = i*zoom*M/4;
407 fltk::fillrect(I,0,1,h());
409 fltk::setcolor(fltk::GRAY50);
410 int P = config.measures_per_phrase;
411 if(P){
412 I=0;
413 for(int i=1; I<w(); i++){
414 I = i*zoom*4*P*M/4/4;
415 fltk::fillrect(I,0,1,h());
420 if(insert_flag){
421 fltk::setcolor(fltk::BLUE);
422 int T1 = insert_torig;
423 int T2 = T1 + insert_toffset;
424 int tmp;
425 if(T1>T2){SWAP(T1,T2);}
426 int X = tick2xpix(T1)+1;
427 int Y = insert_track*30;
428 int W = tick2xpix(T2)-tick2xpix(T1) - 1;
429 fltk::fillrect(X,Y,W,28);
432 if(move_flag){
433 if(check_move_safety()){
434 fltk::setcolor(fltk::MAGENTA);
436 else{
437 fltk::setcolor(fltk::RED);
440 for(int i=0; i<tracks.size(); i++){
441 seqpat* s = tracks[i]->head->next;
442 while(s){
443 if(s->selected){
444 int X = tick2xpix(s->tick + move_toffset);
445 int Y = (s->track + move_koffset)*30;
446 int W = tick2xpix(s->dur);
447 fltk::fillrect(X+1,Y+1,W-1,1);
448 fltk::fillrect(X+1,Y+1,1,29-1);
449 fltk::fillrect(X+1,Y+29-1,W-1,1);
450 fltk::fillrect(X+W-1,Y+1,1,29-1);
452 s = s->next;
457 if(paste_flag){
458 fltk::setcolor(fltk::GREEN);
459 int X = tick2xpix(paste_t)+1;
460 int Y = paste_track*zoom;
461 int W = tick2xpix(main_sel->dur);
462 fltk::fillrect(X,Y,W-1,1);
463 fltk::fillrect(X,Y+28,W-1,1);
464 fltk::fillrect(X,Y,1,28);
465 fltk::fillrect(X+W-2,Y,1,28);
468 int tmp;
469 if(box_flag){
470 fltk::setcolor(fltk::GREEN);
471 int X1,X2,Y1,Y2;
472 X1 = box_x1;
473 X2 = box_x2;
474 Y1 = box_y1;
475 Y2 = box_y2;
476 if(X1>X2){SWAP(X1,X2);}
477 if(Y1>Y2){SWAP(Y1,Y2);}
478 fltk::fillrect(X1,Y1,X2-X1,1);
479 fltk::fillrect(X1,Y1,1,Y2-Y1);
480 fltk::fillrect(X2,Y1,1,Y2-Y1);
481 fltk::fillrect(X1,Y2,X2-X1,1);
484 //draw all seqpat
485 seqpat* s;
486 fltk::Color c;
488 fltk::Color c1,c2,c3,cx;
489 c1 = fltk::BLACK;
491 for(int i=0; i<tracks.size(); i++){
493 s = tracks[i]->head->next;
494 while(s){
496 pattern* p = s->p;
498 get_outline_color(s,&c1,&c2,&c3,&cx);
500 fltk::setcolor(c1);
502 int R1 = lresize_flag&&s->selected ? lresize_toffset : 0;
503 int R2 = rresize_flag&&s->selected ? rresize_toffset : 0;
505 int T1 = s->tick+R1;
506 int T2 = s->tick+s->dur+R2;
508 if(T1 > T2){SWAP(T1,T2)};
510 int X = tick2xpix(T1)+1;
511 int Y = s->track * 30;
512 int W = tick2xpix(T2)-tick2xpix(T1)-1;
514 if(rresize_flag && s->selected && T1==T2){
515 W = tick2xpix(128)-1;
517 if(lresize_flag && s->selected && T1==T2){
518 W = tick2xpix(128)-1;
521 fillrect(X+1,Y+1,W-2,27);
522 float a = 1.5f;
525 fltk::setcolor(c2);
526 fillrect(X+W-1,Y,1,29);
527 fillrect(X,Y+28,W-1,1);
529 fltk::setcolor(c3);
530 fillrect(X,Y,1,28);
531 fillrect(X,Y,W,1);
533 fltk::push_clip(tick2xpix(T1),s->track*30,tick2xpix(T2-T1),30);
535 if(s->rhandle && !rresize_flag){
536 setcolor(cx);
537 if(delete_flag){
538 setcolor(fltk::color(128,0,0));
541 W = 5;
542 X = tick2xpix(s->tick+s->dur) - W - 1;
543 Y = s->track*30;
544 addvertex(X+W,Y+28/2);
545 addvertex(X,Y);
546 addvertex(X,Y+28);
547 fillpath();
550 if(s->lhandle && !lresize_flag){
551 setcolor(cx);
552 if(delete_flag){
553 setcolor(fltk::color(128,0,0));
555 W = 5;
556 X = tick2xpix(s->tick)+1;
557 Y = s->track*30;
558 addvertex(X,Y+28/2);
559 addvertex(X+W,Y);
560 addvertex(X+W,Y+28);
561 fillpath();
564 fltk::setcolor(cx);
567 mevent* e = s->p->events;
568 while(e){
569 if(e->tick >= s->dur){
570 break;
572 if(e->type == MIDI_NOTE_ON){
573 X = tick2xpix(e->tick) + tick2xpix(s->tick)+2;
574 Y = s->track*30 + 27 - e->value1*27/127;
575 W = tick2xpix(e->dur);
576 if(W==0){W=1;}
577 fillrect(X,Y,W,1);
579 e=e->next;
583 int total = s->layer_total();
584 if(total > 1){
585 fltk::setcolor(fltk::BLACK);
586 int X = tick2xpix(s->tick);
587 int Y = s->track * 30;
588 int count = s->layer_index()+1;
589 char buf[16];
590 snprintf(buf,16,"%d / %d",count,total);
591 fltk::drawtext(buf,X+2,Y+27);
595 fltk::pop_clip();
597 s=s->next;
602 static int kludge = 4;//see the same kludge in pianoroll.cpp
603 void Arranger::layout(){
604 if(kludge > 0){
605 kludge--;
606 return;
609 maxt = 0;
610 for(int i=0; i<tracks.size(); i++){
611 seqpat* s = tracks[i]->head->next;
612 while(s){
613 if(s->tick+s->dur > maxt){maxt=s->tick+s->dur;}
614 s=s->next;
617 int ws = tick2xpix(maxt);
618 if(ws > w()-120){
619 w(ws+500);
621 if(ws < w()-120){
622 w(ws+500);
625 int wp = ui->song_scroll->w();
626 if(wp > w()){
627 w(wp+500);
630 int hp = ui->song_scroll->h();
631 if(hp > h()){
632 h(hp);
634 else{
635 h(16*30);
638 int xp = ui->song_scroll->xposition();
639 int yp = ui->song_scroll->yposition();
640 ui->song_timeline->scroll = xp;
641 ui->track_info->scroll = yp;
643 if(xp_last != xp){
644 ui->song_timeline->redraw();
646 if(yp_last != yp){
647 ui->track_info->redraw();
650 yp_last = yp;
651 xp_last = xp;
657 seqpat* Arranger::over_seqpat(){
658 int track = event_y() / 30;
659 if(track >= tracks.size()){
660 return NULL;
662 int tick = xpix2tick(event_x());
663 seqpat* s = tfind<seqpat>(tracks[track]->head,tick);
664 if(s){
665 if(tick < s->tick+s->dur){
666 return s;
669 return NULL;
673 //true if over right handle of s
674 int Arranger::over_rhandle(seqpat* s, int X, int Y){
675 int X1 = tick2xpix(s->tick);
676 int X2 = X1 + tick2xpix(s->dur);
677 int Y1 = s->track * 30 + 1;
678 int Y2 = Y1 + 29;
680 if(tick2xpix(s->dur) < 10){
681 return 0;
684 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - 5);
687 //true if over left handle of s
688 int Arranger::over_lhandle(seqpat* s, int X, int Y){
689 int X1 = tick2xpix(s->tick);
690 int X2 = X1 + tick2xpix(s->dur);
691 int Y1 = s->track * 30 + 1;
692 int Y2 = Y1 + 29;
694 if(tick2xpix(s->dur) < 10){
695 return 0;
698 return (Y > Y1 && Y < Y2 && X < X1 + 5 + 1 && X > X1+1);
701 // 4=beats per measure, 128=ticks per beat, 30=width of measure in pixels
702 int Arranger::tick2xpix(int tick){
703 return tick *zoom /(128*4);
706 int Arranger::xpix2tick(int xpix){
707 return xpix * (128*4) /zoom;
710 int Arranger::quantize(int tick){
711 return tick/q_tick * q_tick;
715 void Arranger::update(int pos){
716 if(!is_backend_playing()){
717 return;
719 int wp = ui->song_scroll->w();
720 int xp = ui->song_scroll->xposition();
721 int yp = ui->song_scroll->yposition();
722 int X1 = tick2xpix(pos);
723 int X2 = X1 - xp;
724 if(X1 > w()-40){
725 return;
727 if(X2 < 0){
728 ui->song_scroll->scrollTo(X1-50<0?0:X1-50,yp);
730 if(X2 > wp-30){
731 ui->song_scroll->scrollTo(X1-50,yp);
736 void Arranger::unselect_all(){
737 seqpat* s;
738 for(int i=0; i<tracks.size(); i++){
739 s = tracks[i]->head->next;
740 while(s){
741 if(s->selected==1){
742 s->selected = 0;
744 s = s->next;
749 void Arranger::get_outline_color(seqpat* s, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3, fltk::Color* cx){
751 pattern* p = s->p;
752 *c1 = fltk::color(p->r1, p->g1, p->b1);
753 *cx = fltk::color(p->rx, p->gx, p->bx);
755 int T1,T2;
756 int tmp;
757 seqpat* over_s = over_seqpat();
758 if(delete_flag && s->selected){
759 *c1 = fltk::color(255,0,0);
760 *c2 = fltk::color(255,0,0);
761 *c3 = fltk::color(255,0,0);
762 return;
765 if(box_flag){
766 T1=box_t1;
767 T2=box_t2;
768 int K1 = box_k1;
769 int K2 = box_k2;
770 int K = s->track;
771 if(T1>T2){SWAP(T1,T2);}
772 if(K1<K2){SWAP(K1,K2);}
773 if(s->tick+s->dur > T1 && s->tick < T2 && K >= K2 && K <= K1){
774 *c1 = fltk::color(0,255,0);
775 *c2 = fltk::color(71,120,59);
776 *c3 = fltk::color(108,229,75);
777 return;
781 if(s->selected){
782 *c1 = fltk::color(255,255,0);
783 *c2 = fltk::color(140,137,46);
784 *c3 = fltk::color(232,255,37);
785 *cx = fltk::color(128,128,0);
786 return;
790 *c2 = fltk::color(p->r2,p->g2,p->b2);
791 *c3 = fltk::color(p->r3,p->g3,p->b3);
796 void Arranger::apply_insert(){
798 if(!check_insert_safety()){
799 return;
802 int tmp;
803 int T1 = insert_torig;
804 int T2 = T1 + insert_toffset;
805 if(T1>T2){SWAP(T1,T2);}
807 Command* c=new CreateSeqpatBlank(insert_track,T1,T2-T1);
808 set_undo(c);
809 undo_push(1);
811 if(T2>maxt){relayout();}
814 void Arranger::apply_box(){
815 seqpat* s;
816 int tmp;
817 int T1=box_t1;
818 int T2=box_t2;
819 int K1 = box_k1;
820 int K2 = box_k2;
821 if(T1>T2){SWAP(T1,T2);}
822 if(K1>K2){SWAP(K1,K2);}
823 if(K1 < 0){K1 = 0;}
824 if(K2 > tracks.size()-1){K2 = tracks.size()-1;}
825 for(int i=K1; i<=K2; i++){
826 s = tracks[i]->head->next;
827 while(s){
828 if(s->tick+s->dur > T1 && s->tick < T2){
829 s->selected = 1;
831 s = s->next;
837 void Arranger::apply_delete(){
838 Command* c;
839 seqpat* s;
840 seqpat* next;
841 int N=0;
842 for(int i=0; i<tracks.size(); i++){
843 s = tracks[i]->head->next;
844 while(s){
845 next = s->next;
846 if(s->selected){
847 tracks[s->track]->modified = 1;
848 c=new DeleteSeqpat(s);
849 set_undo(c);
850 N++;
852 s = next;
855 undo_push(N);
857 unmodify_and_unstick_tracks();
861 void Arranger::apply_move(){
862 if(move_toffset==0 && move_koffset==0){
863 return;
866 if(!check_move_safety()){
867 return;
870 Command* c;
871 seqpat* s;
872 seqpat* next;
873 int N=0;
874 for(int i=0; i<tracks.size(); i++){
875 s = tracks[i]->head->next;
876 while(s){
877 next = s->next;
878 if(s->selected && s->modified == 0){
879 int K = s->track + move_koffset;
880 int T = s->tick + move_toffset;
881 tracks[s->track]->modified = 1;
882 tracks[K]->modified = 1;
883 s->modified = 1;
884 c=new MoveSeqpat(s,K,T);
885 set_undo(c);
886 N++;
888 if(T+s->dur > maxt){relayout();}
890 s = next;
893 undo_push(N);
895 unmodify_blocks();
896 unmodify_and_unstick_tracks();
899 void Arranger::apply_paste(){
900 //safety check
903 Command* c;
905 c = new CreateSeqpat(paste_track,paste_t,main_sel,0);
906 set_undo(c);
907 undo_push(1);
912 void Arranger::apply_rresize(){
913 if(rresize_toffset==0){
914 return;
917 if(!check_resize_safety()){
918 return;
921 Command* c;
922 seqpat* s;
923 seqpat* next;
924 int tmp;
925 int N=0;
926 for(int i=0; i<tracks.size(); i++){
927 s = tracks[i]->head->next;
928 while(s){
929 next = s->next;
930 if(s->selected && s->modified == 0){
931 tracks[i]->modified = 1;
932 s->modified = 1;
933 int T1 = s->tick;
934 int T2 = s->tick + s->dur + rresize_toffset;
935 if(T1 > T2){
936 SWAP(T1,T2);
937 seqpat* stmp = s->prev;
938 //c=new ReverseSeqpat(s);
939 //set_undo(c);
940 s = stmp->next;
941 c=new ResizeSeqpat(s,T2-T1);
942 set_undo(c);
943 s = stmp->next;
944 c=new MoveSeqpat(s,s->track,T1);
945 set_undo(c);
946 N+=2;
948 s = stmp->next;
949 if(s->tick+s->dur > maxt){relayout();}
951 else{
952 if(T1==T2){
953 T2 = T1+128; //magic
955 c=new ResizeSeqpat(s,T2-T1);
956 set_undo(c);
957 N++;
959 if(T2 > maxt){relayout();}
963 s = next;
966 undo_push(N);
968 unmodify_blocks();
969 unmodify_and_unstick_tracks();
972 void Arranger::apply_lresize(){
973 if(lresize_toffset==0){
974 return;
977 if(!check_resize_safety()){
978 return;
981 Command* c;
982 seqpat* s;
983 seqpat* next;
984 int tmp;
985 int N=0;
986 for(int i=0; i<tracks.size(); i++){
987 s = tracks[i]->head->next;
988 while(s){
989 next = s->next;
990 if(s->selected && s->modified == 0){
991 tracks[i]->modified = 1;
992 s->modified = 1;
993 int T1 = s->tick + lresize_toffset;
994 int T2 = s->tick + s->dur;
995 if(T1 > T2){
996 SWAP(T1,T2);
997 seqpat* stmp = s->prev;
998 //c=new ReverseSeqpat(s);
999 //set_undo(c);
1000 s = stmp->next;
1001 c=new ResizeSeqpat(s,T2-T1);
1002 set_undo(c);
1003 s = stmp->next;
1004 c=new MoveSeqpat(s,s->track,T1);
1005 set_undo(c);
1006 N+=2;
1008 s = stmp->next;
1009 if(s->tick+s->dur > maxt){relayout();}
1011 else{
1012 if(T1==T2){
1013 T2 = T1+128; //magic
1015 seqpat* stmp = s->prev;
1016 c=new MoveSeqpat(s,s->track,T1);
1017 set_undo(c);
1018 s = stmp->next;
1019 c=new ResizeSeqpat(s,T2-T1);
1020 set_undo(c);
1021 N+=2;
1023 s = stmp->next;
1024 if(s->tick+s->dur>maxt){relayout();}
1028 s = next;
1031 undo_push(N);
1033 unmodify_blocks();
1034 unmodify_and_unstick_tracks();
1039 int collision_test(int t11, int t12, int t21, int t22){
1040 return !((t11 < t21 && t12 <= t21) ||
1041 (t11 >= t22 && t12 > t22)) ? 1 : 0;
1044 int Arranger::check_move_safety(){
1045 seqpat* s;
1046 seqpat* ptr;
1048 for(int i=0; i<tracks.size(); i++){
1049 s = tracks[i]->head->next;
1050 while(s){
1051 if(s->selected){
1052 if(i+move_koffset < 0 || i+move_koffset > tracks.size()-1 ||
1053 s->tick + move_toffset < 0){
1054 return 0;
1056 ptr = tracks[i+move_koffset]->head->next;
1057 while(ptr){
1058 if(ptr == s){
1059 ptr=ptr->next; continue;
1061 if(collision_test(s->tick+move_toffset,s->tick+s->dur+move_toffset,ptr->tick,ptr->tick+ptr->dur) ){
1062 if(!ptr->selected){
1063 return 0;
1066 ptr = ptr->next;
1069 s = s->next;
1073 return 1;
1076 int Arranger::check_insert_safety(){
1077 seqpat* s;
1079 int T1 = insert_torig;
1080 int T2 = T1 + insert_toffset;
1081 int tmp;
1083 if(T1>T2){SWAP(T1,T2);}
1085 if(T1 < 0){
1086 return 0;
1088 if(insert_track > tracks.size()-1){
1089 return 0;
1091 if(tracks[insert_track]==NULL){
1092 return 0;
1095 s = tracks[insert_track]->head->next;
1097 while(s){
1098 if(collision_test(T1,T2,s->tick,s->tick+s->dur)){
1099 return 0;
1101 s = s->next;
1104 return 1;
1107 int Arranger::check_resize_safety(){
1108 seqpat* s;
1109 seqpat* ptr;
1111 int T1,T2;
1112 int S1,S2;
1113 int tmp;
1115 for(int i=0; i<tracks.size(); i++){
1116 s = tracks[i]->head->next;
1117 while(s){
1118 if(!s->selected){
1119 s = s->next; continue;
1122 if(rresize_flag){
1123 T1 = s->tick;
1124 T2 = s->tick + s->dur + rresize_toffset;
1126 else if(lresize_flag){
1127 T1 = s->tick + lresize_toffset;
1128 T2 = s->tick + s->dur;
1130 if(T1>T2){SWAP(T1,T2);}
1132 if(T1 < 0){
1133 return 0;
1135 ptr = tracks[s->track]->head->next;
1136 while(ptr){
1137 if(ptr == s){
1138 ptr=ptr->next; continue;
1141 S1 = ptr->tick;
1142 S2 = ptr->tick + ptr->dur;
1143 if(ptr->selected){
1144 if(rresize_flag){
1145 S2 += rresize_toffset;
1147 else if(lresize_flag){
1148 S1 += lresize_toffset;
1152 if(collision_test(T1,T2,S1,S2)){
1153 return 0;
1155 ptr = ptr->next;
1158 s = s->next;
1162 return 1;
1166 int Arranger::check_paste_safety(){
1167 return 1;