4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * ***** END GPL LICENSE BLOCK *****
29 #include "MEM_guardedalloc.h"
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_editVert.h"
34 #include "BLI_dlrbTree.h"
36 #include "DNA_armature_types.h"
37 #include "DNA_image_types.h"
38 #include "DNA_lattice_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_meta_types.h"
45 #include "BKE_blender.h"
46 #include "BKE_colortools.h"
47 #include "BKE_context.h"
48 #include "BKE_customdata.h"
49 #include "BKE_global.h"
50 #include "BKE_image.h"
51 #include "BKE_idprop.h"
52 #include "BKE_library.h"
55 #include "BKE_multires.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 #include "BKE_screen.h"
59 #include "BKE_utildefines.h"
60 #include "BKE_sound.h"
66 #include "ED_screen.h"
68 #include "ED_object.h"
69 #include "ED_screen_types.h"
70 #include "ED_keyframes_draw.h"
72 #include "RE_pipeline.h"
73 #include "IMB_imbuf.h"
74 #include "IMB_imbuf_types.h"
76 #include "RNA_access.h"
77 #include "RNA_define.h"
79 #include "UI_interface.h"
80 #include "UI_resources.h"
82 #include "wm_window.h"
84 #include "screen_intern.h" /* own module include */
86 #define KM_MODAL_CANCEL 1
87 #define KM_MODAL_APPLY 2
88 #define KM_MODAL_STEP10 3
89 #define KM_MODAL_STEP10_OFF 4
91 /* ************** Exported Poll tests ********************** */
93 int ED_operator_regionactive(bContext *C)
95 if(CTX_wm_window(C)==NULL) return 0;
96 if(CTX_wm_screen(C)==NULL) return 0;
97 if(CTX_wm_region(C)==NULL) return 0;
101 int ED_operator_areaactive(bContext *C)
103 if(CTX_wm_window(C)==NULL) return 0;
104 if(CTX_wm_screen(C)==NULL) return 0;
105 if(CTX_wm_area(C)==NULL) return 0;
109 int ED_operator_screenactive(bContext *C)
111 if(CTX_wm_window(C)==NULL) return 0;
112 if(CTX_wm_screen(C)==NULL) return 0;
116 /* when mouse is over area-edge */
117 int ED_operator_screen_mainwinactive(bContext *C)
119 if(CTX_wm_window(C)==NULL) return 0;
120 if(CTX_wm_screen(C)==NULL) return 0;
121 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
125 int ED_operator_scene_editable(bContext *C)
127 Scene *scene= CTX_data_scene(C);
128 if(scene && scene->id.lib==NULL)
133 static int ed_spacetype_test(bContext *C, int type)
135 if(ED_operator_areaactive(C)) {
136 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
137 return sl && (sl->spacetype == type);
142 int ED_operator_view3d_active(bContext *C)
144 return ed_spacetype_test(C, SPACE_VIEW3D);
147 int ED_operator_timeline_active(bContext *C)
149 return ed_spacetype_test(C, SPACE_TIME);
152 int ED_operator_outliner_active(bContext *C)
154 return ed_spacetype_test(C, SPACE_OUTLINER);
157 int ED_operator_file_active(bContext *C)
159 return ed_spacetype_test(C, SPACE_FILE);
162 int ED_operator_action_active(bContext *C)
164 return ed_spacetype_test(C, SPACE_ACTION);
167 int ED_operator_buttons_active(bContext *C)
169 return ed_spacetype_test(C, SPACE_BUTS);
172 int ED_operator_node_active(bContext *C)
174 SpaceNode *snode= CTX_wm_space_node(C);
176 if(snode && snode->edittree)
183 int ED_operator_ipo_active(bContext *C)
185 return ed_spacetype_test(C, SPACE_IPO);
188 int ED_operator_sequencer_active(bContext *C)
190 return ed_spacetype_test(C, SPACE_SEQ);
193 int ED_operator_image_active(bContext *C)
195 return ed_spacetype_test(C, SPACE_IMAGE);
198 int ED_operator_nla_active(bContext *C)
200 return ed_spacetype_test(C, SPACE_NLA);
203 int ED_operator_logic_active(bContext *C)
205 return ed_spacetype_test(C, SPACE_LOGIC);
208 int ED_operator_object_active(bContext *C)
210 return NULL != CTX_data_active_object(C);
213 int ED_operator_editmesh(bContext *C)
215 Object *obedit= CTX_data_edit_object(C);
216 if(obedit && obedit->type==OB_MESH)
217 return NULL != ((Mesh *)obedit->data)->edit_mesh;
221 int ED_operator_editarmature(bContext *C)
223 Object *obedit= CTX_data_edit_object(C);
224 if(obedit && obedit->type==OB_ARMATURE)
225 return NULL != ((bArmature *)obedit->data)->edbo;
229 int ED_operator_posemode(bContext *C)
231 Object *obact= CTX_data_active_object(C);
232 Object *obedit= CTX_data_edit_object(C);
234 if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
235 return (obact->mode & OB_MODE_POSE)!=0;
241 int ED_operator_uvedit(bContext *C)
243 Object *obedit= CTX_data_edit_object(C);
246 if(obedit && obedit->type==OB_MESH)
247 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
249 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
250 BKE_mesh_end_editmesh(obedit->data, em);
255 BKE_mesh_end_editmesh(obedit->data, em);
259 int ED_operator_uvmap(bContext *C)
261 Object *obedit= CTX_data_edit_object(C);
264 if(obedit && obedit->type==OB_MESH)
265 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
267 if(em && (em->faces.first)) {
268 BKE_mesh_end_editmesh(obedit->data, em);
273 BKE_mesh_end_editmesh(obedit->data, em);
277 int ED_operator_editsurfcurve(bContext *C)
279 Object *obedit= CTX_data_edit_object(C);
280 if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
281 return NULL != ((Curve *)obedit->data)->editnurb;
286 int ED_operator_editcurve(bContext *C)
288 Object *obedit= CTX_data_edit_object(C);
289 if(obedit && obedit->type==OB_CURVE)
290 return NULL != ((Curve *)obedit->data)->editnurb;
294 int ED_operator_editsurf(bContext *C)
296 Object *obedit= CTX_data_edit_object(C);
297 if(obedit && obedit->type==OB_SURF)
298 return NULL != ((Curve *)obedit->data)->editnurb;
302 int ED_operator_editfont(bContext *C)
304 Object *obedit= CTX_data_edit_object(C);
305 if(obedit && obedit->type==OB_FONT)
306 return NULL != ((Curve *)obedit->data)->editfont;
310 int ED_operator_editlattice(bContext *C)
312 Object *obedit= CTX_data_edit_object(C);
313 if(obedit && obedit->type==OB_LATTICE)
314 return NULL != ((Lattice *)obedit->data)->editlatt;
318 int ED_operator_editmball(bContext *C)
320 Object *obedit= CTX_data_edit_object(C);
321 if(obedit && obedit->type==OB_MBALL)
322 return NULL != ((MetaBall *)obedit->data)->editelems;
326 /* *************************** action zone operator ************************** */
328 /* operator state vars used:
333 apply() set actionzone event
335 exit() free customdata
341 invoke() check if in zone
342 add customdata, put mouseco and area in it
345 modal() accept modal events while doing it
346 call apply() with gesture info, active window, nonactive window
347 call exit() and remove handler when LMB confirm
351 typedef struct sActionzoneData {
354 int x, y, gesture_dir, modifier;
357 /* used by other operators too */
358 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
361 sa= scr->areabase.first;
363 if(BLI_in_rcti(&sa->totrct, x, y)) break;
370 /* quick poll to save operators to be created and handled */
371 static int actionzone_area_poll(bContext *C)
373 wmWindow *win= CTX_wm_window(C);
374 ScrArea *sa= CTX_wm_area(C);
378 int x= win->eventstate->x;
379 int y= win->eventstate->y;
381 for(az= sa->actionzones.first; az; az= az->next)
382 if(BLI_in_rcti(&az->rect, x, y))
388 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
392 for(az= sa->actionzones.first; az; az= az->next) {
393 if(BLI_in_rcti(&az->rect, x, y)) {
394 if(az->type == AZONE_AREA) {
395 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
398 else if(az->type == AZONE_REGION) {
399 float v1[2], v2[2], v3[2], pt[2];
401 v1[0]= az->x1; v1[1]= az->y1;
402 v2[0]= az->x2; v2[1]= az->y2;
403 v3[0]= az->x3; v3[1]= az->y3;
406 if(IsPointInTri2D(v1, v2, v3, pt))
416 static void actionzone_exit(bContext *C, wmOperator *op)
419 MEM_freeN(op->customdata);
420 op->customdata= NULL;
423 /* send EVT_ACTIONZONE event */
424 static void actionzone_apply(bContext *C, wmOperator *op, int type)
427 wmWindow *win= CTX_wm_window(C);
428 sActionzoneData *sad= op->customdata;
430 sad->modifier= RNA_int_get(op->ptr, "modifier");
432 event= *(win->eventstate); /* XXX huh huh? make api call */
434 event.type= EVT_ACTIONZONE_AREA;
436 event.type= EVT_ACTIONZONE_REGION;
437 event.customdata= op->customdata;
438 event.customdatafree= TRUE;
439 op->customdata= NULL;
441 wm_event_add(win, &event);
444 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
446 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
447 sActionzoneData *sad;
451 return OPERATOR_PASS_THROUGH;
453 /* ok we do the actionzone */
454 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
455 sad->sa1= CTX_wm_area(C);
457 sad->x= event->x; sad->y= event->y;
459 /* region azone directly reacts on mouse clicks */
460 if(sad->az->type==AZONE_REGION) {
461 actionzone_apply(C, op, AZONE_REGION);
462 actionzone_exit(C, op);
463 return OPERATOR_FINISHED;
466 /* add modal handler */
467 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
469 return OPERATOR_RUNNING_MODAL;
474 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
476 sActionzoneData *sad= op->customdata;
478 int mindelta= sad->az->type==AZONE_REGION?1:12;
480 switch(event->type) {
482 /* calculate gesture direction */
483 deltax= (event->x - sad->x);
484 deltay= (event->y - sad->y);
486 if(deltay > ABS(deltax))
487 sad->gesture_dir= 'n';
488 else if(deltax > ABS(deltay))
489 sad->gesture_dir= 'e';
490 else if(deltay < -ABS(deltax))
491 sad->gesture_dir= 's';
493 sad->gesture_dir= 'w';
495 /* gesture is large enough? */
496 if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
498 /* second area, for join */
499 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
500 /* apply sends event */
501 actionzone_apply(C, op, sad->az->type);
502 actionzone_exit(C, op);
504 return OPERATOR_FINISHED;
508 actionzone_exit(C, op);
509 return OPERATOR_CANCELLED;
511 actionzone_exit(C, op);
512 return OPERATOR_CANCELLED;
516 return OPERATOR_RUNNING_MODAL;
519 static void SCREEN_OT_actionzone(wmOperatorType *ot)
522 ot->name= "Handle area action zones";
523 ot->idname= "SCREEN_OT_actionzone";
525 ot->invoke= actionzone_invoke;
526 ot->modal= actionzone_modal;
527 ot->poll= actionzone_area_poll;
529 ot->flag= OPTYPE_BLOCKING;
531 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
534 /* ************** swap area operator *********************************** */
536 /* operator state vars used:
538 sa2 area to swap with
542 init() set custom data for operator, based on actionzone event custom data
544 cancel() cancel the operator
546 exit() cleanup, send notifier
550 invoke() gets called on shift+lmb drag in actionzone
551 call init(), add handler
553 modal() accept modal events while doing it
557 typedef struct sAreaSwapData {
561 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
563 sAreaSwapData *sd= NULL;
564 sActionzoneData *sad= event->customdata;
566 if(sad==NULL || sad->sa1==NULL)
569 sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
578 static void area_swap_exit(bContext *C, wmOperator *op)
581 MEM_freeN(op->customdata);
582 op->customdata= NULL;
585 static int area_swap_cancel(bContext *C, wmOperator *op)
587 area_swap_exit(C, op);
588 return OPERATOR_CANCELLED;
591 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
594 if(!area_swap_init(C, op, event))
595 return OPERATOR_PASS_THROUGH;
597 /* add modal handler */
598 WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
599 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
601 return OPERATOR_RUNNING_MODAL;
605 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
607 sActionzoneData *sad= op->customdata;
609 switch(event->type) {
611 /* second area, for join */
612 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
614 case LEFTMOUSE: /* release LMB */
616 if(sad->sa1 == sad->sa2) {
618 return area_swap_cancel(C, op);
620 ED_area_swapspace(C, sad->sa1, sad->sa2);
622 area_swap_exit(C, op);
624 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
626 return OPERATOR_FINISHED;
631 return area_swap_cancel(C, op);
633 return OPERATOR_RUNNING_MODAL;
636 static void SCREEN_OT_area_swap(wmOperatorType *ot)
638 ot->name= "Swap areas";
639 ot->idname= "SCREEN_OT_area_swap";
641 ot->invoke= area_swap_invoke;
642 ot->modal= area_swap_modal;
643 ot->poll= ED_operator_areaactive;
645 ot->flag= OPTYPE_BLOCKING;
648 /* *********** Duplicate area as new window operator ****************** */
650 /* operator callback */
651 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
653 wmWindow *newwin, *win;
658 win= CTX_wm_window(C);
659 sc= CTX_wm_screen(C);
663 if(event->type==EVT_ACTIONZONE_AREA) {
664 sActionzoneData *sad= event->customdata;
667 return OPERATOR_PASS_THROUGH;
672 /* poll() checks area context, but we don't accept full-area windows */
673 if(sc->full != SCREENNORMAL) {
674 if(event->type==EVT_ACTIONZONE_AREA)
675 actionzone_exit(C, op);
676 return OPERATOR_CANCELLED;
679 /* adds window to WM */
681 BLI_translate_rcti(&rect, win->posx, win->posy);
682 newwin= WM_window_open(C, &rect);
684 /* allocs new screen and adds to newly created window, using window size */
685 newsc= ED_screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
686 newwin->screen= newsc;
688 /* copy area to new screen */
689 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
691 /* screen, areas init */
692 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
694 if(event->type==EVT_ACTIONZONE_AREA)
695 actionzone_exit(C, op);
697 return OPERATOR_FINISHED;
700 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
702 ot->name= "Duplicate Area into New Window";
703 ot->idname= "SCREEN_OT_area_dupli";
705 ot->invoke= area_dupli_invoke;
706 ot->poll= ED_operator_areaactive;
710 /* ************** move area edge operator *********************************** */
712 /* operator state vars used:
713 x, y mouse coord near edge
714 delta movement of edge
718 init() set default property values, find edge based on mouse coords, test
719 if the edge can be moved, select edges, calculate min and max movement
721 apply() apply delta on selection
723 exit() cleanup, send notifier
725 cancel() cancel moving
729 exec() execute without any user interaction, based on properties
730 call init(), apply(), exit()
732 invoke() gets called on mouse click near edge
733 call init(), add handler
735 modal() accept modal events while doing it
736 call apply() with delta motion
737 call exit() and remove handler
741 typedef struct sAreaMoveData {
742 int bigger, smaller, origval, step;
746 /* helper call to move area-edge, sets limits */
747 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
751 /* we check all areas and test for free space with MINSIZE */
752 *bigger= *smaller= 100000;
754 for(sa= sc->areabase.first; sa; sa= sa->next) {
756 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
758 /* if top or down edge selected, test height */
759 if(sa->v1->flag && sa->v4->flag)
760 *bigger= MIN2(*bigger, y1);
761 else if(sa->v2->flag && sa->v3->flag)
762 *smaller= MIN2(*smaller, y1);
765 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
767 /* if left or right edge selected, test width */
768 if(sa->v1->flag && sa->v2->flag)
769 *bigger= MIN2(*bigger, x1);
770 else if(sa->v3->flag && sa->v4->flag)
771 *smaller= MIN2(*smaller, x1);
776 /* validate selection inside screen, set variables OK */
777 /* return 0: init failed */
778 static int area_move_init (bContext *C, wmOperator *op)
780 bScreen *sc= CTX_wm_screen(C);
785 /* required properties */
786 x= RNA_int_get(op->ptr, "x");
787 y= RNA_int_get(op->ptr, "y");
790 actedge= screen_find_active_scredge(sc, x, y);
791 if(actedge==NULL) return 0;
793 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
796 md->dir= scredge_is_horizontal(actedge)?'h':'v';
797 if(md->dir=='h') md->origval= actedge->v1->vec.y;
798 else md->origval= actedge->v1->vec.x;
800 select_connected_scredge(sc, actedge);
801 /* now all vertices with 'flag==1' are the ones that can be moved. */
803 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
808 /* moves selected screen edge amount of delta, used by split & move */
809 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
811 wmWindow *win= CTX_wm_window(C);
812 bScreen *sc= CTX_wm_screen(C);
815 delta= CLAMPIS(delta, -smaller, bigger);
817 for (v1= sc->vertbase.first; v1; v1= v1->next) {
819 /* that way a nice AREAGRID */
820 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
821 v1->vec.x= origval + delta;
822 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
824 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
825 v1->vec.y= origval + delta;
827 v1->vec.y+= AREAGRID-1;
828 v1->vec.y-= (v1->vec.y % AREAGRID);
830 /* prevent too small top header */
831 if(v1->vec.y > win->sizey-AREAMINY)
832 v1->vec.y= win->sizey-AREAMINY;
837 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
840 static void area_move_apply(bContext *C, wmOperator *op)
842 sAreaMoveData *md= op->customdata;
845 delta= RNA_int_get(op->ptr, "delta");
846 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
849 static void area_move_exit(bContext *C, wmOperator *op)
852 MEM_freeN(op->customdata);
853 op->customdata= NULL;
855 /* this makes sure aligned edges will result in aligned grabbing */
856 removedouble_scrverts(CTX_wm_screen(C));
857 removedouble_scredges(CTX_wm_screen(C));
860 static int area_move_exec(bContext *C, wmOperator *op)
862 if(!area_move_init(C, op))
863 return OPERATOR_CANCELLED;
865 area_move_apply(C, op);
866 area_move_exit(C, op);
868 return OPERATOR_FINISHED;
871 /* interaction callback */
872 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
874 RNA_int_set(op->ptr, "x", event->x);
875 RNA_int_set(op->ptr, "y", event->y);
877 if(!area_move_init(C, op))
878 return OPERATOR_PASS_THROUGH;
880 /* add temp handler */
881 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
883 return OPERATOR_RUNNING_MODAL;
886 static int area_move_cancel(bContext *C, wmOperator *op)
889 RNA_int_set(op->ptr, "delta", 0);
890 area_move_apply(C, op);
891 area_move_exit(C, op);
893 return OPERATOR_CANCELLED;
896 /* modal callback for while moving edges */
897 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
899 sAreaMoveData *md= op->customdata;
902 /* execute the events */
903 switch(event->type) {
906 x= RNA_int_get(op->ptr, "x");
907 y= RNA_int_get(op->ptr, "y");
909 delta= (md->dir == 'v')? event->x - x: event->y - y;
910 if(md->step) delta= delta - (delta % md->step);
911 RNA_int_set(op->ptr, "delta", delta);
913 area_move_apply(C, op);
918 switch (event->val) {
920 area_move_exit(C, op);
921 return OPERATOR_FINISHED;
923 case KM_MODAL_CANCEL:
924 return area_move_cancel(C, op);
926 case KM_MODAL_STEP10:
929 case KM_MODAL_STEP10_OFF:
935 return OPERATOR_RUNNING_MODAL;
938 static void SCREEN_OT_area_move(wmOperatorType *ot)
941 ot->name= "Move area edges";
942 ot->idname= "SCREEN_OT_area_move";
944 ot->exec= area_move_exec;
945 ot->invoke= area_move_invoke;
946 ot->cancel= area_move_cancel;
947 ot->modal= area_move_modal;
948 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
950 ot->flag= OPTYPE_BLOCKING;
953 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
954 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
955 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
958 /* ************** split area operator *********************************** */
963 dir direction 'v' or 'h'
966 area pointer to (active) area
967 x, y last used mouse pos
972 init() set default property values, find area based on context
974 apply() split area based on state vars
976 exit() cleanup, send notifier
978 cancel() remove duplicated area
982 exec() execute without any user interaction, based on state vars
983 call init(), apply(), exit()
985 invoke() gets called on mouse click in action-widget
986 call init(), add modal handler
987 call apply() with initial motion
989 modal() accept modal events while doing it
990 call move-areas code with delta motion
991 call exit() or cancel() and remove handler
995 #define SPLIT_STARTED 1
996 #define SPLIT_PROGRESS 2
998 typedef struct sAreaSplitData
1000 int x, y; /* last used mouse position */
1002 int origval; /* for move areas */
1003 int bigger, smaller; /* constraints for moving new edge */
1004 int delta; /* delta move edge */
1005 int origmin, origsize; /* to calculate fac, for property storage */
1007 ScrEdge *nedge; /* new edge */
1008 ScrArea *sarea; /* start area */
1009 ScrArea *narea; /* new area */
1012 /* generic init, no UI stuff here */
1013 static int area_split_init(bContext *C, wmOperator *op)
1015 ScrArea *sa= CTX_wm_area(C);
1019 /* required context */
1020 if(sa==NULL) return 0;
1022 /* required properties */
1023 dir= RNA_enum_get(op->ptr, "direction");
1026 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
1027 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
1030 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1034 sd->origsize= dir=='v' ? sa->winx:sa->winy;
1035 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1040 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1041 /* used with split operator */
1042 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1044 ScrVert *sav1= sa->v1;
1045 ScrVert *sav2= sa->v2;
1046 ScrVert *sav3= sa->v3;
1047 ScrVert *sav4= sa->v4;
1048 ScrVert *sbv1= sb->v1;
1049 ScrVert *sbv2= sb->v2;
1050 ScrVert *sbv3= sb->v3;
1051 ScrVert *sbv4= sb->v4;
1053 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1054 return screen_findedge(screen, sav1, sav2);
1056 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1057 return screen_findedge(screen, sav2, sav3);
1059 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1060 return screen_findedge(screen, sav3, sav4);
1062 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1063 return screen_findedge(screen, sav1, sav4);
1070 /* do the split, return success */
1071 static int area_split_apply(bContext *C, wmOperator *op)
1073 bScreen *sc= CTX_wm_screen(C);
1074 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1078 fac= RNA_float_get(op->ptr, "factor");
1079 dir= RNA_enum_get(op->ptr, "direction");
1081 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1086 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1088 /* select newly created edge, prepare for moving edge */
1089 for(sv= sc->vertbase.first; sv; sv= sv->next)
1092 sd->nedge->v1->flag= 1;
1093 sd->nedge->v2->flag= 1;
1095 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1096 else sd->origval= sd->nedge->v1->vec.x;
1098 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1106 static void area_split_exit(bContext *C, wmOperator *op)
1108 if (op->customdata) {
1109 MEM_freeN(op->customdata);
1110 op->customdata = NULL;
1113 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1115 /* this makes sure aligned edges will result in aligned grabbing */
1116 removedouble_scrverts(CTX_wm_screen(C));
1117 removedouble_scredges(CTX_wm_screen(C));
1121 /* UI callback, adds new handler */
1122 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1126 if(event->type==EVT_ACTIONZONE_AREA) {
1127 sActionzoneData *sad= event->customdata;
1130 if(sad->modifier>0) {
1131 return OPERATOR_PASS_THROUGH;
1134 /* no full window splitting allowed */
1135 if(CTX_wm_area(C)->full)
1136 return OPERATOR_PASS_THROUGH;
1138 /* verify *sad itself */
1139 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1140 return OPERATOR_PASS_THROUGH;
1142 /* is this our *sad? if areas not equal it should be passed on */
1143 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1144 return OPERATOR_PASS_THROUGH;
1146 /* prepare operator state vars */
1147 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1149 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1153 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1155 RNA_enum_set(op->ptr, "direction", dir);
1157 /* general init, also non-UI case, adds customdata, sets area and defaults */
1158 if(!area_split_init(C, op))
1159 return OPERATOR_PASS_THROUGH;
1161 sd= (sAreaSplitData *)op->customdata;
1167 if(area_split_apply(C, op)) {
1168 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1170 /* add temp handler for edge move or cancel */
1171 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1173 return OPERATOR_RUNNING_MODAL;
1178 /* nonmodal for now */
1179 return op->type->exec(C, op);
1182 return OPERATOR_PASS_THROUGH;
1185 /* function to be called outside UI context, or for redo */
1186 static int area_split_exec(bContext *C, wmOperator *op)
1189 if(!area_split_init(C, op))
1190 return OPERATOR_CANCELLED;
1192 area_split_apply(C, op);
1193 area_split_exit(C, op);
1195 return OPERATOR_FINISHED;
1199 static int area_split_cancel(bContext *C, wmOperator *op)
1201 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1203 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1204 if (CTX_wm_area(C) == sd->narea) {
1205 CTX_wm_area_set(C, NULL);
1206 CTX_wm_region_set(C, NULL);
1210 area_split_exit(C, op);
1212 return OPERATOR_CANCELLED;
1215 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1217 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1221 /* execute the events */
1222 switch(event->type) {
1224 dir= RNA_enum_get(op->ptr, "direction");
1226 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1227 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1229 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1230 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1232 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1236 if(event->val==0) { /* mouse up */
1237 area_split_exit(C, op);
1238 return OPERATOR_FINISHED;
1241 case RIGHTMOUSE: /* cancel operation */
1243 return area_split_cancel(C, op);
1246 return OPERATOR_RUNNING_MODAL;
1249 static EnumPropertyItem prop_direction_items[] = {
1250 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1251 {'v', "VERTICAL", 0, "Vertical", ""},
1252 {0, NULL, 0, NULL, NULL}};
1254 static void SCREEN_OT_area_split(wmOperatorType *ot)
1256 ot->name = "Split area";
1257 ot->idname = "SCREEN_OT_area_split";
1259 ot->exec= area_split_exec;
1260 ot->invoke= area_split_invoke;
1261 ot->modal= area_split_modal;
1263 ot->poll= ED_operator_areaactive;
1264 ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
1267 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1268 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1273 /* ************** scale region edge operator *********************************** */
1275 typedef struct RegionMoveData {
1277 int bigger, smaller, origval;
1283 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1285 sActionzoneData *sad= event->customdata;
1289 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1291 op->customdata= rmd;
1294 rmd->edge= az->edge;
1295 rmd->origx= event->x;
1296 rmd->origy= event->y;
1297 if(rmd->edge=='l' || rmd->edge=='r')
1298 rmd->origval= rmd->ar->type->minsizex;
1300 rmd->origval= rmd->ar->type->minsizey;
1302 /* add temp handler */
1303 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1305 return OPERATOR_RUNNING_MODAL;
1308 return OPERATOR_FINISHED;
1311 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1313 RegionMoveData *rmd= op->customdata;
1316 /* execute the events */
1317 switch(event->type) {
1320 if(rmd->edge=='l' || rmd->edge=='r') {
1321 delta= event->x - rmd->origx;
1322 if(rmd->edge=='l') delta= -delta;
1323 rmd->ar->type->minsizex= rmd->origval + delta;
1324 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1325 if(rmd->ar->type->minsizex < 10) {
1326 rmd->ar->type->minsizex= 10;
1327 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1330 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1333 delta= event->y - rmd->origy;
1334 if(rmd->edge=='b') delta= -delta;
1335 rmd->ar->type->minsizey= rmd->origval + delta;
1336 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1337 if(rmd->ar->type->minsizey < 10) {
1338 rmd->ar->type->minsizey= 10;
1339 rmd->ar->flag |= RGN_FLAG_HIDDEN;
1342 rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1345 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1352 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1353 rmd->ar->flag ^= RGN_FLAG_HIDDEN;
1354 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1356 MEM_freeN(op->customdata);
1357 op->customdata = NULL;
1359 return OPERATOR_FINISHED;
1367 return OPERATOR_RUNNING_MODAL;
1371 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1374 ot->name= "Scale Region Size";
1375 ot->idname= "SCREEN_OT_region_scale";
1377 ot->invoke= region_scale_invoke;
1378 ot->modal= region_scale_modal;
1380 ot->poll= ED_operator_areaactive;
1382 ot->flag= OPTYPE_BLOCKING;
1386 /* ************** frame change operator ***************************** */
1388 /* function to be called outside UI context, or for redo */
1389 static int frame_offset_exec(bContext *C, wmOperator *op)
1393 delta = RNA_int_get(op->ptr, "delta");
1395 CTX_data_scene(C)->r.cfra += delta;
1397 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1399 return OPERATOR_FINISHED;
1402 static void SCREEN_OT_frame_offset(wmOperatorType *ot)
1404 ot->name = "Frame Offset";
1405 ot->idname = "SCREEN_OT_frame_offset";
1407 ot->exec= frame_offset_exec;
1409 ot->poll= ED_operator_screenactive;
1413 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1417 /* function to be called outside UI context, or for redo */
1418 static int frame_jump_exec(bContext *C, wmOperator *op)
1420 Scene *scene= CTX_data_scene(C);
1422 if (RNA_boolean_get(op->ptr, "end"))
1427 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1429 return OPERATOR_FINISHED;
1432 static void SCREEN_OT_frame_jump(wmOperatorType *ot)
1434 ot->name = "Jump to Endpoint";
1435 ot->idname = "SCREEN_OT_frame_jump";
1437 ot->exec= frame_jump_exec;
1439 ot->poll= ED_operator_screenactive;
1443 RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range.");
1447 /* ************** jump to keyframe operator ***************************** */
1449 /* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
1450 // TODO: make this an API func?
1451 static ActKeyColumn *cfra_find_nearest_next_ak (ActKeyColumn *ak, float cframe, short next)
1453 ActKeyColumn *akn= NULL;
1459 /* check if this is a match, or whether it is in some subtree */
1460 if (cframe < ak->cfra)
1461 akn= cfra_find_nearest_next_ak(ak->left, cframe, next);
1462 else if (cframe > ak->cfra)
1463 akn= cfra_find_nearest_next_ak(ak->right, cframe, next);
1465 /* if no match found (or found match), just use the current one */
1472 /* function to be called outside UI context, or for redo */
1473 static int keyframe_jump_exec(bContext *C, wmOperator *op)
1475 Scene *scene= CTX_data_scene(C);
1476 Object *ob= CTX_data_active_object(C);
1479 short next= RNA_boolean_get(op->ptr, "next");
1483 return OPERATOR_CANCELLED;
1485 /* init binarytree-list for getting keyframes */
1486 BLI_dlrbTree_init(&keys);
1488 /* populate tree with keyframe nodes */
1489 if (scene && scene->adt)
1490 scene_to_keylist(NULL, scene, &keys, NULL);
1492 ob_to_keylist(NULL, ob, &keys, NULL);
1494 /* build linked-list for searching */
1495 BLI_dlrbTree_linkedlist_sync(&keys);
1497 /* find nearest keyframe in the right direction */
1498 ak= cfra_find_nearest_next_ak(keys.root, (float)scene->r.cfra, next);
1500 /* set the new frame (if keyframe found) */
1502 if (next && ak->next)
1503 scene->r.cfra= (int)ak->next->cfra;
1504 else if (!next && ak->prev)
1505 scene->r.cfra= (int)ak->prev->cfra;
1507 printf("ERROR: no suitable keyframe found. Using %f as new frame \n", ak->cfra);
1508 scene->r.cfra= (int)ak->cfra; // XXX
1512 /* free temp stuff */
1513 BLI_dlrbTree_free(&keys);
1515 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1517 return OPERATOR_FINISHED;
1520 static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
1522 ot->name = "Jump to Keyframe";
1523 ot->idname = "SCREEN_OT_keyframe_jump";
1525 ot->exec= keyframe_jump_exec;
1527 ot->poll= ED_operator_screenactive;
1531 RNA_def_boolean(ot->srna, "next", 1, "Next Keyframe", "");
1534 /* ************** switch screen operator ***************************** */
1537 /* function to be called outside UI context, or for redo */
1538 static int screen_set_exec(bContext *C, wmOperator *op)
1540 bScreen *screen= CTX_wm_screen(C);
1541 ScrArea *sa= CTX_wm_area(C);
1542 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1543 int delta= RNA_int_get(op->ptr, "delta");
1545 /* this screen is 'fake', solve later XXX */
1547 return OPERATOR_CANCELLED;
1551 screen= screen->id.next;
1552 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1553 if(screen->winid==0 && screen->full==0)
1557 else if(delta== -1) {
1559 screen= screen->id.prev;
1560 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1561 if(screen->winid==0 && screen->full==0)
1570 ED_screen_set(C, screen);
1571 return OPERATOR_FINISHED;
1573 return OPERATOR_CANCELLED;
1576 static void SCREEN_OT_screen_set(wmOperatorType *ot)
1578 ot->name = "Set Screen";
1579 ot->idname = "SCREEN_OT_screen_set";
1581 ot->exec= screen_set_exec;
1582 ot->poll= ED_operator_screenactive;
1585 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1588 /* ************** screen full-area operator ***************************** */
1591 /* function to be called outside UI context, or for redo */
1592 static int screen_full_area_exec(bContext *C, wmOperator *op)
1594 ed_screen_fullarea(C, CTX_wm_area(C));
1595 return OPERATOR_FINISHED;
1598 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1600 ot->name = "Toggle Make Area Fullscreen";
1601 ot->idname = "SCREEN_OT_screen_full_area";
1603 ot->exec= screen_full_area_exec;
1604 ot->poll= ED_operator_areaactive;
1611 /* ************** join area operator ********************************************** */
1613 /* operator state vars used:
1614 x1, y1 mouse coord in first area, which will disappear
1615 x2, y2 mouse coord in 2nd area, which will become joined
1619 init() find edge based on state vars
1620 test if the edge divides two areas,
1621 store active and nonactive area,
1623 apply() do the actual join
1625 exit() cleanup, send notifier
1629 exec() calls init, apply, exit
1631 invoke() sets mouse coords in x,y
1635 modal() accept modal events while doing it
1636 call apply() with active window and nonactive window
1637 call exit() and remove handler when LMB confirm
1641 typedef struct sAreaJoinData
1643 ScrArea *sa1; /* first area to be considered */
1644 ScrArea *sa2; /* second area to be considered */
1645 ScrArea *scr; /* designed for removal */
1650 /* validate selection inside screen, set variables OK */
1651 /* return 0: init failed */
1652 /* XXX todo: find edge based on (x,y) and set other area? */
1653 static int area_join_init(bContext *C, wmOperator *op)
1656 sAreaJoinData* jd= NULL;
1660 /* required properties, make negative to get return 0 if not set by caller */
1661 x1= RNA_int_get(op->ptr, "x1");
1662 y1= RNA_int_get(op->ptr, "y1");
1663 x2= RNA_int_get(op->ptr, "x2");
1664 y2= RNA_int_get(op->ptr, "y2");
1666 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1667 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1668 if(sa1==NULL || sa2==NULL || sa1==sa2)
1671 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1674 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1676 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1683 /* apply the join of the areas (space types) */
1684 static int area_join_apply(bContext *C, wmOperator *op)
1686 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1689 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1692 if (CTX_wm_area(C) == jd->sa2) {
1693 CTX_wm_area_set(C, NULL);
1694 CTX_wm_region_set(C, NULL);
1700 /* finish operation */
1701 static void area_join_exit(bContext *C, wmOperator *op)
1703 if (op->customdata) {
1704 MEM_freeN(op->customdata);
1705 op->customdata = NULL;
1708 /* this makes sure aligned edges will result in aligned grabbing */
1709 removedouble_scredges(CTX_wm_screen(C));
1710 removenotused_scredges(CTX_wm_screen(C));
1711 removenotused_scrverts(CTX_wm_screen(C));
1714 static int area_join_exec(bContext *C, wmOperator *op)
1716 if(!area_join_init(C, op))
1717 return OPERATOR_CANCELLED;
1719 area_join_apply(C, op);
1720 area_join_exit(C, op);
1722 return OPERATOR_FINISHED;
1725 /* interaction callback */
1726 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1729 if(event->type==EVT_ACTIONZONE_AREA) {
1730 sActionzoneData *sad= event->customdata;
1732 if(sad->modifier>0) {
1733 return OPERATOR_PASS_THROUGH;
1736 /* verify *sad itself */
1737 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1738 return OPERATOR_PASS_THROUGH;
1740 /* is this our *sad? if areas equal it should be passed on */
1741 if(sad->sa1==sad->sa2)
1742 return OPERATOR_PASS_THROUGH;
1744 /* prepare operator state vars */
1745 RNA_int_set(op->ptr, "x1", sad->x);
1746 RNA_int_set(op->ptr, "y1", sad->y);
1747 RNA_int_set(op->ptr, "x2", event->x);
1748 RNA_int_set(op->ptr, "y2", event->y);
1750 if(!area_join_init(C, op))
1751 return OPERATOR_PASS_THROUGH;
1753 /* add temp handler */
1754 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1756 return OPERATOR_RUNNING_MODAL;
1759 return OPERATOR_PASS_THROUGH;
1762 static int area_join_cancel(bContext *C, wmOperator *op)
1764 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1767 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1768 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1771 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1772 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1775 WM_event_add_notifier(C, NC_WINDOW, NULL);
1777 area_join_exit(C, op);
1779 return OPERATOR_CANCELLED;
1782 /* modal callback while selecting area (space) that will be removed */
1783 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1785 bScreen *sc= CTX_wm_screen(C);
1786 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1788 /* execute the events */
1789 switch(event->type) {
1793 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1797 if (jd->sa1 != sa) {
1798 dir = area_getorientation(sc, jd->sa1, sa);
1800 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1802 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1805 /* we are not bordering on the previously selected area
1806 we check if area has common border with the one marked for removal
1807 in this case we can swap areas.
1809 dir = area_getorientation(sc, sa, jd->sa2);
1811 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1812 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1815 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1816 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1819 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1823 WM_event_add_notifier(C, NC_WINDOW, NULL);
1826 /* we are back in the area previously selected for keeping
1827 * we swap the areas if possible to allow user to choose */
1828 if (jd->sa2 != NULL) {
1829 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1830 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1833 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1834 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1835 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1837 printf("oops, didn't expect that!\n");
1841 dir = area_getorientation(sc, jd->sa1, sa);
1843 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1845 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1848 WM_event_add_notifier(C, NC_WINDOW, NULL);
1855 area_join_apply(C, op);
1856 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1857 area_join_exit(C, op);
1858 return OPERATOR_FINISHED;
1863 return area_join_cancel(C, op);
1866 return OPERATOR_RUNNING_MODAL;
1869 /* Operator for joining two areas (space types) */
1870 static void SCREEN_OT_area_join(wmOperatorType *ot)
1873 ot->name= "Join area";
1874 ot->idname= "SCREEN_OT_area_join";
1877 ot->exec= area_join_exec;
1878 ot->invoke= area_join_invoke;
1879 ot->modal= area_join_modal;
1880 ot->poll= ED_operator_areaactive;
1882 ot->flag= OPTYPE_BLOCKING;
1885 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1886 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1887 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1888 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1891 /* ************** repeat last operator ***************************** */
1893 static int repeat_last_exec(bContext *C, wmOperator *op)
1895 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1898 WM_operator_repeat(C, lastop);
1900 return OPERATOR_CANCELLED;
1903 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
1906 ot->name= "Repeat Last";
1907 ot->idname= "SCREEN_OT_repeat_last";
1910 ot->exec= repeat_last_exec;
1912 ot->poll= ED_operator_screenactive;
1916 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1918 wmWindowManager *wm= CTX_wm_manager(C);
1924 items= BLI_countlist(&wm->operators);
1926 return OPERATOR_CANCELLED;
1928 pup= uiPupMenuBegin(C, op->type->name, 0);
1929 layout= uiPupMenuLayout(pup);
1931 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1932 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1934 uiPupMenuEnd(C, pup);
1936 return OPERATOR_CANCELLED;
1939 static int repeat_history_exec(bContext *C, wmOperator *op)
1941 wmWindowManager *wm= CTX_wm_manager(C);
1943 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1945 /* let's put it as last operator in list */
1946 BLI_remlink(&wm->operators, op);
1947 BLI_addtail(&wm->operators, op);
1949 WM_operator_repeat(C, op);
1952 return OPERATOR_FINISHED;
1955 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
1958 ot->name= "Repeat History";
1959 ot->idname= "SCREEN_OT_repeat_history";
1962 ot->invoke= repeat_history_invoke;
1963 ot->exec= repeat_history_exec;
1965 ot->poll= ED_operator_screenactive;
1967 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1970 /* ********************** redo operator ***************************** */
1972 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1974 wmWindowManager *wm= CTX_wm_manager(C);
1977 /* only for operators that are registered and did an undo push */
1978 for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1979 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1983 WM_operator_redo_popup(C, lastop);
1985 return OPERATOR_CANCELLED;
1988 static void SCREEN_OT_redo_last(wmOperatorType *ot)
1991 ot->name= "Redo Last";
1992 ot->idname= "SCREEN_OT_redo_last";
1995 ot->invoke= redo_last_invoke;
1997 ot->poll= ED_operator_screenactive;
2000 /* ************** region split operator ***************************** */
2002 /* insert a region in the area region list */
2003 static int region_split_exec(bContext *C, wmOperator *op)
2005 ARegion *ar= CTX_wm_region(C);
2007 if(ar->regiontype==RGN_TYPE_HEADER)
2008 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
2009 else if(ar->alignment==RGN_ALIGN_QSPLIT)
2010 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
2012 ScrArea *sa= CTX_wm_area(C);
2013 ARegion *newar= BKE_area_region_copy(sa->type, ar);
2014 int dir= RNA_enum_get(op->ptr, "type");
2016 BLI_insertlinkafter(&sa->regionbase, ar, newar);
2018 newar->alignment= ar->alignment;
2021 ar->alignment= RGN_ALIGN_HSPLIT;
2023 ar->alignment= RGN_ALIGN_VSPLIT;
2025 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2028 return OPERATOR_FINISHED;
2031 static void SCREEN_OT_region_split(wmOperatorType *ot)
2034 ot->name= "Split Region";
2035 ot->idname= "SCREEN_OT_region_split";
2038 ot->invoke= WM_menu_invoke;
2039 ot->exec= region_split_exec;
2040 ot->poll= ED_operator_areaactive;
2042 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
2045 /* ************** region four-split operator ***************************** */
2047 /* insert a region in the area region list */
2048 static int region_foursplit_exec(bContext *C, wmOperator *op)
2050 ARegion *ar= CTX_wm_region(C);
2053 if(ar->regiontype!=RGN_TYPE_WINDOW)
2054 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
2055 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
2056 ScrArea *sa= CTX_wm_area(C);
2059 /* keep current region */
2062 if(sa->spacetype==SPACE_VIEW3D) {
2063 RegionView3D *rv3d= ar->regiondata;
2065 rv3d->rflag &= ~RV3D_CLIPPING;
2068 for(ar= sa->regionbase.first; ar; ar= arn) {
2070 if(ar->alignment==RGN_ALIGN_QSPLIT) {
2071 ED_region_exit(C, ar);
2072 BKE_area_region_free(sa->type, ar);
2073 BLI_remlink(&sa->regionbase, ar);
2077 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2080 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
2082 ScrArea *sa= CTX_wm_area(C);
2086 ar->alignment= RGN_ALIGN_QSPLIT;
2088 for(count=0; count<3; count++) {
2089 newar= BKE_area_region_copy(sa->type, ar);
2090 BLI_addtail(&sa->regionbase, newar);
2093 /* lock views and set them */
2094 if(sa->spacetype==SPACE_VIEW3D) {
2097 rv3d= ar->regiondata;
2098 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
2101 rv3d= ar->regiondata;
2102 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
2105 rv3d= ar->regiondata;
2106 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
2109 rv3d= ar->regiondata;
2110 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
2113 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2117 return OPERATOR_FINISHED;
2120 static void SCREEN_OT_region_foursplit(wmOperatorType *ot)
2123 ot->name= "Split Region in 4 Parts";
2124 ot->idname= "SCREEN_OT_region_foursplit";
2127 // ot->invoke= WM_operator_confirm;
2128 ot->exec= region_foursplit_exec;
2129 ot->poll= ED_operator_areaactive;
2130 ot->flag= OPTYPE_REGISTER;
2135 /* ************** region flip operator ***************************** */
2137 /* flip a region alignment */
2138 static int region_flip_exec(bContext *C, wmOperator *op)
2140 ARegion *ar= CTX_wm_region(C);
2142 if(ar->alignment==RGN_ALIGN_TOP)
2143 ar->alignment= RGN_ALIGN_BOTTOM;
2144 else if(ar->alignment==RGN_ALIGN_BOTTOM)
2145 ar->alignment= RGN_ALIGN_TOP;
2146 else if(ar->alignment==RGN_ALIGN_LEFT)
2147 ar->alignment= RGN_ALIGN_RIGHT;
2148 else if(ar->alignment==RGN_ALIGN_RIGHT)
2149 ar->alignment= RGN_ALIGN_LEFT;
2151 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2152 printf("executed region flip\n");
2154 return OPERATOR_FINISHED;
2158 static void SCREEN_OT_region_flip(wmOperatorType *ot)
2161 ot->name= "Flip Region";
2162 ot->idname= "SCREEN_OT_region_flip";
2165 ot->exec= region_flip_exec;
2167 ot->poll= ED_operator_areaactive;
2168 ot->flag= OPTYPE_REGISTER;
2172 /* ****************** anim player, with timer ***************** */
2174 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2176 if(regiontype==RGN_TYPE_WINDOW) {
2178 switch (spacetype) {
2180 if(redraws & TIME_ALL_3D_WIN)
2186 if(redraws & TIME_ALL_ANIM_WIN)
2190 /* if only 1 window or 3d windows, we do timeline too */
2191 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2195 if(redraws & TIME_ALL_BUTS_WIN)
2199 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2203 if(redraws & TIME_ALL_IMAGE_WIN)
2209 else if(regiontype==RGN_TYPE_UI) {
2210 if(redraws & TIME_ALL_BUTS_WIN)
2213 else if(regiontype==RGN_TYPE_HEADER) {
2214 if(spacetype==SPACE_TIME)
2220 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2222 bScreen *screen= CTX_wm_screen(C);
2224 if(screen->animtimer==event->customdata) {
2225 Scene *scene= CTX_data_scene(C);
2226 wmTimer *wt= screen->animtimer;
2227 ScreenAnimData *sad= wt->customdata;
2231 /* sync, don't sync, or follow scene setting */
2232 if(sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2233 else if(sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2234 else sync= (scene->r.audio.flag & AUDIO_SYNC);
2238 int step = floor(wt->duration * FPS);
2239 if(sad->flag & ANIMPLAY_FLAG_REVERSE) // XXX does this option work with audio?
2240 scene->r.cfra -= step;
2242 scene->r.cfra += step;
2243 wt->duration -= ((float)step)/FPS;
2247 if(sad->flag & ANIMPLAY_FLAG_REVERSE)
2253 /* reset 'jumped' flag before checking if we need to jump... */
2254 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2256 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2257 /* jump back to end? */
2258 if (scene->r.psfra) {
2259 if (scene->r.cfra < scene->r.psfra) {
2260 scene->r.cfra= scene->r.pefra;
2261 sad->flag |= ANIMPLAY_FLAG_JUMPED;
2265 if (scene->r.cfra < scene->r.sfra) {
2266 scene->r.cfra= scene->r.efra;
2267 sad->flag |= ANIMPLAY_FLAG_JUMPED;
2272 /* jump back to start? */
2273 if (scene->r.psfra) {
2274 if (scene->r.cfra > scene->r.pefra) {
2275 scene->r.cfra= scene->r.psfra;
2276 sad->flag |= ANIMPLAY_FLAG_JUMPED;
2280 if (scene->r.cfra > scene->r.efra) {
2281 scene->r.cfra= scene->r.sfra;
2282 sad->flag |= ANIMPLAY_FLAG_JUMPED;
2287 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2288 ED_update_for_newframe(C, 1);
2290 sound_update_playing(C);
2292 for(sa= screen->areabase.first; sa; sa= sa->next) {
2294 for(ar= sa->regionbase.first; ar; ar= ar->next) {
2296 ED_region_tag_redraw(ar);
2298 if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2299 ED_region_tag_redraw(ar);
2303 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2305 return OPERATOR_FINISHED;
2307 return OPERATOR_PASS_THROUGH;
2310 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2313 ot->name= "Animation Step";
2314 ot->idname= "SCREEN_OT_animation_step";
2317 ot->invoke= screen_animation_step;
2319 ot->poll= ED_operator_screenactive;
2323 /* ****************** anim player, starts or ends timer ***************** */
2325 /* toggle operator */
2326 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2328 bScreen *screen= CTX_wm_screen(C);
2330 if(screen->animtimer) {
2331 ED_screen_animation_timer(C, 0, 0, 0);
2335 ScrArea *sa= CTX_wm_area(C);
2336 int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2339 if(RNA_property_is_set(op->ptr, "sync"))
2340 sync= (RNA_boolean_get(op->ptr, "sync"));
2342 /* timeline gets special treatment since it has it's own menu for determining redraws */
2343 if ((sa) && (sa->spacetype == SPACE_TIME)) {
2344 SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
2346 ED_screen_animation_timer(C, stime->redraws, sync, mode);
2348 /* update region if TIME_REGION was set, to leftmost 3d window */
2349 ED_screen_animation_timer_update(C, stime->redraws);
2352 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, sync, mode);
2354 if(screen->animtimer) {
2355 wmTimer *wt= screen->animtimer;
2356 ScreenAnimData *sad= wt->customdata;
2358 sad->ar= CTX_wm_region(C);
2363 return OPERATOR_FINISHED;
2366 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2369 ot->name= "Animation player";
2370 ot->idname= "SCREEN_OT_animation_play";
2373 ot->invoke= screen_animation_play;
2375 ot->poll= ED_operator_screenactive;
2377 RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2378 RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate and stay in sync with audio.");
2381 /* ************** border select operator (template) ***************************** */
2383 /* operator state vars used: (added by default WM callbacks)
2387 customdata: the wmGesture pointer
2391 exec() has to be filled in by user
2393 invoke() default WM function
2396 modal() default WM function
2397 accept modal events while doing it, calls exec(), handles ESC and border drawing
2399 poll() has to be filled in by user for context
2402 static int border_select_do(bContext *C, wmOperator *op)
2404 int event_type= RNA_int_get(op->ptr, "event_type");
2406 if(event_type==LEFTMOUSE)
2407 printf("border select do select\n");
2408 else if(event_type==RIGHTMOUSE)
2409 printf("border select deselect\n");
2411 printf("border select do something\n");
2416 static void SCREEN_OT_border_select(wmOperatorType *ot)
2419 ot->name= "Border select";
2420 ot->idname= "SCREEN_OT_border_select";
2423 ot->exec= border_select_do;
2424 ot->invoke= WM_border_select_invoke;
2425 ot->modal= WM_border_select_modal;
2427 ot->poll= ED_operator_areaactive;
2430 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2431 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2432 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2433 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2434 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2439 /* ****************************** render invoking ***************** */
2441 /* set callbacks, exported to sequence render too.
2442 Only call in foreground (UI) renders. */
2444 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2445 /* window as the last possible alternative. */
2446 static ScrArea *biggest_non_image_area(bContext *C)
2448 bScreen *sc= CTX_wm_screen(C);
2449 ScrArea *sa, *big= NULL;
2450 int size, maxsize= 0, bwmaxsize= 0;
2453 for(sa= sc->areabase.first; sa; sa= sa->next) {
2454 if(sa->winx > 30 && sa->winy > 30) {
2455 size= sa->winx*sa->winy;
2456 if(sa->spacetype == SPACE_BUTS) {
2457 if(foundwin == 0 && size > bwmaxsize) {
2462 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2473 static ScrArea *biggest_area(bContext *C)
2475 bScreen *sc= CTX_wm_screen(C);
2476 ScrArea *sa, *big= NULL;
2477 int size, maxsize= 0;
2479 for(sa= sc->areabase.first; sa; sa= sa->next) {
2480 size= sa->winx*sa->winy;
2481 if(size > maxsize) {
2490 static ScrArea *find_area_showing_r_result(bContext *C)
2492 bScreen *sc= CTX_wm_screen(C);
2496 /* find an imagewindow showing render result */
2497 for(sa=sc->areabase.first; sa; sa= sa->next) {
2498 if(sa->spacetype==SPACE_IMAGE) {
2499 sima= sa->spacedata.first;
2500 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2507 static ScrArea *find_area_image_empty(bContext *C)
2509 bScreen *sc= CTX_wm_screen(C);
2513 /* find an imagewindow showing render result */
2514 for(sa=sc->areabase.first; sa; sa= sa->next) {
2515 if(sa->spacetype==SPACE_IMAGE) {
2516 sima= sa->spacedata.first;
2524 #if 0 // XXX not used
2525 static ScrArea *find_empty_image_area(bContext *C)
2527 bScreen *sc= CTX_wm_screen(C);
2531 /* find an imagewindow showing render result */
2532 for(sa=sc->areabase.first; sa; sa= sa->next) {
2533 if(sa->spacetype==SPACE_IMAGE) {
2534 sima= sa->spacedata.first;
2541 #endif // XXX not used
2543 /* new window uses x,y to set position */
2544 static void screen_set_image_output(bContext *C, int mx, int my)
2546 Scene *scene= CTX_data_scene(C);
2550 if(scene->r.displaymode==R_OUTPUT_WINDOW) {
2554 sizex= 10 + (scene->r.xsch*scene->r.size)/100;
2555 sizey= 40 + (scene->r.ysch*scene->r.size)/100;
2557 /* arbitrary... miniature image window views don't make much sense */
2558 if(sizex < 320) sizex= 320;
2559 if(sizey < 256) sizey= 256;
2561 /* XXX some magic to calculate postition */
2562 rect.xmin= mx + CTX_wm_window(C)->posx - sizex/2;
2563 rect.ymin= my + CTX_wm_window(C)->posy - sizey/2;
2564 rect.xmax= rect.xmin + sizex;
2565 rect.ymax= rect.ymin + sizey;
2567 /* changes context! */
2568 WM_window_open_temp(C, &rect, WM_WINDOW_RENDER);
2572 else if(scene->r.displaymode==R_OUTPUT_SCREEN) {
2573 /* this function returns with changed context */
2574 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
2579 sa= find_area_showing_r_result(C);
2581 sa= find_area_image_empty(C);
2584 /* find largest open non-image area */
2585 sa= biggest_non_image_area(C);
2587 ED_area_newspace(C, sa, SPACE_IMAGE);
2588 sima= sa->spacedata.first;
2590 /* makes ESC go back to prev space */
2591 sima->flag |= SI_PREVSPACE;
2594 /* use any area of decent size */
2595 sa= biggest_area(C);
2596 if(sa->spacetype!=SPACE_IMAGE) {
2597 // XXX newspace(sa, SPACE_IMAGE);
2598 sima= sa->spacedata.first;
2600 /* makes ESC go back to prev space */
2601 sima->flag |= SI_PREVSPACE;
2606 sima= sa->spacedata.first;
2608 /* get the correct image, and scale it */
2609 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2611 // if(G.displaymode==2) { // XXX
2613 sima->flag |= SI_FULLWINDOW|SI_PREVSPACE;
2615 // ed_screen_fullarea(C, sa);
2621 /* executes blocking render */
2622 static int screen_render_exec(bContext *C, wmOperator *op)
2624 Scene *scene= CTX_data_scene(C);
2625 Render *re= RE_GetRender(scene->id.name);
2628 re= RE_NewRender(scene->id.name);
2630 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2632 if(RNA_boolean_get(op->ptr, "animation"))
2633 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2635 RE_BlenderFrame(re, scene, scene->r.cfra);
2637 // no redraw needed, we leave state as we entered it
2638 ED_update_for_newframe(C, 1);
2640 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2642 return OPERATOR_FINISHED;
2645 typedef struct RenderJob {
2656 static void render_freejob(void *rjv)
2663 /* str is IMA_RW_MAXTEXT in size */
2664 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
2666 char info_time_str[32]; // used to be extern to header_info.c
2667 uintptr_t mem_in_use, mmap_in_use;
2668 float megs_used_memory, mmap_used_memory;
2671 mem_in_use= MEM_get_memory_in_use();
2672 mmap_in_use= MEM_get_mapped_memory_in_use();
2674 megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
2675 mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
2677 if(scene->lay & 0xFF000000)
2678 spos+= sprintf(spos, "Localview | ");
2679 else if(scene->r.scemode & R_SINGLE_LAYER)
2680 spos+= sprintf(spos, "Single Layer | ");
2683 spos+= sprintf(spos, "%s ", rs->statstr);
2686 spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
2687 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
2688 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
2689 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
2692 spos+= sprintf(spos, "Field %d ", rs->curfield);
2694 spos+= sprintf(spos, "Blur %d ", rs->curblur);
2697 BLI_timestr(rs->lastframetime, info_time_str);
2698 spos+= sprintf(spos, "Time:%s ", info_time_str);
2700 if(rs->infostr && rs->infostr[0])
2701 spos+= sprintf(spos, "| %s ", rs->infostr);
2703 /* very weak... but 512 characters is quite safe */
2704 if(spos >= str+IMA_RW_MAXTEXT)
2705 printf("WARNING! renderwin text beyond limit \n");
2709 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
2713 /* malloc OK here, stats_draw is not in tile threads */
2714 if(rj->image->render_text==NULL)
2715 rj->image->render_text= MEM_callocN(IMA_RW_MAXTEXT, "rendertext");
2717 make_renderinfo_string(rs, rj->scene, rj->image->render_text);
2719 /* make jobs timer to send notifier */
2720 *(rj->do_update)= 1;
2724 /* called inside thread! */
2725 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2729 float x1, y1, *rectf= NULL;
2730 int ymin, ymax, xmin, xmax;
2734 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2735 if(ibuf==NULL) return;
2737 /* if renrect argument, we only refresh scanlines */
2739 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2740 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2743 /* xmin here is first subrect x coord, xmax defines subrect width */
2744 xmin = renrect->xmin + rr->crop;
2745 xmax = renrect->xmax - xmin - rr->crop;
2748 ymin= renrect->ymin + rr->crop;
2749 ymax= renrect->ymax - ymin - rr->crop;
2752 renrect->ymin= renrect->ymax;
2756 xmin = ymin = rr->crop;
2757 xmax = rr->rectx - 2*rr->crop;
2758 ymax = rr->recty - 2*rr->crop;
2761 /* xmin ymin is in tile coords. transform to ibuf */
2762 rxmin= rr->tilerect.xmin + xmin;
2763 if(rxmin >= ibuf->x) return;
2764 rymin= rr->tilerect.ymin + ymin;
2765 if(rymin >= ibuf->y) return;
2767 if(rxmin + xmax > ibuf->x)
2768 xmax= ibuf->x - rxmin;
2769 if(rymin + ymax > ibuf->y)
2770 ymax= ibuf->y - rymin;
2772 if(xmax < 1 || ymax < 1) return;
2774 /* find current float rect for display, first case is after composit... still weak */
2781 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2782 rectf= rr->renlay->rectf;
2785 if(rectf==NULL) return;
2787 rectf+= 4*(rr->rectx*ymin + xmin);
2788 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2790 /* XXX make nice consistent functions for this */
2791 if (rj->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
2792 for(y1= 0; y1<ymax; y1++) {
2797 /* XXX temp. because crop offset */
2798 if( rectc >= (char *)(ibuf->rect)) {
2799 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2800 srgb[0]= linearrgb_to_srgb(rf[0]);
2801 srgb[1]= linearrgb_to_srgb(rf[1]);
2802 srgb[2]= linearrgb_to_srgb(rf[2]);
2804 rc[0]= FTOCHAR(srgb[0]);
2805 rc[1]= FTOCHAR(srgb[1]);
2806 rc[2]= FTOCHAR(srgb[2]);
2807 rc[3]= FTOCHAR(rf[3]);
2810 rectf += 4*rr->rectx;
2814 for(y1= 0; y1<ymax; y1++) {
2818 /* XXX temp. because crop offset */
2819 if( rectc >= (char *)(ibuf->rect)) {
2820 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2821 rc[0]= FTOCHAR(rf[0]);
2822 rc[1]= FTOCHAR(rf[1]);
2823 rc[2]= FTOCHAR(rf[2]);
2824 rc[3]= FTOCHAR(rf[3]);
2827 rectf += 4*rr->rectx;
2832 /* make jobs timer to send notifier */
2833 *(rj->do_update)= 1;
2836 static void render_startjob(void *rjv, short *stop, short *do_update)
2841 rj->do_update= do_update;
2844 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2846 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2849 /* called by render, check job 'stop' value or the global */
2850 static int render_breakjob(void *rjv)
2856 if(rj->stop && *(rj->stop))
2862 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2864 /* no running blender, remove handler and pass through */
2865 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2866 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2868 /* running render */
2869 switch (event->type) {
2871 return OPERATOR_RUNNING_MODAL;
2874 return OPERATOR_PASS_THROUGH;
2877 /* using context, starts job */
2878 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2880 /* new render clears all callbacks */
2881 Scene *scene= CTX_data_scene(C);
2887 /* only one render job at a time */
2888 if(WM_jobs_test(CTX_wm_manager(C), scene))
2889 return OPERATOR_CANCELLED;
2891 /* stop all running jobs, currently previews frustrate Render */
2892 WM_jobs_stop_all(CTX_wm_manager(C));
2894 /* handle UI stuff */
2897 /* flush multires changes (for sculpt) */
2898 multires_force_update(CTX_data_active_object(C));
2900 /* get editmode results */
2901 ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */
2904 // get view3d layer, local layer, make this nice api call to render
2907 /* ensure at least 1 area shows result */
2908 screen_set_image_output(C, event->x, event->y);
2910 /* job custom data */
2911 rj= MEM_callocN(sizeof(RenderJob), "render job");
2913 rj->win= CTX_wm_window(C);
2914 rj->anim= RNA_boolean_get(op->ptr, "animation");
2915 rj->iuser.scene= scene;
2919 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2920 WM_jobs_customdata(steve, rj, render_freejob);
2921 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2922 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2924 /* get a render result image, and make sure it is empty */
2925 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2926 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2929 /* setup new render */
2930 re= RE_NewRender(scene->id.name);
2931 RE_test_break_cb(re, rj, render_breakjob);
2932 RE_display_draw_cb(re, rj, image_rect_update);
2933 RE_stats_draw_cb(re, rj, image_renderinfo_cb);
2938 // BKE_report in render!
2939 // RE_error_cb(re, error_cb);
2941 WM_jobs_start(CTX_wm_manager(C), steve);
2946 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2948 /* add modal handler for ESC */
2949 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2951 return OPERATOR_RUNNING_MODAL;
2955 /* contextual render, using current scene, view3d? */
2956 static void SCREEN_OT_render(wmOperatorType *ot)
2960 ot->idname= "SCREEN_OT_render";
2963 ot->invoke= screen_render_invoke;
2964 ot->modal= screen_render_modal;
2965 ot->exec= screen_render_exec;
2967 ot->poll= ED_operator_screenactive;
2969 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2970 RNA_def_boolean(ot->srna, "animation", 0, "Animation", "");
2973 /* *********************** cancel render viewer *************** */
2975 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2977 ScrArea *sa= CTX_wm_area(C);
2978 SpaceImage *sima= sa->spacedata.first;
2980 /* test if we have a temp screen in front */
2981 if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
2982 wm_window_lower(CTX_wm_window(C));
2984 /* determine if render already shows */
2985 else if(sima->flag & SI_PREVSPACE) {
2986 sima->flag &= ~SI_PREVSPACE;
2988 if(sima->flag & SI_FULLWINDOW) {
2989 sima->flag &= ~SI_FULLWINDOW;
2990 ED_screen_full_prevspace(C);
2993 ED_area_prevspace(C);
2995 else if(sima->flag & SI_FULLWINDOW) {
2996 sima->flag &= ~SI_FULLWINDOW;
2997 ed_screen_fullarea(C, sa);
3000 return OPERATOR_FINISHED;
3003 static void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
3006 ot->name= "Cancel Render View";
3007 ot->idname= "SCREEN_OT_render_view_cancel";
3010 ot->exec= render_view_cancel_exec;
3011 ot->poll= ED_operator_image_active;
3014 /* *********************** show render viewer *************** */
3016 static int render_view_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
3018 ScrArea *sa= find_area_showing_r_result(C);
3020 /* test if we have a temp screen in front */
3021 if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
3022 wm_window_lower(CTX_wm_window(C));
3024 /* determine if render already shows */
3026 SpaceImage *sima= sa->spacedata.first;
3028 if(sima->flag & SI_PREVSPACE) {
3029 sima->flag &= ~SI_PREVSPACE;
3031 if(sima->flag & SI_FULLWINDOW) {
3032 sima->flag &= ~SI_FULLWINDOW;
3033 ED_screen_full_prevspace(C);
3035 else if(sima->next) {
3036 ED_area_newspace(C, sa, sima->next->spacetype);
3037 ED_area_tag_redraw(sa);
3042 screen_set_image_output(C, event->x, event->y);
3045 return OPERATOR_FINISHED;
3048 static void SCREEN_OT_render_view_show(struct wmOperatorType *ot)
3051 ot->name= "Show/Hide Render View";
3052 ot->idname= "SCREEN_OT_render_view_show";
3055 ot->invoke= render_view_show_invoke;
3056 ot->poll= ED_operator_screenactive;
3059 /* *********** show user pref window ****** */
3061 static int userpref_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
3070 /* some magic to calculate postition */
3071 rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
3072 rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
3073 rect.xmax= rect.xmin + sizex;
3074 rect.ymax= rect.ymin + sizey;
3076 /* changes context! */
3077 WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
3082 return OPERATOR_FINISHED;
3086 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
3089 ot->name= "Show/Hide User Preferences";
3090 ot->idname= "SCREEN_OT_userpref_show";
3093 ot->invoke= userpref_show_invoke;
3094 ot->poll= ED_operator_screenactive;
3097 /********************* new screen operator *********************/
3099 static int screen_new_exec(bContext *C, wmOperator *op)
3101 wmWindow *win= CTX_wm_window(C);
3102 bScreen *sc= CTX_wm_screen(C);
3104 sc= ED_screen_duplicate(win, sc);
3105 WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
3107 return OPERATOR_FINISHED;
3110 void SCREEN_OT_new(wmOperatorType *ot)
3113 ot->name= "New Screen";
3114 ot->idname= "SCREEN_OT_new";
3117 ot->exec= screen_new_exec;
3120 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3123 /********************* delete screen operator *********************/
3125 static int screen_delete_exec(bContext *C, wmOperator *op)
3127 bScreen *sc= CTX_wm_screen(C);
3129 WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
3131 return OPERATOR_FINISHED;
3134 void SCREEN_OT_delete(wmOperatorType *ot)
3137 ot->name= "Delete Scene";
3138 ot->idname= "SCREEN_OT_delete";
3141 ot->exec= screen_delete_exec;
3144 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3147 /********************* new scene operator *********************/
3149 static int scene_new_exec(bContext *C, wmOperator *op)
3151 Scene *newscene, *scene= CTX_data_scene(C);
3152 Main *bmain= CTX_data_main(C);
3153 int type= RNA_enum_get(op->ptr, "type");
3155 newscene= copy_scene(bmain, scene, type);
3157 /* these can't be handled in blenkernel curently, so do them here */
3158 if(type == SCE_COPY_LINK_DATA)
3159 ED_object_single_users(newscene, 0);
3160 else if(type == SCE_COPY_FULL)
3161 ED_object_single_users(newscene, 1);
3163 WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
3165 return OPERATOR_FINISHED;
3168 void SCENE_OT_new(wmOperatorType *ot)
3170 static EnumPropertyItem type_items[]= {
3171 {SCE_COPY_EMPTY, "EMPTY", 0, "Empty", "Add empty scene."},
3172 {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene."},
3173 {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene."},
3174 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene."},
3175 {0, NULL, 0, NULL, NULL}};
3178 ot->name= "New Scene";
3179 ot->idname= "SCENE_OT_new";
3182 ot->exec= scene_new_exec;
3183 ot->invoke= WM_menu_invoke;
3186 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3189 RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
3192 /********************* delete scene operator *********************/
3194 static int scene_delete_exec(bContext *C, wmOperator *op)
3196 Scene *scene= CTX_data_scene(C);
3198 WM_event_add_notifier(C, NC_SCENE|ND_SCENEDELETE, scene);
3200 return OPERATOR_FINISHED;
3203 void SCENE_OT_delete(wmOperatorType *ot)
3206 ot->name= "Delete Scene";
3207 ot->idname= "SCENE_OT_delete";
3210 ot->exec= scene_delete_exec;
3213 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3216 /* **************** Assigning operatortypes to global list, adding handlers **************** */
3218 /* called in spacetypes.c */
3219 void ED_operatortypes_screen(void)
3221 /* generic UI stuff */
3222 WM_operatortype_append(SCREEN_OT_actionzone);
3223 WM_operatortype_append(SCREEN_OT_repeat_last);
3224 WM_operatortype_append(SCREEN_OT_repeat_history);
3225 WM_operatortype_append(SCREEN_OT_redo_last);
3228 WM_operatortype_append(SCREEN_OT_area_move);
3229 WM_operatortype_append(SCREEN_OT_area_split);
3230 WM_operatortype_append(SCREEN_OT_area_join);
3231 WM_operatortype_append(SCREEN_OT_area_dupli);
3232 WM_operatortype_append(SCREEN_OT_area_swap);
3233 WM_operatortype_append(SCREEN_OT_region_split);
3234 WM_operatortype_append(SCREEN_OT_region_foursplit);
3235 WM_operatortype_append(SCREEN_OT_region_flip);
3236 WM_operatortype_append(SCREEN_OT_region_scale);
3237 WM_operatortype_append(SCREEN_OT_screen_set);
3238 WM_operatortype_append(SCREEN_OT_screen_full_area);
3239 WM_operatortype_append(SCREEN_OT_screenshot);
3240 WM_operatortype_append(SCREEN_OT_screencast);
3241 WM_operatortype_append(SCREEN_OT_userpref_show);
3244 WM_operatortype_append(SCREEN_OT_frame_offset);
3245 WM_operatortype_append(SCREEN_OT_frame_jump);
3246 WM_operatortype_append(SCREEN_OT_keyframe_jump);
3248 WM_operatortype_append(SCREEN_OT_animation_step);
3249 WM_operatortype_append(SCREEN_OT_animation_play);
3252 WM_operatortype_append(SCREEN_OT_render);
3253 WM_operatortype_append(SCREEN_OT_render_view_cancel);
3254 WM_operatortype_append(SCREEN_OT_render_view_show);
3257 WM_operatortype_append(SCREEN_OT_new);
3258 WM_operatortype_append(SCREEN_OT_delete);
3259 WM_operatortype_append(SCENE_OT_new);
3260 WM_operatortype_append(SCENE_OT_delete);
3262 /* tools shared by more space types */
3263 WM_operatortype_append(ED_OT_undo);
3264 WM_operatortype_append(ED_OT_redo);
3268 static void keymap_modal_set(wmWindowManager *wm)
3270 static EnumPropertyItem modal_items[] = {
3271 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
3272 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
3273 {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
3274 {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
3275 {0, NULL, 0, NULL, NULL}};
3278 /* Standard Modal keymap ------------------------------------------------ */
3279 keymap= WM_modalkeymap_add(wm, "Standard Modal Map", modal_items);
3281 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
3282 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
3283 WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
3284 WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
3286 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
3287 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
3289 WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
3293 /* called in spacetypes.c */
3294 void ED_keymap_screen(wmWindowManager *wm)
3298 /* Screen General ------------------------------------------------ */
3299 keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
3302 /* standard timers */
3303 WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
3305 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
3306 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
3307 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
3310 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
3311 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
3312 WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
3313 WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
3314 WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
3315 /* area move after action zones */
3316 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
3318 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
3319 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
3320 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area&q