Replaced old fly mode for a fly mode that works in all 3 view types - ortho, perspect...
[blender-staging.git] / source / blender / src / drawseq.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #include <string.h>
38 #include <math.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BMF_Api.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
46
47 #include "IMB_imbuf_types.h"
48
49 #include "DNA_sequence_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_view2d_types.h"
54
55 #include "BKE_global.h"
56 #include "BKE_plugin_types.h"
57 #include "BKE_scene.h"
58 #include "BKE_utildefines.h"
59
60 #include "BIF_gl.h"
61 #include "BIF_mywindow.h"
62 #include "BIF_screen.h"
63 #include "BIF_drawseq.h"
64 #include "BIF_editseq.h"
65 #include "BIF_glutil.h"
66 #include "BIF_resources.h"
67 #include "BIF_space.h"
68 #include "BIF_interface.h"
69
70 #include "BSE_view.h"
71 #include "BSE_drawipo.h"
72 #include "BSE_sequence.h"
73 #include "BSE_seqeffects.h"
74 #include "BSE_seqscopes.h"
75 #include "BSE_seqaudio.h"
76
77 #include "IMB_imbuf_types.h"
78 #include "IMB_imbuf.h"
79
80 #include "blendef.h"    /* CFRA */
81 #include "mydevice.h"   /* REDRAWSEQ */
82
83 int no_rightbox=0, no_leftbox= 0;
84
85 static void EmbossBoxf(float x1, float y1, float x2, float y2, int sel, unsigned int dark, unsigned int light)
86 {
87
88         if(sel) cpack(dark);
89         else cpack(light);
90         if(sel) glLineWidth(2.0);
91         fdrawline(x1,  y2,  x2,  y2);   /* top */
92         if(no_leftbox==0) fdrawline(x1,  y1,  x1,  y2); /* left */
93
94         if(sel) glLineWidth(1.0);
95
96         if(sel) cpack(light);
97         else cpack(dark);
98         fdrawline(x1,  y1,  x2,  y1); /* bottom */
99         if(no_rightbox==0) fdrawline(x2,  y1,  x2,  y2);        /* right */
100
101 }
102
103 static char *give_seqname(Sequence *seq)
104 {
105         if(seq->type==SEQ_META) {
106                 if(seq->name[2]) return seq->name+2;
107                 return "META";
108         }
109         else if(seq->type==SEQ_IMAGE) return "IMAGE";
110         else if(seq->type==SEQ_SCENE) return "SCENE";
111         else if(seq->type==SEQ_MOVIE) return "MOVIE";
112         else if(seq->type==SEQ_RAM_SOUND) return "AUDIO (RAM)";
113         else if(seq->type==SEQ_HD_SOUND) return "AUDIO (HD)";
114         else if(seq->type<SEQ_EFFECT) return seq->strip->dir;
115         else if(seq->type==SEQ_CROSS) return "CROSS";
116         else if(seq->type==SEQ_GAMCROSS) return "GAMMA CROSS";
117         else if(seq->type==SEQ_ADD) return "ADD";
118         else if(seq->type==SEQ_SUB) return "SUB";
119         else if(seq->type==SEQ_MUL) return "MUL";
120         else if(seq->type==SEQ_ALPHAOVER) return "ALPHAOVER";
121         else if(seq->type==SEQ_ALPHAUNDER) return "ALPHAUNDER";
122         else if(seq->type==SEQ_OVERDROP) return "OVER DROP";
123         else if(seq->type==SEQ_WIPE) return "WIPE";
124         else if(seq->type==SEQ_GLOW) return "GLOW";
125         else if(seq->type==SEQ_PLUGIN) {
126                 if(seq->plugin && seq->plugin->doit) return seq->plugin->pname;
127                 return "PLUGIN";
128         }
129         else return "EFFECT";
130
131 }
132 static void draw_cfra_seq(void)
133 {
134         glColor3ub(0x30, 0x90, 0x50);
135         glLineWidth(2.0);
136         glBegin(GL_LINES);
137         glVertex2f(G.scene->r.cfra, G.v2d->cur.ymin);
138         glVertex2f(G.scene->r.cfra, G.v2d->cur.ymax);
139         glEnd();
140         glLineWidth(1.0);
141 }
142
143 static unsigned int seq_color(Sequence *seq)
144 {
145         switch(seq->type) {
146         case SEQ_META:
147                 return 0x509090;
148         case SEQ_MOVIE:
149                 return 0x805040;
150         case SEQ_SCENE:
151                 if(seq->scene==G.scene) return 0x709050;
152                 return 0x609060;
153         case SEQ_CROSS:
154                 return 0x505090;
155         case SEQ_GAMCROSS:
156                 return 0x5040A0;
157         case SEQ_ADD:
158                 return 0x6060A0;
159         case SEQ_SUB:
160                 return 0x8060A0;
161         case SEQ_MUL:
162                 return 0x8080A0;
163         case SEQ_ALPHAOVER:
164                 return 0x6080A0;
165         case SEQ_ALPHAUNDER:
166                 return 0x9080A0;
167         case SEQ_OVERDROP:
168                 return 0x5080B0;
169         case SEQ_WIPE:
170                 return 0x2080B0;
171         case SEQ_GLOW:
172                 return 0x0080B0;
173         case SEQ_PLUGIN:
174                 return 0x906000;
175         case SEQ_HD_SOUND:
176                 if(seq->flag & SEQ_MUTE) return 0x707060; else return 0x787850;
177         case SEQ_RAM_SOUND:
178                 if(seq->flag & SEQ_MUTE) return 0x707060; else return 0x787850;
179         default:
180                 return 0x906060;
181         }
182
183 }
184 static void drawmeta_contents(Sequence *seqm, float x1, float y1, float x2, float y2)
185 {
186         Sequence *seq;
187         float dx;
188         int nr;
189
190         nr= 0;
191         WHILE_SEQ(&seqm->seqbase) {
192                 nr++;
193         }
194         END_SEQ
195
196         dx= (x2-x1)/nr;
197
198         WHILE_SEQ(&seqm->seqbase) {
199                 cpack(seq_color(seq));
200                 glRectf(x1,  y1,  x1+0.9*dx,  y2);
201                 EmbossBoxf(x1, y1, x1+0.9*dx, y2, 0, 0x404040, 0xB0B0B0);
202                 x1+= dx;
203         }
204         END_SEQ
205 }
206
207 static void drawseqwave(Sequence *seq, float x1, float y1, float x2, float y2, int winx)
208 {
209         float f, height, midy, clipxmin, clipxmax, sample_step;
210         int offset, offset_next, sofs, eofs, i=0;
211         signed short* s;
212         bSound *sound;
213         int wavesample, wavesamplemin, wavesamplemax, subsample_step=4; /* used for finding the min and max wave peaks */
214         Uint8 *stream;
215         float fsofs, feofs_sofs, sound_width, wavemulti; /* for faster access in the loop */
216         
217         audio_makestream(seq->sound);
218         if(seq->sound->stream==NULL) return;    
219         
220         if (seq->flag & SEQ_MUTE) glColor3ub(0x70, 0x80, 0x80); else glColor3ub(0x70, 0xc0, 0xc0);
221         
222         sofs = ((int)( (((float)(seq->startdisp-seq->start))/(float)G.scene->r.frs_sec)*(float)G.scene->audio.mixrate*4.0 )) & (~3);
223         eofs = ((int)( (((float)(seq->enddisp-seq->start))/(float)G.scene->r.frs_sec)*(float)G.scene->audio.mixrate*4.0 )) & (~3);
224         
225         /* clip the drawing area to the screen bounds to save time */
226         sample_step= (G.v2d->cur.xmax-G.v2d->cur.xmin)/winx;
227         clipxmin= MAX2(x1, G.v2d->cur.xmin);
228         clipxmax= MIN2(x2, G.v2d->cur.xmax);
229         
230         /* Stops dithering on redraw when clipxmin is offset. */
231         if (clipxmin != x1) {
232                 clipxmin = (float) ((int)((clipxmin*sample_step)+(i*sample_step))) / sample_step;
233                 while (clipxmin < x1) {
234                         clipxmin = (float) ((int)((clipxmin*sample_step)+(i*sample_step))) / sample_step;
235                         i+=1;
236                 }
237                 clipxmin = (float)((int)clipxmin); /* snap to int */    
238         }
239         
240         /* when the sample step is 4 every sample of the wave is evaluated for min and max
241         values used to draw the wave, however this is slow ehrn zoomed out
242         so when the sample step is above 1 (the larger the further out the zoom is)
243         so not evaluate all samples, only some.*/
244         if (sample_step > 1)
245                 subsample_step= ((int)(subsample_step*sample_step*8)) & (~3);
246         
247         /* for speedy access */
248         midy = (y1+y2)/2;
249         fsofs= (float)sofs;
250         feofs_sofs= (float)(eofs-sofs);
251         sound_width= x2-x1;
252         height= y2-y1;
253         sound = seq->sound;
254         stream = sound->stream;
255         wavemulti = height/196605;
256         wavesample=0;
257         
258         
259         /* we need to get the starting offset value, excuse the duplicate code */
260         f=clipxmin;
261         offset = (int) (fsofs + ((f-x1)/sound_width) * feofs_sofs) & (~3);
262         
263         /* start the loop, draw a line per sample_step -sample_step is about 1 line drawn per pixel */
264         glBegin(GL_LINES);
265         for (f=clipxmin+sample_step; f<=clipxmax; f+=sample_step) {
266                 
267                 offset_next = (int) (fsofs + ((f-x1)/sound_width) * feofs_sofs) & (~3);
268                 
269                 /* if this is close to the last sample just exit */
270                 if (offset_next >= sound->streamlen) break;
271                 
272                 wavesamplemin = 131070;
273                 wavesamplemax = -131070;
274                 
275                 /*find with high and low of the waveform for this draw,
276                 evaluate small samples to find this range */
277                 while (offset < offset_next) {
278                         s = (signed short*)(stream+offset);
279                         
280                         wavesample = s[0]*2 + s[1];
281                         if (wavesamplemin>wavesample)
282                                 wavesamplemin=wavesample;
283                         if (wavesamplemax<wavesample)
284                                 wavesamplemax=wavesample;
285                         offset+=subsample_step;
286                 }
287                 /* draw the wave line, looks good up close and zoomed out */
288                 glVertex2f(f,  midy-(wavemulti*wavesamplemin) );
289                 glVertex2f(f,  midy-(wavemulti*wavesamplemax) );
290                 offset=offset_next;
291         }
292         glEnd();
293 }
294
295 /*
296 Draw a sequencer block, bounds check alredy made
297 ScrArea is currently only used to get the windows width in pixels
298 so wave file sample drawing precission is zoom adjusted
299 */
300 void drawseq(Sequence *seq, ScrArea *sa)
301 {
302         float v1[2], v2[2], x1, x2, y1, y2, color_tint[4];
303         unsigned int body, dark, light;
304         int len, size;
305         short mval[2];
306         char str[120], *strp;
307
308
309         if(seq->startdisp > seq->enddisp) body= 0x707070;
310
311         body= seq_color(seq);
312         dark= 0x202020;
313         light= 0xB0B0B0;
314
315         if(G.moving && (seq->flag & SELECT)) {
316                 if(seq->flag & SEQ_OVERLAP) dark= light= 0x4040FF;
317                 else {
318                         if(seq->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL));
319                         else dark= light= 0xFFFFFF;
320                 }
321         }
322
323         /* body */
324         if(seq->startstill) x1= seq->start;
325         else x1= seq->startdisp;
326         y1= seq->machine+0.2;
327         if(seq->endstill) x2= seq->start+seq->len;
328         else x2= seq->enddisp;
329         y2= seq->machine+0.8;
330
331         cpack(body);
332         glRectf(x1,  y1,  x2,  y2);
333         if (seq->type == SEQ_RAM_SOUND) drawseqwave(seq, x1, y1, x2, y2, sa->winx);
334         EmbossBoxf(x1, y1, x2, y2, seq->flag & 1, dark, light);
335
336         v1[1]= y1;
337         v2[1]= y2;
338         if(seq->type < SEQ_EFFECT) {
339
340                 /* decoration: the bars */
341                 x1= seq->startdisp;
342                 x2= seq->enddisp;
343
344                 if(seq->startofs) {
345                         cpack(0x707070);
346                         glRectf((float)(seq->start),  y1-0.2,  x1,  y1);
347                         EmbossBoxf((float)(seq->start), y1-0.2, x1, y1, seq->flag & 1, dark, light);
348                 }
349                 if(seq->endofs) {
350                         cpack(0x707070);
351                         glRectf(x2,  y2,  (float)(seq->start+seq->len),  y2+0.2);
352                         EmbossBoxf(x2, y2, (float)(seq->start+seq->len), y2+0.2, seq->flag & 1, dark, light);
353                 }
354
355                 if(seq->startstill) {
356                         cpack(body);
357                         glRectf(x1,  y1+0.1,  (float)(seq->start),  y1+0.5);
358                         no_rightbox= 1;
359                         EmbossBoxf(x1, y1+0.1, (float)(seq->start), y1+0.5, seq->flag & 1, dark, light);
360                         no_rightbox= 0;
361                 }
362                 if(seq->endstill) {
363                         cpack(body);
364                         glRectf((float)(seq->start+seq->len),  y1+0.1,  x2,  y1+0.5);
365                         no_leftbox= 1;
366                         EmbossBoxf((float)(seq->start+seq->len), y1+0.1, x2, y1+0.5, seq->flag & 1, dark, light);
367                         no_leftbox= 0;
368                 }
369
370         }
371
372         /* calculate if seq is long enough to print a name */
373         x1= seq->startdisp+seq->handsize;
374         x2= seq->enddisp-seq->handsize;
375
376         /* but first the contents of a meta */
377         if(seq->type==SEQ_META) drawmeta_contents(seq, x1, y1+0.15, x2, y2-0.15);
378
379         if(x1<G.v2d->cur.xmin) x1= G.v2d->cur.xmin;
380         else if(x1>G.v2d->cur.xmax) x1= G.v2d->cur.xmax;
381         if(x2<G.v2d->cur.xmin) x2= G.v2d->cur.xmin;
382         else if(x2>G.v2d->cur.xmax) x2= G.v2d->cur.xmax;
383
384         if(x1 != x2) {
385                 v1[0]= x1;
386                 ipoco_to_areaco_noclip(G.v2d, v1, mval);
387                 x1= mval[0];
388                 v2[0]= x2;
389                 ipoco_to_areaco_noclip(G.v2d, v2, mval);
390                 x2= mval[0];
391                 size= x2-x1;
392
393                 if(seq->name[2]) {
394                         sprintf(str, "%s: %s (%d)", give_seqname(seq), seq->name+2, seq->len);
395                 }else{
396                         if(seq->type == SEQ_META) {
397                                 sprintf(str, "%d %s", seq->len, give_seqname(seq));
398                         }
399                         else if(seq->type == SEQ_SCENE) {
400                                 if(seq->scene) sprintf(str, "%d %s %s", seq->len, give_seqname(seq), seq->scene->id.name+2);
401                                 else sprintf(str, "%d %s", seq->len, give_seqname(seq));
402
403                         }
404                         else if(seq->type == SEQ_IMAGE) {
405                                 sprintf(str, "%d %s%s", seq->len, seq->strip->dir, seq->strip->stripdata->name);
406                         }
407                         else if(seq->type & SEQ_EFFECT) {
408                                 if(seq->seq3!=seq->seq2 && seq->seq1!=seq->seq3)
409                                         sprintf(str, "%d %s: %d-%d (use %d)", seq->len, give_seqname(seq), seq->seq1->machine, seq->seq2->machine, seq->seq3->machine);
410                                 else
411                                         sprintf(str, "%d %s: %d-%d", seq->len, give_seqname(seq), seq->seq1->machine, seq->seq2->machine);
412                         }
413                         else if (seq->type == SEQ_RAM_SOUND) {
414                                 sprintf(str, "%d %s", seq->len, seq->strip->stripdata->name);
415                         }
416                         else if (seq->type == SEQ_HD_SOUND) {
417                                 sprintf(str, "%d %s", seq->len, seq->strip->stripdata->name);
418                         }
419                         else if (seq->type == SEQ_MOVIE) {
420                                 sprintf(str, "%d %s%s", seq->len, seq->strip->dir, seq->strip->stripdata->name);
421                         }
422                 }
423
424
425                 strp= str;
426
427                 while( (len= BMF_GetStringWidth(G.font, strp)) > size) {
428                         if(len < 10) break;
429                         if(strp[1]==0) break;
430                         strp++;
431                 }
432
433                 mval[0]= (x1+x2-len+1)/2;
434                 mval[1]= 1;
435                 areamouseco_to_ipoco(G.v2d, mval, &x1, &x2);
436
437                 if(seq->flag & SELECT) cpack(0xFFFFFF);
438                 else cpack(0x0);
439                 glRasterPos3f(x1,  y1+0.2, 0.0);
440                 BMF_DrawString(G.font, strp);
441         }
442         
443
444         
445         if(seq->type < SEQ_EFFECT) {
446                 /* decoration: triangles */
447                 x1= seq->startdisp;
448                 x2= seq->enddisp;
449
450                 body+= 0x101010;
451                 dark= 0x202020;
452                 light= 0xB0B0B0;
453
454                 /* left triangle */
455                 if(seq->flag & SEQ_LEFTSEL) {
456                         cpack(body+0x20);
457                         if(G.moving) {
458                                 if(seq->flag & SEQ_OVERLAP) dark= light= 0x4040FF;
459                                 else dark= light= 0xFFFFFF;
460                         }
461                 } else {
462                         cpack(body);
463                 }
464         
465                 /*Tint the color for wave display to show through */
466                 if (seq->type == SEQ_RAM_SOUND) {
467                         glEnable( GL_BLEND );
468                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
469                         glGetFloatv(GL_CURRENT_COLOR, color_tint);
470                         glColor4f(color_tint[0], color_tint[1], color_tint[2], 0.7);
471                 }
472                 
473                 glBegin(GL_TRIANGLES);
474                         v1[0]= x1; glVertex2fv(v1);
475                         v2[0]= x1; glVertex2fv(v2);
476                         v2[0]+= seq->handsize; v2[1]= (y1+y2)/2.0; glVertex2fv(v2); v2[1]= y2;
477                 glEnd();
478
479                 cpack(light);
480                 glBegin(GL_LINE_STRIP);
481                         v1[0]= x1; glVertex2fv(v1);
482                         v2[0]= x1; glVertex2fv(v2);
483                         v2[0]+= seq->handsize; v2[1]= (y1+y2)/2.0; glVertex2fv(v2); v2[1]= y2;
484                         cpack(dark);
485                         glVertex2fv(v1);
486                 glEnd();
487         }
488
489
490                 /* right triangle */
491         if(seq->type < SEQ_EFFECT) {
492                 dark= 0x202020;
493                 light= 0xB0B0B0;
494
495                 if(seq->flag & SEQ_RIGHTSEL) {
496                         cpack(body+0x20);
497                         if(G.moving) {
498                                 if(seq->flag & SEQ_OVERLAP) dark= light= 0x4040FF;
499                                 else dark= light= 0xFFFFFF;
500                         }
501                 }
502                 else {
503                         cpack(body);
504                 }
505                 /*Tint the color for wave display to show through */
506                 if (seq->type == SEQ_RAM_SOUND) {
507                         glGetFloatv(GL_CURRENT_COLOR, color_tint);
508                         glColor4f(color_tint[0], color_tint[1], color_tint[2], 0.7);
509                 }
510                 
511                 glBegin(GL_TRIANGLES);
512                         v2[0]= x2; glVertex2fv(v2);
513                         v1[0]= x2; glVertex2fv(v1);
514                         v2[0]-= seq->handsize; v2[1]= (y1+y2)/2.0; glVertex2fv(v2); v2[1]= y2;
515                 glEnd();
516                 
517                 if (seq->type == SEQ_RAM_SOUND)
518                         glDisable( GL_BLEND );
519
520                 cpack(dark);
521                 glBegin(GL_LINE_STRIP);
522                         v2[0]= x2; glVertex2fv(v2);
523                         v1[0]= x2; glVertex2fv(v1);
524                         v1[0]-= seq->handsize; v1[1]= (y1+y2)/2.0; glVertex2fv(v1); v1[1]= y2;
525                         cpack(light);
526                         glVertex2fv(v2);
527                 glEnd();
528         }
529         
530         
531         if(G.moving || (seq->flag & SEQ_LEFTSEL)) {
532                 cpack(0xFFFFFF);
533                 glRasterPos3f(x1,  y1+0.2, 0.0);
534                 sprintf(str, "%d", seq->startdisp);
535                 BMF_DrawString(G.font, str);
536         }
537         
538         if(G.moving || (seq->flag & SEQ_RIGHTSEL)) {
539                 cpack(0xFFFFFF);
540                 glRasterPos3f(x2-seq->handsize/2,  y1+0.2, 0.0);
541                 sprintf(str, "%d", seq->enddisp-1);
542                 BMF_DrawString(G.font, str);
543         }
544 }
545
546 static Sequence *special_seq_update= 0;
547
548 void set_special_seq_update(int val)
549 {
550         int x;
551
552         /* if mouse over a sequence && LEFTMOUSE */
553         if(val) {
554                 special_seq_update= find_nearest_seq(&x);
555         }
556         else special_seq_update= 0;
557 }
558
559
560 static void draw_image_seq(ScrArea *sa)
561 {
562         SpaceSeq *sseq;
563         StripElem *se;
564         struct ImBuf *ibuf;
565         int x1, y1, rectx, recty;
566         int free_ibuf = 0;
567         float zoom;
568
569         glClearColor(0.0, 0.0, 0.0, 0.0);
570         glClear(GL_COLOR_BUFFER_BIT);
571
572         sseq= sa->spacedata.first;
573         if(sseq==0) return;
574
575         rectx= (G.scene->r.size*G.scene->r.xsch)/100;
576         recty= (G.scene->r.size*G.scene->r.ysch)/100;
577
578         ibuf= (ImBuf *)give_ibuf_seq(rectx, recty,
579                                      (G.scene->r.cfra), sseq->chanshown);
580
581         if(special_seq_update) {
582                 se = special_seq_update->curelem;
583                 if(se) {
584                         if(se->ok==2) {
585                                 if(se->se1)
586                                         ibuf= se->se1->ibuf;
587                         }
588                         else ibuf= se->ibuf;
589                 }
590         }
591         if(ibuf==NULL) 
592                 return;
593         if(ibuf->rect_float && ibuf->rect==NULL)
594                 IMB_rect_from_float(ibuf);
595         if(ibuf->rect==NULL) 
596                 return;
597
598         if (sseq->mainb == SEQ_DRAW_IMG_WAVEFORM) {
599                 ibuf = make_waveform_view_from_ibuf(ibuf);
600                 free_ibuf = 1;
601         } else if (sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE) {
602                 ibuf = make_vectorscope_view_from_ibuf(ibuf);
603                 free_ibuf = 1;
604         }
605
606         if (sseq->zoom > 0) {
607                 zoom = sseq->zoom;
608         } else if (sseq->zoom == 0) {
609                 zoom = 1.0;
610         } else {
611                 zoom = -1.0/sseq->zoom;
612         }
613
614         /* calc location */
615         x1= (sa->winx-zoom*ibuf->x)/2;
616         y1= (sa->winy-zoom*ibuf->y)/2;
617
618         /* needed for gla draw */
619         glaDefine2DArea(&curarea->winrct);
620         glPixelZoom(zoom, zoom);
621         
622         glaDrawPixelsSafe(x1, y1, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
623         
624         glPixelZoom(1.0, 1.0);
625
626         if (free_ibuf) {
627                 IMB_freeImBuf(ibuf);
628         }
629
630         sa->win_swap= WIN_BACK_OK;
631 }
632
633 static void draw_extra_seqinfo(void)
634 {
635         Sequence *last_seq = get_last_seq();
636         StripElem *se, *last;
637         float xco, xfac;
638         int sta, end;
639         char str[256];
640
641         if(last_seq==0) return;
642
643         /* xfac: size of 1 pixel */
644         xfac= G.v2d->cur.xmax - G.v2d->cur.xmin;
645         xfac/= (float)(G.v2d->mask.xmax-G.v2d->mask.xmin);
646         xco= G.v2d->cur.xmin+40*xfac;
647
648         BIF_ThemeColor(TH_TEXT);
649
650         /* NAME */
651         glRasterPos3f(xco,  0.3, 0.0);
652         strncpy(str, give_seqname(last_seq), 255);
653         BMF_DrawString(G.font, str);
654         xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac;
655
656         if(last_seq->type==SEQ_SCENE && last_seq->scene) {
657                 glRasterPos3f(xco,  0.3, 0.0);
658                 BMF_DrawString(G.font, last_seq->scene->id.name+2);
659                 xco += xfac*BMF_GetStringWidth(G.font, last_seq->scene->id.name+2) +30.0*xfac;
660         }
661
662         /* LEN */
663         if(last_seq->type & SEQ_EFFECT)
664                 sprintf(str, "len: %d   From %d - %d", last_seq->len, last_seq->startdisp, last_seq->enddisp-1);
665         else
666                 sprintf(str, "len: %d (%d)", last_seq->enddisp-last_seq->startdisp, last_seq->len);
667
668         glRasterPos3f(xco,  0.3, 0.0);
669         BMF_DrawString(G.font, str);
670         xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac;
671
672         if(last_seq->type==SEQ_IMAGE) {
673
674                 /* CURRENT */
675                 se= (StripElem *)give_stripelem(last_seq,  (G.scene->r.cfra));
676                 if(se) {
677                         sprintf(str, "cur: %s", se->name);
678                         glRasterPos3f(xco,  0.3, 0.0);
679                         BMF_DrawString(G.font, str);
680                         xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac;
681                 }
682
683                 /* FIRST AND LAST */
684
685                 if(last_seq->strip) {
686                         se= last_seq->strip->stripdata;
687                         last= se+last_seq->len-1;
688                         if(last_seq->startofs) se+= last_seq->startofs;
689                         if(last_seq->endofs) last-= last_seq->endofs;
690
691                         sprintf(str, "First: %s at %d     Last: %s at %d", se->name, last_seq->startdisp, last->name, last_seq->enddisp-1);
692                         glRasterPos3f(xco,  0.3, 0.0);
693                         BMF_DrawString(G.font, str);
694                         xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac;
695
696                         /* orig size */
697                         sprintf(str, "OrigSize: %d x %d", last_seq->strip->orx, last_seq->strip->ory);
698                         glRasterPos3f(xco,  0.3, 0.0);
699                         BMF_DrawString(G.font, str);
700                         xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac;
701                 }
702         }
703         else if(last_seq->type==SEQ_MOVIE) {
704
705                 sta= last_seq->startofs;
706                 end= last_seq->len-1-last_seq->endofs;
707
708                 sprintf(str, "%s   %s%s  First: %d at %d     Last: %d at %d     Cur: %d",
709                                 last_seq->name+2, last_seq->strip->dir, last_seq->strip->stripdata->name,
710                                 sta, last_seq->startdisp, end, last_seq->enddisp-1,  (G.scene->r.cfra)-last_seq->startdisp);
711
712                 glRasterPos3f(xco,  0.3, 0.0);
713                 BMF_DrawString(G.font, str);
714         }
715         else if(last_seq->type==SEQ_RAM_SOUND
716                 || last_seq->type == SEQ_HD_SOUND) {
717
718                 sta= last_seq->startofs;
719                 end= last_seq->len-1-last_seq->endofs;
720
721                 sprintf(str, "%s   %s%s  First: %d at %d     Last: %d at %d     Cur: %d     Gain: %.2f dB     Pan: %.2f",
722                                 last_seq->name+2, last_seq->strip->dir, last_seq->strip->stripdata->name,
723                                 sta, last_seq->startdisp, end, last_seq->enddisp-1,  (G.scene->r.cfra)-last_seq->startdisp,
724                                 last_seq->level, last_seq->pan);
725
726                 glRasterPos3f(xco,  0.3, 0.0);
727                 BMF_DrawString(G.font, str);
728         }
729 }
730
731 #define SEQ_BUT_PLUGIN  1
732 #define SEQ_BUT_RELOAD  2
733 #define SEQ_BUT_EFFECT  3
734
735 void do_seqbuttons(short val)
736 {
737         Sequence *last_seq = get_last_seq();
738
739         switch(val) {
740         case SEQ_BUT_PLUGIN:
741                 new_stripdata(last_seq);
742                 free_imbuf_effect_spec(CFRA);
743                 break;
744
745         case SEQ_BUT_RELOAD:
746                 free_imbuf_seq();       // frees all
747                 break;
748         case SEQ_BUT_EFFECT:
749                 new_stripdata(last_seq);
750                 calc_sequence(last_seq);
751                 break;
752         }
753
754         allqueue(REDRAWSEQ, 0);
755 }
756
757 static void seq_panel_properties(short cntrl)   // SEQ_HANDLER_PROPERTIES
758 {
759         Sequence *last_seq = get_last_seq();
760         uiBlock *block;
761
762         block= uiNewBlock(&curarea->uiblocks, "seq_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
763         uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
764         uiSetPanelHandler(SEQ_HANDLER_PROPERTIES);  // for close and esc
765         if(uiNewPanel(curarea, block, "Strip Properties", "Seq", 10, 230, 318, 204)==0) return;
766
767         if(last_seq==NULL) return;
768
769         if(last_seq->type==SEQ_PLUGIN) {
770                 PluginSeq *pis;
771                 VarStruct *varstr;
772                 int a, xco, yco;
773
774                 uiDefBut(block, LABEL, 0, "Type: Plugin", 10,50,70,20, 0, 0, 0, 0, 0, "");
775
776                 pis= last_seq->plugin;
777                 if(pis->vars==0) return;
778
779                 varstr= pis->varstr;
780                 if(varstr) {
781                         for(a=0; a<pis->vars; a++, varstr++) {
782                                 xco= 150*(a/6)+10;
783                                 yco= 125 - 20*(a % 6)+1;
784                                 uiDefBut(block, varstr->type, SEQ_BUT_PLUGIN, varstr->name, xco,yco,150,19, &(pis->data[a]), varstr->min, varstr->max, 100, 0, varstr->tip);
785
786                         }
787                 }
788                 uiDefButBitS(block, TOG, SEQ_IPO_FRAME_LOCKED,
789                              SEQ_BUT_RELOAD, "IPO Frame locked",
790                              10,-40,150,19, &last_seq->flag,
791                              0.0, 1.0, 0, 0,
792                              "Lock the IPO coordinates to the "
793                              "global frame counter.");
794
795         }
796         else if(last_seq->type==SEQ_IMAGE) {
797
798                 uiDefBut(block, LABEL, 0, "Type: Image", 10,140,150,20, 0, 0, 0, 0, 0, "");
799                 uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
800                 
801                 uiBlockBeginAlign(block);
802                 uiDefButBitS(block, TOG, SEQ_MAKE_PREMUL, SEQ_BUT_RELOAD, "Convert to Premul", 10,90,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Converts RGB values to become premultiplied with Alpha");
803                 uiDefButBitS(block, TOG, SEQ_FILTERY, SEQ_BUT_RELOAD, "FilterY",        10,70,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "For video movies to remove fields");
804                 uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Mul:",                   10,50,150,19, &last_seq->mul, 0.001, 5.0, 100, 0, "Multiply colors");
805                 uiDefButS(block, TOG|BIT|7, SEQ_BUT_RELOAD, "Reverse Frames", 10,30,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Reverse frame order");
806                 uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Strobe:",                        10,10,150,19, &last_seq->strobe, 1.0, 30.0, 100, 0, "Only display every nth frame");
807                 uiBlockEndAlign(block);
808         }
809         else if(last_seq->type==SEQ_META) {
810
811                 uiDefBut(block, LABEL, 0, "Type: Meta", 10,140,150,20, 0, 0, 0, 0, 0, "");
812                 uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
813
814         }
815         else if(last_seq->type==SEQ_SCENE) {
816
817                 uiDefBut(block, LABEL, 0, "Type: Scene", 10,140,150,20, 0, 0, 0, 0, 0, "");
818                 uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
819                 uiDefButS(block, TOG|BIT|7, SEQ_BUT_RELOAD, "Reverse Frames", 10,90,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Reverse frame order");
820         }
821         else if(last_seq->type==SEQ_MOVIE) {
822
823                 if(last_seq->mul==0.0) last_seq->mul= 1.0;
824
825                 uiDefBut(block, LABEL, 0, "Type: Movie", 10,140,150,20, 0, 0, 0, 0, 0, "");
826                 uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
827                 
828                 uiBlockBeginAlign(block);
829                 uiDefButBitS(block, TOG, SEQ_MAKE_PREMUL, SEQ_BUT_RELOAD, "Make Premul Alpha ", 10,90,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Converts RGB values to become premultiplied with Alpha");
830                 uiDefButBitS(block, TOG, SEQ_FILTERY, SEQ_BUT_RELOAD, "FilterY ",       10,70,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "For video movies to remove fields");
831                 uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Mul:",                   10,50,150,19, &last_seq->mul, 0.001, 5.0, 100, 0, "Multiply colors");
832                 
833                 uiDefButS(block, TOG|BIT|7, SEQ_BUT_RELOAD, "Reverse Frames", 10,30,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Reverse frame order");
834                 uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Strobe:",                        10,10,150,19, &last_seq->strobe, 1.0, 30.0, 100, 0, "Only display every nth frame");
835                 uiDefButI(block, NUM, SEQ_BUT_RELOAD, "Preseek:",                       10,-10,150,19, &last_seq->anim_preseek, 0.0, 50.0, 100, 0, "On MPEG-seeking preseek this many frames");
836                 uiBlockEndAlign(block);
837         }
838         else if(last_seq->type==SEQ_RAM_SOUND || 
839                 last_seq->type==SEQ_HD_SOUND) {
840
841                 uiDefBut(block, LABEL, 0, "Type: Audio", 10,140,150,20, 0, 0, 0, 0, 0, "");
842                 uiDefBut(block, TEX, 0, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
843                 
844                 uiBlockBeginAlign(block);
845                 uiDefButBitS(block, TOG, SEQ_IPO_FRAME_LOCKED,
846                              SEQ_BUT_RELOAD, "IPO Frame locked",
847                              10,90,150,19, &last_seq->flag, 
848                              0.0, 1.0, 0, 0, 
849                              "Lock the IPO coordinates to the "
850                              "global frame counter.");
851
852                 uiDefButBitS(block, TOG, SEQ_MUTE, B_NOP, "Mute", 10,70,120,19, &last_seq->flag, 0.0, 21.0, 100, 0, "");
853                 uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Gain (dB):", 10,50,150,19, &last_seq->level, -96.0, 6.0, 100, 0, "");
854                 uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Pan:",   10,30,150,19, &last_seq->pan, -1.0, 1.0, 100, 0, "");
855                 uiBlockEndAlign(block);
856         }
857         else if(last_seq->type>=SEQ_EFFECT) {
858                 uiDefBut(block, LABEL, 0, "Type: Effect", 10,140,150,20, 0, 0, 0, 0, 0, "");
859                 uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
860                 
861                 uiDefButBitS(block, TOG, SEQ_IPO_FRAME_LOCKED,
862                              SEQ_BUT_RELOAD, "IPO Frame locked",
863                              10,90,150,19, &last_seq->flag, 
864                              0.0, 1.0, 0, 0, 
865                              "Lock the IPO coordinates to the "
866                              "global frame counter.");
867                 
868                 uiBlockBeginAlign(block);
869                 if(last_seq->type==SEQ_WIPE){
870                         WipeVars *wipe = (WipeVars *)last_seq->effectdata;
871                         char formatstring[256];
872                         
873                         strncpy(formatstring, "Transition Type %t|Single Wipe%x0|Double Wipe %x1|Iris Wipe %x4|Clock Wipe %x5", 255);
874                         uiDefButS(block, MENU,SEQ_BUT_EFFECT, formatstring,     10,65,220,22, &wipe->wipetype, 0, 0, 0, 0, "What type of wipe should be performed");
875                         uiDefButF(block, NUM,SEQ_BUT_EFFECT,"Blur:",    10,40,220,22, &wipe->edgeWidth,0.0,1.0, 1, 2, "The percent width of the blur edge");
876                         switch(wipe->wipetype){ /*Skip Types that do not require angle*/
877                                 case DO_IRIS_WIPE:
878                                 case DO_CLOCK_WIPE:
879                                 break;
880                                 
881                                 default:
882                                         uiDefButF(block, NUM,SEQ_BUT_EFFECT,"Angle:",   10,15,220,22, &wipe->angle,-90.0,90.0, 1, 2, "The Angle of the Edge");
883                         }
884                         uiDefButS(block, TOG,SEQ_BUT_EFFECT,"Wipe In",  10,-10,220,22, &wipe->forward,0,0, 0, 0, "Controls Primary Direction of Wipe");                         
885                 }
886                 else if(last_seq->type==SEQ_GLOW){
887                         GlowVars *glow = (GlowVars *)last_seq->effectdata;
888
889                         uiBlockBeginAlign(block);
890                         uiDefButF(block, NUM, SEQ_BUT_EFFECT, "Threshold:",     10,70,150,19, &glow->fMini, 0.0, 1.0, 0, 0, "Trigger Intensity");
891                         uiDefButF(block, NUM, SEQ_BUT_EFFECT, "Clamp:",                 10,50,150,19, &glow->fClamp, 0.0, 1.0, 0, 0, "Brightness limit of intensity");
892                         uiDefButF(block, NUM, SEQ_BUT_EFFECT, "Boost factor:",  10,30,150,19, &glow->fBoost, 0.0, 10.0, 0, 0, "Brightness multiplier");
893                         uiDefButF(block, NUM, SEQ_BUT_EFFECT, "Blur distance:",         10,10,150,19, &glow->dDist, 0.5, 20.0, 0, 0, "Radius of glow effect");
894                         uiDefButI(block, NUM, B_NOP, "Quality:", 10,-5,150,19, &glow->dQuality, 1.0, 5.0, 0, 0, "Accuracy of the blur effect");
895                         uiDefButI(block, TOG, B_NOP, "Only boost", 10,-25,150,19, &glow->bNoComp, 0.0, 0.0, 0, 0, "Show the glow buffer only");
896                 }
897                 uiBlockEndAlign(block);
898         }
899 }
900
901 static void seq_blockhandlers(ScrArea *sa)
902 {
903         SpaceSeq *sseq= sa->spacedata.first;
904         short a;
905
906         /* warning; blocks need to be freed each time, handlers dont remove (for ipo moved to drawipospace) */
907         uiFreeBlocksWin(&sa->uiblocks, sa->win);
908
909         for(a=0; a<SPACE_MAXHANDLER; a+=2) {
910                 switch(sseq->blockhandler[a]) {
911
912                 case SEQ_HANDLER_PROPERTIES:
913                         seq_panel_properties(sseq->blockhandler[a+1]);
914                         break;
915
916                 }
917                 /* clear action value for event */
918                 sseq->blockhandler[a+1]= 0;
919         }
920         uiDrawBlocksPanels(sa, 0);
921
922 }
923
924 void drawseqspace(ScrArea *sa, void *spacedata)
925 {
926         SpaceSeq *sseq= sa->spacedata.first;
927         View2D *v2d= &sseq->v2d;
928         Editing *ed;
929         Sequence *seq;
930         float col[3];
931         int ofsx, ofsy;
932
933         ed= G.scene->ed;
934
935         if(sseq->mainb) {
936                 draw_image_seq(sa);
937                 return;
938         }
939
940         bwin_clear_viewmat(sa->win);    /* clear buttons view */
941         glLoadIdentity();
942
943         BIF_GetThemeColor3fv(TH_BACK, col);
944         if(ed && ed->metastack.first) glClearColor(col[0], col[1], col[2]-0.1, 0.0);
945         else glClearColor(col[0], col[1], col[2], 0.0);
946
947         glClear(GL_COLOR_BUFFER_BIT);
948
949         calc_scrollrcts(sa, v2d, sa->winx, sa->winy);
950
951         if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
952                 if(v2d->scroll) {
953                         ofsx= sa->winrct.xmin;  /* because of mywin */
954                         ofsy= sa->winrct.ymin;
955                         glViewport(ofsx+v2d->mask.xmin,  ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
956                         glScissor(ofsx+v2d->mask.xmin,  ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
957                 }
958         }
959
960
961         myortho2(v2d->cur.xmin, v2d->cur.xmax, v2d->cur.ymin, v2d->cur.ymax);
962
963         BIF_ThemeColorShade(TH_BACK, -20);
964         glRectf(v2d->cur.xmin,  0.0,  v2d->cur.xmax,  1.0);
965
966         
967         boundbox_seq();
968         calc_ipogrid();
969         
970         
971         /*Draw Track Gradients  Comment out for now do somthing more subtle
972         start drawing gradients at the bottom of the screen.*/
973         /*
974         i= MAX2(1, ((int)v2d->cur.ymin)-1); 
975         glShadeModel(GL_SMOOTH);
976         glBegin(GL_QUADS);
977         while (i<v2d->cur.ymax) {
978                 BIF_ThemeColorShade(TH_BACK, 0);
979                 glVertex2f(v2d->cur.xmax, i);
980                 glVertex2f(v2d->cur.xmin, i);
981                 BIF_ThemeColorShade(TH_BACK, 30);
982                 glVertex2f(v2d->cur.xmin, i+1);
983                 glVertex2f(v2d->cur.xmax, i+1);
984                 i+=1.0;
985         }
986         glEnd();
987         glShadeModel(GL_FLAT);
988         */ /* End Draw Track Gradients */
989         
990         
991         /* Quad Stripes ?*/
992         /*i= MAX2(1, ((int)v2d->cur.ymin)-1);
993         glBegin(GL_QUADS);
994         while (i<v2d->cur.ymax) {
995                 if (((int)i) & 1)
996                         BIF_ThemeColorShade(TH_BACK, -15);
997                 else
998                         BIF_ThemeColorShade(TH_BACK, -25);
999                 
1000                 glVertex2f(v2d->cur.xmax, i);
1001                 glVertex2f(v2d->cur.xmin, i);
1002                 glVertex2f(v2d->cur.xmin, i+1);
1003                 glVertex2f(v2d->cur.xmax, i+1);
1004                 i+=1.0;
1005         }
1006         glEnd();*/
1007         
1008         /* Force grid lines instead - Hangs on andys pc... will look at later */
1009         /*
1010         glBegin(GL_LINES);
1011         while (i<v2d->cur.ymax) {
1012                 BIF_ThemeColorShade(TH_BACK, -40);
1013                 glVertex2f(v2d->cur.xmax, i);
1014                 glVertex2f(v2d->cur.xmin, i);
1015                 i+=1.0;
1016         }
1017         glEnd();
1018         */
1019         
1020         draw_ipogrid();
1021         draw_cfra_seq();
1022
1023
1024         /* sequences: first deselect */
1025         if(ed) {
1026                 seq= ed->seqbasep->first;
1027                 while(seq) { /* bound box test, dont draw outside the view */
1028                         if (seq->flag & SELECT ||
1029                                         seq->startdisp > v2d->cur.xmax ||
1030                                         seq->enddisp < v2d->cur.xmin ||
1031                                         seq->machine+1.0 < v2d->cur.ymin ||
1032                                         seq->machine > v2d->cur.ymax)
1033                         {
1034                                 /* dont draw */
1035                         } else {
1036                                 drawseq(seq, sa);
1037                         }
1038                         seq= seq->next;
1039                 }
1040         }
1041         ed= G.scene->ed;
1042         if(ed) {
1043                 seq= ed->seqbasep->first;
1044                 while(seq) { /* bound box test, dont draw outside the view */
1045                         if (!(seq->flag & SELECT) ||
1046                                         seq->startdisp > v2d->cur.xmax ||
1047                                         seq->enddisp < v2d->cur.xmin ||
1048                                         seq->machine+1.0 < v2d->cur.ymin ||
1049                                         seq->machine > v2d->cur.ymax)
1050                         {
1051                                 /* dont draw */
1052                         } else {
1053                                 drawseq(seq, sa);
1054                         }
1055                         seq= seq->next;
1056                 }
1057         }
1058
1059         draw_extra_seqinfo();
1060
1061         /* restore viewport */
1062         mywinset(sa->win);
1063
1064         /* ortho at pixel level sa */
1065         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
1066
1067         if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
1068                 if(v2d->scroll) {
1069                         drawscroll(0);
1070                 }
1071         }
1072
1073         draw_area_emboss(sa);
1074
1075         if(sseq->mainb==0) {
1076                 /* it is important to end a view in a transform compatible with buttons */
1077                 bwin_scalematrix(sa->win, sseq->blockscale, sseq->blockscale, sseq->blockscale);
1078                 seq_blockhandlers(sa);
1079         }
1080
1081         sa->win_swap= WIN_BACK_OK;
1082 }
1083
1084