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"
35 #include "DNA_armature_types.h"
36 #include "DNA_image_types.h"
37 #include "DNA_lattice_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_mesh_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_scene_types.h"
43 #include "BKE_blender.h"
44 #include "BKE_colortools.h"
45 #include "BKE_context.h"
46 #include "BKE_customdata.h"
47 #include "BKE_global.h"
48 #include "BKE_image.h"
49 #include "BKE_idprop.h"
50 #include "BKE_library.h"
53 #include "BKE_multires.h"
54 #include "BKE_report.h"
55 #include "BKE_screen.h"
56 #include "BKE_utildefines.h"
62 #include "ED_screen.h"
64 #include "ED_object.h"
65 #include "ED_screen_types.h"
67 #include "RE_pipeline.h"
68 #include "IMB_imbuf.h"
69 #include "IMB_imbuf_types.h"
71 #include "RNA_access.h"
72 #include "RNA_define.h"
74 #include "UI_interface.h"
75 #include "UI_resources.h"
77 #include "screen_intern.h" /* own module include */
79 /* ************** Exported Poll tests ********************** */
81 int ED_operator_regionactive(bContext *C)
83 if(CTX_wm_window(C)==NULL) return 0;
84 if(CTX_wm_screen(C)==NULL) return 0;
85 if(CTX_wm_region(C)==NULL) return 0;
89 int ED_operator_areaactive(bContext *C)
91 if(CTX_wm_window(C)==NULL) return 0;
92 if(CTX_wm_screen(C)==NULL) return 0;
93 if(CTX_wm_area(C)==NULL) return 0;
97 int ED_operator_screenactive(bContext *C)
99 if(CTX_wm_window(C)==NULL) return 0;
100 if(CTX_wm_screen(C)==NULL) return 0;
104 /* when mouse is over area-edge */
105 int ED_operator_screen_mainwinactive(bContext *C)
107 if(CTX_wm_window(C)==NULL) return 0;
108 if(CTX_wm_screen(C)==NULL) return 0;
109 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
113 int ED_operator_scene_editable(bContext *C)
115 Scene *scene= CTX_data_scene(C);
116 if(scene && scene->id.lib==NULL)
121 static int ed_spacetype_test(bContext *C, int type)
123 if(ED_operator_areaactive(C)) {
124 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
125 return sl && (sl->spacetype == type);
130 int ED_operator_view3d_active(bContext *C)
132 return ed_spacetype_test(C, SPACE_VIEW3D);
135 int ED_operator_timeline_active(bContext *C)
137 return ed_spacetype_test(C, SPACE_TIME);
140 int ED_operator_outliner_active(bContext *C)
142 return ed_spacetype_test(C, SPACE_OUTLINER);
145 int ED_operator_file_active(bContext *C)
147 return ed_spacetype_test(C, SPACE_FILE);
150 int ED_operator_action_active(bContext *C)
152 return ed_spacetype_test(C, SPACE_ACTION);
155 int ED_operator_buttons_active(bContext *C)
157 return ed_spacetype_test(C, SPACE_BUTS);
160 int ED_operator_node_active(bContext *C)
162 if(ed_spacetype_test(C, SPACE_NODE)) {
163 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
171 int ED_operator_ipo_active(bContext *C)
173 return ed_spacetype_test(C, SPACE_IPO);
176 int ED_operator_sequencer_active(bContext *C)
178 return ed_spacetype_test(C, SPACE_SEQ);
181 int ED_operator_image_active(bContext *C)
183 return ed_spacetype_test(C, SPACE_IMAGE);
186 int ED_operator_nla_active(bContext *C)
188 return ed_spacetype_test(C, SPACE_NLA);
191 int ED_operator_logic_active(bContext *C)
193 return ed_spacetype_test(C, SPACE_LOGIC);
196 int ED_operator_object_active(bContext *C)
198 return NULL != CTX_data_active_object(C);
201 int ED_operator_editmesh(bContext *C)
203 Object *obedit= CTX_data_edit_object(C);
204 if(obedit && obedit->type==OB_MESH)
205 return NULL != ((Mesh *)obedit->data)->edit_mesh;
209 int ED_operator_editarmature(bContext *C)
211 Object *obedit= CTX_data_edit_object(C);
212 if(obedit && obedit->type==OB_ARMATURE)
213 return NULL != ((bArmature *)obedit->data)->edbo;
217 int ED_operator_posemode(bContext *C)
219 Object *obact= CTX_data_active_object(C);
220 Object *obedit= CTX_data_edit_object(C);
222 if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
223 return (obact->flag & OB_POSEMODE)!=0;
229 int ED_operator_uvedit(bContext *C)
231 Object *obedit= CTX_data_edit_object(C);
234 if(obedit && obedit->type==OB_MESH)
235 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
237 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
238 BKE_mesh_end_editmesh(obedit->data, em);
243 BKE_mesh_end_editmesh(obedit->data, em);
247 int ED_operator_uvmap(bContext *C)
249 Object *obedit= CTX_data_edit_object(C);
252 if(obedit && obedit->type==OB_MESH)
253 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
255 if(em && (em->faces.first)) {
256 BKE_mesh_end_editmesh(obedit->data, em);
261 BKE_mesh_end_editmesh(obedit->data, em);
265 int ED_operator_editsurfcurve(bContext *C)
267 Object *obedit= CTX_data_edit_object(C);
268 if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
269 return NULL != ((Curve *)obedit->data)->editnurb;
274 int ED_operator_editcurve(bContext *C)
276 Object *obedit= CTX_data_edit_object(C);
277 if(obedit && obedit->type==OB_CURVE)
278 return NULL != ((Curve *)obedit->data)->editnurb;
282 int ED_operator_editsurf(bContext *C)
284 Object *obedit= CTX_data_edit_object(C);
285 if(obedit && obedit->type==OB_SURF)
286 return NULL != ((Curve *)obedit->data)->editnurb;
290 int ED_operator_editfont(bContext *C)
292 Object *obedit= CTX_data_edit_object(C);
293 if(obedit && obedit->type==OB_FONT)
294 return NULL != ((Curve *)obedit->data)->editfont;
298 int ED_operator_editlattice(bContext *C)
300 Object *obedit= CTX_data_edit_object(C);
301 if(obedit && obedit->type==OB_LATTICE)
302 return NULL != ((Lattice *)obedit->data)->editlatt;
306 /* *************************** action zone operator ************************** */
308 /* operator state vars used:
313 apply() set actionzone event
315 exit() free customdata
321 invoke() check if in zone
322 add customdata, put mouseco and area in it
325 modal() accept modal events while doing it
326 call apply() with gesture info, active window, nonactive window
327 call exit() and remove handler when LMB confirm
331 typedef struct sActionzoneData {
334 int x, y, gesture_dir, modifier;
337 /* used by other operators too */
338 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
341 sa= scr->areabase.first;
343 if(BLI_in_rcti(&sa->totrct, x, y)) break;
350 /* quick poll to save operators to be created and handled */
351 static int actionzone_area_poll(bContext *C)
353 wmWindow *win= CTX_wm_window(C);
354 ScrArea *sa= CTX_wm_area(C);
358 int x= win->eventstate->x;
359 int y= win->eventstate->y;
361 for(az= sa->actionzones.first; az; az= az->next)
362 if(BLI_in_rcti(&az->rect, x, y))
368 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
372 for(az= sa->actionzones.first; az; az= az->next) {
373 if(BLI_in_rcti(&az->rect, x, y)) {
374 if(az->type == AZONE_AREA) {
375 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
378 else if(az->type == AZONE_REGION) {
379 float v1[2], v2[2], v3[2], pt[2];
381 v1[0]= az->x1; v1[1]= az->y1;
382 v2[0]= az->x2; v2[1]= az->y2;
383 v3[0]= az->x3; v3[1]= az->y3;
386 if(IsPointInTri2D(v1, v2, v3, pt))
396 static void actionzone_exit(bContext *C, wmOperator *op)
399 MEM_freeN(op->customdata);
400 op->customdata= NULL;
403 /* send EVT_ACTIONZONE event */
404 static void actionzone_apply(bContext *C, wmOperator *op, int type)
407 wmWindow *win= CTX_wm_window(C);
408 sActionzoneData *sad= op->customdata;
410 sad->modifier= RNA_int_get(op->ptr, "modifier");
412 event= *(win->eventstate); /* XXX huh huh? make api call */
414 event.type= EVT_ACTIONZONE_AREA;
416 event.type= EVT_ACTIONZONE_REGION;
417 event.customdata= op->customdata;
418 event.customdatafree= TRUE;
419 op->customdata= NULL;
421 wm_event_add(win, &event);
424 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
426 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
427 sActionzoneData *sad;
431 return OPERATOR_PASS_THROUGH;
433 /* ok we do the actionzone */
434 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
435 sad->sa1= CTX_wm_area(C);
437 sad->x= event->x; sad->y= event->y;
439 /* region azone directly reacts on mouse clicks */
440 if(sad->az->type==AZONE_REGION) {
441 actionzone_apply(C, op, AZONE_REGION);
442 actionzone_exit(C, op);
443 return OPERATOR_FINISHED;
446 /* add modal handler */
447 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
449 return OPERATOR_RUNNING_MODAL;
454 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
456 sActionzoneData *sad= op->customdata;
458 int mindelta= sad->az->type==AZONE_REGION?1:12;
460 switch(event->type) {
462 /* calculate gesture direction */
463 deltax= (event->x - sad->x);
464 deltay= (event->y - sad->y);
466 if(deltay > ABS(deltax))
467 sad->gesture_dir= 'n';
468 else if(deltax > ABS(deltay))
469 sad->gesture_dir= 'e';
470 else if(deltay < -ABS(deltax))
471 sad->gesture_dir= 's';
473 sad->gesture_dir= 'w';
475 /* gesture is large enough? */
476 if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
478 /* second area, for join */
479 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
480 /* apply sends event */
481 actionzone_apply(C, op, sad->az->type);
482 actionzone_exit(C, op);
484 return OPERATOR_FINISHED;
488 actionzone_exit(C, op);
489 return OPERATOR_CANCELLED;
491 actionzone_exit(C, op);
492 return OPERATOR_CANCELLED;
496 return OPERATOR_RUNNING_MODAL;
499 void SCREEN_OT_actionzone(wmOperatorType *ot)
502 ot->name= "Handle area action zones";
503 ot->idname= "SCREEN_OT_actionzone";
505 ot->invoke= actionzone_invoke;
506 ot->modal= actionzone_modal;
507 ot->poll= actionzone_area_poll;
509 ot->flag= OPTYPE_BLOCKING;
511 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
514 /* ************** swap area operator *********************************** */
516 /* operator state vars used:
518 sa2 area to swap with
522 init() set custom data for operator, based on actionzone event custom data
524 cancel() cancel the operator
526 exit() cleanup, send notifier
530 invoke() gets called on shift+lmb drag in actionzone
531 call init(), add handler
533 modal() accept modal events while doing it
537 typedef struct sAreaSwapData {
541 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
543 sAreaSwapData *sd= NULL;
544 sActionzoneData *sad= event->customdata;
546 if(sad==NULL || sad->sa1==NULL)
549 sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
558 static void area_swap_exit(bContext *C, wmOperator *op)
561 MEM_freeN(op->customdata);
562 op->customdata= NULL;
565 static int area_swap_cancel(bContext *C, wmOperator *op)
567 area_swap_exit(C, op);
568 return OPERATOR_CANCELLED;
571 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
574 if(!area_swap_init(C, op, event))
575 return OPERATOR_PASS_THROUGH;
577 /* add modal handler */
578 WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
579 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
581 return OPERATOR_RUNNING_MODAL;
585 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
587 sActionzoneData *sad= op->customdata;
589 switch(event->type) {
591 /* second area, for join */
592 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
594 case LEFTMOUSE: /* release LMB */
596 if(sad->sa1 == sad->sa2) {
598 return area_swap_cancel(C, op);
600 ED_area_swapspace(C, sad->sa1, sad->sa2);
602 area_swap_exit(C, op);
604 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
606 return OPERATOR_FINISHED;
611 return area_swap_cancel(C, op);
613 return OPERATOR_RUNNING_MODAL;
616 static void SCREEN_OT_area_swap(wmOperatorType *ot)
618 ot->name= "Swap areas";
619 ot->idname= "SCREEN_OT_area_swap";
621 ot->invoke= area_swap_invoke;
622 ot->modal= area_swap_modal;
623 ot->poll= ED_operator_areaactive;
625 ot->flag= OPTYPE_BLOCKING;
628 /* *********** Duplicate area as new window operator ****************** */
630 /* operator callback */
631 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
633 wmWindow *newwin, *win;
638 win= CTX_wm_window(C);
639 sc= CTX_wm_screen(C);
643 if(event->type==EVT_ACTIONZONE_AREA) {
644 sActionzoneData *sad= event->customdata;
647 return OPERATOR_PASS_THROUGH;
652 /* poll() checks area context, but we don't accept full-area windows */
653 if(sc->full != SCREENNORMAL) {
654 if(event->type==EVT_ACTIONZONE_AREA)
655 actionzone_exit(C, op);
656 return OPERATOR_CANCELLED;
659 /* adds window to WM */
661 BLI_translate_rcti(&rect, win->posx, win->posy);
662 newwin= WM_window_open(C, &rect);
664 /* allocs new screen and adds to newly created window, using window size */
665 newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
666 newwin->screen= newsc;
668 /* copy area to new screen */
669 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
671 /* screen, areas init */
672 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
674 if(event->type==EVT_ACTIONZONE_AREA)
675 actionzone_exit(C, op);
677 return OPERATOR_FINISHED;
680 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
682 ot->name= "Duplicate Area into New Window";
683 ot->idname= "SCREEN_OT_area_dupli";
685 ot->invoke= area_dupli_invoke;
686 ot->poll= ED_operator_areaactive;
690 /* ************** move area edge operator *********************************** */
692 /* operator state vars used:
693 x, y mouse coord near edge
694 delta movement of edge
698 init() set default property values, find edge based on mouse coords, test
699 if the edge can be moved, select edges, calculate min and max movement
701 apply() apply delta on selection
703 exit() cleanup, send notifier
705 cancel() cancel moving
709 exec() execute without any user interaction, based on properties
710 call init(), apply(), exit()
712 invoke() gets called on mouse click near edge
713 call init(), add handler
715 modal() accept modal events while doing it
716 call apply() with delta motion
717 call exit() and remove handler
721 typedef struct sAreaMoveData {
722 int bigger, smaller, origval;
726 /* helper call to move area-edge, sets limits */
727 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
731 /* we check all areas and test for free space with MINSIZE */
732 *bigger= *smaller= 100000;
734 for(sa= sc->areabase.first; sa; sa= sa->next) {
736 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
738 /* if top or down edge selected, test height */
739 if(sa->v1->flag && sa->v4->flag)
740 *bigger= MIN2(*bigger, y1);
741 else if(sa->v2->flag && sa->v3->flag)
742 *smaller= MIN2(*smaller, y1);
745 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
747 /* if left or right edge selected, test width */
748 if(sa->v1->flag && sa->v2->flag)
749 *bigger= MIN2(*bigger, x1);
750 else if(sa->v3->flag && sa->v4->flag)
751 *smaller= MIN2(*smaller, x1);
756 /* validate selection inside screen, set variables OK */
757 /* return 0: init failed */
758 static int area_move_init (bContext *C, wmOperator *op)
760 bScreen *sc= CTX_wm_screen(C);
765 /* required properties */
766 x= RNA_int_get(op->ptr, "x");
767 y= RNA_int_get(op->ptr, "y");
770 actedge= screen_find_active_scredge(sc, x, y);
771 if(actedge==NULL) return 0;
773 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
776 md->dir= scredge_is_horizontal(actedge)?'h':'v';
777 if(md->dir=='h') md->origval= actedge->v1->vec.y;
778 else md->origval= actedge->v1->vec.x;
780 select_connected_scredge(sc, actedge);
781 /* now all vertices with 'flag==1' are the ones that can be moved. */
783 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
788 /* moves selected screen edge amount of delta, used by split & move */
789 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
791 wmWindow *win= CTX_wm_window(C);
792 bScreen *sc= CTX_wm_screen(C);
795 delta= CLAMPIS(delta, -smaller, bigger);
797 for (v1= sc->vertbase.first; v1; v1= v1->next) {
799 /* that way a nice AREAGRID */
800 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
801 v1->vec.x= origval + delta;
802 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
804 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
805 v1->vec.y= origval + delta;
807 v1->vec.y+= AREAGRID-1;
808 v1->vec.y-= (v1->vec.y % AREAGRID);
810 /* prevent too small top header */
811 if(v1->vec.y > win->sizey-AREAMINY)
812 v1->vec.y= win->sizey-AREAMINY;
817 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
820 static void area_move_apply(bContext *C, wmOperator *op)
822 sAreaMoveData *md= op->customdata;
825 delta= RNA_int_get(op->ptr, "delta");
826 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
829 static void area_move_exit(bContext *C, wmOperator *op)
832 MEM_freeN(op->customdata);
833 op->customdata= NULL;
835 /* this makes sure aligned edges will result in aligned grabbing */
836 removedouble_scrverts(CTX_wm_screen(C));
837 removedouble_scredges(CTX_wm_screen(C));
840 static int area_move_exec(bContext *C, wmOperator *op)
842 if(!area_move_init(C, op))
843 return OPERATOR_CANCELLED;
845 area_move_apply(C, op);
846 area_move_exit(C, op);
848 return OPERATOR_FINISHED;
851 /* interaction callback */
852 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
854 RNA_int_set(op->ptr, "x", event->x);
855 RNA_int_set(op->ptr, "y", event->y);
857 if(!area_move_init(C, op))
858 return OPERATOR_PASS_THROUGH;
860 /* add temp handler */
861 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
863 return OPERATOR_RUNNING_MODAL;
866 static int area_move_cancel(bContext *C, wmOperator *op)
869 RNA_int_set(op->ptr, "delta", 0);
870 area_move_apply(C, op);
871 area_move_exit(C, op);
873 return OPERATOR_CANCELLED;
876 /* modal callback for while moving edges */
877 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
884 x= RNA_int_get(op->ptr, "x");
885 y= RNA_int_get(op->ptr, "y");
887 /* execute the events */
888 switch(event->type) {
890 delta= (md->dir == 'v')? event->x - x: event->y - y;
891 RNA_int_set(op->ptr, "delta", delta);
893 area_move_apply(C, op);
898 area_move_exit(C, op);
899 return OPERATOR_FINISHED;
904 return area_move_cancel(C, op);
907 return OPERATOR_RUNNING_MODAL;
910 void SCREEN_OT_area_move(wmOperatorType *ot)
913 ot->name= "Move area edges";
914 ot->idname= "SCREEN_OT_area_move";
916 ot->exec= area_move_exec;
917 ot->invoke= area_move_invoke;
918 ot->cancel= area_move_cancel;
919 ot->modal= area_move_modal;
920 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
922 ot->flag= OPTYPE_BLOCKING;
925 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
926 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
927 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
930 /* ************** split area operator *********************************** */
935 dir direction 'v' or 'h'
938 area pointer to (active) area
939 x, y last used mouse pos
944 init() set default property values, find area based on context
946 apply() split area based on state vars
948 exit() cleanup, send notifier
950 cancel() remove duplicated area
954 exec() execute without any user interaction, based on state vars
955 call init(), apply(), exit()
957 invoke() gets called on mouse click in action-widget
958 call init(), add modal handler
959 call apply() with initial motion
961 modal() accept modal events while doing it
962 call move-areas code with delta motion
963 call exit() or cancel() and remove handler
967 #define SPLIT_STARTED 1
968 #define SPLIT_PROGRESS 2
970 typedef struct sAreaSplitData
972 int x, y; /* last used mouse position */
974 int origval; /* for move areas */
975 int bigger, smaller; /* constraints for moving new edge */
976 int delta; /* delta move edge */
977 int origmin, origsize; /* to calculate fac, for property storage */
979 ScrEdge *nedge; /* new edge */
980 ScrArea *sarea; /* start area */
981 ScrArea *narea; /* new area */
984 /* generic init, no UI stuff here */
985 static int area_split_init(bContext *C, wmOperator *op)
987 ScrArea *sa= CTX_wm_area(C);
991 /* required context */
992 if(sa==NULL) return 0;
994 /* required properties */
995 dir= RNA_enum_get(op->ptr, "direction");
998 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
999 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
1002 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1006 sd->origsize= dir=='v' ? sa->winx:sa->winy;
1007 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1012 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1013 /* used with split operator */
1014 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1016 ScrVert *sav1= sa->v1;
1017 ScrVert *sav2= sa->v2;
1018 ScrVert *sav3= sa->v3;
1019 ScrVert *sav4= sa->v4;
1020 ScrVert *sbv1= sb->v1;
1021 ScrVert *sbv2= sb->v2;
1022 ScrVert *sbv3= sb->v3;
1023 ScrVert *sbv4= sb->v4;
1025 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1026 return screen_findedge(screen, sav1, sav2);
1028 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1029 return screen_findedge(screen, sav2, sav3);
1031 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1032 return screen_findedge(screen, sav3, sav4);
1034 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1035 return screen_findedge(screen, sav1, sav4);
1042 /* do the split, return success */
1043 static int area_split_apply(bContext *C, wmOperator *op)
1045 bScreen *sc= CTX_wm_screen(C);
1046 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1050 fac= RNA_float_get(op->ptr, "factor");
1051 dir= RNA_enum_get(op->ptr, "direction");
1053 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1058 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1060 /* select newly created edge, prepare for moving edge */
1061 for(sv= sc->vertbase.first; sv; sv= sv->next)
1064 sd->nedge->v1->flag= 1;
1065 sd->nedge->v2->flag= 1;
1067 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1068 else sd->origval= sd->nedge->v1->vec.x;
1070 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1078 static void area_split_exit(bContext *C, wmOperator *op)
1080 if (op->customdata) {
1081 MEM_freeN(op->customdata);
1082 op->customdata = NULL;
1085 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1087 /* this makes sure aligned edges will result in aligned grabbing */
1088 removedouble_scrverts(CTX_wm_screen(C));
1089 removedouble_scredges(CTX_wm_screen(C));
1093 /* UI callback, adds new handler */
1094 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1098 if(event->type==EVT_ACTIONZONE_AREA) {
1099 sActionzoneData *sad= event->customdata;
1102 if(sad->modifier>0) {
1103 return OPERATOR_PASS_THROUGH;
1106 /* no full window splitting allowed */
1107 if(CTX_wm_area(C)->full)
1108 return OPERATOR_PASS_THROUGH;
1110 /* verify *sad itself */
1111 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1112 return OPERATOR_PASS_THROUGH;
1114 /* is this our *sad? if areas not equal it should be passed on */
1115 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1116 return OPERATOR_PASS_THROUGH;
1118 /* prepare operator state vars */
1119 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1121 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1125 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1127 RNA_enum_set(op->ptr, "direction", dir);
1129 /* general init, also non-UI case, adds customdata, sets area and defaults */
1130 if(!area_split_init(C, op))
1131 return OPERATOR_PASS_THROUGH;
1133 sd= (sAreaSplitData *)op->customdata;
1139 if(area_split_apply(C, op)) {
1140 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1142 /* add temp handler for edge move or cancel */
1143 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1145 return OPERATOR_RUNNING_MODAL;
1150 /* nonmodal for now */
1151 return op->type->exec(C, op);
1154 return OPERATOR_PASS_THROUGH;
1157 /* function to be called outside UI context, or for redo */
1158 static int area_split_exec(bContext *C, wmOperator *op)
1161 if(!area_split_init(C, op))
1162 return OPERATOR_CANCELLED;
1164 area_split_apply(C, op);
1165 area_split_exit(C, op);
1167 return OPERATOR_FINISHED;
1171 static int area_split_cancel(bContext *C, wmOperator *op)
1173 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1175 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1176 if (CTX_wm_area(C) == sd->narea) {
1177 CTX_wm_area_set(C, NULL);
1178 CTX_wm_region_set(C, NULL);
1182 area_split_exit(C, op);
1184 return OPERATOR_CANCELLED;
1187 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1189 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1193 /* execute the events */
1194 switch(event->type) {
1196 dir= RNA_enum_get(op->ptr, "direction");
1198 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1199 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1201 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1202 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1204 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1208 if(event->val==0) { /* mouse up */
1209 area_split_exit(C, op);
1210 return OPERATOR_FINISHED;
1213 case RIGHTMOUSE: /* cancel operation */
1215 return area_split_cancel(C, op);
1218 return OPERATOR_RUNNING_MODAL;
1221 static EnumPropertyItem prop_direction_items[] = {
1222 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1223 {'v', "VERTICAL", 0, "Vertical", ""},
1224 {0, NULL, 0, NULL, NULL}};
1226 void SCREEN_OT_area_split(wmOperatorType *ot)
1228 ot->name = "Split area";
1229 ot->idname = "SCREEN_OT_area_split";
1231 ot->exec= area_split_exec;
1232 ot->invoke= area_split_invoke;
1233 ot->modal= area_split_modal;
1235 ot->poll= ED_operator_areaactive;
1236 ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
1239 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1240 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1245 /* ************** scale region edge operator *********************************** */
1247 typedef struct RegionMoveData {
1249 int bigger, smaller, origval;
1255 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1257 sActionzoneData *sad= event->customdata;
1261 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1263 op->customdata= rmd;
1266 rmd->edge= az->edge;
1267 rmd->origx= event->x;
1268 rmd->origy= event->y;
1269 if(rmd->edge=='l' || rmd->edge=='r')
1270 rmd->origval= rmd->ar->type->minsizex;
1272 rmd->origval= rmd->ar->type->minsizey;
1274 /* add temp handler */
1275 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1277 return OPERATOR_RUNNING_MODAL;
1280 return OPERATOR_FINISHED;
1283 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1285 RegionMoveData *rmd= op->customdata;
1288 /* execute the events */
1289 switch(event->type) {
1292 if(rmd->edge=='l' || rmd->edge=='r') {
1293 delta= event->x - rmd->origx;
1294 if(rmd->edge=='l') delta= -delta;
1295 rmd->ar->type->minsizex= rmd->origval + delta;
1296 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1297 if(rmd->ar->type->minsizex < 10) {
1298 rmd->ar->type->minsizex= 10;
1299 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1302 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1305 delta= event->y - rmd->origy;
1306 if(rmd->edge=='b') delta= -delta;
1307 rmd->ar->type->minsizey= rmd->origval + delta;
1308 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1309 if(rmd->ar->type->minsizey < 10) {
1310 rmd->ar->type->minsizey= 10;
1311 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1314 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1317 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1324 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1325 rmd->ar->flag ^= RGN_FLAG_HIDDEN;
1326 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1328 MEM_freeN(op->customdata);
1329 op->customdata = NULL;
1331 return OPERATOR_FINISHED;
1339 return OPERATOR_RUNNING_MODAL;
1343 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1346 ot->name= "Scale Region Size";
1347 ot->idname= "SCREEN_OT_region_scale";
1349 ot->invoke= region_scale_invoke;
1350 ot->modal= region_scale_modal;
1352 ot->poll= ED_operator_areaactive;
1354 ot->flag= OPTYPE_BLOCKING;
1358 /* ************** frame change operator ***************************** */
1361 /* function to be called outside UI context, or for redo */
1362 static int frame_offset_exec(bContext *C, wmOperator *op)
1366 delta = RNA_int_get(op->ptr, "delta");
1368 CTX_data_scene(C)->r.cfra += delta;
1370 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1372 return OPERATOR_FINISHED;
1375 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1377 ot->name = "Frame Offset";
1378 ot->idname = "SCREEN_OT_frame_offset";
1380 ot->exec= frame_offset_exec;
1382 ot->poll= ED_operator_screenactive;
1386 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1389 /* ************** switch screen operator ***************************** */
1392 /* function to be called outside UI context, or for redo */
1393 static int screen_set_exec(bContext *C, wmOperator *op)
1395 bScreen *screen= CTX_wm_screen(C);
1396 ScrArea *sa= CTX_wm_area(C);
1397 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1398 int delta= RNA_int_get(op->ptr, "delta");
1400 /* this screen is 'fake', solve later XXX */
1402 return OPERATOR_CANCELLED;
1406 screen= screen->id.next;
1407 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1408 if(screen->winid==0 && screen->full==0)
1412 else if(delta== -1) {
1414 screen= screen->id.prev;
1415 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1416 if(screen->winid==0 && screen->full==0)
1425 ED_screen_set(C, screen);
1426 return OPERATOR_FINISHED;
1428 return OPERATOR_CANCELLED;
1431 void SCREEN_OT_screen_set(wmOperatorType *ot)
1433 ot->name = "Set Screen";
1434 ot->idname = "SCREEN_OT_screen_set";
1436 ot->exec= screen_set_exec;
1437 ot->poll= ED_operator_screenactive;
1440 RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1441 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1444 /* ************** screen full-area operator ***************************** */
1447 /* function to be called outside UI context, or for redo */
1448 static int screen_full_area_exec(bContext *C, wmOperator *op)
1450 ed_screen_fullarea(C, CTX_wm_area(C));
1451 return OPERATOR_FINISHED;
1454 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1456 ot->name = "Toggle Make Area Fullscreen";
1457 ot->idname = "SCREEN_OT_screen_full_area";
1459 ot->exec= screen_full_area_exec;
1460 ot->poll= ED_operator_areaactive;
1467 /* ************** join area operator ********************************************** */
1469 /* operator state vars used:
1470 x1, y1 mouse coord in first area, which will disappear
1471 x2, y2 mouse coord in 2nd area, which will become joined
1475 init() find edge based on state vars
1476 test if the edge divides two areas,
1477 store active and nonactive area,
1479 apply() do the actual join
1481 exit() cleanup, send notifier
1485 exec() calls init, apply, exit
1487 invoke() sets mouse coords in x,y
1491 modal() accept modal events while doing it
1492 call apply() with active window and nonactive window
1493 call exit() and remove handler when LMB confirm
1497 typedef struct sAreaJoinData
1499 ScrArea *sa1; /* first area to be considered */
1500 ScrArea *sa2; /* second area to be considered */
1501 ScrArea *scr; /* designed for removal */
1506 /* validate selection inside screen, set variables OK */
1507 /* return 0: init failed */
1508 /* XXX todo: find edge based on (x,y) and set other area? */
1509 static int area_join_init(bContext *C, wmOperator *op)
1512 sAreaJoinData* jd= NULL;
1516 /* required properties, make negative to get return 0 if not set by caller */
1517 x1= RNA_int_get(op->ptr, "x1");
1518 y1= RNA_int_get(op->ptr, "y1");
1519 x2= RNA_int_get(op->ptr, "x2");
1520 y2= RNA_int_get(op->ptr, "y2");
1522 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1523 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1524 if(sa1==NULL || sa2==NULL || sa1==sa2)
1527 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1530 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1532 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1539 /* apply the join of the areas (space types) */
1540 static int area_join_apply(bContext *C, wmOperator *op)
1542 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1545 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1548 if (CTX_wm_area(C) == jd->sa2) {
1549 CTX_wm_area_set(C, NULL);
1550 CTX_wm_region_set(C, NULL);
1556 /* finish operation */
1557 static void area_join_exit(bContext *C, wmOperator *op)
1559 if (op->customdata) {
1560 MEM_freeN(op->customdata);
1561 op->customdata = NULL;
1564 /* this makes sure aligned edges will result in aligned grabbing */
1565 removedouble_scredges(CTX_wm_screen(C));
1566 removenotused_scredges(CTX_wm_screen(C));
1567 removenotused_scrverts(CTX_wm_screen(C));
1570 static int area_join_exec(bContext *C, wmOperator *op)
1572 if(!area_join_init(C, op))
1573 return OPERATOR_CANCELLED;
1575 area_join_apply(C, op);
1576 area_join_exit(C, op);
1578 return OPERATOR_FINISHED;
1581 /* interaction callback */
1582 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1585 if(event->type==EVT_ACTIONZONE_AREA) {
1586 sActionzoneData *sad= event->customdata;
1588 if(sad->modifier>0) {
1589 return OPERATOR_PASS_THROUGH;
1592 /* verify *sad itself */
1593 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1594 return OPERATOR_PASS_THROUGH;
1596 /* is this our *sad? if areas equal it should be passed on */
1597 if(sad->sa1==sad->sa2)
1598 return OPERATOR_PASS_THROUGH;
1600 /* prepare operator state vars */
1601 RNA_int_set(op->ptr, "x1", sad->x);
1602 RNA_int_set(op->ptr, "y1", sad->y);
1603 RNA_int_set(op->ptr, "x2", event->x);
1604 RNA_int_set(op->ptr, "y2", event->y);
1606 if(!area_join_init(C, op))
1607 return OPERATOR_PASS_THROUGH;
1609 /* add temp handler */
1610 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1612 return OPERATOR_RUNNING_MODAL;
1615 return OPERATOR_PASS_THROUGH;
1618 static int area_join_cancel(bContext *C, wmOperator *op)
1620 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1623 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1624 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1627 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1628 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1631 WM_event_add_notifier(C, NC_WINDOW, NULL);
1633 area_join_exit(C, op);
1635 return OPERATOR_CANCELLED;
1638 /* modal callback while selecting area (space) that will be removed */
1639 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1641 bScreen *sc= CTX_wm_screen(C);
1642 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1644 /* execute the events */
1645 switch(event->type) {
1649 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1653 if (jd->sa1 != sa) {
1654 dir = area_getorientation(sc, jd->sa1, sa);
1656 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1658 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1661 /* we are not bordering on the previously selected area
1662 we check if area has common border with the one marked for removal
1663 in this case we can swap areas.
1665 dir = area_getorientation(sc, sa, jd->sa2);
1667 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1668 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1671 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1672 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1675 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1679 WM_event_add_notifier(C, NC_WINDOW, NULL);
1682 /* we are back in the area previously selected for keeping
1683 * we swap the areas if possible to allow user to choose */
1684 if (jd->sa2 != NULL) {
1685 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1686 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1689 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1690 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1691 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1693 printf("oops, didn't expect that!\n");
1697 dir = area_getorientation(sc, jd->sa1, sa);
1699 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1701 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1704 WM_event_add_notifier(C, NC_WINDOW, NULL);
1711 area_join_apply(C, op);
1712 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1713 area_join_exit(C, op);
1714 return OPERATOR_FINISHED;
1719 return area_join_cancel(C, op);
1722 return OPERATOR_RUNNING_MODAL;
1725 /* Operator for joining two areas (space types) */
1726 void SCREEN_OT_area_join(wmOperatorType *ot)
1729 ot->name= "Join area";
1730 ot->idname= "SCREEN_OT_area_join";
1733 ot->exec= area_join_exec;
1734 ot->invoke= area_join_invoke;
1735 ot->modal= area_join_modal;
1736 ot->poll= ED_operator_areaactive;
1738 ot->flag= OPTYPE_BLOCKING;
1741 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1742 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1743 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1744 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1747 /* ************** repeat last operator ***************************** */
1749 static int repeat_last_exec(bContext *C, wmOperator *op)
1751 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1754 WM_operator_repeat(C, lastop);
1756 return OPERATOR_CANCELLED;
1759 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1762 ot->name= "Repeat Last";
1763 ot->idname= "SCREEN_OT_repeat_last";
1766 ot->exec= repeat_last_exec;
1768 ot->poll= ED_operator_screenactive;
1772 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1774 wmWindowManager *wm= CTX_wm_manager(C);
1780 items= BLI_countlist(&wm->operators);
1782 return OPERATOR_CANCELLED;
1784 pup= uiPupMenuBegin(C, op->type->name, 0);
1785 layout= uiPupMenuLayout(pup);
1787 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1788 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1790 uiPupMenuEnd(C, pup);
1792 return OPERATOR_CANCELLED;
1795 static int repeat_history_exec(bContext *C, wmOperator *op)
1797 wmWindowManager *wm= CTX_wm_manager(C);
1799 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1801 /* let's put it as last operator in list */
1802 BLI_remlink(&wm->operators, op);
1803 BLI_addtail(&wm->operators, op);
1805 WM_operator_repeat(C, op);
1808 return OPERATOR_FINISHED;
1811 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1814 ot->name= "Repeat History";
1815 ot->idname= "SCREEN_OT_repeat_history";
1818 ot->invoke= repeat_history_invoke;
1819 ot->exec= repeat_history_exec;
1821 ot->poll= ED_operator_screenactive;
1823 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1826 /* ********************** redo operator ***************************** */
1828 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1830 wmWindowManager *wm= CTX_wm_manager(C);
1833 /* only for operators that are registered and did an undo push */
1834 for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1835 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1839 WM_operator_redo_popup(C, lastop);
1841 return OPERATOR_CANCELLED;
1844 void SCREEN_OT_redo_last(wmOperatorType *ot)
1847 ot->name= "Redo Last";
1848 ot->idname= "SCREEN_OT_redo_last";
1851 ot->invoke= redo_last_invoke;
1853 ot->poll= ED_operator_screenactive;
1856 /* ************** region split operator ***************************** */
1858 /* insert a region in the area region list */
1859 static int region_split_exec(bContext *C, wmOperator *op)
1861 ARegion *ar= CTX_wm_region(C);
1863 if(ar->regiontype==RGN_TYPE_HEADER)
1864 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1865 else if(ar->alignment==RGN_ALIGN_QSPLIT)
1866 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1868 ScrArea *sa= CTX_wm_area(C);
1869 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1870 int dir= RNA_enum_get(op->ptr, "type");
1872 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1874 newar->alignment= ar->alignment;
1877 ar->alignment= RGN_ALIGN_HSPLIT;
1879 ar->alignment= RGN_ALIGN_VSPLIT;
1881 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1884 return OPERATOR_FINISHED;
1887 void SCREEN_OT_region_split(wmOperatorType *ot)
1890 ot->name= "Split Region";
1891 ot->idname= "SCREEN_OT_region_split";
1894 ot->invoke= WM_menu_invoke;
1895 ot->exec= region_split_exec;
1896 ot->poll= ED_operator_areaactive;
1898 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1901 /* ************** region four-split operator ***************************** */
1903 /* insert a region in the area region list */
1904 static int region_foursplit_exec(bContext *C, wmOperator *op)
1906 ARegion *ar= CTX_wm_region(C);
1909 if(ar->regiontype!=RGN_TYPE_WINDOW)
1910 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1911 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1912 ScrArea *sa= CTX_wm_area(C);
1915 /* keep current region */
1918 if(sa->spacetype==SPACE_VIEW3D) {
1919 RegionView3D *rv3d= ar->regiondata;
1921 rv3d->rflag &= ~RV3D_CLIPPING;
1924 for(ar= sa->regionbase.first; ar; ar= arn) {
1926 if(ar->alignment==RGN_ALIGN_QSPLIT) {
1927 ED_region_exit(C, ar);
1928 BKE_area_region_free(sa->type, ar);
1929 BLI_remlink(&sa->regionbase, ar);
1933 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1936 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1938 ScrArea *sa= CTX_wm_area(C);
1942 ar->alignment= RGN_ALIGN_QSPLIT;
1944 for(count=0; count<3; count++) {
1945 newar= BKE_area_region_copy(sa->type, ar);
1946 BLI_addtail(&sa->regionbase, newar);
1949 /* lock views and set them */
1950 if(sa->spacetype==SPACE_VIEW3D) {
1953 rv3d= ar->regiondata;
1954 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1957 rv3d= ar->regiondata;
1958 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1961 rv3d= ar->regiondata;
1962 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1965 rv3d= ar->regiondata;
1966 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1969 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1973 return OPERATOR_FINISHED;
1976 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1979 ot->name= "Split Region in 4 Parts";
1980 ot->idname= "SCREEN_OT_region_foursplit";
1983 // ot->invoke= WM_operator_confirm;
1984 ot->exec= region_foursplit_exec;
1985 ot->poll= ED_operator_areaactive;
1986 ot->flag= OPTYPE_REGISTER;
1991 /* ************** region flip operator ***************************** */
1993 /* flip a region alignment */
1994 static int region_flip_exec(bContext *C, wmOperator *op)
1996 ARegion *ar= CTX_wm_region(C);
1998 if(ar->alignment==RGN_ALIGN_TOP)
1999 ar->alignment= RGN_ALIGN_BOTTOM;
2000 else if(ar->alignment==RGN_ALIGN_BOTTOM)
2001 ar->alignment= RGN_ALIGN_TOP;
2002 else if(ar->alignment==RGN_ALIGN_LEFT)
2003 ar->alignment= RGN_ALIGN_RIGHT;
2004 else if(ar->alignment==RGN_ALIGN_RIGHT)
2005 ar->alignment= RGN_ALIGN_LEFT;
2007 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2008 printf("executed region flip\n");
2010 return OPERATOR_FINISHED;
2014 void SCREEN_OT_region_flip(wmOperatorType *ot)
2017 ot->name= "Flip Region";
2018 ot->idname= "SCREEN_OT_region_flip";
2021 ot->exec= region_flip_exec;
2023 ot->poll= ED_operator_areaactive;
2024 ot->flag= OPTYPE_REGISTER;
2028 /* ****************** anim player, with timer ***************** */
2030 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2032 if(regiontype==RGN_TYPE_WINDOW) {
2034 switch (spacetype) {
2036 if(redraws & TIME_ALL_3D_WIN)
2042 if(redraws & TIME_ALL_ANIM_WIN)
2046 /* if only 1 window or 3d windows, we do timeline too */
2047 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2051 if(redraws & TIME_ALL_BUTS_WIN)
2055 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2059 if(redraws & TIME_ALL_IMAGE_WIN)
2065 else if(regiontype==RGN_TYPE_UI) {
2066 if(redraws & TIME_ALL_BUTS_WIN)
2069 else if(regiontype==RGN_TYPE_HEADER) {
2070 if(spacetype==SPACE_TIME)
2076 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2078 bScreen *screen= CTX_wm_screen(C);
2080 if(screen->animtimer==event->customdata) {
2081 Scene *scene= CTX_data_scene(C);
2082 wmTimer *wt= screen->animtimer;
2083 ScreenAnimData *sad= wt->customdata;
2086 if(scene->audio.flag & AUDIO_SYNC) {
2087 int step = floor(wt->duration * FPS);
2088 if (sad->reverse) // XXX does this option work with audio?
2089 scene->r.cfra -= step;
2091 scene->r.cfra += step;
2092 wt->duration -= ((float)step)/FPS;
2102 /* jump back to end */
2103 if (scene->r.psfra) {
2104 if(scene->r.cfra < scene->r.psfra)
2105 scene->r.cfra= scene->r.pefra;
2108 if(scene->r.cfra < scene->r.sfra)
2109 scene->r.cfra= scene->r.efra;
2113 /* jump back to start */
2114 if (scene->r.psfra) {
2115 if(scene->r.cfra > scene->r.pefra)
2116 scene->r.cfra= scene->r.psfra;
2119 if(scene->r.cfra > scene->r.efra)
2120 scene->r.cfra= scene->r.sfra;
2124 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2125 ED_update_for_newframe(C, 1);
2127 for(sa= screen->areabase.first; sa; sa= sa->next) {
2129 for(ar= sa->regionbase.first; ar; ar= ar->next) {
2131 ED_region_tag_redraw(ar);
2133 if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2134 ED_region_tag_redraw(ar);
2138 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2140 return OPERATOR_FINISHED;
2142 return OPERATOR_PASS_THROUGH;
2145 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2148 ot->name= "Animation Step";
2149 ot->idname= "SCREEN_OT_animation_step";
2152 ot->invoke= screen_animation_step;
2154 ot->poll= ED_operator_screenactive;
2158 /* ****************** anim player, starts or ends timer ***************** */
2160 /* toggle operator */
2161 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2163 bScreen *screen= CTX_wm_screen(C);
2165 if(screen->animtimer) {
2166 ED_screen_animation_timer(C, 0, 0);
2169 int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2171 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, mode);
2173 if(screen->animtimer) {
2174 wmTimer *wt= screen->animtimer;
2175 ScreenAnimData *sad= wt->customdata;
2177 sad->ar= CTX_wm_region(C);
2181 return OPERATOR_FINISHED;
2184 void SCREEN_OT_animation_play(wmOperatorType *ot)
2187 ot->name= "Animation player";
2188 ot->idname= "SCREEN_OT_animation_play";
2191 ot->invoke= screen_animation_play;
2193 ot->poll= ED_operator_screenactive;
2195 RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2198 /* ************** border select operator (template) ***************************** */
2200 /* operator state vars used: (added by default WM callbacks)
2204 customdata: the wmGesture pointer
2208 exec() has to be filled in by user
2210 invoke() default WM function
2213 modal() default WM function
2214 accept modal events while doing it, calls exec(), handles ESC and border drawing
2216 poll() has to be filled in by user for context
2219 static int border_select_do(bContext *C, wmOperator *op)
2221 int event_type= RNA_int_get(op->ptr, "event_type");
2223 if(event_type==LEFTMOUSE)
2224 printf("border select do select\n");
2225 else if(event_type==RIGHTMOUSE)
2226 printf("border select deselect\n");
2228 printf("border select do something\n");
2233 void SCREEN_OT_border_select(wmOperatorType *ot)
2236 ot->name= "Border select";
2237 ot->idname= "SCREEN_OT_border_select";
2240 ot->exec= border_select_do;
2241 ot->invoke= WM_border_select_invoke;
2242 ot->modal= WM_border_select_modal;
2244 ot->poll= ED_operator_areaactive;
2247 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2248 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2249 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2250 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2251 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2256 /* ****************************** render invoking ***************** */
2258 /* set callbacks, exported to sequence render too.
2259 Only call in foreground (UI) renders. */
2261 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2262 /* window as the last possible alternative. */
2263 static ScrArea *biggest_non_image_area(bContext *C)
2265 bScreen *sc= CTX_wm_screen(C);
2266 ScrArea *sa, *big= NULL;
2267 int size, maxsize= 0, bwmaxsize= 0;
2270 for(sa= sc->areabase.first; sa; sa= sa->next) {
2271 if(sa->winx > 30 && sa->winy > 30) {
2272 size= sa->winx*sa->winy;
2273 if(sa->spacetype == SPACE_BUTS) {
2274 if(foundwin == 0 && size > bwmaxsize) {
2279 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2290 static ScrArea *biggest_area(bContext *C)
2292 bScreen *sc= CTX_wm_screen(C);
2293 ScrArea *sa, *big= NULL;
2294 int size, maxsize= 0;
2296 for(sa= sc->areabase.first; sa; sa= sa->next) {
2297 size= sa->winx*sa->winy;
2298 if(size > maxsize) {
2307 static ScrArea *find_area_showing_r_result(bContext *C)
2309 bScreen *sc= CTX_wm_screen(C);
2313 /* find an imagewindow showing render result */
2314 for(sa=sc->areabase.first; sa; sa= sa->next) {
2315 if(sa->spacetype==SPACE_IMAGE) {
2316 sima= sa->spacedata.first;
2317 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2324 static ScrArea *find_area_image_empty(bContext *C)
2326 bScreen *sc= CTX_wm_screen(C);
2330 /* find an imagewindow showing render result */
2331 for(sa=sc->areabase.first; sa; sa= sa->next) {
2332 if(sa->spacetype==SPACE_IMAGE) {
2333 sima= sa->spacedata.first;
2341 #if 0 // XXX not used
2342 static ScrArea *find_empty_image_area(bContext *C)
2344 bScreen *sc= CTX_wm_screen(C);
2348 /* find an imagewindow showing render result */
2349 for(sa=sc->areabase.first; sa; sa= sa->next) {
2350 if(sa->spacetype==SPACE_IMAGE) {
2351 sima= sa->spacedata.first;
2358 #endif // XXX not used
2360 static void screen_set_image_output(bContext *C)
2362 Scene *scene= CTX_data_scene(C);
2366 if(scene->r.displaymode==R_OUTPUT_SCREEN) {
2367 /* this function returns with changed context */
2368 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
2373 sa= find_area_showing_r_result(C);
2375 sa= find_area_image_empty(C);
2378 /* find largest open non-image area */
2379 sa= biggest_non_image_area(C);
2381 ED_area_newspace(C, sa, SPACE_IMAGE);
2382 sima= sa->spacedata.first;
2384 /* makes ESC go back to prev space */
2385 sima->flag |= SI_PREVSPACE;
2388 /* use any area of decent size */
2389 sa= biggest_area(C);
2390 if(sa->spacetype!=SPACE_IMAGE) {
2391 // XXX newspace(sa, SPACE_IMAGE);
2392 sima= sa->spacedata.first;
2394 /* makes ESC go back to prev space */
2395 sima->flag |= SI_PREVSPACE;
2400 sima= sa->spacedata.first;
2402 /* get the correct image, and scale it */
2403 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2405 // if(G.displaymode==2) { // XXX
2407 sima->flag |= SI_FULLWINDOW|SI_PREVSPACE;
2409 // ed_screen_fullarea(C, sa);
2415 /* executes blocking render */
2416 static int screen_render_exec(bContext *C, wmOperator *op)
2418 Scene *scene= CTX_data_scene(C);
2419 Render *re= RE_GetRender(scene->id.name);
2422 re= RE_NewRender(scene->id.name);
2424 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2426 if(RNA_boolean_get(op->ptr, "anim"))
2427 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2429 RE_BlenderFrame(re, scene, scene->r.cfra);
2431 // no redraw needed, we leave state as we entered it
2432 ED_update_for_newframe(C, 1);
2434 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2436 return OPERATOR_FINISHED;
2439 typedef struct RenderJob {
2450 static void render_freejob(void *rjv)
2457 /* str is IMA_RW_MAXTEXT in size */
2458 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
2460 char info_time_str[32]; // used to be extern to header_info.c
2461 uintptr_t mem_in_use, mmap_in_use;
2462 float megs_used_memory, mmap_used_memory;
2465 mem_in_use= MEM_get_memory_in_use();
2466 mmap_in_use= MEM_get_mapped_memory_in_use();
2468 megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
2469 mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
2471 if(scene->lay & 0xFF000000)
2472 spos+= sprintf(spos, "Localview | ");
2473 else if(scene->r.scemode & R_SINGLE_LAYER)
2474 spos+= sprintf(spos, "Single Layer | ");
2476 spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
2477 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
2478 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
2479 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
2482 spos+= sprintf(spos, "Field %d ", rs->curfield);
2484 spos+= sprintf(spos, "Blur %d ", rs->curblur);
2486 BLI_timestr(rs->lastframetime, info_time_str);
2487 spos+= sprintf(spos, "Time:%s ", info_time_str);
2490 spos+= sprintf(spos, "| %s ", rs->infostr);
2492 /* very weak... but 512 characters is quite safe */
2493 if(spos >= str+IMA_RW_MAXTEXT)
2494 printf("WARNING! renderwin text beyond limit \n");
2498 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
2502 /* malloc OK here, stats_draw is not in tile threads */
2503 if(rj->image->render_text==NULL)
2504 rj->image->render_text= MEM_callocN(IMA_RW_MAXTEXT, "rendertext");
2506 make_renderinfo_string(rs, rj->scene, rj->image->render_text);
2508 /* make jobs timer to send notifier */
2509 *(rj->do_update)= 1;
2513 /* called inside thread! */
2514 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2518 float x1, y1, *rectf= NULL;
2519 int ymin, ymax, xmin, xmax;
2523 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2524 if(ibuf==NULL) return;
2526 /* if renrect argument, we only refresh scanlines */
2528 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2529 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2532 /* xmin here is first subrect x coord, xmax defines subrect width */
2533 xmin = renrect->xmin + rr->crop;
2534 xmax = renrect->xmax - xmin - rr->crop;
2537 ymin= renrect->ymin + rr->crop;
2538 ymax= renrect->ymax - ymin - rr->crop;
2541 renrect->ymin= renrect->ymax;
2545 xmin = ymin = rr->crop;
2546 xmax = rr->rectx - 2*rr->crop;
2547 ymax = rr->recty - 2*rr->crop;
2550 /* xmin ymin is in tile coords. transform to ibuf */
2551 rxmin= rr->tilerect.xmin + xmin;
2552 if(rxmin >= ibuf->x) return;
2553 rymin= rr->tilerect.ymin + ymin;
2554 if(rymin >= ibuf->y) return;
2556 if(rxmin + xmax > ibuf->x)
2557 xmax= ibuf->x - rxmin;
2558 if(rymin + ymax > ibuf->y)
2559 ymax= ibuf->y - rymin;
2561 if(xmax < 1 || ymax < 1) return;
2563 /* find current float rect for display, first case is after composit... still weak */
2570 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2571 rectf= rr->renlay->rectf;
2574 if(rectf==NULL) return;
2576 rectf+= 4*(rr->rectx*ymin + xmin);
2577 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2579 /* XXX make nice consistent functions for this */
2580 if (rj->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
2581 for(y1= 0; y1<ymax; y1++) {
2586 /* XXX temp. because crop offset */
2587 if( rectc >= (char *)(ibuf->rect)) {
2588 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2589 srgb[0]= linearrgb_to_srgb(rf[0]);
2590 srgb[1]= linearrgb_to_srgb(rf[1]);
2591 srgb[2]= linearrgb_to_srgb(rf[2]);
2593 rc[0]= FTOCHAR(srgb[0]);
2594 rc[1]= FTOCHAR(srgb[1]);
2595 rc[2]= FTOCHAR(srgb[2]);
2596 rc[3]= FTOCHAR(rf[3]);
2599 rectf += 4*rr->rectx;
2603 for(y1= 0; y1<ymax; y1++) {
2607 /* XXX temp. because crop offset */
2608 if( rectc >= (char *)(ibuf->rect)) {
2609 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2610 rc[0]= FTOCHAR(rf[0]);
2611 rc[1]= FTOCHAR(rf[1]);
2612 rc[2]= FTOCHAR(rf[2]);
2613 rc[3]= FTOCHAR(rf[3]);
2616 rectf += 4*rr->rectx;
2621 /* make jobs timer to send notifier */
2622 *(rj->do_update)= 1;
2625 static void render_startjob(void *rjv, short *stop, short *do_update)
2630 rj->do_update= do_update;
2633 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2635 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2638 /* called by render, check job 'stop' value or the global */
2639 static int render_breakjob(void *rjv)
2645 if(rj->stop && *(rj->stop))
2651 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2653 /* no running blender, remove handler and pass through */
2654 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2655 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2657 /* running render */
2658 switch (event->type) {
2660 return OPERATOR_RUNNING_MODAL;
2663 return OPERATOR_PASS_THROUGH;
2666 /* using context, starts job */
2667 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2669 /* new render clears all callbacks */
2670 Scene *scene= CTX_data_scene(C);
2676 /* only one job at a time */
2677 if(WM_jobs_test(CTX_wm_manager(C), scene))
2678 return OPERATOR_CANCELLED;
2680 /* handle UI stuff */
2683 /* flush multires changes (for sculpt) */
2684 multires_force_update(CTX_data_active_object(C));
2686 /* get editmode results */
2687 ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */
2690 // get view3d layer, local layer, make this nice api call to render
2693 /* ensure at least 1 area shows result */
2694 screen_set_image_output(C);
2696 /* job custom data */
2697 rj= MEM_callocN(sizeof(RenderJob), "render job");
2699 rj->win= CTX_wm_window(C);
2700 rj->anim= RNA_boolean_get(op->ptr, "anim");
2701 rj->iuser.scene= scene;
2705 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2706 WM_jobs_customdata(steve, rj, render_freejob);
2707 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2708 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2710 /* get a render result image, and make sure it is empty */
2711 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2712 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2715 /* setup new render */
2716 re= RE_NewRender(scene->id.name);
2717 RE_test_break_cb(re, rj, render_breakjob);
2718 RE_display_draw_cb(re, rj, image_rect_update);
2719 RE_stats_draw_cb(re, rj, image_renderinfo_cb);
2724 // BKE_report in render!
2725 // RE_error_cb(re, error_cb);
2727 WM_jobs_start(CTX_wm_manager(C), steve);
2732 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2734 /* add modal handler for ESC */
2735 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2737 return OPERATOR_RUNNING_MODAL;
2741 /* contextual render, using current scene, view3d? */
2742 void SCREEN_OT_render(wmOperatorType *ot)
2746 ot->idname= "SCREEN_OT_render";
2749 ot->invoke= screen_render_invoke;
2750 ot->modal= screen_render_modal;
2751 ot->exec= screen_render_exec;
2753 ot->poll= ED_operator_screenactive;
2755 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2756 RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2759 /* *********************** cancel render viewer *************** */
2761 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2763 ScrArea *sa= CTX_wm_area(C);
2764 SpaceImage *sima= sa->spacedata.first;
2766 if(sima->flag & SI_PREVSPACE) {
2767 sima->flag &= ~SI_PREVSPACE;
2769 if(sima->flag & SI_FULLWINDOW) {
2770 sima->flag &= ~SI_FULLWINDOW;
2771 ED_screen_full_prevspace(C);
2774 ED_area_prevspace(C);
2776 else if(sima->flag & SI_FULLWINDOW) {
2777 sima->flag &= ~SI_FULLWINDOW;
2778 ed_screen_fullarea(C, sa);
2781 return OPERATOR_FINISHED;
2784 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2787 ot->name= "Cancel Render View";
2788 ot->idname= "SCREEN_OT_render_view_cancel";
2791 ot->exec= render_view_cancel_exec;
2792 ot->poll= ED_operator_image_active;
2795 /* *********************** show render viewer *************** */
2797 static int render_view_show_exec(bContext *C, wmOperator *unused)
2799 ScrArea *sa= find_area_showing_r_result(C);
2801 /* determine if render already shows */
2803 SpaceImage *sima= sa->spacedata.first;
2805 if(sima->flag & SI_PREVSPACE) {
2806 sima->flag &= ~SI_PREVSPACE;
2808 if(sima->flag & SI_FULLWINDOW) {
2809 sima->flag &= ~SI_FULLWINDOW;
2810 ED_screen_full_prevspace(C);
2812 else if(sima->next) {
2813 ED_area_newspace(C, sa, sima->next->spacetype);
2814 ED_area_tag_redraw(sa);
2819 screen_set_image_output(C);
2822 return OPERATOR_FINISHED;
2825 void SCREEN_OT_render_view_show(struct wmOperatorType *ot)
2828 ot->name= "Show/Hide Render View";
2829 ot->idname= "SCREEN_OT_render_view_show";
2832 ot->exec= render_view_show_exec;
2833 ot->poll= ED_operator_screenactive;
2838 /* **************** Assigning operatortypes to global list, adding handlers **************** */
2840 /* called in spacetypes.c */
2841 void ED_operatortypes_screen(void)
2843 /* generic UI stuff */
2844 WM_operatortype_append(SCREEN_OT_actionzone);
2845 WM_operatortype_append(SCREEN_OT_repeat_last);
2846 WM_operatortype_append(SCREEN_OT_repeat_history);
2847 WM_operatortype_append(SCREEN_OT_redo_last);
2850 WM_operatortype_append(SCREEN_OT_area_move);
2851 WM_operatortype_append(SCREEN_OT_area_split);
2852 WM_operatortype_append(SCREEN_OT_area_join);
2853 WM_operatortype_append(SCREEN_OT_area_dupli);
2854 WM_operatortype_append(SCREEN_OT_area_swap);
2855 WM_operatortype_append(SCREEN_OT_region_split);
2856 WM_operatortype_append(SCREEN_OT_region_foursplit);
2857 WM_operatortype_append(SCREEN_OT_region_flip);
2858 WM_operatortype_append(SCREEN_OT_region_scale);
2859 WM_operatortype_append(SCREEN_OT_screen_set);
2860 WM_operatortype_append(SCREEN_OT_screen_full_area);
2861 WM_operatortype_append(SCREEN_OT_screenshot);
2862 WM_operatortype_append(SCREEN_OT_screencast);
2865 WM_operatortype_append(SCREEN_OT_frame_offset);
2866 WM_operatortype_append(SCREEN_OT_animation_step);
2867 WM_operatortype_append(SCREEN_OT_animation_play);
2870 WM_operatortype_append(SCREEN_OT_render);
2871 WM_operatortype_append(SCREEN_OT_render_view_cancel);
2872 WM_operatortype_append(SCREEN_OT_render_view_show);
2874 /* tools shared by more space types */
2875 WM_operatortype_append(ED_OT_undo);
2876 WM_operatortype_append(ED_OT_redo);
2880 /* called in spacetypes.c */
2881 void ED_keymap_screen(wmWindowManager *wm)
2885 /* Screen General ------------------------------------------------ */
2886 keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2888 /* standard timers */
2889 WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
2891 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2892 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2893 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2896 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2897 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2898 WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2899 WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
2900 WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2901 /* area move after action zones */
2902 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2904 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2905 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2906 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2907 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2908 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2909 WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2910 WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2913 WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2914 WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2916 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2917 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2918 WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2919 WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2921 RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
2922 WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
2925 WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2926 WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2929 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2930 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2931 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2932 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2935 WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2936 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2937 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_show", F11KEY, KM_PRESS, 0, 0);
2939 /* Anim Playback ------------------------------------------------ */
2940 keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2943 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2944 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2945 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2946 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
2948 /* play (forward and backwards) */
2949 WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
2950 RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1);