Initial refactoring of the scroll stuff.
[epichord.git] / src / arranger.cpp
blobd2a6c5d62871659e8a731dd5c4e7b219e984e7b7
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 insert_flag = 0;
60 box_flag = 0;
61 rresize_flag = 0;
62 lresize_flag = 0;
64 last_handle == NULL;
66 color_flag = 0;
68 maxt = 0;
71 int fakew = 1000;
72 int fakeh = 16*30;
76 int Arranger::handle(int event){
77 Command* c;
79 int X = event_x();
80 int Y = event_y();
82 seqpat* s;
84 switch(event){
85 case fltk::FOCUS:
86 return 1;
87 case fltk::ENTER:
88 return 1;
89 case fltk::KEYUP:
91 return 0;
92 case fltk::MOUSEWHEEL:
93 s = over_seqpat();
94 if(s){
95 s->autocomplete();
96 if(event_dy()>0){
97 s->prev_layer();
99 else if(event_dy()<0){
100 s->next_layer();
102 s->restate();
103 redraw();
105 return 1;
106 case fltk::SHORTCUT:
107 if(event_state() && event_key()=='c'){
109 return 1;
111 if(event_state() && event_key()=='v'){
113 return 1;
115 if(event_state() && event_key()=='z'){
117 return 1;
119 if(event_key()==fltk::DeleteKey){
120 apply_delete();
121 delete_flag = 0;
122 redraw();
123 return 1;
125 if(zoom_out_key(event_key(),event_state())){
126 //if(event_key()==fltk::LeftKey){
127 if(zoom_n > 1){
128 zoom_n--;
129 zoom = 30*(1<<zoom_n)/16;
130 ui->song_timeline->zoom = 30*(1<<zoom_n)/16;
131 ui->song_timeline->update(get_play_position());
132 ui->song_timeline->redraw();
133 relayout();
135 redraw();
136 return 1;
138 if(zoom_in_key(event_key(),event_state())){
139 //if(event_key()==fltk::RightKey){
140 if(zoom_n < 8){
141 zoom_n++;
142 zoom = 30*(1<<zoom_n)/16;
143 ui->song_timeline->zoom = 30*(1<<zoom_n)/16;
144 ui->song_timeline->update(get_play_position());
145 ui->song_timeline->redraw();
146 relayout();
148 redraw();
149 return 1;
151 return 0;
152 case fltk::PUSH:
153 take_focus();
154 if(event_button()==1){//left mouse
155 seqpat* s = over_seqpat();
156 if(s==NULL){
157 if(color_flag){//do nothing
159 else if(event_state()&fltk::SHIFT){//begin box
160 box_flag = 1;
161 box_x1=X;
162 box_x2=X;
163 box_y1=Y;
164 box_y2=Y;
165 box_t1=xpix2tick(X);
166 box_t2=box_t1;
167 box_k1=Y/30;
168 box_k2=box_k1;
170 else{//begin insert
171 insert_flag = 1;
172 insert_torig = xpix2tick(X)/q_tick*q_tick;
173 insert_toffset = q_tick;
174 insert_track = event_y() / 30;
177 else{
178 main_sel = s;
179 if(color_flag){
180 color_sel = s->p;
181 color_orig_x = event_x();
182 color_orig_y = event_y();
183 color_orig_h = color_sel->h;
184 color_orig_v = color_sel->v;
185 color_h = color_orig_h;
186 color_v = color_orig_v;
187 return 1;
189 if(!s->selected && !(event_state()&SHIFT)){
190 unselect_all();
192 s->selected = 1;
193 if(fltk::event_clicks() > 0){//'double click'
194 ui->piano_roll->load(s);
195 ui->event_edit->load(s);
196 ui->pattern_scroll->scrollTo(s->scrollx,s->scrolly);
197 ui->pattern_timeline->update(get_play_position());
198 ui->keyboard->cur_port = tracks[s->track]->port;
199 ui->keyboard->cur_chan = tracks[s->track]->chan;
200 ui->track_info->set_rec(s->track);
201 set_rec_track(s->track);
202 show_pattern_edit();
203 return 1;
206 if(over_lhandle(s,X,Y)){//begin resize
207 lresize_flag = 1;
208 lresize_torig = s->tick;
209 lresize_toffset = 0;
211 else if(over_rhandle(s,X,Y)){//begin resizemove
212 rresize_flag = 1;
213 rresize_torig = s->tick+s->dur;
214 rresize_toffset = 0;
217 else{//begin move
218 move_flag = 1;
219 move_torig = s->tick;
220 move_toffset = 0;
221 move_korig = s->track;
222 move_koffset = 0;
223 move_x = X;
224 move_y = Y;
225 move_offset = xpix2tick(X)/q_tick*q_tick - s->tick;
229 else if(event_button()==2){//middle mouse
230 seqpat* s = over_seqpat();
231 if(color_flag && s){
232 s->p->h = color_h;
233 s->p->v = color_v;
234 s->p->regen_colors();
235 redraw();
236 return 1;
238 if(main_sel){
239 paste_flag = 1;
240 paste_t = quantize(xpix2tick(event_x()));
241 paste_track = event_y() / 30;
244 else if(event_button()==3){//right mouse
245 seqpat* s = over_seqpat();
246 if(color_flag && s){
247 seqpat* ptr = tracks[s->track]->head->next;
248 while(ptr){
249 ptr->p->h = color_h;
250 ptr->p->v = color_v;
251 ptr->p->regen_colors();
252 ptr = ptr->next;
254 redraw();
255 return 1;
257 if(s==NULL){
258 unselect_all();
259 delete_sel = NULL;
260 main_sel = NULL;
261 color_sel = NULL;
263 else{//begin delete
264 delete_flag = 1;
265 delete_sel = s;//this line needs to be removed
266 if(!(s->selected)){
267 unselect_all();
269 s->selected = 1;
272 redraw();
273 return 1;
274 case fltk::DRAG:
275 if(box_flag){
276 box_x2 = X;
277 box_y2 = Y;
278 box_t2 = xpix2tick(X);
279 box_k2 = Y/30;
281 if(color_flag && color_sel){
282 color_sel->h = color_orig_h + (color_orig_x - event_x())/1.0;
283 color_sel->v = color_orig_v + (color_orig_y - event_y())/100.0;
284 color_sel->regen_colors();
285 color_h = color_sel->h;
286 color_v = color_sel->v;
287 set_default_hsv_value(color_v);
289 if(insert_flag){
290 insert_toffset = xpix2tick(X)/q_tick*q_tick + q_tick - insert_torig;
291 if(insert_toffset <=0){
292 insert_toffset -= q_tick;
294 insert_track = Y / 30;
296 else if(rresize_flag){
297 rresize_toffset = xpix2tick(X)/128*128 - rresize_torig;
299 else if(lresize_flag){
300 lresize_toffset = xpix2tick(X)/128*128 - lresize_torig;
302 else if(move_flag){
303 move_toffset = quantize(xpix2tick(X)) - move_torig - move_offset;
304 move_koffset = event_y() / 30 - move_korig;
306 else if(paste_flag){
307 paste_t = quantize(xpix2tick(event_x()));
308 paste_track = event_y() / 30;
310 redraw();
311 return 1;
312 case fltk::RELEASE:
313 if(event_button()==1){
314 if(box_flag){
315 apply_box();
316 box_flag = 0;
318 if(insert_flag){
319 apply_insert();
320 insert_flag = 0;
322 else if(move_flag){
323 apply_move();
324 move_flag = 0;
326 else if(rresize_flag){
327 apply_rresize();
328 rresize_flag = 0;
329 if(last_handle){
330 last_handle->lhandle = 0;
331 last_handle->rhandle = 0;
334 else if(lresize_flag){
335 apply_lresize();
336 lresize_flag = 0;
337 if(last_handle){
338 last_handle->lhandle = 0;
339 last_handle->rhandle = 0;
343 insert_flag=0;
344 color_sel = NULL;
346 else if(event_button()==2){
347 if(paste_flag){
348 apply_paste();
350 paste_flag=0;
352 else if(event_button()==3){
353 seqpat* over_s = over_seqpat();
354 if(delete_flag && over_s){
355 if(over_s->selected){
356 apply_delete();
359 delete_flag=0;
360 //last_handle==NULL;
365 redraw();
366 return 1;
367 case fltk::MOVE:
368 if(color_flag){break;}
369 seqpat* s = over_seqpat();
370 if(s){
371 if(over_rhandle(s,X,Y)){s->rhandle = 1;}
372 else{s->rhandle = 0;}
373 if(over_lhandle(s,X,Y)){s->lhandle = 1;}
374 else{s->lhandle = 0;}
375 if(s != last_handle){
376 if(last_handle){
377 last_handle->rhandle = 0;
378 last_handle->lhandle = 0;
380 last_handle = s;
382 redraw();
384 else if(last_handle){
385 last_handle->rhandle = 0;
386 last_handle->lhandle = 0;
387 last_handle = NULL;
388 redraw();
390 return 1;
393 return 0;
396 void Arranger::draw(){
398 fltk::push_clip(0,0,w(),h());
400 fltk::setfont(fltk::HELVETICA,8);
402 fltk::setcolor(fltk::GRAY05);
403 fltk::fillrect(0,0,w(),h());
405 fltk::setcolor(fltk::GRAY20);
406 int M = config.beats_per_measure;
407 int I=0;
408 for(int i=1; I<w(); i++){
409 I = i*zoom*M/4;
410 fltk::fillrect(I,0,1,h());
412 fltk::setcolor(fltk::GRAY50);
413 int P = config.measures_per_phrase;
414 if(P){
415 I=0;
416 for(int i=1; I<w(); i++){
417 I = i*zoom*4*P*M/4/4;
418 fltk::fillrect(I,0,1,h());
423 if(insert_flag){
424 fltk::setcolor(fltk::BLUE);
425 int T1 = insert_torig;
426 int T2 = T1 + insert_toffset;
427 int tmp;
428 if(T1>T2){SWAP(T1,T2);}
429 int X = tick2xpix(T1)+1;
430 int Y = insert_track*30;
431 int W = tick2xpix(T2)-tick2xpix(T1) - 1;
432 fltk::fillrect(X,Y,W,28);
435 if(move_flag){
436 if(check_move_safety()){
437 fltk::setcolor(fltk::MAGENTA);
439 else{
440 fltk::setcolor(fltk::RED);
443 for(int i=0; i<tracks.size(); i++){
444 seqpat* s = tracks[i]->head->next;
445 while(s){
446 if(s->selected){
447 int X = tick2xpix(s->tick + move_toffset);
448 int Y = (s->track + move_koffset)*30;
449 int W = tick2xpix(s->dur);
450 fltk::fillrect(X+1,Y+1,W-1,1);
451 fltk::fillrect(X+1,Y+1,1,29-1);
452 fltk::fillrect(X+1,Y+29-1,W-1,1);
453 fltk::fillrect(X+W-1,Y+1,1,29-1);
455 s = s->next;
460 if(paste_flag){
461 fltk::setcolor(fltk::GREEN);
462 int X = tick2xpix(paste_t)+1;
463 int Y = paste_track*zoom;
464 int W = tick2xpix(main_sel->dur);
465 fltk::fillrect(X,Y,W-1,1);
466 fltk::fillrect(X,Y+28,W-1,1);
467 fltk::fillrect(X,Y,1,28);
468 fltk::fillrect(X+W-2,Y,1,28);
471 int tmp;
472 if(box_flag){
473 fltk::setcolor(fltk::GREEN);
474 int X1,X2,Y1,Y2;
475 X1 = box_x1;
476 X2 = box_x2;
477 Y1 = box_y1;
478 Y2 = box_y2;
479 if(X1>X2){SWAP(X1,X2);}
480 if(Y1>Y2){SWAP(Y1,Y2);}
481 fltk::fillrect(X1,Y1,X2-X1,1);
482 fltk::fillrect(X1,Y1,1,Y2-Y1);
483 fltk::fillrect(X2,Y1,1,Y2-Y1);
484 fltk::fillrect(X1,Y2,X2-X1,1);
487 //draw all seqpat
488 seqpat* s;
489 fltk::Color c;
491 fltk::Color c1,c2,c3,cx;
492 c1 = fltk::BLACK;
494 for(int i=0; i<tracks.size(); i++){
496 s = tracks[i]->head->next;
497 while(s){
499 pattern* p = s->p;
501 get_outline_color(s,&c1,&c2,&c3,&cx);
503 fltk::setcolor(c1);
505 int R1 = lresize_flag&&s->selected ? lresize_toffset : 0;
506 int R2 = rresize_flag&&s->selected ? rresize_toffset : 0;
508 int T1 = s->tick+R1;
509 int T2 = s->tick+s->dur+R2;
511 if(T1 > T2){SWAP(T1,T2)};
513 int X = tick2xpix(T1)+1;
514 int Y = s->track * 30;
515 int W = tick2xpix(T2)-tick2xpix(T1)-1;
517 if(rresize_flag && s->selected && T1==T2){
518 W = tick2xpix(128)-1;
520 if(lresize_flag && s->selected && T1==T2){
521 W = tick2xpix(128)-1;
524 fillrect(X+1,Y+1,W-2,27);
525 float a = 1.5f;
528 fltk::setcolor(c2);
529 fillrect(X+W-1,Y,1,29);
530 fillrect(X,Y+28,W-1,1);
532 fltk::setcolor(c3);
533 fillrect(X,Y,1,28);
534 fillrect(X,Y,W,1);
536 fltk::push_clip(tick2xpix(T1),s->track*30,tick2xpix(T2-T1),30);
538 if(s->rhandle && !rresize_flag){
539 setcolor(cx);
540 if(delete_flag){
541 setcolor(fltk::color(128,0,0));
544 W = 5;
545 X = tick2xpix(s->tick+s->dur) - W - 1;
546 Y = s->track*30;
547 addvertex(X+W,Y+28/2);
548 addvertex(X,Y);
549 addvertex(X,Y+28);
550 fillpath();
553 if(s->lhandle && !lresize_flag){
554 setcolor(cx);
555 if(delete_flag){
556 setcolor(fltk::color(128,0,0));
558 W = 5;
559 X = tick2xpix(s->tick)+1;
560 Y = s->track*30;
561 addvertex(X,Y+28/2);
562 addvertex(X+W,Y);
563 addvertex(X+W,Y+28);
564 fillpath();
567 fltk::setcolor(cx);
570 mevent* e = s->p->events;
571 while(e){
572 if(e->tick >= s->dur){
573 break;
575 if(e->type == MIDI_NOTE_ON){
576 X = tick2xpix(e->tick) + tick2xpix(s->tick)+2;
577 Y = s->track*30 + 27 - e->value1*27/127;
578 W = tick2xpix(e->dur);
579 if(W==0){W=1;}
580 fillrect(X,Y,W,1);
582 e=e->next;
586 int total = s->layer_total();
587 if(total > 1){
588 fltk::setcolor(fltk::BLACK);
589 int X = tick2xpix(s->tick);
590 int Y = s->track * 30;
591 int count = s->layer_index()+1;
592 char buf[16];
593 snprintf(buf,16,"%d / %d",count,total);
594 fltk::drawtext(buf,X+2,Y+27);
598 fltk::pop_clip();
600 s=s->next;
604 fltk::pop_clip();
608 void Arranger::scrollTo(int X, int Y){
609 scrollx = X;
610 scrolly = Y;
611 redraw();
612 ui->song_timeline->scroll = X;
613 ui->song_timeline->redraw();
614 ui->track_info->scroll = Y;
615 ui->track_info->redraw();
620 seqpat* Arranger::over_seqpat(){
621 int track = event_y() / 30;
622 if(track >= tracks.size()){
623 return NULL;
625 int tick = xpix2tick(event_x());
626 seqpat* s = tfind<seqpat>(tracks[track]->head,tick);
627 if(s){
628 if(tick < s->tick+s->dur){
629 return s;
632 return NULL;
636 //true if over right handle of s
637 int Arranger::over_rhandle(seqpat* s, int X, int Y){
638 int X1 = tick2xpix(s->tick);
639 int X2 = X1 + tick2xpix(s->dur);
640 int Y1 = s->track * 30 + 1;
641 int Y2 = Y1 + 29;
643 if(tick2xpix(s->dur) < 10){
644 return 0;
647 return (Y > Y1 && Y < Y2 && X < X2 && X > X2 - 5);
650 //true if over left handle of s
651 int Arranger::over_lhandle(seqpat* s, int X, int Y){
652 int X1 = tick2xpix(s->tick);
653 int X2 = X1 + tick2xpix(s->dur);
654 int Y1 = s->track * 30 + 1;
655 int Y2 = Y1 + 29;
657 if(tick2xpix(s->dur) < 10){
658 return 0;
661 return (Y > Y1 && Y < Y2 && X < X1 + 5 + 1 && X > X1+1);
664 // 4=beats per measure, 128=ticks per beat, 30=width of measure in pixels
665 int Arranger::tick2xpix(int tick){
666 return tick *zoom /(128*4);
669 int Arranger::xpix2tick(int xpix){
670 return xpix * (128*4) /zoom;
673 int Arranger::quantize(int tick){
674 return tick/q_tick * q_tick;
678 void Arranger::update(int pos){
679 if(!is_backend_playing()){
680 return;
682 //int wp = ui->song_scroll->w();
683 int X1 = tick2xpix(pos);
684 int X2 = X1 - scrollx;
685 if(X1 > w()-40){
686 return;
688 if(X2 < 0){
689 scrollTo(X1-50<0?0:X1-50,scrolly);
691 if(X2 > w()-30){
692 scrollTo(X1-50,scrolly);
697 void Arranger::unselect_all(){
698 seqpat* s;
699 for(int i=0; i<tracks.size(); i++){
700 s = tracks[i]->head->next;
701 while(s){
702 if(s->selected==1){
703 s->selected = 0;
705 s = s->next;
710 void Arranger::get_outline_color(seqpat* s, fltk::Color* c1, fltk::Color* c2, fltk::Color* c3, fltk::Color* cx){
712 pattern* p = s->p;
713 *c1 = fltk::color(p->r1, p->g1, p->b1);
714 *cx = fltk::color(p->rx, p->gx, p->bx);
716 int T1,T2;
717 int tmp;
718 seqpat* over_s = over_seqpat();
719 if(delete_flag && s->selected){
720 *c1 = fltk::color(255,0,0);
721 *c2 = fltk::color(255,0,0);
722 *c3 = fltk::color(255,0,0);
723 return;
726 if(box_flag){
727 T1=box_t1;
728 T2=box_t2;
729 int K1 = box_k1;
730 int K2 = box_k2;
731 int K = s->track;
732 if(T1>T2){SWAP(T1,T2);}
733 if(K1<K2){SWAP(K1,K2);}
734 if(s->tick+s->dur > T1 && s->tick < T2 && K >= K2 && K <= K1){
735 *c1 = fltk::color(0,255,0);
736 *c2 = fltk::color(71,120,59);
737 *c3 = fltk::color(108,229,75);
738 return;
742 if(s->selected){
743 *c1 = fltk::color(255,255,0);
744 *c2 = fltk::color(140,137,46);
745 *c3 = fltk::color(232,255,37);
746 *cx = fltk::color(128,128,0);
747 return;
751 *c2 = fltk::color(p->r2,p->g2,p->b2);
752 *c3 = fltk::color(p->r3,p->g3,p->b3);
757 void Arranger::apply_insert(){
759 if(!check_insert_safety()){
760 return;
763 int tmp;
764 int T1 = insert_torig;
765 int T2 = T1 + insert_toffset;
766 if(T1>T2){SWAP(T1,T2);}
768 Command* c=new CreateSeqpatBlank(insert_track,T1,T2-T1);
769 set_undo(c);
770 undo_push(1);
772 if(T2>maxt){relayout();}
775 void Arranger::apply_box(){
776 seqpat* s;
777 int tmp;
778 int T1=box_t1;
779 int T2=box_t2;
780 int K1 = box_k1;
781 int K2 = box_k2;
782 if(T1>T2){SWAP(T1,T2);}
783 if(K1>K2){SWAP(K1,K2);}
784 if(K1 < 0){K1 = 0;}
785 if(K2 > tracks.size()-1){K2 = tracks.size()-1;}
786 for(int i=K1; i<=K2; i++){
787 s = tracks[i]->head->next;
788 while(s){
789 if(s->tick+s->dur > T1 && s->tick < T2){
790 s->selected = 1;
792 s = s->next;
798 void Arranger::apply_delete(){
799 Command* c;
800 seqpat* s;
801 seqpat* next;
802 int N=0;
803 for(int i=0; i<tracks.size(); i++){
804 s = tracks[i]->head->next;
805 while(s){
806 next = s->next;
807 if(s->selected){
808 tracks[s->track]->modified = 1;
809 c=new DeleteSeqpat(s);
810 set_undo(c);
811 N++;
813 s = next;
816 undo_push(N);
818 unmodify_and_unstick_tracks();
822 void Arranger::apply_move(){
823 if(move_toffset==0 && move_koffset==0){
824 return;
827 if(!check_move_safety()){
828 return;
831 Command* c;
832 seqpat* s;
833 seqpat* next;
834 int N=0;
835 for(int i=0; i<tracks.size(); i++){
836 s = tracks[i]->head->next;
837 while(s){
838 next = s->next;
839 if(s->selected && s->modified == 0){
840 int K = s->track + move_koffset;
841 int T = s->tick + move_toffset;
842 tracks[s->track]->modified = 1;
843 tracks[K]->modified = 1;
844 s->modified = 1;
845 c=new MoveSeqpat(s,K,T);
846 set_undo(c);
847 N++;
849 if(T+s->dur > maxt){relayout();}
851 s = next;
854 undo_push(N);
856 unmodify_blocks();
857 unmodify_and_unstick_tracks();
860 void Arranger::apply_paste(){
861 //safety check
864 Command* c;
866 c = new CreateSeqpat(paste_track,paste_t,main_sel,0);
867 set_undo(c);
868 undo_push(1);
873 void Arranger::apply_rresize(){
874 if(rresize_toffset==0){
875 return;
878 if(!check_resize_safety()){
879 return;
882 Command* c;
883 seqpat* s;
884 seqpat* next;
885 int tmp;
886 int N=0;
887 for(int i=0; i<tracks.size(); i++){
888 s = tracks[i]->head->next;
889 while(s){
890 next = s->next;
891 if(s->selected && s->modified == 0){
892 tracks[i]->modified = 1;
893 s->modified = 1;
894 int T1 = s->tick;
895 int T2 = s->tick + s->dur + rresize_toffset;
896 if(T1 > T2){
897 SWAP(T1,T2);
898 seqpat* stmp = s->prev;
899 //c=new ReverseSeqpat(s);
900 //set_undo(c);
901 s = stmp->next;
902 c=new ResizeSeqpat(s,T2-T1);
903 set_undo(c);
904 s = stmp->next;
905 c=new MoveSeqpat(s,s->track,T1);
906 set_undo(c);
907 N+=2;
909 s = stmp->next;
910 if(s->tick+s->dur > maxt){relayout();}
912 else{
913 if(T1==T2){
914 T2 = T1+128; //magic
916 c=new ResizeSeqpat(s,T2-T1);
917 set_undo(c);
918 N++;
920 if(T2 > maxt){relayout();}
924 s = next;
927 undo_push(N);
929 unmodify_blocks();
930 unmodify_and_unstick_tracks();
933 void Arranger::apply_lresize(){
934 if(lresize_toffset==0){
935 return;
938 if(!check_resize_safety()){
939 return;
942 Command* c;
943 seqpat* s;
944 seqpat* next;
945 int tmp;
946 int N=0;
947 for(int i=0; i<tracks.size(); i++){
948 s = tracks[i]->head->next;
949 while(s){
950 next = s->next;
951 if(s->selected && s->modified == 0){
952 tracks[i]->modified = 1;
953 s->modified = 1;
954 int T1 = s->tick + lresize_toffset;
955 int T2 = s->tick + s->dur;
956 if(T1 > T2){
957 SWAP(T1,T2);
958 seqpat* stmp = s->prev;
959 //c=new ReverseSeqpat(s);
960 //set_undo(c);
961 s = stmp->next;
962 c=new ResizeSeqpat(s,T2-T1);
963 set_undo(c);
964 s = stmp->next;
965 c=new MoveSeqpat(s,s->track,T1);
966 set_undo(c);
967 N+=2;
969 s = stmp->next;
970 if(s->tick+s->dur > maxt){relayout();}
972 else{
973 if(T1==T2){
974 T2 = T1+128; //magic
976 seqpat* stmp = s->prev;
977 c=new MoveSeqpat(s,s->track,T1);
978 set_undo(c);
979 s = stmp->next;
980 c=new ResizeSeqpat(s,T2-T1);
981 set_undo(c);
982 N+=2;
984 s = stmp->next;
985 if(s->tick+s->dur>maxt){relayout();}
989 s = next;
992 undo_push(N);
994 unmodify_blocks();
995 unmodify_and_unstick_tracks();
1000 int collision_test(int t11, int t12, int t21, int t22){
1001 return !((t11 < t21 && t12 <= t21) ||
1002 (t11 >= t22 && t12 > t22)) ? 1 : 0;
1005 int Arranger::check_move_safety(){
1006 seqpat* s;
1007 seqpat* ptr;
1009 for(int i=0; i<tracks.size(); i++){
1010 s = tracks[i]->head->next;
1011 while(s){
1012 if(s->selected){
1013 if(i+move_koffset < 0 || i+move_koffset > tracks.size()-1 ||
1014 s->tick + move_toffset < 0){
1015 return 0;
1017 ptr = tracks[i+move_koffset]->head->next;
1018 while(ptr){
1019 if(ptr == s){
1020 ptr=ptr->next; continue;
1022 if(collision_test(s->tick+move_toffset,s->tick+s->dur+move_toffset,ptr->tick,ptr->tick+ptr->dur) ){
1023 if(!ptr->selected){
1024 return 0;
1027 ptr = ptr->next;
1030 s = s->next;
1034 return 1;
1037 int Arranger::check_insert_safety(){
1038 seqpat* s;
1040 int T1 = insert_torig;
1041 int T2 = T1 + insert_toffset;
1042 int tmp;
1044 if(T1>T2){SWAP(T1,T2);}
1046 if(T1 < 0){
1047 return 0;
1049 if(insert_track > tracks.size()-1){
1050 return 0;
1052 if(tracks[insert_track]==NULL){
1053 return 0;
1056 s = tracks[insert_track]->head->next;
1058 while(s){
1059 if(collision_test(T1,T2,s->tick,s->tick+s->dur)){
1060 return 0;
1062 s = s->next;
1065 return 1;
1068 int Arranger::check_resize_safety(){
1069 seqpat* s;
1070 seqpat* ptr;
1072 int T1,T2;
1073 int S1,S2;
1074 int tmp;
1076 for(int i=0; i<tracks.size(); i++){
1077 s = tracks[i]->head->next;
1078 while(s){
1079 if(!s->selected){
1080 s = s->next; continue;
1083 if(rresize_flag){
1084 T1 = s->tick;
1085 T2 = s->tick + s->dur + rresize_toffset;
1087 else if(lresize_flag){
1088 T1 = s->tick + lresize_toffset;
1089 T2 = s->tick + s->dur;
1091 if(T1>T2){SWAP(T1,T2);}
1093 if(T1 < 0){
1094 return 0;
1096 ptr = tracks[s->track]->head->next;
1097 while(ptr){
1098 if(ptr == s){
1099 ptr=ptr->next; continue;
1102 S1 = ptr->tick;
1103 S2 = ptr->tick + ptr->dur;
1104 if(ptr->selected){
1105 if(rresize_flag){
1106 S2 += rresize_toffset;
1108 else if(lresize_flag){
1109 S1 += lresize_toffset;
1113 if(collision_test(T1,T2,S1,S2)){
1114 return 0;
1116 ptr = ptr->next;
1119 s = s->next;
1123 return 1;
1127 int Arranger::check_paste_safety(){
1128 return 1;