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_context.h"
45 #include "BKE_customdata.h"
46 #include "BKE_global.h"
47 #include "BKE_image.h"
48 #include "BKE_idprop.h"
49 #include "BKE_library.h"
52 #include "BKE_multires.h"
53 #include "BKE_report.h"
54 #include "BKE_screen.h"
55 #include "BKE_utildefines.h"
61 #include "ED_screen.h"
63 #include "ED_object.h"
64 #include "ED_screen_types.h"
66 #include "RE_pipeline.h"
67 #include "IMB_imbuf.h"
68 #include "IMB_imbuf_types.h"
70 #include "RNA_access.h"
71 #include "RNA_define.h"
73 #include "UI_interface.h"
74 #include "UI_resources.h"
76 #include "screen_intern.h" /* own module include */
78 /* ************** Exported Poll tests ********************** */
80 int ED_operator_regionactive(bContext *C)
82 if(CTX_wm_window(C)==NULL) return 0;
83 if(CTX_wm_screen(C)==NULL) return 0;
84 if(CTX_wm_region(C)==NULL) return 0;
88 int ED_operator_areaactive(bContext *C)
90 if(CTX_wm_window(C)==NULL) return 0;
91 if(CTX_wm_screen(C)==NULL) return 0;
92 if(CTX_wm_area(C)==NULL) return 0;
96 int ED_operator_screenactive(bContext *C)
98 if(CTX_wm_window(C)==NULL) return 0;
99 if(CTX_wm_screen(C)==NULL) return 0;
103 /* when mouse is over area-edge */
104 int ED_operator_screen_mainwinactive(bContext *C)
106 if(CTX_wm_window(C)==NULL) return 0;
107 if(CTX_wm_screen(C)==NULL) return 0;
108 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
112 int ED_operator_scene_editable(bContext *C)
114 Scene *scene= CTX_data_scene(C);
115 if(scene && scene->id.lib==NULL)
120 static int ed_spacetype_test(bContext *C, int type)
122 if(ED_operator_areaactive(C)) {
123 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
124 return sl && (sl->spacetype == type);
129 int ED_operator_view3d_active(bContext *C)
131 return ed_spacetype_test(C, SPACE_VIEW3D);
134 int ED_operator_timeline_active(bContext *C)
136 return ed_spacetype_test(C, SPACE_TIME);
139 int ED_operator_outliner_active(bContext *C)
141 return ed_spacetype_test(C, SPACE_OUTLINER);
144 int ED_operator_file_active(bContext *C)
146 return ed_spacetype_test(C, SPACE_FILE);
149 int ED_operator_action_active(bContext *C)
151 return ed_spacetype_test(C, SPACE_ACTION);
154 int ED_operator_buttons_active(bContext *C)
156 return ed_spacetype_test(C, SPACE_BUTS);
159 int ED_operator_node_active(bContext *C)
161 if(ed_spacetype_test(C, SPACE_NODE)) {
162 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
170 int ED_operator_ipo_active(bContext *C)
172 return ed_spacetype_test(C, SPACE_IPO);
175 int ED_operator_sequencer_active(bContext *C)
177 return ed_spacetype_test(C, SPACE_SEQ);
180 int ED_operator_image_active(bContext *C)
182 return ed_spacetype_test(C, SPACE_IMAGE);
185 int ED_operator_nla_active(bContext *C)
187 return ed_spacetype_test(C, SPACE_NLA);
190 int ED_operator_logic_active(bContext *C)
192 return ed_spacetype_test(C, SPACE_LOGIC);
195 int ED_operator_object_active(bContext *C)
197 return NULL != CTX_data_active_object(C);
200 int ED_operator_editmesh(bContext *C)
202 Object *obedit= CTX_data_edit_object(C);
203 if(obedit && obedit->type==OB_MESH)
204 return NULL != ((Mesh *)obedit->data)->edit_mesh;
208 int ED_operator_editarmature(bContext *C)
210 Object *obedit= CTX_data_edit_object(C);
211 if(obedit && obedit->type==OB_ARMATURE)
212 return NULL != ((bArmature *)obedit->data)->edbo;
216 int ED_operator_posemode(bContext *C)
218 Object *obact= CTX_data_active_object(C);
219 Object *obedit= CTX_data_edit_object(C);
221 if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
222 return (obact->flag & OB_POSEMODE)!=0;
228 int ED_operator_uvedit(bContext *C)
230 Object *obedit= CTX_data_edit_object(C);
233 if(obedit && obedit->type==OB_MESH)
234 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
236 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
237 BKE_mesh_end_editmesh(obedit->data, em);
242 BKE_mesh_end_editmesh(obedit->data, em);
246 int ED_operator_uvmap(bContext *C)
248 Object *obedit= CTX_data_edit_object(C);
251 if(obedit && obedit->type==OB_MESH)
252 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
254 if(em && (em->faces.first)) {
255 BKE_mesh_end_editmesh(obedit->data, em);
260 BKE_mesh_end_editmesh(obedit->data, em);
264 int ED_operator_editsurfcurve(bContext *C)
266 Object *obedit= CTX_data_edit_object(C);
267 if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
268 return NULL != ((Curve *)obedit->data)->editnurb;
273 int ED_operator_editcurve(bContext *C)
275 Object *obedit= CTX_data_edit_object(C);
276 if(obedit && obedit->type==OB_CURVE)
277 return NULL != ((Curve *)obedit->data)->editnurb;
281 int ED_operator_editsurf(bContext *C)
283 Object *obedit= CTX_data_edit_object(C);
284 if(obedit && obedit->type==OB_SURF)
285 return NULL != ((Curve *)obedit->data)->editnurb;
289 int ED_operator_editfont(bContext *C)
291 Object *obedit= CTX_data_edit_object(C);
292 if(obedit && obedit->type==OB_FONT)
293 return NULL != ((Curve *)obedit->data)->editfont;
297 int ED_operator_editlattice(bContext *C)
299 Object *obedit= CTX_data_edit_object(C);
300 if(obedit && obedit->type==OB_LATTICE)
301 return NULL != ((Lattice *)obedit->data)->editlatt;
305 /* *************************** action zone operator ************************** */
307 /* operator state vars used:
312 apply() set actionzone event
314 exit() free customdata
320 invoke() check if in zone
321 add customdata, put mouseco and area in it
324 modal() accept modal events while doing it
325 call apply() with gesture info, active window, nonactive window
326 call exit() and remove handler when LMB confirm
330 typedef struct sActionzoneData {
333 int x, y, gesture_dir, modifier;
336 /* used by other operators too */
337 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
340 sa= scr->areabase.first;
342 if(BLI_in_rcti(&sa->totrct, x, y)) break;
349 /* quick poll to save operators to be created and handled */
350 static int actionzone_area_poll(bContext *C)
352 wmWindow *win= CTX_wm_window(C);
353 ScrArea *sa= CTX_wm_area(C);
357 int x= win->eventstate->x;
358 int y= win->eventstate->y;
360 for(az= sa->actionzones.first; az; az= az->next)
361 if(BLI_in_rcti(&az->rect, x, y))
367 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
371 for(az= sa->actionzones.first; az; az= az->next) {
372 if(BLI_in_rcti(&az->rect, x, y)) {
373 if(az->type == AZONE_AREA) {
374 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
377 else if(az->type == AZONE_REGION) {
378 float v1[2], v2[2], v3[2], pt[2];
380 v1[0]= az->x1; v1[1]= az->y1;
381 v2[0]= az->x2; v2[1]= az->y2;
382 v3[0]= az->x3; v3[1]= az->y3;
385 if(IsPointInTri2D(v1, v2, v3, pt))
395 static void actionzone_exit(bContext *C, wmOperator *op)
398 MEM_freeN(op->customdata);
399 op->customdata= NULL;
402 /* send EVT_ACTIONZONE event */
403 static void actionzone_apply(bContext *C, wmOperator *op, int type)
406 wmWindow *win= CTX_wm_window(C);
407 sActionzoneData *sad= op->customdata;
409 sad->modifier= RNA_int_get(op->ptr, "modifier");
411 event= *(win->eventstate); /* XXX huh huh? make api call */
413 event.type= EVT_ACTIONZONE_AREA;
415 event.type= EVT_ACTIONZONE_REGION;
416 event.customdata= op->customdata;
417 event.customdatafree= TRUE;
418 op->customdata= NULL;
420 wm_event_add(win, &event);
423 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
425 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
426 sActionzoneData *sad;
430 return OPERATOR_PASS_THROUGH;
432 /* ok we do the actionzone */
433 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
434 sad->sa1= CTX_wm_area(C);
436 sad->x= event->x; sad->y= event->y;
438 /* region azone directly reacts on mouse clicks */
439 if(sad->az->type==AZONE_REGION) {
440 actionzone_apply(C, op, AZONE_REGION);
441 actionzone_exit(C, op);
442 return OPERATOR_FINISHED;
445 /* add modal handler */
446 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
448 return OPERATOR_RUNNING_MODAL;
453 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
455 sActionzoneData *sad= op->customdata;
457 int mindelta= sad->az->type==AZONE_REGION?1:12;
459 switch(event->type) {
461 /* calculate gesture direction */
462 deltax= (event->x - sad->x);
463 deltay= (event->y - sad->y);
465 if(deltay > ABS(deltax))
466 sad->gesture_dir= 'n';
467 else if(deltax > ABS(deltay))
468 sad->gesture_dir= 'e';
469 else if(deltay < -ABS(deltax))
470 sad->gesture_dir= 's';
472 sad->gesture_dir= 'w';
474 /* gesture is large enough? */
475 if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
477 /* second area, for join */
478 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
479 /* apply sends event */
480 actionzone_apply(C, op, sad->az->type);
481 actionzone_exit(C, op);
483 return OPERATOR_FINISHED;
487 actionzone_exit(C, op);
488 return OPERATOR_CANCELLED;
490 actionzone_exit(C, op);
491 return OPERATOR_CANCELLED;
495 return OPERATOR_RUNNING_MODAL;
498 void SCREEN_OT_actionzone(wmOperatorType *ot)
501 ot->name= "Handle area action zones";
502 ot->idname= "SCREEN_OT_actionzone";
504 ot->invoke= actionzone_invoke;
505 ot->modal= actionzone_modal;
506 ot->poll= actionzone_area_poll;
508 ot->flag= OPTYPE_BLOCKING;
510 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
513 /* ************** swap area operator *********************************** */
515 /* operator state vars used:
517 sa2 area to swap with
521 init() set custom data for operator, based on actionzone event custom data
523 cancel() cancel the operator
525 exit() cleanup, send notifier
529 invoke() gets called on shift+lmb drag in actionzone
530 call init(), add handler
532 modal() accept modal events while doing it
536 typedef struct sAreaSwapData {
540 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
542 sAreaSwapData *sd= NULL;
543 sActionzoneData *sad= event->customdata;
545 if(sad==NULL || sad->sa1==NULL)
548 sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
557 static void area_swap_exit(bContext *C, wmOperator *op)
560 MEM_freeN(op->customdata);
561 op->customdata= NULL;
564 static int area_swap_cancel(bContext *C, wmOperator *op)
566 area_swap_exit(C, op);
567 return OPERATOR_CANCELLED;
570 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
573 if(!area_swap_init(C, op, event))
574 return OPERATOR_PASS_THROUGH;
576 /* add modal handler */
577 WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
578 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
580 return OPERATOR_RUNNING_MODAL;
584 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
586 sActionzoneData *sad= op->customdata;
588 switch(event->type) {
590 /* second area, for join */
591 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
593 case LEFTMOUSE: /* release LMB */
595 if(sad->sa1 == sad->sa2) {
597 return area_swap_cancel(C, op);
599 ED_area_swapspace(C, sad->sa1, sad->sa2);
601 area_swap_exit(C, op);
603 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
605 return OPERATOR_FINISHED;
610 return area_swap_cancel(C, op);
612 return OPERATOR_RUNNING_MODAL;
615 static void SCREEN_OT_area_swap(wmOperatorType *ot)
617 ot->name= "Swap areas";
618 ot->idname= "SCREEN_OT_area_swap";
620 ot->invoke= area_swap_invoke;
621 ot->modal= area_swap_modal;
622 ot->poll= ED_operator_areaactive;
624 ot->flag= OPTYPE_BLOCKING;
627 /* *********** Duplicate area as new window operator ****************** */
629 /* operator callback */
630 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
632 wmWindow *newwin, *win;
637 win= CTX_wm_window(C);
638 sc= CTX_wm_screen(C);
642 if(event->type==EVT_ACTIONZONE_AREA) {
643 sActionzoneData *sad= event->customdata;
646 return OPERATOR_PASS_THROUGH;
651 /* poll() checks area context, but we don't accept full-area windows */
652 if(sc->full != SCREENNORMAL) {
653 if(event->type==EVT_ACTIONZONE_AREA)
654 actionzone_exit(C, op);
655 return OPERATOR_CANCELLED;
658 /* adds window to WM */
660 BLI_translate_rcti(&rect, win->posx, win->posy);
661 newwin= WM_window_open(C, &rect);
663 /* allocs new screen and adds to newly created window, using window size */
664 newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
665 newwin->screen= newsc;
667 /* copy area to new screen */
668 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
670 /* screen, areas init */
671 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
673 if(event->type==EVT_ACTIONZONE_AREA)
674 actionzone_exit(C, op);
676 return OPERATOR_FINISHED;
679 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
681 ot->name= "Duplicate Area into New Window";
682 ot->idname= "SCREEN_OT_area_dupli";
684 ot->invoke= area_dupli_invoke;
685 ot->poll= ED_operator_areaactive;
689 /* ************** move area edge operator *********************************** */
691 /* operator state vars used:
692 x, y mouse coord near edge
693 delta movement of edge
697 init() set default property values, find edge based on mouse coords, test
698 if the edge can be moved, select edges, calculate min and max movement
700 apply() apply delta on selection
702 exit() cleanup, send notifier
704 cancel() cancel moving
708 exec() execute without any user interaction, based on properties
709 call init(), apply(), exit()
711 invoke() gets called on mouse click near edge
712 call init(), add handler
714 modal() accept modal events while doing it
715 call apply() with delta motion
716 call exit() and remove handler
720 typedef struct sAreaMoveData {
721 int bigger, smaller, origval;
725 /* helper call to move area-edge, sets limits */
726 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
730 /* we check all areas and test for free space with MINSIZE */
731 *bigger= *smaller= 100000;
733 for(sa= sc->areabase.first; sa; sa= sa->next) {
735 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
737 /* if top or down edge selected, test height */
738 if(sa->v1->flag && sa->v4->flag)
739 *bigger= MIN2(*bigger, y1);
740 else if(sa->v2->flag && sa->v3->flag)
741 *smaller= MIN2(*smaller, y1);
744 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
746 /* if left or right edge selected, test width */
747 if(sa->v1->flag && sa->v2->flag)
748 *bigger= MIN2(*bigger, x1);
749 else if(sa->v3->flag && sa->v4->flag)
750 *smaller= MIN2(*smaller, x1);
755 /* validate selection inside screen, set variables OK */
756 /* return 0: init failed */
757 static int area_move_init (bContext *C, wmOperator *op)
759 bScreen *sc= CTX_wm_screen(C);
764 /* required properties */
765 x= RNA_int_get(op->ptr, "x");
766 y= RNA_int_get(op->ptr, "y");
769 actedge= screen_find_active_scredge(sc, x, y);
770 if(actedge==NULL) return 0;
772 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
775 md->dir= scredge_is_horizontal(actedge)?'h':'v';
776 if(md->dir=='h') md->origval= actedge->v1->vec.y;
777 else md->origval= actedge->v1->vec.x;
779 select_connected_scredge(sc, actedge);
780 /* now all vertices with 'flag==1' are the ones that can be moved. */
782 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
787 /* moves selected screen edge amount of delta, used by split & move */
788 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
790 wmWindow *win= CTX_wm_window(C);
791 bScreen *sc= CTX_wm_screen(C);
794 delta= CLAMPIS(delta, -smaller, bigger);
796 for (v1= sc->vertbase.first; v1; v1= v1->next) {
798 /* that way a nice AREAGRID */
799 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
800 v1->vec.x= origval + delta;
801 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
803 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
804 v1->vec.y= origval + delta;
806 v1->vec.y+= AREAGRID-1;
807 v1->vec.y-= (v1->vec.y % AREAGRID);
809 /* prevent too small top header */
810 if(v1->vec.y > win->sizey-AREAMINY)
811 v1->vec.y= win->sizey-AREAMINY;
816 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
819 static void area_move_apply(bContext *C, wmOperator *op)
821 sAreaMoveData *md= op->customdata;
824 delta= RNA_int_get(op->ptr, "delta");
825 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
828 static void area_move_exit(bContext *C, wmOperator *op)
831 MEM_freeN(op->customdata);
832 op->customdata= NULL;
834 /* this makes sure aligned edges will result in aligned grabbing */
835 removedouble_scrverts(CTX_wm_screen(C));
836 removedouble_scredges(CTX_wm_screen(C));
839 static int area_move_exec(bContext *C, wmOperator *op)
841 if(!area_move_init(C, op))
842 return OPERATOR_CANCELLED;
844 area_move_apply(C, op);
845 area_move_exit(C, op);
847 return OPERATOR_FINISHED;
850 /* interaction callback */
851 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
853 RNA_int_set(op->ptr, "x", event->x);
854 RNA_int_set(op->ptr, "y", event->y);
856 if(!area_move_init(C, op))
857 return OPERATOR_PASS_THROUGH;
859 /* add temp handler */
860 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
862 return OPERATOR_RUNNING_MODAL;
865 static int area_move_cancel(bContext *C, wmOperator *op)
868 RNA_int_set(op->ptr, "delta", 0);
869 area_move_apply(C, op);
870 area_move_exit(C, op);
872 return OPERATOR_CANCELLED;
875 /* modal callback for while moving edges */
876 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
883 x= RNA_int_get(op->ptr, "x");
884 y= RNA_int_get(op->ptr, "y");
886 /* execute the events */
887 switch(event->type) {
889 delta= (md->dir == 'v')? event->x - x: event->y - y;
890 RNA_int_set(op->ptr, "delta", delta);
892 area_move_apply(C, op);
897 area_move_exit(C, op);
898 return OPERATOR_FINISHED;
903 return area_move_cancel(C, op);
906 return OPERATOR_RUNNING_MODAL;
909 void SCREEN_OT_area_move(wmOperatorType *ot)
912 ot->name= "Move area edges";
913 ot->idname= "SCREEN_OT_area_move";
915 ot->exec= area_move_exec;
916 ot->invoke= area_move_invoke;
917 ot->cancel= area_move_cancel;
918 ot->modal= area_move_modal;
919 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
921 ot->flag= OPTYPE_BLOCKING;
924 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
925 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
926 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
929 /* ************** split area operator *********************************** */
934 dir direction 'v' or 'h'
937 area pointer to (active) area
938 x, y last used mouse pos
943 init() set default property values, find area based on context
945 apply() split area based on state vars
947 exit() cleanup, send notifier
949 cancel() remove duplicated area
953 exec() execute without any user interaction, based on state vars
954 call init(), apply(), exit()
956 invoke() gets called on mouse click in action-widget
957 call init(), add modal handler
958 call apply() with initial motion
960 modal() accept modal events while doing it
961 call move-areas code with delta motion
962 call exit() or cancel() and remove handler
966 #define SPLIT_STARTED 1
967 #define SPLIT_PROGRESS 2
969 typedef struct sAreaSplitData
971 int x, y; /* last used mouse position */
973 int origval; /* for move areas */
974 int bigger, smaller; /* constraints for moving new edge */
975 int delta; /* delta move edge */
976 int origmin, origsize; /* to calculate fac, for property storage */
978 ScrEdge *nedge; /* new edge */
979 ScrArea *sarea; /* start area */
980 ScrArea *narea; /* new area */
983 /* generic init, no UI stuff here */
984 static int area_split_init(bContext *C, wmOperator *op)
986 ScrArea *sa= CTX_wm_area(C);
990 /* required context */
991 if(sa==NULL) return 0;
993 /* required properties */
994 dir= RNA_enum_get(op->ptr, "direction");
997 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
998 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
1001 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1005 sd->origsize= dir=='v' ? sa->winx:sa->winy;
1006 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1011 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1012 /* used with split operator */
1013 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1015 ScrVert *sav1= sa->v1;
1016 ScrVert *sav2= sa->v2;
1017 ScrVert *sav3= sa->v3;
1018 ScrVert *sav4= sa->v4;
1019 ScrVert *sbv1= sb->v1;
1020 ScrVert *sbv2= sb->v2;
1021 ScrVert *sbv3= sb->v3;
1022 ScrVert *sbv4= sb->v4;
1024 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1025 return screen_findedge(screen, sav1, sav2);
1027 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1028 return screen_findedge(screen, sav2, sav3);
1030 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1031 return screen_findedge(screen, sav3, sav4);
1033 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1034 return screen_findedge(screen, sav1, sav4);
1041 /* do the split, return success */
1042 static int area_split_apply(bContext *C, wmOperator *op)
1044 bScreen *sc= CTX_wm_screen(C);
1045 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1049 fac= RNA_float_get(op->ptr, "factor");
1050 dir= RNA_enum_get(op->ptr, "direction");
1052 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1057 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1059 /* select newly created edge, prepare for moving edge */
1060 for(sv= sc->vertbase.first; sv; sv= sv->next)
1063 sd->nedge->v1->flag= 1;
1064 sd->nedge->v2->flag= 1;
1066 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1067 else sd->origval= sd->nedge->v1->vec.x;
1069 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1077 static void area_split_exit(bContext *C, wmOperator *op)
1079 if (op->customdata) {
1080 MEM_freeN(op->customdata);
1081 op->customdata = NULL;
1084 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1086 /* this makes sure aligned edges will result in aligned grabbing */
1087 removedouble_scrverts(CTX_wm_screen(C));
1088 removedouble_scredges(CTX_wm_screen(C));
1092 /* UI callback, adds new handler */
1093 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1097 if(event->type==EVT_ACTIONZONE_AREA) {
1098 sActionzoneData *sad= event->customdata;
1101 if(sad->modifier>0) {
1102 return OPERATOR_PASS_THROUGH;
1105 /* no full window splitting allowed */
1106 if(CTX_wm_area(C)->full)
1107 return OPERATOR_PASS_THROUGH;
1109 /* verify *sad itself */
1110 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1111 return OPERATOR_PASS_THROUGH;
1113 /* is this our *sad? if areas not equal it should be passed on */
1114 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1115 return OPERATOR_PASS_THROUGH;
1117 /* prepare operator state vars */
1118 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1120 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1124 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1126 RNA_enum_set(op->ptr, "direction", dir);
1128 /* general init, also non-UI case, adds customdata, sets area and defaults */
1129 if(!area_split_init(C, op))
1130 return OPERATOR_PASS_THROUGH;
1132 sd= (sAreaSplitData *)op->customdata;
1138 if(area_split_apply(C, op)) {
1139 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1141 /* add temp handler for edge move or cancel */
1142 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1144 return OPERATOR_RUNNING_MODAL;
1149 /* nonmodal for now */
1150 return op->type->exec(C, op);
1153 return OPERATOR_PASS_THROUGH;
1156 /* function to be called outside UI context, or for redo */
1157 static int area_split_exec(bContext *C, wmOperator *op)
1160 if(!area_split_init(C, op))
1161 return OPERATOR_CANCELLED;
1163 area_split_apply(C, op);
1164 area_split_exit(C, op);
1166 return OPERATOR_FINISHED;
1170 static int area_split_cancel(bContext *C, wmOperator *op)
1172 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1174 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1175 if (CTX_wm_area(C) == sd->narea) {
1176 CTX_wm_area_set(C, NULL);
1177 CTX_wm_region_set(C, NULL);
1181 area_split_exit(C, op);
1183 return OPERATOR_CANCELLED;
1186 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1188 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1192 /* execute the events */
1193 switch(event->type) {
1195 dir= RNA_enum_get(op->ptr, "direction");
1197 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1198 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1200 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1201 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1203 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1207 if(event->val==0) { /* mouse up */
1208 area_split_exit(C, op);
1209 return OPERATOR_FINISHED;
1212 case RIGHTMOUSE: /* cancel operation */
1214 return area_split_cancel(C, op);
1217 return OPERATOR_RUNNING_MODAL;
1220 static EnumPropertyItem prop_direction_items[] = {
1221 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1222 {'v', "VERTICAL", 0, "Vertical", ""},
1223 {0, NULL, 0, NULL, NULL}};
1225 void SCREEN_OT_area_split(wmOperatorType *ot)
1227 ot->name = "Split area";
1228 ot->idname = "SCREEN_OT_area_split";
1230 ot->exec= area_split_exec;
1231 ot->invoke= area_split_invoke;
1232 ot->modal= area_split_modal;
1234 ot->poll= ED_operator_areaactive;
1235 ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
1238 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1239 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1244 /* ************** scale region edge operator *********************************** */
1246 typedef struct RegionMoveData {
1248 int bigger, smaller, origval;
1254 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1256 sActionzoneData *sad= event->customdata;
1260 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1262 op->customdata= rmd;
1265 rmd->edge= az->edge;
1266 rmd->origx= event->x;
1267 rmd->origy= event->y;
1268 if(rmd->edge=='l' || rmd->edge=='r')
1269 rmd->origval= rmd->ar->type->minsizex;
1271 rmd->origval= rmd->ar->type->minsizey;
1273 /* add temp handler */
1274 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1276 return OPERATOR_RUNNING_MODAL;
1279 return OPERATOR_FINISHED;
1282 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1284 RegionMoveData *rmd= op->customdata;
1287 /* execute the events */
1288 switch(event->type) {
1291 if(rmd->edge=='l' || rmd->edge=='r') {
1292 delta= event->x - rmd->origx;
1293 if(rmd->edge=='l') delta= -delta;
1294 rmd->ar->type->minsizex= rmd->origval + delta;
1295 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1296 if(rmd->ar->type->minsizex < 10) {
1297 rmd->ar->type->minsizex= 10;
1298 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1301 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1304 delta= event->y - rmd->origy;
1305 if(rmd->edge=='b') delta= -delta;
1306 rmd->ar->type->minsizey= rmd->origval + delta;
1307 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1308 if(rmd->ar->type->minsizey < 10) {
1309 rmd->ar->type->minsizey= 10;
1310 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1313 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1316 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1323 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1324 rmd->ar->flag ^= RGN_FLAG_HIDDEN;
1325 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1327 MEM_freeN(op->customdata);
1328 op->customdata = NULL;
1330 return OPERATOR_FINISHED;
1338 return OPERATOR_RUNNING_MODAL;
1342 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1345 ot->name= "Scale Region Size";
1346 ot->idname= "SCREEN_OT_region_scale";
1348 ot->invoke= region_scale_invoke;
1349 ot->modal= region_scale_modal;
1351 ot->poll= ED_operator_areaactive;
1353 ot->flag= OPTYPE_BLOCKING;
1357 /* ************** frame change operator ***************************** */
1360 /* function to be called outside UI context, or for redo */
1361 static int frame_offset_exec(bContext *C, wmOperator *op)
1365 delta = RNA_int_get(op->ptr, "delta");
1367 CTX_data_scene(C)->r.cfra += delta;
1369 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1371 return OPERATOR_FINISHED;
1374 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1376 ot->name = "Frame Offset";
1377 ot->idname = "SCREEN_OT_frame_offset";
1379 ot->exec= frame_offset_exec;
1381 ot->poll= ED_operator_screenactive;
1385 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1388 /* ************** switch screen operator ***************************** */
1391 /* function to be called outside UI context, or for redo */
1392 static int screen_set_exec(bContext *C, wmOperator *op)
1394 bScreen *screen= CTX_wm_screen(C);
1395 ScrArea *sa= CTX_wm_area(C);
1396 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1397 int delta= RNA_int_get(op->ptr, "delta");
1399 /* this screen is 'fake', solve later XXX */
1401 return OPERATOR_CANCELLED;
1405 screen= screen->id.next;
1406 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1407 if(screen->winid==0 && screen->full==0)
1411 else if(delta== -1) {
1413 screen= screen->id.prev;
1414 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1415 if(screen->winid==0 && screen->full==0)
1424 ED_screen_set(C, screen);
1425 return OPERATOR_FINISHED;
1427 return OPERATOR_CANCELLED;
1430 void SCREEN_OT_screen_set(wmOperatorType *ot)
1432 ot->name = "Set Screen";
1433 ot->idname = "SCREEN_OT_screen_set";
1435 ot->exec= screen_set_exec;
1436 ot->poll= ED_operator_screenactive;
1439 RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1440 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1443 /* ************** screen full-area operator ***************************** */
1446 /* function to be called outside UI context, or for redo */
1447 static int screen_full_area_exec(bContext *C, wmOperator *op)
1449 ed_screen_fullarea(C, CTX_wm_area(C));
1450 return OPERATOR_FINISHED;
1453 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1455 ot->name = "Toggle Make Area Fullscreen";
1456 ot->idname = "SCREEN_OT_screen_full_area";
1458 ot->exec= screen_full_area_exec;
1459 ot->poll= ED_operator_areaactive;
1466 /* ************** join area operator ********************************************** */
1468 /* operator state vars used:
1469 x1, y1 mouse coord in first area, which will disappear
1470 x2, y2 mouse coord in 2nd area, which will become joined
1474 init() find edge based on state vars
1475 test if the edge divides two areas,
1476 store active and nonactive area,
1478 apply() do the actual join
1480 exit() cleanup, send notifier
1484 exec() calls init, apply, exit
1486 invoke() sets mouse coords in x,y
1490 modal() accept modal events while doing it
1491 call apply() with active window and nonactive window
1492 call exit() and remove handler when LMB confirm
1496 typedef struct sAreaJoinData
1498 ScrArea *sa1; /* first area to be considered */
1499 ScrArea *sa2; /* second area to be considered */
1500 ScrArea *scr; /* designed for removal */
1505 /* validate selection inside screen, set variables OK */
1506 /* return 0: init failed */
1507 /* XXX todo: find edge based on (x,y) and set other area? */
1508 static int area_join_init(bContext *C, wmOperator *op)
1511 sAreaJoinData* jd= NULL;
1515 /* required properties, make negative to get return 0 if not set by caller */
1516 x1= RNA_int_get(op->ptr, "x1");
1517 y1= RNA_int_get(op->ptr, "y1");
1518 x2= RNA_int_get(op->ptr, "x2");
1519 y2= RNA_int_get(op->ptr, "y2");
1521 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1522 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1523 if(sa1==NULL || sa2==NULL || sa1==sa2)
1526 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1529 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1531 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1538 /* apply the join of the areas (space types) */
1539 static int area_join_apply(bContext *C, wmOperator *op)
1541 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1544 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1547 if (CTX_wm_area(C) == jd->sa2) {
1548 CTX_wm_area_set(C, NULL);
1549 CTX_wm_region_set(C, NULL);
1555 /* finish operation */
1556 static void area_join_exit(bContext *C, wmOperator *op)
1558 if (op->customdata) {
1559 MEM_freeN(op->customdata);
1560 op->customdata = NULL;
1563 /* this makes sure aligned edges will result in aligned grabbing */
1564 removedouble_scredges(CTX_wm_screen(C));
1565 removenotused_scredges(CTX_wm_screen(C));
1566 removenotused_scrverts(CTX_wm_screen(C));
1569 static int area_join_exec(bContext *C, wmOperator *op)
1571 if(!area_join_init(C, op))
1572 return OPERATOR_CANCELLED;
1574 area_join_apply(C, op);
1575 area_join_exit(C, op);
1577 return OPERATOR_FINISHED;
1580 /* interaction callback */
1581 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1584 if(event->type==EVT_ACTIONZONE_AREA) {
1585 sActionzoneData *sad= event->customdata;
1587 if(sad->modifier>0) {
1588 return OPERATOR_PASS_THROUGH;
1591 /* verify *sad itself */
1592 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1593 return OPERATOR_PASS_THROUGH;
1595 /* is this our *sad? if areas equal it should be passed on */
1596 if(sad->sa1==sad->sa2)
1597 return OPERATOR_PASS_THROUGH;
1599 /* prepare operator state vars */
1600 RNA_int_set(op->ptr, "x1", sad->x);
1601 RNA_int_set(op->ptr, "y1", sad->y);
1602 RNA_int_set(op->ptr, "x2", event->x);
1603 RNA_int_set(op->ptr, "y2", event->y);
1605 if(!area_join_init(C, op))
1606 return OPERATOR_PASS_THROUGH;
1608 /* add temp handler */
1609 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1611 return OPERATOR_RUNNING_MODAL;
1614 return OPERATOR_PASS_THROUGH;
1617 static int area_join_cancel(bContext *C, wmOperator *op)
1619 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1622 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1623 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1626 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1627 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1630 WM_event_add_notifier(C, NC_WINDOW, NULL);
1632 area_join_exit(C, op);
1634 return OPERATOR_CANCELLED;
1637 /* modal callback while selecting area (space) that will be removed */
1638 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1640 bScreen *sc= CTX_wm_screen(C);
1641 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1643 /* execute the events */
1644 switch(event->type) {
1648 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1652 if (jd->sa1 != sa) {
1653 dir = area_getorientation(sc, jd->sa1, sa);
1655 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1657 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1660 /* we are not bordering on the previously selected area
1661 we check if area has common border with the one marked for removal
1662 in this case we can swap areas.
1664 dir = area_getorientation(sc, sa, jd->sa2);
1666 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1667 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1670 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1671 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1674 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1678 WM_event_add_notifier(C, NC_WINDOW, NULL);
1681 /* we are back in the area previously selected for keeping
1682 * we swap the areas if possible to allow user to choose */
1683 if (jd->sa2 != NULL) {
1684 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1685 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1688 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1689 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1690 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1692 printf("oops, didn't expect that!\n");
1696 dir = area_getorientation(sc, jd->sa1, sa);
1698 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1700 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1703 WM_event_add_notifier(C, NC_WINDOW, NULL);
1710 area_join_apply(C, op);
1711 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1712 area_join_exit(C, op);
1713 return OPERATOR_FINISHED;
1718 return area_join_cancel(C, op);
1721 return OPERATOR_RUNNING_MODAL;
1724 /* Operator for joining two areas (space types) */
1725 void SCREEN_OT_area_join(wmOperatorType *ot)
1728 ot->name= "Join area";
1729 ot->idname= "SCREEN_OT_area_join";
1732 ot->exec= area_join_exec;
1733 ot->invoke= area_join_invoke;
1734 ot->modal= area_join_modal;
1735 ot->poll= ED_operator_areaactive;
1737 ot->flag= OPTYPE_BLOCKING;
1740 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1741 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1742 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1743 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1746 /* ************** repeat last operator ***************************** */
1748 static int repeat_last_exec(bContext *C, wmOperator *op)
1750 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1753 WM_operator_repeat(C, lastop);
1755 return OPERATOR_CANCELLED;
1758 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1761 ot->name= "Repeat Last";
1762 ot->idname= "SCREEN_OT_repeat_last";
1765 ot->exec= repeat_last_exec;
1767 ot->poll= ED_operator_screenactive;
1771 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1773 wmWindowManager *wm= CTX_wm_manager(C);
1779 items= BLI_countlist(&wm->operators);
1781 return OPERATOR_CANCELLED;
1783 pup= uiPupMenuBegin(C, op->type->name, 0);
1784 layout= uiPupMenuLayout(pup);
1786 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1787 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1789 uiPupMenuEnd(C, pup);
1791 return OPERATOR_CANCELLED;
1794 static int repeat_history_exec(bContext *C, wmOperator *op)
1796 wmWindowManager *wm= CTX_wm_manager(C);
1798 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1800 /* let's put it as last operator in list */
1801 BLI_remlink(&wm->operators, op);
1802 BLI_addtail(&wm->operators, op);
1804 WM_operator_repeat(C, op);
1807 return OPERATOR_FINISHED;
1810 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1813 ot->name= "Repeat History";
1814 ot->idname= "SCREEN_OT_repeat_history";
1817 ot->invoke= repeat_history_invoke;
1818 ot->exec= repeat_history_exec;
1820 ot->poll= ED_operator_screenactive;
1822 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1825 /* ********************** redo operator ***************************** */
1827 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1829 wmWindowManager *wm= CTX_wm_manager(C);
1832 /* only for operators that are registered and did an undo push */
1833 for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1834 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1838 WM_operator_redo_popup(C, lastop);
1840 return OPERATOR_CANCELLED;
1843 void SCREEN_OT_redo_last(wmOperatorType *ot)
1846 ot->name= "Redo Last";
1847 ot->idname= "SCREEN_OT_redo_last";
1850 ot->invoke= redo_last_invoke;
1852 ot->poll= ED_operator_screenactive;
1855 /* ************** region split operator ***************************** */
1857 /* insert a region in the area region list */
1858 static int region_split_exec(bContext *C, wmOperator *op)
1860 ARegion *ar= CTX_wm_region(C);
1862 if(ar->regiontype==RGN_TYPE_HEADER)
1863 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1864 else if(ar->alignment==RGN_ALIGN_QSPLIT)
1865 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1867 ScrArea *sa= CTX_wm_area(C);
1868 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1869 int dir= RNA_enum_get(op->ptr, "type");
1871 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1873 newar->alignment= ar->alignment;
1876 ar->alignment= RGN_ALIGN_HSPLIT;
1878 ar->alignment= RGN_ALIGN_VSPLIT;
1880 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1883 return OPERATOR_FINISHED;
1886 void SCREEN_OT_region_split(wmOperatorType *ot)
1889 ot->name= "Split Region";
1890 ot->idname= "SCREEN_OT_region_split";
1893 ot->invoke= WM_menu_invoke;
1894 ot->exec= region_split_exec;
1895 ot->poll= ED_operator_areaactive;
1897 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1900 /* ************** region four-split operator ***************************** */
1902 /* insert a region in the area region list */
1903 static int region_foursplit_exec(bContext *C, wmOperator *op)
1905 ARegion *ar= CTX_wm_region(C);
1908 if(ar->regiontype!=RGN_TYPE_WINDOW)
1909 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1910 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1911 ScrArea *sa= CTX_wm_area(C);
1914 /* keep current region */
1917 if(sa->spacetype==SPACE_VIEW3D) {
1918 RegionView3D *rv3d= ar->regiondata;
1920 rv3d->rflag &= ~RV3D_CLIPPING;
1923 for(ar= sa->regionbase.first; ar; ar= arn) {
1925 if(ar->alignment==RGN_ALIGN_QSPLIT) {
1926 ED_region_exit(C, ar);
1927 BKE_area_region_free(sa->type, ar);
1928 BLI_remlink(&sa->regionbase, ar);
1932 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1935 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1937 ScrArea *sa= CTX_wm_area(C);
1941 ar->alignment= RGN_ALIGN_QSPLIT;
1943 for(count=0; count<3; count++) {
1944 newar= BKE_area_region_copy(sa->type, ar);
1945 BLI_addtail(&sa->regionbase, newar);
1948 /* lock views and set them */
1949 if(sa->spacetype==SPACE_VIEW3D) {
1952 rv3d= ar->regiondata;
1953 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1956 rv3d= ar->regiondata;
1957 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1960 rv3d= ar->regiondata;
1961 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1964 rv3d= ar->regiondata;
1965 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1968 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1972 return OPERATOR_FINISHED;
1975 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1978 ot->name= "Split Region in 4 Parts";
1979 ot->idname= "SCREEN_OT_region_foursplit";
1982 ot->invoke= WM_operator_confirm;
1983 ot->exec= region_foursplit_exec;
1984 ot->poll= ED_operator_areaactive;
1985 ot->flag= OPTYPE_REGISTER;
1990 /* ************** region flip operator ***************************** */
1992 /* flip a region alignment */
1993 static int region_flip_exec(bContext *C, wmOperator *op)
1995 ARegion *ar= CTX_wm_region(C);
1997 if(ar->alignment==RGN_ALIGN_TOP)
1998 ar->alignment= RGN_ALIGN_BOTTOM;
1999 else if(ar->alignment==RGN_ALIGN_BOTTOM)
2000 ar->alignment= RGN_ALIGN_TOP;
2001 else if(ar->alignment==RGN_ALIGN_LEFT)
2002 ar->alignment= RGN_ALIGN_RIGHT;
2003 else if(ar->alignment==RGN_ALIGN_RIGHT)
2004 ar->alignment= RGN_ALIGN_LEFT;
2006 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2007 printf("executed region flip\n");
2009 return OPERATOR_FINISHED;
2013 void SCREEN_OT_region_flip(wmOperatorType *ot)
2016 ot->name= "Flip Region";
2017 ot->idname= "SCREEN_OT_region_flip";
2020 ot->exec= region_flip_exec;
2022 ot->poll= ED_operator_areaactive;
2023 ot->flag= OPTYPE_REGISTER;
2027 /* ****************** anim player, with timer ***************** */
2029 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2031 if(regiontype==RGN_TYPE_WINDOW) {
2033 switch (spacetype) {
2035 if(redraws & TIME_ALL_3D_WIN)
2041 if(redraws & TIME_ALL_ANIM_WIN)
2045 /* if only 1 window or 3d windows, we do timeline too */
2046 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2050 if(redraws & TIME_ALL_BUTS_WIN)
2054 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2058 if(redraws & TIME_ALL_IMAGE_WIN)
2064 else if(regiontype==RGN_TYPE_UI) {
2065 if(redraws & TIME_ALL_BUTS_WIN)
2068 else if(regiontype==RGN_TYPE_HEADER) {
2069 if(spacetype==SPACE_TIME)
2075 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2077 bScreen *screen= CTX_wm_screen(C);
2079 if(screen->animtimer==event->customdata) {
2080 Scene *scene= CTX_data_scene(C);
2081 wmTimer *wt= screen->animtimer;
2082 ScreenAnimData *sad= wt->customdata;
2085 if(scene->audio.flag & AUDIO_SYNC) {
2086 int step = floor(wt->duration * FPS);
2087 if (sad->reverse) // XXX does this option work with audio?
2088 scene->r.cfra -= step;
2090 scene->r.cfra += step;
2091 wt->duration -= ((float)step)/FPS;
2101 /* jump back to end */
2102 if (scene->r.psfra) {
2103 if(scene->r.cfra < scene->r.psfra)
2104 scene->r.cfra= scene->r.pefra;
2107 if(scene->r.cfra < scene->r.sfra)
2108 scene->r.cfra= scene->r.efra;
2112 /* jump back to start */
2113 if (scene->r.psfra) {
2114 if(scene->r.cfra > scene->r.pefra)
2115 scene->r.cfra= scene->r.psfra;
2118 if(scene->r.cfra > scene->r.efra)
2119 scene->r.cfra= scene->r.sfra;
2123 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2124 ED_update_for_newframe(C, 1);
2126 for(sa= screen->areabase.first; sa; sa= sa->next) {
2128 for(ar= sa->regionbase.first; ar; ar= ar->next) {
2130 ED_region_tag_redraw(ar);
2132 if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2133 ED_region_tag_redraw(ar);
2137 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2139 return OPERATOR_FINISHED;
2141 return OPERATOR_PASS_THROUGH;
2144 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2147 ot->name= "Animation Step";
2148 ot->idname= "SCREEN_OT_animation_step";
2151 ot->invoke= screen_animation_step;
2153 ot->poll= ED_operator_screenactive;
2157 /* ****************** anim player, starts or ends timer ***************** */
2159 /* toggle operator */
2160 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2162 bScreen *screen= CTX_wm_screen(C);
2164 if(screen->animtimer) {
2165 ED_screen_animation_timer(C, 0, 0);
2168 int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2170 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, mode);
2172 if(screen->animtimer) {
2173 wmTimer *wt= screen->animtimer;
2174 ScreenAnimData *sad= wt->customdata;
2176 sad->ar= CTX_wm_region(C);
2180 return OPERATOR_FINISHED;
2183 void SCREEN_OT_animation_play(wmOperatorType *ot)
2186 ot->name= "Animation player";
2187 ot->idname= "SCREEN_OT_animation_play";
2190 ot->invoke= screen_animation_play;
2192 ot->poll= ED_operator_screenactive;
2194 RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2197 /* ************** border select operator (template) ***************************** */
2199 /* operator state vars used: (added by default WM callbacks)
2203 customdata: the wmGesture pointer
2207 exec() has to be filled in by user
2209 invoke() default WM function
2212 modal() default WM function
2213 accept modal events while doing it, calls exec(), handles ESC and border drawing
2215 poll() has to be filled in by user for context
2218 static int border_select_do(bContext *C, wmOperator *op)
2220 int event_type= RNA_int_get(op->ptr, "event_type");
2222 if(event_type==LEFTMOUSE)
2223 printf("border select do select\n");
2224 else if(event_type==RIGHTMOUSE)
2225 printf("border select deselect\n");
2227 printf("border select do something\n");
2232 void SCREEN_OT_border_select(wmOperatorType *ot)
2235 ot->name= "Border select";
2236 ot->idname= "SCREEN_OT_border_select";
2239 ot->exec= border_select_do;
2240 ot->invoke= WM_border_select_invoke;
2241 ot->modal= WM_border_select_modal;
2243 ot->poll= ED_operator_areaactive;
2246 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2247 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2248 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2249 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2250 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2255 /* ****************************** render invoking ***************** */
2257 /* set callbacks, exported to sequence render too.
2258 Only call in foreground (UI) renders. */
2260 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2261 /* window as the last possible alternative. */
2262 static ScrArea *biggest_non_image_area(bContext *C)
2264 bScreen *sc= CTX_wm_screen(C);
2265 ScrArea *sa, *big= NULL;
2266 int size, maxsize= 0, bwmaxsize= 0;
2269 for(sa= sc->areabase.first; sa; sa= sa->next) {
2270 if(sa->winx > 30 && sa->winy > 30) {
2271 size= sa->winx*sa->winy;
2272 if(sa->spacetype == SPACE_BUTS) {
2273 if(foundwin == 0 && size > bwmaxsize) {
2278 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2289 static ScrArea *biggest_area(bContext *C)
2291 bScreen *sc= CTX_wm_screen(C);
2292 ScrArea *sa, *big= NULL;
2293 int size, maxsize= 0;
2295 for(sa= sc->areabase.first; sa; sa= sa->next) {
2296 size= sa->winx*sa->winy;
2297 if(size > maxsize) {
2306 static ScrArea *find_area_showing_r_result(bContext *C)
2308 bScreen *sc= CTX_wm_screen(C);
2312 /* find an imagewindow showing render result */
2313 for(sa=sc->areabase.first; sa; sa= sa->next) {
2314 if(sa->spacetype==SPACE_IMAGE) {
2315 sima= sa->spacedata.first;
2316 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2323 static void screen_set_image_output(bContext *C)
2325 Scene *scene= CTX_data_scene(C);
2329 if(scene->r.displaymode==R_OUTPUT_SCREEN) {
2330 /* this function returns with changed context */
2331 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
2336 sa= find_area_showing_r_result(C);
2339 /* find largest open non-image area */
2340 sa= biggest_non_image_area(C);
2342 ED_area_newspace(C, sa, SPACE_IMAGE);
2343 sima= sa->spacedata.first;
2345 /* makes ESC go back to prev space */
2346 sima->flag |= SI_PREVSPACE;
2349 /* use any area of decent size */
2350 sa= biggest_area(C);
2351 if(sa->spacetype!=SPACE_IMAGE) {
2352 // XXX newspace(sa, SPACE_IMAGE);
2353 sima= sa->spacedata.first;
2355 /* makes ESC go back to prev space */
2356 sima->flag |= SI_PREVSPACE;
2361 sima= sa->spacedata.first;
2363 /* get the correct image, and scale it */
2364 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2366 // if(G.displaymode==2) { // XXX
2368 sima->flag |= SI_FULLWINDOW|SI_PREVSPACE;
2370 // ed_screen_fullarea(C, sa);
2376 /* executes blocking render */
2377 static int screen_render_exec(bContext *C, wmOperator *op)
2379 Scene *scene= CTX_data_scene(C);
2380 Render *re= RE_GetRender(scene->id.name);
2383 re= RE_NewRender(scene->id.name);
2385 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2387 if(RNA_boolean_get(op->ptr, "anim"))
2388 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2390 RE_BlenderFrame(re, scene, scene->r.cfra);
2392 // no redraw needed, we leave state as we entered it
2393 ED_update_for_newframe(C, 1);
2395 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2397 return OPERATOR_FINISHED;
2400 typedef struct RenderJob {
2411 static void render_freejob(void *rjv)
2418 /* str is IMA_RW_MAXTEXT in size */
2419 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
2421 char info_time_str[32]; // used to be extern to header_info.c
2422 uintptr_t mem_in_use, mmap_in_use;
2423 float megs_used_memory, mmap_used_memory;
2426 mem_in_use= MEM_get_memory_in_use();
2427 mmap_in_use= MEM_get_mapped_memory_in_use();
2429 megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
2430 mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
2432 if(scene->lay & 0xFF000000)
2433 spos+= sprintf(spos, "Localview | ");
2434 else if(scene->r.scemode & R_SINGLE_LAYER)
2435 spos+= sprintf(spos, "Single Layer | ");
2437 spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
2438 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
2439 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
2440 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
2443 spos+= sprintf(spos, "Field %d ", rs->curfield);
2445 spos+= sprintf(spos, "Blur %d ", rs->curblur);
2447 BLI_timestr(rs->lastframetime, info_time_str);
2448 spos+= sprintf(spos, "Time:%s ", info_time_str);
2451 spos+= sprintf(spos, "| %s ", rs->infostr);
2453 /* very weak... but 512 characters is quite safe */
2454 if(spos >= str+IMA_RW_MAXTEXT)
2455 printf("WARNING! renderwin text beyond limit \n");
2459 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
2463 /* malloc OK here, stats_draw is not in tile threads */
2464 if(rj->image->render_text==NULL)
2465 rj->image->render_text= MEM_callocN(IMA_RW_MAXTEXT, "rendertext");
2467 make_renderinfo_string(rs, rj->scene, rj->image->render_text);
2469 /* make jobs timer to send notifier */
2470 *(rj->do_update)= 1;
2474 /* called inside thread! */
2475 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2479 float x1, y1, *rectf= NULL;
2480 int ymin, ymax, xmin, xmax;
2484 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2485 if(ibuf==NULL) return;
2487 /* if renrect argument, we only refresh scanlines */
2489 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2490 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2493 /* xmin here is first subrect x coord, xmax defines subrect width */
2494 xmin = renrect->xmin + rr->crop;
2495 xmax = renrect->xmax - xmin - rr->crop;
2498 ymin= renrect->ymin + rr->crop;
2499 ymax= renrect->ymax - ymin - rr->crop;
2502 renrect->ymin= renrect->ymax;
2506 xmin = ymin = rr->crop;
2507 xmax = rr->rectx - 2*rr->crop;
2508 ymax = rr->recty - 2*rr->crop;
2511 /* xmin ymin is in tile coords. transform to ibuf */
2512 rxmin= rr->tilerect.xmin + xmin;
2513 if(rxmin >= ibuf->x) return;
2514 rymin= rr->tilerect.ymin + ymin;
2515 if(rymin >= ibuf->y) return;
2517 if(rxmin + xmax > ibuf->x)
2518 xmax= ibuf->x - rxmin;
2519 if(rymin + ymax > ibuf->y)
2520 ymax= ibuf->y - rymin;
2522 if(xmax < 1 || ymax < 1) return;
2524 /* find current float rect for display, first case is after composit... still weak */
2531 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2532 rectf= rr->renlay->rectf;
2535 if(rectf==NULL) return;
2537 rectf+= 4*(rr->rectx*ymin + xmin);
2538 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2540 for(y1= 0; y1<ymax; y1++) {
2544 /* XXX temp. because crop offset */
2545 if( rectc >= (char *)(ibuf->rect)) {
2546 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2547 rc[0]= FTOCHAR(rf[0]);
2548 rc[1]= FTOCHAR(rf[1]);
2549 rc[2]= FTOCHAR(rf[2]);
2550 rc[3]= FTOCHAR(rf[3]);
2553 rectf += 4*rr->rectx;
2557 /* make jobs timer to send notifier */
2558 *(rj->do_update)= 1;
2561 static void render_startjob(void *rjv, short *stop, short *do_update)
2566 rj->do_update= do_update;
2569 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2571 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2574 /* called by render, check job 'stop' value or the global */
2575 static int render_breakjob(void *rjv)
2581 if(rj->stop && *(rj->stop))
2587 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2589 /* no running blender, remove handler and pass through */
2590 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2591 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2593 /* running render */
2594 switch (event->type) {
2596 return OPERATOR_RUNNING_MODAL;
2599 return OPERATOR_PASS_THROUGH;
2602 /* using context, starts job */
2603 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2605 /* new render clears all callbacks */
2606 Scene *scene= CTX_data_scene(C);
2612 /* only one job at a time */
2613 if(WM_jobs_test(CTX_wm_manager(C), scene))
2614 return OPERATOR_CANCELLED;
2616 /* handle UI stuff */
2619 /* flush multires changes (for sculpt) */
2620 multires_force_update(CTX_data_active_object(C));
2622 /* get editmode results */
2623 ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */
2626 // get view3d layer, local layer, make this nice api call to render
2629 /* ensure at least 1 area shows result */
2630 screen_set_image_output(C);
2632 /* job custom data */
2633 rj= MEM_callocN(sizeof(RenderJob), "render job");
2635 rj->win= CTX_wm_window(C);
2636 rj->anim= RNA_boolean_get(op->ptr, "anim");
2637 rj->iuser.scene= scene;
2641 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2642 WM_jobs_customdata(steve, rj, render_freejob);
2643 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2644 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2646 /* get a render result image, and make sure it is empty */
2647 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2648 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2651 /* setup new render */
2652 re= RE_NewRender(scene->id.name);
2653 RE_test_break_cb(re, rj, render_breakjob);
2654 RE_display_draw_cb(re, rj, image_rect_update);
2655 RE_stats_draw_cb(re, rj, image_renderinfo_cb);
2660 // BKE_report in render!
2661 // RE_error_cb(re, error_cb);
2663 WM_jobs_start(CTX_wm_manager(C), steve);
2668 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2670 /* add modal handler for ESC */
2671 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2673 return OPERATOR_RUNNING_MODAL;
2677 /* contextual render, using current scene, view3d? */
2678 void SCREEN_OT_render(wmOperatorType *ot)
2682 ot->idname= "SCREEN_OT_render";
2685 ot->invoke= screen_render_invoke;
2686 ot->modal= screen_render_modal;
2687 ot->exec= screen_render_exec;
2689 ot->poll= ED_operator_screenactive;
2691 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2692 RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2695 /* *********************** cancel render viewer *************** */
2697 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2699 ScrArea *sa= CTX_wm_area(C);
2700 SpaceImage *sima= sa->spacedata.first;
2702 if(sima->flag & SI_PREVSPACE) {
2703 sima->flag &= ~SI_PREVSPACE;
2705 if(sima->flag & SI_FULLWINDOW) {
2706 sima->flag &= ~SI_FULLWINDOW;
2707 ED_screen_full_prevspace(C);
2710 ED_area_prevspace(C);
2712 else if(sima->flag & SI_FULLWINDOW) {
2713 sima->flag &= ~SI_FULLWINDOW;
2714 ed_screen_fullarea(C, sa);
2717 return OPERATOR_FINISHED;
2720 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2723 ot->name= "Cancel Render View";
2724 ot->idname= "SCREEN_OT_render_view_cancel";
2727 ot->exec= render_view_cancel_exec;
2728 ot->poll= ED_operator_image_active;
2731 /* *********************** show render viewer *************** */
2733 static int render_view_show_exec(bContext *C, wmOperator *unused)
2735 ScrArea *sa= find_area_showing_r_result(C);
2737 /* determine if render already shows */
2739 SpaceImage *sima= sa->spacedata.first;
2741 if(sima->flag & SI_PREVSPACE) {
2742 sima->flag &= ~SI_PREVSPACE;
2744 if(sima->flag & SI_FULLWINDOW) {
2745 sima->flag &= ~SI_FULLWINDOW;
2746 ED_screen_full_prevspace(C);
2748 else if(sima->next) {
2749 ED_area_newspace(C, sa, sima->next->spacetype);
2750 ED_area_tag_redraw(sa);
2755 screen_set_image_output(C);
2758 return OPERATOR_FINISHED;
2761 void SCREEN_OT_render_view_show(struct wmOperatorType *ot)
2764 ot->name= "Show/Hide Render View";
2765 ot->idname= "SCREEN_OT_render_view_show";
2768 ot->exec= render_view_show_exec;
2769 ot->poll= ED_operator_screenactive;
2774 /* **************** Assigning operatortypes to global list, adding handlers **************** */
2776 /* called in spacetypes.c */
2777 void ED_operatortypes_screen(void)
2779 /* generic UI stuff */
2780 WM_operatortype_append(SCREEN_OT_actionzone);
2781 WM_operatortype_append(SCREEN_OT_repeat_last);
2782 WM_operatortype_append(SCREEN_OT_repeat_history);
2783 WM_operatortype_append(SCREEN_OT_redo_last);
2786 WM_operatortype_append(SCREEN_OT_area_move);
2787 WM_operatortype_append(SCREEN_OT_area_split);
2788 WM_operatortype_append(SCREEN_OT_area_join);
2789 WM_operatortype_append(SCREEN_OT_area_dupli);
2790 WM_operatortype_append(SCREEN_OT_area_swap);
2791 WM_operatortype_append(SCREEN_OT_region_split);
2792 WM_operatortype_append(SCREEN_OT_region_foursplit);
2793 WM_operatortype_append(SCREEN_OT_region_flip);
2794 WM_operatortype_append(SCREEN_OT_region_scale);
2795 WM_operatortype_append(SCREEN_OT_screen_set);
2796 WM_operatortype_append(SCREEN_OT_screen_full_area);
2797 WM_operatortype_append(SCREEN_OT_screenshot);
2798 WM_operatortype_append(SCREEN_OT_screencast);
2801 WM_operatortype_append(SCREEN_OT_frame_offset);
2802 WM_operatortype_append(SCREEN_OT_animation_step);
2803 WM_operatortype_append(SCREEN_OT_animation_play);
2806 WM_operatortype_append(SCREEN_OT_render);
2807 WM_operatortype_append(SCREEN_OT_render_view_cancel);
2808 WM_operatortype_append(SCREEN_OT_render_view_show);
2810 /* tools shared by more space types */
2811 WM_operatortype_append(ED_OT_undo);
2812 WM_operatortype_append(ED_OT_redo);
2816 /* called in spacetypes.c */
2817 void ED_keymap_screen(wmWindowManager *wm)
2819 ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2821 /* standard timers */
2822 WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
2824 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2825 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2826 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2829 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2830 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2831 WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2832 WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
2833 WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2834 /* area move after action zones */
2835 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2837 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2838 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2839 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2840 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2841 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2842 WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2843 WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2846 WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2847 WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2849 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2850 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2851 WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2852 WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2854 RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
2855 WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
2858 WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2859 WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2862 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2863 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2864 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2865 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2868 WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2869 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2870 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_show", F11KEY, KM_PRESS, 0, 0);
2872 /* frame offsets & play */
2873 keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2874 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2875 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2876 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2877 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
2878 WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);