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