4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * ***** END GPL LICENSE BLOCK *****
29 #include "MEM_guardedalloc.h"
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_editVert.h"
34 #include "BLI_dlrbTree.h"
36 #include "DNA_armature_types.h"
37 #include "DNA_image_types.h"
38 #include "DNA_lattice_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_scene_types.h"
44 #include "BKE_blender.h"
45 #include "BKE_colortools.h"
46 #include "BKE_context.h"
47 #include "BKE_customdata.h"
48 #include "BKE_global.h"
49 #include "BKE_image.h"
50 #include "BKE_idprop.h"
51 #include "BKE_library.h"
54 #include "BKE_multires.h"
55 #include "BKE_report.h"
56 #include "BKE_screen.h"
57 #include "BKE_utildefines.h"
63 #include "ED_screen.h"
65 #include "ED_object.h"
66 #include "ED_screen_types.h"
67 #include "ED_keyframes_draw.h"
69 #include "RE_pipeline.h"
70 #include "IMB_imbuf.h"
71 #include "IMB_imbuf_types.h"
73 #include "RNA_access.h"
74 #include "RNA_define.h"
76 #include "UI_interface.h"
77 #include "UI_resources.h"
79 #include "wm_window.h"
81 #include "screen_intern.h" /* own module include */
83 #define KM_MODAL_CANCEL 1
84 #define KM_MODAL_APPLY 2
85 #define KM_MODAL_STEP10 3
86 #define KM_MODAL_STEP10_OFF 4
88 /* ************** Exported Poll tests ********************** */
90 int ED_operator_regionactive(bContext *C)
92 if(CTX_wm_window(C)==NULL) return 0;
93 if(CTX_wm_screen(C)==NULL) return 0;
94 if(CTX_wm_region(C)==NULL) return 0;
98 int ED_operator_areaactive(bContext *C)
100 if(CTX_wm_window(C)==NULL) return 0;
101 if(CTX_wm_screen(C)==NULL) return 0;
102 if(CTX_wm_area(C)==NULL) return 0;
106 int ED_operator_screenactive(bContext *C)
108 if(CTX_wm_window(C)==NULL) return 0;
109 if(CTX_wm_screen(C)==NULL) return 0;
113 /* when mouse is over area-edge */
114 int ED_operator_screen_mainwinactive(bContext *C)
116 if(CTX_wm_window(C)==NULL) return 0;
117 if(CTX_wm_screen(C)==NULL) return 0;
118 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
122 int ED_operator_scene_editable(bContext *C)
124 Scene *scene= CTX_data_scene(C);
125 if(scene && scene->id.lib==NULL)
130 static int ed_spacetype_test(bContext *C, int type)
132 if(ED_operator_areaactive(C)) {
133 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
134 return sl && (sl->spacetype == type);
139 int ED_operator_view3d_active(bContext *C)
141 return ed_spacetype_test(C, SPACE_VIEW3D);
144 int ED_operator_timeline_active(bContext *C)
146 return ed_spacetype_test(C, SPACE_TIME);
149 int ED_operator_outliner_active(bContext *C)
151 return ed_spacetype_test(C, SPACE_OUTLINER);
154 int ED_operator_file_active(bContext *C)
156 return ed_spacetype_test(C, SPACE_FILE);
159 int ED_operator_action_active(bContext *C)
161 return ed_spacetype_test(C, SPACE_ACTION);
164 int ED_operator_buttons_active(bContext *C)
166 return ed_spacetype_test(C, SPACE_BUTS);
169 int ED_operator_node_active(bContext *C)
171 if(ed_spacetype_test(C, SPACE_NODE)) {
172 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
180 int ED_operator_ipo_active(bContext *C)
182 return ed_spacetype_test(C, SPACE_IPO);
185 int ED_operator_sequencer_active(bContext *C)
187 return ed_spacetype_test(C, SPACE_SEQ);
190 int ED_operator_image_active(bContext *C)
192 return ed_spacetype_test(C, SPACE_IMAGE);
195 int ED_operator_nla_active(bContext *C)
197 return ed_spacetype_test(C, SPACE_NLA);
200 int ED_operator_logic_active(bContext *C)
202 return ed_spacetype_test(C, SPACE_LOGIC);
205 int ED_operator_object_active(bContext *C)
207 return NULL != CTX_data_active_object(C);
210 int ED_operator_editmesh(bContext *C)
212 Object *obedit= CTX_data_edit_object(C);
213 if(obedit && obedit->type==OB_MESH)
214 return NULL != ((Mesh *)obedit->data)->edit_mesh;
218 int ED_operator_editarmature(bContext *C)
220 Object *obedit= CTX_data_edit_object(C);
221 if(obedit && obedit->type==OB_ARMATURE)
222 return NULL != ((bArmature *)obedit->data)->edbo;
226 int ED_operator_posemode(bContext *C)
228 Object *obact= CTX_data_active_object(C);
229 Object *obedit= CTX_data_edit_object(C);
231 if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
232 return (obact->flag & OB_POSEMODE)!=0;
238 int ED_operator_uvedit(bContext *C)
240 Object *obedit= CTX_data_edit_object(C);
243 if(obedit && obedit->type==OB_MESH)
244 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
246 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
247 BKE_mesh_end_editmesh(obedit->data, em);
252 BKE_mesh_end_editmesh(obedit->data, em);
256 int ED_operator_uvmap(bContext *C)
258 Object *obedit= CTX_data_edit_object(C);
261 if(obedit && obedit->type==OB_MESH)
262 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
264 if(em && (em->faces.first)) {
265 BKE_mesh_end_editmesh(obedit->data, em);
270 BKE_mesh_end_editmesh(obedit->data, em);
274 int ED_operator_editsurfcurve(bContext *C)
276 Object *obedit= CTX_data_edit_object(C);
277 if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
278 return NULL != ((Curve *)obedit->data)->editnurb;
283 int ED_operator_editcurve(bContext *C)
285 Object *obedit= CTX_data_edit_object(C);
286 if(obedit && obedit->type==OB_CURVE)
287 return NULL != ((Curve *)obedit->data)->editnurb;
291 int ED_operator_editsurf(bContext *C)
293 Object *obedit= CTX_data_edit_object(C);
294 if(obedit && obedit->type==OB_SURF)
295 return NULL != ((Curve *)obedit->data)->editnurb;
299 int ED_operator_editfont(bContext *C)
301 Object *obedit= CTX_data_edit_object(C);
302 if(obedit && obedit->type==OB_FONT)
303 return NULL != ((Curve *)obedit->data)->editfont;
307 int ED_operator_editlattice(bContext *C)
309 Object *obedit= CTX_data_edit_object(C);
310 if(obedit && obedit->type==OB_LATTICE)
311 return NULL != ((Lattice *)obedit->data)->editlatt;
315 /* *************************** action zone operator ************************** */
317 /* operator state vars used:
322 apply() set actionzone event
324 exit() free customdata
330 invoke() check if in zone
331 add customdata, put mouseco and area in it
334 modal() accept modal events while doing it
335 call apply() with gesture info, active window, nonactive window
336 call exit() and remove handler when LMB confirm
340 typedef struct sActionzoneData {
343 int x, y, gesture_dir, modifier;
346 /* used by other operators too */
347 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
350 sa= scr->areabase.first;
352 if(BLI_in_rcti(&sa->totrct, x, y)) break;
359 /* quick poll to save operators to be created and handled */
360 static int actionzone_area_poll(bContext *C)
362 wmWindow *win= CTX_wm_window(C);
363 ScrArea *sa= CTX_wm_area(C);
367 int x= win->eventstate->x;
368 int y= win->eventstate->y;
370 for(az= sa->actionzones.first; az; az= az->next)
371 if(BLI_in_rcti(&az->rect, x, y))
377 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
381 for(az= sa->actionzones.first; az; az= az->next) {
382 if(BLI_in_rcti(&az->rect, x, y)) {
383 if(az->type == AZONE_AREA) {
384 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
387 else if(az->type == AZONE_REGION) {
388 float v1[2], v2[2], v3[2], pt[2];
390 v1[0]= az->x1; v1[1]= az->y1;
391 v2[0]= az->x2; v2[1]= az->y2;
392 v3[0]= az->x3; v3[1]= az->y3;
395 if(IsPointInTri2D(v1, v2, v3, pt))
405 static void actionzone_exit(bContext *C, wmOperator *op)
408 MEM_freeN(op->customdata);
409 op->customdata= NULL;
412 /* send EVT_ACTIONZONE event */
413 static void actionzone_apply(bContext *C, wmOperator *op, int type)
416 wmWindow *win= CTX_wm_window(C);
417 sActionzoneData *sad= op->customdata;
419 sad->modifier= RNA_int_get(op->ptr, "modifier");
421 event= *(win->eventstate); /* XXX huh huh? make api call */
423 event.type= EVT_ACTIONZONE_AREA;
425 event.type= EVT_ACTIONZONE_REGION;
426 event.customdata= op->customdata;
427 event.customdatafree= TRUE;
428 op->customdata= NULL;
430 wm_event_add(win, &event);
433 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
435 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
436 sActionzoneData *sad;
440 return OPERATOR_PASS_THROUGH;
442 /* ok we do the actionzone */
443 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
444 sad->sa1= CTX_wm_area(C);
446 sad->x= event->x; sad->y= event->y;
448 /* region azone directly reacts on mouse clicks */
449 if(sad->az->type==AZONE_REGION) {
450 actionzone_apply(C, op, AZONE_REGION);
451 actionzone_exit(C, op);
452 return OPERATOR_FINISHED;
455 /* add modal handler */
456 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
458 return OPERATOR_RUNNING_MODAL;
463 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
465 sActionzoneData *sad= op->customdata;
467 int mindelta= sad->az->type==AZONE_REGION?1:12;
469 switch(event->type) {
471 /* calculate gesture direction */
472 deltax= (event->x - sad->x);
473 deltay= (event->y - sad->y);
475 if(deltay > ABS(deltax))
476 sad->gesture_dir= 'n';
477 else if(deltax > ABS(deltay))
478 sad->gesture_dir= 'e';
479 else if(deltay < -ABS(deltax))
480 sad->gesture_dir= 's';
482 sad->gesture_dir= 'w';
484 /* gesture is large enough? */
485 if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
487 /* second area, for join */
488 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
489 /* apply sends event */
490 actionzone_apply(C, op, sad->az->type);
491 actionzone_exit(C, op);
493 return OPERATOR_FINISHED;
497 actionzone_exit(C, op);
498 return OPERATOR_CANCELLED;
500 actionzone_exit(C, op);
501 return OPERATOR_CANCELLED;
505 return OPERATOR_RUNNING_MODAL;
508 static void SCREEN_OT_actionzone(wmOperatorType *ot)
511 ot->name= "Handle area action zones";
512 ot->idname= "SCREEN_OT_actionzone";
514 ot->invoke= actionzone_invoke;
515 ot->modal= actionzone_modal;
516 ot->poll= actionzone_area_poll;
518 ot->flag= OPTYPE_BLOCKING;
520 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
523 /* ************** swap area operator *********************************** */
525 /* operator state vars used:
527 sa2 area to swap with
531 init() set custom data for operator, based on actionzone event custom data
533 cancel() cancel the operator
535 exit() cleanup, send notifier
539 invoke() gets called on shift+lmb drag in actionzone
540 call init(), add handler
542 modal() accept modal events while doing it
546 typedef struct sAreaSwapData {
550 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
552 sAreaSwapData *sd= NULL;
553 sActionzoneData *sad= event->customdata;
555 if(sad==NULL || sad->sa1==NULL)
558 sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
567 static void area_swap_exit(bContext *C, wmOperator *op)
570 MEM_freeN(op->customdata);
571 op->customdata= NULL;
574 static int area_swap_cancel(bContext *C, wmOperator *op)
576 area_swap_exit(C, op);
577 return OPERATOR_CANCELLED;
580 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
583 if(!area_swap_init(C, op, event))
584 return OPERATOR_PASS_THROUGH;
586 /* add modal handler */
587 WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
588 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
590 return OPERATOR_RUNNING_MODAL;
594 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
596 sActionzoneData *sad= op->customdata;
598 switch(event->type) {
600 /* second area, for join */
601 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
603 case LEFTMOUSE: /* release LMB */
605 if(sad->sa1 == sad->sa2) {
607 return area_swap_cancel(C, op);
609 ED_area_swapspace(C, sad->sa1, sad->sa2);
611 area_swap_exit(C, op);
613 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
615 return OPERATOR_FINISHED;
620 return area_swap_cancel(C, op);
622 return OPERATOR_RUNNING_MODAL;
625 static void SCREEN_OT_area_swap(wmOperatorType *ot)
627 ot->name= "Swap areas";
628 ot->idname= "SCREEN_OT_area_swap";
630 ot->invoke= area_swap_invoke;
631 ot->modal= area_swap_modal;
632 ot->poll= ED_operator_areaactive;
634 ot->flag= OPTYPE_BLOCKING;
637 /* *********** Duplicate area as new window operator ****************** */
639 /* operator callback */
640 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
642 wmWindow *newwin, *win;
647 win= CTX_wm_window(C);
648 sc= CTX_wm_screen(C);
652 if(event->type==EVT_ACTIONZONE_AREA) {
653 sActionzoneData *sad= event->customdata;
656 return OPERATOR_PASS_THROUGH;
661 /* poll() checks area context, but we don't accept full-area windows */
662 if(sc->full != SCREENNORMAL) {
663 if(event->type==EVT_ACTIONZONE_AREA)
664 actionzone_exit(C, op);
665 return OPERATOR_CANCELLED;
668 /* adds window to WM */
670 BLI_translate_rcti(&rect, win->posx, win->posy);
671 newwin= WM_window_open(C, &rect);
673 /* allocs new screen and adds to newly created window, using window size */
674 newsc= ED_screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
675 newwin->screen= newsc;
677 /* copy area to new screen */
678 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
680 /* screen, areas init */
681 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
683 if(event->type==EVT_ACTIONZONE_AREA)
684 actionzone_exit(C, op);
686 return OPERATOR_FINISHED;
689 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
691 ot->name= "Duplicate Area into New Window";
692 ot->idname= "SCREEN_OT_area_dupli";
694 ot->invoke= area_dupli_invoke;
695 ot->poll= ED_operator_areaactive;
699 /* ************** move area edge operator *********************************** */
701 /* operator state vars used:
702 x, y mouse coord near edge
703 delta movement of edge
707 init() set default property values, find edge based on mouse coords, test
708 if the edge can be moved, select edges, calculate min and max movement
710 apply() apply delta on selection
712 exit() cleanup, send notifier
714 cancel() cancel moving
718 exec() execute without any user interaction, based on properties
719 call init(), apply(), exit()
721 invoke() gets called on mouse click near edge
722 call init(), add handler
724 modal() accept modal events while doing it
725 call apply() with delta motion
726 call exit() and remove handler
730 typedef struct sAreaMoveData {
731 int bigger, smaller, origval, step;
735 /* helper call to move area-edge, sets limits */
736 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
740 /* we check all areas and test for free space with MINSIZE */
741 *bigger= *smaller= 100000;
743 for(sa= sc->areabase.first; sa; sa= sa->next) {
745 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
747 /* if top or down edge selected, test height */
748 if(sa->v1->flag && sa->v4->flag)
749 *bigger= MIN2(*bigger, y1);
750 else if(sa->v2->flag && sa->v3->flag)
751 *smaller= MIN2(*smaller, y1);
754 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
756 /* if left or right edge selected, test width */
757 if(sa->v1->flag && sa->v2->flag)
758 *bigger= MIN2(*bigger, x1);
759 else if(sa->v3->flag && sa->v4->flag)
760 *smaller= MIN2(*smaller, x1);
765 /* validate selection inside screen, set variables OK */
766 /* return 0: init failed */
767 static int area_move_init (bContext *C, wmOperator *op)
769 bScreen *sc= CTX_wm_screen(C);
774 /* required properties */
775 x= RNA_int_get(op->ptr, "x");
776 y= RNA_int_get(op->ptr, "y");
779 actedge= screen_find_active_scredge(sc, x, y);
780 if(actedge==NULL) return 0;
782 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
785 md->dir= scredge_is_horizontal(actedge)?'h':'v';
786 if(md->dir=='h') md->origval= actedge->v1->vec.y;
787 else md->origval= actedge->v1->vec.x;
789 select_connected_scredge(sc, actedge);
790 /* now all vertices with 'flag==1' are the ones that can be moved. */
792 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
797 /* moves selected screen edge amount of delta, used by split & move */
798 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
800 wmWindow *win= CTX_wm_window(C);
801 bScreen *sc= CTX_wm_screen(C);
804 delta= CLAMPIS(delta, -smaller, bigger);
806 for (v1= sc->vertbase.first; v1; v1= v1->next) {
808 /* that way a nice AREAGRID */
809 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
810 v1->vec.x= origval + delta;
811 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
813 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
814 v1->vec.y= origval + delta;
816 v1->vec.y+= AREAGRID-1;
817 v1->vec.y-= (v1->vec.y % AREAGRID);
819 /* prevent too small top header */
820 if(v1->vec.y > win->sizey-AREAMINY)
821 v1->vec.y= win->sizey-AREAMINY;
826 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
829 static void area_move_apply(bContext *C, wmOperator *op)
831 sAreaMoveData *md= op->customdata;
834 delta= RNA_int_get(op->ptr, "delta");
835 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
838 static void area_move_exit(bContext *C, wmOperator *op)
841 MEM_freeN(op->customdata);
842 op->customdata= NULL;
844 /* this makes sure aligned edges will result in aligned grabbing */
845 removedouble_scrverts(CTX_wm_screen(C));
846 removedouble_scredges(CTX_wm_screen(C));
849 static int area_move_exec(bContext *C, wmOperator *op)
851 if(!area_move_init(C, op))
852 return OPERATOR_CANCELLED;
854 area_move_apply(C, op);
855 area_move_exit(C, op);
857 return OPERATOR_FINISHED;
860 /* interaction callback */
861 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
863 RNA_int_set(op->ptr, "x", event->x);
864 RNA_int_set(op->ptr, "y", event->y);
866 if(!area_move_init(C, op))
867 return OPERATOR_PASS_THROUGH;
869 /* add temp handler */
870 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
872 return OPERATOR_RUNNING_MODAL;
875 static int area_move_cancel(bContext *C, wmOperator *op)
878 RNA_int_set(op->ptr, "delta", 0);
879 area_move_apply(C, op);
880 area_move_exit(C, op);
882 return OPERATOR_CANCELLED;
885 /* modal callback for while moving edges */
886 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
888 sAreaMoveData *md= op->customdata;
891 /* execute the events */
892 switch(event->type) {
895 x= RNA_int_get(op->ptr, "x");
896 y= RNA_int_get(op->ptr, "y");
898 delta= (md->dir == 'v')? event->x - x: event->y - y;
899 if(md->step) delta= delta - (delta % md->step);
900 RNA_int_set(op->ptr, "delta", delta);
902 area_move_apply(C, op);
907 switch (event->val) {
909 area_move_exit(C, op);
910 return OPERATOR_FINISHED;
912 case KM_MODAL_CANCEL:
913 return area_move_cancel(C, op);
915 case KM_MODAL_STEP10:
918 case KM_MODAL_STEP10_OFF:
924 return OPERATOR_RUNNING_MODAL;
927 static void SCREEN_OT_area_move(wmOperatorType *ot)
930 ot->name= "Move area edges";
931 ot->idname= "SCREEN_OT_area_move";
933 ot->exec= area_move_exec;
934 ot->invoke= area_move_invoke;
935 ot->cancel= area_move_cancel;
936 ot->modal= area_move_modal;
937 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
939 ot->flag= OPTYPE_BLOCKING;
942 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
943 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
944 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
947 /* ************** split area operator *********************************** */
952 dir direction 'v' or 'h'
955 area pointer to (active) area
956 x, y last used mouse pos
961 init() set default property values, find area based on context
963 apply() split area based on state vars
965 exit() cleanup, send notifier
967 cancel() remove duplicated area
971 exec() execute without any user interaction, based on state vars
972 call init(), apply(), exit()
974 invoke() gets called on mouse click in action-widget
975 call init(), add modal handler
976 call apply() with initial motion
978 modal() accept modal events while doing it
979 call move-areas code with delta motion
980 call exit() or cancel() and remove handler
984 #define SPLIT_STARTED 1
985 #define SPLIT_PROGRESS 2
987 typedef struct sAreaSplitData
989 int x, y; /* last used mouse position */
991 int origval; /* for move areas */
992 int bigger, smaller; /* constraints for moving new edge */
993 int delta; /* delta move edge */
994 int origmin, origsize; /* to calculate fac, for property storage */
996 ScrEdge *nedge; /* new edge */
997 ScrArea *sarea; /* start area */
998 ScrArea *narea; /* new area */
1001 /* generic init, no UI stuff here */
1002 static int area_split_init(bContext *C, wmOperator *op)
1004 ScrArea *sa= CTX_wm_area(C);
1008 /* required context */
1009 if(sa==NULL) return 0;
1011 /* required properties */
1012 dir= RNA_enum_get(op->ptr, "direction");
1015 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
1016 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
1019 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1023 sd->origsize= dir=='v' ? sa->winx:sa->winy;
1024 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1029 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1030 /* used with split operator */
1031 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1033 ScrVert *sav1= sa->v1;
1034 ScrVert *sav2= sa->v2;
1035 ScrVert *sav3= sa->v3;
1036 ScrVert *sav4= sa->v4;
1037 ScrVert *sbv1= sb->v1;
1038 ScrVert *sbv2= sb->v2;
1039 ScrVert *sbv3= sb->v3;
1040 ScrVert *sbv4= sb->v4;
1042 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1043 return screen_findedge(screen, sav1, sav2);
1045 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1046 return screen_findedge(screen, sav2, sav3);
1048 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1049 return screen_findedge(screen, sav3, sav4);
1051 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1052 return screen_findedge(screen, sav1, sav4);
1059 /* do the split, return success */
1060 static int area_split_apply(bContext *C, wmOperator *op)
1062 bScreen *sc= CTX_wm_screen(C);
1063 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1067 fac= RNA_float_get(op->ptr, "factor");
1068 dir= RNA_enum_get(op->ptr, "direction");
1070 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1075 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1077 /* select newly created edge, prepare for moving edge */
1078 for(sv= sc->vertbase.first; sv; sv= sv->next)
1081 sd->nedge->v1->flag= 1;
1082 sd->nedge->v2->flag= 1;
1084 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1085 else sd->origval= sd->nedge->v1->vec.x;
1087 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1095 static void area_split_exit(bContext *C, wmOperator *op)
1097 if (op->customdata) {
1098 MEM_freeN(op->customdata);
1099 op->customdata = NULL;
1102 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1104 /* this makes sure aligned edges will result in aligned grabbing */
1105 removedouble_scrverts(CTX_wm_screen(C));
1106 removedouble_scredges(CTX_wm_screen(C));
1110 /* UI callback, adds new handler */
1111 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1115 if(event->type==EVT_ACTIONZONE_AREA) {
1116 sActionzoneData *sad= event->customdata;
1119 if(sad->modifier>0) {
1120 return OPERATOR_PASS_THROUGH;
1123 /* no full window splitting allowed */
1124 if(CTX_wm_area(C)->full)
1125 return OPERATOR_PASS_THROUGH;
1127 /* verify *sad itself */
1128 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1129 return OPERATOR_PASS_THROUGH;
1131 /* is this our *sad? if areas not equal it should be passed on */
1132 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1133 return OPERATOR_PASS_THROUGH;
1135 /* prepare operator state vars */
1136 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1138 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1142 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1144 RNA_enum_set(op->ptr, "direction", dir);
1146 /* general init, also non-UI case, adds customdata, sets area and defaults */
1147 if(!area_split_init(C, op))
1148 return OPERATOR_PASS_THROUGH;
1150 sd= (sAreaSplitData *)op->customdata;
1156 if(area_split_apply(C, op)) {
1157 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1159 /* add temp handler for edge move or cancel */
1160 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1162 return OPERATOR_RUNNING_MODAL;
1167 /* nonmodal for now */
1168 return op->type->exec(C, op);
1171 return OPERATOR_PASS_THROUGH;
1174 /* function to be called outside UI context, or for redo */
1175 static int area_split_exec(bContext *C, wmOperator *op)
1178 if(!area_split_init(C, op))
1179 return OPERATOR_CANCELLED;
1181 area_split_apply(C, op);
1182 area_split_exit(C, op);
1184 return OPERATOR_FINISHED;
1188 static int area_split_cancel(bContext *C, wmOperator *op)
1190 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1192 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1193 if (CTX_wm_area(C) == sd->narea) {
1194 CTX_wm_area_set(C, NULL);
1195 CTX_wm_region_set(C, NULL);
1199 area_split_exit(C, op);
1201 return OPERATOR_CANCELLED;
1204 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1206 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1210 /* execute the events */
1211 switch(event->type) {
1213 dir= RNA_enum_get(op->ptr, "direction");
1215 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1216 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1218 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1219 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1221 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1225 if(event->val==0) { /* mouse up */
1226 area_split_exit(C, op);
1227 return OPERATOR_FINISHED;
1230 case RIGHTMOUSE: /* cancel operation */
1232 return area_split_cancel(C, op);
1235 return OPERATOR_RUNNING_MODAL;
1238 static EnumPropertyItem prop_direction_items[] = {
1239 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1240 {'v', "VERTICAL", 0, "Vertical", ""},
1241 {0, NULL, 0, NULL, NULL}};
1243 static void SCREEN_OT_area_split(wmOperatorType *ot)
1245 ot->name = "Split area";
1246 ot->idname = "SCREEN_OT_area_split";
1248 ot->exec= area_split_exec;
1249 ot->invoke= area_split_invoke;
1250 ot->modal= area_split_modal;
1252 ot->poll= ED_operator_areaactive;
1253 ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
1256 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1257 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1262 /* ************** scale region edge operator *********************************** */
1264 typedef struct RegionMoveData {
1266 int bigger, smaller, origval;
1272 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1274 sActionzoneData *sad= event->customdata;
1278 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1280 op->customdata= rmd;
1283 rmd->edge= az->edge;
1284 rmd->origx= event->x;
1285 rmd->origy= event->y;
1286 if(rmd->edge=='l' || rmd->edge=='r')
1287 rmd->origval= rmd->ar->type->minsizex;
1289 rmd->origval= rmd->ar->type->minsizey;
1291 /* add temp handler */
1292 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1294 return OPERATOR_RUNNING_MODAL;
1297 return OPERATOR_FINISHED;
1300 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1302 RegionMoveData *rmd= op->customdata;
1305 /* execute the events */
1306 switch(event->type) {
1309 if(rmd->edge=='l' || rmd->edge=='r') {
1310 delta= event->x - rmd->origx;
1311 if(rmd->edge=='l') delta= -delta;
1312 rmd->ar->type->minsizex= rmd->origval + delta;
1313 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1314 if(rmd->ar->type->minsizex < 10) {
1315 rmd->ar->type->minsizex= 10;
1316 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1319 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1322 delta= event->y - rmd->origy;
1323 if(rmd->edge=='b') delta= -delta;
1324 rmd->ar->type->minsizey= rmd->origval + delta;
1325 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1326 if(rmd->ar->type->minsizey < 10) {
1327 rmd->ar->type->minsizey= 10;
1328 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1331 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1334 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1341 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1342 rmd->ar->flag ^= RGN_FLAG_HIDDEN;
1343 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1345 MEM_freeN(op->customdata);
1346 op->customdata = NULL;
1348 return OPERATOR_FINISHED;
1356 return OPERATOR_RUNNING_MODAL;
1360 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1363 ot->name= "Scale Region Size";
1364 ot->idname= "SCREEN_OT_region_scale";
1366 ot->invoke= region_scale_invoke;
1367 ot->modal= region_scale_modal;
1369 ot->poll= ED_operator_areaactive;
1371 ot->flag= OPTYPE_BLOCKING;
1375 /* ************** frame change operator ***************************** */
1377 /* function to be called outside UI context, or for redo */
1378 static int frame_offset_exec(bContext *C, wmOperator *op)
1382 delta = RNA_int_get(op->ptr, "delta");
1384 CTX_data_scene(C)->r.cfra += delta;
1386 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1388 return OPERATOR_FINISHED;
1391 static void SCREEN_OT_frame_offset(wmOperatorType *ot)
1393 ot->name = "Frame Offset";
1394 ot->idname = "SCREEN_OT_frame_offset";
1396 ot->exec= frame_offset_exec;
1398 ot->poll= ED_operator_screenactive;
1402 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1405 /* ************** jump to keyframe operator ***************************** */
1407 /* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
1408 // TODO: make this an API func?
1409 static ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next)
1411 ActKeyColumn *akn= NULL;
1417 /* check if this is a match, or whether it is in some subtree */
1418 if (cframe < ak->cfra)
1419 akn= cfra_find_nearest_next_ak(ak->left, cframe, next);
1420 else if (cframe > ak->cfra)
1421 akn= cfra_find_nearest_next_ak(ak->right, cframe, next);
1423 /* if no match found (or found match), just use the current one */
1430 /* function to be called outside UI context, or for redo */
1431 static int keyframe_jump_exec(bContext *C, wmOperator *op)
1433 Scene *scene= CTX_data_scene(C);
1434 Object *ob= CTX_data_active_object(C);
1437 short next= RNA_boolean_get(op->ptr, "next");
1441 return OPERATOR_CANCELLED;
1443 /* init binarytree-list for getting keyframes */
1444 BLI_dlrbTree_init(&keys);
1446 /* populate tree with keyframe nodes */
1447 if (scene && scene->adt)
1448 scene_to_keylist(NULL, scene, &keys, NULL);
1450 ob_to_keylist(NULL, ob, &keys, NULL);
1452 /* build linked-list for searching */
1453 BLI_dlrbTree_linkedlist_sync(&keys);
1455 /* find nearest keyframe in the right direction */
1456 ak= cfra_find_nearest_next_ak(keys.root, (float)scene->r.cfra, next);
1458 /* set the new frame (if keyframe found) */
1460 if (next && ak->next)
1461 scene->r.cfra= (int)ak->next->cfra;
1462 else if (!next && ak->prev)
1463 scene->r.cfra= (int)ak->prev->cfra;
1465 printf("ERROR: no suitable keyframe found. Using %f as new frame \n", ak->cfra);
1466 scene->r.cfra= (int)ak->cfra; // XXX
1470 /* free temp stuff */
1471 BLI_dlrbTree_free(&keys);
1473 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1475 return OPERATOR_FINISHED;
1478 static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
1480 ot->name = "Jump to Keyframe";
1481 ot->idname = "SCREEN_OT_keyframe_jump";
1483 ot->exec= keyframe_jump_exec;
1485 ot->poll= ED_operator_screenactive;
1489 RNA_def_boolean(ot->srna, "next", 1, "Next Keyframe", "");
1492 /* ************** switch screen operator ***************************** */
1495 /* function to be called outside UI context, or for redo */
1496 static int screen_set_exec(bContext *C, wmOperator *op)
1498 bScreen *screen= CTX_wm_screen(C);
1499 ScrArea *sa= CTX_wm_area(C);
1500 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1501 int delta= RNA_int_get(op->ptr, "delta");
1503 /* this screen is 'fake', solve later XXX */
1505 return OPERATOR_CANCELLED;
1509 screen= screen->id.next;
1510 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1511 if(screen->winid==0 && screen->full==0)
1515 else if(delta== -1) {
1517 screen= screen->id.prev;
1518 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1519 if(screen->winid==0 && screen->full==0)
1528 ED_screen_set(C, screen);
1529 return OPERATOR_FINISHED;
1531 return OPERATOR_CANCELLED;
1534 static void SCREEN_OT_screen_set(wmOperatorType *ot)
1536 ot->name = "Set Screen";
1537 ot->idname = "SCREEN_OT_screen_set";
1539 ot->exec= screen_set_exec;
1540 ot->poll= ED_operator_screenactive;
1543 RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1544 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1547 /* ************** screen full-area operator ***************************** */
1550 /* function to be called outside UI context, or for redo */
1551 static int screen_full_area_exec(bContext *C, wmOperator *op)
1553 ed_screen_fullarea(C, CTX_wm_area(C));
1554 return OPERATOR_FINISHED;
1557 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1559 ot->name = "Toggle Make Area Fullscreen";
1560 ot->idname = "SCREEN_OT_screen_full_area";
1562 ot->exec= screen_full_area_exec;
1563 ot->poll= ED_operator_areaactive;
1570 /* ************** join area operator ********************************************** */
1572 /* operator state vars used:
1573 x1, y1 mouse coord in first area, which will disappear
1574 x2, y2 mouse coord in 2nd area, which will become joined
1578 init() find edge based on state vars
1579 test if the edge divides two areas,
1580 store active and nonactive area,
1582 apply() do the actual join
1584 exit() cleanup, send notifier
1588 exec() calls init, apply, exit
1590 invoke() sets mouse coords in x,y
1594 modal() accept modal events while doing it
1595 call apply() with active window and nonactive window
1596 call exit() and remove handler when LMB confirm
1600 typedef struct sAreaJoinData
1602 ScrArea *sa1; /* first area to be considered */
1603 ScrArea *sa2; /* second area to be considered */
1604 ScrArea *scr; /* designed for removal */
1609 /* validate selection inside screen, set variables OK */
1610 /* return 0: init failed */
1611 /* XXX todo: find edge based on (x,y) and set other area? */
1612 static int area_join_init(bContext *C, wmOperator *op)
1615 sAreaJoinData* jd= NULL;
1619 /* required properties, make negative to get return 0 if not set by caller */
1620 x1= RNA_int_get(op->ptr, "x1");
1621 y1= RNA_int_get(op->ptr, "y1");
1622 x2= RNA_int_get(op->ptr, "x2");
1623 y2= RNA_int_get(op->ptr, "y2");
1625 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1626 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1627 if(sa1==NULL || sa2==NULL || sa1==sa2)
1630 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1633 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1635 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1642 /* apply the join of the areas (space types) */
1643 static int area_join_apply(bContext *C, wmOperator *op)
1645 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1648 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1651 if (CTX_wm_area(C) == jd->sa2) {
1652 CTX_wm_area_set(C, NULL);
1653 CTX_wm_region_set(C, NULL);
1659 /* finish operation */
1660 static void area_join_exit(bContext *C, wmOperator *op)
1662 if (op->customdata) {
1663 MEM_freeN(op->customdata);
1664 op->customdata = NULL;
1667 /* this makes sure aligned edges will result in aligned grabbing */
1668 removedouble_scredges(CTX_wm_screen(C));
1669 removenotused_scredges(CTX_wm_screen(C));
1670 removenotused_scrverts(CTX_wm_screen(C));
1673 static int area_join_exec(bContext *C, wmOperator *op)
1675 if(!area_join_init(C, op))
1676 return OPERATOR_CANCELLED;
1678 area_join_apply(C, op);
1679 area_join_exit(C, op);
1681 return OPERATOR_FINISHED;
1684 /* interaction callback */
1685 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1688 if(event->type==EVT_ACTIONZONE_AREA) {
1689 sActionzoneData *sad= event->customdata;
1691 if(sad->modifier>0) {
1692 return OPERATOR_PASS_THROUGH;
1695 /* verify *sad itself */
1696 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1697 return OPERATOR_PASS_THROUGH;
1699 /* is this our *sad? if areas equal it should be passed on */
1700 if(sad->sa1==sad->sa2)
1701 return OPERATOR_PASS_THROUGH;
1703 /* prepare operator state vars */
1704 RNA_int_set(op->ptr, "x1", sad->x);
1705 RNA_int_set(op->ptr, "y1", sad->y);
1706 RNA_int_set(op->ptr, "x2", event->x);
1707 RNA_int_set(op->ptr, "y2", event->y);
1709 if(!area_join_init(C, op))
1710 return OPERATOR_PASS_THROUGH;
1712 /* add temp handler */
1713 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1715 return OPERATOR_RUNNING_MODAL;
1718 return OPERATOR_PASS_THROUGH;
1721 static int area_join_cancel(bContext *C, wmOperator *op)
1723 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1726 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1727 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1730 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1731 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1734 WM_event_add_notifier(C, NC_WINDOW, NULL);
1736 area_join_exit(C, op);
1738 return OPERATOR_CANCELLED;
1741 /* modal callback while selecting area (space) that will be removed */
1742 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1744 bScreen *sc= CTX_wm_screen(C);
1745 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1747 /* execute the events */
1748 switch(event->type) {
1752 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1756 if (jd->sa1 != sa) {
1757 dir = area_getorientation(sc, jd->sa1, sa);
1759 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1761 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1764 /* we are not bordering on the previously selected area
1765 we check if area has common border with the one marked for removal
1766 in this case we can swap areas.
1768 dir = area_getorientation(sc, sa, jd->sa2);
1770 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1771 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1774 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1775 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1778 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1782 WM_event_add_notifier(C, NC_WINDOW, NULL);
1785 /* we are back in the area previously selected for keeping
1786 * we swap the areas if possible to allow user to choose */
1787 if (jd->sa2 != NULL) {
1788 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1789 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1792 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1793 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1794 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1796 printf("oops, didn't expect that!\n");
1800 dir = area_getorientation(sc, jd->sa1, sa);
1802 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1804 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1807 WM_event_add_notifier(C, NC_WINDOW, NULL);
1814 area_join_apply(C, op);
1815 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1816 area_join_exit(C, op);
1817 return OPERATOR_FINISHED;
1822 return area_join_cancel(C, op);
1825 return OPERATOR_RUNNING_MODAL;
1828 /* Operator for joining two areas (space types) */
1829 static void SCREEN_OT_area_join(wmOperatorType *ot)
1832 ot->name= "Join area";
1833 ot->idname= "SCREEN_OT_area_join";
1836 ot->exec= area_join_exec;
1837 ot->invoke= area_join_invoke;
1838 ot->modal= area_join_modal;
1839 ot->poll= ED_operator_areaactive;
1841 ot->flag= OPTYPE_BLOCKING;
1844 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1845 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1846 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1847 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1850 /* ************** repeat last operator ***************************** */
1852 static int repeat_last_exec(bContext *C, wmOperator *op)
1854 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1857 WM_operator_repeat(C, lastop);
1859 return OPERATOR_CANCELLED;
1862 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
1865 ot->name= "Repeat Last";
1866 ot->idname= "SCREEN_OT_repeat_last";
1869 ot->exec= repeat_last_exec;
1871 ot->poll= ED_operator_screenactive;
1875 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1877 wmWindowManager *wm= CTX_wm_manager(C);
1883 items= BLI_countlist(&wm->operators);
1885 return OPERATOR_CANCELLED;
1887 pup= uiPupMenuBegin(C, op->type->name, 0);
1888 layout= uiPupMenuLayout(pup);
1890 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1891 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1893 uiPupMenuEnd(C, pup);
1895 return OPERATOR_CANCELLED;
1898 static int repeat_history_exec(bContext *C, wmOperator *op)
1900 wmWindowManager *wm= CTX_wm_manager(C);
1902 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1904 /* let's put it as last operator in list */
1905 BLI_remlink(&wm->operators, op);
1906 BLI_addtail(&wm->operators, op);
1908 WM_operator_repeat(C, op);
1911 return OPERATOR_FINISHED;
1914 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
1917 ot->name= "Repeat History";
1918 ot->idname= "SCREEN_OT_repeat_history";
1921 ot->invoke= repeat_history_invoke;
1922 ot->exec= repeat_history_exec;
1924 ot->poll= ED_operator_screenactive;
1926 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1929 /* ********************** redo operator ***************************** */
1931 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1933 wmWindowManager *wm= CTX_wm_manager(C);
1936 /* only for operators that are registered and did an undo push */
1937 for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1938 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1942 WM_operator_redo_popup(C, lastop);
1944 return OPERATOR_CANCELLED;
1947 static void SCREEN_OT_redo_last(wmOperatorType *ot)
1950 ot->name= "Redo Last";
1951 ot->idname= "SCREEN_OT_redo_last";
1954 ot->invoke= redo_last_invoke;
1956 ot->poll= ED_operator_screenactive;
1959 /* ************** region split operator ***************************** */
1961 /* insert a region in the area region list */
1962 static int region_split_exec(bContext *C, wmOperator *op)
1964 ARegion *ar= CTX_wm_region(C);
1966 if(ar->regiontype==RGN_TYPE_HEADER)
1967 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1968 else if(ar->alignment==RGN_ALIGN_QSPLIT)
1969 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1971 ScrArea *sa= CTX_wm_area(C);
1972 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1973 int dir= RNA_enum_get(op->ptr, "type");
1975 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1977 newar->alignment= ar->alignment;
1980 ar->alignment= RGN_ALIGN_HSPLIT;
1982 ar->alignment= RGN_ALIGN_VSPLIT;
1984 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1987 return OPERATOR_FINISHED;
1990 static void SCREEN_OT_region_split(wmOperatorType *ot)
1993 ot->name= "Split Region";
1994 ot->idname= "SCREEN_OT_region_split";
1997 ot->invoke= WM_menu_invoke;
1998 ot->exec= region_split_exec;
1999 ot->poll= ED_operator_areaactive;
2001 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
2004 /* ************** region four-split operator ***************************** */
2006 /* insert a region in the area region list */
2007 static int region_foursplit_exec(bContext *C, wmOperator *op)
2009 ARegion *ar= CTX_wm_region(C);
2012 if(ar->regiontype!=RGN_TYPE_WINDOW)
2013 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
2014 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
2015 ScrArea *sa= CTX_wm_area(C);
2018 /* keep current region */
2021 if(sa->spacetype==SPACE_VIEW3D) {
2022 RegionView3D *rv3d= ar->regiondata;
2024 rv3d->rflag &= ~RV3D_CLIPPING;
2027 for(ar= sa->regionbase.first; ar; ar= arn) {
2029 if(ar->alignment==RGN_ALIGN_QSPLIT) {
2030 ED_region_exit(C, ar);
2031 BKE_area_region_free(sa->type, ar);
2032 BLI_remlink(&sa->regionbase, ar);
2036 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2039 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
2041 ScrArea *sa= CTX_wm_area(C);
2045 ar->alignment= RGN_ALIGN_QSPLIT;
2047 for(count=0; count<3; count++) {
2048 newar= BKE_area_region_copy(sa->type, ar);
2049 BLI_addtail(&sa->regionbase, newar);
2052 /* lock views and set them */
2053 if(sa->spacetype==SPACE_VIEW3D) {
2056 rv3d= ar->regiondata;
2057 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
2060 rv3d= ar->regiondata;
2061 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
2064 rv3d= ar->regiondata;
2065 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
2068 rv3d= ar->regiondata;
2069 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
2072 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2076 return OPERATOR_FINISHED;
2079 static void SCREEN_OT_region_foursplit(wmOperatorType *ot)
2082 ot->name= "Split Region in 4 Parts";
2083 ot->idname= "SCREEN_OT_region_foursplit";
2086 // ot->invoke= WM_operator_confirm;
2087 ot->exec= region_foursplit_exec;
2088 ot->poll= ED_operator_areaactive;
2089 ot->flag= OPTYPE_REGISTER;
2094 /* ************** region flip operator ***************************** */
2096 /* flip a region alignment */
2097 static int region_flip_exec(bContext *C, wmOperator *op)
2099 ARegion *ar= CTX_wm_region(C);
2101 if(ar->alignment==RGN_ALIGN_TOP)
2102 ar->alignment= RGN_ALIGN_BOTTOM;
2103 else if(ar->alignment==RGN_ALIGN_BOTTOM)
2104 ar->alignment= RGN_ALIGN_TOP;
2105 else if(ar->alignment==RGN_ALIGN_LEFT)
2106 ar->alignment= RGN_ALIGN_RIGHT;
2107 else if(ar->alignment==RGN_ALIGN_RIGHT)
2108 ar->alignment= RGN_ALIGN_LEFT;
2110 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2111 printf("executed region flip\n");
2113 return OPERATOR_FINISHED;
2117 static void SCREEN_OT_region_flip(wmOperatorType *ot)
2120 ot->name= "Flip Region";
2121 ot->idname= "SCREEN_OT_region_flip";
2124 ot->exec= region_flip_exec;
2126 ot->poll= ED_operator_areaactive;
2127 ot->flag= OPTYPE_REGISTER;
2131 /* ****************** anim player, with timer ***************** */
2133 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2135 if(regiontype==RGN_TYPE_WINDOW) {
2137 switch (spacetype) {
2139 if(redraws & TIME_ALL_3D_WIN)
2145 if(redraws & TIME_ALL_ANIM_WIN)
2149 /* if only 1 window or 3d windows, we do timeline too */
2150 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2154 if(redraws & TIME_ALL_BUTS_WIN)
2158 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2162 if(redraws & TIME_ALL_IMAGE_WIN)
2168 else if(regiontype==RGN_TYPE_UI) {
2169 if(redraws & TIME_ALL_BUTS_WIN)
2172 else if(regiontype==RGN_TYPE_HEADER) {
2173 if(spacetype==SPACE_TIME)
2179 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2181 bScreen *screen= CTX_wm_screen(C);
2183 if(screen->animtimer==event->customdata) {
2184 Scene *scene= CTX_data_scene(C);
2185 wmTimer *wt= screen->animtimer;
2186 ScreenAnimData *sad= wt->customdata;
2189 if(scene->audio.flag & AUDIO_SYNC) {
2190 int step = floor(wt->duration * FPS);
2191 if (sad->reverse) // XXX does this option work with audio?
2192 scene->r.cfra -= step;
2194 scene->r.cfra += step;
2195 wt->duration -= ((float)step)/FPS;
2205 /* jump back to end */
2206 if (scene->r.psfra) {
2207 if(scene->r.cfra < scene->r.psfra)
2208 scene->r.cfra= scene->r.pefra;
2211 if(scene->r.cfra < scene->r.sfra)
2212 scene->r.cfra= scene->r.efra;
2216 /* jump back to start */
2217 if (scene->r.psfra) {
2218 if(scene->r.cfra > scene->r.pefra)
2219 scene->r.cfra= scene->r.psfra;
2222 if(scene->r.cfra > scene->r.efra)
2223 scene->r.cfra= scene->r.sfra;
2227 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2228 ED_update_for_newframe(C, 1);
2230 for(sa= screen->areabase.first; sa; sa= sa->next) {
2232 for(ar= sa->regionbase.first; ar; ar= ar->next) {
2234 ED_region_tag_redraw(ar);
2236 if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2237 ED_region_tag_redraw(ar);
2241 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2243 return OPERATOR_FINISHED;
2245 return OPERATOR_PASS_THROUGH;
2248 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2251 ot->name= "Animation Step";
2252 ot->idname= "SCREEN_OT_animation_step";
2255 ot->invoke= screen_animation_step;
2257 ot->poll= ED_operator_screenactive;
2261 /* ****************** anim player, starts or ends timer ***************** */
2263 /* toggle operator */
2264 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2266 bScreen *screen= CTX_wm_screen(C);
2268 if(screen->animtimer) {
2269 ED_screen_animation_timer(C, 0, 0);
2272 int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2274 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, mode);
2276 if(screen->animtimer) {
2277 wmTimer *wt= screen->animtimer;
2278 ScreenAnimData *sad= wt->customdata;
2280 sad->ar= CTX_wm_region(C);
2284 return OPERATOR_FINISHED;
2287 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2290 ot->name= "Animation player";
2291 ot->idname= "SCREEN_OT_animation_play";
2294 ot->invoke= screen_animation_play;
2296 ot->poll= ED_operator_screenactive;
2298 RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2301 /* ************** border select operator (template) ***************************** */
2303 /* operator state vars used: (added by default WM callbacks)
2307 customdata: the wmGesture pointer
2311 exec() has to be filled in by user
2313 invoke() default WM function
2316 modal() default WM function
2317 accept modal events while doing it, calls exec(), handles ESC and border drawing
2319 poll() has to be filled in by user for context
2322 static int border_select_do(bContext *C, wmOperator *op)
2324 int event_type= RNA_int_get(op->ptr, "event_type");
2326 if(event_type==LEFTMOUSE)
2327 printf("border select do select\n");
2328 else if(event_type==RIGHTMOUSE)
2329 printf("border select deselect\n");
2331 printf("border select do something\n");
2336 static void SCREEN_OT_border_select(wmOperatorType *ot)
2339 ot->name= "Border select";
2340 ot->idname= "SCREEN_OT_border_select";
2343 ot->exec= border_select_do;
2344 ot->invoke= WM_border_select_invoke;
2345 ot->modal= WM_border_select_modal;
2347 ot->poll= ED_operator_areaactive;
2350 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2351 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2352 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2353 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2354 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2359 /* ****************************** render invoking ***************** */
2361 /* set callbacks, exported to sequence render too.
2362 Only call in foreground (UI) renders. */
2364 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2365 /* window as the last possible alternative. */
2366 static ScrArea *biggest_non_image_area(bContext *C)
2368 bScreen *sc= CTX_wm_screen(C);
2369 ScrArea *sa, *big= NULL;
2370 int size, maxsize= 0, bwmaxsize= 0;
2373 for(sa= sc->areabase.first; sa; sa= sa->next) {
2374 if(sa->winx > 30 && sa->winy > 30) {
2375 size= sa->winx*sa->winy;
2376 if(sa->spacetype == SPACE_BUTS) {
2377 if(foundwin == 0 && size > bwmaxsize) {
2382 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2393 static ScrArea *biggest_area(bContext *C)
2395 bScreen *sc= CTX_wm_screen(C);
2396 ScrArea *sa, *big= NULL;
2397 int size, maxsize= 0;
2399 for(sa= sc->areabase.first; sa; sa= sa->next) {
2400 size= sa->winx*sa->winy;
2401 if(size > maxsize) {
2410 static ScrArea *find_area_showing_r_result(bContext *C)
2412 bScreen *sc= CTX_wm_screen(C);
2416 /* find an imagewindow showing render result */
2417 for(sa=sc->areabase.first; sa; sa= sa->next) {
2418 if(sa->spacetype==SPACE_IMAGE) {
2419 sima= sa->spacedata.first;
2420 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2427 static ScrArea *find_area_image_empty(bContext *C)
2429 bScreen *sc= CTX_wm_screen(C);
2433 /* find an imagewindow showing render result */
2434 for(sa=sc->areabase.first; sa; sa= sa->next) {
2435 if(sa->spacetype==SPACE_IMAGE) {
2436 sima= sa->spacedata.first;
2444 #if 0 // XXX not used
2445 static ScrArea *find_empty_image_area(bContext *C)
2447 bScreen *sc= CTX_wm_screen(C);
2451 /* find an imagewindow showing render result */
2452 for(sa=sc->areabase.first; sa; sa= sa->next) {
2453 if(sa->spacetype==SPACE_IMAGE) {
2454 sima= sa->spacedata.first;
2461 #endif // XXX not used
2463 /* new window uses x,y to set position */
2464 static void screen_set_image_output(bContext *C, int mx, int my)
2466 Scene *scene= CTX_data_scene(C);
2470 if(scene->r.displaymode==R_OUTPUT_WINDOW) {
2474 sizex= 10 + (scene->r.xsch*scene->r.size)/100;
2475 sizey= 40 + (scene->r.ysch*scene->r.size)/100;
2477 /* arbitrary... miniature image window views don't make much sense */
2478 if(sizex < 320) sizex= 320;
2479 if(sizey < 256) sizey= 256;
2481 /* XXX some magic to calculate postition */
2482 rect.xmin= mx + CTX_wm_window(C)->posx - sizex/2;
2483 rect.ymin= my + CTX_wm_window(C)->posy - sizey/2;
2484 rect.xmax= rect.xmin + sizex;
2485 rect.ymax= rect.ymin + sizey;
2487 /* changes context! */
2488 WM_window_open_temp(C, &rect, WM_WINDOW_RENDER);
2492 else if(scene->r.displaymode==R_OUTPUT_SCREEN) {
2493 /* this function returns with changed context */
2494 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
2499 sa= find_area_showing_r_result(C);
2501 sa= find_area_image_empty(C);
2504 /* find largest open non-image area */
2505 sa= biggest_non_image_area(C);
2507 ED_area_newspace(C, sa, SPACE_IMAGE);
2508 sima= sa->spacedata.first;
2510 /* makes ESC go back to prev space */
2511 sima->flag |= SI_PREVSPACE;
2514 /* use any area of decent size */
2515 sa= biggest_area(C);
2516 if(sa->spacetype!=SPACE_IMAGE) {
2517 // XXX newspace(sa, SPACE_IMAGE);
2518 sima= sa->spacedata.first;
2520 /* makes ESC go back to prev space */
2521 sima->flag |= SI_PREVSPACE;
2526 sima= sa->spacedata.first;
2528 /* get the correct image, and scale it */
2529 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2531 // if(G.displaymode==2) { // XXX
2533 sima->flag |= SI_FULLWINDOW|SI_PREVSPACE;
2535 // ed_screen_fullarea(C, sa);
2541 /* executes blocking render */
2542 static int screen_render_exec(bContext *C, wmOperator *op)
2544 Scene *scene= CTX_data_scene(C);
2545 Render *re= RE_GetRender(scene->id.name);
2548 re= RE_NewRender(scene->id.name);
2550 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2552 if(RNA_boolean_get(op->ptr, "animation"))
2553 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2555 RE_BlenderFrame(re, scene, scene->r.cfra);
2557 // no redraw needed, we leave state as we entered it
2558 ED_update_for_newframe(C, 1);
2560 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2562 return OPERATOR_FINISHED;
2565 typedef struct RenderJob {
2576 static void render_freejob(void *rjv)
2583 /* str is IMA_RW_MAXTEXT in size */
2584 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
2586 char info_time_str[32]; // used to be extern to header_info.c
2587 uintptr_t mem_in_use, mmap_in_use;
2588 float megs_used_memory, mmap_used_memory;
2591 mem_in_use= MEM_get_memory_in_use();
2592 mmap_in_use= MEM_get_mapped_memory_in_use();
2594 megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
2595 mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
2597 if(scene->lay & 0xFF000000)
2598 spos+= sprintf(spos, "Localview | ");
2599 else if(scene->r.scemode & R_SINGLE_LAYER)
2600 spos+= sprintf(spos, "Single Layer | ");
2603 spos+= sprintf(spos, "%s ", rs->statstr);
2606 spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
2607 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
2608 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
2609 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
2612 spos+= sprintf(spos, "Field %d ", rs->curfield);
2614 spos+= sprintf(spos, "Blur %d ", rs->curblur);
2617 BLI_timestr(rs->lastframetime, info_time_str);
2618 spos+= sprintf(spos, "Time:%s ", info_time_str);
2620 if(rs->infostr && rs->infostr[0])
2621 spos+= sprintf(spos, "| %s ", rs->infostr);
2623 /* very weak... but 512 characters is quite safe */
2624 if(spos >= str+IMA_RW_MAXTEXT)
2625 printf("WARNING! renderwin text beyond limit \n");
2629 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
2633 /* malloc OK here, stats_draw is not in tile threads */
2634 if(rj->image->render_text==NULL)
2635 rj->image->render_text= MEM_callocN(IMA_RW_MAXTEXT, "rendertext");
2637 make_renderinfo_string(rs, rj->scene, rj->image->render_text);
2639 /* make jobs timer to send notifier */
2640 *(rj->do_update)= 1;
2644 /* called inside thread! */
2645 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2649 float x1, y1, *rectf= NULL;
2650 int ymin, ymax, xmin, xmax;
2654 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2655 if(ibuf==NULL) return;
2657 /* if renrect argument, we only refresh scanlines */
2659 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2660 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2663 /* xmin here is first subrect x coord, xmax defines subrect width */
2664 xmin = renrect->xmin + rr->crop;
2665 xmax = renrect->xmax - xmin - rr->crop;
2668 ymin= renrect->ymin + rr->crop;
2669 ymax= renrect->ymax - ymin - rr->crop;
2672 renrect->ymin= renrect->ymax;
2676 xmin = ymin = rr->crop;
2677 xmax = rr->rectx - 2*rr->crop;
2678 ymax = rr->recty - 2*rr->crop;
2681 /* xmin ymin is in tile coords. transform to ibuf */
2682 rxmin= rr->tilerect.xmin + xmin;
2683 if(rxmin >= ibuf->x) return;
2684 rymin= rr->tilerect.ymin + ymin;
2685 if(rymin >= ibuf->y) return;
2687 if(rxmin + xmax > ibuf->x)
2688 xmax= ibuf->x - rxmin;
2689 if(rymin + ymax > ibuf->y)
2690 ymax= ibuf->y - rymin;
2692 if(xmax < 1 || ymax < 1) return;
2694 /* find current float rect for display, first case is after composit... still weak */
2701 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2702 rectf= rr->renlay->rectf;
2705 if(rectf==NULL) return;
2707 rectf+= 4*(rr->rectx*ymin + xmin);
2708 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2710 /* XXX make nice consistent functions for this */
2711 if (rj->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
2712 for(y1= 0; y1<ymax; y1++) {
2717 /* XXX temp. because crop offset */
2718 if( rectc >= (char *)(ibuf->rect)) {
2719 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2720 srgb[0]= linearrgb_to_srgb(rf[0]);
2721 srgb[1]= linearrgb_to_srgb(rf[1]);
2722 srgb[2]= linearrgb_to_srgb(rf[2]);
2724 rc[0]= FTOCHAR(srgb[0]);
2725 rc[1]= FTOCHAR(srgb[1]);
2726 rc[2]= FTOCHAR(srgb[2]);
2727 rc[3]= FTOCHAR(rf[3]);
2730 rectf += 4*rr->rectx;
2734 for(y1= 0; y1<ymax; y1++) {
2738 /* XXX temp. because crop offset */
2739 if( rectc >= (char *)(ibuf->rect)) {
2740 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2741 rc[0]= FTOCHAR(rf[0]);
2742 rc[1]= FTOCHAR(rf[1]);
2743 rc[2]= FTOCHAR(rf[2]);
2744 rc[3]= FTOCHAR(rf[3]);
2747 rectf += 4*rr->rectx;
2752 /* make jobs timer to send notifier */
2753 *(rj->do_update)= 1;
2756 static void render_startjob(void *rjv, short *stop, short *do_update)
2761 rj->do_update= do_update;
2764 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2766 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2769 /* called by render, check job 'stop' value or the global */
2770 static int render_breakjob(void *rjv)
2776 if(rj->stop && *(rj->stop))
2782 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2784 /* no running blender, remove handler and pass through */
2785 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2786 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2788 /* running render */
2789 switch (event->type) {
2791 return OPERATOR_RUNNING_MODAL;
2794 return OPERATOR_PASS_THROUGH;
2797 /* using context, starts job */
2798 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2800 /* new render clears all callbacks */
2801 Scene *scene= CTX_data_scene(C);
2807 /* only one job at a time */
2808 if(WM_jobs_test(CTX_wm_manager(C), scene))
2809 return OPERATOR_CANCELLED;
2811 /* handle UI stuff */
2814 /* flush multires changes (for sculpt) */
2815 multires_force_update(CTX_data_active_object(C));
2817 /* get editmode results */
2818 ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */
2821 // get view3d layer, local layer, make this nice api call to render
2824 /* ensure at least 1 area shows result */
2825 screen_set_image_output(C, event->x, event->y);
2827 /* job custom data */
2828 rj= MEM_callocN(sizeof(RenderJob), "render job");
2830 rj->win= CTX_wm_window(C);
2831 rj->anim= RNA_boolean_get(op->ptr, "animation");
2832 rj->iuser.scene= scene;
2836 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2837 WM_jobs_customdata(steve, rj, render_freejob);
2838 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2839 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2841 /* get a render result image, and make sure it is empty */
2842 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2843 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2846 /* setup new render */
2847 re= RE_NewRender(scene->id.name);
2848 RE_test_break_cb(re, rj, render_breakjob);
2849 RE_display_draw_cb(re, rj, image_rect_update);
2850 RE_stats_draw_cb(re, rj, image_renderinfo_cb);
2855 // BKE_report in render!
2856 // RE_error_cb(re, error_cb);
2858 WM_jobs_start(CTX_wm_manager(C), steve);
2863 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2865 /* add modal handler for ESC */
2866 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2868 return OPERATOR_RUNNING_MODAL;
2872 /* contextual render, using current scene, view3d? */
2873 static void SCREEN_OT_render(wmOperatorType *ot)
2877 ot->idname= "SCREEN_OT_render";
2880 ot->invoke= screen_render_invoke;
2881 ot->modal= screen_render_modal;
2882 ot->exec= screen_render_exec;
2884 ot->poll= ED_operator_screenactive;
2886 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2887 RNA_def_boolean(ot->srna, "animation", 0, "Animation", "");
2890 /* *********************** cancel render viewer *************** */
2892 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2894 ScrArea *sa= CTX_wm_area(C);
2895 SpaceImage *sima= sa->spacedata.first;
2897 /* test if we have a temp screen in front */
2898 if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
2899 wm_window_lower(CTX_wm_window(C));
2901 /* determine if render already shows */
2902 else if(sima->flag & SI_PREVSPACE) {
2903 sima->flag &= ~SI_PREVSPACE;
2905 if(sima->flag & SI_FULLWINDOW) {
2906 sima->flag &= ~SI_FULLWINDOW;
2907 ED_screen_full_prevspace(C);
2910 ED_area_prevspace(C);
2912 else if(sima->flag & SI_FULLWINDOW) {
2913 sima->flag &= ~SI_FULLWINDOW;
2914 ed_screen_fullarea(C, sa);
2917 return OPERATOR_FINISHED;
2920 static void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2923 ot->name= "Cancel Render View";
2924 ot->idname= "SCREEN_OT_render_view_cancel";
2927 ot->exec= render_view_cancel_exec;
2928 ot->poll= ED_operator_image_active;
2931 /* *********************** show render viewer *************** */
2933 static int render_view_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
2935 ScrArea *sa= find_area_showing_r_result(C);
2937 /* test if we have a temp screen in front */
2938 if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
2939 wm_window_lower(CTX_wm_window(C));
2941 /* determine if render already shows */
2943 SpaceImage *sima= sa->spacedata.first;
2945 if(sima->flag & SI_PREVSPACE) {
2946 sima->flag &= ~SI_PREVSPACE;
2948 if(sima->flag & SI_FULLWINDOW) {
2949 sima->flag &= ~SI_FULLWINDOW;
2950 ED_screen_full_prevspace(C);
2952 else if(sima->next) {
2953 ED_area_newspace(C, sa, sima->next->spacetype);
2954 ED_area_tag_redraw(sa);
2959 screen_set_image_output(C, event->x, event->y);
2962 return OPERATOR_FINISHED;
2965 static void SCREEN_OT_render_view_show(struct wmOperatorType *ot)
2968 ot->name= "Show/Hide Render View";
2969 ot->idname= "SCREEN_OT_render_view_show";
2972 ot->invoke= render_view_show_invoke;
2973 ot->poll= ED_operator_screenactive;
2976 /* *********** show user pref window ****** */
2978 static int userpref_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
2987 /* some magic to calculate postition */
2988 rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
2989 rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
2990 rect.xmax= rect.xmin + sizex;
2991 rect.ymax= rect.ymin + sizey;
2993 /* changes context! */
2994 WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
2999 return OPERATOR_FINISHED;
3003 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
3006 ot->name= "Show/Hide User Preferences";
3007 ot->idname= "SCREEN_OT_userpref_show";
3010 ot->invoke= userpref_show_invoke;
3011 ot->poll= ED_operator_screenactive;
3016 /* **************** Assigning operatortypes to global list, adding handlers **************** */
3018 /* called in spacetypes.c */
3019 void ED_operatortypes_screen(void)
3021 /* generic UI stuff */
3022 WM_operatortype_append(SCREEN_OT_actionzone);
3023 WM_operatortype_append(SCREEN_OT_repeat_last);
3024 WM_operatortype_append(SCREEN_OT_repeat_history);
3025 WM_operatortype_append(SCREEN_OT_redo_last);
3028 WM_operatortype_append(SCREEN_OT_area_move);
3029 WM_operatortype_append(SCREEN_OT_area_split);
3030 WM_operatortype_append(SCREEN_OT_area_join);
3031 WM_operatortype_append(SCREEN_OT_area_dupli);
3032 WM_operatortype_append(SCREEN_OT_area_swap);
3033 WM_operatortype_append(SCREEN_OT_region_split);
3034 WM_operatortype_append(SCREEN_OT_region_foursplit);
3035 WM_operatortype_append(SCREEN_OT_region_flip);
3036 WM_operatortype_append(SCREEN_OT_region_scale);
3037 WM_operatortype_append(SCREEN_OT_screen_set);
3038 WM_operatortype_append(SCREEN_OT_screen_full_area);
3039 WM_operatortype_append(SCREEN_OT_screenshot);
3040 WM_operatortype_append(SCREEN_OT_screencast);
3041 WM_operatortype_append(SCREEN_OT_userpref_show);
3044 WM_operatortype_append(SCREEN_OT_frame_offset);
3045 WM_operatortype_append(SCREEN_OT_keyframe_jump);
3047 WM_operatortype_append(SCREEN_OT_animation_step);
3048 WM_operatortype_append(SCREEN_OT_animation_play);
3051 WM_operatortype_append(SCREEN_OT_render);
3052 WM_operatortype_append(SCREEN_OT_render_view_cancel);
3053 WM_operatortype_append(SCREEN_OT_render_view_show);
3055 /* tools shared by more space types */
3056 WM_operatortype_append(ED_OT_undo);
3057 WM_operatortype_append(ED_OT_redo);
3061 static void keymap_modal_set(wmWindowManager *wm)
3063 static EnumPropertyItem modal_items[] = {
3064 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
3065 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
3066 {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
3067 {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
3068 {0, NULL, 0, NULL, NULL}};
3071 /* Standard Modal keymap ------------------------------------------------ */
3072 keymap= WM_modalkeymap_add(wm, "Standard Modal Map", modal_items);
3074 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
3075 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
3076 WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
3077 WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
3079 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
3080 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
3082 WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
3086 /* called in spacetypes.c */
3087 void ED_keymap_screen(wmWindowManager *wm)
3091 /* Screen General ------------------------------------------------ */
3092 keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
3094 /* standard timers */
3095 WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
3097 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
3098 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
3099 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
3102 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
3103 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
3104 WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
3105 WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
3106 WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
3107 /* area move after action zones */
3108 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
3110 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
3111 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
3112 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
3113 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
3114 WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
3115 WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
3118 WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
3119 WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
3121 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
3122 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
3123 WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
3124 WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
3126 RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
3127 WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
3130 WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
3131 WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
3134 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
3135 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
3136 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
3137 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
3140 WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
3141 RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, KM_CTRL, 0)->ptr, "animation", 1);
3142 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
3143 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_show", F11KEY, KM_PRESS, 0, 0);
3146 WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", UKEY, KM_PRESS, KM_ALT, 0);
3148 /* Anim Playback ------------------------------------------------ */
3149 keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
3152 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
3153 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
3154 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
3155 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
3157 WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEUPKEY, KM_PRESS, KM_CTRL, 0);
3158 RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEDOWNKEY, KM_PRESS, KM_CTRL, 0)->ptr, "next", 0);
3160 /* play (forward and backwards) */
3161 WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
3162 RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1);
3164 keymap_modal_set(wm);