2.5
[blender-staging.git] / source / blender / editors / screen / screen_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL 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. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <math.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_editVert.h"
34
35 #include "DNA_armature_types.h"
36 #include "DNA_image_types.h"
37 #include "DNA_lattice_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_mesh_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_scene_types.h"
42
43 #include "BKE_blender.h"
44 #include "BKE_context.h"
45 #include "BKE_customdata.h"
46 #include "BKE_global.h"
47 #include "BKE_image.h"
48 #include "BKE_idprop.h"
49 #include "BKE_library.h"
50 #include "BKE_main.h"
51 #include "BKE_mesh.h"
52 #include "BKE_multires.h"
53 #include "BKE_report.h"
54 #include "BKE_screen.h"
55 #include "BKE_utildefines.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "ED_util.h"
61 #include "ED_screen.h"
62 #include "ED_mesh.h"
63 #include "ED_object.h"
64 #include "ED_screen_types.h"
65
66 #include "RE_pipeline.h"
67 #include "IMB_imbuf.h"
68 #include "IMB_imbuf_types.h"
69
70 #include "RNA_access.h"
71 #include "RNA_define.h"
72
73 #include "UI_interface.h"
74 #include "UI_resources.h"
75
76 #include "screen_intern.h"      /* own module include */
77
78 /* ************** Exported Poll tests ********************** */
79
80 int ED_operator_regionactive(bContext *C)
81 {
82         if(CTX_wm_window(C)==NULL) return 0;
83         if(CTX_wm_screen(C)==NULL) return 0;
84         if(CTX_wm_region(C)==NULL) return 0;
85         return 1;
86 }
87
88 int ED_operator_areaactive(bContext *C)
89 {
90         if(CTX_wm_window(C)==NULL) return 0;
91         if(CTX_wm_screen(C)==NULL) return 0;
92         if(CTX_wm_area(C)==NULL) return 0;
93         return 1;
94 }
95
96 int ED_operator_screenactive(bContext *C)
97 {
98         if(CTX_wm_window(C)==NULL) return 0;
99         if(CTX_wm_screen(C)==NULL) return 0;
100         return 1;
101 }
102
103 /* when mouse is over area-edge */
104 int ED_operator_screen_mainwinactive(bContext *C)
105 {
106         if(CTX_wm_window(C)==NULL) return 0;
107         if(CTX_wm_screen(C)==NULL) return 0;
108         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
109         return 1;
110 }
111
112 int ED_operator_scene_editable(bContext *C)
113 {
114         Scene *scene= CTX_data_scene(C);
115         if(scene && scene->id.lib==NULL)
116                 return 1;
117         return 0;
118 }
119
120 static int ed_spacetype_test(bContext *C, int type)
121 {
122         if(ED_operator_areaactive(C)) {
123                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
124                 return sl && (sl->spacetype == type);
125         }
126         return 0;
127 }
128
129 int ED_operator_view3d_active(bContext *C)
130 {
131         return ed_spacetype_test(C, SPACE_VIEW3D);
132 }
133
134 int ED_operator_timeline_active(bContext *C)
135 {
136         return ed_spacetype_test(C, SPACE_TIME);
137 }
138
139 int ED_operator_outliner_active(bContext *C)
140 {
141         return ed_spacetype_test(C, SPACE_OUTLINER);
142 }
143
144 int ED_operator_file_active(bContext *C)
145 {
146         return ed_spacetype_test(C, SPACE_FILE);
147 }
148
149 int ED_operator_action_active(bContext *C)
150 {
151         return ed_spacetype_test(C, SPACE_ACTION);
152 }
153
154 int ED_operator_buttons_active(bContext *C)
155 {
156         return ed_spacetype_test(C, SPACE_BUTS);
157 }
158
159 int ED_operator_node_active(bContext *C)
160 {
161         if(ed_spacetype_test(C, SPACE_NODE)) {
162                 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
163                 if(snode->edittree)
164                         return 1;
165         }
166         return 0;
167 }
168
169 int ED_operator_ipo_active(bContext *C)
170 {
171         return ed_spacetype_test(C, SPACE_IPO);
172 }
173
174 int ED_operator_sequencer_active(bContext *C)
175 {
176         return ed_spacetype_test(C, SPACE_SEQ);
177 }
178
179 int ED_operator_image_active(bContext *C)
180 {
181         return ed_spacetype_test(C, SPACE_IMAGE);
182 }
183
184 int ED_operator_logic_active(bContext *C)
185 {
186         return ed_spacetype_test(C, SPACE_LOGIC);
187 }
188
189 int ED_operator_object_active(bContext *C)
190 {
191         return NULL != CTX_data_active_object(C);
192 }
193
194 int ED_operator_editmesh(bContext *C)
195 {
196         Object *obedit= CTX_data_edit_object(C);
197         if(obedit && obedit->type==OB_MESH)
198                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
199         return 0;
200 }
201
202 int ED_operator_editarmature(bContext *C)
203 {
204         Object *obedit= CTX_data_edit_object(C);
205         if(obedit && obedit->type==OB_ARMATURE)
206                 return NULL != ((bArmature *)obedit->data)->edbo;
207         return 0;
208 }
209
210 int ED_operator_posemode(bContext *C)
211 {
212         Object *obact= CTX_data_active_object(C);
213         Object *obedit= CTX_data_edit_object(C);
214         
215         if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
216                 return (obact->flag & OB_POSEMODE)!=0;
217                 
218         return 0;
219 }
220
221
222 int ED_operator_uvedit(bContext *C)
223 {
224         Object *obedit= CTX_data_edit_object(C);
225         EditMesh *em= NULL;
226
227         if(obedit && obedit->type==OB_MESH)
228                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
229
230         if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
231                 BKE_mesh_end_editmesh(obedit->data, em);
232                 return 1;
233         }
234
235         if(obedit)
236                 BKE_mesh_end_editmesh(obedit->data, em);
237         return 0;
238 }
239
240 int ED_operator_uvmap(bContext *C)
241 {
242         Object *obedit= CTX_data_edit_object(C);
243         EditMesh *em= NULL;
244
245         if(obedit && obedit->type==OB_MESH)
246                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
247
248         if(em && (em->faces.first)) {
249                 BKE_mesh_end_editmesh(obedit->data, em);
250                 return 1;
251         }
252
253         if(obedit)
254                 BKE_mesh_end_editmesh(obedit->data, em);
255         return 0;
256 }
257
258 int ED_operator_editsurfcurve(bContext *C)
259 {
260         Object *obedit= CTX_data_edit_object(C);
261         if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
262                 return NULL != ((Curve *)obedit->data)->editnurb;
263         return 0;
264 }
265
266
267 int ED_operator_editcurve(bContext *C)
268 {
269         Object *obedit= CTX_data_edit_object(C);
270         if(obedit && obedit->type==OB_CURVE)
271                 return NULL != ((Curve *)obedit->data)->editnurb;
272         return 0;
273 }
274
275 int ED_operator_editsurf(bContext *C)
276 {
277         Object *obedit= CTX_data_edit_object(C);
278         if(obedit && obedit->type==OB_SURF)
279                 return NULL != ((Curve *)obedit->data)->editnurb;
280         return 0;
281 }
282
283 int ED_operator_editfont(bContext *C)
284 {
285         Object *obedit= CTX_data_edit_object(C);
286         if(obedit && obedit->type==OB_FONT)
287                 return NULL != ((Curve *)obedit->data)->editfont;
288         return 0;
289 }
290
291 int ED_operator_editlattice(bContext *C)
292 {
293         Object *obedit= CTX_data_edit_object(C);
294         if(obedit && obedit->type==OB_LATTICE)
295                 return NULL != ((Lattice *)obedit->data)->editlatt;
296         return 0;
297 }
298
299 /* *************************** action zone operator ************************** */
300
301 /* operator state vars used:  
302         none
303
304 functions:
305
306         apply() set actionzone event
307
308         exit()  free customdata
309         
310 callbacks:
311
312         exec()  never used
313
314         invoke() check if in zone  
315                 add customdata, put mouseco and area in it
316                 add modal handler
317
318         modal() accept modal events while doing it
319                 call apply() with gesture info, active window, nonactive window
320                 call exit() and remove handler when LMB confirm
321
322 */
323
324 typedef struct sActionzoneData {
325         ScrArea *sa1, *sa2;
326         AZone *az;
327         int x, y, gesture_dir, modifier;
328 } sActionzoneData;
329
330 /* used by other operators too */
331 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
332 {
333         ScrArea *sa= NULL;
334         sa= scr->areabase.first;
335         while(sa) {
336                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
337                 sa= sa->next;
338         }
339         
340         return sa;
341 }
342
343 /* quick poll to save operators to be created and handled */
344 static int actionzone_area_poll(bContext *C)
345 {
346         wmWindow *win= CTX_wm_window(C);
347         ScrArea *sa= CTX_wm_area(C);
348         
349         if(sa && win) {
350                 AZone *az;
351                 int x= win->eventstate->x;
352                 int y= win->eventstate->y;
353                 
354                 for(az= sa->actionzones.first; az; az= az->next)
355                         if(BLI_in_rcti(&az->rect, x, y))
356                            return 1;
357         }       
358         return 0;
359 }
360
361 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
362 {
363         AZone *az= NULL;
364         
365         for(az= sa->actionzones.first; az; az= az->next) {
366                 if(BLI_in_rcti(&az->rect, x, y)) {
367                         if(az->type == AZONE_AREA) {
368                                 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) 
369                                         break;
370                         }
371                         else if(az->type == AZONE_REGION) {
372                                 float v1[2], v2[2], v3[2], pt[2];
373                                 
374                                 v1[0]= az->x1; v1[1]= az->y1;
375                                 v2[0]= az->x2; v2[1]= az->y2;
376                                 v3[0]= az->x3; v3[1]= az->y3;
377                                 pt[0]= x; pt[1]=y;
378
379                                 if(IsPointInTri2D(v1, v2, v3, pt)) 
380                                         break;
381                         }
382                 }
383         }
384         
385         return az;
386 }
387
388
389 static void actionzone_exit(bContext *C, wmOperator *op)
390 {
391         if(op->customdata)
392                 MEM_freeN(op->customdata);
393         op->customdata= NULL;
394 }
395
396 /* send EVT_ACTIONZONE event */
397 static void actionzone_apply(bContext *C, wmOperator *op, int type)
398 {
399         wmEvent event;
400         wmWindow *win= CTX_wm_window(C);
401         sActionzoneData *sad= op->customdata;
402         
403         sad->modifier= RNA_int_get(op->ptr, "modifier");
404         
405         event= *(win->eventstate);      /* XXX huh huh? make api call */
406         if(type==AZONE_AREA)
407                 event.type= EVT_ACTIONZONE_AREA;
408         else
409                 event.type= EVT_ACTIONZONE_REGION;
410         event.customdata= op->customdata;
411         event.customdatafree= TRUE;
412         op->customdata= NULL;
413         
414         wm_event_add(win, &event);
415 }
416
417 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
418 {
419         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
420         sActionzoneData *sad;
421         
422         /* quick escape */
423         if(az==NULL)
424                 return OPERATOR_PASS_THROUGH;
425         
426         /* ok we do the actionzone */
427         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
428         sad->sa1= CTX_wm_area(C);
429         sad->az= az;
430         sad->x= event->x; sad->y= event->y;
431         
432         /* region azone directly reacts on mouse clicks */
433         if(sad->az->type==AZONE_REGION) {
434                 actionzone_apply(C, op, AZONE_REGION);
435                 actionzone_exit(C, op);
436                 return OPERATOR_FINISHED;
437         }
438         else {
439                 /* add modal handler */
440                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
441                 
442                 return OPERATOR_RUNNING_MODAL;
443         }
444 }
445
446
447 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
448 {
449         sActionzoneData *sad= op->customdata;
450         int deltax, deltay;
451         int mindelta= sad->az->type==AZONE_REGION?1:12;
452         
453         switch(event->type) {
454                 case MOUSEMOVE:
455                         /* calculate gesture direction */
456                         deltax= (event->x - sad->x);
457                         deltay= (event->y - sad->y);
458                         
459                         if(deltay > ABS(deltax))
460                                 sad->gesture_dir= 'n';
461                         else if(deltax > ABS(deltay))
462                                 sad->gesture_dir= 'e';
463                         else if(deltay < -ABS(deltax))
464                                 sad->gesture_dir= 's';
465                         else
466                                 sad->gesture_dir= 'w';
467                         
468                         /* gesture is large enough? */
469                         if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
470                                 
471                                 /* second area, for join */
472                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
473                                 /* apply sends event */
474                                 actionzone_apply(C, op, sad->az->type);
475                                 actionzone_exit(C, op);
476                                 
477                                 return OPERATOR_FINISHED;
478                         }
479                                 break;
480                 case ESCKEY:
481                         actionzone_exit(C, op);
482                         return OPERATOR_CANCELLED;
483                 case LEFTMOUSE:                         
484                         actionzone_exit(C, op);
485                         return OPERATOR_CANCELLED;
486
487         }
488         
489         return OPERATOR_RUNNING_MODAL;
490 }
491
492 void SCREEN_OT_actionzone(wmOperatorType *ot)
493 {
494         /* identifiers */
495         ot->name= "Handle area action zones";
496         ot->idname= "SCREEN_OT_actionzone";
497         
498         ot->invoke= actionzone_invoke;
499         ot->modal= actionzone_modal;
500         
501         ot->poll= actionzone_area_poll;
502         RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
503 }
504
505 /* ************** swap area operator *********************************** */
506
507 /* operator state vars used:  
508                                         sa1             start area
509                                         sa2             area to swap with
510
511         functions:
512
513         init()   set custom data for operator, based on actionzone event custom data
514
515         cancel()        cancel the operator
516
517         exit()  cleanup, send notifier
518
519         callbacks:
520
521         invoke() gets called on shift+lmb drag in actionzone
522             call init(), add handler
523
524         modal()  accept modal events while doing it
525
526 */
527
528 typedef struct sAreaSwapData {
529         ScrArea *sa1, *sa2;
530 } sAreaSwapData;
531
532 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
533 {
534         sAreaSwapData *sd= NULL;
535         sActionzoneData *sad= event->customdata;
536
537         if(sad==NULL || sad->sa1==NULL)
538                                         return 0;
539         
540         sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
541         sd->sa1= sad->sa1;
542         sd->sa2= sad->sa2;
543         op->customdata= sd;
544
545         return 1;
546 }
547
548
549 static void area_swap_exit(bContext *C, wmOperator *op)
550 {
551         if(op->customdata)
552                 MEM_freeN(op->customdata);
553         op->customdata= NULL;
554 }
555
556 static int area_swap_cancel(bContext *C, wmOperator *op)
557 {
558         area_swap_exit(C, op);
559         return OPERATOR_CANCELLED;
560 }
561
562 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
563 {
564
565         if(!area_swap_init(C, op, event))
566                 return OPERATOR_PASS_THROUGH;
567
568         /* add modal handler */
569         WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
570         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
571         
572         return OPERATOR_RUNNING_MODAL;
573
574 }
575
576 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
577 {
578         sActionzoneData *sad= op->customdata;
579
580         switch(event->type) {
581                 case MOUSEMOVE:
582                         /* second area, for join */
583                         sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
584                         break;
585                 case LEFTMOUSE: /* release LMB */
586                         if(event->val==0) {
587                                 if(sad->sa1 == sad->sa2) {
588
589                                         return area_swap_cancel(C, op);
590                                 }
591                                 ED_area_swapspace(C, sad->sa1, sad->sa2);
592
593                                 area_swap_exit(C, op);
594
595                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
596
597                                 return OPERATOR_FINISHED;
598                         }
599                         break;
600
601                 case ESCKEY:
602                         return area_swap_cancel(C, op);
603         }
604         return OPERATOR_RUNNING_MODAL;
605 }
606
607 static void SCREEN_OT_area_swap(wmOperatorType *ot)
608 {
609         ot->name= "Swap areas";
610         ot->idname= "SCREEN_OT_area_swap";
611
612         ot->invoke= area_swap_invoke;
613         ot->modal= area_swap_modal;
614         ot->poll= ED_operator_areaactive;
615 }
616
617 /* *********** Duplicate area as new window operator ****************** */
618
619 /* operator callback */
620 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
621 {
622         wmWindow *newwin, *win;
623         bScreen *newsc, *sc;
624         ScrArea *sa;
625         rcti rect;
626         
627         win= CTX_wm_window(C);
628         sc= CTX_wm_screen(C);
629         sa= CTX_wm_area(C);
630         
631         /* XXX hrmf! */
632         if(event->type==EVT_ACTIONZONE_AREA) {
633                 sActionzoneData *sad= event->customdata;
634
635                 if(sad==NULL)
636                         return OPERATOR_PASS_THROUGH;
637         
638                 sa= sad->sa1;
639         }
640         
641         /*  poll() checks area context, but we don't accept full-area windows */
642         if(sc->full != SCREENNORMAL) {
643                 if(event->type==EVT_ACTIONZONE_AREA)
644                         actionzone_exit(C, op);
645                 return OPERATOR_CANCELLED;
646         }
647         
648         /* adds window to WM */
649         rect= sa->totrct;
650         BLI_translate_rcti(&rect, win->posx, win->posy);
651         newwin= WM_window_open(C, &rect);
652         
653         /* allocs new screen and adds to newly created window, using window size */
654         newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
655         newwin->screen= newsc;
656         
657         /* copy area to new screen */
658         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
659         
660         /* screen, areas init */
661         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
662
663         if(event->type==EVT_ACTIONZONE_AREA)
664                 actionzone_exit(C, op);
665         
666         return OPERATOR_FINISHED;
667 }
668
669 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
670 {
671         ot->name= "Duplicate Area into New Window";
672         ot->idname= "SCREEN_OT_area_dupli";
673         
674         ot->invoke= area_dupli_invoke;
675         ot->poll= ED_operator_areaactive;
676 }
677
678
679 /* ************** move area edge operator *********************************** */
680
681 /* operator state vars used:  
682            x, y                         mouse coord near edge
683            delta            movement of edge
684
685         functions:
686
687         init()   set default property values, find edge based on mouse coords, test
688             if the edge can be moved, select edges, calculate min and max movement
689
690         apply() apply delta on selection
691
692         exit()  cleanup, send notifier
693
694         cancel() cancel moving
695
696         callbacks:
697
698         exec()   execute without any user interaction, based on properties
699             call init(), apply(), exit()
700
701         invoke() gets called on mouse click near edge
702             call init(), add handler
703
704         modal()  accept modal events while doing it
705                         call apply() with delta motion
706             call exit() and remove handler
707
708 */
709
710 typedef struct sAreaMoveData {
711         int bigger, smaller, origval;
712         char dir;
713 } sAreaMoveData;
714
715 /* helper call to move area-edge, sets limits */
716 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
717 {
718         ScrArea *sa;
719         
720         /* we check all areas and test for free space with MINSIZE */
721         *bigger= *smaller= 100000;
722         
723         for(sa= sc->areabase.first; sa; sa= sa->next) {
724                 if(dir=='h') {
725                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
726                         
727                         /* if top or down edge selected, test height */
728                         if(sa->v1->flag && sa->v4->flag)
729                                 *bigger= MIN2(*bigger, y1);
730                         else if(sa->v2->flag && sa->v3->flag)
731                                 *smaller= MIN2(*smaller, y1);
732                 }
733                 else {
734                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
735                         
736                         /* if left or right edge selected, test width */
737                         if(sa->v1->flag && sa->v2->flag)
738                                 *bigger= MIN2(*bigger, x1);
739                         else if(sa->v3->flag && sa->v4->flag)
740                                 *smaller= MIN2(*smaller, x1);
741                 }
742         }
743 }
744
745 /* validate selection inside screen, set variables OK */
746 /* return 0: init failed */
747 static int area_move_init (bContext *C, wmOperator *op)
748 {
749         bScreen *sc= CTX_wm_screen(C);
750         ScrEdge *actedge;
751         sAreaMoveData *md;
752         int x, y;
753
754         /* required properties */
755         x= RNA_int_get(op->ptr, "x");
756         y= RNA_int_get(op->ptr, "y");
757
758         /* setup */
759         actedge= screen_find_active_scredge(sc, x, y);
760         if(actedge==NULL) return 0;
761
762         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
763         op->customdata= md;
764
765         md->dir= scredge_is_horizontal(actedge)?'h':'v';
766         if(md->dir=='h') md->origval= actedge->v1->vec.y;
767         else md->origval= actedge->v1->vec.x;
768         
769         select_connected_scredge(sc, actedge);
770         /* now all vertices with 'flag==1' are the ones that can be moved. */
771
772         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
773         
774         return 1;
775 }
776
777 /* moves selected screen edge amount of delta, used by split & move */
778 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
779 {
780         wmWindow *win= CTX_wm_window(C);
781         bScreen *sc= CTX_wm_screen(C);
782         ScrVert *v1;
783         
784         delta= CLAMPIS(delta, -smaller, bigger);
785         
786         for (v1= sc->vertbase.first; v1; v1= v1->next) {
787                 if (v1->flag) {
788                         /* that way a nice AREAGRID  */
789                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
790                                 v1->vec.x= origval + delta;
791                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
792                         }
793                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
794                                 v1->vec.y= origval + delta;
795
796                                 v1->vec.y+= AREAGRID-1;
797                                 v1->vec.y-= (v1->vec.y % AREAGRID);
798                                 
799                                 /* prevent too small top header */
800                                 if(v1->vec.y > win->sizey-AREAMINY)
801                                         v1->vec.y= win->sizey-AREAMINY;
802                         }
803                 }
804         }
805
806         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
807 }
808
809 static void area_move_apply(bContext *C, wmOperator *op)
810 {
811         sAreaMoveData *md= op->customdata;
812         int delta;
813         
814         delta= RNA_int_get(op->ptr, "delta");
815         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
816 }
817
818 static void area_move_exit(bContext *C, wmOperator *op)
819 {
820         if(op->customdata)
821                 MEM_freeN(op->customdata);
822         op->customdata= NULL;
823         
824         /* this makes sure aligned edges will result in aligned grabbing */
825         removedouble_scrverts(CTX_wm_screen(C));
826         removedouble_scredges(CTX_wm_screen(C));
827 }
828
829 static int area_move_exec(bContext *C, wmOperator *op)
830 {
831         if(!area_move_init(C, op))
832                 return OPERATOR_CANCELLED;
833         
834         area_move_apply(C, op);
835         area_move_exit(C, op);
836         
837         return OPERATOR_FINISHED;
838 }
839
840 /* interaction callback */
841 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
842 {
843         RNA_int_set(op->ptr, "x", event->x);
844         RNA_int_set(op->ptr, "y", event->y);
845
846         if(!area_move_init(C, op)) 
847                 return OPERATOR_PASS_THROUGH;
848         
849         /* add temp handler */
850         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
851         
852         return OPERATOR_RUNNING_MODAL;
853 }
854
855 static int area_move_cancel(bContext *C, wmOperator *op)
856 {
857
858         RNA_int_set(op->ptr, "delta", 0);
859         area_move_apply(C, op);
860         area_move_exit(C, op);
861
862         return OPERATOR_CANCELLED;
863 }
864
865 /* modal callback for while moving edges */
866 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
867 {
868         sAreaMoveData *md;
869         int delta, x, y;
870
871         md= op->customdata;
872
873         x= RNA_int_get(op->ptr, "x");
874         y= RNA_int_get(op->ptr, "y");
875
876         /* execute the events */
877         switch(event->type) {
878                 case MOUSEMOVE:
879                         delta= (md->dir == 'v')? event->x - x: event->y - y;
880                         RNA_int_set(op->ptr, "delta", delta);
881
882                         area_move_apply(C, op);
883                         break;
884                         
885                 case LEFTMOUSE:
886                         if(event->val==0) {
887                                 area_move_exit(C, op);
888                                 return OPERATOR_FINISHED;
889                         }
890                         break;
891                         
892                 case ESCKEY:
893                         return area_move_cancel(C, op);
894         }
895         
896         return OPERATOR_RUNNING_MODAL;
897 }
898
899 void SCREEN_OT_area_move(wmOperatorType *ot)
900 {
901         /* identifiers */
902         ot->name= "Move area edges";
903         ot->idname= "SCREEN_OT_area_move";
904
905         ot->exec= area_move_exec;
906         ot->invoke= area_move_invoke;
907         ot->cancel= area_move_cancel;
908         ot->modal= area_move_modal;
909
910         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
911
912         /* rna */
913         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
914         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
915         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
916 }
917
918 /* ************** split area operator *********************************** */
919
920 /* 
921 operator state vars:  
922         fac              spit point
923         dir              direction 'v' or 'h'
924
925 operator customdata:
926         area                    pointer to (active) area
927         x, y                    last used mouse pos
928         (more, see below)
929
930 functions:
931
932         init()   set default property values, find area based on context
933
934         apply() split area based on state vars
935
936         exit()  cleanup, send notifier
937
938         cancel() remove duplicated area
939
940 callbacks:
941
942         exec()   execute without any user interaction, based on state vars
943             call init(), apply(), exit()
944
945         invoke() gets called on mouse click in action-widget
946             call init(), add modal handler
947                         call apply() with initial motion
948
949         modal()  accept modal events while doing it
950             call move-areas code with delta motion
951             call exit() or cancel() and remove handler
952
953 */
954
955 #define SPLIT_STARTED   1
956 #define SPLIT_PROGRESS  2
957
958 typedef struct sAreaSplitData
959 {
960         int x, y;       /* last used mouse position */
961         
962         int origval;                    /* for move areas */
963         int bigger, smaller;    /* constraints for moving new edge */
964         int delta;                              /* delta move edge */
965         int origmin, origsize;  /* to calculate fac, for property storage */
966
967         ScrEdge *nedge;                 /* new edge */
968         ScrArea *sarea;                 /* start area */
969         ScrArea *narea;                 /* new area */
970 } sAreaSplitData;
971
972 /* generic init, no UI stuff here */
973 static int area_split_init(bContext *C, wmOperator *op)
974 {
975         ScrArea *sa= CTX_wm_area(C);
976         sAreaSplitData *sd;
977         int dir;
978         
979         /* required context */
980         if(sa==NULL) return 0;
981         
982         /* required properties */
983         dir= RNA_enum_get(op->ptr, "direction");
984         
985         /* minimal size */
986         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
987         if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
988            
989         /* custom data */
990         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
991         op->customdata= sd;
992         
993         sd->sarea= sa;
994         sd->origsize= dir=='v' ? sa->winx:sa->winy;
995         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
996         
997         return 1;
998 }
999
1000 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1001 /* used with split operator */
1002 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1003 {
1004         ScrVert *sav1= sa->v1;
1005         ScrVert *sav2= sa->v2;
1006         ScrVert *sav3= sa->v3;
1007         ScrVert *sav4= sa->v4;
1008         ScrVert *sbv1= sb->v1;
1009         ScrVert *sbv2= sb->v2;
1010         ScrVert *sbv3= sb->v3;
1011         ScrVert *sbv4= sb->v4;
1012         
1013         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1014                 return screen_findedge(screen, sav1, sav2);
1015         }
1016         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1017                 return screen_findedge(screen, sav2, sav3);
1018         }
1019         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1020                 return screen_findedge(screen, sav3, sav4);
1021         }
1022         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1023                 return screen_findedge(screen, sav1, sav4);
1024         }
1025
1026         return NULL;
1027 }
1028
1029
1030 /* do the split, return success */
1031 static int area_split_apply(bContext *C, wmOperator *op)
1032 {
1033         bScreen *sc= CTX_wm_screen(C);
1034         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1035         float fac;
1036         int dir;
1037         
1038         fac= RNA_float_get(op->ptr, "factor");
1039         dir= RNA_enum_get(op->ptr, "direction");
1040
1041         sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1042         
1043         if(sd->narea) {
1044                 ScrVert *sv;
1045                 
1046                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1047         
1048                 /* select newly created edge, prepare for moving edge */
1049                 for(sv= sc->vertbase.first; sv; sv= sv->next)
1050                         sv->flag = 0;
1051                 
1052                 sd->nedge->v1->flag= 1;
1053                 sd->nedge->v2->flag= 1;
1054
1055                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1056                 else sd->origval= sd->nedge->v1->vec.x;
1057
1058                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1059                 
1060                 return 1;
1061         }               
1062         
1063         return 0;
1064 }
1065
1066 static void area_split_exit(bContext *C, wmOperator *op)
1067 {
1068         if (op->customdata) {
1069                 MEM_freeN(op->customdata);
1070                 op->customdata = NULL;
1071         }
1072         
1073         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1074
1075         /* this makes sure aligned edges will result in aligned grabbing */
1076         removedouble_scrverts(CTX_wm_screen(C));
1077         removedouble_scredges(CTX_wm_screen(C));
1078 }
1079
1080
1081 /* UI callback, adds new handler */
1082 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1083 {
1084         sAreaSplitData *sd;
1085         
1086         if(event->type==EVT_ACTIONZONE_AREA) {
1087                 sActionzoneData *sad= event->customdata;
1088                 int dir;
1089
1090                 if(sad->modifier>0) {
1091                         return OPERATOR_PASS_THROUGH;
1092                 }
1093                 
1094                 /* no full window splitting allowed */
1095                 if(CTX_wm_area(C)->full)
1096                         return OPERATOR_PASS_THROUGH;
1097                 
1098                 /* verify *sad itself */
1099                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1100                         return OPERATOR_PASS_THROUGH;
1101                 
1102                 /* is this our *sad? if areas not equal it should be passed on */
1103                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1104                         return OPERATOR_PASS_THROUGH;
1105                 
1106                 /* prepare operator state vars */
1107                 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1108                         dir= 'h';
1109                         RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1110                 }
1111                 else {
1112                         dir= 'v';
1113                         RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1114                 }
1115                 RNA_enum_set(op->ptr, "direction", dir);
1116
1117                 /* general init, also non-UI case, adds customdata, sets area and defaults */
1118                 if(!area_split_init(C, op))
1119                         return OPERATOR_PASS_THROUGH;
1120                 
1121                 sd= (sAreaSplitData *)op->customdata;
1122                 
1123                 sd->x= event->x;
1124                 sd->y= event->y;
1125                 
1126                 /* do the split */
1127                 if(area_split_apply(C, op)) {
1128                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1129                         
1130                         /* add temp handler for edge move or cancel */
1131                         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1132                         
1133                         return OPERATOR_RUNNING_MODAL;
1134                 }
1135                 
1136         }
1137         else {
1138                 /* nonmodal for now */
1139                 return op->type->exec(C, op);
1140         }
1141         
1142         return OPERATOR_PASS_THROUGH;
1143 }
1144
1145 /* function to be called outside UI context, or for redo */
1146 static int area_split_exec(bContext *C, wmOperator *op)
1147 {
1148         
1149         if(!area_split_init(C, op))
1150                 return OPERATOR_CANCELLED;
1151         
1152         area_split_apply(C, op);
1153         area_split_exit(C, op);
1154         
1155         return OPERATOR_FINISHED;
1156 }
1157
1158
1159 static int area_split_cancel(bContext *C, wmOperator *op)
1160 {
1161         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1162
1163         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1164                 if (CTX_wm_area(C) == sd->narea) {
1165                         CTX_wm_area_set(C, NULL);
1166                         CTX_wm_region_set(C, NULL);
1167                 }
1168                 sd->narea = NULL;
1169         }
1170         area_split_exit(C, op);
1171
1172         return OPERATOR_CANCELLED;
1173 }
1174
1175 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1176 {
1177         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1178         float fac;
1179         int dir;
1180
1181         /* execute the events */
1182         switch(event->type) {
1183                 case MOUSEMOVE:
1184                         dir= RNA_enum_get(op->ptr, "direction");
1185                         
1186                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1187                         area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1188                         
1189                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1190                         RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1191                         
1192                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1193                         break;
1194                         
1195                 case LEFTMOUSE:
1196                         if(event->val==0) { /* mouse up */
1197                                 area_split_exit(C, op);
1198                                 return OPERATOR_FINISHED;
1199                         }
1200                         break;
1201                 case RIGHTMOUSE: /* cancel operation */
1202                 case ESCKEY:
1203                         return area_split_cancel(C, op);
1204         }
1205         
1206         return OPERATOR_RUNNING_MODAL;
1207 }
1208
1209 static EnumPropertyItem prop_direction_items[] = {
1210         {'h', "HORIZONTAL", 0, "Horizontal", ""},
1211         {'v', "VERTICAL", 0, "Vertical", ""},
1212         {0, NULL, 0, NULL, NULL}};
1213
1214 void SCREEN_OT_area_split(wmOperatorType *ot)
1215 {
1216         ot->name = "Split area";
1217         ot->idname = "SCREEN_OT_area_split";
1218         
1219         ot->exec= area_split_exec;
1220         ot->invoke= area_split_invoke;
1221         ot->modal= area_split_modal;
1222         
1223         ot->poll= ED_operator_areaactive;
1224         ot->flag= OPTYPE_REGISTER;
1225         
1226         /* rna */
1227         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1228         RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1229 }
1230
1231
1232
1233 /* ************** scale region edge operator *********************************** */
1234
1235 typedef struct RegionMoveData {
1236         ARegion *ar;
1237         int bigger, smaller, origval;
1238         int origx, origy;
1239         char edge;
1240         
1241 } RegionMoveData;
1242
1243 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1244 {
1245         sActionzoneData *sad= event->customdata;
1246         AZone *az= sad->az;
1247         
1248         if(az->ar) {
1249                 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1250                 
1251                 op->customdata= rmd;
1252                 
1253                 rmd->ar= az->ar;
1254                 rmd->edge= az->edge;
1255                 rmd->origx= event->x;
1256                 rmd->origy= event->y;
1257                 if(rmd->edge=='l' || rmd->edge=='r') 
1258                         rmd->origval= rmd->ar->type->minsizex;
1259                 else
1260                         rmd->origval= rmd->ar->type->minsizey;
1261                 
1262                 /* add temp handler */
1263                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1264                 
1265                 return OPERATOR_RUNNING_MODAL;
1266         }
1267         
1268         return OPERATOR_FINISHED;
1269 }
1270
1271 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1272 {
1273         RegionMoveData *rmd= op->customdata;
1274         int delta;
1275         
1276         /* execute the events */
1277         switch(event->type) {
1278                 case MOUSEMOVE:
1279                         
1280                         if(rmd->edge=='l' || rmd->edge=='r') {
1281                                 delta= event->x - rmd->origx;
1282                                 if(rmd->edge=='l') delta= -delta;
1283                                 rmd->ar->type->minsizex= rmd->origval + delta;
1284                                 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1285                                 if(rmd->ar->type->minsizex < 10) {
1286                                         rmd->ar->type->minsizex= 10;
1287                                         rmd->ar->flag |= RGN_FLAG_HIDDEN;
1288                                 }
1289                                 else
1290                                         rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1291                         }
1292                         else {
1293                                 delta= event->y - rmd->origy;
1294                                 if(rmd->edge=='b') delta= -delta;
1295                                 rmd->ar->type->minsizey= rmd->origval + delta;
1296                                 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1297                                 if(rmd->ar->type->minsizey < 10) {
1298                                         rmd->ar->type->minsizey= 10;
1299                                         rmd->ar->flag |= RGN_FLAG_HIDDEN;
1300                                 }
1301                                 else
1302                                         rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1303                         }
1304                         
1305                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1306                                         
1307                         break;
1308                         
1309                 case LEFTMOUSE:
1310                         if(event->val==0) {
1311                                 
1312                                 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1313                                         rmd->ar->flag ^= RGN_FLAG_HIDDEN;
1314                                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1315                                 }                               
1316                                 MEM_freeN(op->customdata);
1317                                 op->customdata = NULL;
1318
1319                                 return OPERATOR_FINISHED;
1320                         }
1321                         break;
1322                         
1323                 case ESCKEY:
1324                         ;
1325         }
1326         
1327         return OPERATOR_RUNNING_MODAL;
1328 }
1329
1330
1331 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1332 {
1333         /* identifiers */
1334         ot->name= "Scale Region Size";
1335         ot->idname= "SCREEN_OT_region_scale";
1336         
1337         ot->invoke= region_scale_invoke;
1338         ot->modal= region_scale_modal;
1339         
1340         ot->poll= ED_operator_areaactive;
1341 }
1342
1343
1344 /* ************** frame change operator ***************************** */
1345
1346
1347 /* function to be called outside UI context, or for redo */
1348 static int frame_offset_exec(bContext *C, wmOperator *op)
1349 {
1350         int delta;
1351
1352         delta = RNA_int_get(op->ptr, "delta");
1353
1354         CTX_data_scene(C)->r.cfra += delta;
1355
1356         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1357
1358         return OPERATOR_FINISHED;
1359 }
1360
1361 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1362 {
1363         ot->name = "Frame Offset";
1364         ot->idname = "SCREEN_OT_frame_offset";
1365
1366         ot->exec= frame_offset_exec;
1367
1368         ot->poll= ED_operator_screenactive;
1369         ot->flag= 0;
1370
1371         /* rna */
1372         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1373 }
1374
1375 /* ************** switch screen operator ***************************** */
1376
1377
1378 /* function to be called outside UI context, or for redo */
1379 static int screen_set_exec(bContext *C, wmOperator *op)
1380 {
1381         bScreen *screen= CTX_wm_screen(C);
1382         ScrArea *sa= CTX_wm_area(C);
1383         int tot= BLI_countlist(&CTX_data_main(C)->screen);
1384         int delta= RNA_int_get(op->ptr, "delta");
1385         
1386         /* this screen is 'fake', solve later XXX */
1387         if(sa && sa->full)
1388                 return OPERATOR_CANCELLED;
1389         
1390         if(delta==1) {
1391                 while(tot--) {
1392                         screen= screen->id.next;
1393                         if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1394                         if(screen->winid==0 && screen->full==0)
1395                                 break;
1396                 }
1397         }
1398         else if(delta== -1) {
1399                 while(tot--) {
1400                         screen= screen->id.prev;
1401                         if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1402                         if(screen->winid==0 && screen->full==0)
1403                                 break;
1404                 }
1405         }
1406         else {
1407                 screen= NULL;
1408         }
1409         
1410         if(screen) {
1411                 ED_screen_set(C, screen);
1412                 return OPERATOR_FINISHED;
1413         }
1414         return OPERATOR_CANCELLED;
1415 }
1416
1417 void SCREEN_OT_screen_set(wmOperatorType *ot)
1418 {
1419         ot->name = "Set Screen";
1420         ot->idname = "SCREEN_OT_screen_set";
1421         
1422         ot->exec= screen_set_exec;
1423         ot->poll= ED_operator_screenactive;
1424         
1425         /* rna */
1426         RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1427         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1428 }
1429
1430 /* ************** screen full-area operator ***************************** */
1431
1432
1433 /* function to be called outside UI context, or for redo */
1434 static int screen_full_area_exec(bContext *C, wmOperator *op)
1435 {
1436         ed_screen_fullarea(C, CTX_wm_area(C));
1437         return OPERATOR_FINISHED;
1438 }
1439
1440 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1441 {
1442         ot->name = "Toggle Make Area Fullscreen";
1443         ot->idname = "SCREEN_OT_screen_full_area";
1444         
1445         ot->exec= screen_full_area_exec;
1446         ot->poll= ED_operator_areaactive;
1447         ot->flag= 0;
1448
1449 }
1450
1451
1452
1453 /* ************** join area operator ********************************************** */
1454
1455 /* operator state vars used:  
1456                         x1, y1     mouse coord in first area, which will disappear
1457                         x2, y2     mouse coord in 2nd area, which will become joined
1458
1459 functions:
1460
1461    init()   find edge based on state vars 
1462                         test if the edge divides two areas, 
1463                         store active and nonactive area,
1464             
1465    apply()  do the actual join
1466
1467    exit()       cleanup, send notifier
1468
1469 callbacks:
1470
1471    exec()       calls init, apply, exit 
1472    
1473    invoke() sets mouse coords in x,y
1474             call init()
1475             add modal handler
1476
1477    modal()      accept modal events while doing it
1478                         call apply() with active window and nonactive window
1479             call exit() and remove handler when LMB confirm
1480
1481 */
1482
1483 typedef struct sAreaJoinData
1484 {
1485         ScrArea *sa1;   /* first area to be considered */
1486         ScrArea *sa2;   /* second area to be considered */
1487         ScrArea *scr;   /* designed for removal */
1488
1489 } sAreaJoinData;
1490
1491
1492 /* validate selection inside screen, set variables OK */
1493 /* return 0: init failed */
1494 /* XXX todo: find edge based on (x,y) and set other area? */
1495 static int area_join_init(bContext *C, wmOperator *op)
1496 {
1497         ScrArea *sa1, *sa2;
1498         sAreaJoinData* jd= NULL;
1499         int x1, y1;
1500         int x2, y2;
1501
1502         /* required properties, make negative to get return 0 if not set by caller */
1503         x1= RNA_int_get(op->ptr, "x1");
1504         y1= RNA_int_get(op->ptr, "y1");
1505         x2= RNA_int_get(op->ptr, "x2");
1506         y2= RNA_int_get(op->ptr, "y2");
1507         
1508         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1509         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1510         if(sa1==NULL || sa2==NULL || sa1==sa2)
1511                 return 0;
1512
1513         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1514                 
1515         jd->sa1 = sa1;
1516         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1517         jd->sa2 = sa2;
1518         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1519         
1520         op->customdata= jd;
1521         
1522         return 1;
1523 }
1524
1525 /* apply the join of the areas (space types) */
1526 static int area_join_apply(bContext *C, wmOperator *op)
1527 {
1528         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1529         if (!jd) return 0;
1530
1531         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1532                 return 0;
1533         }
1534         if (CTX_wm_area(C) == jd->sa2) {
1535                 CTX_wm_area_set(C, NULL);
1536                 CTX_wm_region_set(C, NULL);
1537         }
1538
1539         return 1;
1540 }
1541
1542 /* finish operation */
1543 static void area_join_exit(bContext *C, wmOperator *op)
1544 {
1545         if (op->customdata) {
1546                 MEM_freeN(op->customdata);
1547                 op->customdata = NULL;
1548         }
1549
1550         /* this makes sure aligned edges will result in aligned grabbing */
1551         removedouble_scredges(CTX_wm_screen(C));
1552         removenotused_scredges(CTX_wm_screen(C));
1553         removenotused_scrverts(CTX_wm_screen(C));
1554 }
1555
1556 static int area_join_exec(bContext *C, wmOperator *op)
1557 {
1558         if(!area_join_init(C, op)) 
1559                 return OPERATOR_CANCELLED;
1560         
1561         area_join_apply(C, op);
1562         area_join_exit(C, op);
1563
1564         return OPERATOR_FINISHED;
1565 }
1566
1567 /* interaction callback */
1568 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1569 {
1570
1571         if(event->type==EVT_ACTIONZONE_AREA) {
1572                 sActionzoneData *sad= event->customdata;
1573
1574                 if(sad->modifier>0) {
1575                         return OPERATOR_PASS_THROUGH;
1576                 }
1577                 
1578                 /* verify *sad itself */
1579                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1580                         return OPERATOR_PASS_THROUGH;
1581                 
1582                 /* is this our *sad? if areas equal it should be passed on */
1583                 if(sad->sa1==sad->sa2)
1584                         return OPERATOR_PASS_THROUGH;
1585                 
1586                 /* prepare operator state vars */
1587                 RNA_int_set(op->ptr, "x1", sad->x);
1588                 RNA_int_set(op->ptr, "y1", sad->y);
1589                 RNA_int_set(op->ptr, "x2", event->x);
1590                 RNA_int_set(op->ptr, "y2", event->y);
1591
1592                 if(!area_join_init(C, op)) 
1593                         return OPERATOR_PASS_THROUGH;
1594         
1595                 /* add temp handler */
1596                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1597         
1598                 return OPERATOR_RUNNING_MODAL;
1599         }
1600         
1601         return OPERATOR_PASS_THROUGH;
1602 }
1603
1604 static int area_join_cancel(bContext *C, wmOperator *op)
1605 {
1606         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1607
1608         if (jd->sa1) {
1609                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1610                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1611         }
1612         if (jd->sa2) {
1613                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1614                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1615         }
1616
1617         WM_event_add_notifier(C, NC_WINDOW, NULL);
1618         
1619         area_join_exit(C, op);
1620
1621         return OPERATOR_CANCELLED;
1622 }
1623
1624 /* modal callback while selecting area (space) that will be removed */
1625 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1626 {
1627         bScreen *sc= CTX_wm_screen(C);
1628         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1629         
1630         /* execute the events */
1631         switch(event->type) {
1632                         
1633                 case MOUSEMOVE: 
1634                         {
1635                                 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1636                                 int dir;
1637                                 
1638                                 if (sa) {                                       
1639                                         if (jd->sa1 != sa) {
1640                                                 dir = area_getorientation(sc, jd->sa1, sa);
1641                                                 if (dir >= 0) {
1642                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1643                                                         jd->sa2 = sa;
1644                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1645                                                 } 
1646                                                 else {
1647                                                         /* we are not bordering on the previously selected area 
1648                                                            we check if area has common border with the one marked for removal
1649                                                            in this case we can swap areas.
1650                                                         */
1651                                                         dir = area_getorientation(sc, sa, jd->sa2);
1652                                                         if (dir >= 0) {
1653                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1654                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1655                                                                 jd->sa1 = jd->sa2;
1656                                                                 jd->sa2 = sa;
1657                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1658                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1659                                                         } 
1660                                                         else {
1661                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1662                                                                 jd->sa2 = NULL;
1663                                                         }
1664                                                 }
1665                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1666                                         } 
1667                                         else {
1668                                                 /* we are back in the area previously selected for keeping 
1669                                                  * we swap the areas if possible to allow user to choose */
1670                                                 if (jd->sa2 != NULL) {
1671                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1672                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1673                                                         jd->sa1 = jd->sa2;
1674                                                         jd->sa2 = sa;
1675                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1676                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1677                                                         dir = area_getorientation(sc, jd->sa1, jd->sa2);
1678                                                         if (dir < 0) {
1679                                                                 printf("oops, didn't expect that!\n");
1680                                                         }
1681                                                 } 
1682                                                 else {
1683                                                         dir = area_getorientation(sc, jd->sa1, sa);
1684                                                         if (dir >= 0) {
1685                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1686                                                                 jd->sa2 = sa;
1687                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1688                                                         }
1689                                                 }
1690                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1691                                         }
1692                                 }
1693                         }
1694                         break;
1695                 case LEFTMOUSE:
1696                         if(event->val==0) {
1697                                 area_join_apply(C, op);
1698                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1699                                 area_join_exit(C, op);
1700                                 return OPERATOR_FINISHED;
1701                         }
1702                         break;
1703                         
1704                 case ESCKEY:
1705                         return area_join_cancel(C, op);
1706         }
1707
1708         return OPERATOR_RUNNING_MODAL;
1709 }
1710
1711 /* Operator for joining two areas (space types) */
1712 void SCREEN_OT_area_join(wmOperatorType *ot)
1713 {
1714         /* identifiers */
1715         ot->name= "Join area";
1716         ot->idname= "SCREEN_OT_area_join";
1717         
1718         /* api callbacks */
1719         ot->exec= area_join_exec;
1720         ot->invoke= area_join_invoke;
1721         ot->modal= area_join_modal;
1722
1723         ot->poll= ED_operator_areaactive;
1724
1725         /* rna */
1726         RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1727         RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1728         RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1729         RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1730 }
1731
1732 /* ************** repeat last operator ***************************** */
1733
1734 static int repeat_last_exec(bContext *C, wmOperator *op)
1735 {
1736         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1737         
1738         if(lastop)
1739                 WM_operator_repeat(C, lastop);
1740         
1741         return OPERATOR_CANCELLED;
1742 }
1743
1744 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1745 {
1746         /* identifiers */
1747         ot->name= "Repeat Last";
1748         ot->idname= "SCREEN_OT_repeat_last";
1749         
1750         /* api callbacks */
1751         ot->exec= repeat_last_exec;
1752         
1753         ot->poll= ED_operator_screenactive;
1754         
1755 }
1756
1757 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1758 {
1759         wmWindowManager *wm= CTX_wm_manager(C);
1760         wmOperator *lastop;
1761         uiPopupMenu *pup;
1762         uiLayout *layout;
1763         int items, i;
1764         
1765         items= BLI_countlist(&wm->operators);
1766         if(items==0)
1767                 return OPERATOR_CANCELLED;
1768         
1769         pup= uiPupMenuBegin(C, op->type->name, 0);
1770         layout= uiPupMenuLayout(pup);
1771
1772         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1773                 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1774
1775         uiPupMenuEnd(C, pup);
1776         
1777         return OPERATOR_CANCELLED;
1778 }
1779
1780 static int repeat_history_exec(bContext *C, wmOperator *op)
1781 {
1782         wmWindowManager *wm= CTX_wm_manager(C);
1783         
1784         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1785         if(op) {
1786                 /* let's put it as last operator in list */
1787                 BLI_remlink(&wm->operators, op);
1788                 BLI_addtail(&wm->operators, op);
1789                 
1790                 WM_operator_repeat(C, op);
1791         }
1792                                          
1793         return OPERATOR_FINISHED;
1794 }
1795
1796 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1797 {
1798         /* identifiers */
1799         ot->name= "Repeat History";
1800         ot->idname= "SCREEN_OT_repeat_history";
1801         
1802         /* api callbacks */
1803         ot->invoke= repeat_history_invoke;
1804         ot->exec= repeat_history_exec;
1805         
1806         ot->poll= ED_operator_screenactive;
1807         
1808         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1809 }
1810
1811 /* ********************** redo operator ***************************** */
1812
1813 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1814 {
1815         wmWindowManager *wm= CTX_wm_manager(C);
1816         wmOperator *lastop;
1817
1818         /* only for operators that are registered and did an undo push */
1819         for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1820                 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1821                         break;
1822         
1823         if(lastop)
1824                 WM_operator_redo_popup(C, lastop);
1825
1826         return OPERATOR_CANCELLED;
1827 }
1828
1829 void SCREEN_OT_redo_last(wmOperatorType *ot)
1830 {
1831         /* identifiers */
1832         ot->name= "Redo Last";
1833         ot->idname= "SCREEN_OT_redo_last";
1834         
1835         /* api callbacks */
1836         ot->invoke= redo_last_invoke;
1837         
1838         ot->poll= ED_operator_screenactive;
1839 }
1840
1841 /* ************** region split operator ***************************** */
1842
1843 /* insert a region in the area region list */
1844 static int region_split_exec(bContext *C, wmOperator *op)
1845 {
1846         ARegion *ar= CTX_wm_region(C);
1847         
1848         if(ar->regiontype==RGN_TYPE_HEADER)
1849                 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1850         else if(ar->alignment==RGN_ALIGN_QSPLIT)
1851                 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1852         else {
1853                 ScrArea *sa= CTX_wm_area(C);
1854                 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1855                 int dir= RNA_enum_get(op->ptr, "type");
1856         
1857                 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1858                 
1859                 newar->alignment= ar->alignment;
1860                 
1861                 if(dir=='h')
1862                         ar->alignment= RGN_ALIGN_HSPLIT;
1863                 else
1864                         ar->alignment= RGN_ALIGN_VSPLIT;
1865                 
1866                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1867         }
1868         
1869         return OPERATOR_FINISHED;
1870 }
1871
1872 void SCREEN_OT_region_split(wmOperatorType *ot)
1873 {
1874         /* identifiers */
1875         ot->name= "Split Region";
1876         ot->idname= "SCREEN_OT_region_split";
1877         
1878         /* api callbacks */
1879         ot->invoke= WM_menu_invoke;
1880         ot->exec= region_split_exec;
1881         ot->poll= ED_operator_areaactive;
1882         
1883         RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1884 }
1885
1886 /* ************** region four-split operator ***************************** */
1887
1888 /* insert a region in the area region list */
1889 static int region_foursplit_exec(bContext *C, wmOperator *op)
1890 {
1891         ARegion *ar= CTX_wm_region(C);
1892         
1893         /* some rules... */
1894         if(ar->regiontype!=RGN_TYPE_WINDOW)
1895                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1896         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1897                 ScrArea *sa= CTX_wm_area(C);
1898                 ARegion *arn;
1899                 
1900                 /* keep current region */
1901                 ar->alignment= 0;
1902                 
1903                 if(sa->spacetype==SPACE_VIEW3D) {
1904                         RegionView3D *rv3d= ar->regiondata;
1905                         rv3d->viewlock= 0;
1906                         rv3d->rflag &= ~RV3D_CLIPPING;
1907                 }
1908                 
1909                 for(ar= sa->regionbase.first; ar; ar= arn) {
1910                         arn= ar->next;
1911                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
1912                                 ED_region_exit(C, ar);
1913                                 BKE_area_region_free(sa->type, ar);
1914                                 BLI_remlink(&sa->regionbase, ar);
1915                                 MEM_freeN(ar);
1916                         }
1917                 }
1918                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1919         }
1920         else if(ar->next)
1921                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1922         else {
1923                 ScrArea *sa= CTX_wm_area(C);
1924                 ARegion *newar;
1925                 int count;
1926                 
1927                 ar->alignment= RGN_ALIGN_QSPLIT;
1928                 
1929                 for(count=0; count<3; count++) {
1930                         newar= BKE_area_region_copy(sa->type, ar);
1931                         BLI_addtail(&sa->regionbase, newar);
1932                 }
1933                 
1934                 /* lock views and set them */
1935                 if(sa->spacetype==SPACE_VIEW3D) {
1936                         RegionView3D *rv3d;
1937                         
1938                         rv3d= ar->regiondata;
1939                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1940                         
1941                         ar= ar->next;
1942                         rv3d= ar->regiondata;
1943                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1944                         
1945                         ar= ar->next;
1946                         rv3d= ar->regiondata;
1947                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1948                         
1949                         ar= ar->next;
1950                         rv3d= ar->regiondata;
1951                         rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1952                 }
1953                 
1954                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1955         }
1956         
1957         
1958         return OPERATOR_FINISHED;
1959 }
1960
1961 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1962 {
1963         /* identifiers */
1964         ot->name= "Split Region in 4 Parts";
1965         ot->idname= "SCREEN_OT_region_foursplit";
1966         
1967         /* api callbacks */
1968         ot->invoke= WM_operator_confirm;
1969         ot->exec= region_foursplit_exec;
1970         ot->poll= ED_operator_areaactive;
1971         ot->flag= OPTYPE_REGISTER;
1972 }
1973
1974
1975
1976 /* ************** region flip operator ***************************** */
1977
1978 /* flip a region alignment */
1979 static int region_flip_exec(bContext *C, wmOperator *op)
1980 {
1981         ARegion *ar= CTX_wm_region(C);
1982
1983         if(ar->alignment==RGN_ALIGN_TOP)
1984                 ar->alignment= RGN_ALIGN_BOTTOM;
1985         else if(ar->alignment==RGN_ALIGN_BOTTOM)
1986                 ar->alignment= RGN_ALIGN_TOP;
1987         else if(ar->alignment==RGN_ALIGN_LEFT)
1988                 ar->alignment= RGN_ALIGN_RIGHT;
1989         else if(ar->alignment==RGN_ALIGN_RIGHT)
1990                 ar->alignment= RGN_ALIGN_LEFT;
1991         
1992         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1993         printf("executed region flip\n");
1994         
1995         return OPERATOR_FINISHED;
1996 }
1997
1998
1999 void SCREEN_OT_region_flip(wmOperatorType *ot)
2000 {
2001         /* identifiers */
2002         ot->name= "Flip Region";
2003         ot->idname= "SCREEN_OT_region_flip";
2004         
2005         /* api callbacks */
2006         ot->exec= region_flip_exec;
2007         
2008         ot->poll= ED_operator_areaactive;
2009         ot->flag= OPTYPE_REGISTER;
2010
2011 }
2012
2013 /* ****************** anim player, with timer ***************** */
2014
2015 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2016 {
2017         if(regiontype==RGN_TYPE_WINDOW) {
2018
2019                 switch (spacetype) {
2020                         case SPACE_VIEW3D:
2021                                 if(redraws & TIME_ALL_3D_WIN)
2022                                         return 1;
2023                                 break;
2024                         case SPACE_IPO:
2025                         case SPACE_ACTION:
2026                         case SPACE_NLA:
2027                                 if(redraws & TIME_ALL_ANIM_WIN)
2028                                         return 1;
2029                                 break;
2030                         case SPACE_TIME:
2031                                 /* if only 1 window or 3d windows, we do timeline too */
2032                                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2033                                         return 1;
2034                                 break;
2035                         case SPACE_BUTS:
2036                                 if(redraws & TIME_ALL_BUTS_WIN)
2037                                         return 1;
2038                                 break;
2039                         case SPACE_SEQ:
2040                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2041                                         return 1;
2042                                 break;
2043                         case SPACE_IMAGE:
2044                                 if(redraws & TIME_ALL_IMAGE_WIN)
2045                                         return 1;
2046                                 break;
2047                                 
2048                 }
2049         }
2050         else if(regiontype==RGN_TYPE_UI) {
2051                 if(redraws & TIME_ALL_BUTS_WIN)
2052                         return 1;
2053         }
2054         else if(regiontype==RGN_TYPE_HEADER) {
2055                 if(spacetype==SPACE_TIME)
2056                         return 1;
2057         }
2058         return 0;
2059 }
2060
2061 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2062 {
2063         bScreen *screen= CTX_wm_screen(C);
2064         
2065         if(screen->animtimer==event->customdata) {
2066                 Scene *scene= CTX_data_scene(C);
2067                 wmTimer *wt= screen->animtimer;
2068                 ScreenAnimData *sad= wt->customdata;
2069                 ScrArea *sa;
2070                 
2071                 if(scene->audio.flag & AUDIO_SYNC) {
2072                         int step = floor(wt->duration * FPS);
2073                         scene->r.cfra += step;
2074                         wt->duration -= ((float)step)/FPS;
2075                 }
2076                 else
2077                         scene->r.cfra++;
2078                 
2079                 if (scene->r.psfra) {
2080                         if(scene->r.cfra > scene->r.pefra)
2081                                 scene->r.cfra= scene->r.psfra;
2082                 }
2083                 else {
2084                         if(scene->r.cfra > scene->r.efra)
2085                                 scene->r.cfra= scene->r.sfra;
2086                 }
2087
2088                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2089                 ED_update_for_newframe(C, 1);
2090                 
2091                 for(sa= screen->areabase.first; sa; sa= sa->next) {
2092                         ARegion *ar;
2093                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
2094                                 if(ar==sad->ar)
2095                                         ED_region_tag_redraw(ar);
2096                                 else
2097                                         if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2098                                                 ED_region_tag_redraw(ar);
2099                         }
2100                 }
2101                 
2102                 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2103                 
2104                 return OPERATOR_FINISHED;
2105         }
2106         return OPERATOR_PASS_THROUGH;
2107 }
2108
2109 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2110 {
2111         /* identifiers */
2112         ot->name= "Animation Step";
2113         ot->idname= "SCREEN_OT_animation_step";
2114         
2115         /* api callbacks */
2116         ot->invoke= screen_animation_step;
2117         
2118         ot->poll= ED_operator_screenactive;
2119         
2120 }
2121
2122 /* ****************** anim player, starts or ends timer ***************** */
2123
2124 /* toggle operator */
2125 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2126 {
2127         bScreen *screen= CTX_wm_screen(C);
2128         
2129         if(screen->animtimer) {
2130                 ED_screen_animation_timer(C, 0, 0);
2131         }
2132         else {
2133                 /* todo: RNA properties to define play types */
2134                 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, 1);
2135                 
2136                 if(screen->animtimer) {
2137                         wmTimer *wt= screen->animtimer;
2138                         ScreenAnimData *sad= wt->customdata;
2139                         
2140                         sad->ar= CTX_wm_region(C);
2141                 }
2142         }
2143         
2144         return OPERATOR_FINISHED;
2145 }
2146
2147 void SCREEN_OT_animation_play(wmOperatorType *ot)
2148 {
2149         /* identifiers */
2150         ot->name= "Animation player";
2151         ot->idname= "SCREEN_OT_animation_play";
2152         
2153         /* api callbacks */
2154         ot->invoke= screen_animation_play;
2155         
2156         ot->poll= ED_operator_screenactive;
2157         
2158         
2159 }
2160
2161 /* ************** border select operator (template) ***************************** */
2162
2163 /* operator state vars used: (added by default WM callbacks)   
2164         xmin, ymin     
2165         xmax, ymax     
2166
2167         customdata: the wmGesture pointer
2168
2169 callbacks:
2170
2171         exec()  has to be filled in by user
2172
2173         invoke() default WM function
2174                          adds modal handler
2175
2176         modal() default WM function 
2177                         accept modal events while doing it, calls exec(), handles ESC and border drawing
2178         
2179         poll()  has to be filled in by user for context
2180 */
2181 #if 0
2182 static int border_select_do(bContext *C, wmOperator *op)
2183 {
2184         int event_type= RNA_int_get(op->ptr, "event_type");
2185         
2186         if(event_type==LEFTMOUSE)
2187                 printf("border select do select\n");
2188         else if(event_type==RIGHTMOUSE)
2189                 printf("border select deselect\n");
2190         else 
2191                 printf("border select do something\n");
2192         
2193         return 1;
2194 }
2195
2196 void SCREEN_OT_border_select(wmOperatorType *ot)
2197 {
2198         /* identifiers */
2199         ot->name= "Border select";
2200         ot->idname= "SCREEN_OT_border_select";
2201         
2202         /* api callbacks */
2203         ot->exec= border_select_do;
2204         ot->invoke= WM_border_select_invoke;
2205         ot->modal= WM_border_select_modal;
2206         
2207         ot->poll= ED_operator_areaactive;
2208         
2209         /* rna */
2210         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2211         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2212         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2213         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2214         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2215
2216 }
2217 #endif
2218
2219 /* ****************************** render invoking ***************** */
2220
2221 /* set callbacks, exported to sequence render too. 
2222 Only call in foreground (UI) renders. */
2223
2224 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2225 /* window as the last possible alternative.                                                                        */
2226 static ScrArea *biggest_non_image_area(bContext *C)
2227 {
2228         bScreen *sc= CTX_wm_screen(C);
2229         ScrArea *sa, *big= NULL;
2230         int size, maxsize= 0, bwmaxsize= 0;
2231         short foundwin= 0;
2232         
2233         for(sa= sc->areabase.first; sa; sa= sa->next) {
2234                 if(sa->winx > 30 && sa->winy > 30) {
2235                         size= sa->winx*sa->winy;
2236                         if(sa->spacetype == SPACE_BUTS) {
2237                                 if(foundwin == 0 && size > bwmaxsize) {
2238                                         bwmaxsize= size;
2239                                         big= sa;        
2240                                 }
2241                         }
2242                         else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2243                                 maxsize= size;
2244                                 big= sa;
2245                                 foundwin= 1;
2246                         }
2247                 }
2248         }
2249         
2250         return big;
2251 }
2252
2253 static ScrArea *biggest_area(bContext *C)
2254 {
2255         bScreen *sc= CTX_wm_screen(C);
2256         ScrArea *sa, *big= NULL;
2257         int size, maxsize= 0;
2258         
2259         for(sa= sc->areabase.first; sa; sa= sa->next) {
2260                 size= sa->winx*sa->winy;
2261                 if(size > maxsize) {
2262                         maxsize= size;
2263                         big= sa;
2264                 }
2265         }
2266         return big;
2267 }
2268
2269
2270 static ScrArea *find_area_showing_r_result(bContext *C)
2271 {
2272         bScreen *sc= CTX_wm_screen(C);
2273         ScrArea *sa;
2274         SpaceImage *sima;
2275         
2276         /* find an imagewindow showing render result */
2277         for(sa=sc->areabase.first; sa; sa= sa->next) {
2278                 if(sa->spacetype==SPACE_IMAGE) {
2279                         sima= sa->spacedata.first;
2280                         if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2281                                 break;
2282                 }
2283         }
2284         return sa;
2285 }
2286
2287 static void screen_set_image_output(bContext *C)
2288 {
2289         Scene *scene= CTX_data_scene(C);
2290         ScrArea *sa;
2291         SpaceImage *sima;
2292         
2293         if(scene->r.displaymode==R_OUTPUT_SCREEN) {
2294                 /* this function returns with changed context */
2295                 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
2296                 sa= CTX_wm_area(C);
2297         }
2298         else {
2299         
2300                 sa= find_area_showing_r_result(C);
2301                 
2302                 if(sa==NULL) {
2303                         /* find largest open non-image area */
2304                         sa= biggest_non_image_area(C);
2305                         if(sa) {
2306                                 ED_area_newspace(C, sa, SPACE_IMAGE);
2307                                 sima= sa->spacedata.first;
2308                                 
2309                                 /* makes ESC go back to prev space */
2310                                 sima->flag |= SI_PREVSPACE;
2311                         }
2312                         else {
2313                                 /* use any area of decent size */
2314                                 sa= biggest_area(C);
2315                                 if(sa->spacetype!=SPACE_IMAGE) {
2316                                         // XXX newspace(sa, SPACE_IMAGE);
2317                                         sima= sa->spacedata.first;
2318                                         
2319                                         /* makes ESC go back to prev space */
2320                                         sima->flag |= SI_PREVSPACE;
2321                                 }
2322                         }
2323                 }
2324         }       
2325         sima= sa->spacedata.first;
2326         
2327         /* get the correct image, and scale it */
2328         sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2329         
2330 //      if(G.displaymode==2) { // XXX
2331                 if(sa->full) {
2332                         sima->flag |= SI_FULLWINDOW|SI_PREVSPACE;
2333                         
2334 //                      ed_screen_fullarea(C, sa);
2335                 }
2336 //      }
2337         
2338 }
2339
2340 /* executes blocking render */
2341 static int screen_render_exec(bContext *C, wmOperator *op)
2342 {
2343         Scene *scene= CTX_data_scene(C);
2344         Render *re= RE_GetRender(scene->id.name);
2345         
2346         if(re==NULL) {
2347                 re= RE_NewRender(scene->id.name);
2348         }
2349         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2350         
2351         if(RNA_boolean_get(op->ptr, "anim"))
2352                 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2353         else
2354                 RE_BlenderFrame(re, scene, scene->r.cfra);
2355         
2356         // no redraw needed, we leave state as we entered it
2357         ED_update_for_newframe(C, 1);
2358         
2359         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2360
2361         return OPERATOR_FINISHED;
2362 }
2363
2364 typedef struct RenderJob {
2365         Scene *scene;
2366         Render *re;
2367         wmWindow *win;
2368         int anim;
2369         Image *image;
2370         ImageUser iuser;
2371         short *stop;
2372         short *do_update;
2373 } RenderJob;
2374
2375 static void render_freejob(void *rjv)
2376 {
2377         RenderJob *rj= rjv;
2378         
2379         MEM_freeN(rj);
2380 }
2381
2382 /* str is IMA_RW_MAXTEXT in size */
2383 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
2384 {
2385         char info_time_str[32]; // used to be extern to header_info.c
2386         uintptr_t mem_in_use, mmap_in_use;
2387         float megs_used_memory, mmap_used_memory;
2388         char *spos= str;
2389         
2390         mem_in_use= MEM_get_memory_in_use();
2391         mmap_in_use= MEM_get_mapped_memory_in_use();
2392         
2393         megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
2394         mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
2395         
2396         if(scene->lay & 0xFF000000)
2397                 spos+= sprintf(spos, "Localview | ");
2398         else if(scene->r.scemode & R_SINGLE_LAYER)
2399                 spos+= sprintf(spos, "Single Layer | ");
2400         
2401         spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
2402         if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
2403         if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
2404         spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
2405         
2406         if(rs->curfield)
2407                 spos+= sprintf(spos, "Field %d ", rs->curfield);
2408         if(rs->curblur)
2409                 spos+= sprintf(spos, "Blur %d ", rs->curblur);
2410         
2411         BLI_timestr(rs->lastframetime, info_time_str);
2412         spos+= sprintf(spos, "Time:%s ", info_time_str);
2413         
2414         if(rs->infostr)
2415                 spos+= sprintf(spos, "| %s ", rs->infostr);
2416         
2417         /* very weak... but 512 characters is quite safe */
2418         if(spos >= str+IMA_RW_MAXTEXT)
2419                 printf("WARNING! renderwin text beyond limit \n");
2420         
2421 }
2422
2423 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
2424 {
2425         RenderJob *rj= rjv;
2426         
2427         /* malloc OK here, stats_draw is not in tile threads */
2428         if(rj->image->render_text==NULL)
2429                 rj->image->render_text= MEM_callocN(IMA_RW_MAXTEXT, "rendertext");
2430         
2431         make_renderinfo_string(rs, rj->scene, rj->image->render_text);
2432         
2433         /* make jobs timer to send notifier */
2434         *(rj->do_update)= 1;
2435
2436 }
2437
2438 /* called inside thread! */
2439 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2440 {
2441         RenderJob *rj= rjv;
2442         ImBuf *ibuf;
2443         float x1, y1, *rectf= NULL;
2444         int ymin, ymax, xmin, xmax;
2445         int rymin, rxmin;
2446         char *rectc;
2447         
2448         ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2449         if(ibuf==NULL) return;
2450
2451         /* if renrect argument, we only refresh scanlines */
2452         if(renrect) {
2453                 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2454                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2455                         return;
2456                 
2457                 /* xmin here is first subrect x coord, xmax defines subrect width */
2458                 xmin = renrect->xmin + rr->crop;
2459                 xmax = renrect->xmax - xmin - rr->crop;
2460                 if (xmax<2) return;
2461                 
2462                 ymin= renrect->ymin + rr->crop;
2463                 ymax= renrect->ymax - ymin - rr->crop;
2464                 if(ymax<2)
2465                         return;
2466                 renrect->ymin= renrect->ymax;
2467                 
2468         }
2469         else {
2470                 xmin = ymin = rr->crop;
2471                 xmax = rr->rectx - 2*rr->crop;
2472                 ymax = rr->recty - 2*rr->crop;
2473         }
2474         
2475         /* xmin ymin is in tile coords. transform to ibuf */
2476         rxmin= rr->tilerect.xmin + xmin;
2477         if(rxmin >= ibuf->x) return;
2478         rymin= rr->tilerect.ymin + ymin;
2479         if(rymin >= ibuf->y) return;
2480         
2481         if(rxmin + xmax > ibuf->x)
2482                 xmax= ibuf->x - rxmin;
2483         if(rymin + ymax > ibuf->y)
2484                 ymax= ibuf->y - rymin;
2485         
2486         if(xmax < 1 || ymax < 1) return;
2487         
2488         /* find current float rect for display, first case is after composit... still weak */
2489         if(rr->rectf)
2490                 rectf= rr->rectf;
2491         else {
2492                 if(rr->rect32)
2493                         return;
2494                 else {
2495                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2496                         rectf= rr->renlay->rectf;
2497                 }
2498         }
2499         if(rectf==NULL) return;
2500         
2501         rectf+= 4*(rr->rectx*ymin + xmin);
2502         rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2503
2504         for(y1= 0; y1<ymax; y1++) {
2505                 float *rf= rectf;
2506                 char *rc= rectc;
2507                 
2508                 /* XXX temp. because crop offset */
2509                 if( rectc >= (char *)(ibuf->rect)) {
2510                         for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2511                                 rc[0]= FTOCHAR(rf[0]);
2512                                 rc[1]= FTOCHAR(rf[1]);
2513                                 rc[2]= FTOCHAR(rf[2]);
2514                                 rc[3]= FTOCHAR(rf[3]);
2515                         }
2516                 }
2517                 rectf += 4*rr->rectx;
2518                 rectc += 4*ibuf->x;
2519         }
2520         
2521         /* make jobs timer to send notifier */
2522         *(rj->do_update)= 1;
2523 }
2524
2525 static void render_startjob(void *rjv, short *stop, short *do_update)
2526 {
2527         RenderJob *rj= rjv;
2528         
2529         rj->stop= stop;
2530         rj->do_update= do_update;
2531         
2532         if(rj->anim)
2533                 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2534         else
2535                 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2536 }
2537
2538 /* called by render, check job 'stop' value or the global */
2539 static int render_breakjob(void *rjv)
2540 {
2541         RenderJob *rj= rjv;
2542         
2543         if(G.afbreek)
2544                 return 1;
2545         if(rj->stop && *(rj->stop))
2546                 return 1;
2547         return 0;
2548 }
2549
2550 /* catch esc */
2551 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2552 {
2553         /* no running blender, remove handler and pass through */
2554         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2555            return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2556         
2557         /* running render */
2558         switch (event->type) {
2559                 case ESCKEY:
2560                         return OPERATOR_RUNNING_MODAL;
2561                         break;
2562         }
2563         return OPERATOR_PASS_THROUGH;
2564 }
2565
2566 /* using context, starts job */
2567 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2568 {
2569         /* new render clears all callbacks */
2570         Scene *scene= CTX_data_scene(C);
2571         Render *re;
2572         wmJob *steve;
2573         RenderJob *rj;
2574         Image *ima;
2575         
2576         /* only one job at a time */
2577         if(WM_jobs_test(CTX_wm_manager(C), scene))
2578                 return OPERATOR_CANCELLED;
2579         
2580         /* handle UI stuff */
2581         WM_cursor_wait(1);
2582
2583         /* flush multires changes (for sculpt) */
2584         multires_force_update(CTX_data_active_object(C));
2585         
2586         /* get editmode results */
2587         ED_object_exit_editmode(C, 0);  /* 0 = does not exit editmode */
2588         
2589         // store spare
2590         // get view3d layer, local layer, make this nice api call to render
2591         // store spare
2592         
2593         /* ensure at least 1 area shows result */
2594         screen_set_image_output(C);
2595
2596         /* job custom data */
2597         rj= MEM_callocN(sizeof(RenderJob), "render job");
2598         rj->scene= scene;
2599         rj->win= CTX_wm_window(C);
2600         rj->anim= RNA_boolean_get(op->ptr, "anim");
2601         rj->iuser.scene= scene;
2602         rj->iuser.ok= 1;
2603         
2604         /* setup job */
2605         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2606         WM_jobs_customdata(steve, rj, render_freejob);
2607         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2608         WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2609         
2610         /* get a render result image, and make sure it is empty */
2611         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2612         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2613         rj->image= ima;
2614         
2615         /* setup new render */
2616         re= RE_NewRender(scene->id.name);
2617         RE_test_break_cb(re, rj, render_breakjob);
2618         RE_display_draw_cb(re, rj, image_rect_update);
2619         RE_stats_draw_cb(re, rj, image_renderinfo_cb);
2620         
2621         rj->re= re;
2622         G.afbreek= 0;
2623         
2624         //      BKE_report in render!
2625         //      RE_error_cb(re, error_cb);
2626
2627         WM_jobs_start(CTX_wm_manager(C), steve);
2628         
2629         G.afbreek= 0;
2630         
2631         WM_cursor_wait(0);
2632         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2633
2634         /* add modal handler for ESC */
2635         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2636         
2637         return OPERATOR_RUNNING_MODAL;
2638 }
2639
2640
2641 /* contextual render, using current scene, view3d? */
2642 void SCREEN_OT_render(wmOperatorType *ot)
2643 {
2644         /* identifiers */
2645         ot->name= "Render";
2646         ot->idname= "SCREEN_OT_render";
2647         
2648         /* api callbacks */
2649         ot->invoke= screen_render_invoke;
2650         ot->modal= screen_render_modal;
2651         ot->exec= screen_render_exec;
2652         
2653         ot->poll= ED_operator_screenactive;
2654         
2655         RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2656         RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2657 }
2658
2659 /* *********************** cancel render viewer *************** */
2660
2661 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2662 {
2663         ScrArea *sa= CTX_wm_area(C);
2664         SpaceImage *sima= sa->spacedata.first;
2665         
2666         if(sima->flag & SI_PREVSPACE) {
2667                 sima->flag &= ~SI_PREVSPACE;
2668                 
2669                 if(sima->flag & SI_FULLWINDOW) {
2670                         sima->flag &= ~SI_FULLWINDOW;
2671                         ED_screen_full_prevspace(C);
2672                 }
2673                 else
2674                         ED_area_prevspace(C);
2675         }
2676         else if(sima->flag & SI_FULLWINDOW) {
2677                 sima->flag &= ~SI_FULLWINDOW;
2678                 ed_screen_fullarea(C, sa);
2679         }               
2680         
2681         return OPERATOR_FINISHED;
2682 }
2683
2684 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2685 {
2686         /* identifiers */
2687         ot->name= "Cancel Render View";
2688         ot->idname= "SCREEN_OT_render_view_cancel";
2689         
2690         /* api callbacks */
2691         ot->exec= render_view_cancel_exec;
2692         ot->poll= ED_operator_image_active;
2693 }
2694
2695 /* *********************** show render viewer *************** */
2696
2697 static int render_view_show_exec(bContext *C, wmOperator *unused)
2698 {
2699         ScrArea *sa= find_area_showing_r_result(C);
2700         
2701         /* determine if render already shows */
2702         if(sa) {
2703                 SpaceImage *sima= sa->spacedata.first;
2704                 
2705                 if(sima->flag & SI_PREVSPACE) {
2706                         sima->flag &= ~SI_PREVSPACE;
2707                         
2708                         if(sima->flag & SI_FULLWINDOW) {
2709                                 sima->flag &= ~SI_FULLWINDOW;
2710                                 ED_screen_full_prevspace(C);
2711                         }
2712                         else if(sima->next) {
2713                                 ED_area_newspace(C, sa, sima->next->spacetype);
2714                                 ED_area_tag_redraw(sa);
2715                         }
2716                 }
2717         }
2718         else {
2719                 screen_set_image_output(C);
2720         }
2721         
2722         return OPERATOR_FINISHED;
2723 }
2724
2725 void SCREEN_OT_render_view_show(struct wmOperatorType *ot)
2726 {
2727         /* identifiers */
2728         ot->name= "Show/Hide Render View";
2729         ot->idname= "SCREEN_OT_render_view_show";
2730         
2731         /* api callbacks */
2732         ot->exec= render_view_show_exec;
2733         ot->poll= ED_operator_screenactive;
2734 }
2735
2736
2737
2738 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2739
2740 /* called in spacetypes.c */
2741 void ED_operatortypes_screen(void)
2742 {
2743         /* generic UI stuff */
2744         WM_operatortype_append(SCREEN_OT_actionzone);
2745         WM_operatortype_append(SCREEN_OT_repeat_last);
2746         WM_operatortype_append(SCREEN_OT_repeat_history);
2747         WM_operatortype_append(SCREEN_OT_redo_last);
2748         
2749         /* screen tools */
2750         WM_operatortype_append(SCREEN_OT_area_move);
2751         WM_operatortype_append(SCREEN_OT_area_split);
2752         WM_operatortype_append(SCREEN_OT_area_join);
2753         WM_operatortype_append(SCREEN_OT_area_dupli);
2754         WM_operatortype_append(SCREEN_OT_area_swap);
2755         WM_operatortype_append(SCREEN_OT_region_split);
2756         WM_operatortype_append(SCREEN_OT_region_foursplit);
2757         WM_operatortype_append(SCREEN_OT_region_flip);
2758         WM_operatortype_append(SCREEN_OT_region_scale);
2759         WM_operatortype_append(SCREEN_OT_screen_set);
2760         WM_operatortype_append(SCREEN_OT_screen_full_area);
2761         WM_operatortype_append(SCREEN_OT_screenshot);
2762         WM_operatortype_append(SCREEN_OT_screencast);
2763         
2764         /*frame changes*/
2765         WM_operatortype_append(SCREEN_OT_frame_offset);
2766         WM_operatortype_append(SCREEN_OT_animation_step);
2767         WM_operatortype_append(SCREEN_OT_animation_play);
2768         
2769         /* render */
2770         WM_operatortype_append(SCREEN_OT_render);
2771         WM_operatortype_append(SCREEN_OT_render_view_cancel);
2772         WM_operatortype_append(SCREEN_OT_render_view_show);
2773
2774         /* tools shared by more space types */
2775         WM_operatortype_append(ED_OT_undo);
2776         WM_operatortype_append(ED_OT_redo);     
2777         
2778 }
2779
2780 /* called in spacetypes.c */
2781 void ED_keymap_screen(wmWindowManager *wm)
2782 {
2783         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2784         
2785         /* standard timers */
2786         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
2787         
2788         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2789         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2790         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2791         
2792         /* screen tools */
2793         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2794         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2795         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2796         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
2797         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2798                         /* area move after action zones */
2799         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2800         
2801         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2802         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2803         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2804         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2805         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2806         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2807         WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2808
2809          /* tests */
2810         WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2811         WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2812         
2813         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2814         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2815         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2816         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2817         
2818         RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
2819         WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
2820
2821         /* files */
2822         WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2823         WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2824         
2825         /* undo */
2826         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2827         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2828         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2829         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2830                                                   
2831         /* render */
2832         WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2833         WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2834         WM_keymap_add_item(keymap, "SCREEN_OT_render_view_show", F11KEY, KM_PRESS, 0, 0);
2835         
2836         /* frame offsets & play */
2837         keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2838         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2839         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2840         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2841         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
2842         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
2843         
2844 }
2845