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 *****
27 #include "MEM_guardedalloc.h"
29 #include "BLI_arithb.h"
30 #include "BLI_blenlib.h"
31 #include "BLI_editVert.h"
33 #include "DNA_armature_types.h"
34 #include "DNA_image_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_mesh_types.h"
37 #include "DNA_curve_types.h"
38 #include "DNA_scene_types.h"
40 #include "BKE_blender.h"
41 #include "BKE_context.h"
42 #include "BKE_customdata.h"
43 #include "BKE_global.h"
44 #include "BKE_image.h"
45 #include "BKE_idprop.h"
46 #include "BKE_library.h"
48 #include "BKE_multires.h"
49 #include "BKE_report.h"
50 #include "BKE_screen.h"
51 #include "BKE_utildefines.h"
57 #include "ED_screen.h"
58 #include "ED_screen_types.h"
60 #include "RE_pipeline.h"
61 #include "IMB_imbuf.h"
62 #include "IMB_imbuf_types.h"
64 #include "RNA_access.h"
65 #include "RNA_define.h"
67 #include "UI_interface.h"
68 #include "UI_resources.h"
70 #include "screen_intern.h" /* own module include */
72 /* ************** Exported Poll tests ********************** */
74 int ED_operator_areaactive(bContext *C)
76 if(CTX_wm_window(C)==NULL) return 0;
77 if(CTX_wm_screen(C)==NULL) return 0;
78 if(CTX_wm_area(C)==NULL) return 0;
82 int ED_operator_screenactive(bContext *C)
84 if(CTX_wm_window(C)==NULL) return 0;
85 if(CTX_wm_screen(C)==NULL) return 0;
89 /* when mouse is over area-edge */
90 int ED_operator_screen_mainwinactive(bContext *C)
92 if(CTX_wm_window(C)==NULL) return 0;
93 if(CTX_wm_screen(C)==NULL) return 0;
94 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
98 int ED_operator_scene_editable(bContext *C)
100 Scene *scene= CTX_data_scene(C);
101 if(scene && scene->id.lib==NULL)
106 static int ed_spacetype_test(bContext *C, int type)
108 if(ED_operator_areaactive(C)) {
109 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
110 return sl && (sl->spacetype == type);
115 int ED_operator_view3d_active(bContext *C)
117 return ed_spacetype_test(C, SPACE_VIEW3D);
120 int ED_operator_timeline_active(bContext *C)
122 return ed_spacetype_test(C, SPACE_TIME);
125 int ED_operator_outliner_active(bContext *C)
127 if(ed_spacetype_test(C, SPACE_OOPS)) {
128 SpaceOops *so= (SpaceOops *)CTX_wm_space_data(C);
129 return (so->type == SO_OUTLINER);
134 int ED_operator_file_active(bContext *C)
136 return ed_spacetype_test(C, SPACE_FILE);
139 int ED_operator_action_active(bContext *C)
141 return ed_spacetype_test(C, SPACE_ACTION);
144 int ED_operator_buttons_active(bContext *C)
146 return ed_spacetype_test(C, SPACE_BUTS);
149 int ED_operator_node_active(bContext *C)
151 return ed_spacetype_test(C, SPACE_NODE);
154 int ED_operator_ipo_active(bContext *C)
156 return ed_spacetype_test(C, SPACE_IPO);
159 int ED_operator_sequencer_active(bContext *C)
161 return ed_spacetype_test(C, SPACE_SEQ);
164 int ED_operator_image_active(bContext *C)
166 return ed_spacetype_test(C, SPACE_IMAGE);
169 int ED_operator_object_active(bContext *C)
171 return NULL != CTX_data_active_object(C);
174 int ED_operator_editmesh(bContext *C)
176 Object *obedit= CTX_data_edit_object(C);
177 if(obedit && obedit->type==OB_MESH)
178 return NULL != ((Mesh *)obedit->data)->edit_mesh;
182 int ED_operator_editarmature(bContext *C)
184 Object *obedit= CTX_data_edit_object(C);
185 if(obedit && obedit->type==OB_ARMATURE)
186 return NULL != ((bArmature *)obedit->data)->edbo;
190 int ED_operator_posemode(bContext *C)
192 Object *obact= CTX_data_active_object(C);
193 if(obact && obact->type==OB_ARMATURE)
194 return (obact->flag & OB_POSEMODE)!=0;
199 int ED_operator_uvedit(bContext *C)
201 Object *obedit= CTX_data_edit_object(C);
204 if(obedit && obedit->type==OB_MESH)
205 em= ((Mesh *)obedit->data)->edit_mesh;
207 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE)))
213 int ED_operator_uvmap(bContext *C)
215 Object *obedit= CTX_data_edit_object(C);
218 if(obedit && obedit->type==OB_MESH)
219 em= ((Mesh *)obedit->data)->edit_mesh;
221 if(em && (em->faces.first))
227 int ED_operator_editcurve(bContext *C)
229 Object *obedit= CTX_data_edit_object(C);
230 if(obedit && obedit->type==OB_CURVE)
231 return NULL != ((Mesh *)obedit->data)->edit_mesh;
236 /* *************************** action zone operator ************************** */
238 /* operator state vars used:
243 apply() set actionzone event
245 exit() free customdata
251 invoke() check if in zone
252 add customdata, put mouseco and area in it
255 modal() accept modal events while doing it
256 call apply() with gesture info, active window, nonactive window
257 call exit() and remove handler when LMB confirm
261 typedef struct sActionzoneData {
264 int x, y, gesture_dir;
267 /* used by other operators too */
268 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
271 sa= scr->areabase.first;
273 if(BLI_in_rcti(&sa->totrct, x, y)) break;
281 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
286 for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
287 if(az->type == AZONE_TRI) {
288 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
291 if(az->type == AZONE_QUAD) {
292 if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2)
300 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
302 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
303 sActionzoneData *sad;
307 return OPERATOR_PASS_THROUGH;
309 /* ok we do the actionzone */
310 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
311 sad->sa1= CTX_wm_area(C);
313 sad->x= event->x; sad->y= event->y;
315 /* add modal handler */
316 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
318 return OPERATOR_RUNNING_MODAL;
321 static void actionzone_exit(bContext *C, wmOperator *op)
324 MEM_freeN(op->customdata);
325 op->customdata= NULL;
328 /* send EVT_ACTIONZONE event */
329 static void actionzone_apply(bContext *C, wmOperator *op)
332 wmWindow *win= CTX_wm_window(C);
334 event= *(win->eventstate); /* XXX huh huh? make api call */
335 event.type= EVT_ACTIONZONE;
336 event.customdata= op->customdata;
337 event.customdatafree= TRUE;
338 op->customdata= NULL;
340 wm_event_add(win, &event);
343 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
345 sActionzoneData *sad= op->customdata;
348 switch(event->type) {
350 /* calculate gesture direction */
351 deltax= (event->x - sad->x);
352 deltay= (event->y - sad->y);
354 if(deltay > ABS(deltax))
355 sad->gesture_dir= AZONE_N;
356 else if(deltax > ABS(deltay))
357 sad->gesture_dir= AZONE_E;
358 else if(deltay < -ABS(deltax))
359 sad->gesture_dir= AZONE_S;
361 sad->gesture_dir= AZONE_W;
363 /* gesture is large enough? */
364 if(ABS(deltax) > 12 || ABS(deltay) > 12) {
366 /* second area, for join */
367 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
368 /* apply sends event */
369 actionzone_apply(C, op);
370 actionzone_exit(C, op);
372 return OPERATOR_FINISHED;
377 actionzone_exit(C, op);
378 return OPERATOR_CANCELLED;
381 return OPERATOR_RUNNING_MODAL;
384 void SCREEN_OT_actionzone(wmOperatorType *ot)
387 ot->name= "Handle area action zones";
388 ot->idname= "SCREEN_OT_actionzone";
390 ot->invoke= actionzone_invoke;
391 ot->modal= actionzone_modal;
393 ot->poll= ED_operator_areaactive;
397 /* *********** Rip area operator ****************** */
400 /* operator callback */
401 /* (ton) removed attempt to merge ripped area with another, don't think this is desired functionality.
402 conventions: 'atomic' and 'dont think for user' :) */
403 static int screen_area_rip_op(bContext *C, wmOperator *op)
405 wmWindow *newwin, *win;
410 win= CTX_wm_window(C);
411 sc= CTX_wm_screen(C);
414 /* poll() checks area context, but we don't accept full-area windows */
415 if(sc->full != SCREENNORMAL)
416 return OPERATOR_CANCELLED;
418 /* adds window to WM */
420 BLI_translate_rcti(&rect, win->posx, win->posy);
421 newwin= WM_window_open(C, &rect);
423 /* allocs new screen and adds to newly created window, using window size */
424 newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
425 newwin->screen= newsc;
427 /* copy area to new screen */
428 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
430 /* screen, areas init */
431 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
433 return OPERATOR_FINISHED;
436 void SCREEN_OT_area_rip(wmOperatorType *ot)
438 ot->name= "Rip Area into New Window";
439 ot->idname= "SCREEN_OT_area_rip";
441 ot->invoke= WM_operator_confirm;
442 ot->exec= screen_area_rip_op;
443 ot->poll= ED_operator_areaactive;
447 /* ************** move area edge operator *********************************** */
449 /* operator state vars used:
450 x, y mouse coord near edge
451 delta movement of edge
455 init() set default property values, find edge based on mouse coords, test
456 if the edge can be moved, select edges, calculate min and max movement
458 apply() apply delta on selection
460 exit() cleanup, send notifier
462 cancel() cancel moving
466 exec() execute without any user interaction, based on properties
467 call init(), apply(), exit()
469 invoke() gets called on mouse click near edge
470 call init(), add handler
472 modal() accept modal events while doing it
473 call apply() with delta motion
474 call exit() and remove handler
478 typedef struct sAreaMoveData {
479 int bigger, smaller, origval;
483 /* helper call to move area-edge, sets limits */
484 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
488 /* we check all areas and test for free space with MINSIZE */
489 *bigger= *smaller= 100000;
491 for(sa= sc->areabase.first; sa; sa= sa->next) {
493 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
495 /* if top or down edge selected, test height */
496 if(sa->v1->flag && sa->v4->flag)
497 *bigger= MIN2(*bigger, y1);
498 else if(sa->v2->flag && sa->v3->flag)
499 *smaller= MIN2(*smaller, y1);
502 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
504 /* if left or right edge selected, test width */
505 if(sa->v1->flag && sa->v2->flag)
506 *bigger= MIN2(*bigger, x1);
507 else if(sa->v3->flag && sa->v4->flag)
508 *smaller= MIN2(*smaller, x1);
513 /* validate selection inside screen, set variables OK */
514 /* return 0: init failed */
515 static int area_move_init (bContext *C, wmOperator *op)
517 bScreen *sc= CTX_wm_screen(C);
522 /* required properties */
523 x= RNA_int_get(op->ptr, "x");
524 y= RNA_int_get(op->ptr, "y");
527 actedge= screen_find_active_scredge(sc, x, y);
528 if(actedge==NULL) return 0;
530 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
533 md->dir= scredge_is_horizontal(actedge)?'h':'v';
534 if(md->dir=='h') md->origval= actedge->v1->vec.y;
535 else md->origval= actedge->v1->vec.x;
537 select_connected_scredge(sc, actedge);
538 /* now all vertices with 'flag==1' are the ones that can be moved. */
540 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
545 /* moves selected screen edge amount of delta, used by split & move */
546 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
548 wmWindow *win= CTX_wm_window(C);
549 bScreen *sc= CTX_wm_screen(C);
552 delta= CLAMPIS(delta, -smaller, bigger);
554 for (v1= sc->vertbase.first; v1; v1= v1->next) {
556 /* that way a nice AREAGRID */
557 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
558 v1->vec.x= origval + delta;
559 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
561 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
562 v1->vec.y= origval + delta;
564 v1->vec.y+= AREAGRID-1;
565 v1->vec.y-= (v1->vec.y % AREAGRID);
567 /* prevent too small top header */
568 if(v1->vec.y > win->sizey-AREAMINY)
569 v1->vec.y= win->sizey-AREAMINY;
574 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
577 static void area_move_apply(bContext *C, wmOperator *op)
579 sAreaMoveData *md= op->customdata;
582 delta= RNA_int_get(op->ptr, "delta");
583 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
586 static void area_move_exit(bContext *C, wmOperator *op)
589 MEM_freeN(op->customdata);
590 op->customdata= NULL;
592 /* this makes sure aligned edges will result in aligned grabbing */
593 removedouble_scrverts(CTX_wm_screen(C));
594 removedouble_scredges(CTX_wm_screen(C));
597 static int area_move_exec(bContext *C, wmOperator *op)
599 if(!area_move_init(C, op))
600 return OPERATOR_CANCELLED;
602 area_move_apply(C, op);
603 area_move_exit(C, op);
605 return OPERATOR_FINISHED;
608 /* interaction callback */
609 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
611 RNA_int_set(op->ptr, "x", event->x);
612 RNA_int_set(op->ptr, "y", event->y);
614 if(!area_move_init(C, op))
615 return OPERATOR_PASS_THROUGH;
617 /* add temp handler */
618 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
620 return OPERATOR_RUNNING_MODAL;
623 static int area_move_cancel(bContext *C, wmOperator *op)
626 RNA_int_set(op->ptr, "delta", 0);
627 area_move_apply(C, op);
628 area_move_exit(C, op);
630 return OPERATOR_CANCELLED;
633 /* modal callback for while moving edges */
634 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
641 x= RNA_int_get(op->ptr, "x");
642 y= RNA_int_get(op->ptr, "y");
644 /* execute the events */
645 switch(event->type) {
647 delta= (md->dir == 'v')? event->x - x: event->y - y;
648 RNA_int_set(op->ptr, "delta", delta);
650 area_move_apply(C, op);
655 area_move_exit(C, op);
656 return OPERATOR_FINISHED;
661 return area_move_cancel(C, op);
664 return OPERATOR_RUNNING_MODAL;
667 void SCREEN_OT_area_move(wmOperatorType *ot)
670 ot->name= "Move area edges";
671 ot->idname= "SCREEN_OT_area_move";
673 ot->exec= area_move_exec;
674 ot->invoke= area_move_invoke;
675 ot->cancel= area_move_cancel;
676 ot->modal= area_move_modal;
678 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
681 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
682 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
683 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
686 /* ************** split area operator *********************************** */
691 dir direction 'v' or 'h'
694 area pointer to (active) area
695 x, y last used mouse pos
700 init() set default property values, find area based on context
702 apply() split area based on state vars
704 exit() cleanup, send notifier
706 cancel() remove duplicated area
710 exec() execute without any user interaction, based on state vars
711 call init(), apply(), exit()
713 invoke() gets called on mouse click in action-widget
714 call init(), add modal handler
715 call apply() with initial motion
717 modal() accept modal events while doing it
718 call move-areas code with delta motion
719 call exit() or cancel() and remove handler
723 #define SPLIT_STARTED 1
724 #define SPLIT_PROGRESS 2
726 typedef struct sAreaSplitData
728 int x, y; /* last used mouse position */
730 int origval; /* for move areas */
731 int bigger, smaller; /* constraints for moving new edge */
732 int delta; /* delta move edge */
733 int origmin, origsize; /* to calculate fac, for property storage */
735 ScrEdge *nedge; /* new edge */
736 ScrArea *sarea; /* start area */
737 ScrArea *narea; /* new area */
740 /* generic init, no UI stuff here */
741 static int area_split_init(bContext *C, wmOperator *op)
743 ScrArea *sa= CTX_wm_area(C);
747 /* required context */
748 if(sa==NULL) return 0;
750 /* required properties */
751 dir= RNA_enum_get(op->ptr, "direction");
754 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
755 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
758 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
762 sd->origsize= dir=='v' ? sa->winx:sa->winy;
763 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
768 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
769 /* used with split operator */
770 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
772 ScrVert *sav1= sa->v1;
773 ScrVert *sav2= sa->v2;
774 ScrVert *sav3= sa->v3;
775 ScrVert *sav4= sa->v4;
776 ScrVert *sbv1= sb->v1;
777 ScrVert *sbv2= sb->v2;
778 ScrVert *sbv3= sb->v3;
779 ScrVert *sbv4= sb->v4;
781 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
782 return screen_findedge(screen, sav1, sav2);
784 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
785 return screen_findedge(screen, sav2, sav3);
787 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
788 return screen_findedge(screen, sav3, sav4);
790 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
791 return screen_findedge(screen, sav1, sav4);
798 /* do the split, return success */
799 static int area_split_apply(bContext *C, wmOperator *op)
801 bScreen *sc= CTX_wm_screen(C);
802 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
806 fac= RNA_float_get(op->ptr, "factor");
807 dir= RNA_enum_get(op->ptr, "direction");
809 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
814 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
816 /* select newly created edge, prepare for moving edge */
817 for(sv= sc->vertbase.first; sv; sv= sv->next)
820 sd->nedge->v1->flag= 1;
821 sd->nedge->v2->flag= 1;
823 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
824 else sd->origval= sd->nedge->v1->vec.x;
826 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
834 static void area_split_exit(bContext *C, wmOperator *op)
836 if (op->customdata) {
837 MEM_freeN(op->customdata);
838 op->customdata = NULL;
841 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
843 /* this makes sure aligned edges will result in aligned grabbing */
844 removedouble_scrverts(CTX_wm_screen(C));
845 removedouble_scredges(CTX_wm_screen(C));
849 /* UI callback, adds new handler */
850 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
854 if(event->type==EVT_ACTIONZONE) {
855 sActionzoneData *sad= event->customdata;
858 /* verify *sad itself */
859 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
860 return OPERATOR_PASS_THROUGH;
862 /* is this our *sad? if areas not equal it should be passed on */
863 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
864 return OPERATOR_PASS_THROUGH;
866 /* prepare operator state vars */
867 if(sad->gesture_dir==AZONE_N || sad->gesture_dir==AZONE_S) {
869 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
873 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
875 RNA_enum_set(op->ptr, "direction", dir);
877 /* general init, also non-UI case, adds customdata, sets area and defaults */
878 if(!area_split_init(C, op))
879 return OPERATOR_PASS_THROUGH;
881 sd= (sAreaSplitData *)op->customdata;
887 if(area_split_apply(C, op)) {
888 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
890 /* add temp handler for edge move or cancel */
891 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
893 return OPERATOR_RUNNING_MODAL;
898 /* nonmodal for now */
899 return op->type->exec(C, op);
902 return OPERATOR_PASS_THROUGH;
905 /* function to be called outside UI context, or for redo */
906 static int area_split_exec(bContext *C, wmOperator *op)
909 if(!area_split_init(C, op))
910 return OPERATOR_CANCELLED;
912 area_split_apply(C, op);
913 area_split_exit(C, op);
915 return OPERATOR_FINISHED;
919 static int area_split_cancel(bContext *C, wmOperator *op)
921 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
923 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
924 if (CTX_wm_area(C) == sd->narea) {
925 CTX_wm_area_set(C, NULL);
926 CTX_wm_region_set(C, NULL);
930 area_split_exit(C, op);
932 return OPERATOR_CANCELLED;
935 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
937 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
941 /* execute the events */
942 switch(event->type) {
944 dir= RNA_enum_get(op->ptr, "direction");
946 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
947 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
949 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
950 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
952 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
956 if(event->val==0) { /* mouse up */
957 area_split_exit(C, op);
958 return OPERATOR_FINISHED;
961 case RIGHTMOUSE: /* cancel operation */
963 return area_split_cancel(C, op);
966 return OPERATOR_RUNNING_MODAL;
969 static EnumPropertyItem prop_direction_items[] = {
970 {'h', "HORIZONTAL", "Horizontal", ""},
971 {'v', "VERTICAL", "Vertical", ""},
972 {0, NULL, NULL, NULL}};
974 void SCREEN_OT_area_split(wmOperatorType *ot)
976 ot->name = "Split area";
977 ot->idname = "SCREEN_OT_area_split";
979 ot->exec= area_split_exec;
980 ot->invoke= area_split_invoke;
981 ot->modal= area_split_modal;
983 ot->poll= ED_operator_areaactive;
984 ot->flag= OPTYPE_REGISTER;
987 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
988 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
991 /* ************** frame change operator ***************************** */
994 /* function to be called outside UI context, or for redo */
995 static int frame_offset_exec(bContext *C, wmOperator *op)
999 delta = RNA_int_get(op->ptr, "delta");
1001 CTX_data_scene(C)->r.cfra += delta;
1002 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1004 return OPERATOR_FINISHED;
1007 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1009 ot->name = "Frame Offset";
1010 ot->idname = "SCREEN_OT_frame_offset";
1012 ot->exec= frame_offset_exec;
1014 ot->poll= ED_operator_screenactive;
1015 ot->flag= OPTYPE_REGISTER;
1018 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1021 /* ************** switch screen operator ***************************** */
1024 /* function to be called outside UI context, or for redo */
1025 static int screen_set_exec(bContext *C, wmOperator *op)
1027 bScreen *screen= CTX_wm_screen(C);
1028 ScrArea *sa= CTX_wm_area(C);
1029 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1030 int delta= RNA_int_get(op->ptr, "delta");
1032 /* this screen is 'fake', solve later XXX */
1034 return OPERATOR_CANCELLED;
1038 screen= screen->id.next;
1039 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1040 if(screen->winid==0 && screen->full==0)
1044 else if(delta== -1) {
1046 screen= screen->id.prev;
1047 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1048 if(screen->winid==0 && screen->full==0)
1057 ED_screen_set(C, screen);
1058 return OPERATOR_FINISHED;
1060 return OPERATOR_CANCELLED;
1063 void SCREEN_OT_screen_set(wmOperatorType *ot)
1065 ot->name = "Set Screen";
1066 ot->idname = "SCREEN_OT_screen_set";
1068 ot->exec= screen_set_exec;
1069 ot->poll= ED_operator_screenactive;
1072 RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1073 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1076 /* ************** screen full-area operator ***************************** */
1079 /* function to be called outside UI context, or for redo */
1080 static int screen_full_area_exec(bContext *C, wmOperator *op)
1082 ed_screen_fullarea(C, CTX_wm_area(C));
1083 return OPERATOR_FINISHED;
1086 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1088 ot->name = "Toggle Make Area Fullscreen";
1089 ot->idname = "SCREEN_OT_screen_full_area";
1091 ot->exec= screen_full_area_exec;
1092 ot->poll= ED_operator_areaactive;
1093 ot->flag= OPTYPE_REGISTER;
1099 /* ************** join area operator ********************************************** */
1101 /* operator state vars used:
1102 x1, y1 mouse coord in first area, which will disappear
1103 x2, y2 mouse coord in 2nd area, which will become joined
1107 init() find edge based on state vars
1108 test if the edge divides two areas,
1109 store active and nonactive area,
1111 apply() do the actual join
1113 exit() cleanup, send notifier
1117 exec() calls init, apply, exit
1119 invoke() sets mouse coords in x,y
1123 modal() accept modal events while doing it
1124 call apply() with active window and nonactive window
1125 call exit() and remove handler when LMB confirm
1129 typedef struct sAreaJoinData
1131 ScrArea *sa1; /* first area to be considered */
1132 ScrArea *sa2; /* second area to be considered */
1133 ScrArea *scr; /* designed for removal */
1138 /* validate selection inside screen, set variables OK */
1139 /* return 0: init failed */
1140 /* XXX todo: find edge based on (x,y) and set other area? */
1141 static int area_join_init(bContext *C, wmOperator *op)
1144 sAreaJoinData* jd= NULL;
1148 /* required properties, make negative to get return 0 if not set by caller */
1149 x1= RNA_int_get(op->ptr, "x1");
1150 y1= RNA_int_get(op->ptr, "y1");
1151 x2= RNA_int_get(op->ptr, "x2");
1152 y2= RNA_int_get(op->ptr, "y2");
1154 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1155 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1156 if(sa1==NULL || sa2==NULL || sa1==sa2)
1159 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1162 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1164 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1171 /* apply the join of the areas (space types) */
1172 static int area_join_apply(bContext *C, wmOperator *op)
1174 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1177 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1180 if (CTX_wm_area(C) == jd->sa2) {
1181 CTX_wm_area_set(C, NULL);
1182 CTX_wm_region_set(C, NULL);
1188 /* finish operation */
1189 static void area_join_exit(bContext *C, wmOperator *op)
1191 if (op->customdata) {
1192 MEM_freeN(op->customdata);
1193 op->customdata = NULL;
1196 /* this makes sure aligned edges will result in aligned grabbing */
1197 removedouble_scredges(CTX_wm_screen(C));
1198 removenotused_scredges(CTX_wm_screen(C));
1199 removenotused_scrverts(CTX_wm_screen(C));
1202 static int area_join_exec(bContext *C, wmOperator *op)
1204 if(!area_join_init(C, op))
1205 return OPERATOR_CANCELLED;
1207 area_join_apply(C, op);
1208 area_join_exit(C, op);
1210 return OPERATOR_FINISHED;
1213 /* interaction callback */
1214 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1217 if(event->type==EVT_ACTIONZONE) {
1218 sActionzoneData *sad= event->customdata;
1220 /* verify *sad itself */
1221 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1222 return OPERATOR_PASS_THROUGH;
1224 /* is this our *sad? if areas equal it should be passed on */
1225 if(sad->sa1==sad->sa2)
1226 return OPERATOR_PASS_THROUGH;
1228 /* prepare operator state vars */
1229 RNA_int_set(op->ptr, "x1", sad->x);
1230 RNA_int_set(op->ptr, "y1", sad->y);
1231 RNA_int_set(op->ptr, "x2", event->x);
1232 RNA_int_set(op->ptr, "y2", event->y);
1234 if(!area_join_init(C, op))
1235 return OPERATOR_PASS_THROUGH;
1237 /* add temp handler */
1238 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1240 return OPERATOR_RUNNING_MODAL;
1243 return OPERATOR_PASS_THROUGH;
1246 static int area_join_cancel(bContext *C, wmOperator *op)
1248 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1251 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1252 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1255 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1256 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1259 WM_event_add_notifier(C, NC_WINDOW, NULL);
1261 area_join_exit(C, op);
1263 return OPERATOR_CANCELLED;
1266 /* modal callback while selecting area (space) that will be removed */
1267 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1269 bScreen *sc= CTX_wm_screen(C);
1270 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1272 /* execute the events */
1273 switch(event->type) {
1277 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1281 if (jd->sa1 != sa) {
1282 dir = area_getorientation(sc, jd->sa1, sa);
1284 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1286 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1289 /* we are not bordering on the previously selected area
1290 we check if area has common border with the one marked for removal
1291 in this case we can swap areas.
1293 dir = area_getorientation(sc, sa, jd->sa2);
1295 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1296 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1299 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1300 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1303 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1307 WM_event_add_notifier(C, NC_WINDOW, NULL);
1310 /* we are back in the area previously selected for keeping
1311 * we swap the areas if possible to allow user to choose */
1312 if (jd->sa2 != NULL) {
1313 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1314 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1317 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1318 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1319 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1321 printf("oops, didn't expect that!\n");
1325 dir = area_getorientation(sc, jd->sa1, sa);
1327 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1329 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1332 WM_event_add_notifier(C, NC_WINDOW, NULL);
1339 area_join_apply(C, op);
1340 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1341 area_join_exit(C, op);
1342 return OPERATOR_FINISHED;
1347 return area_join_cancel(C, op);
1350 return OPERATOR_RUNNING_MODAL;
1353 /* Operator for joining two areas (space types) */
1354 void SCREEN_OT_area_join(wmOperatorType *ot)
1357 ot->name= "Join area";
1358 ot->idname= "SCREEN_OT_area_join";
1361 ot->exec= area_join_exec;
1362 ot->invoke= area_join_invoke;
1363 ot->modal= area_join_modal;
1365 ot->poll= ED_operator_areaactive;
1368 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1369 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1370 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1371 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1374 /* ************** repeat last operator ***************************** */
1376 static int repeat_last_exec(bContext *C, wmOperator *op)
1378 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1381 WM_operator_repeat(C, lastop);
1383 return OPERATOR_CANCELLED;
1386 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1389 ot->name= "Repeat Last";
1390 ot->idname= "SCREEN_OT_repeat_last";
1393 ot->exec= repeat_last_exec;
1395 ot->poll= ED_operator_screenactive;
1399 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1401 wmWindowManager *wm= CTX_wm_manager(C);
1406 items= BLI_countlist(&wm->operators);
1408 return OPERATOR_CANCELLED;
1410 head= uiPupMenuBegin(op->type->name, 0);
1412 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1413 uiMenuItemIntO(head, lastop->type->name, 0, op->type->idname, "index", i);
1415 uiPupMenuEnd(C, head);
1417 return OPERATOR_CANCELLED;
1420 static int repeat_history_exec(bContext *C, wmOperator *op)
1422 wmWindowManager *wm= CTX_wm_manager(C);
1424 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1426 /* let's put it as last operator in list */
1427 BLI_remlink(&wm->operators, op);
1428 BLI_addtail(&wm->operators, op);
1430 WM_operator_repeat(C, op);
1433 return OPERATOR_FINISHED;
1436 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1439 ot->name= "Repeat History";
1440 ot->idname= "SCREEN_OT_repeat_history";
1443 ot->invoke= repeat_history_invoke;
1444 ot->exec= repeat_history_exec;
1446 ot->poll= ED_operator_screenactive;
1448 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1451 /* ********************** redo operator ***************************** */
1453 static int redo_last_exec(bContext *C, wmOperator *op)
1456 /* XXX context is not correct after popup menu */
1457 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1461 WM_operator_repeat(C, lastop);
1465 return OPERATOR_CANCELLED;
1468 static void redo_last_cb(bContext *C, void *arg1, void *arg2)
1470 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1474 WM_operator_repeat(C, lastop);
1479 static uiBlock *ui_block_create_redo_last(bContext *C, ARegion *ar, void *arg_op)
1481 wmWindowManager *wm= CTX_wm_manager(C);
1482 wmOperator *op= arg_op;
1487 block= uiBeginBlock(C, ar, "redo_last_popup", UI_EMBOSS, UI_HELV);
1488 uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1);
1489 uiBlockSetFunc(block, redo_last_cb, NULL, NULL);
1491 if(!op->properties) {
1492 IDPropertyTemplate val = {0};
1493 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
1496 RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
1497 height= uiDefAutoButsRNA(block, &ptr);
1499 uiPopupBoundsBlock(block, 4.0f, 0, 0);
1500 uiEndBlock(C, block);
1505 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1507 wmWindowManager *wm= CTX_wm_manager(C);
1508 wmOperator *lastop= wm->operators.last;
1511 return OPERATOR_CANCELLED;
1513 /* only for operators that are registered and did an undo push */
1514 if(!(lastop->type->flag & OPTYPE_REGISTER) || !(lastop->type->flag & OPTYPE_UNDO))
1515 return OPERATOR_CANCELLED;
1517 uiPupBlockO(C, ui_block_create_redo_last, lastop, op->type->idname, WM_OP_EXEC_DEFAULT);
1519 return OPERATOR_CANCELLED;
1522 void SCREEN_OT_redo_last(wmOperatorType *ot)
1525 ot->name= "Redo Last";
1526 ot->idname= "SCREEN_OT_redo_last";
1529 ot->invoke= redo_last_invoke;
1530 ot->exec= redo_last_exec;
1532 ot->poll= ED_operator_screenactive;
1535 /* ************** region split operator ***************************** */
1537 /* insert a region in the area region list */
1538 static int region_split_exec(bContext *C, wmOperator *op)
1540 ARegion *ar= CTX_wm_region(C);
1542 if(ar->regiontype==RGN_TYPE_HEADER)
1543 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1544 else if(ar->alignment==RGN_ALIGN_QSPLIT)
1545 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1547 ScrArea *sa= CTX_wm_area(C);
1548 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1549 int dir= RNA_enum_get(op->ptr, "type");
1551 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1553 newar->alignment= ar->alignment;
1556 ar->alignment= RGN_ALIGN_HSPLIT;
1558 ar->alignment= RGN_ALIGN_VSPLIT;
1560 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1563 return OPERATOR_FINISHED;
1566 void SCREEN_OT_region_split(wmOperatorType *ot)
1569 ot->name= "Split Region";
1570 ot->idname= "SCREEN_OT_region_split";
1573 ot->invoke= WM_menu_invoke;
1574 ot->exec= region_split_exec;
1575 ot->poll= ED_operator_areaactive;
1577 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1580 /* ************** region four-split operator ***************************** */
1582 /* insert a region in the area region list */
1583 static int region_foursplit_exec(bContext *C, wmOperator *op)
1585 ARegion *ar= CTX_wm_region(C);
1588 if(ar->regiontype!=RGN_TYPE_WINDOW)
1589 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1590 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1591 ScrArea *sa= CTX_wm_area(C);
1594 /* keep current region */
1597 if(sa->spacetype==SPACE_VIEW3D) {
1598 RegionView3D *rv3d= ar->regiondata;
1602 for(ar= sa->regionbase.first; ar; ar= arn) {
1604 if(ar->alignment==RGN_ALIGN_QSPLIT) {
1605 ED_region_exit(C, ar);
1606 BKE_area_region_free(sa->type, ar);
1607 BLI_remlink(&sa->regionbase, ar);
1611 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1614 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1616 ScrArea *sa= CTX_wm_area(C);
1620 ar->alignment= RGN_ALIGN_QSPLIT;
1622 for(count=0; count<3; count++) {
1623 newar= BKE_area_region_copy(sa->type, ar);
1624 BLI_addtail(&sa->regionbase, newar);
1627 /* lock views and set them */
1628 if(sa->spacetype==SPACE_VIEW3D) {
1631 rv3d= ar->regiondata;
1632 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1635 rv3d= ar->regiondata;
1636 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1639 rv3d= ar->regiondata;
1640 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1643 rv3d= ar->regiondata;
1644 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1647 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1651 return OPERATOR_FINISHED;
1654 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1657 ot->name= "Split Region in 4 Parts";
1658 ot->idname= "SCREEN_OT_region_foursplit";
1661 ot->invoke= WM_operator_confirm;
1662 ot->exec= region_foursplit_exec;
1663 ot->poll= ED_operator_areaactive;
1664 ot->flag= OPTYPE_REGISTER;
1669 /* ************** region flip operator ***************************** */
1671 /* flip a region alignment */
1672 static int region_flip_exec(bContext *C, wmOperator *op)
1674 ARegion *ar= CTX_wm_region(C);
1676 if(ar->alignment==RGN_ALIGN_TOP)
1677 ar->alignment= RGN_ALIGN_BOTTOM;
1678 else if(ar->alignment==RGN_ALIGN_BOTTOM)
1679 ar->alignment= RGN_ALIGN_TOP;
1680 else if(ar->alignment==RGN_ALIGN_LEFT)
1681 ar->alignment= RGN_ALIGN_RIGHT;
1682 else if(ar->alignment==RGN_ALIGN_RIGHT)
1683 ar->alignment= RGN_ALIGN_LEFT;
1685 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1686 printf("executed region flip\n");
1688 return OPERATOR_FINISHED;
1691 static void testfunc(bContext *C, void *argv, int arg)
1693 printf("arg %d\n", arg);
1696 static void newlevel1(bContext *C, uiMenuItem *head, void *arg)
1698 uiMenuFunc(head, testfunc, NULL);
1700 uiMenuItemVal(head, "First", ICON_PROP_ON, 1);
1701 uiMenuItemVal(head, "Second", ICON_PROP_CON, 2);
1702 uiMenuItemVal(head, "Third", ICON_SMOOTHCURVE, 3);
1703 uiMenuItemVal(head, "Fourth", ICON_SHARPCURVE, 4);
1706 static int testing123(bContext *C, wmOperator *op, wmEvent *event)
1708 uiMenuItem *head= uiPupMenuBegin("Hello world", 0);
1710 uiMenuContext(head, WM_OP_EXEC_DEFAULT);
1711 uiMenuItemO(head, ICON_PROP_ON, "SCREEN_OT_region_flip");
1712 uiMenuItemO(head, ICON_PROP_CON, "SCREEN_OT_screen_full_area");
1713 uiMenuItemO(head, ICON_SMOOTHCURVE, "SCREEN_OT_region_foursplit");
1714 uiMenuLevel(head, "Submenu", newlevel1);
1715 uiMenuItemO(head, ICON_PROP_ON, "SCREEN_OT_area_rip");
1717 uiPupMenuEnd(C, head);
1719 /* this operator is only for a menu, not used further */
1720 return OPERATOR_CANCELLED;
1723 void SCREEN_OT_region_flip(wmOperatorType *ot)
1726 ot->name= "Flip Region";
1727 ot->idname= "SCREEN_OT_region_flip";
1730 ot->invoke= testing123; // XXX WM_operator_confirm;
1731 ot->exec= region_flip_exec;
1733 ot->poll= ED_operator_areaactive;
1734 ot->flag= OPTYPE_REGISTER;
1736 RNA_def_int(ot->srna, "test", 0, INT_MIN, INT_MAX, "test", "", INT_MIN, INT_MAX);
1740 /* ****************** anim player, typically with timer ***************** */
1742 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
1744 bScreen *screen= CTX_wm_screen(C);
1746 if(screen->animtimer==event->customdata) {
1747 Scene *scene= CTX_data_scene(C);
1751 if (scene->r.psfra) {
1752 if(scene->r.cfra > scene->r.pefra)
1753 scene->r.cfra= scene->r.psfra;
1756 if(scene->r.cfra > scene->r.efra)
1757 scene->r.cfra= scene->r.sfra;
1760 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1762 return OPERATOR_FINISHED;
1764 return OPERATOR_PASS_THROUGH;
1767 void SCREEN_OT_animation_play(wmOperatorType *ot)
1770 ot->name= "Animation player";
1771 ot->idname= "SCREEN_OT_animation_play";
1774 ot->invoke= screen_animation_play;
1776 ot->poll= ED_operator_screenactive;
1780 /* ************** border select operator (template) ***************************** */
1782 /* operator state vars used: (added by default WM callbacks)
1786 customdata: the wmGesture pointer
1790 exec() has to be filled in by user
1792 invoke() default WM function
1795 modal() default WM function
1796 accept modal events while doing it, calls exec(), handles ESC and border drawing
1798 poll() has to be filled in by user for context
1801 static int border_select_do(bContext *C, wmOperator *op)
1803 int event_type= RNA_int_get(op->ptr, "event_type");
1805 if(event_type==LEFTMOUSE)
1806 printf("border select do select\n");
1807 else if(event_type==RIGHTMOUSE)
1808 printf("border select deselect\n");
1810 printf("border select do something\n");
1815 void SCREEN_OT_border_select(wmOperatorType *ot)
1818 ot->name= "Border select";
1819 ot->idname= "SCREEN_OT_border_select";
1822 ot->exec= border_select_do;
1823 ot->invoke= WM_border_select_invoke;
1824 ot->modal= WM_border_select_modal;
1826 ot->poll= ED_operator_areaactive;
1829 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1830 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1831 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1832 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1833 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1838 /* ****************************** render invoking ***************** */
1840 /* set callbacks, exported to sequence render too.
1841 Only call in foreground (UI) renders. */
1843 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
1844 /* window as the last possible alternative. */
1845 static ScrArea *biggest_non_image_area(bContext *C)
1847 bScreen *sc= CTX_wm_screen(C);
1848 ScrArea *sa, *big= NULL;
1849 int size, maxsize= 0, bwmaxsize= 0;
1852 for(sa= sc->areabase.first; sa; sa= sa->next) {
1853 if(sa->winx > 10 && sa->winy > 10) {
1854 size= sa->winx*sa->winy;
1855 if(sa->spacetype == SPACE_BUTS) {
1856 if(foundwin == 0 && size > bwmaxsize) {
1861 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
1872 static ScrArea *biggest_area(bContext *C)
1874 bScreen *sc= CTX_wm_screen(C);
1875 ScrArea *sa, *big= NULL;
1876 int size, maxsize= 0;
1878 for(sa= sc->areabase.first; sa; sa= sa->next) {
1879 size= sa->winx*sa->winy;
1880 if(size > maxsize) {
1889 static ScrArea *find_area_showing_r_result(bContext *C)
1891 bScreen *sc= CTX_wm_screen(C);
1895 /* find an imagewindow showing render result */
1896 for(sa=sc->areabase.first; sa; sa= sa->next) {
1897 if(sa->spacetype==SPACE_IMAGE) {
1898 sima= sa->spacedata.first;
1899 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
1906 static void screen_set_image_output(bContext *C)
1911 sa= find_area_showing_r_result(C);
1914 /* find largest open non-image area */
1915 sa= biggest_non_image_area(C);
1917 ED_area_newspace(C, sa, SPACE_IMAGE);
1918 sima= sa->spacedata.first;
1920 /* makes ESC go back to prev space */
1921 sima->flag |= SI_PREVSPACE;
1924 /* use any area of decent size */
1925 sa= biggest_area(C);
1926 if(sa->spacetype!=SPACE_IMAGE) {
1927 // XXX newspace(sa, SPACE_IMAGE);
1928 sima= sa->spacedata.first;
1930 /* makes ESC go back to prev space */
1931 sima->flag |= SI_PREVSPACE;
1936 sima= sa->spacedata.first;
1938 /* get the correct image, and scale it */
1939 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
1941 if(G.displaymode==2) { // XXX
1943 sima->flag |= SI_FULLWINDOW;
1945 ed_screen_fullarea(C, sa);
1951 /* executes blocking render */
1952 static int screen_render_exec(bContext *C, wmOperator *op)
1954 Scene *scene= CTX_data_scene(C);
1955 Render *re= RE_GetRender(scene->id.name);
1958 re= RE_NewRender(scene->id.name);
1960 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
1962 if(RNA_boolean_get(op->ptr, "anim"))
1963 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
1965 RE_BlenderFrame(re, scene, scene->r.cfra);
1967 // no redraw needed, we leave state as we entered it
1968 ED_update_for_newframe(C, 1);
1970 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
1972 return OPERATOR_FINISHED;
1975 typedef struct RenderJob {
1986 static void render_freejob(void *rjv)
1993 /* called inside thread! */
1994 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
1998 float x1, y1, *rectf= NULL;
1999 int ymin, ymax, xmin, xmax;
2003 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2004 if(ibuf==NULL) return;
2006 /* if renrect argument, we only refresh scanlines */
2008 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2009 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2012 /* xmin here is first subrect x coord, xmax defines subrect width */
2013 xmin = renrect->xmin;
2014 xmax = renrect->xmax - xmin;
2017 ymin= renrect->ymin;
2018 ymax= renrect->ymax - ymin;
2021 renrect->ymin= renrect->ymax;
2024 xmin = ymin = rr->crop;
2025 xmax = rr->rectx - 2*rr->crop;
2026 ymax = rr->recty - 2*rr->crop;
2029 /* xmin ymin is in tile coords. transform to ibuf */
2030 rxmin= rr->tilerect.xmin + xmin;
2031 if(rxmin >= ibuf->x) return;
2032 rymin= rr->tilerect.ymin + ymin;
2033 if(rymin >= ibuf->y) return;
2035 if(rxmin + xmax > ibuf->x)
2036 xmax= ibuf->x - rxmin;
2037 if(rymin + ymax > ibuf->y)
2038 ymax= ibuf->y - rymin;
2039 if(xmax < 1 || ymax < 1) return;
2041 /* find current float rect for display, first case is after composit... still weak */
2048 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2049 rectf= rr->renlay->rectf;
2052 if(rectf==NULL) return;
2054 rectf+= 4*(rr->rectx*ymin + xmin);
2055 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2057 for(y1= 0; y1<ymax; y1++) {
2061 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2062 rc[0]= FTOCHAR(rf[0]);
2063 rc[1]= FTOCHAR(rf[1]);
2064 rc[2]= FTOCHAR(rf[2]);
2065 rc[3]= FTOCHAR(rf[3]);
2067 rectf += 4*rr->rectx;
2071 /* make jobs timer to send notifier */
2072 *(rj->do_update)= 1;
2075 static void render_startjob(void *rjv, short *stop, short *do_update)
2080 rj->do_update= do_update;
2083 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2085 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2088 /* called by render, check job 'stop' value or the global */
2089 static int render_breakjob(void *rjv)
2095 if(rj->stop && *(rj->stop))
2100 /* using context, starts job */
2101 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2103 /* new render clears all callbacks */
2104 Scene *scene= CTX_data_scene(C);
2110 /* only one job at a time */
2111 if(WM_jobs_test(CTX_wm_manager(C), scene))
2112 return OPERATOR_CANCELLED;
2114 /* handle UI stuff */
2117 /* flush multires changes (for sculpt) */
2118 multires_force_update(CTX_data_active_object(C));
2120 // get editmode results
2122 // get view3d layer, local layer, make this nice api call to render
2125 /* ensure at least 1 area shows result */
2126 screen_set_image_output(C);
2128 /* job custom data */
2129 rj= MEM_callocN(sizeof(RenderJob), "render job");
2131 rj->win= CTX_wm_window(C);
2132 rj->anim= RNA_boolean_get(op->ptr, "anim");
2133 rj->iuser.scene= scene;
2137 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2138 WM_jobs_customdata(steve, rj, render_freejob);
2139 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2140 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2142 /* get a render result image, and make sure it is empty */
2143 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2144 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2147 /* setup new render */
2148 re= RE_NewRender(scene->id.name);
2149 RE_test_break_cb(re, rj, render_breakjob);
2150 RE_display_draw_cb(re, rj, image_rect_update);
2154 // BKE_report in render!
2155 // RE_error_cb(re, error_cb);
2157 WM_jobs_start(steve);
2162 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2164 return OPERATOR_FINISHED;
2168 /* contextual render, using current scene, view3d? */
2169 void SCREEN_OT_render(wmOperatorType *ot)
2173 ot->idname= "SCREEN_OT_render";
2176 ot->invoke= screen_render_invoke;
2177 ot->exec= screen_render_exec;
2179 ot->poll= ED_operator_screenactive;
2181 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2182 RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2185 /* *********************** cancel render viewer *************** */
2187 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2189 ScrArea *sa= CTX_wm_area(C);
2190 SpaceImage *sima= sa->spacedata.first;
2192 if(sima->flag & SI_PREVSPACE) {
2193 sima->flag &= ~SI_PREVSPACE;
2194 ED_area_prevspace(C);
2196 else if(sima->flag & SI_FULLWINDOW) {
2197 sima->flag &= ~SI_FULLWINDOW;
2198 ED_screen_full_prevspace(C);
2201 return OPERATOR_FINISHED;
2204 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2207 ot->name= "Cancel Render View";
2208 ot->idname= "SCREEN_OT_render_view_cancel";
2211 ot->exec= render_view_cancel_exec;
2212 ot->poll= ED_operator_image_active;
2216 /* **************** Assigning operatortypes to global list, adding handlers **************** */
2218 /* called in spacetypes.c */
2219 void ED_operatortypes_screen(void)
2221 /* generic UI stuff */
2222 WM_operatortype_append(SCREEN_OT_actionzone);
2223 WM_operatortype_append(SCREEN_OT_repeat_last);
2224 WM_operatortype_append(SCREEN_OT_repeat_history);
2225 WM_operatortype_append(SCREEN_OT_redo_last);
2228 WM_operatortype_append(SCREEN_OT_area_move);
2229 WM_operatortype_append(SCREEN_OT_area_split);
2230 WM_operatortype_append(SCREEN_OT_area_join);
2231 WM_operatortype_append(SCREEN_OT_area_rip);
2232 WM_operatortype_append(SCREEN_OT_region_split);
2233 WM_operatortype_append(SCREEN_OT_region_foursplit);
2234 WM_operatortype_append(SCREEN_OT_region_flip);
2235 WM_operatortype_append(SCREEN_OT_screen_set);
2236 WM_operatortype_append(SCREEN_OT_screen_full_area);
2239 WM_operatortype_append(SCREEN_OT_frame_offset);
2240 WM_operatortype_append(SCREEN_OT_animation_play);
2243 WM_operatortype_append(SCREEN_OT_render);
2244 WM_operatortype_append(SCREEN_OT_render_view_cancel);
2246 /* tools shared by more space types */
2247 WM_operatortype_append(ED_OT_undo);
2248 WM_operatortype_append(ED_OT_redo);
2252 /* called in spacetypes.c */
2253 void ED_keymap_screen(wmWindowManager *wm)
2255 ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2257 /* standard timers */
2258 WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
2260 WM_keymap_verify_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0);
2262 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2263 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0);
2264 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);
2265 WM_keymap_verify_item(keymap, "SCREEN_OT_area_rip", RKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2266 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2267 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2268 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2269 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2270 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2273 WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2274 WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2276 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2277 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2278 WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2279 WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2282 WM_keymap_add_item(keymap, "ED_FILE_OT_load", RETKEY, KM_PRESS, 0, 0);
2283 WM_keymap_add_item(keymap, "ED_FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2286 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2287 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2288 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2289 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2292 WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2293 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2296 keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2297 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2298 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2299 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2300 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);