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 #define KM_MODAL_CANCEL 1
80 #define KM_MODAL_APPLY 2
81 #define KM_MODAL_STEP10 3
82 #define KM_MODAL_STEP10_OFF 4
84 /* ************** Exported Poll tests ********************** */
86 int ED_operator_regionactive(bContext *C)
88 if(CTX_wm_window(C)==NULL) return 0;
89 if(CTX_wm_screen(C)==NULL) return 0;
90 if(CTX_wm_region(C)==NULL) return 0;
94 int ED_operator_areaactive(bContext *C)
96 if(CTX_wm_window(C)==NULL) return 0;
97 if(CTX_wm_screen(C)==NULL) return 0;
98 if(CTX_wm_area(C)==NULL) return 0;
102 int ED_operator_screenactive(bContext *C)
104 if(CTX_wm_window(C)==NULL) return 0;
105 if(CTX_wm_screen(C)==NULL) return 0;
109 /* when mouse is over area-edge */
110 int ED_operator_screen_mainwinactive(bContext *C)
112 if(CTX_wm_window(C)==NULL) return 0;
113 if(CTX_wm_screen(C)==NULL) return 0;
114 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
118 int ED_operator_scene_editable(bContext *C)
120 Scene *scene= CTX_data_scene(C);
121 if(scene && scene->id.lib==NULL)
126 static int ed_spacetype_test(bContext *C, int type)
128 if(ED_operator_areaactive(C)) {
129 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
130 return sl && (sl->spacetype == type);
135 int ED_operator_view3d_active(bContext *C)
137 return ed_spacetype_test(C, SPACE_VIEW3D);
140 int ED_operator_timeline_active(bContext *C)
142 return ed_spacetype_test(C, SPACE_TIME);
145 int ED_operator_outliner_active(bContext *C)
147 return ed_spacetype_test(C, SPACE_OUTLINER);
150 int ED_operator_file_active(bContext *C)
152 return ed_spacetype_test(C, SPACE_FILE);
155 int ED_operator_action_active(bContext *C)
157 return ed_spacetype_test(C, SPACE_ACTION);
160 int ED_operator_buttons_active(bContext *C)
162 return ed_spacetype_test(C, SPACE_BUTS);
165 int ED_operator_node_active(bContext *C)
167 if(ed_spacetype_test(C, SPACE_NODE)) {
168 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
176 int ED_operator_ipo_active(bContext *C)
178 return ed_spacetype_test(C, SPACE_IPO);
181 int ED_operator_sequencer_active(bContext *C)
183 return ed_spacetype_test(C, SPACE_SEQ);
186 int ED_operator_image_active(bContext *C)
188 return ed_spacetype_test(C, SPACE_IMAGE);
191 int ED_operator_nla_active(bContext *C)
193 return ed_spacetype_test(C, SPACE_NLA);
196 int ED_operator_logic_active(bContext *C)
198 return ed_spacetype_test(C, SPACE_LOGIC);
201 int ED_operator_object_active(bContext *C)
203 return NULL != CTX_data_active_object(C);
206 int ED_operator_editmesh(bContext *C)
208 Object *obedit= CTX_data_edit_object(C);
209 if(obedit && obedit->type==OB_MESH)
210 return NULL != ((Mesh *)obedit->data)->edit_mesh;
214 int ED_operator_editarmature(bContext *C)
216 Object *obedit= CTX_data_edit_object(C);
217 if(obedit && obedit->type==OB_ARMATURE)
218 return NULL != ((bArmature *)obedit->data)->edbo;
222 int ED_operator_posemode(bContext *C)
224 Object *obact= CTX_data_active_object(C);
225 Object *obedit= CTX_data_edit_object(C);
227 if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
228 return (obact->flag & OB_POSEMODE)!=0;
234 int ED_operator_uvedit(bContext *C)
236 Object *obedit= CTX_data_edit_object(C);
239 if(obedit && obedit->type==OB_MESH)
240 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
242 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
243 BKE_mesh_end_editmesh(obedit->data, em);
248 BKE_mesh_end_editmesh(obedit->data, em);
252 int ED_operator_uvmap(bContext *C)
254 Object *obedit= CTX_data_edit_object(C);
257 if(obedit && obedit->type==OB_MESH)
258 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
260 if(em && (em->faces.first)) {
261 BKE_mesh_end_editmesh(obedit->data, em);
266 BKE_mesh_end_editmesh(obedit->data, em);
270 int ED_operator_editsurfcurve(bContext *C)
272 Object *obedit= CTX_data_edit_object(C);
273 if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
274 return NULL != ((Curve *)obedit->data)->editnurb;
279 int ED_operator_editcurve(bContext *C)
281 Object *obedit= CTX_data_edit_object(C);
282 if(obedit && obedit->type==OB_CURVE)
283 return NULL != ((Curve *)obedit->data)->editnurb;
287 int ED_operator_editsurf(bContext *C)
289 Object *obedit= CTX_data_edit_object(C);
290 if(obedit && obedit->type==OB_SURF)
291 return NULL != ((Curve *)obedit->data)->editnurb;
295 int ED_operator_editfont(bContext *C)
297 Object *obedit= CTX_data_edit_object(C);
298 if(obedit && obedit->type==OB_FONT)
299 return NULL != ((Curve *)obedit->data)->editfont;
303 int ED_operator_editlattice(bContext *C)
305 Object *obedit= CTX_data_edit_object(C);
306 if(obedit && obedit->type==OB_LATTICE)
307 return NULL != ((Lattice *)obedit->data)->editlatt;
311 /* *************************** action zone operator ************************** */
313 /* operator state vars used:
318 apply() set actionzone event
320 exit() free customdata
326 invoke() check if in zone
327 add customdata, put mouseco and area in it
330 modal() accept modal events while doing it
331 call apply() with gesture info, active window, nonactive window
332 call exit() and remove handler when LMB confirm
336 typedef struct sActionzoneData {
339 int x, y, gesture_dir, modifier;
342 /* used by other operators too */
343 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
346 sa= scr->areabase.first;
348 if(BLI_in_rcti(&sa->totrct, x, y)) break;
355 /* quick poll to save operators to be created and handled */
356 static int actionzone_area_poll(bContext *C)
358 wmWindow *win= CTX_wm_window(C);
359 ScrArea *sa= CTX_wm_area(C);
363 int x= win->eventstate->x;
364 int y= win->eventstate->y;
366 for(az= sa->actionzones.first; az; az= az->next)
367 if(BLI_in_rcti(&az->rect, x, y))
373 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
377 for(az= sa->actionzones.first; az; az= az->next) {
378 if(BLI_in_rcti(&az->rect, x, y)) {
379 if(az->type == AZONE_AREA) {
380 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
383 else if(az->type == AZONE_REGION) {
384 float v1[2], v2[2], v3[2], pt[2];
386 v1[0]= az->x1; v1[1]= az->y1;
387 v2[0]= az->x2; v2[1]= az->y2;
388 v3[0]= az->x3; v3[1]= az->y3;
391 if(IsPointInTri2D(v1, v2, v3, pt))
401 static void actionzone_exit(bContext *C, wmOperator *op)
404 MEM_freeN(op->customdata);
405 op->customdata= NULL;
408 /* send EVT_ACTIONZONE event */
409 static void actionzone_apply(bContext *C, wmOperator *op, int type)
412 wmWindow *win= CTX_wm_window(C);
413 sActionzoneData *sad= op->customdata;
415 sad->modifier= RNA_int_get(op->ptr, "modifier");
417 event= *(win->eventstate); /* XXX huh huh? make api call */
419 event.type= EVT_ACTIONZONE_AREA;
421 event.type= EVT_ACTIONZONE_REGION;
422 event.customdata= op->customdata;
423 event.customdatafree= TRUE;
424 op->customdata= NULL;
426 wm_event_add(win, &event);
429 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
431 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
432 sActionzoneData *sad;
436 return OPERATOR_PASS_THROUGH;
438 /* ok we do the actionzone */
439 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
440 sad->sa1= CTX_wm_area(C);
442 sad->x= event->x; sad->y= event->y;
444 /* region azone directly reacts on mouse clicks */
445 if(sad->az->type==AZONE_REGION) {
446 actionzone_apply(C, op, AZONE_REGION);
447 actionzone_exit(C, op);
448 return OPERATOR_FINISHED;
451 /* add modal handler */
452 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
454 return OPERATOR_RUNNING_MODAL;
459 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
461 sActionzoneData *sad= op->customdata;
463 int mindelta= sad->az->type==AZONE_REGION?1:12;
465 switch(event->type) {
467 /* calculate gesture direction */
468 deltax= (event->x - sad->x);
469 deltay= (event->y - sad->y);
471 if(deltay > ABS(deltax))
472 sad->gesture_dir= 'n';
473 else if(deltax > ABS(deltay))
474 sad->gesture_dir= 'e';
475 else if(deltay < -ABS(deltax))
476 sad->gesture_dir= 's';
478 sad->gesture_dir= 'w';
480 /* gesture is large enough? */
481 if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
483 /* second area, for join */
484 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
485 /* apply sends event */
486 actionzone_apply(C, op, sad->az->type);
487 actionzone_exit(C, op);
489 return OPERATOR_FINISHED;
493 actionzone_exit(C, op);
494 return OPERATOR_CANCELLED;
496 actionzone_exit(C, op);
497 return OPERATOR_CANCELLED;
501 return OPERATOR_RUNNING_MODAL;
504 void SCREEN_OT_actionzone(wmOperatorType *ot)
507 ot->name= "Handle area action zones";
508 ot->idname= "SCREEN_OT_actionzone";
510 ot->invoke= actionzone_invoke;
511 ot->modal= actionzone_modal;
512 ot->poll= actionzone_area_poll;
514 ot->flag= OPTYPE_BLOCKING;
516 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
519 /* ************** swap area operator *********************************** */
521 /* operator state vars used:
523 sa2 area to swap with
527 init() set custom data for operator, based on actionzone event custom data
529 cancel() cancel the operator
531 exit() cleanup, send notifier
535 invoke() gets called on shift+lmb drag in actionzone
536 call init(), add handler
538 modal() accept modal events while doing it
542 typedef struct sAreaSwapData {
546 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
548 sAreaSwapData *sd= NULL;
549 sActionzoneData *sad= event->customdata;
551 if(sad==NULL || sad->sa1==NULL)
554 sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
563 static void area_swap_exit(bContext *C, wmOperator *op)
566 MEM_freeN(op->customdata);
567 op->customdata= NULL;
570 static int area_swap_cancel(bContext *C, wmOperator *op)
572 area_swap_exit(C, op);
573 return OPERATOR_CANCELLED;
576 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
579 if(!area_swap_init(C, op, event))
580 return OPERATOR_PASS_THROUGH;
582 /* add modal handler */
583 WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
584 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
586 return OPERATOR_RUNNING_MODAL;
590 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
592 sActionzoneData *sad= op->customdata;
594 switch(event->type) {
596 /* second area, for join */
597 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
599 case LEFTMOUSE: /* release LMB */
601 if(sad->sa1 == sad->sa2) {
603 return area_swap_cancel(C, op);
605 ED_area_swapspace(C, sad->sa1, sad->sa2);
607 area_swap_exit(C, op);
609 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
611 return OPERATOR_FINISHED;
616 return area_swap_cancel(C, op);
618 return OPERATOR_RUNNING_MODAL;
621 static void SCREEN_OT_area_swap(wmOperatorType *ot)
623 ot->name= "Swap areas";
624 ot->idname= "SCREEN_OT_area_swap";
626 ot->invoke= area_swap_invoke;
627 ot->modal= area_swap_modal;
628 ot->poll= ED_operator_areaactive;
630 ot->flag= OPTYPE_BLOCKING;
633 /* *********** Duplicate area as new window operator ****************** */
635 /* operator callback */
636 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
638 wmWindow *newwin, *win;
643 win= CTX_wm_window(C);
644 sc= CTX_wm_screen(C);
648 if(event->type==EVT_ACTIONZONE_AREA) {
649 sActionzoneData *sad= event->customdata;
652 return OPERATOR_PASS_THROUGH;
657 /* poll() checks area context, but we don't accept full-area windows */
658 if(sc->full != SCREENNORMAL) {
659 if(event->type==EVT_ACTIONZONE_AREA)
660 actionzone_exit(C, op);
661 return OPERATOR_CANCELLED;
664 /* adds window to WM */
666 BLI_translate_rcti(&rect, win->posx, win->posy);
667 newwin= WM_window_open(C, &rect);
669 /* allocs new screen and adds to newly created window, using window size */
670 newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
671 newwin->screen= newsc;
673 /* copy area to new screen */
674 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
676 /* screen, areas init */
677 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
679 if(event->type==EVT_ACTIONZONE_AREA)
680 actionzone_exit(C, op);
682 return OPERATOR_FINISHED;
685 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
687 ot->name= "Duplicate Area into New Window";
688 ot->idname= "SCREEN_OT_area_dupli";
690 ot->invoke= area_dupli_invoke;
691 ot->poll= ED_operator_areaactive;
695 /* ************** move area edge operator *********************************** */
697 /* operator state vars used:
698 x, y mouse coord near edge
699 delta movement of edge
703 init() set default property values, find edge based on mouse coords, test
704 if the edge can be moved, select edges, calculate min and max movement
706 apply() apply delta on selection
708 exit() cleanup, send notifier
710 cancel() cancel moving
714 exec() execute without any user interaction, based on properties
715 call init(), apply(), exit()
717 invoke() gets called on mouse click near edge
718 call init(), add handler
720 modal() accept modal events while doing it
721 call apply() with delta motion
722 call exit() and remove handler
726 typedef struct sAreaMoveData {
727 int bigger, smaller, origval, step;
731 /* helper call to move area-edge, sets limits */
732 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
736 /* we check all areas and test for free space with MINSIZE */
737 *bigger= *smaller= 100000;
739 for(sa= sc->areabase.first; sa; sa= sa->next) {
741 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
743 /* if top or down edge selected, test height */
744 if(sa->v1->flag && sa->v4->flag)
745 *bigger= MIN2(*bigger, y1);
746 else if(sa->v2->flag && sa->v3->flag)
747 *smaller= MIN2(*smaller, y1);
750 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
752 /* if left or right edge selected, test width */
753 if(sa->v1->flag && sa->v2->flag)
754 *bigger= MIN2(*bigger, x1);
755 else if(sa->v3->flag && sa->v4->flag)
756 *smaller= MIN2(*smaller, x1);
761 /* validate selection inside screen, set variables OK */
762 /* return 0: init failed */
763 static int area_move_init (bContext *C, wmOperator *op)
765 bScreen *sc= CTX_wm_screen(C);
770 /* required properties */
771 x= RNA_int_get(op->ptr, "x");
772 y= RNA_int_get(op->ptr, "y");
775 actedge= screen_find_active_scredge(sc, x, y);
776 if(actedge==NULL) return 0;
778 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
781 md->dir= scredge_is_horizontal(actedge)?'h':'v';
782 if(md->dir=='h') md->origval= actedge->v1->vec.y;
783 else md->origval= actedge->v1->vec.x;
785 select_connected_scredge(sc, actedge);
786 /* now all vertices with 'flag==1' are the ones that can be moved. */
788 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
793 /* moves selected screen edge amount of delta, used by split & move */
794 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
796 wmWindow *win= CTX_wm_window(C);
797 bScreen *sc= CTX_wm_screen(C);
800 delta= CLAMPIS(delta, -smaller, bigger);
802 for (v1= sc->vertbase.first; v1; v1= v1->next) {
804 /* that way a nice AREAGRID */
805 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
806 v1->vec.x= origval + delta;
807 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
809 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
810 v1->vec.y= origval + delta;
812 v1->vec.y+= AREAGRID-1;
813 v1->vec.y-= (v1->vec.y % AREAGRID);
815 /* prevent too small top header */
816 if(v1->vec.y > win->sizey-AREAMINY)
817 v1->vec.y= win->sizey-AREAMINY;
822 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
825 static void area_move_apply(bContext *C, wmOperator *op)
827 sAreaMoveData *md= op->customdata;
830 delta= RNA_int_get(op->ptr, "delta");
831 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
834 static void area_move_exit(bContext *C, wmOperator *op)
837 MEM_freeN(op->customdata);
838 op->customdata= NULL;
840 /* this makes sure aligned edges will result in aligned grabbing */
841 removedouble_scrverts(CTX_wm_screen(C));
842 removedouble_scredges(CTX_wm_screen(C));
845 static int area_move_exec(bContext *C, wmOperator *op)
847 if(!area_move_init(C, op))
848 return OPERATOR_CANCELLED;
850 area_move_apply(C, op);
851 area_move_exit(C, op);
853 return OPERATOR_FINISHED;
856 /* interaction callback */
857 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
859 RNA_int_set(op->ptr, "x", event->x);
860 RNA_int_set(op->ptr, "y", event->y);
862 if(!area_move_init(C, op))
863 return OPERATOR_PASS_THROUGH;
865 /* add temp handler */
866 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
868 return OPERATOR_RUNNING_MODAL;
871 static int area_move_cancel(bContext *C, wmOperator *op)
874 RNA_int_set(op->ptr, "delta", 0);
875 area_move_apply(C, op);
876 area_move_exit(C, op);
878 return OPERATOR_CANCELLED;
881 /* modal callback for while moving edges */
882 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
884 sAreaMoveData *md= op->customdata;
887 /* execute the events */
888 switch(event->type) {
891 x= RNA_int_get(op->ptr, "x");
892 y= RNA_int_get(op->ptr, "y");
894 delta= (md->dir == 'v')? event->x - x: event->y - y;
895 if(md->step) delta= delta - (delta % md->step);
896 RNA_int_set(op->ptr, "delta", delta);
898 area_move_apply(C, op);
903 switch (event->val) {
905 area_move_exit(C, op);
906 return OPERATOR_FINISHED;
908 case KM_MODAL_CANCEL:
909 return area_move_cancel(C, op);
911 case KM_MODAL_STEP10:
914 case KM_MODAL_STEP10_OFF:
920 return OPERATOR_RUNNING_MODAL;
923 void SCREEN_OT_area_move(wmOperatorType *ot)
926 ot->name= "Move area edges";
927 ot->idname= "SCREEN_OT_area_move";
929 ot->exec= area_move_exec;
930 ot->invoke= area_move_invoke;
931 ot->cancel= area_move_cancel;
932 ot->modal= area_move_modal;
933 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
935 ot->flag= OPTYPE_BLOCKING;
938 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
939 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
940 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
943 /* ************** split area operator *********************************** */
948 dir direction 'v' or 'h'
951 area pointer to (active) area
952 x, y last used mouse pos
957 init() set default property values, find area based on context
959 apply() split area based on state vars
961 exit() cleanup, send notifier
963 cancel() remove duplicated area
967 exec() execute without any user interaction, based on state vars
968 call init(), apply(), exit()
970 invoke() gets called on mouse click in action-widget
971 call init(), add modal handler
972 call apply() with initial motion
974 modal() accept modal events while doing it
975 call move-areas code with delta motion
976 call exit() or cancel() and remove handler
980 #define SPLIT_STARTED 1
981 #define SPLIT_PROGRESS 2
983 typedef struct sAreaSplitData
985 int x, y; /* last used mouse position */
987 int origval; /* for move areas */
988 int bigger, smaller; /* constraints for moving new edge */
989 int delta; /* delta move edge */
990 int origmin, origsize; /* to calculate fac, for property storage */
992 ScrEdge *nedge; /* new edge */
993 ScrArea *sarea; /* start area */
994 ScrArea *narea; /* new area */
997 /* generic init, no UI stuff here */
998 static int area_split_init(bContext *C, wmOperator *op)
1000 ScrArea *sa= CTX_wm_area(C);
1004 /* required context */
1005 if(sa==NULL) return 0;
1007 /* required properties */
1008 dir= RNA_enum_get(op->ptr, "direction");
1011 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
1012 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
1015 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1019 sd->origsize= dir=='v' ? sa->winx:sa->winy;
1020 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1025 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1026 /* used with split operator */
1027 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1029 ScrVert *sav1= sa->v1;
1030 ScrVert *sav2= sa->v2;
1031 ScrVert *sav3= sa->v3;
1032 ScrVert *sav4= sa->v4;
1033 ScrVert *sbv1= sb->v1;
1034 ScrVert *sbv2= sb->v2;
1035 ScrVert *sbv3= sb->v3;
1036 ScrVert *sbv4= sb->v4;
1038 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1039 return screen_findedge(screen, sav1, sav2);
1041 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1042 return screen_findedge(screen, sav2, sav3);
1044 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1045 return screen_findedge(screen, sav3, sav4);
1047 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1048 return screen_findedge(screen, sav1, sav4);
1055 /* do the split, return success */
1056 static int area_split_apply(bContext *C, wmOperator *op)
1058 bScreen *sc= CTX_wm_screen(C);
1059 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1063 fac= RNA_float_get(op->ptr, "factor");
1064 dir= RNA_enum_get(op->ptr, "direction");
1066 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1071 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1073 /* select newly created edge, prepare for moving edge */
1074 for(sv= sc->vertbase.first; sv; sv= sv->next)
1077 sd->nedge->v1->flag= 1;
1078 sd->nedge->v2->flag= 1;
1080 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1081 else sd->origval= sd->nedge->v1->vec.x;
1083 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1091 static void area_split_exit(bContext *C, wmOperator *op)
1093 if (op->customdata) {
1094 MEM_freeN(op->customdata);
1095 op->customdata = NULL;
1098 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1100 /* this makes sure aligned edges will result in aligned grabbing */
1101 removedouble_scrverts(CTX_wm_screen(C));
1102 removedouble_scredges(CTX_wm_screen(C));
1106 /* UI callback, adds new handler */
1107 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1111 if(event->type==EVT_ACTIONZONE_AREA) {
1112 sActionzoneData *sad= event->customdata;
1115 if(sad->modifier>0) {
1116 return OPERATOR_PASS_THROUGH;
1119 /* no full window splitting allowed */
1120 if(CTX_wm_area(C)->full)
1121 return OPERATOR_PASS_THROUGH;
1123 /* verify *sad itself */
1124 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1125 return OPERATOR_PASS_THROUGH;
1127 /* is this our *sad? if areas not equal it should be passed on */
1128 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1129 return OPERATOR_PASS_THROUGH;
1131 /* prepare operator state vars */
1132 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1134 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1138 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1140 RNA_enum_set(op->ptr, "direction", dir);
1142 /* general init, also non-UI case, adds customdata, sets area and defaults */
1143 if(!area_split_init(C, op))
1144 return OPERATOR_PASS_THROUGH;
1146 sd= (sAreaSplitData *)op->customdata;
1152 if(area_split_apply(C, op)) {
1153 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1155 /* add temp handler for edge move or cancel */
1156 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1158 return OPERATOR_RUNNING_MODAL;
1163 /* nonmodal for now */
1164 return op->type->exec(C, op);
1167 return OPERATOR_PASS_THROUGH;
1170 /* function to be called outside UI context, or for redo */
1171 static int area_split_exec(bContext *C, wmOperator *op)
1174 if(!area_split_init(C, op))
1175 return OPERATOR_CANCELLED;
1177 area_split_apply(C, op);
1178 area_split_exit(C, op);
1180 return OPERATOR_FINISHED;
1184 static int area_split_cancel(bContext *C, wmOperator *op)
1186 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1188 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1189 if (CTX_wm_area(C) == sd->narea) {
1190 CTX_wm_area_set(C, NULL);
1191 CTX_wm_region_set(C, NULL);
1195 area_split_exit(C, op);
1197 return OPERATOR_CANCELLED;
1200 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1202 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1206 /* execute the events */
1207 switch(event->type) {
1209 dir= RNA_enum_get(op->ptr, "direction");
1211 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1212 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1214 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1215 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1217 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1221 if(event->val==0) { /* mouse up */
1222 area_split_exit(C, op);
1223 return OPERATOR_FINISHED;
1226 case RIGHTMOUSE: /* cancel operation */
1228 return area_split_cancel(C, op);
1231 return OPERATOR_RUNNING_MODAL;
1234 static EnumPropertyItem prop_direction_items[] = {
1235 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1236 {'v', "VERTICAL", 0, "Vertical", ""},
1237 {0, NULL, 0, NULL, NULL}};
1239 void SCREEN_OT_area_split(wmOperatorType *ot)
1241 ot->name = "Split area";
1242 ot->idname = "SCREEN_OT_area_split";
1244 ot->exec= area_split_exec;
1245 ot->invoke= area_split_invoke;
1246 ot->modal= area_split_modal;
1248 ot->poll= ED_operator_areaactive;
1249 ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
1252 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1253 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1258 /* ************** scale region edge operator *********************************** */
1260 typedef struct RegionMoveData {
1262 int bigger, smaller, origval;
1268 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1270 sActionzoneData *sad= event->customdata;
1274 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1276 op->customdata= rmd;
1279 rmd->edge= az->edge;
1280 rmd->origx= event->x;
1281 rmd->origy= event->y;
1282 if(rmd->edge=='l' || rmd->edge=='r')
1283 rmd->origval= rmd->ar->type->minsizex;
1285 rmd->origval= rmd->ar->type->minsizey;
1287 /* add temp handler */
1288 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1290 return OPERATOR_RUNNING_MODAL;
1293 return OPERATOR_FINISHED;
1296 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1298 RegionMoveData *rmd= op->customdata;
1301 /* execute the events */
1302 switch(event->type) {
1305 if(rmd->edge=='l' || rmd->edge=='r') {
1306 delta= event->x - rmd->origx;
1307 if(rmd->edge=='l') delta= -delta;
1308 rmd->ar->type->minsizex= rmd->origval + delta;
1309 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1310 if(rmd->ar->type->minsizex < 10) {
1311 rmd->ar->type->minsizex= 10;
1312 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1315 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1318 delta= event->y - rmd->origy;
1319 if(rmd->edge=='b') delta= -delta;
1320 rmd->ar->type->minsizey= rmd->origval + delta;
1321 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1322 if(rmd->ar->type->minsizey < 10) {
1323 rmd->ar->type->minsizey= 10;
1324 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1327 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1330 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1337 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1338 rmd->ar->flag ^= RGN_FLAG_HIDDEN;
1339 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1341 MEM_freeN(op->customdata);
1342 op->customdata = NULL;
1344 return OPERATOR_FINISHED;
1352 return OPERATOR_RUNNING_MODAL;
1356 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1359 ot->name= "Scale Region Size";
1360 ot->idname= "SCREEN_OT_region_scale";
1362 ot->invoke= region_scale_invoke;
1363 ot->modal= region_scale_modal;
1365 ot->poll= ED_operator_areaactive;
1367 ot->flag= OPTYPE_BLOCKING;
1371 /* ************** frame change operator ***************************** */
1374 /* function to be called outside UI context, or for redo */
1375 static int frame_offset_exec(bContext *C, wmOperator *op)
1379 delta = RNA_int_get(op->ptr, "delta");
1381 CTX_data_scene(C)->r.cfra += delta;
1383 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1385 return OPERATOR_FINISHED;
1388 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1390 ot->name = "Frame Offset";
1391 ot->idname = "SCREEN_OT_frame_offset";
1393 ot->exec= frame_offset_exec;
1395 ot->poll= ED_operator_screenactive;
1399 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1402 /* ************** switch screen operator ***************************** */
1405 /* function to be called outside UI context, or for redo */
1406 static int screen_set_exec(bContext *C, wmOperator *op)
1408 bScreen *screen= CTX_wm_screen(C);
1409 ScrArea *sa= CTX_wm_area(C);
1410 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1411 int delta= RNA_int_get(op->ptr, "delta");
1413 /* this screen is 'fake', solve later XXX */
1415 return OPERATOR_CANCELLED;
1419 screen= screen->id.next;
1420 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1421 if(screen->winid==0 && screen->full==0)
1425 else if(delta== -1) {
1427 screen= screen->id.prev;
1428 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1429 if(screen->winid==0 && screen->full==0)
1438 ED_screen_set(C, screen);
1439 return OPERATOR_FINISHED;
1441 return OPERATOR_CANCELLED;
1444 void SCREEN_OT_screen_set(wmOperatorType *ot)
1446 ot->name = "Set Screen";
1447 ot->idname = "SCREEN_OT_screen_set";
1449 ot->exec= screen_set_exec;
1450 ot->poll= ED_operator_screenactive;
1453 RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1454 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1457 /* ************** screen full-area operator ***************************** */
1460 /* function to be called outside UI context, or for redo */
1461 static int screen_full_area_exec(bContext *C, wmOperator *op)
1463 ed_screen_fullarea(C, CTX_wm_area(C));
1464 return OPERATOR_FINISHED;
1467 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1469 ot->name = "Toggle Make Area Fullscreen";
1470 ot->idname = "SCREEN_OT_screen_full_area";
1472 ot->exec= screen_full_area_exec;
1473 ot->poll= ED_operator_areaactive;
1480 /* ************** join area operator ********************************************** */
1482 /* operator state vars used:
1483 x1, y1 mouse coord in first area, which will disappear
1484 x2, y2 mouse coord in 2nd area, which will become joined
1488 init() find edge based on state vars
1489 test if the edge divides two areas,
1490 store active and nonactive area,
1492 apply() do the actual join
1494 exit() cleanup, send notifier
1498 exec() calls init, apply, exit
1500 invoke() sets mouse coords in x,y
1504 modal() accept modal events while doing it
1505 call apply() with active window and nonactive window
1506 call exit() and remove handler when LMB confirm
1510 typedef struct sAreaJoinData
1512 ScrArea *sa1; /* first area to be considered */
1513 ScrArea *sa2; /* second area to be considered */
1514 ScrArea *scr; /* designed for removal */
1519 /* validate selection inside screen, set variables OK */
1520 /* return 0: init failed */
1521 /* XXX todo: find edge based on (x,y) and set other area? */
1522 static int area_join_init(bContext *C, wmOperator *op)
1525 sAreaJoinData* jd= NULL;
1529 /* required properties, make negative to get return 0 if not set by caller */
1530 x1= RNA_int_get(op->ptr, "x1");
1531 y1= RNA_int_get(op->ptr, "y1");
1532 x2= RNA_int_get(op->ptr, "x2");
1533 y2= RNA_int_get(op->ptr, "y2");
1535 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1536 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1537 if(sa1==NULL || sa2==NULL || sa1==sa2)
1540 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1543 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1545 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1552 /* apply the join of the areas (space types) */
1553 static int area_join_apply(bContext *C, wmOperator *op)
1555 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1558 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1561 if (CTX_wm_area(C) == jd->sa2) {
1562 CTX_wm_area_set(C, NULL);
1563 CTX_wm_region_set(C, NULL);
1569 /* finish operation */
1570 static void area_join_exit(bContext *C, wmOperator *op)
1572 if (op->customdata) {
1573 MEM_freeN(op->customdata);
1574 op->customdata = NULL;
1577 /* this makes sure aligned edges will result in aligned grabbing */
1578 removedouble_scredges(CTX_wm_screen(C));
1579 removenotused_scredges(CTX_wm_screen(C));
1580 removenotused_scrverts(CTX_wm_screen(C));
1583 static int area_join_exec(bContext *C, wmOperator *op)
1585 if(!area_join_init(C, op))
1586 return OPERATOR_CANCELLED;
1588 area_join_apply(C, op);
1589 area_join_exit(C, op);
1591 return OPERATOR_FINISHED;
1594 /* interaction callback */
1595 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1598 if(event->type==EVT_ACTIONZONE_AREA) {
1599 sActionzoneData *sad= event->customdata;
1601 if(sad->modifier>0) {
1602 return OPERATOR_PASS_THROUGH;
1605 /* verify *sad itself */
1606 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1607 return OPERATOR_PASS_THROUGH;
1609 /* is this our *sad? if areas equal it should be passed on */
1610 if(sad->sa1==sad->sa2)
1611 return OPERATOR_PASS_THROUGH;
1613 /* prepare operator state vars */
1614 RNA_int_set(op->ptr, "x1", sad->x);
1615 RNA_int_set(op->ptr, "y1", sad->y);
1616 RNA_int_set(op->ptr, "x2", event->x);
1617 RNA_int_set(op->ptr, "y2", event->y);
1619 if(!area_join_init(C, op))
1620 return OPERATOR_PASS_THROUGH;
1622 /* add temp handler */
1623 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1625 return OPERATOR_RUNNING_MODAL;
1628 return OPERATOR_PASS_THROUGH;
1631 static int area_join_cancel(bContext *C, wmOperator *op)
1633 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1636 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1637 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1640 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1641 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1644 WM_event_add_notifier(C, NC_WINDOW, NULL);
1646 area_join_exit(C, op);
1648 return OPERATOR_CANCELLED;
1651 /* modal callback while selecting area (space) that will be removed */
1652 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1654 bScreen *sc= CTX_wm_screen(C);
1655 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1657 /* execute the events */
1658 switch(event->type) {
1662 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1666 if (jd->sa1 != sa) {
1667 dir = area_getorientation(sc, jd->sa1, sa);
1669 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1671 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1674 /* we are not bordering on the previously selected area
1675 we check if area has common border with the one marked for removal
1676 in this case we can swap areas.
1678 dir = area_getorientation(sc, sa, jd->sa2);
1680 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1681 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1684 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1685 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1688 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1692 WM_event_add_notifier(C, NC_WINDOW, NULL);
1695 /* we are back in the area previously selected for keeping
1696 * we swap the areas if possible to allow user to choose */
1697 if (jd->sa2 != NULL) {
1698 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1699 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1702 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1703 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1704 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1706 printf("oops, didn't expect that!\n");
1710 dir = area_getorientation(sc, jd->sa1, sa);
1712 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1714 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1717 WM_event_add_notifier(C, NC_WINDOW, NULL);
1724 area_join_apply(C, op);
1725 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1726 area_join_exit(C, op);
1727 return OPERATOR_FINISHED;
1732 return area_join_cancel(C, op);
1735 return OPERATOR_RUNNING_MODAL;
1738 /* Operator for joining two areas (space types) */
1739 void SCREEN_OT_area_join(wmOperatorType *ot)
1742 ot->name= "Join area";
1743 ot->idname= "SCREEN_OT_area_join";
1746 ot->exec= area_join_exec;
1747 ot->invoke= area_join_invoke;
1748 ot->modal= area_join_modal;
1749 ot->poll= ED_operator_areaactive;
1751 ot->flag= OPTYPE_BLOCKING;
1754 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1755 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1756 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1757 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1760 /* ************** repeat last operator ***************************** */
1762 static int repeat_last_exec(bContext *C, wmOperator *op)
1764 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1767 WM_operator_repeat(C, lastop);
1769 return OPERATOR_CANCELLED;
1772 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1775 ot->name= "Repeat Last";
1776 ot->idname= "SCREEN_OT_repeat_last";
1779 ot->exec= repeat_last_exec;
1781 ot->poll= ED_operator_screenactive;
1785 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1787 wmWindowManager *wm= CTX_wm_manager(C);
1793 items= BLI_countlist(&wm->operators);
1795 return OPERATOR_CANCELLED;
1797 pup= uiPupMenuBegin(C, op->type->name, 0);
1798 layout= uiPupMenuLayout(pup);
1800 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1801 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1803 uiPupMenuEnd(C, pup);
1805 return OPERATOR_CANCELLED;
1808 static int repeat_history_exec(bContext *C, wmOperator *op)
1810 wmWindowManager *wm= CTX_wm_manager(C);
1812 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1814 /* let's put it as last operator in list */
1815 BLI_remlink(&wm->operators, op);
1816 BLI_addtail(&wm->operators, op);
1818 WM_operator_repeat(C, op);
1821 return OPERATOR_FINISHED;
1824 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1827 ot->name= "Repeat History";
1828 ot->idname= "SCREEN_OT_repeat_history";
1831 ot->invoke= repeat_history_invoke;
1832 ot->exec= repeat_history_exec;
1834 ot->poll= ED_operator_screenactive;
1836 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1839 /* ********************** redo operator ***************************** */
1841 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1843 wmWindowManager *wm= CTX_wm_manager(C);
1846 /* only for operators that are registered and did an undo push */
1847 for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1848 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1852 WM_operator_redo_popup(C, lastop);
1854 return OPERATOR_CANCELLED;
1857 void SCREEN_OT_redo_last(wmOperatorType *ot)
1860 ot->name= "Redo Last";
1861 ot->idname= "SCREEN_OT_redo_last";
1864 ot->invoke= redo_last_invoke;
1866 ot->poll= ED_operator_screenactive;
1869 /* ************** region split operator ***************************** */
1871 /* insert a region in the area region list */
1872 static int region_split_exec(bContext *C, wmOperator *op)
1874 ARegion *ar= CTX_wm_region(C);
1876 if(ar->regiontype==RGN_TYPE_HEADER)
1877 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1878 else if(ar->alignment==RGN_ALIGN_QSPLIT)
1879 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1881 ScrArea *sa= CTX_wm_area(C);
1882 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1883 int dir= RNA_enum_get(op->ptr, "type");
1885 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1887 newar->alignment= ar->alignment;
1890 ar->alignment= RGN_ALIGN_HSPLIT;
1892 ar->alignment= RGN_ALIGN_VSPLIT;
1894 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1897 return OPERATOR_FINISHED;
1900 void SCREEN_OT_region_split(wmOperatorType *ot)
1903 ot->name= "Split Region";
1904 ot->idname= "SCREEN_OT_region_split";
1907 ot->invoke= WM_menu_invoke;
1908 ot->exec= region_split_exec;
1909 ot->poll= ED_operator_areaactive;
1911 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1914 /* ************** region four-split operator ***************************** */
1916 /* insert a region in the area region list */
1917 static int region_foursplit_exec(bContext *C, wmOperator *op)
1919 ARegion *ar= CTX_wm_region(C);
1922 if(ar->regiontype!=RGN_TYPE_WINDOW)
1923 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1924 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1925 ScrArea *sa= CTX_wm_area(C);
1928 /* keep current region */
1931 if(sa->spacetype==SPACE_VIEW3D) {
1932 RegionView3D *rv3d= ar->regiondata;
1934 rv3d->rflag &= ~RV3D_CLIPPING;
1937 for(ar= sa->regionbase.first; ar; ar= arn) {
1939 if(ar->alignment==RGN_ALIGN_QSPLIT) {
1940 ED_region_exit(C, ar);
1941 BKE_area_region_free(sa->type, ar);
1942 BLI_remlink(&sa->regionbase, ar);
1946 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1949 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1951 ScrArea *sa= CTX_wm_area(C);
1955 ar->alignment= RGN_ALIGN_QSPLIT;
1957 for(count=0; count<3; count++) {
1958 newar= BKE_area_region_copy(sa->type, ar);
1959 BLI_addtail(&sa->regionbase, newar);
1962 /* lock views and set them */
1963 if(sa->spacetype==SPACE_VIEW3D) {
1966 rv3d= ar->regiondata;
1967 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1970 rv3d= ar->regiondata;
1971 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1974 rv3d= ar->regiondata;
1975 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1978 rv3d= ar->regiondata;
1979 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1982 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1986 return OPERATOR_FINISHED;
1989 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1992 ot->name= "Split Region in 4 Parts";
1993 ot->idname= "SCREEN_OT_region_foursplit";
1996 // ot->invoke= WM_operator_confirm;
1997 ot->exec= region_foursplit_exec;
1998 ot->poll= ED_operator_areaactive;
1999 ot->flag= OPTYPE_REGISTER;
2004 /* ************** region flip operator ***************************** */
2006 /* flip a region alignment */
2007 static int region_flip_exec(bContext *C, wmOperator *op)
2009 ARegion *ar= CTX_wm_region(C);
2011 if(ar->alignment==RGN_ALIGN_TOP)
2012 ar->alignment= RGN_ALIGN_BOTTOM;
2013 else if(ar->alignment==RGN_ALIGN_BOTTOM)
2014 ar->alignment= RGN_ALIGN_TOP;
2015 else if(ar->alignment==RGN_ALIGN_LEFT)
2016 ar->alignment= RGN_ALIGN_RIGHT;
2017 else if(ar->alignment==RGN_ALIGN_RIGHT)
2018 ar->alignment= RGN_ALIGN_LEFT;
2020 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2021 printf("executed region flip\n");
2023 return OPERATOR_FINISHED;
2027 void SCREEN_OT_region_flip(wmOperatorType *ot)
2030 ot->name= "Flip Region";
2031 ot->idname= "SCREEN_OT_region_flip";
2034 ot->exec= region_flip_exec;
2036 ot->poll= ED_operator_areaactive;
2037 ot->flag= OPTYPE_REGISTER;
2041 /* ****************** anim player, with timer ***************** */
2043 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2045 if(regiontype==RGN_TYPE_WINDOW) {
2047 switch (spacetype) {
2049 if(redraws & TIME_ALL_3D_WIN)
2055 if(redraws & TIME_ALL_ANIM_WIN)
2059 /* if only 1 window or 3d windows, we do timeline too */
2060 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2064 if(redraws & TIME_ALL_BUTS_WIN)
2068 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2072 if(redraws & TIME_ALL_IMAGE_WIN)
2078 else if(regiontype==RGN_TYPE_UI) {
2079 if(redraws & TIME_ALL_BUTS_WIN)
2082 else if(regiontype==RGN_TYPE_HEADER) {
2083 if(spacetype==SPACE_TIME)
2089 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2091 bScreen *screen= CTX_wm_screen(C);
2093 if(screen->animtimer==event->customdata) {
2094 Scene *scene= CTX_data_scene(C);
2095 wmTimer *wt= screen->animtimer;
2096 ScreenAnimData *sad= wt->customdata;
2099 if(scene->audio.flag & AUDIO_SYNC) {
2100 int step = floor(wt->duration * FPS);
2101 if (sad->reverse) // XXX does this option work with audio?
2102 scene->r.cfra -= step;
2104 scene->r.cfra += step;
2105 wt->duration -= ((float)step)/FPS;
2115 /* jump back to end */
2116 if (scene->r.psfra) {
2117 if(scene->r.cfra < scene->r.psfra)
2118 scene->r.cfra= scene->r.pefra;
2121 if(scene->r.cfra < scene->r.sfra)
2122 scene->r.cfra= scene->r.efra;
2126 /* jump back to start */
2127 if (scene->r.psfra) {
2128 if(scene->r.cfra > scene->r.pefra)
2129 scene->r.cfra= scene->r.psfra;
2132 if(scene->r.cfra > scene->r.efra)
2133 scene->r.cfra= scene->r.sfra;
2137 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2138 ED_update_for_newframe(C, 1);
2140 for(sa= screen->areabase.first; sa; sa= sa->next) {
2142 for(ar= sa->regionbase.first; ar; ar= ar->next) {
2144 ED_region_tag_redraw(ar);
2146 if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2147 ED_region_tag_redraw(ar);
2151 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2153 return OPERATOR_FINISHED;
2155 return OPERATOR_PASS_THROUGH;
2158 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2161 ot->name= "Animation Step";
2162 ot->idname= "SCREEN_OT_animation_step";
2165 ot->invoke= screen_animation_step;
2167 ot->poll= ED_operator_screenactive;
2171 /* ****************** anim player, starts or ends timer ***************** */
2173 /* toggle operator */
2174 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2176 bScreen *screen= CTX_wm_screen(C);
2178 if(screen->animtimer) {
2179 ED_screen_animation_timer(C, 0, 0);
2182 int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2184 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, mode);
2186 if(screen->animtimer) {
2187 wmTimer *wt= screen->animtimer;
2188 ScreenAnimData *sad= wt->customdata;
2190 sad->ar= CTX_wm_region(C);
2194 return OPERATOR_FINISHED;
2197 void SCREEN_OT_animation_play(wmOperatorType *ot)
2200 ot->name= "Animation player";
2201 ot->idname= "SCREEN_OT_animation_play";
2204 ot->invoke= screen_animation_play;
2206 ot->poll= ED_operator_screenactive;
2208 RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2211 /* ************** border select operator (template) ***************************** */
2213 /* operator state vars used: (added by default WM callbacks)
2217 customdata: the wmGesture pointer
2221 exec() has to be filled in by user
2223 invoke() default WM function
2226 modal() default WM function
2227 accept modal events while doing it, calls exec(), handles ESC and border drawing
2229 poll() has to be filled in by user for context
2232 static int border_select_do(bContext *C, wmOperator *op)
2234 int event_type= RNA_int_get(op->ptr, "event_type");
2236 if(event_type==LEFTMOUSE)
2237 printf("border select do select\n");
2238 else if(event_type==RIGHTMOUSE)
2239 printf("border select deselect\n");
2241 printf("border select do something\n");
2246 void SCREEN_OT_border_select(wmOperatorType *ot)
2249 ot->name= "Border select";
2250 ot->idname= "SCREEN_OT_border_select";
2253 ot->exec= border_select_do;
2254 ot->invoke= WM_border_select_invoke;
2255 ot->modal= WM_border_select_modal;
2257 ot->poll= ED_operator_areaactive;
2260 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2261 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2262 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2263 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2264 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2269 /* ****************************** render invoking ***************** */
2271 /* set callbacks, exported to sequence render too.
2272 Only call in foreground (UI) renders. */
2274 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2275 /* window as the last possible alternative. */
2276 static ScrArea *biggest_non_image_area(bContext *C)
2278 bScreen *sc= CTX_wm_screen(C);
2279 ScrArea *sa, *big= NULL;
2280 int size, maxsize= 0, bwmaxsize= 0;
2283 for(sa= sc->areabase.first; sa; sa= sa->next) {
2284 if(sa->winx > 30 && sa->winy > 30) {
2285 size= sa->winx*sa->winy;
2286 if(sa->spacetype == SPACE_BUTS) {
2287 if(foundwin == 0 && size > bwmaxsize) {
2292 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2303 static ScrArea *biggest_area(bContext *C)
2305 bScreen *sc= CTX_wm_screen(C);
2306 ScrArea *sa, *big= NULL;
2307 int size, maxsize= 0;
2309 for(sa= sc->areabase.first; sa; sa= sa->next) {
2310 size= sa->winx*sa->winy;
2311 if(size > maxsize) {
2320 static ScrArea *find_area_showing_r_result(bContext *C)
2322 bScreen *sc= CTX_wm_screen(C);
2326 /* find an imagewindow showing render result */
2327 for(sa=sc->areabase.first; sa; sa= sa->next) {
2328 if(sa->spacetype==SPACE_IMAGE) {
2329 sima= sa->spacedata.first;
2330 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2337 static ScrArea *find_area_image_empty(bContext *C)
2339 bScreen *sc= CTX_wm_screen(C);
2343 /* find an imagewindow showing render result */
2344 for(sa=sc->areabase.first; sa; sa= sa->next) {
2345 if(sa->spacetype==SPACE_IMAGE) {
2346 sima= sa->spacedata.first;
2354 #if 0 // XXX not used
2355 static ScrArea *find_empty_image_area(bContext *C)
2357 bScreen *sc= CTX_wm_screen(C);
2361 /* find an imagewindow showing render result */
2362 for(sa=sc->areabase.first; sa; sa= sa->next) {
2363 if(sa->spacetype==SPACE_IMAGE) {
2364 sima= sa->spacedata.first;
2371 #endif // XXX not used
2373 static void screen_set_image_output(bContext *C)
2375 Scene *scene= CTX_data_scene(C);
2379 if(scene->r.displaymode==R_OUTPUT_SCREEN) {
2380 /* this function returns with changed context */
2381 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
2386 sa= find_area_showing_r_result(C);
2388 sa= find_area_image_empty(C);
2391 /* find largest open non-image area */
2392 sa= biggest_non_image_area(C);
2394 ED_area_newspace(C, sa, SPACE_IMAGE);
2395 sima= sa->spacedata.first;
2397 /* makes ESC go back to prev space */
2398 sima->flag |= SI_PREVSPACE;
2401 /* use any area of decent size */
2402 sa= biggest_area(C);
2403 if(sa->spacetype!=SPACE_IMAGE) {
2404 // XXX newspace(sa, SPACE_IMAGE);
2405 sima= sa->spacedata.first;
2407 /* makes ESC go back to prev space */
2408 sima->flag |= SI_PREVSPACE;
2413 sima= sa->spacedata.first;
2415 /* get the correct image, and scale it */
2416 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2418 // if(G.displaymode==2) { // XXX
2420 sima->flag |= SI_FULLWINDOW|SI_PREVSPACE;
2422 // ed_screen_fullarea(C, sa);
2428 /* executes blocking render */
2429 static int screen_render_exec(bContext *C, wmOperator *op)
2431 Scene *scene= CTX_data_scene(C);
2432 Render *re= RE_GetRender(scene->id.name);
2435 re= RE_NewRender(scene->id.name);
2437 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2439 if(RNA_boolean_get(op->ptr, "anim"))
2440 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2442 RE_BlenderFrame(re, scene, scene->r.cfra);
2444 // no redraw needed, we leave state as we entered it
2445 ED_update_for_newframe(C, 1);
2447 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2449 return OPERATOR_FINISHED;
2452 typedef struct RenderJob {
2463 static void render_freejob(void *rjv)
2470 /* str is IMA_RW_MAXTEXT in size */
2471 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
2473 char info_time_str[32]; // used to be extern to header_info.c
2474 uintptr_t mem_in_use, mmap_in_use;
2475 float megs_used_memory, mmap_used_memory;
2478 mem_in_use= MEM_get_memory_in_use();
2479 mmap_in_use= MEM_get_mapped_memory_in_use();
2481 megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
2482 mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
2484 if(scene->lay & 0xFF000000)
2485 spos+= sprintf(spos, "Localview | ");
2486 else if(scene->r.scemode & R_SINGLE_LAYER)
2487 spos+= sprintf(spos, "Single Layer | ");
2489 spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
2490 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
2491 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
2492 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
2495 spos+= sprintf(spos, "Field %d ", rs->curfield);
2497 spos+= sprintf(spos, "Blur %d ", rs->curblur);
2499 BLI_timestr(rs->lastframetime, info_time_str);
2500 spos+= sprintf(spos, "Time:%s ", info_time_str);
2503 spos+= sprintf(spos, "| %s ", rs->infostr);
2505 /* very weak... but 512 characters is quite safe */
2506 if(spos >= str+IMA_RW_MAXTEXT)
2507 printf("WARNING! renderwin text beyond limit \n");
2511 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
2515 /* malloc OK here, stats_draw is not in tile threads */
2516 if(rj->image->render_text==NULL)
2517 rj->image->render_text= MEM_callocN(IMA_RW_MAXTEXT, "rendertext");
2519 make_renderinfo_string(rs, rj->scene, rj->image->render_text);
2521 /* make jobs timer to send notifier */
2522 *(rj->do_update)= 1;
2526 /* called inside thread! */
2527 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2531 float x1, y1, *rectf= NULL;
2532 int ymin, ymax, xmin, xmax;
2536 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2537 if(ibuf==NULL) return;
2539 /* if renrect argument, we only refresh scanlines */
2541 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2542 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2545 /* xmin here is first subrect x coord, xmax defines subrect width */
2546 xmin = renrect->xmin + rr->crop;
2547 xmax = renrect->xmax - xmin - rr->crop;
2550 ymin= renrect->ymin + rr->crop;
2551 ymax= renrect->ymax - ymin - rr->crop;
2554 renrect->ymin= renrect->ymax;
2558 xmin = ymin = rr->crop;
2559 xmax = rr->rectx - 2*rr->crop;
2560 ymax = rr->recty - 2*rr->crop;
2563 /* xmin ymin is in tile coords. transform to ibuf */
2564 rxmin= rr->tilerect.xmin + xmin;
2565 if(rxmin >= ibuf->x) return;
2566 rymin= rr->tilerect.ymin + ymin;
2567 if(rymin >= ibuf->y) return;
2569 if(rxmin + xmax > ibuf->x)
2570 xmax= ibuf->x - rxmin;
2571 if(rymin + ymax > ibuf->y)
2572 ymax= ibuf->y - rymin;
2574 if(xmax < 1 || ymax < 1) return;
2576 /* find current float rect for display, first case is after composit... still weak */
2583 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2584 rectf= rr->renlay->rectf;
2587 if(rectf==NULL) return;
2589 rectf+= 4*(rr->rectx*ymin + xmin);
2590 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2592 /* XXX make nice consistent functions for this */
2593 if (rj->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
2594 for(y1= 0; y1<ymax; y1++) {
2599 /* XXX temp. because crop offset */
2600 if( rectc >= (char *)(ibuf->rect)) {
2601 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2602 srgb[0]= linearrgb_to_srgb(rf[0]);
2603 srgb[1]= linearrgb_to_srgb(rf[1]);
2604 srgb[2]= linearrgb_to_srgb(rf[2]);
2606 rc[0]= FTOCHAR(srgb[0]);
2607 rc[1]= FTOCHAR(srgb[1]);
2608 rc[2]= FTOCHAR(srgb[2]);
2609 rc[3]= FTOCHAR(rf[3]);
2612 rectf += 4*rr->rectx;
2616 for(y1= 0; y1<ymax; y1++) {
2620 /* XXX temp. because crop offset */
2621 if( rectc >= (char *)(ibuf->rect)) {
2622 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2623 rc[0]= FTOCHAR(rf[0]);
2624 rc[1]= FTOCHAR(rf[1]);
2625 rc[2]= FTOCHAR(rf[2]);
2626 rc[3]= FTOCHAR(rf[3]);
2629 rectf += 4*rr->rectx;
2634 /* make jobs timer to send notifier */
2635 *(rj->do_update)= 1;
2638 static void render_startjob(void *rjv, short *stop, short *do_update)
2643 rj->do_update= do_update;
2646 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2648 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2651 /* called by render, check job 'stop' value or the global */
2652 static int render_breakjob(void *rjv)
2658 if(rj->stop && *(rj->stop))
2664 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2666 /* no running blender, remove handler and pass through */
2667 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2668 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2670 /* running render */
2671 switch (event->type) {
2673 return OPERATOR_RUNNING_MODAL;
2676 return OPERATOR_PASS_THROUGH;
2679 /* using context, starts job */
2680 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2682 /* new render clears all callbacks */
2683 Scene *scene= CTX_data_scene(C);
2689 /* only one job at a time */
2690 if(WM_jobs_test(CTX_wm_manager(C), scene))
2691 return OPERATOR_CANCELLED;
2693 /* handle UI stuff */
2696 /* flush multires changes (for sculpt) */
2697 multires_force_update(CTX_data_active_object(C));
2699 /* get editmode results */
2700 ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */
2703 // get view3d layer, local layer, make this nice api call to render
2706 /* ensure at least 1 area shows result */
2707 screen_set_image_output(C);
2709 /* job custom data */
2710 rj= MEM_callocN(sizeof(RenderJob), "render job");
2712 rj->win= CTX_wm_window(C);
2713 rj->anim= RNA_boolean_get(op->ptr, "anim");
2714 rj->iuser.scene= scene;
2718 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2719 WM_jobs_customdata(steve, rj, render_freejob);
2720 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2721 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2723 /* get a render result image, and make sure it is empty */
2724 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2725 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2728 /* setup new render */
2729 re= RE_NewRender(scene->id.name);
2730 RE_test_break_cb(re, rj, render_breakjob);
2731 RE_display_draw_cb(re, rj, image_rect_update);
2732 RE_stats_draw_cb(re, rj, image_renderinfo_cb);
2737 // BKE_report in render!
2738 // RE_error_cb(re, error_cb);
2740 WM_jobs_start(CTX_wm_manager(C), steve);
2745 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2747 /* add modal handler for ESC */
2748 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2750 return OPERATOR_RUNNING_MODAL;
2754 /* contextual render, using current scene, view3d? */
2755 void SCREEN_OT_render(wmOperatorType *ot)
2759 ot->idname= "SCREEN_OT_render";
2762 ot->invoke= screen_render_invoke;
2763 ot->modal= screen_render_modal;
2764 ot->exec= screen_render_exec;
2766 ot->poll= ED_operator_screenactive;
2768 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2769 RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2772 /* *********************** cancel render viewer *************** */
2774 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2776 ScrArea *sa= CTX_wm_area(C);
2777 SpaceImage *sima= sa->spacedata.first;
2779 if(sima->flag & SI_PREVSPACE) {
2780 sima->flag &= ~SI_PREVSPACE;
2782 if(sima->flag & SI_FULLWINDOW) {
2783 sima->flag &= ~SI_FULLWINDOW;
2784 ED_screen_full_prevspace(C);
2787 ED_area_prevspace(C);
2789 else if(sima->flag & SI_FULLWINDOW) {
2790 sima->flag &= ~SI_FULLWINDOW;
2791 ed_screen_fullarea(C, sa);
2794 return OPERATOR_FINISHED;
2797 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2800 ot->name= "Cancel Render View";
2801 ot->idname= "SCREEN_OT_render_view_cancel";
2804 ot->exec= render_view_cancel_exec;
2805 ot->poll= ED_operator_image_active;
2808 /* *********************** show render viewer *************** */
2810 static int render_view_show_exec(bContext *C, wmOperator *unused)
2812 ScrArea *sa= find_area_showing_r_result(C);
2814 /* determine if render already shows */
2816 SpaceImage *sima= sa->spacedata.first;
2818 if(sima->flag & SI_PREVSPACE) {
2819 sima->flag &= ~SI_PREVSPACE;
2821 if(sima->flag & SI_FULLWINDOW) {
2822 sima->flag &= ~SI_FULLWINDOW;
2823 ED_screen_full_prevspace(C);
2825 else if(sima->next) {
2826 ED_area_newspace(C, sa, sima->next->spacetype);
2827 ED_area_tag_redraw(sa);
2832 screen_set_image_output(C);
2835 return OPERATOR_FINISHED;
2838 void SCREEN_OT_render_view_show(struct wmOperatorType *ot)
2841 ot->name= "Show/Hide Render View";
2842 ot->idname= "SCREEN_OT_render_view_show";
2845 ot->exec= render_view_show_exec;
2846 ot->poll= ED_operator_screenactive;
2851 /* **************** Assigning operatortypes to global list, adding handlers **************** */
2853 /* called in spacetypes.c */
2854 void ED_operatortypes_screen(void)
2856 /* generic UI stuff */
2857 WM_operatortype_append(SCREEN_OT_actionzone);
2858 WM_operatortype_append(SCREEN_OT_repeat_last);
2859 WM_operatortype_append(SCREEN_OT_repeat_history);
2860 WM_operatortype_append(SCREEN_OT_redo_last);
2863 WM_operatortype_append(SCREEN_OT_area_move);
2864 WM_operatortype_append(SCREEN_OT_area_split);
2865 WM_operatortype_append(SCREEN_OT_area_join);
2866 WM_operatortype_append(SCREEN_OT_area_dupli);
2867 WM_operatortype_append(SCREEN_OT_area_swap);
2868 WM_operatortype_append(SCREEN_OT_region_split);
2869 WM_operatortype_append(SCREEN_OT_region_foursplit);
2870 WM_operatortype_append(SCREEN_OT_region_flip);
2871 WM_operatortype_append(SCREEN_OT_region_scale);
2872 WM_operatortype_append(SCREEN_OT_screen_set);
2873 WM_operatortype_append(SCREEN_OT_screen_full_area);
2874 WM_operatortype_append(SCREEN_OT_screenshot);
2875 WM_operatortype_append(SCREEN_OT_screencast);
2878 WM_operatortype_append(SCREEN_OT_frame_offset);
2879 WM_operatortype_append(SCREEN_OT_animation_step);
2880 WM_operatortype_append(SCREEN_OT_animation_play);
2883 WM_operatortype_append(SCREEN_OT_render);
2884 WM_operatortype_append(SCREEN_OT_render_view_cancel);
2885 WM_operatortype_append(SCREEN_OT_render_view_show);
2887 /* tools shared by more space types */
2888 WM_operatortype_append(ED_OT_undo);
2889 WM_operatortype_append(ED_OT_redo);
2893 static void keymap_modal_set(wmWindowManager *wm)
2895 static EnumPropertyItem modal_items[] = {
2896 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
2897 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
2898 {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
2899 {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
2900 {0, NULL, 0, NULL, NULL}};
2903 /* Standard Modal keymap ------------------------------------------------ */
2904 keymap= WM_modalkeymap_add(wm, "Standard Modal Map", modal_items);
2906 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
2907 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
2908 WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
2909 WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
2911 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
2912 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
2914 WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
2918 /* called in spacetypes.c */
2919 void ED_keymap_screen(wmWindowManager *wm)
2923 /* Screen General ------------------------------------------------ */
2924 keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2926 /* standard timers */
2927 WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
2929 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2930 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2931 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2934 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2935 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2936 WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2937 WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
2938 WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2939 /* area move after action zones */
2940 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2942 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2943 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2944 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2945 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2946 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2947 WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2948 WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2951 WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2952 WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2954 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2955 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2956 WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2957 WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2959 RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
2960 WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
2963 WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2964 WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2967 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2968 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2969 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2970 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2973 WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2974 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2975 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_show", F11KEY, KM_PRESS, 0, 0);
2977 /* Anim Playback ------------------------------------------------ */
2978 keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2981 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2982 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2983 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2984 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
2986 /* play (forward and backwards) */
2987 WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
2988 RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1);
2990 keymap_modal_set(wm);