4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * ***** END GPL LICENSE BLOCK *****
29 #include "MEM_guardedalloc.h"
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_editVert.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_image_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_scene_types.h"
42 #include "BKE_blender.h"
43 #include "BKE_context.h"
44 #include "BKE_customdata.h"
45 #include "BKE_global.h"
46 #include "BKE_image.h"
47 #include "BKE_idprop.h"
48 #include "BKE_library.h"
50 #include "BKE_multires.h"
51 #include "BKE_report.h"
52 #include "BKE_screen.h"
53 #include "BKE_utildefines.h"
59 #include "ED_screen.h"
60 #include "ED_screen_types.h"
62 #include "RE_pipeline.h"
63 #include "IMB_imbuf.h"
64 #include "IMB_imbuf_types.h"
66 #include "RNA_access.h"
67 #include "RNA_define.h"
69 #include "UI_interface.h"
70 #include "UI_resources.h"
72 #include "screen_intern.h" /* own module include */
74 /* ************** Exported Poll tests ********************** */
76 int ED_operator_areaactive(bContext *C)
78 if(CTX_wm_window(C)==NULL) return 0;
79 if(CTX_wm_screen(C)==NULL) return 0;
80 if(CTX_wm_area(C)==NULL) return 0;
84 int ED_operator_screenactive(bContext *C)
86 if(CTX_wm_window(C)==NULL) return 0;
87 if(CTX_wm_screen(C)==NULL) return 0;
91 /* when mouse is over area-edge */
92 int ED_operator_screen_mainwinactive(bContext *C)
94 if(CTX_wm_window(C)==NULL) return 0;
95 if(CTX_wm_screen(C)==NULL) return 0;
96 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
100 int ED_operator_scene_editable(bContext *C)
102 Scene *scene= CTX_data_scene(C);
103 if(scene && scene->id.lib==NULL)
108 static int ed_spacetype_test(bContext *C, int type)
110 if(ED_operator_areaactive(C)) {
111 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
112 return sl && (sl->spacetype == type);
117 int ED_operator_view3d_active(bContext *C)
119 return ed_spacetype_test(C, SPACE_VIEW3D);
122 int ED_operator_timeline_active(bContext *C)
124 return ed_spacetype_test(C, SPACE_TIME);
127 int ED_operator_outliner_active(bContext *C)
129 if(ed_spacetype_test(C, SPACE_OOPS)) {
130 SpaceOops *so= (SpaceOops *)CTX_wm_space_data(C);
131 return (so->type == SO_OUTLINER);
136 int ED_operator_file_active(bContext *C)
138 return ed_spacetype_test(C, SPACE_FILE);
141 int ED_operator_action_active(bContext *C)
143 return ed_spacetype_test(C, SPACE_ACTION);
146 int ED_operator_buttons_active(bContext *C)
148 return ed_spacetype_test(C, SPACE_BUTS);
151 int ED_operator_node_active(bContext *C)
153 if(ed_spacetype_test(C, SPACE_NODE)) {
154 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
161 int ED_operator_ipo_active(bContext *C)
163 return ed_spacetype_test(C, SPACE_IPO);
166 int ED_operator_sequencer_active(bContext *C)
168 return ed_spacetype_test(C, SPACE_SEQ);
171 int ED_operator_image_active(bContext *C)
173 return ed_spacetype_test(C, SPACE_IMAGE);
176 int ED_operator_object_active(bContext *C)
178 return NULL != CTX_data_active_object(C);
181 int ED_operator_editmesh(bContext *C)
183 Object *obedit= CTX_data_edit_object(C);
184 if(obedit && obedit->type==OB_MESH)
185 return NULL != ((Mesh *)obedit->data)->edit_mesh;
189 int ED_operator_editarmature(bContext *C)
191 Object *obedit= CTX_data_edit_object(C);
192 if(obedit && obedit->type==OB_ARMATURE)
193 return NULL != ((bArmature *)obedit->data)->edbo;
197 int ED_operator_posemode(bContext *C)
199 Object *obact= CTX_data_active_object(C);
200 Object *obedit= CTX_data_edit_object(C);
202 if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
203 return (obact->flag & OB_POSEMODE)!=0;
209 int ED_operator_uvedit(bContext *C)
211 Object *obedit= CTX_data_edit_object(C);
214 if(obedit && obedit->type==OB_MESH)
215 em= ((Mesh *)obedit->data)->edit_mesh;
217 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE)))
223 int ED_operator_uvmap(bContext *C)
225 Object *obedit= CTX_data_edit_object(C);
228 if(obedit && obedit->type==OB_MESH)
229 em= ((Mesh *)obedit->data)->edit_mesh;
231 if(em && (em->faces.first))
237 int ED_operator_editsurfcurve(bContext *C)
239 Object *obedit= CTX_data_edit_object(C);
240 if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
241 return NULL != ((Curve *)obedit->data)->editnurb;
246 int ED_operator_editcurve(bContext *C)
248 Object *obedit= CTX_data_edit_object(C);
249 if(obedit && obedit->type==OB_CURVE)
250 return NULL != ((Curve *)obedit->data)->editnurb;
254 int ED_operator_editsurf(bContext *C)
256 Object *obedit= CTX_data_edit_object(C);
257 if(obedit && obedit->type==OB_SURF)
258 return NULL != ((Curve *)obedit->data)->editnurb;
262 int ED_operator_editfont(bContext *C)
264 Object *obedit= CTX_data_edit_object(C);
265 if(obedit && obedit->type==OB_FONT)
266 return NULL != ((Curve *)obedit->data)->editfont;
270 /* *************************** action zone operator ************************** */
272 /* operator state vars used:
277 apply() set actionzone event
279 exit() free customdata
285 invoke() check if in zone
286 add customdata, put mouseco and area in it
289 modal() accept modal events while doing it
290 call apply() with gesture info, active window, nonactive window
291 call exit() and remove handler when LMB confirm
295 typedef struct sActionzoneData {
298 int x, y, gesture_dir;
301 /* used by other operators too */
302 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
305 sa= scr->areabase.first;
307 if(BLI_in_rcti(&sa->totrct, x, y)) break;
315 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
320 for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
321 if(az->type == AZONE_TRI) {
322 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
325 if(az->type == AZONE_QUAD) {
326 if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2)
334 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
336 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
337 sActionzoneData *sad;
341 return OPERATOR_PASS_THROUGH;
343 /* ok we do the actionzone */
344 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
345 sad->sa1= CTX_wm_area(C);
347 sad->x= event->x; sad->y= event->y;
349 /* add modal handler */
350 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
352 return OPERATOR_RUNNING_MODAL;
355 static void actionzone_exit(bContext *C, wmOperator *op)
358 MEM_freeN(op->customdata);
359 op->customdata= NULL;
362 /* send EVT_ACTIONZONE event */
363 static void actionzone_apply(bContext *C, wmOperator *op)
366 wmWindow *win= CTX_wm_window(C);
368 event= *(win->eventstate); /* XXX huh huh? make api call */
369 event.type= EVT_ACTIONZONE;
370 event.customdata= op->customdata;
371 event.customdatafree= TRUE;
372 op->customdata= NULL;
374 wm_event_add(win, &event);
377 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
379 sActionzoneData *sad= op->customdata;
382 switch(event->type) {
384 /* calculate gesture direction */
385 deltax= (event->x - sad->x);
386 deltay= (event->y - sad->y);
388 if(deltay > ABS(deltax))
389 sad->gesture_dir= AZONE_N;
390 else if(deltax > ABS(deltay))
391 sad->gesture_dir= AZONE_E;
392 else if(deltay < -ABS(deltax))
393 sad->gesture_dir= AZONE_S;
395 sad->gesture_dir= AZONE_W;
397 /* gesture is large enough? */
398 if(ABS(deltax) > 12 || ABS(deltay) > 12) {
400 /* second area, for join */
401 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
402 /* apply sends event */
403 actionzone_apply(C, op);
404 actionzone_exit(C, op);
406 return OPERATOR_FINISHED;
411 actionzone_exit(C, op);
412 return OPERATOR_CANCELLED;
415 return OPERATOR_RUNNING_MODAL;
418 void SCREEN_OT_actionzone(wmOperatorType *ot)
421 ot->name= "Handle area action zones";
422 ot->idname= "SCREEN_OT_actionzone";
424 ot->invoke= actionzone_invoke;
425 ot->modal= actionzone_modal;
427 ot->poll= ED_operator_areaactive;
431 /* *********** Rip area operator ****************** */
434 /* operator callback */
435 /* (ton) removed attempt to merge ripped area with another, don't think this is desired functionality.
436 conventions: 'atomic' and 'dont think for user' :) */
437 static int screen_area_rip_op(bContext *C, wmOperator *op)
439 wmWindow *newwin, *win;
444 win= CTX_wm_window(C);
445 sc= CTX_wm_screen(C);
448 /* poll() checks area context, but we don't accept full-area windows */
449 if(sc->full != SCREENNORMAL)
450 return OPERATOR_CANCELLED;
452 /* adds window to WM */
454 BLI_translate_rcti(&rect, win->posx, win->posy);
455 newwin= WM_window_open(C, &rect);
457 /* allocs new screen and adds to newly created window, using window size */
458 newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
459 newwin->screen= newsc;
461 /* copy area to new screen */
462 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
464 /* screen, areas init */
465 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
467 return OPERATOR_FINISHED;
470 void SCREEN_OT_area_rip(wmOperatorType *ot)
472 ot->name= "Rip Area into New Window";
473 ot->idname= "SCREEN_OT_area_rip";
475 ot->invoke= WM_operator_confirm;
476 ot->exec= screen_area_rip_op;
477 ot->poll= ED_operator_areaactive;
481 /* ************** move area edge operator *********************************** */
483 /* operator state vars used:
484 x, y mouse coord near edge
485 delta movement of edge
489 init() set default property values, find edge based on mouse coords, test
490 if the edge can be moved, select edges, calculate min and max movement
492 apply() apply delta on selection
494 exit() cleanup, send notifier
496 cancel() cancel moving
500 exec() execute without any user interaction, based on properties
501 call init(), apply(), exit()
503 invoke() gets called on mouse click near edge
504 call init(), add handler
506 modal() accept modal events while doing it
507 call apply() with delta motion
508 call exit() and remove handler
512 typedef struct sAreaMoveData {
513 int bigger, smaller, origval;
517 /* helper call to move area-edge, sets limits */
518 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
522 /* we check all areas and test for free space with MINSIZE */
523 *bigger= *smaller= 100000;
525 for(sa= sc->areabase.first; sa; sa= sa->next) {
527 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
529 /* if top or down edge selected, test height */
530 if(sa->v1->flag && sa->v4->flag)
531 *bigger= MIN2(*bigger, y1);
532 else if(sa->v2->flag && sa->v3->flag)
533 *smaller= MIN2(*smaller, y1);
536 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
538 /* if left or right edge selected, test width */
539 if(sa->v1->flag && sa->v2->flag)
540 *bigger= MIN2(*bigger, x1);
541 else if(sa->v3->flag && sa->v4->flag)
542 *smaller= MIN2(*smaller, x1);
547 /* validate selection inside screen, set variables OK */
548 /* return 0: init failed */
549 static int area_move_init (bContext *C, wmOperator *op)
551 bScreen *sc= CTX_wm_screen(C);
556 /* required properties */
557 x= RNA_int_get(op->ptr, "x");
558 y= RNA_int_get(op->ptr, "y");
561 actedge= screen_find_active_scredge(sc, x, y);
562 if(actedge==NULL) return 0;
564 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
567 md->dir= scredge_is_horizontal(actedge)?'h':'v';
568 if(md->dir=='h') md->origval= actedge->v1->vec.y;
569 else md->origval= actedge->v1->vec.x;
571 select_connected_scredge(sc, actedge);
572 /* now all vertices with 'flag==1' are the ones that can be moved. */
574 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
579 /* moves selected screen edge amount of delta, used by split & move */
580 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
582 wmWindow *win= CTX_wm_window(C);
583 bScreen *sc= CTX_wm_screen(C);
586 delta= CLAMPIS(delta, -smaller, bigger);
588 for (v1= sc->vertbase.first; v1; v1= v1->next) {
590 /* that way a nice AREAGRID */
591 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
592 v1->vec.x= origval + delta;
593 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
595 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
596 v1->vec.y= origval + delta;
598 v1->vec.y+= AREAGRID-1;
599 v1->vec.y-= (v1->vec.y % AREAGRID);
601 /* prevent too small top header */
602 if(v1->vec.y > win->sizey-AREAMINY)
603 v1->vec.y= win->sizey-AREAMINY;
608 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
611 static void area_move_apply(bContext *C, wmOperator *op)
613 sAreaMoveData *md= op->customdata;
616 delta= RNA_int_get(op->ptr, "delta");
617 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
620 static void area_move_exit(bContext *C, wmOperator *op)
623 MEM_freeN(op->customdata);
624 op->customdata= NULL;
626 /* this makes sure aligned edges will result in aligned grabbing */
627 removedouble_scrverts(CTX_wm_screen(C));
628 removedouble_scredges(CTX_wm_screen(C));
631 static int area_move_exec(bContext *C, wmOperator *op)
633 if(!area_move_init(C, op))
634 return OPERATOR_CANCELLED;
636 area_move_apply(C, op);
637 area_move_exit(C, op);
639 return OPERATOR_FINISHED;
642 /* interaction callback */
643 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
645 RNA_int_set(op->ptr, "x", event->x);
646 RNA_int_set(op->ptr, "y", event->y);
648 if(!area_move_init(C, op))
649 return OPERATOR_PASS_THROUGH;
651 /* add temp handler */
652 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
654 return OPERATOR_RUNNING_MODAL;
657 static int area_move_cancel(bContext *C, wmOperator *op)
660 RNA_int_set(op->ptr, "delta", 0);
661 area_move_apply(C, op);
662 area_move_exit(C, op);
664 return OPERATOR_CANCELLED;
667 /* modal callback for while moving edges */
668 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
675 x= RNA_int_get(op->ptr, "x");
676 y= RNA_int_get(op->ptr, "y");
678 /* execute the events */
679 switch(event->type) {
681 delta= (md->dir == 'v')? event->x - x: event->y - y;
682 RNA_int_set(op->ptr, "delta", delta);
684 area_move_apply(C, op);
689 area_move_exit(C, op);
690 return OPERATOR_FINISHED;
695 return area_move_cancel(C, op);
698 return OPERATOR_RUNNING_MODAL;
701 void SCREEN_OT_area_move(wmOperatorType *ot)
704 ot->name= "Move area edges";
705 ot->idname= "SCREEN_OT_area_move";
707 ot->exec= area_move_exec;
708 ot->invoke= area_move_invoke;
709 ot->cancel= area_move_cancel;
710 ot->modal= area_move_modal;
712 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
715 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
716 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
717 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
720 /* ************** split area operator *********************************** */
725 dir direction 'v' or 'h'
728 area pointer to (active) area
729 x, y last used mouse pos
734 init() set default property values, find area based on context
736 apply() split area based on state vars
738 exit() cleanup, send notifier
740 cancel() remove duplicated area
744 exec() execute without any user interaction, based on state vars
745 call init(), apply(), exit()
747 invoke() gets called on mouse click in action-widget
748 call init(), add modal handler
749 call apply() with initial motion
751 modal() accept modal events while doing it
752 call move-areas code with delta motion
753 call exit() or cancel() and remove handler
757 #define SPLIT_STARTED 1
758 #define SPLIT_PROGRESS 2
760 typedef struct sAreaSplitData
762 int x, y; /* last used mouse position */
764 int origval; /* for move areas */
765 int bigger, smaller; /* constraints for moving new edge */
766 int delta; /* delta move edge */
767 int origmin, origsize; /* to calculate fac, for property storage */
769 ScrEdge *nedge; /* new edge */
770 ScrArea *sarea; /* start area */
771 ScrArea *narea; /* new area */
774 /* generic init, no UI stuff here */
775 static int area_split_init(bContext *C, wmOperator *op)
777 ScrArea *sa= CTX_wm_area(C);
781 /* required context */
782 if(sa==NULL) return 0;
784 /* required properties */
785 dir= RNA_enum_get(op->ptr, "direction");
788 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
789 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
792 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
796 sd->origsize= dir=='v' ? sa->winx:sa->winy;
797 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
802 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
803 /* used with split operator */
804 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
806 ScrVert *sav1= sa->v1;
807 ScrVert *sav2= sa->v2;
808 ScrVert *sav3= sa->v3;
809 ScrVert *sav4= sa->v4;
810 ScrVert *sbv1= sb->v1;
811 ScrVert *sbv2= sb->v2;
812 ScrVert *sbv3= sb->v3;
813 ScrVert *sbv4= sb->v4;
815 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
816 return screen_findedge(screen, sav1, sav2);
818 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
819 return screen_findedge(screen, sav2, sav3);
821 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
822 return screen_findedge(screen, sav3, sav4);
824 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
825 return screen_findedge(screen, sav1, sav4);
832 /* do the split, return success */
833 static int area_split_apply(bContext *C, wmOperator *op)
835 bScreen *sc= CTX_wm_screen(C);
836 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
840 fac= RNA_float_get(op->ptr, "factor");
841 dir= RNA_enum_get(op->ptr, "direction");
843 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
848 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
850 /* select newly created edge, prepare for moving edge */
851 for(sv= sc->vertbase.first; sv; sv= sv->next)
854 sd->nedge->v1->flag= 1;
855 sd->nedge->v2->flag= 1;
857 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
858 else sd->origval= sd->nedge->v1->vec.x;
860 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
868 static void area_split_exit(bContext *C, wmOperator *op)
870 if (op->customdata) {
871 MEM_freeN(op->customdata);
872 op->customdata = NULL;
875 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
877 /* this makes sure aligned edges will result in aligned grabbing */
878 removedouble_scrverts(CTX_wm_screen(C));
879 removedouble_scredges(CTX_wm_screen(C));
883 /* UI callback, adds new handler */
884 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
888 if(event->type==EVT_ACTIONZONE) {
889 sActionzoneData *sad= event->customdata;
892 /* verify *sad itself */
893 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
894 return OPERATOR_PASS_THROUGH;
896 /* is this our *sad? if areas not equal it should be passed on */
897 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
898 return OPERATOR_PASS_THROUGH;
900 /* prepare operator state vars */
901 if(sad->gesture_dir==AZONE_N || sad->gesture_dir==AZONE_S) {
903 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
907 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
909 RNA_enum_set(op->ptr, "direction", dir);
911 /* general init, also non-UI case, adds customdata, sets area and defaults */
912 if(!area_split_init(C, op))
913 return OPERATOR_PASS_THROUGH;
915 sd= (sAreaSplitData *)op->customdata;
921 if(area_split_apply(C, op)) {
922 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
924 /* add temp handler for edge move or cancel */
925 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
927 return OPERATOR_RUNNING_MODAL;
932 /* nonmodal for now */
933 return op->type->exec(C, op);
936 return OPERATOR_PASS_THROUGH;
939 /* function to be called outside UI context, or for redo */
940 static int area_split_exec(bContext *C, wmOperator *op)
943 if(!area_split_init(C, op))
944 return OPERATOR_CANCELLED;
946 area_split_apply(C, op);
947 area_split_exit(C, op);
949 return OPERATOR_FINISHED;
953 static int area_split_cancel(bContext *C, wmOperator *op)
955 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
957 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
958 if (CTX_wm_area(C) == sd->narea) {
959 CTX_wm_area_set(C, NULL);
960 CTX_wm_region_set(C, NULL);
964 area_split_exit(C, op);
966 return OPERATOR_CANCELLED;
969 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
971 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
975 /* execute the events */
976 switch(event->type) {
978 dir= RNA_enum_get(op->ptr, "direction");
980 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
981 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
983 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
984 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
986 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
990 if(event->val==0) { /* mouse up */
991 area_split_exit(C, op);
992 return OPERATOR_FINISHED;
995 case RIGHTMOUSE: /* cancel operation */
997 return area_split_cancel(C, op);
1000 return OPERATOR_RUNNING_MODAL;
1003 static EnumPropertyItem prop_direction_items[] = {
1004 {'h', "HORIZONTAL", "Horizontal", ""},
1005 {'v', "VERTICAL", "Vertical", ""},
1006 {0, NULL, NULL, NULL}};
1008 void SCREEN_OT_area_split(wmOperatorType *ot)
1010 ot->name = "Split area";
1011 ot->idname = "SCREEN_OT_area_split";
1013 ot->exec= area_split_exec;
1014 ot->invoke= area_split_invoke;
1015 ot->modal= area_split_modal;
1017 ot->poll= ED_operator_areaactive;
1018 ot->flag= OPTYPE_REGISTER;
1021 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1022 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1025 /* ************** frame change operator ***************************** */
1028 /* function to be called outside UI context, or for redo */
1029 static int frame_offset_exec(bContext *C, wmOperator *op)
1033 delta = RNA_int_get(op->ptr, "delta");
1035 CTX_data_scene(C)->r.cfra += delta;
1037 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1039 return OPERATOR_FINISHED;
1042 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1044 ot->name = "Frame Offset";
1045 ot->idname = "SCREEN_OT_frame_offset";
1047 ot->exec= frame_offset_exec;
1049 ot->poll= ED_operator_screenactive;
1053 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1056 /* ************** switch screen operator ***************************** */
1059 /* function to be called outside UI context, or for redo */
1060 static int screen_set_exec(bContext *C, wmOperator *op)
1062 bScreen *screen= CTX_wm_screen(C);
1063 ScrArea *sa= CTX_wm_area(C);
1064 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1065 int delta= RNA_int_get(op->ptr, "delta");
1067 /* this screen is 'fake', solve later XXX */
1069 return OPERATOR_CANCELLED;
1073 screen= screen->id.next;
1074 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1075 if(screen->winid==0 && screen->full==0)
1079 else if(delta== -1) {
1081 screen= screen->id.prev;
1082 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1083 if(screen->winid==0 && screen->full==0)
1092 ED_screen_set(C, screen);
1093 return OPERATOR_FINISHED;
1095 return OPERATOR_CANCELLED;
1098 void SCREEN_OT_screen_set(wmOperatorType *ot)
1100 ot->name = "Set Screen";
1101 ot->idname = "SCREEN_OT_screen_set";
1103 ot->exec= screen_set_exec;
1104 ot->poll= ED_operator_screenactive;
1107 RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1108 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1111 /* ************** screen full-area operator ***************************** */
1114 /* function to be called outside UI context, or for redo */
1115 static int screen_full_area_exec(bContext *C, wmOperator *op)
1117 ed_screen_fullarea(C, CTX_wm_area(C));
1118 return OPERATOR_FINISHED;
1121 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1123 ot->name = "Toggle Make Area Fullscreen";
1124 ot->idname = "SCREEN_OT_screen_full_area";
1126 ot->exec= screen_full_area_exec;
1127 ot->poll= ED_operator_areaactive;
1134 /* ************** join area operator ********************************************** */
1136 /* operator state vars used:
1137 x1, y1 mouse coord in first area, which will disappear
1138 x2, y2 mouse coord in 2nd area, which will become joined
1142 init() find edge based on state vars
1143 test if the edge divides two areas,
1144 store active and nonactive area,
1146 apply() do the actual join
1148 exit() cleanup, send notifier
1152 exec() calls init, apply, exit
1154 invoke() sets mouse coords in x,y
1158 modal() accept modal events while doing it
1159 call apply() with active window and nonactive window
1160 call exit() and remove handler when LMB confirm
1164 typedef struct sAreaJoinData
1166 ScrArea *sa1; /* first area to be considered */
1167 ScrArea *sa2; /* second area to be considered */
1168 ScrArea *scr; /* designed for removal */
1173 /* validate selection inside screen, set variables OK */
1174 /* return 0: init failed */
1175 /* XXX todo: find edge based on (x,y) and set other area? */
1176 static int area_join_init(bContext *C, wmOperator *op)
1179 sAreaJoinData* jd= NULL;
1183 /* required properties, make negative to get return 0 if not set by caller */
1184 x1= RNA_int_get(op->ptr, "x1");
1185 y1= RNA_int_get(op->ptr, "y1");
1186 x2= RNA_int_get(op->ptr, "x2");
1187 y2= RNA_int_get(op->ptr, "y2");
1189 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1190 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1191 if(sa1==NULL || sa2==NULL || sa1==sa2)
1194 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1197 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1199 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1206 /* apply the join of the areas (space types) */
1207 static int area_join_apply(bContext *C, wmOperator *op)
1209 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1212 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1215 if (CTX_wm_area(C) == jd->sa2) {
1216 CTX_wm_area_set(C, NULL);
1217 CTX_wm_region_set(C, NULL);
1223 /* finish operation */
1224 static void area_join_exit(bContext *C, wmOperator *op)
1226 if (op->customdata) {
1227 MEM_freeN(op->customdata);
1228 op->customdata = NULL;
1231 /* this makes sure aligned edges will result in aligned grabbing */
1232 removedouble_scredges(CTX_wm_screen(C));
1233 removenotused_scredges(CTX_wm_screen(C));
1234 removenotused_scrverts(CTX_wm_screen(C));
1237 static int area_join_exec(bContext *C, wmOperator *op)
1239 if(!area_join_init(C, op))
1240 return OPERATOR_CANCELLED;
1242 area_join_apply(C, op);
1243 area_join_exit(C, op);
1245 return OPERATOR_FINISHED;
1248 /* interaction callback */
1249 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1252 if(event->type==EVT_ACTIONZONE) {
1253 sActionzoneData *sad= event->customdata;
1255 /* verify *sad itself */
1256 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1257 return OPERATOR_PASS_THROUGH;
1259 /* is this our *sad? if areas equal it should be passed on */
1260 if(sad->sa1==sad->sa2)
1261 return OPERATOR_PASS_THROUGH;
1263 /* prepare operator state vars */
1264 RNA_int_set(op->ptr, "x1", sad->x);
1265 RNA_int_set(op->ptr, "y1", sad->y);
1266 RNA_int_set(op->ptr, "x2", event->x);
1267 RNA_int_set(op->ptr, "y2", event->y);
1269 if(!area_join_init(C, op))
1270 return OPERATOR_PASS_THROUGH;
1272 /* add temp handler */
1273 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1275 return OPERATOR_RUNNING_MODAL;
1278 return OPERATOR_PASS_THROUGH;
1281 static int area_join_cancel(bContext *C, wmOperator *op)
1283 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1286 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1287 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1290 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1291 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1294 WM_event_add_notifier(C, NC_WINDOW, NULL);
1296 area_join_exit(C, op);
1298 return OPERATOR_CANCELLED;
1301 /* modal callback while selecting area (space) that will be removed */
1302 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1304 bScreen *sc= CTX_wm_screen(C);
1305 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1307 /* execute the events */
1308 switch(event->type) {
1312 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1316 if (jd->sa1 != sa) {
1317 dir = area_getorientation(sc, jd->sa1, sa);
1319 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1321 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1324 /* we are not bordering on the previously selected area
1325 we check if area has common border with the one marked for removal
1326 in this case we can swap areas.
1328 dir = area_getorientation(sc, sa, jd->sa2);
1330 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1331 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1334 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1335 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1338 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1342 WM_event_add_notifier(C, NC_WINDOW, NULL);
1345 /* we are back in the area previously selected for keeping
1346 * we swap the areas if possible to allow user to choose */
1347 if (jd->sa2 != NULL) {
1348 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1349 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1352 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1353 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1354 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1356 printf("oops, didn't expect that!\n");
1360 dir = area_getorientation(sc, jd->sa1, sa);
1362 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1364 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1367 WM_event_add_notifier(C, NC_WINDOW, NULL);
1374 area_join_apply(C, op);
1375 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1376 area_join_exit(C, op);
1377 return OPERATOR_FINISHED;
1382 return area_join_cancel(C, op);
1385 return OPERATOR_RUNNING_MODAL;
1388 /* Operator for joining two areas (space types) */
1389 void SCREEN_OT_area_join(wmOperatorType *ot)
1392 ot->name= "Join area";
1393 ot->idname= "SCREEN_OT_area_join";
1396 ot->exec= area_join_exec;
1397 ot->invoke= area_join_invoke;
1398 ot->modal= area_join_modal;
1400 ot->poll= ED_operator_areaactive;
1403 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1404 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1405 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1406 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1409 /* ************** repeat last operator ***************************** */
1411 static int repeat_last_exec(bContext *C, wmOperator *op)
1413 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1416 WM_operator_repeat(C, lastop);
1418 return OPERATOR_CANCELLED;
1421 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1424 ot->name= "Repeat Last";
1425 ot->idname= "SCREEN_OT_repeat_last";
1428 ot->exec= repeat_last_exec;
1430 ot->poll= ED_operator_screenactive;
1434 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1436 wmWindowManager *wm= CTX_wm_manager(C);
1441 items= BLI_countlist(&wm->operators);
1443 return OPERATOR_CANCELLED;
1445 head= uiPupMenuBegin(op->type->name, 0);
1447 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1448 uiMenuItemIntO(head, lastop->type->name, 0, op->type->idname, "index", i);
1450 uiPupMenuEnd(C, head);
1452 return OPERATOR_CANCELLED;
1455 static int repeat_history_exec(bContext *C, wmOperator *op)
1457 wmWindowManager *wm= CTX_wm_manager(C);
1459 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1461 /* let's put it as last operator in list */
1462 BLI_remlink(&wm->operators, op);
1463 BLI_addtail(&wm->operators, op);
1465 WM_operator_repeat(C, op);
1468 return OPERATOR_FINISHED;
1471 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1474 ot->name= "Repeat History";
1475 ot->idname= "SCREEN_OT_repeat_history";
1478 ot->invoke= repeat_history_invoke;
1479 ot->exec= repeat_history_exec;
1481 ot->poll= ED_operator_screenactive;
1483 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1486 /* ********************** redo operator ***************************** */
1488 static void redo_last_cb(bContext *C, void *arg_op, void *arg2)
1490 wmOperator *lastop= arg_op;
1494 WM_operator_repeat(C, lastop);
1499 static uiBlock *ui_block_create_redo_last(bContext *C, ARegion *ar, void *arg_op)
1501 wmWindowManager *wm= CTX_wm_manager(C);
1502 wmOperator *op= arg_op;
1507 block= uiBeginBlock(C, ar, "redo_last_popup", UI_EMBOSS, UI_HELV);
1508 uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1);
1509 uiBlockSetFunc(block, redo_last_cb, arg_op, NULL);
1511 if(!op->properties) {
1512 IDPropertyTemplate val = {0};
1513 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
1516 RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
1517 height= uiDefAutoButsRNA(block, &ptr);
1519 uiPopupBoundsBlock(block, 4.0f, 0, 0);
1520 uiEndBlock(C, block);
1525 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1527 wmWindowManager *wm= CTX_wm_manager(C);
1530 /* only for operators that are registered and did an undo push */
1531 for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1532 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1536 return OPERATOR_CANCELLED;
1538 uiPupBlock(C, ui_block_create_redo_last, lastop);
1540 return OPERATOR_CANCELLED;
1543 void SCREEN_OT_redo_last(wmOperatorType *ot)
1546 ot->name= "Redo Last";
1547 ot->idname= "SCREEN_OT_redo_last";
1550 ot->invoke= redo_last_invoke;
1552 ot->poll= ED_operator_screenactive;
1555 /* ************** region split operator ***************************** */
1557 /* insert a region in the area region list */
1558 static int region_split_exec(bContext *C, wmOperator *op)
1560 ARegion *ar= CTX_wm_region(C);
1562 if(ar->regiontype==RGN_TYPE_HEADER)
1563 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1564 else if(ar->alignment==RGN_ALIGN_QSPLIT)
1565 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1567 ScrArea *sa= CTX_wm_area(C);
1568 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1569 int dir= RNA_enum_get(op->ptr, "type");
1571 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1573 newar->alignment= ar->alignment;
1576 ar->alignment= RGN_ALIGN_HSPLIT;
1578 ar->alignment= RGN_ALIGN_VSPLIT;
1580 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1583 return OPERATOR_FINISHED;
1586 void SCREEN_OT_region_split(wmOperatorType *ot)
1589 ot->name= "Split Region";
1590 ot->idname= "SCREEN_OT_region_split";
1593 ot->invoke= WM_menu_invoke;
1594 ot->exec= region_split_exec;
1595 ot->poll= ED_operator_areaactive;
1597 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1600 /* ************** region four-split operator ***************************** */
1602 /* insert a region in the area region list */
1603 static int region_foursplit_exec(bContext *C, wmOperator *op)
1605 ARegion *ar= CTX_wm_region(C);
1608 if(ar->regiontype!=RGN_TYPE_WINDOW)
1609 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1610 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1611 ScrArea *sa= CTX_wm_area(C);
1614 /* keep current region */
1617 if(sa->spacetype==SPACE_VIEW3D) {
1618 RegionView3D *rv3d= ar->regiondata;
1620 rv3d->rflag &= ~RV3D_CLIPPING;
1623 for(ar= sa->regionbase.first; ar; ar= arn) {
1625 if(ar->alignment==RGN_ALIGN_QSPLIT) {
1626 ED_region_exit(C, ar);
1627 BKE_area_region_free(sa->type, ar);
1628 BLI_remlink(&sa->regionbase, ar);
1632 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1635 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1637 ScrArea *sa= CTX_wm_area(C);
1641 ar->alignment= RGN_ALIGN_QSPLIT;
1643 for(count=0; count<3; count++) {
1644 newar= BKE_area_region_copy(sa->type, ar);
1645 BLI_addtail(&sa->regionbase, newar);
1648 /* lock views and set them */
1649 if(sa->spacetype==SPACE_VIEW3D) {
1652 rv3d= ar->regiondata;
1653 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1656 rv3d= ar->regiondata;
1657 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1660 rv3d= ar->regiondata;
1661 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1664 rv3d= ar->regiondata;
1665 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1668 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1672 return OPERATOR_FINISHED;
1675 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1678 ot->name= "Split Region in 4 Parts";
1679 ot->idname= "SCREEN_OT_region_foursplit";
1682 ot->invoke= WM_operator_confirm;
1683 ot->exec= region_foursplit_exec;
1684 ot->poll= ED_operator_areaactive;
1685 ot->flag= OPTYPE_REGISTER;
1690 /* ************** region flip operator ***************************** */
1692 /* flip a region alignment */
1693 static int region_flip_exec(bContext *C, wmOperator *op)
1695 ARegion *ar= CTX_wm_region(C);
1697 if(ar->alignment==RGN_ALIGN_TOP)
1698 ar->alignment= RGN_ALIGN_BOTTOM;
1699 else if(ar->alignment==RGN_ALIGN_BOTTOM)
1700 ar->alignment= RGN_ALIGN_TOP;
1701 else if(ar->alignment==RGN_ALIGN_LEFT)
1702 ar->alignment= RGN_ALIGN_RIGHT;
1703 else if(ar->alignment==RGN_ALIGN_RIGHT)
1704 ar->alignment= RGN_ALIGN_LEFT;
1706 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1707 printf("executed region flip\n");
1709 return OPERATOR_FINISHED;
1712 static void testfunc(bContext *C, void *argv, int arg)
1714 printf("arg %d\n", arg);
1717 static void newlevel1(bContext *C, uiMenuItem *head, void *arg)
1719 uiMenuFunc(head, testfunc, NULL);
1721 uiMenuItemVal(head, "First", ICON_PROP_ON, 1);
1722 uiMenuItemVal(head, "Second", ICON_PROP_CON, 2);
1723 uiMenuItemVal(head, "Third", ICON_SMOOTHCURVE, 3);
1724 uiMenuItemVal(head, "Fourth", ICON_SHARPCURVE, 4);
1727 static int testing123(bContext *C, wmOperator *op, wmEvent *event)
1729 uiMenuItem *head= uiPupMenuBegin("Hello world", 0);
1731 uiMenuContext(head, WM_OP_EXEC_DEFAULT);
1732 uiMenuItemO(head, ICON_PROP_ON, "SCREEN_OT_region_flip");
1733 uiMenuItemO(head, ICON_PROP_CON, "SCREEN_OT_screen_full_area");
1734 uiMenuItemO(head, ICON_SMOOTHCURVE, "SCREEN_OT_region_foursplit");
1735 uiMenuLevel(head, "Submenu", newlevel1);
1736 uiMenuItemO(head, ICON_PROP_ON, "SCREEN_OT_area_rip");
1738 uiPupMenuEnd(C, head);
1740 /* this operator is only for a menu, not used further */
1741 return OPERATOR_CANCELLED;
1744 void SCREEN_OT_region_flip(wmOperatorType *ot)
1747 ot->name= "Flip Region";
1748 ot->idname= "SCREEN_OT_region_flip";
1751 ot->invoke= testing123; // XXX WM_operator_confirm;
1752 ot->exec= region_flip_exec;
1754 ot->poll= ED_operator_areaactive;
1755 ot->flag= OPTYPE_REGISTER;
1757 RNA_def_int(ot->srna, "test", 0, INT_MIN, INT_MAX, "test", "", INT_MIN, INT_MAX);
1761 /* ****************** anim player, typically with timer ***************** */
1763 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
1765 bScreen *screen= CTX_wm_screen(C);
1767 if(screen->animtimer==event->customdata) {
1768 Scene *scene= CTX_data_scene(C);
1770 if(scene->audio.flag & AUDIO_SYNC) {
1771 wmTimer *wt= screen->animtimer;
1772 int step = floor(wt->duration * FPS);
1773 scene->r.cfra += step;
1774 wt->duration -= ((float)step)/FPS;
1779 if (scene->r.psfra) {
1780 if(scene->r.cfra > scene->r.pefra)
1781 scene->r.cfra= scene->r.psfra;
1784 if(scene->r.cfra > scene->r.efra)
1785 scene->r.cfra= scene->r.sfra;
1788 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1790 return OPERATOR_FINISHED;
1792 return OPERATOR_PASS_THROUGH;
1795 void SCREEN_OT_animation_play(wmOperatorType *ot)
1798 ot->name= "Animation player";
1799 ot->idname= "SCREEN_OT_animation_play";
1802 ot->invoke= screen_animation_play;
1804 ot->poll= ED_operator_screenactive;
1808 /* ************** border select operator (template) ***************************** */
1810 /* operator state vars used: (added by default WM callbacks)
1814 customdata: the wmGesture pointer
1818 exec() has to be filled in by user
1820 invoke() default WM function
1823 modal() default WM function
1824 accept modal events while doing it, calls exec(), handles ESC and border drawing
1826 poll() has to be filled in by user for context
1829 static int border_select_do(bContext *C, wmOperator *op)
1831 int event_type= RNA_int_get(op->ptr, "event_type");
1833 if(event_type==LEFTMOUSE)
1834 printf("border select do select\n");
1835 else if(event_type==RIGHTMOUSE)
1836 printf("border select deselect\n");
1838 printf("border select do something\n");
1843 void SCREEN_OT_border_select(wmOperatorType *ot)
1846 ot->name= "Border select";
1847 ot->idname= "SCREEN_OT_border_select";
1850 ot->exec= border_select_do;
1851 ot->invoke= WM_border_select_invoke;
1852 ot->modal= WM_border_select_modal;
1854 ot->poll= ED_operator_areaactive;
1857 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1858 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1859 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1860 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1861 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1866 /* ****************************** render invoking ***************** */
1868 /* set callbacks, exported to sequence render too.
1869 Only call in foreground (UI) renders. */
1871 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
1872 /* window as the last possible alternative. */
1873 static ScrArea *biggest_non_image_area(bContext *C)
1875 bScreen *sc= CTX_wm_screen(C);
1876 ScrArea *sa, *big= NULL;
1877 int size, maxsize= 0, bwmaxsize= 0;
1880 for(sa= sc->areabase.first; sa; sa= sa->next) {
1881 if(sa->winx > 10 && sa->winy > 10) {
1882 size= sa->winx*sa->winy;
1883 if(sa->spacetype == SPACE_BUTS) {
1884 if(foundwin == 0 && size > bwmaxsize) {
1889 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
1900 static ScrArea *biggest_area(bContext *C)
1902 bScreen *sc= CTX_wm_screen(C);
1903 ScrArea *sa, *big= NULL;
1904 int size, maxsize= 0;
1906 for(sa= sc->areabase.first; sa; sa= sa->next) {
1907 size= sa->winx*sa->winy;
1908 if(size > maxsize) {
1917 static ScrArea *find_area_showing_r_result(bContext *C)
1919 bScreen *sc= CTX_wm_screen(C);
1923 /* find an imagewindow showing render result */
1924 for(sa=sc->areabase.first; sa; sa= sa->next) {
1925 if(sa->spacetype==SPACE_IMAGE) {
1926 sima= sa->spacedata.first;
1927 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
1934 static void screen_set_image_output(bContext *C)
1939 sa= find_area_showing_r_result(C);
1942 /* find largest open non-image area */
1943 sa= biggest_non_image_area(C);
1945 ED_area_newspace(C, sa, SPACE_IMAGE);
1946 sima= sa->spacedata.first;
1948 /* makes ESC go back to prev space */
1949 sima->flag |= SI_PREVSPACE;
1952 /* use any area of decent size */
1953 sa= biggest_area(C);
1954 if(sa->spacetype!=SPACE_IMAGE) {
1955 // XXX newspace(sa, SPACE_IMAGE);
1956 sima= sa->spacedata.first;
1958 /* makes ESC go back to prev space */
1959 sima->flag |= SI_PREVSPACE;
1964 sima= sa->spacedata.first;
1966 /* get the correct image, and scale it */
1967 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
1969 if(G.displaymode==2) { // XXX
1971 sima->flag |= SI_FULLWINDOW;
1973 ed_screen_fullarea(C, sa);
1979 /* executes blocking render */
1980 static int screen_render_exec(bContext *C, wmOperator *op)
1982 Scene *scene= CTX_data_scene(C);
1983 Render *re= RE_GetRender(scene->id.name);
1986 re= RE_NewRender(scene->id.name);
1988 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
1990 if(RNA_boolean_get(op->ptr, "anim"))
1991 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
1993 RE_BlenderFrame(re, scene, scene->r.cfra);
1995 // no redraw needed, we leave state as we entered it
1996 ED_update_for_newframe(C, 1);
1998 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2000 return OPERATOR_FINISHED;
2003 typedef struct RenderJob {
2014 static void render_freejob(void *rjv)
2021 /* called inside thread! */
2022 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2026 float x1, y1, *rectf= NULL;
2027 int ymin, ymax, xmin, xmax;
2031 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2032 if(ibuf==NULL) return;
2034 /* if renrect argument, we only refresh scanlines */
2036 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2037 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2040 /* xmin here is first subrect x coord, xmax defines subrect width */
2041 xmin = renrect->xmin + rr->crop;
2042 xmax = renrect->xmax - xmin - rr->crop;
2045 ymin= renrect->ymin + rr->crop;
2046 ymax= renrect->ymax - ymin - rr->crop;
2049 renrect->ymin= renrect->ymax;
2053 xmin = ymin = rr->crop;
2054 xmax = rr->rectx - 2*rr->crop;
2055 ymax = rr->recty - 2*rr->crop;
2058 /* xmin ymin is in tile coords. transform to ibuf */
2059 rxmin= rr->tilerect.xmin + xmin;
2060 if(rxmin >= ibuf->x) return;
2061 rymin= rr->tilerect.ymin + ymin;
2062 if(rymin >= ibuf->y) return;
2064 if(rxmin + xmax > ibuf->x)
2065 xmax= ibuf->x - rxmin;
2066 if(rymin + ymax > ibuf->y)
2067 ymax= ibuf->y - rymin;
2069 if(xmax < 1 || ymax < 1) return;
2071 /* find current float rect for display, first case is after composit... still weak */
2078 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2079 rectf= rr->renlay->rectf;
2082 if(rectf==NULL) return;
2084 rectf+= 4*(rr->rectx*ymin + xmin);
2085 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2087 for(y1= 0; y1<ymax; y1++) {
2091 /* XXX temp. because crop offset */
2092 if( rectc >= (char *)(ibuf->rect)) {
2093 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2094 rc[0]= FTOCHAR(rf[0]);
2095 rc[1]= FTOCHAR(rf[1]);
2096 rc[2]= FTOCHAR(rf[2]);
2097 rc[3]= FTOCHAR(rf[3]);
2100 rectf += 4*rr->rectx;
2104 /* make jobs timer to send notifier */
2105 *(rj->do_update)= 1;
2108 static void render_startjob(void *rjv, short *stop, short *do_update)
2113 rj->do_update= do_update;
2116 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2118 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2121 /* called by render, check job 'stop' value or the global */
2122 static int render_breakjob(void *rjv)
2128 if(rj->stop && *(rj->stop))
2134 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2136 /* no running blender, remove handler and pass through */
2137 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2138 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2140 /* running render */
2141 switch (event->type) {
2143 return OPERATOR_RUNNING_MODAL;
2146 return OPERATOR_PASS_THROUGH;
2149 /* using context, starts job */
2150 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2152 /* new render clears all callbacks */
2153 Scene *scene= CTX_data_scene(C);
2159 /* only one job at a time */
2160 if(WM_jobs_test(CTX_wm_manager(C), scene))
2161 return OPERATOR_CANCELLED;
2163 /* handle UI stuff */
2166 /* flush multires changes (for sculpt) */
2167 multires_force_update(CTX_data_active_object(C));
2169 // get editmode results
2171 // get view3d layer, local layer, make this nice api call to render
2174 /* ensure at least 1 area shows result */
2175 screen_set_image_output(C);
2177 /* job custom data */
2178 rj= MEM_callocN(sizeof(RenderJob), "render job");
2180 rj->win= CTX_wm_window(C);
2181 rj->anim= RNA_boolean_get(op->ptr, "anim");
2182 rj->iuser.scene= scene;
2186 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2187 WM_jobs_customdata(steve, rj, render_freejob);
2188 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2189 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2191 /* get a render result image, and make sure it is empty */
2192 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2193 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2196 /* setup new render */
2197 re= RE_NewRender(scene->id.name);
2198 RE_test_break_cb(re, rj, render_breakjob);
2199 RE_display_draw_cb(re, rj, image_rect_update);
2203 // BKE_report in render!
2204 // RE_error_cb(re, error_cb);
2206 WM_jobs_start(steve);
2211 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2213 /* add modal handler for ESC */
2214 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2216 return OPERATOR_RUNNING_MODAL;
2220 /* contextual render, using current scene, view3d? */
2221 void SCREEN_OT_render(wmOperatorType *ot)
2225 ot->idname= "SCREEN_OT_render";
2228 ot->invoke= screen_render_invoke;
2229 ot->modal= screen_render_modal;
2230 ot->exec= screen_render_exec;
2232 ot->poll= ED_operator_screenactive;
2234 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2235 RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2238 /* *********************** cancel render viewer *************** */
2240 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2242 ScrArea *sa= CTX_wm_area(C);
2243 SpaceImage *sima= sa->spacedata.first;
2245 if(sima->flag & SI_PREVSPACE) {
2246 sima->flag &= ~SI_PREVSPACE;
2248 if(sima->flag & SI_FULLWINDOW) {
2249 sima->flag &= ~SI_FULLWINDOW;
2250 ED_screen_full_prevspace(C);
2253 ED_area_prevspace(C);
2255 else if(sima->flag & SI_FULLWINDOW) {
2256 sima->flag &= ~SI_FULLWINDOW;
2257 ed_screen_fullarea(C, sa);
2260 return OPERATOR_FINISHED;
2263 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2266 ot->name= "Cancel Render View";
2267 ot->idname= "SCREEN_OT_render_view_cancel";
2270 ot->exec= render_view_cancel_exec;
2271 ot->poll= ED_operator_image_active;
2275 /* **************** Assigning operatortypes to global list, adding handlers **************** */
2277 /* called in spacetypes.c */
2278 void ED_operatortypes_screen(void)
2280 /* generic UI stuff */
2281 WM_operatortype_append(SCREEN_OT_actionzone);
2282 WM_operatortype_append(SCREEN_OT_repeat_last);
2283 WM_operatortype_append(SCREEN_OT_repeat_history);
2284 WM_operatortype_append(SCREEN_OT_redo_last);
2287 WM_operatortype_append(SCREEN_OT_area_move);
2288 WM_operatortype_append(SCREEN_OT_area_split);
2289 WM_operatortype_append(SCREEN_OT_area_join);
2290 WM_operatortype_append(SCREEN_OT_area_rip);
2291 WM_operatortype_append(SCREEN_OT_region_split);
2292 WM_operatortype_append(SCREEN_OT_region_foursplit);
2293 WM_operatortype_append(SCREEN_OT_region_flip);
2294 WM_operatortype_append(SCREEN_OT_screen_set);
2295 WM_operatortype_append(SCREEN_OT_screen_full_area);
2296 WM_operatortype_append(SCREEN_OT_screenshot);
2297 WM_operatortype_append(SCREEN_OT_screencast);
2300 WM_operatortype_append(SCREEN_OT_frame_offset);
2301 WM_operatortype_append(SCREEN_OT_animation_play);
2304 WM_operatortype_append(SCREEN_OT_render);
2305 WM_operatortype_append(SCREEN_OT_render_view_cancel);
2307 /* tools shared by more space types */
2308 WM_operatortype_append(ED_OT_undo);
2309 WM_operatortype_append(ED_OT_redo);
2313 /* called in spacetypes.c */
2314 void ED_keymap_screen(wmWindowManager *wm)
2316 ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2318 /* standard timers */
2319 WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
2321 WM_keymap_verify_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0);
2324 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2325 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0);
2326 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);
2327 WM_keymap_verify_item(keymap, "SCREEN_OT_area_rip", RKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2328 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2329 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2330 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2331 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2332 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2333 WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2334 WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2337 WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2338 WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2340 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2341 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2342 WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2343 WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2346 WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2347 WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2350 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2351 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2352 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2353 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2356 WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2357 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2360 keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2361 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2362 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2363 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2364 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);