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