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