4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * ***** END GPL LICENSE BLOCK *****
29 #include "MEM_guardedalloc.h"
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_editVert.h"
34 #include "BLI_dlrbTree.h"
36 #include "DNA_armature_types.h"
37 #include "DNA_image_types.h"
38 #include "DNA_lattice_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_meta_types.h"
45 #include "BKE_blender.h"
46 #include "BKE_colortools.h"
47 #include "BKE_context.h"
48 #include "BKE_customdata.h"
49 #include "BKE_global.h"
50 #include "BKE_image.h"
51 #include "BKE_idprop.h"
52 #include "BKE_library.h"
55 #include "BKE_multires.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 #include "BKE_screen.h"
59 #include "BKE_utildefines.h"
60 #include "BKE_sound.h"
66 #include "ED_screen.h"
68 #include "ED_object.h"
69 #include "ED_screen_types.h"
70 #include "ED_keyframes_draw.h"
72 #include "RE_pipeline.h"
73 #include "IMB_imbuf.h"
74 #include "IMB_imbuf_types.h"
76 #include "RNA_access.h"
77 #include "RNA_define.h"
79 #include "UI_interface.h"
80 #include "UI_resources.h"
82 #include "wm_window.h"
84 #include "screen_intern.h" /* own module include */
86 #define KM_MODAL_CANCEL 1
87 #define KM_MODAL_APPLY 2
88 #define KM_MODAL_STEP10 3
89 #define KM_MODAL_STEP10_OFF 4
91 /* ************** Exported Poll tests ********************** */
93 int ED_operator_regionactive(bContext *C)
95 if(CTX_wm_window(C)==NULL) return 0;
96 if(CTX_wm_screen(C)==NULL) return 0;
97 if(CTX_wm_region(C)==NULL) return 0;
101 int ED_operator_areaactive(bContext *C)
103 if(CTX_wm_window(C)==NULL) return 0;
104 if(CTX_wm_screen(C)==NULL) return 0;
105 if(CTX_wm_area(C)==NULL) return 0;
109 int ED_operator_screenactive(bContext *C)
111 if(CTX_wm_window(C)==NULL) return 0;
112 if(CTX_wm_screen(C)==NULL) return 0;
116 /* when mouse is over area-edge */
117 int ED_operator_screen_mainwinactive(bContext *C)
119 if(CTX_wm_window(C)==NULL) return 0;
120 if(CTX_wm_screen(C)==NULL) return 0;
121 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
125 int ED_operator_scene_editable(bContext *C)
127 Scene *scene= CTX_data_scene(C);
128 if(scene && scene->id.lib==NULL)
133 static int ed_spacetype_test(bContext *C, int type)
135 if(ED_operator_areaactive(C)) {
136 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
137 return sl && (sl->spacetype == type);
142 int ED_operator_view3d_active(bContext *C)
144 return ed_spacetype_test(C, SPACE_VIEW3D);
147 int ED_operator_timeline_active(bContext *C)
149 return ed_spacetype_test(C, SPACE_TIME);
152 int ED_operator_outliner_active(bContext *C)
154 return ed_spacetype_test(C, SPACE_OUTLINER);
157 int ED_operator_file_active(bContext *C)
159 return ed_spacetype_test(C, SPACE_FILE);
162 int ED_operator_action_active(bContext *C)
164 return ed_spacetype_test(C, SPACE_ACTION);
167 int ED_operator_buttons_active(bContext *C)
169 return ed_spacetype_test(C, SPACE_BUTS);
172 int ED_operator_node_active(bContext *C)
174 SpaceNode *snode= CTX_wm_space_node(C);
176 if(snode && snode->edittree)
183 int ED_operator_ipo_active(bContext *C)
185 return ed_spacetype_test(C, SPACE_IPO);
188 int ED_operator_sequencer_active(bContext *C)
190 return ed_spacetype_test(C, SPACE_SEQ);
193 int ED_operator_image_active(bContext *C)
195 return ed_spacetype_test(C, SPACE_IMAGE);
198 int ED_operator_nla_active(bContext *C)
200 return ed_spacetype_test(C, SPACE_NLA);
203 int ED_operator_logic_active(bContext *C)
205 return ed_spacetype_test(C, SPACE_LOGIC);
208 int ED_operator_object_active(bContext *C)
210 return NULL != CTX_data_active_object(C);
213 int ED_operator_editmesh(bContext *C)
215 Object *obedit= CTX_data_edit_object(C);
216 if(obedit && obedit->type==OB_MESH)
217 return NULL != ((Mesh *)obedit->data)->edit_mesh;
221 int ED_operator_editarmature(bContext *C)
223 Object *obedit= CTX_data_edit_object(C);
224 if(obedit && obedit->type==OB_ARMATURE)
225 return NULL != ((bArmature *)obedit->data)->edbo;
229 int ED_operator_posemode(bContext *C)
231 Object *obact= CTX_data_active_object(C);
232 Object *obedit= CTX_data_edit_object(C);
234 if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
235 return (obact->mode & OB_MODE_POSE)!=0;
241 int ED_operator_uvedit(bContext *C)
243 Object *obedit= CTX_data_edit_object(C);
246 if(obedit && obedit->type==OB_MESH)
247 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
249 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
250 BKE_mesh_end_editmesh(obedit->data, em);
255 BKE_mesh_end_editmesh(obedit->data, em);
259 int ED_operator_uvmap(bContext *C)
261 Object *obedit= CTX_data_edit_object(C);
264 if(obedit && obedit->type==OB_MESH)
265 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
267 if(em && (em->faces.first)) {
268 BKE_mesh_end_editmesh(obedit->data, em);
273 BKE_mesh_end_editmesh(obedit->data, em);
277 int ED_operator_editsurfcurve(bContext *C)
279 Object *obedit= CTX_data_edit_object(C);
280 if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
281 return NULL != ((Curve *)obedit->data)->editnurb;
286 int ED_operator_editcurve(bContext *C)
288 Object *obedit= CTX_data_edit_object(C);
289 if(obedit && obedit->type==OB_CURVE)
290 return NULL != ((Curve *)obedit->data)->editnurb;
294 int ED_operator_editsurf(bContext *C)
296 Object *obedit= CTX_data_edit_object(C);
297 if(obedit && obedit->type==OB_SURF)
298 return NULL != ((Curve *)obedit->data)->editnurb;
302 int ED_operator_editfont(bContext *C)
304 Object *obedit= CTX_data_edit_object(C);
305 if(obedit && obedit->type==OB_FONT)
306 return NULL != ((Curve *)obedit->data)->editfont;
310 int ED_operator_editlattice(bContext *C)
312 Object *obedit= CTX_data_edit_object(C);
313 if(obedit && obedit->type==OB_LATTICE)
314 return NULL != ((Lattice *)obedit->data)->editlatt;
318 int ED_operator_editmball(bContext *C)
320 Object *obedit= CTX_data_edit_object(C);
321 if(obedit && obedit->type==OB_MBALL)
322 return NULL != ((MetaBall *)obedit->data)->editelems;
326 /* *************************** action zone operator ************************** */
328 /* operator state vars used:
333 apply() set actionzone event
335 exit() free customdata
341 invoke() check if in zone
342 add customdata, put mouseco and area in it
345 modal() accept modal events while doing it
346 call apply() with gesture info, active window, nonactive window
347 call exit() and remove handler when LMB confirm
351 typedef struct sActionzoneData {
354 int x, y, gesture_dir, modifier;
357 /* used by other operators too */
358 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
361 sa= scr->areabase.first;
363 if(BLI_in_rcti(&sa->totrct, x, y)) break;
370 /* quick poll to save operators to be created and handled */
371 static int actionzone_area_poll(bContext *C)
373 wmWindow *win= CTX_wm_window(C);
374 ScrArea *sa= CTX_wm_area(C);
378 int x= win->eventstate->x;
379 int y= win->eventstate->y;
381 for(az= sa->actionzones.first; az; az= az->next)
382 if(BLI_in_rcti(&az->rect, x, y))
388 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
392 for(az= sa->actionzones.first; az; az= az->next) {
393 if(BLI_in_rcti(&az->rect, x, y)) {
394 if(az->type == AZONE_AREA) {
395 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
398 else if(az->type == AZONE_REGION) {
408 static void actionzone_exit(bContext *C, wmOperator *op)
411 MEM_freeN(op->customdata);
412 op->customdata= NULL;
415 /* send EVT_ACTIONZONE event */
416 static void actionzone_apply(bContext *C, wmOperator *op, int type)
419 wmWindow *win= CTX_wm_window(C);
420 sActionzoneData *sad= op->customdata;
422 sad->modifier= RNA_int_get(op->ptr, "modifier");
424 event= *(win->eventstate); /* XXX huh huh? make api call */
426 event.type= EVT_ACTIONZONE_AREA;
428 event.type= EVT_ACTIONZONE_REGION;
429 event.customdata= op->customdata;
430 event.customdatafree= TRUE;
431 op->customdata= NULL;
433 wm_event_add(win, &event);
436 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
438 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
439 sActionzoneData *sad;
443 return OPERATOR_PASS_THROUGH;
445 /* ok we do the actionzone */
446 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
447 sad->sa1= CTX_wm_area(C);
449 sad->x= event->x; sad->y= event->y;
451 /* region azone directly reacts on mouse clicks */
452 if(sad->az->type==AZONE_REGION) {
453 actionzone_apply(C, op, AZONE_REGION);
454 actionzone_exit(C, op);
455 return OPERATOR_FINISHED;
458 /* add modal handler */
459 WM_event_add_modal_handler(C, op);
461 return OPERATOR_RUNNING_MODAL;
466 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
468 sActionzoneData *sad= op->customdata;
470 int mindelta= sad->az->type==AZONE_REGION?1:12;
472 switch(event->type) {
474 /* calculate gesture direction */
475 deltax= (event->x - sad->x);
476 deltay= (event->y - sad->y);
478 if(deltay > ABS(deltax))
479 sad->gesture_dir= 'n';
480 else if(deltax > ABS(deltay))
481 sad->gesture_dir= 'e';
482 else if(deltay < -ABS(deltax))
483 sad->gesture_dir= 's';
485 sad->gesture_dir= 'w';
487 /* gesture is large enough? */
488 if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
490 /* second area, for join */
491 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
492 /* apply sends event */
493 actionzone_apply(C, op, sad->az->type);
494 actionzone_exit(C, op);
496 return OPERATOR_FINISHED;
500 actionzone_exit(C, op);
501 return OPERATOR_CANCELLED;
503 actionzone_exit(C, op);
504 return OPERATOR_CANCELLED;
508 return OPERATOR_RUNNING_MODAL;
511 static void SCREEN_OT_actionzone(wmOperatorType *ot)
514 ot->name= "Handle area action zones";
515 ot->description= "Handle area action zones for mouse actions/gestures.";
516 ot->idname= "SCREEN_OT_actionzone";
518 ot->invoke= actionzone_invoke;
519 ot->modal= actionzone_modal;
520 ot->poll= actionzone_area_poll;
522 ot->flag= OPTYPE_BLOCKING;
524 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
527 /* ************** swap area operator *********************************** */
529 /* operator state vars used:
531 sa2 area to swap with
535 init() set custom data for operator, based on actionzone event custom data
537 cancel() cancel the operator
539 exit() cleanup, send notifier
543 invoke() gets called on shift+lmb drag in actionzone
544 call init(), add handler
546 modal() accept modal events while doing it
550 typedef struct sAreaSwapData {
554 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
556 sAreaSwapData *sd= NULL;
557 sActionzoneData *sad= event->customdata;
559 if(sad==NULL || sad->sa1==NULL)
562 sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
571 static void area_swap_exit(bContext *C, wmOperator *op)
574 MEM_freeN(op->customdata);
575 op->customdata= NULL;
578 static int area_swap_cancel(bContext *C, wmOperator *op)
580 area_swap_exit(C, op);
581 return OPERATOR_CANCELLED;
584 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
587 if(!area_swap_init(C, op, event))
588 return OPERATOR_PASS_THROUGH;
590 /* add modal handler */
591 WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
592 WM_event_add_modal_handler(C, op);
594 return OPERATOR_RUNNING_MODAL;
598 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
600 sActionzoneData *sad= op->customdata;
602 switch(event->type) {
604 /* second area, for join */
605 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
607 case LEFTMOUSE: /* release LMB */
608 if(event->val==KM_RELEASE) {
609 if(!sad->sa2 || sad->sa1 == sad->sa2) {
611 return area_swap_cancel(C, op);
613 ED_area_swapspace(C, sad->sa1, sad->sa2);
615 area_swap_exit(C, op);
617 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
619 return OPERATOR_FINISHED;
624 return area_swap_cancel(C, op);
626 return OPERATOR_RUNNING_MODAL;
629 static void SCREEN_OT_area_swap(wmOperatorType *ot)
631 ot->name= "Swap areas";
632 ot->description= "Swap selected areas screen positions.";
633 ot->idname= "SCREEN_OT_area_swap";
635 ot->invoke= area_swap_invoke;
636 ot->modal= area_swap_modal;
637 ot->poll= ED_operator_areaactive;
639 ot->flag= OPTYPE_BLOCKING;
642 /* *********** Duplicate area as new window operator ****************** */
644 /* operator callback */
645 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
647 wmWindow *newwin, *win;
652 win= CTX_wm_window(C);
653 sc= CTX_wm_screen(C);
657 if(event->type==EVT_ACTIONZONE_AREA) {
658 sActionzoneData *sad= event->customdata;
661 return OPERATOR_PASS_THROUGH;
666 /* poll() checks area context, but we don't accept full-area windows */
667 if(sc->full != SCREENNORMAL) {
668 if(event->type==EVT_ACTIONZONE_AREA)
669 actionzone_exit(C, op);
670 return OPERATOR_CANCELLED;
673 /* adds window to WM */
675 BLI_translate_rcti(&rect, win->posx, win->posy);
676 newwin= WM_window_open(C, &rect);
678 /* allocs new screen and adds to newly created window, using window size */
679 newsc= ED_screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
680 newwin->screen= newsc;
682 /* copy area to new screen */
683 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
685 /* screen, areas init */
686 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
688 if(event->type==EVT_ACTIONZONE_AREA)
689 actionzone_exit(C, op);
691 return OPERATOR_FINISHED;
694 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
696 ot->name= "Duplicate Area into New Window";
697 ot->description= "Duplicate selected area into new window.";
698 ot->idname= "SCREEN_OT_area_dupli";
700 ot->invoke= area_dupli_invoke;
701 ot->poll= ED_operator_areaactive;
705 /* ************** move area edge operator *********************************** */
707 /* operator state vars used:
708 x, y mouse coord near edge
709 delta movement of edge
713 init() set default property values, find edge based on mouse coords, test
714 if the edge can be moved, select edges, calculate min and max movement
716 apply() apply delta on selection
718 exit() cleanup, send notifier
720 cancel() cancel moving
724 exec() execute without any user interaction, based on properties
725 call init(), apply(), exit()
727 invoke() gets called on mouse click near edge
728 call init(), add handler
730 modal() accept modal events while doing it
731 call apply() with delta motion
732 call exit() and remove handler
736 typedef struct sAreaMoveData {
737 int bigger, smaller, origval, step;
741 /* helper call to move area-edge, sets limits */
742 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
746 /* we check all areas and test for free space with MINSIZE */
747 *bigger= *smaller= 100000;
749 for(sa= sc->areabase.first; sa; sa= sa->next) {
751 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
753 /* if top or down edge selected, test height */
754 if(sa->v1->flag && sa->v4->flag)
755 *bigger= MIN2(*bigger, y1);
756 else if(sa->v2->flag && sa->v3->flag)
757 *smaller= MIN2(*smaller, y1);
760 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
762 /* if left or right edge selected, test width */
763 if(sa->v1->flag && sa->v2->flag)
764 *bigger= MIN2(*bigger, x1);
765 else if(sa->v3->flag && sa->v4->flag)
766 *smaller= MIN2(*smaller, x1);
771 /* validate selection inside screen, set variables OK */
772 /* return 0: init failed */
773 static int area_move_init (bContext *C, wmOperator *op)
775 bScreen *sc= CTX_wm_screen(C);
780 /* required properties */
781 x= RNA_int_get(op->ptr, "x");
782 y= RNA_int_get(op->ptr, "y");
785 actedge= screen_find_active_scredge(sc, x, y);
786 if(actedge==NULL) return 0;
788 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
791 md->dir= scredge_is_horizontal(actedge)?'h':'v';
792 if(md->dir=='h') md->origval= actedge->v1->vec.y;
793 else md->origval= actedge->v1->vec.x;
795 select_connected_scredge(sc, actedge);
796 /* now all vertices with 'flag==1' are the ones that can be moved. */
798 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
803 /* moves selected screen edge amount of delta, used by split & move */
804 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
806 wmWindow *win= CTX_wm_window(C);
807 bScreen *sc= CTX_wm_screen(C);
810 delta= CLAMPIS(delta, -smaller, bigger);
812 for (v1= sc->vertbase.first; v1; v1= v1->next) {
814 /* that way a nice AREAGRID */
815 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
816 v1->vec.x= origval + delta;
817 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
819 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
820 v1->vec.y= origval + delta;
822 v1->vec.y+= AREAGRID-1;
823 v1->vec.y-= (v1->vec.y % AREAGRID);
825 /* prevent too small top header */
826 if(v1->vec.y > win->sizey-AREAMINY)
827 v1->vec.y= win->sizey-AREAMINY;
832 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
835 static void area_move_apply(bContext *C, wmOperator *op)
837 sAreaMoveData *md= op->customdata;
840 delta= RNA_int_get(op->ptr, "delta");
841 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
844 static void area_move_exit(bContext *C, wmOperator *op)
847 MEM_freeN(op->customdata);
848 op->customdata= NULL;
850 /* this makes sure aligned edges will result in aligned grabbing */
851 removedouble_scrverts(CTX_wm_screen(C));
852 removedouble_scredges(CTX_wm_screen(C));
855 static int area_move_exec(bContext *C, wmOperator *op)
857 if(!area_move_init(C, op))
858 return OPERATOR_CANCELLED;
860 area_move_apply(C, op);
861 area_move_exit(C, op);
863 return OPERATOR_FINISHED;
866 /* interaction callback */
867 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
869 RNA_int_set(op->ptr, "x", event->x);
870 RNA_int_set(op->ptr, "y", event->y);
872 if(!area_move_init(C, op))
873 return OPERATOR_PASS_THROUGH;
875 /* add temp handler */
876 WM_event_add_modal_handler(C, op);
878 return OPERATOR_RUNNING_MODAL;
881 static int area_move_cancel(bContext *C, wmOperator *op)
884 RNA_int_set(op->ptr, "delta", 0);
885 area_move_apply(C, op);
886 area_move_exit(C, op);
888 return OPERATOR_CANCELLED;
891 /* modal callback for while moving edges */
892 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
894 sAreaMoveData *md= op->customdata;
897 /* execute the events */
898 switch(event->type) {
901 x= RNA_int_get(op->ptr, "x");
902 y= RNA_int_get(op->ptr, "y");
904 delta= (md->dir == 'v')? event->x - x: event->y - y;
905 if(md->step) delta= delta - (delta % md->step);
906 RNA_int_set(op->ptr, "delta", delta);
908 area_move_apply(C, op);
913 switch (event->val) {
915 area_move_exit(C, op);
916 return OPERATOR_FINISHED;
918 case KM_MODAL_CANCEL:
919 return area_move_cancel(C, op);
921 case KM_MODAL_STEP10:
924 case KM_MODAL_STEP10_OFF:
930 return OPERATOR_RUNNING_MODAL;
933 static void SCREEN_OT_area_move(wmOperatorType *ot)
936 ot->name= "Move area edges";
937 ot->description= "Move selected area edges.";
938 ot->idname= "SCREEN_OT_area_move";
940 ot->exec= area_move_exec;
941 ot->invoke= area_move_invoke;
942 ot->cancel= area_move_cancel;
943 ot->modal= area_move_modal;
944 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
946 ot->flag= OPTYPE_BLOCKING;
949 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
950 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
951 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
954 /* ************** split area operator *********************************** */
959 dir direction 'v' or 'h'
962 area pointer to (active) area
963 x, y last used mouse pos
968 init() set default property values, find area based on context
970 apply() split area based on state vars
972 exit() cleanup, send notifier
974 cancel() remove duplicated area
978 exec() execute without any user interaction, based on state vars
979 call init(), apply(), exit()
981 invoke() gets called on mouse click in action-widget
982 call init(), add modal handler
983 call apply() with initial motion
985 modal() accept modal events while doing it
986 call move-areas code with delta motion
987 call exit() or cancel() and remove handler
991 #define SPLIT_STARTED 1
992 #define SPLIT_PROGRESS 2
994 typedef struct sAreaSplitData
996 int x, y; /* last used mouse position */
998 int origval; /* for move areas */
999 int bigger, smaller; /* constraints for moving new edge */
1000 int delta; /* delta move edge */
1001 int origmin, origsize; /* to calculate fac, for property storage */
1003 ScrEdge *nedge; /* new edge */
1004 ScrArea *sarea; /* start area */
1005 ScrArea *narea; /* new area */
1008 /* generic init, no UI stuff here */
1009 static int area_split_init(bContext *C, wmOperator *op)
1011 ScrArea *sa= CTX_wm_area(C);
1015 /* required context */
1016 if(sa==NULL) return 0;
1018 /* required properties */
1019 dir= RNA_enum_get(op->ptr, "direction");
1022 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
1023 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
1026 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1030 sd->origsize= dir=='v' ? sa->winx:sa->winy;
1031 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1036 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1037 /* used with split operator */
1038 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1040 ScrVert *sav1= sa->v1;
1041 ScrVert *sav2= sa->v2;
1042 ScrVert *sav3= sa->v3;
1043 ScrVert *sav4= sa->v4;
1044 ScrVert *sbv1= sb->v1;
1045 ScrVert *sbv2= sb->v2;
1046 ScrVert *sbv3= sb->v3;
1047 ScrVert *sbv4= sb->v4;
1049 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1050 return screen_findedge(screen, sav1, sav2);
1052 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1053 return screen_findedge(screen, sav2, sav3);
1055 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1056 return screen_findedge(screen, sav3, sav4);
1058 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1059 return screen_findedge(screen, sav1, sav4);
1066 /* do the split, return success */
1067 static int area_split_apply(bContext *C, wmOperator *op)
1069 bScreen *sc= CTX_wm_screen(C);
1070 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1074 fac= RNA_float_get(op->ptr, "factor");
1075 dir= RNA_enum_get(op->ptr, "direction");
1077 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1082 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1084 /* select newly created edge, prepare for moving edge */
1085 for(sv= sc->vertbase.first; sv; sv= sv->next)
1088 sd->nedge->v1->flag= 1;
1089 sd->nedge->v2->flag= 1;
1091 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1092 else sd->origval= sd->nedge->v1->vec.x;
1094 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1102 static void area_split_exit(bContext *C, wmOperator *op)
1104 if (op->customdata) {
1105 MEM_freeN(op->customdata);
1106 op->customdata = NULL;
1109 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1111 /* this makes sure aligned edges will result in aligned grabbing */
1112 removedouble_scrverts(CTX_wm_screen(C));
1113 removedouble_scredges(CTX_wm_screen(C));
1117 /* UI callback, adds new handler */
1118 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1122 if(event->type==EVT_ACTIONZONE_AREA) {
1123 sActionzoneData *sad= event->customdata;
1126 if(sad->modifier>0) {
1127 return OPERATOR_PASS_THROUGH;
1130 /* no full window splitting allowed */
1131 if(CTX_wm_area(C)->full)
1132 return OPERATOR_PASS_THROUGH;
1134 /* verify *sad itself */
1135 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1136 return OPERATOR_PASS_THROUGH;
1138 /* is this our *sad? if areas not equal it should be passed on */
1139 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1140 return OPERATOR_PASS_THROUGH;
1142 /* prepare operator state vars */
1143 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1145 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1149 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1151 RNA_enum_set(op->ptr, "direction", dir);
1153 /* general init, also non-UI case, adds customdata, sets area and defaults */
1154 if(!area_split_init(C, op))
1155 return OPERATOR_PASS_THROUGH;
1157 sd= (sAreaSplitData *)op->customdata;
1163 if(area_split_apply(C, op)) {
1164 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1166 /* add temp handler for edge move or cancel */
1167 WM_event_add_modal_handler(C, op);
1169 return OPERATOR_RUNNING_MODAL;
1174 /* nonmodal for now */
1175 return op->type->exec(C, op);
1178 return OPERATOR_PASS_THROUGH;
1181 /* function to be called outside UI context, or for redo */
1182 static int area_split_exec(bContext *C, wmOperator *op)
1185 if(!area_split_init(C, op))
1186 return OPERATOR_CANCELLED;
1188 area_split_apply(C, op);
1189 area_split_exit(C, op);
1191 return OPERATOR_FINISHED;
1195 static int area_split_cancel(bContext *C, wmOperator *op)
1197 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1199 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1200 if (CTX_wm_area(C) == sd->narea) {
1201 CTX_wm_area_set(C, NULL);
1202 CTX_wm_region_set(C, NULL);
1206 area_split_exit(C, op);
1208 return OPERATOR_CANCELLED;
1211 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1213 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1217 /* execute the events */
1218 switch(event->type) {
1220 dir= RNA_enum_get(op->ptr, "direction");
1222 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1223 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1225 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1226 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1228 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1232 if(event->val==KM_RELEASE) { /* mouse up */
1233 area_split_exit(C, op);
1234 return OPERATOR_FINISHED;
1237 case RIGHTMOUSE: /* cancel operation */
1239 return area_split_cancel(C, op);
1242 return OPERATOR_RUNNING_MODAL;
1245 static EnumPropertyItem prop_direction_items[] = {
1246 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1247 {'v', "VERTICAL", 0, "Vertical", ""},
1248 {0, NULL, 0, NULL, NULL}};
1250 static void SCREEN_OT_area_split(wmOperatorType *ot)
1252 ot->name = "Split area";
1253 ot->description= "Split selected area into new windows.";
1254 ot->idname = "SCREEN_OT_area_split";
1256 ot->exec= area_split_exec;
1257 ot->invoke= area_split_invoke;
1258 ot->modal= area_split_modal;
1260 ot->poll= ED_operator_areaactive;
1261 ot->flag= OPTYPE_BLOCKING;
1264 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1265 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1270 /* ************** scale region edge operator *********************************** */
1272 typedef struct RegionMoveData {
1276 int bigger, smaller, origval;
1282 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1284 sActionzoneData *sad= event->customdata;
1288 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1290 op->customdata= rmd;
1295 rmd->edge= az->edge;
1296 rmd->origx= event->x;
1297 rmd->origy= event->y;
1298 if(rmd->edge=='l' || rmd->edge=='r')
1299 rmd->origval= rmd->ar->type->minsizex;
1301 rmd->origval= rmd->ar->type->minsizey;
1303 /* add temp handler */
1304 WM_event_add_modal_handler(C, op);
1306 return OPERATOR_RUNNING_MODAL;
1309 return OPERATOR_FINISHED;
1312 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1314 RegionMoveData *rmd= op->customdata;
1317 /* execute the events */
1318 switch(event->type) {
1321 if(rmd->edge=='l' || rmd->edge=='r') {
1322 delta= event->x - rmd->origx;
1323 if(rmd->edge=='l') delta= -delta;
1324 rmd->ar->type->minsizex= rmd->origval + delta;
1325 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1326 if(rmd->ar->type->minsizex < 24) {
1327 rmd->ar->type->minsizex= rmd->origval;
1328 if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1329 ED_region_toggle_hidden(C, rmd->ar);
1331 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1332 ED_region_toggle_hidden(C, rmd->ar);
1335 delta= event->y - rmd->origy;
1336 if(rmd->edge=='b') delta= -delta;
1337 rmd->ar->type->minsizey= rmd->origval + delta;
1338 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1339 if(rmd->ar->type->minsizey < 24) {
1340 rmd->ar->type->minsizey= rmd->origval;
1341 if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1342 ED_region_toggle_hidden(C, rmd->ar);
1344 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1345 ED_region_toggle_hidden(C, rmd->ar);
1348 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1353 if(event->val==KM_RELEASE) {
1355 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1356 if(rmd->ar->flag & RGN_FLAG_HIDDEN) {
1357 ED_region_toggle_hidden(C, rmd->ar);
1358 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1361 MEM_freeN(op->customdata);
1362 op->customdata = NULL;
1364 return OPERATOR_FINISHED;
1372 return OPERATOR_RUNNING_MODAL;
1376 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1379 ot->name= "Scale Region Size";
1380 ot->description= "Scale selected area.";
1381 ot->idname= "SCREEN_OT_region_scale";
1383 ot->invoke= region_scale_invoke;
1384 ot->modal= region_scale_modal;
1386 ot->poll= ED_operator_areaactive;
1388 ot->flag= OPTYPE_BLOCKING;
1392 /* ************** frame change operator ***************************** */
1394 /* function to be called outside UI context, or for redo */
1395 static int frame_offset_exec(bContext *C, wmOperator *op)
1399 delta = RNA_int_get(op->ptr, "delta");
1401 CTX_data_scene(C)->r.cfra += delta;
1403 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1405 return OPERATOR_FINISHED;
1408 static void SCREEN_OT_frame_offset(wmOperatorType *ot)
1410 ot->name = "Frame Offset";
1411 ot->idname = "SCREEN_OT_frame_offset";
1413 ot->exec= frame_offset_exec;
1415 ot->poll= ED_operator_screenactive;
1419 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1423 /* function to be called outside UI context, or for redo */
1424 static int frame_jump_exec(bContext *C, wmOperator *op)
1426 Scene *scene= CTX_data_scene(C);
1428 if (RNA_boolean_get(op->ptr, "end"))
1433 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1435 return OPERATOR_FINISHED;
1438 static void SCREEN_OT_frame_jump(wmOperatorType *ot)
1440 ot->name = "Jump to Endpoint";
1441 ot->description= "Jump to first/last frame in frame range.";
1442 ot->idname = "SCREEN_OT_frame_jump";
1444 ot->exec= frame_jump_exec;
1446 ot->poll= ED_operator_screenactive;
1450 RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range.");
1454 /* ************** jump to keyframe operator ***************************** */
1456 /* function to be called outside UI context, or for redo */
1457 static int keyframe_jump_exec(bContext *C, wmOperator *op)
1459 Scene *scene= CTX_data_scene(C);
1460 Object *ob= CTX_data_active_object(C);
1463 short next= RNA_boolean_get(op->ptr, "next");
1467 return OPERATOR_CANCELLED;
1469 /* init binarytree-list for getting keyframes */
1470 BLI_dlrbTree_init(&keys);
1472 /* populate tree with keyframe nodes */
1473 if (scene && scene->adt)
1474 scene_to_keylist(NULL, scene, &keys, NULL);
1476 ob_to_keylist(NULL, ob, &keys, NULL);
1478 /* build linked-list for searching */
1479 BLI_dlrbTree_linkedlist_sync(&keys);
1481 /* find nearest keyframe in the right direction */
1482 ak= cfra_find_nearest_next_ak(keys.root, (float)scene->r.cfra, next);
1484 /* set the new frame (if keyframe found) */
1486 if (next && ak->next)
1487 scene->r.cfra= (int)ak->next->cfra;
1488 else if (!next && ak->prev)
1489 scene->r.cfra= (int)ak->prev->cfra;
1491 printf("ERROR: no suitable keyframe found. Using %f as new frame \n", ak->cfra);
1492 scene->r.cfra= (int)ak->cfra; // XXX
1496 /* free temp stuff */
1497 BLI_dlrbTree_free(&keys);
1499 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1501 return OPERATOR_FINISHED;
1504 static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
1506 ot->name = "Jump to Keyframe";
1507 ot->description= "Jump to previous/next keyframe.";
1508 ot->idname = "SCREEN_OT_keyframe_jump";
1510 ot->exec= keyframe_jump_exec;
1512 ot->poll= ED_operator_screenactive;
1516 RNA_def_boolean(ot->srna, "next", 1, "Next Keyframe", "");
1519 /* ************** switch screen operator ***************************** */
1522 /* function to be called outside UI context, or for redo */
1523 static int screen_set_exec(bContext *C, wmOperator *op)
1525 bScreen *screen= CTX_wm_screen(C);
1526 ScrArea *sa= CTX_wm_area(C);
1527 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1528 int delta= RNA_int_get(op->ptr, "delta");
1530 /* this screen is 'fake', solve later XXX */
1532 return OPERATOR_CANCELLED;
1536 screen= screen->id.next;
1537 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1538 if(screen->winid==0 && screen->full==0)
1542 else if(delta== -1) {
1544 screen= screen->id.prev;
1545 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1546 if(screen->winid==0 && screen->full==0)
1555 ED_screen_set(C, screen);
1556 return OPERATOR_FINISHED;
1558 return OPERATOR_CANCELLED;
1561 static void SCREEN_OT_screen_set(wmOperatorType *ot)
1563 ot->name = "Set Screen";
1564 ot->description= "Cycle through available screens.";
1565 ot->idname = "SCREEN_OT_screen_set";
1567 ot->exec= screen_set_exec;
1568 ot->poll= ED_operator_screenactive;
1571 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1574 /* ************** screen full-area operator ***************************** */
1577 /* function to be called outside UI context, or for redo */
1578 static int screen_full_area_exec(bContext *C, wmOperator *op)
1580 ed_screen_fullarea(C, CTX_wm_area(C));
1581 return OPERATOR_FINISHED;
1584 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1586 ot->name = "Toggle Full Screen";
1587 ot->description= "Toggle display selected area as fullscreen.";
1588 ot->idname = "SCREEN_OT_screen_full_area";
1590 ot->exec= screen_full_area_exec;
1591 ot->poll= ED_operator_areaactive;
1598 /* ************** join area operator ********************************************** */
1600 /* operator state vars used:
1601 x1, y1 mouse coord in first area, which will disappear
1602 x2, y2 mouse coord in 2nd area, which will become joined
1606 init() find edge based on state vars
1607 test if the edge divides two areas,
1608 store active and nonactive area,
1610 apply() do the actual join
1612 exit() cleanup, send notifier
1616 exec() calls init, apply, exit
1618 invoke() sets mouse coords in x,y
1622 modal() accept modal events while doing it
1623 call apply() with active window and nonactive window
1624 call exit() and remove handler when LMB confirm
1628 typedef struct sAreaJoinData
1630 ScrArea *sa1; /* first area to be considered */
1631 ScrArea *sa2; /* second area to be considered */
1632 ScrArea *scr; /* designed for removal */
1637 /* validate selection inside screen, set variables OK */
1638 /* return 0: init failed */
1639 /* XXX todo: find edge based on (x,y) and set other area? */
1640 static int area_join_init(bContext *C, wmOperator *op)
1643 sAreaJoinData* jd= NULL;
1647 /* required properties, make negative to get return 0 if not set by caller */
1648 x1= RNA_int_get(op->ptr, "x1");
1649 y1= RNA_int_get(op->ptr, "y1");
1650 x2= RNA_int_get(op->ptr, "x2");
1651 y2= RNA_int_get(op->ptr, "y2");
1653 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1654 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1655 if(sa1==NULL || sa2==NULL || sa1==sa2)
1658 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1661 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1663 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1670 /* apply the join of the areas (space types) */
1671 static int area_join_apply(bContext *C, wmOperator *op)
1673 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1676 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1679 if (CTX_wm_area(C) == jd->sa2) {
1680 CTX_wm_area_set(C, NULL);
1681 CTX_wm_region_set(C, NULL);
1687 /* finish operation */
1688 static void area_join_exit(bContext *C, wmOperator *op)
1690 if (op->customdata) {
1691 MEM_freeN(op->customdata);
1692 op->customdata = NULL;
1695 /* this makes sure aligned edges will result in aligned grabbing */
1696 removedouble_scredges(CTX_wm_screen(C));
1697 removenotused_scredges(CTX_wm_screen(C));
1698 removenotused_scrverts(CTX_wm_screen(C));
1701 static int area_join_exec(bContext *C, wmOperator *op)
1703 if(!area_join_init(C, op))
1704 return OPERATOR_CANCELLED;
1706 area_join_apply(C, op);
1707 area_join_exit(C, op);
1709 return OPERATOR_FINISHED;
1712 /* interaction callback */
1713 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1716 if(event->type==EVT_ACTIONZONE_AREA) {
1717 sActionzoneData *sad= event->customdata;
1719 if(sad->modifier>0) {
1720 return OPERATOR_PASS_THROUGH;
1723 /* verify *sad itself */
1724 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1725 return OPERATOR_PASS_THROUGH;
1727 /* is this our *sad? if areas equal it should be passed on */
1728 if(sad->sa1==sad->sa2)
1729 return OPERATOR_PASS_THROUGH;
1731 /* prepare operator state vars */
1732 RNA_int_set(op->ptr, "x1", sad->x);
1733 RNA_int_set(op->ptr, "y1", sad->y);
1734 RNA_int_set(op->ptr, "x2", event->x);
1735 RNA_int_set(op->ptr, "y2", event->y);
1737 if(!area_join_init(C, op))
1738 return OPERATOR_PASS_THROUGH;
1740 /* add temp handler */
1741 WM_event_add_modal_handler(C, op);
1743 return OPERATOR_RUNNING_MODAL;
1746 return OPERATOR_PASS_THROUGH;
1749 static int area_join_cancel(bContext *C, wmOperator *op)
1751 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1754 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1755 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1758 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1759 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1762 WM_event_add_notifier(C, NC_WINDOW, NULL);
1764 area_join_exit(C, op);
1766 return OPERATOR_CANCELLED;
1769 /* modal callback while selecting area (space) that will be removed */
1770 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1772 bScreen *sc= CTX_wm_screen(C);
1773 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1775 /* execute the events */
1776 switch(event->type) {
1780 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1784 if (jd->sa1 != sa) {
1785 dir = area_getorientation(sc, jd->sa1, sa);
1787 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1789 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1792 /* we are not bordering on the previously selected area
1793 we check if area has common border with the one marked for removal
1794 in this case we can swap areas.
1796 dir = area_getorientation(sc, sa, jd->sa2);
1798 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1799 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1802 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1803 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1806 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1810 WM_event_add_notifier(C, NC_WINDOW, NULL);
1813 /* we are back in the area previously selected for keeping
1814 * we swap the areas if possible to allow user to choose */
1815 if (jd->sa2 != NULL) {
1816 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1817 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1820 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1821 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1822 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1824 printf("oops, didn't expect that!\n");
1828 dir = area_getorientation(sc, jd->sa1, sa);
1830 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1832 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1835 WM_event_add_notifier(C, NC_WINDOW, NULL);
1841 if(event->val==KM_RELEASE) {
1842 area_join_apply(C, op);
1843 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1844 area_join_exit(C, op);
1845 return OPERATOR_FINISHED;
1850 return area_join_cancel(C, op);
1853 return OPERATOR_RUNNING_MODAL;
1856 /* Operator for joining two areas (space types) */
1857 static void SCREEN_OT_area_join(wmOperatorType *ot)
1860 ot->name= "Join area";
1861 ot->description= "Join selected areas into new window.";
1862 ot->idname= "SCREEN_OT_area_join";
1865 ot->exec= area_join_exec;
1866 ot->invoke= area_join_invoke;
1867 ot->modal= area_join_modal;
1868 ot->poll= ED_operator_areaactive;
1870 ot->flag= OPTYPE_BLOCKING;
1873 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1874 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1875 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1876 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1879 /* ************** repeat last operator ***************************** */
1881 static int repeat_last_exec(bContext *C, wmOperator *op)
1883 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1886 WM_operator_repeat(C, lastop);
1888 return OPERATOR_CANCELLED;
1891 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
1894 ot->name= "Repeat Last";
1895 ot->description= "Repeat last action.";
1896 ot->idname= "SCREEN_OT_repeat_last";
1899 ot->exec= repeat_last_exec;
1901 ot->poll= ED_operator_screenactive;
1905 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1907 wmWindowManager *wm= CTX_wm_manager(C);
1913 items= BLI_countlist(&wm->operators);
1915 return OPERATOR_CANCELLED;
1917 pup= uiPupMenuBegin(C, op->type->name, 0);
1918 layout= uiPupMenuLayout(pup);
1920 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1921 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1923 uiPupMenuEnd(C, pup);
1925 return OPERATOR_CANCELLED;
1928 static int repeat_history_exec(bContext *C, wmOperator *op)
1930 wmWindowManager *wm= CTX_wm_manager(C);
1932 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1934 /* let's put it as last operator in list */
1935 BLI_remlink(&wm->operators, op);
1936 BLI_addtail(&wm->operators, op);
1938 WM_operator_repeat(C, op);
1941 return OPERATOR_FINISHED;
1944 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
1947 ot->name= "Repeat History";
1948 ot->description= "Display menu for previous actions performed.";
1949 ot->idname= "SCREEN_OT_repeat_history";
1952 ot->invoke= repeat_history_invoke;
1953 ot->exec= repeat_history_exec;
1955 ot->poll= ED_operator_screenactive;
1957 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1960 /* ********************** redo operator ***************************** */
1962 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1964 wmWindowManager *wm= CTX_wm_manager(C);
1967 /* only for operators that are registered and did an undo push */
1968 for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1969 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1973 WM_operator_redo_popup(C, lastop);
1975 return OPERATOR_CANCELLED;
1978 static void SCREEN_OT_redo_last(wmOperatorType *ot)
1981 ot->name= "Redo Last";
1982 ot->description= "Display menu for last action performed.";
1983 ot->idname= "SCREEN_OT_redo_last";
1986 ot->invoke= redo_last_invoke;
1988 ot->poll= ED_operator_screenactive;
1991 /* ************** region split operator ***************************** */
1993 /* insert a region in the area region list */
1994 static int region_split_exec(bContext *C, wmOperator *op)
1996 ARegion *ar= CTX_wm_region(C);
1998 if(ar->regiontype==RGN_TYPE_HEADER)
1999 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
2000 else if(ar->alignment==RGN_ALIGN_QSPLIT)
2001 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
2003 ScrArea *sa= CTX_wm_area(C);
2004 ARegion *newar= BKE_area_region_copy(sa->type, ar);
2005 int dir= RNA_enum_get(op->ptr, "type");
2007 BLI_insertlinkafter(&sa->regionbase, ar, newar);
2009 newar->alignment= ar->alignment;
2012 ar->alignment= RGN_ALIGN_HSPLIT;
2014 ar->alignment= RGN_ALIGN_VSPLIT;
2016 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2019 return OPERATOR_FINISHED;
2022 static void SCREEN_OT_region_split(wmOperatorType *ot)
2025 ot->name= "Split Region";
2026 ot->description= "Split area by directional position.";
2027 ot->idname= "SCREEN_OT_region_split";
2030 ot->invoke= WM_menu_invoke;
2031 ot->exec= region_split_exec;
2032 ot->poll= ED_operator_areaactive;
2034 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
2037 /* ************** region four-split operator ***************************** */
2039 /* insert a region in the area region list */
2040 static int region_foursplit_exec(bContext *C, wmOperator *op)
2042 ARegion *ar= CTX_wm_region(C);
2045 if(ar->regiontype!=RGN_TYPE_WINDOW)
2046 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
2047 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
2048 ScrArea *sa= CTX_wm_area(C);
2051 /* keep current region */
2054 if(sa->spacetype==SPACE_VIEW3D) {
2055 RegionView3D *rv3d= ar->regiondata;
2057 rv3d->rflag &= ~RV3D_CLIPPING;
2060 for(ar= sa->regionbase.first; ar; ar= arn) {
2062 if(ar->alignment==RGN_ALIGN_QSPLIT) {
2063 ED_region_exit(C, ar);
2064 BKE_area_region_free(sa->type, ar);
2065 BLI_remlink(&sa->regionbase, ar);
2069 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2072 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
2074 ScrArea *sa= CTX_wm_area(C);
2078 ar->alignment= RGN_ALIGN_QSPLIT;
2080 for(count=0; count<3; count++) {
2081 newar= BKE_area_region_copy(sa->type, ar);
2082 BLI_addtail(&sa->regionbase, newar);
2085 /* lock views and set them */
2086 if(sa->spacetype==SPACE_VIEW3D) {
2089 rv3d= ar->regiondata;
2090 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
2093 rv3d= ar->regiondata;
2094 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
2097 rv3d= ar->regiondata;
2098 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
2101 rv3d= ar->regiondata;
2102 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
2105 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2109 return OPERATOR_FINISHED;
2112 static void SCREEN_OT_region_foursplit(wmOperatorType *ot)
2115 ot->name= "Toggle Quad View";
2116 ot->description= "Split selected area into camera, front, right & top views.";
2117 ot->idname= "SCREEN_OT_region_foursplit";
2120 // ot->invoke= WM_operator_confirm;
2121 ot->exec= region_foursplit_exec;
2122 ot->poll= ED_operator_areaactive;
2128 /* ************** region flip operator ***************************** */
2130 /* flip a region alignment */
2131 static int region_flip_exec(bContext *C, wmOperator *op)
2133 ARegion *ar= CTX_wm_region(C);
2135 if(ar->alignment==RGN_ALIGN_TOP)
2136 ar->alignment= RGN_ALIGN_BOTTOM;
2137 else if(ar->alignment==RGN_ALIGN_BOTTOM)
2138 ar->alignment= RGN_ALIGN_TOP;
2139 else if(ar->alignment==RGN_ALIGN_LEFT)
2140 ar->alignment= RGN_ALIGN_RIGHT;
2141 else if(ar->alignment==RGN_ALIGN_RIGHT)
2142 ar->alignment= RGN_ALIGN_LEFT;
2144 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2145 printf("executed region flip\n");
2147 return OPERATOR_FINISHED;
2151 static void SCREEN_OT_region_flip(wmOperatorType *ot)
2154 ot->name= "Flip Region";
2155 ot->idname= "SCREEN_OT_region_flip";
2158 ot->exec= region_flip_exec;
2160 ot->poll= ED_operator_areaactive;
2165 /* ****************** anim player, with timer ***************** */
2167 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2169 if(regiontype==RGN_TYPE_WINDOW) {
2171 switch (spacetype) {
2173 if(redraws & TIME_ALL_3D_WIN)
2179 if(redraws & TIME_ALL_ANIM_WIN)
2183 /* if only 1 window or 3d windows, we do timeline too */
2184 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2188 if(redraws & TIME_ALL_BUTS_WIN)
2192 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2196 if(redraws & (TIME_NODES))
2200 if(redraws & TIME_ALL_IMAGE_WIN)
2206 else if(regiontype==RGN_TYPE_UI) {
2207 if(redraws & TIME_ALL_BUTS_WIN)
2210 else if(regiontype==RGN_TYPE_HEADER) {
2211 if(spacetype==SPACE_TIME)
2217 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2219 bScreen *screen= CTX_wm_screen(C);
2221 if(screen->animtimer==event->customdata) {
2222 Scene *scene= CTX_data_scene(C);
2223 wmTimer *wt= screen->animtimer;
2224 ScreenAnimData *sad= wt->customdata;
2228 /* sync, don't sync, or follow scene setting */
2229 if(sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2230 else if(sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2231 else sync= (scene->audio.flag & AUDIO_SYNC);
2235 int step = floor(wt->duration * FPS);
2236 if(sad->flag & ANIMPLAY_FLAG_REVERSE) // XXX does this option work with audio?
2237 scene->r.cfra -= step;
2239 scene->r.cfra += step;
2240 wt->duration -= ((float)step)/FPS;
2244 if(sad->flag & ANIMPLAY_FLAG_REVERSE)
2250 /* reset 'jumped' flag before checking if we need to jump... */
2251 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2253 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2254 /* jump back to end? */
2255 if (scene->r.psfra) {
2256 if (scene->r.cfra < scene->r.psfra) {
2257 scene->r.cfra= scene->r.pefra;
2258 sad->flag |= ANIMPLAY_FLAG_JUMPED;
2262 if (scene->r.cfra < scene->r.sfra) {
2263 scene->r.cfra= scene->r.efra;
2264 sad->flag |= ANIMPLAY_FLAG_JUMPED;
2269 /* jump back to start? */
2270 if (scene->r.psfra) {
2271 if (scene->r.cfra > scene->r.pefra) {
2272 scene->r.cfra= scene->r.psfra;
2273 sad->flag |= ANIMPLAY_FLAG_JUMPED;
2277 if (scene->r.cfra > scene->r.efra) {
2278 scene->r.cfra= scene->r.sfra;
2279 sad->flag |= ANIMPLAY_FLAG_JUMPED;
2284 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2285 ED_update_for_newframe(C, 1);
2287 sound_update_playing(C);
2289 for(sa= screen->areabase.first; sa; sa= sa->next) {
2291 for(ar= sa->regionbase.first; ar; ar= ar->next) {
2293 ED_region_tag_redraw(ar);
2295 if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2296 ED_region_tag_redraw(ar);
2300 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2302 return OPERATOR_FINISHED;
2304 return OPERATOR_PASS_THROUGH;
2307 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2310 ot->name= "Animation Step";
2311 ot->description= "Step through animation by position.";
2312 ot->idname= "SCREEN_OT_animation_step";
2315 ot->invoke= screen_animation_step;
2317 ot->poll= ED_operator_screenactive;
2321 /* ****************** anim player, starts or ends timer ***************** */
2323 /* toggle operator */
2324 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2326 bScreen *screen= CTX_wm_screen(C);
2328 if(screen->animtimer) {
2329 ED_screen_animation_timer(C, 0, 0, 0);
2333 ScrArea *sa= CTX_wm_area(C);
2334 int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2337 if(RNA_property_is_set(op->ptr, "sync"))
2338 sync= (RNA_boolean_get(op->ptr, "sync"));
2340 /* timeline gets special treatment since it has it's own menu for determining redraws */
2341 if ((sa) && (sa->spacetype == SPACE_TIME)) {
2342 SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
2344 ED_screen_animation_timer(C, stime->redraws, sync, mode);
2346 /* update region if TIME_REGION was set, to leftmost 3d window */
2347 ED_screen_animation_timer_update(C, stime->redraws);
2350 int redraws = TIME_REGION|TIME_ALL_3D_WIN;
2352 /* XXX - would like a better way to deal with this situation - Campbell */
2353 if((sa) && (sa->spacetype == SPACE_SEQ)) {
2354 redraws |= TIME_SEQ;
2357 ED_screen_animation_timer(C, redraws, sync, mode);
2359 if(screen->animtimer) {
2360 wmTimer *wt= screen->animtimer;
2361 ScreenAnimData *sad= wt->customdata;
2363 sad->ar= CTX_wm_region(C);
2368 return OPERATOR_FINISHED;
2371 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2374 ot->name= "Play Animation";
2375 ot->description= "Play animation.";
2376 ot->idname= "SCREEN_OT_animation_play";
2379 ot->invoke= screen_animation_play;
2381 ot->poll= ED_operator_screenactive;
2383 RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2384 RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate and stay in sync with audio.");
2387 static int screen_animation_cancel(bContext *C, wmOperator *op, wmEvent *event)
2389 bScreen *screen= CTX_wm_screen(C);
2391 if(screen->animtimer)
2392 return screen_animation_play(C, op, event);
2394 return OPERATOR_PASS_THROUGH;
2397 static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
2400 ot->name= "Cancel Animation";
2401 ot->description= "Cancel animation.";
2402 ot->idname= "SCREEN_OT_animation_cancel";
2405 ot->invoke= screen_animation_cancel;
2407 ot->poll= ED_operator_screenactive;
2410 /* ************** border select operator (template) ***************************** */
2412 /* operator state vars used: (added by default WM callbacks)
2416 customdata: the wmGesture pointer
2420 exec() has to be filled in by user
2422 invoke() default WM function
2425 modal() default WM function
2426 accept modal events while doing it, calls exec(), handles ESC and border drawing
2428 poll() has to be filled in by user for context
2431 static int border_select_do(bContext *C, wmOperator *op)
2433 int event_type= RNA_int_get(op->ptr, "event_type");
2435 if(event_type==LEFTMOUSE)
2436 printf("border select do select\n");
2437 else if(event_type==RIGHTMOUSE)
2438 printf("border select deselect\n");
2440 printf("border select do something\n");
2445 static void SCREEN_OT_border_select(wmOperatorType *ot)
2448 ot->name= "Border select";
2449 ot->idname= "SCREEN_OT_border_select";
2452 ot->exec= border_select_do;
2453 ot->invoke= WM_border_select_invoke;
2454 ot->modal= WM_border_select_modal;
2456 ot->poll= ED_operator_areaactive;
2459 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2460 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2461 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2462 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2463 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2468 /* ****************************** render invoking ***************** */
2470 /* set callbacks, exported to sequence render too.
2471 Only call in foreground (UI) renders. */
2473 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2474 /* window as the last possible alternative. */
2475 static ScrArea *biggest_non_image_area(bContext *C)
2477 bScreen *sc= CTX_wm_screen(C);
2478 ScrArea *sa, *big= NULL;
2479 int size, maxsize= 0, bwmaxsize= 0;
2482 for(sa= sc->areabase.first; sa; sa= sa->next) {
2483 if(sa->winx > 30 && sa->winy > 30) {
2484 size= sa->winx*sa->winy;
2485 if(sa->spacetype == SPACE_BUTS) {
2486 if(foundwin == 0 && size > bwmaxsize) {
2491 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2502 static ScrArea *biggest_area(bContext *C)
2504 bScreen *sc= CTX_wm_screen(C);
2505 ScrArea *sa, *big= NULL;
2506 int size, maxsize= 0;
2508 for(sa= sc->areabase.first; sa; sa= sa->next) {
2509 size= sa->winx*sa->winy;
2510 if(size > maxsize) {
2519 static ScrArea *find_area_showing_r_result(bContext *C)
2521 bScreen *sc= CTX_wm_screen(C);
2525 /* find an imagewindow showing render result */
2526 for(sa=sc->areabase.first; sa; sa= sa->next) {
2527 if(sa->spacetype==SPACE_IMAGE) {
2528 sima= sa->spacedata.first;
2529 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2536 static ScrArea *find_area_image_empty(bContext *C)
2538 bScreen *sc= CTX_wm_screen(C);
2542 /* find an imagewindow showing render result */
2543 for(sa=sc->areabase.first; sa; sa= sa->next) {
2544 if(sa->spacetype==SPACE_IMAGE) {
2545 sima= sa->spacedata.first;
2553 #if 0 // XXX not used
2554 static ScrArea *find_empty_image_area(bContext *C)
2556 bScreen *sc= CTX_wm_screen(C);
2560 /* find an imagewindow showing render result */
2561 for(sa=sc->areabase.first; sa; sa= sa->next) {
2562 if(sa->spacetype==SPACE_IMAGE) {
2563 sima= sa->spacedata.first;
2570 #endif // XXX not used
2572 /* new window uses x,y to set position */
2573 static void screen_set_image_output(bContext *C, int mx, int my)
2575 Scene *scene= CTX_data_scene(C);
2579 if(scene->r.displaymode==R_OUTPUT_WINDOW) {
2583 sizex= 10 + (scene->r.xsch*scene->r.size)/100;
2584 sizey= 40 + (scene->r.ysch*scene->r.size)/100;
2586 /* arbitrary... miniature image window views don't make much sense */
2587 if(sizex < 320) sizex= 320;
2588 if(sizey < 256) sizey= 256;
2590 /* XXX some magic to calculate postition */
2591 rect.xmin= mx + CTX_wm_window(C)->posx - sizex/2;
2592 rect.ymin= my + CTX_wm_window(C)->posy - sizey/2;
2593 rect.xmax= rect.xmin + sizex;
2594 rect.ymax= rect.ymin + sizey;
2596 /* changes context! */
2597 WM_window_open_temp(C, &rect, WM_WINDOW_RENDER);
2601 else if(scene->r.displaymode==R_OUTPUT_SCREEN) {
2602 /* this function returns with changed context */
2603 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
2608 sa= find_area_showing_r_result(C);
2610 sa= find_area_image_empty(C);
2613 /* find largest open non-image area */
2614 sa= biggest_non_image_area(C);
2616 ED_area_newspace(C, sa, SPACE_IMAGE);
2617 sima= sa->spacedata.first;
2619 /* makes ESC go back to prev space */
2620 sima->flag |= SI_PREVSPACE;
2623 /* use any area of decent size */
2624 sa= biggest_area(C);
2625 if(sa->spacetype!=SPACE_IMAGE) {
2626 // XXX newspace(sa, SPACE_IMAGE);
2627 sima= sa->spacedata.first;
2629 /* makes ESC go back to prev space */
2630 sima->flag |= SI_PREVSPACE;
2635 sima= sa->spacedata.first;
2637 /* get the correct image, and scale it */
2638 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2640 // if(G.displaymode==2) { // XXX
2642 sima->flag |= SI_FULLWINDOW|SI_PREVSPACE;
2644 // ed_screen_fullarea(C, sa);
2650 /* executes blocking render */
2651 static int screen_render_exec(bContext *C, wmOperator *op)
2653 Scene *scene= CTX_data_scene(C);
2654 Render *re= RE_GetRender(scene->id.name);
2657 re= RE_NewRender(scene->id.name);
2659 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2661 if(RNA_boolean_get(op->ptr, "animation"))
2662 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2664 RE_BlenderFrame(re, scene, scene->r.cfra);
2666 // no redraw needed, we leave state as we entered it
2667 ED_update_for_newframe(C, 1);
2669 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2671 return OPERATOR_FINISHED;
2674 typedef struct RenderJob {
2685 static void render_freejob(void *rjv)
2692 /* str is IMA_RW_MAXTEXT in size */
2693 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
2695 char info_time_str[32]; // used to be extern to header_info.c
2696 uintptr_t mem_in_use, mmap_in_use;
2697 float megs_used_memory, mmap_used_memory;
2700 mem_in_use= MEM_get_memory_in_use();
2701 mmap_in_use= MEM_get_mapped_memory_in_use();
2703 megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
2704 mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
2706 if(scene->lay & 0xFF000000)
2707 spos+= sprintf(spos, "Localview | ");
2708 else if(scene->r.scemode & R_SINGLE_LAYER)
2709 spos+= sprintf(spos, "Single Layer | ");
2712 spos+= sprintf(spos, "%s ", rs->statstr);
2715 spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
2716 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
2717 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
2718 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
2721 spos+= sprintf(spos, "Field %d ", rs->curfield);
2723 spos+= sprintf(spos, "Blur %d ", rs->curblur);
2726 BLI_timestr(rs->lastframetime, info_time_str);
2727 spos+= sprintf(spos, "Time:%s ", info_time_str);
2729 if(rs->infostr && rs->infostr[0])
2730 spos+= sprintf(spos, "| %s ", rs->infostr);
2732 /* very weak... but 512 characters is quite safe */
2733 if(spos >= str+IMA_RW_MAXTEXT)
2734 printf("WARNING! renderwin text beyond limit \n");
2738 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
2742 /* malloc OK here, stats_draw is not in tile threads */
2743 if(rj->image->render_text==NULL)
2744 rj->image->render_text= MEM_callocN(IMA_RW_MAXTEXT, "rendertext");
2746 make_renderinfo_string(rs, rj->scene, rj->image->render_text);
2748 /* make jobs timer to send notifier */
2749 *(rj->do_update)= 1;
2753 /* called inside thread! */
2754 static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect)
2756 float x1, y1, *rectf= NULL;
2757 int ymin, ymax, xmin, xmax;
2761 /* if renrect argument, we only refresh scanlines */
2763 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2764 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2767 /* xmin here is first subrect x coord, xmax defines subrect width */
2768 xmin = renrect->xmin + rr->crop;
2769 xmax = renrect->xmax - xmin - rr->crop;
2772 ymin= renrect->ymin + rr->crop;
2773 ymax= renrect->ymax - ymin - rr->crop;
2776 renrect->ymin= renrect->ymax;
2780 xmin = ymin = rr->crop;
2781 xmax = rr->rectx - 2*rr->crop;
2782 ymax = rr->recty - 2*rr->crop;
2785 /* xmin ymin is in tile coords. transform to ibuf */
2786 rxmin= rr->tilerect.xmin + xmin;
2787 if(rxmin >= ibuf->x) return;
2788 rymin= rr->tilerect.ymin + ymin;
2789 if(rymin >= ibuf->y) return;
2791 if(rxmin + xmax > ibuf->x)
2792 xmax= ibuf->x - rxmin;
2793 if(rymin + ymax > ibuf->y)
2794 ymax= ibuf->y - rymin;
2796 if(xmax < 1 || ymax < 1) return;
2798 /* find current float rect for display, first case is after composit... still weak */
2805 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2806 rectf= rr->renlay->rectf;
2809 if(rectf==NULL) return;
2811 rectf+= 4*(rr->rectx*ymin + xmin);
2812 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2814 /* XXX make nice consistent functions for this */
2815 if (rj->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
2816 for(y1= 0; y1<ymax; y1++) {
2821 /* XXX temp. because crop offset */
2822 if( rectc >= (char *)(ibuf->rect)) {
2823 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2824 srgb[0]= linearrgb_to_srgb(rf[0]);
2825 srgb[1]= linearrgb_to_srgb(rf[1]);
2826 srgb[2]= linearrgb_to_srgb(rf[2]);
2828 rc[0]= FTOCHAR(srgb[0]);
2829 rc[1]= FTOCHAR(srgb[1]);
2830 rc[2]= FTOCHAR(srgb[2]);
2831 rc[3]= FTOCHAR(rf[3]);
2834 rectf += 4*rr->rectx;
2838 for(y1= 0; y1<ymax; y1++) {
2842 /* XXX temp. because crop offset */
2843 if( rectc >= (char *)(ibuf->rect)) {
2844 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2845 rc[0]= FTOCHAR(rf[0]);
2846 rc[1]= FTOCHAR(rf[1]);
2847 rc[2]= FTOCHAR(rf[2]);
2848 rc[3]= FTOCHAR(rf[3]);
2851 rectf += 4*rr->rectx;
2856 /* make jobs timer to send notifier */
2857 *(rj->do_update)= 1;
2860 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2866 ibuf= BKE_image_acquire_ibuf(rj->image, &rj->iuser, &lock);
2868 image_buffer_rect_update(rj, rr, ibuf, renrect);
2869 BKE_image_release_ibuf(rj->image, lock);
2872 static void render_startjob(void *rjv, short *stop, short *do_update)
2877 rj->do_update= do_update;
2880 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2882 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2885 /* called by render, check job 'stop' value or the global */
2886 static int render_breakjob(void *rjv)
2892 if(rj->stop && *(rj->stop))
2898 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2900 /* no running blender, remove handler and pass through */
2901 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2902 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2904 /* running render */
2905 switch (event->type) {
2907 return OPERATOR_RUNNING_MODAL;
2910 return OPERATOR_PASS_THROUGH;
2913 /* using context, starts job */
2914 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2916 /* new render clears all callbacks */
2917 Scene *scene= CTX_data_scene(C);
2923 /* only one render job at a time */
2924 if(WM_jobs_test(CTX_wm_manager(C), scene))
2925 return OPERATOR_CANCELLED;
2927 /* stop all running jobs, currently previews frustrate Render */
2928 WM_jobs_stop_all(CTX_wm_manager(C));
2930 /* handle UI stuff */
2933 /* flush multires changes (for sculpt) */
2934 multires_force_update(CTX_data_active_object(C));
2936 /* get editmode results */
2937 ED_object_exit_editmode(C, EM_DO_UNDO); /* 0 = does not exit editmode */
2940 // get view3d layer, local layer, make this nice api call to render
2943 /* ensure at least 1 area shows result */
2944 screen_set_image_output(C, event->x, event->y);
2946 /* job custom data */
2947 rj= MEM_callocN(sizeof(RenderJob), "render job");
2949 rj->win= CTX_wm_window(C);
2950 rj->anim= RNA_boolean_get(op->ptr, "animation");
2951 rj->iuser.scene= scene;
2955 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY);
2956 WM_jobs_customdata(steve, rj, render_freejob);
2957 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2958 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2960 /* get a render result image, and make sure it is empty */
2961 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2962 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2965 /* setup new render */
2966 re= RE_NewRender(scene->id.name);
2967 RE_test_break_cb(re, rj, render_breakjob);
2968 RE_display_draw_cb(re, rj, image_rect_update);
2969 RE_stats_draw_cb(re, rj, image_renderinfo_cb);
2974 // BKE_report in render!
2975 // RE_error_cb(re, error_cb);
2977 WM_jobs_start(CTX_wm_manager(C), steve);
2982 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2984 /* add modal handler for ESC */
2985 WM_event_add_modal_handler(C, op);
2987 return OPERATOR_RUNNING_MODAL;
2991 /* contextual render, using current scene, view3d? */
2992 static void SCREEN_OT_render(wmOperatorType *ot)
2996 ot->description= "Render active scene.";
2997 ot->idname= "SCREEN_OT_render";
3000 ot->invoke= screen_render_invoke;
3001 ot->modal= screen_render_modal;
3002 ot->exec= screen_render_exec;
3004 ot->poll= ED_operator_screenactive;
3006 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
3007 RNA_def_boolean(ot->srna, "animation", 0, "Animation", "");
3010 /* *********************** cancel render viewer *************** */
3012 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
3014 ScrArea *sa= CTX_wm_area(C);
3015 SpaceImage *sima= sa->spacedata.first;
3017 /* test if we have a temp screen in front */
3018 if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
3019 wm_window_lower(CTX_wm_window(C));
3020 return OPERATOR_FINISHED;
3022 /* determine if render already shows */
3023 else if(sima->flag & SI_PREVSPACE) {
3024 sima->flag &= ~SI_PREVSPACE;
3026 if(sima->flag & SI_FULLWINDOW) {
3027 sima->flag &= ~SI_FULLWINDOW;
3028 ED_screen_full_prevspace(C);
3031 ED_area_prevspace(C);
3033 return OPERATOR_FINISHED;
3035 else if(sima->flag & SI_FULLWINDOW) {
3036 sima->flag &= ~SI_FULLWINDOW;
3037 ed_screen_fullarea(C, sa);
3038 return OPERATOR_FINISHED;
3041 return OPERATOR_PASS_THROUGH;
3044 static void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
3047 ot->name= "Cancel Render View";
3048 ot->description= "Cancel show render view.";
3049 ot->idname= "SCREEN_OT_render_view_cancel";
3052 ot->exec= render_view_cancel_exec;
3053 ot->poll= ED_operator_image_active;
3056 /* *********************** show render viewer *************** */
3058 static int render_view_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
3060 ScrArea *sa= find_area_showing_r_result(C);
3062 /* test if we have a temp screen in front */
3063 if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
3064 wm_window_lower(CTX_wm_window(C));
3066 /* determine if render already shows */
3068 SpaceImage *sima= sa->spacedata.first;
3070 if(sima->flag & SI_PREVSPACE) {
3071 sima->flag &= ~SI_PREVSPACE;
3073 if(sima->flag & SI_FULLWINDOW) {
3074 sima->flag &= ~SI_FULLWINDOW;
3075 ED_screen_full_prevspace(C);
3077 else if(sima->next) {
3078 ED_area_newspace(C, sa, sima->next->spacetype);
3079 ED_area_tag_redraw(sa);
3084 screen_set_image_output(C, event->x, event->y);
3087 return OPERATOR_FINISHED;
3090 static void SCREEN_OT_render_view_show(struct wmOperatorType *ot)
3093 ot->name= "Show/Hide Render View";
3094 ot->description= "Toggle show render view.";
3095 ot->idname= "SCREEN_OT_render_view_show";
3098 ot->invoke= render_view_show_invoke;
3099 ot->poll= ED_operator_screenactive;
3102 /* *********** show user pref window ****** */
3104 static int userpref_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
3113 /* some magic to calculate postition */
3114 rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
3115 rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
3116 rect.xmax= rect.xmin + sizex;
3117 rect.ymax= rect.ymin + sizey;
3119 /* changes context! */
3120 WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
3125 return OPERATOR_FINISHED;
3129 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
3132 ot->name= "Show/Hide User Preferences";
3133 ot->description= "Show/hide user preferences.";
3134 ot->idname= "SCREEN_OT_userpref_show";
3137 ot->invoke= userpref_show_invoke;
3138 ot->poll= ED_operator_screenactive;
3141 /********************* new screen operator *********************/
3143 static int screen_new_exec(bContext *C, wmOperator *op)
3145 wmWindow *win= CTX_wm_window(C);
3146 bScreen *sc= CTX_wm_screen(C);
3148 sc= ED_screen_duplicate(win, sc);
3149 WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
3151 return OPERATOR_FINISHED;
3154 void SCREEN_OT_new(wmOperatorType *ot)
3157 ot->name= "New Screen";
3158 ot->description= "Add a new screen.";
3159 ot->idname= "SCREEN_OT_new";
3162 ot->exec= screen_new_exec;
3165 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3168 /********************* delete screen operator *********************/
3170 static int screen_delete_exec(bContext *C, wmOperator *op)
3172 bScreen *sc= CTX_wm_screen(C);
3174 WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
3176 return OPERATOR_FINISHED;
3179 void SCREEN_OT_delete(wmOperatorType *ot)
3182 ot->name= "Delete Screen"; //was scene
3183 ot->description= "Delete active screen.";
3184 ot->idname= "SCREEN_OT_delete";
3187 ot->exec= screen_delete_exec;
3190 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3193 /********************* new scene operator *********************/
3195 static int scene_new_exec(bContext *C, wmOperator *op)
3197 Scene *newscene, *scene= CTX_data_scene(C);
3198 Main *bmain= CTX_data_main(C);
3199 int type= RNA_enum_get(op->ptr, "type");
3201 newscene= copy_scene(bmain, scene, type);
3203 /* these can't be handled in blenkernel curently, so do them here */
3204 if(type == SCE_COPY_LINK_DATA)
3205 ED_object_single_users(newscene, 0);
3206 else if(type == SCE_COPY_FULL)
3207 ED_object_single_users(newscene, 1);
3209 WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
3211 return OPERATOR_FINISHED;
3214 void SCENE_OT_new(wmOperatorType *ot)
3216 static EnumPropertyItem type_items[]= {
3217 {SCE_COPY_EMPTY, "EMPTY", 0, "Empty", "Add empty scene."},
3218 {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene."},
3219 {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene."},
3220 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene."},
3221 {0, NULL, 0, NULL, NULL}};
3224 ot->name= "New Scene";
3225 ot->description= "Add new scene by type.";
3226 ot->idname= "SCENE_OT_new";
3229 ot->exec= scene_new_exec;
3230 ot->invoke= WM_menu_invoke;
3233 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3236 RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
3239 /********************* delete scene operator *********************/
3241 static int scene_delete_exec(bContext *C, wmOperator *op)
3243 Scene *scene= CTX_data_scene(C);
3245 WM_event_add_notifier(C, NC_SCENE|ND_SCENEDELETE, scene);
3247 return OPERATOR_FINISHED;
3250 void SCENE_OT_delete(wmOperatorType *ot)
3253 ot->name= "Delete Scene";
3254 ot->description= "Delete active scene.";
3255 ot->idname= "SCENE_OT_delete";
3258 ot->exec= scene_delete_exec;
3261 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3264 /* **************** Assigning operatortypes to global list, adding handlers **************** */
3266 /* called in spacetypes.c */
3267 void ED_operatortypes_screen(void)
3269 /* generic UI stuff */
3270 WM_operatortype_append(SCREEN_OT_actionzone);
3271 WM_operatortype_append(SCREEN_OT_repeat_last);
3272 WM_operatortype_append(SCREEN_OT_repeat_history);
3273 WM_operatortype_append(SCREEN_OT_redo_last);
3276 WM_operatortype_append(SCREEN_OT_area_move);
3277 WM_operatortype_append(SCREEN_OT_area_split);
3278 WM_operatortype_append(SCREEN_OT_area_join);
3279 WM_operatortype_append(SCREEN_OT_area_dupli);
3280 WM_operatortype_append(SCREEN_OT_area_swap);
3281 WM_operatortype_append(SCREEN_OT_region_split);
3282 WM_operatortype_append(SCREEN_OT_region_foursplit);
3283 WM_operatortype_append(SCREEN_OT_region_flip);
3284 WM_operatortype_append(SCREEN_OT_region_scale);
3285 WM_operatortype_append(SCREEN_OT_screen_set);
3286 WM_operatortype_append(SCREEN_OT_screen_full_area);
3287 WM_operatortype_append(SCREEN_OT_screenshot);
3288 WM_operatortype_append(SCREEN_OT_screencast);
3289 WM_operatortype_append(SCREEN_OT_userpref_show);
3292 WM_operatortype_append(SCREEN_OT_frame_offset);
3293 WM_operatortype_append(SCREEN_OT_frame_jump);
3294 WM_operatortype_append(SCREEN_OT_keyframe_jump);
3296 WM_operatortype_append(SCREEN_OT_animation_step);
3297 WM_operatortype_append(SCREEN_OT_animation_play);
3298 WM_operatortype_append(SCREEN_OT_animation_cancel);
3301 WM_operatortype_append(SCREEN_OT_render);
3302 WM_operatortype_append(SCREEN_OT_render_view_cancel);
3303 WM_operatortype_append(SCREEN_OT_render_view_show);
3306 WM_operatortype_append(SCREEN_OT_new);
3307 WM_operatortype_append(SCREEN_OT_delete);
3308 WM_operatortype_append(SCENE_OT_new);
3309 WM_operatortype_append(SCENE_OT_delete);
3311 /* tools shared by more space types */
3312 WM_operatortype_append(ED_OT_undo);
3313 WM_operatortype_append(ED_OT_redo);
3317 static void keymap_modal_set(wmKeyConfig *keyconf)
3319 static EnumPropertyItem modal_items[] = {
3320 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
3321 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},