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 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1029 int delta= RNA_int_get(op->ptr, "delta");
1031 /* this screen is 'fake', solve later XXX */
1032 if(CTX_wm_area(C)->full)
1033 return OPERATOR_CANCELLED;
1037 screen= screen->id.next;
1038 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1039 if(screen->winid==0 && screen->full==0)
1043 else if(delta== -1) {
1045 screen= screen->id.prev;
1046 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1047 if(screen->winid==0 && screen->full==0)
1056 ED_screen_set(C, screen);
1057 return OPERATOR_FINISHED;
1059 return OPERATOR_CANCELLED;
1062 void SCREEN_OT_screen_set(wmOperatorType *ot)
1064 ot->name = "Set Screen";
1065 ot->idname = "SCREEN_OT_screen_set";
1067 ot->exec= screen_set_exec;
1068 ot->poll= ED_operator_screenactive;
1071 RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1072 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1075 /* ************** screen full-area operator ***************************** */
1078 /* function to be called outside UI context, or for redo */
1079 static int screen_full_area_exec(bContext *C, wmOperator *op)
1081 ed_screen_fullarea(C, CTX_wm_area(C));
1082 return OPERATOR_FINISHED;
1085 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1087 ot->name = "Toggle Make Area Fullscreen";
1088 ot->idname = "SCREEN_OT_screen_full_area";
1090 ot->exec= screen_full_area_exec;
1091 ot->poll= ED_operator_screenactive;
1092 ot->flag= OPTYPE_REGISTER;
1098 /* ************** join area operator ********************************************** */
1100 /* operator state vars used:
1101 x1, y1 mouse coord in first area, which will disappear
1102 x2, y2 mouse coord in 2nd area, which will become joined
1106 init() find edge based on state vars
1107 test if the edge divides two areas,
1108 store active and nonactive area,
1110 apply() do the actual join
1112 exit() cleanup, send notifier
1116 exec() calls init, apply, exit
1118 invoke() sets mouse coords in x,y
1122 modal() accept modal events while doing it
1123 call apply() with active window and nonactive window
1124 call exit() and remove handler when LMB confirm
1128 typedef struct sAreaJoinData
1130 ScrArea *sa1; /* first area to be considered */
1131 ScrArea *sa2; /* second area to be considered */
1132 ScrArea *scr; /* designed for removal */
1137 /* validate selection inside screen, set variables OK */
1138 /* return 0: init failed */
1139 /* XXX todo: find edge based on (x,y) and set other area? */
1140 static int area_join_init(bContext *C, wmOperator *op)
1143 sAreaJoinData* jd= NULL;
1147 /* required properties, make negative to get return 0 if not set by caller */
1148 x1= RNA_int_get(op->ptr, "x1");
1149 y1= RNA_int_get(op->ptr, "y1");
1150 x2= RNA_int_get(op->ptr, "x2");
1151 y2= RNA_int_get(op->ptr, "y2");
1153 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1154 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1155 if(sa1==NULL || sa2==NULL || sa1==sa2)
1158 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1161 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1163 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1170 /* apply the join of the areas (space types) */
1171 static int area_join_apply(bContext *C, wmOperator *op)
1173 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1176 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1179 if (CTX_wm_area(C) == jd->sa2) {
1180 CTX_wm_area_set(C, NULL);
1181 CTX_wm_region_set(C, NULL);
1187 /* finish operation */
1188 static void area_join_exit(bContext *C, wmOperator *op)
1190 if (op->customdata) {
1191 MEM_freeN(op->customdata);
1192 op->customdata = NULL;
1195 /* this makes sure aligned edges will result in aligned grabbing */
1196 removedouble_scredges(CTX_wm_screen(C));
1197 removenotused_scredges(CTX_wm_screen(C));
1198 removenotused_scrverts(CTX_wm_screen(C));
1201 static int area_join_exec(bContext *C, wmOperator *op)
1203 if(!area_join_init(C, op))
1204 return OPERATOR_CANCELLED;
1206 area_join_apply(C, op);
1207 area_join_exit(C, op);
1209 return OPERATOR_FINISHED;
1212 /* interaction callback */
1213 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1216 if(event->type==EVT_ACTIONZONE) {
1217 sActionzoneData *sad= event->customdata;
1219 /* verify *sad itself */
1220 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1221 return OPERATOR_PASS_THROUGH;
1223 /* is this our *sad? if areas equal it should be passed on */
1224 if(sad->sa1==sad->sa2)
1225 return OPERATOR_PASS_THROUGH;
1227 /* prepare operator state vars */
1228 RNA_int_set(op->ptr, "x1", sad->x);
1229 RNA_int_set(op->ptr, "y1", sad->y);
1230 RNA_int_set(op->ptr, "x2", event->x);
1231 RNA_int_set(op->ptr, "y2", event->y);
1233 if(!area_join_init(C, op))
1234 return OPERATOR_PASS_THROUGH;
1236 /* add temp handler */
1237 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1239 return OPERATOR_RUNNING_MODAL;
1242 return OPERATOR_PASS_THROUGH;
1245 static int area_join_cancel(bContext *C, wmOperator *op)
1247 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1250 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1251 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1254 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1255 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1258 WM_event_add_notifier(C, NC_WINDOW, NULL);
1260 area_join_exit(C, op);
1262 return OPERATOR_CANCELLED;
1265 /* modal callback while selecting area (space) that will be removed */
1266 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1268 bScreen *sc= CTX_wm_screen(C);
1269 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1271 /* execute the events */
1272 switch(event->type) {
1276 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1280 if (jd->sa1 != sa) {
1281 dir = area_getorientation(sc, jd->sa1, sa);
1283 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1285 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1288 /* we are not bordering on the previously selected area
1289 we check if area has common border with the one marked for removal
1290 in this case we can swap areas.
1292 dir = area_getorientation(sc, sa, jd->sa2);
1294 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1295 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1298 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1299 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1302 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1306 WM_event_add_notifier(C, NC_WINDOW, NULL);
1309 /* we are back in the area previously selected for keeping
1310 * we swap the areas if possible to allow user to choose */
1311 if (jd->sa2 != NULL) {
1312 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1313 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1316 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1317 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1318 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1320 printf("oops, didn't expect that!\n");
1324 dir = area_getorientation(sc, jd->sa1, sa);
1326 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1328 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1331 WM_event_add_notifier(C, NC_WINDOW, NULL);
1338 area_join_apply(C, op);
1339 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1340 area_join_exit(C, op);
1341 return OPERATOR_FINISHED;
1346 return area_join_cancel(C, op);
1349 return OPERATOR_RUNNING_MODAL;
1352 /* Operator for joining two areas (space types) */
1353 void SCREEN_OT_area_join(wmOperatorType *ot)
1356 ot->name= "Join area";
1357 ot->idname= "SCREEN_OT_area_join";
1360 ot->exec= area_join_exec;
1361 ot->invoke= area_join_invoke;
1362 ot->modal= area_join_modal;
1364 ot->poll= ED_operator_screenactive;
1367 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1368 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1369 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1370 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1373 /* ************** repeat last operator ***************************** */
1375 static int repeat_last_exec(bContext *C, wmOperator *op)
1377 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1380 WM_operator_repeat(C, lastop);
1382 return OPERATOR_CANCELLED;
1385 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1388 ot->name= "Repeat Last";
1389 ot->idname= "SCREEN_OT_repeat_last";
1392 ot->exec= repeat_last_exec;
1394 ot->poll= ED_operator_screenactive;
1398 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1400 wmWindowManager *wm= CTX_wm_manager(C);
1405 items= BLI_countlist(&wm->operators);
1407 return OPERATOR_CANCELLED;
1409 head= uiPupMenuBegin(op->type->name, 0);
1411 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1412 uiMenuItemIntO(head, lastop->type->name, 0, op->type->idname, "index", i);
1414 uiPupMenuEnd(C, head);
1416 return OPERATOR_CANCELLED;
1419 static int repeat_history_exec(bContext *C, wmOperator *op)
1421 wmWindowManager *wm= CTX_wm_manager(C);
1423 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1425 /* let's put it as last operator in list */
1426 BLI_remlink(&wm->operators, op);
1427 BLI_addtail(&wm->operators, op);
1429 WM_operator_repeat(C, op);
1432 return OPERATOR_FINISHED;
1435 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1438 ot->name= "Repeat History";
1439 ot->idname= "SCREEN_OT_repeat_history";
1442 ot->invoke= repeat_history_invoke;
1443 ot->exec= repeat_history_exec;
1445 ot->poll= ED_operator_screenactive;
1447 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1450 /* ********************** redo operator ***************************** */
1452 static int redo_last_exec(bContext *C, wmOperator *op)
1455 /* XXX context is not correct after popup menu */
1456 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1460 WM_operator_repeat(C, lastop);
1464 return OPERATOR_CANCELLED;
1467 static void redo_last_cb(bContext *C, void *arg1, void *arg2)
1469 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1473 WM_operator_repeat(C, lastop);
1478 static uiBlock *ui_block_create_redo_last(bContext *C, ARegion *ar, void *arg_op)
1480 wmWindowManager *wm= CTX_wm_manager(C);
1481 wmOperator *op= arg_op;
1486 block= uiBeginBlock(C, ar, "redo_last_popup", UI_EMBOSS, UI_HELV);
1487 uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1);
1488 uiBlockSetFunc(block, redo_last_cb, NULL, NULL);
1490 if(!op->properties) {
1491 IDPropertyTemplate val = {0};
1492 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
1495 RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
1496 height= uiDefAutoButsRNA(block, &ptr);
1498 uiPopupBoundsBlock(block, 4.0f, 0, 0);
1499 uiEndBlock(C, block);
1504 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1506 wmWindowManager *wm= CTX_wm_manager(C);
1507 wmOperator *lastop= wm->operators.last;
1510 return OPERATOR_CANCELLED;
1512 /* only for operators that are registered and did an undo push */
1513 if(!(lastop->type->flag & OPTYPE_REGISTER) || !(lastop->type->flag & OPTYPE_UNDO))
1514 return OPERATOR_CANCELLED;
1516 uiPupBlockO(C, ui_block_create_redo_last, lastop, op->type->idname, WM_OP_EXEC_DEFAULT);
1518 return OPERATOR_CANCELLED;
1521 void SCREEN_OT_redo_last(wmOperatorType *ot)
1524 ot->name= "Redo Last";
1525 ot->idname= "SCREEN_OT_redo_last";
1528 ot->invoke= redo_last_invoke;
1529 ot->exec= redo_last_exec;
1531 ot->poll= ED_operator_screenactive;
1534 /* ************** region split operator ***************************** */
1536 /* insert a region in the area region list */
1537 static int region_split_exec(bContext *C, wmOperator *op)
1539 ARegion *ar= CTX_wm_region(C);
1541 if(ar->regiontype==RGN_TYPE_HEADER)
1542 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1543 else if(ar->alignment==RGN_ALIGN_QSPLIT)
1544 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1546 ScrArea *sa= CTX_wm_area(C);
1547 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1548 int dir= RNA_enum_get(op->ptr, "type");
1550 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1552 newar->alignment= ar->alignment;
1555 ar->alignment= RGN_ALIGN_HSPLIT;
1557 ar->alignment= RGN_ALIGN_VSPLIT;
1559 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1562 return OPERATOR_FINISHED;
1565 void SCREEN_OT_region_split(wmOperatorType *ot)
1568 ot->name= "Split Region";
1569 ot->idname= "SCREEN_OT_region_split";
1572 ot->invoke= WM_menu_invoke;
1573 ot->exec= region_split_exec;
1574 ot->poll= ED_operator_areaactive;
1576 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1579 /* ************** region four-split operator ***************************** */
1581 /* insert a region in the area region list */
1582 static int region_foursplit_exec(bContext *C, wmOperator *op)
1584 ARegion *ar= CTX_wm_region(C);
1587 if(ar->regiontype!=RGN_TYPE_WINDOW)
1588 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1589 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1590 ScrArea *sa= CTX_wm_area(C);
1593 /* keep current region */
1596 if(sa->spacetype==SPACE_VIEW3D) {
1597 RegionView3D *rv3d= ar->regiondata;
1601 for(ar= sa->regionbase.first; ar; ar= arn) {
1603 if(ar->alignment==RGN_ALIGN_QSPLIT) {
1604 ED_region_exit(C, ar);
1605 BKE_area_region_free(sa->type, ar);
1606 BLI_remlink(&sa->regionbase, ar);
1610 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1613 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1615 ScrArea *sa= CTX_wm_area(C);
1619 ar->alignment= RGN_ALIGN_QSPLIT;
1621 for(count=0; count<3; count++) {
1622 newar= BKE_area_region_copy(sa->type, ar);
1623 BLI_addtail(&sa->regionbase, newar);
1626 /* lock views and set them */
1627 if(sa->spacetype==SPACE_VIEW3D) {
1630 rv3d= ar->regiondata;
1631 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1634 rv3d= ar->regiondata;
1635 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1638 rv3d= ar->regiondata;
1639 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1642 rv3d= ar->regiondata;
1643 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1646 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1650 return OPERATOR_FINISHED;
1653 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1656 ot->name= "Split Region in 4 Parts";
1657 ot->idname= "SCREEN_OT_region_foursplit";
1660 ot->invoke= WM_operator_confirm;
1661 ot->exec= region_foursplit_exec;
1662 ot->poll= ED_operator_areaactive;
1663 ot->flag= OPTYPE_REGISTER;
1668 /* ************** region flip operator ***************************** */
1670 /* flip a region alignment */
1671 static int region_flip_exec(bContext *C, wmOperator *op)
1673 ARegion *ar= CTX_wm_region(C);
1675 if(ar->alignment==RGN_ALIGN_TOP)
1676 ar->alignment= RGN_ALIGN_BOTTOM;
1677 else if(ar->alignment==RGN_ALIGN_BOTTOM)
1678 ar->alignment= RGN_ALIGN_TOP;
1679 else if(ar->alignment==RGN_ALIGN_LEFT)
1680 ar->alignment= RGN_ALIGN_RIGHT;
1681 else if(ar->alignment==RGN_ALIGN_RIGHT)
1682 ar->alignment= RGN_ALIGN_LEFT;
1684 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1685 printf("executed region flip\n");
1687 return OPERATOR_FINISHED;
1690 static void testfunc(bContext *C, void *argv, int arg)
1692 printf("arg %d\n", arg);
1695 static void newlevel1(bContext *C, uiMenuItem *head, void *arg)
1697 uiMenuFunc(head, testfunc, NULL);
1699 uiMenuItemVal(head, "First", ICON_PROP_ON, 1);
1700 uiMenuItemVal(head, "Second", ICON_PROP_CON, 2);
1701 uiMenuItemVal(head, "Third", ICON_SMOOTHCURVE, 3);
1702 uiMenuItemVal(head, "Fourth", ICON_SHARPCURVE, 4);
1705 static int testing123(bContext *C, wmOperator *op, wmEvent *event)
1707 uiMenuItem *head= uiPupMenuBegin("Hello world", 0);
1709 uiMenuContext(head, WM_OP_EXEC_DEFAULT);
1710 uiMenuItemO(head, ICON_PROP_ON, "SCREEN_OT_region_flip");
1711 uiMenuItemO(head, ICON_PROP_CON, "SCREEN_OT_screen_full_area");
1712 uiMenuItemO(head, ICON_SMOOTHCURVE, "SCREEN_OT_region_foursplit");
1713 uiMenuLevel(head, "Submenu", newlevel1);
1714 uiMenuItemO(head, ICON_PROP_ON, "SCREEN_OT_area_rip");
1716 uiPupMenuEnd(C, head);
1718 /* this operator is only for a menu, not used further */
1719 return OPERATOR_CANCELLED;
1722 void SCREEN_OT_region_flip(wmOperatorType *ot)
1725 ot->name= "Flip Region";
1726 ot->idname= "SCREEN_OT_region_flip";
1729 ot->invoke= testing123; // XXX WM_operator_confirm;
1730 ot->exec= region_flip_exec;
1732 ot->poll= ED_operator_areaactive;
1733 ot->flag= OPTYPE_REGISTER;
1735 RNA_def_int(ot->srna, "test", 0, INT_MIN, INT_MAX, "test", "", INT_MIN, INT_MAX);
1739 /* ****************** anim player, typically with timer ***************** */
1741 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
1743 bScreen *screen= CTX_wm_screen(C);
1745 if(screen->animtimer==event->customdata) {
1746 Scene *scene= CTX_data_scene(C);
1750 if (scene->r.psfra) {
1751 if(scene->r.cfra > scene->r.pefra)
1752 scene->r.cfra= scene->r.psfra;
1755 if(scene->r.cfra > scene->r.efra)
1756 scene->r.cfra= scene->r.sfra;
1759 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1761 return OPERATOR_FINISHED;
1763 return OPERATOR_PASS_THROUGH;
1766 void SCREEN_OT_animation_play(wmOperatorType *ot)
1769 ot->name= "Animation player";
1770 ot->idname= "SCREEN_OT_animation_play";
1773 ot->invoke= screen_animation_play;
1775 ot->poll= ED_operator_screenactive;
1779 /* ************** border select operator (template) ***************************** */
1781 /* operator state vars used: (added by default WM callbacks)
1785 customdata: the wmGesture pointer
1789 exec() has to be filled in by user
1791 invoke() default WM function
1794 modal() default WM function
1795 accept modal events while doing it, calls exec(), handles ESC and border drawing
1797 poll() has to be filled in by user for context
1800 static int border_select_do(bContext *C, wmOperator *op)
1802 int event_type= RNA_int_get(op->ptr, "event_type");
1804 if(event_type==LEFTMOUSE)
1805 printf("border select do select\n");
1806 else if(event_type==RIGHTMOUSE)
1807 printf("border select deselect\n");
1809 printf("border select do something\n");
1814 void SCREEN_OT_border_select(wmOperatorType *ot)
1817 ot->name= "Border select";
1818 ot->idname= "SCREEN_OT_border_select";
1821 ot->exec= border_select_do;
1822 ot->invoke= WM_border_select_invoke;
1823 ot->modal= WM_border_select_modal;
1825 ot->poll= ED_operator_areaactive;
1828 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1829 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1830 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1831 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1832 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1837 /* ****************************** render invoking ***************** */
1839 /* set callbacks, exported to sequence render too.
1840 Only call in foreground (UI) renders. */
1842 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
1843 /* window as the last possible alternative. */
1844 static ScrArea *biggest_non_image_area(bContext *C)
1846 bScreen *sc= CTX_wm_screen(C);
1847 ScrArea *sa, *big= NULL;
1848 int size, maxsize= 0, bwmaxsize= 0;
1851 for(sa= sc->areabase.first; sa; sa= sa->next) {
1852 if(sa->winx > 10 && sa->winy > 10) {
1853 size= sa->winx*sa->winy;
1854 if(sa->spacetype == SPACE_BUTS) {
1855 if(foundwin == 0 && size > bwmaxsize) {
1860 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
1871 static ScrArea *biggest_area(bContext *C)
1873 bScreen *sc= CTX_wm_screen(C);
1874 ScrArea *sa, *big= NULL;
1875 int size, maxsize= 0;
1877 for(sa= sc->areabase.first; sa; sa= sa->next) {
1878 size= sa->winx*sa->winy;
1879 if(size > maxsize) {
1888 static ScrArea *find_area_showing_r_result(bContext *C)
1890 bScreen *sc= CTX_wm_screen(C);
1894 /* find an imagewindow showing render result */
1895 for(sa=sc->areabase.first; sa; sa= sa->next) {
1896 if(sa->spacetype==SPACE_IMAGE) {
1897 sima= sa->spacedata.first;
1898 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
1905 static void screen_set_image_output(bContext *C)
1910 sa= find_area_showing_r_result(C);
1913 /* find largest open non-image area */
1914 sa= biggest_non_image_area(C);
1916 ED_area_newspace(C, sa, SPACE_IMAGE);
1917 sima= sa->spacedata.first;
1919 /* makes ESC go back to prev space */
1920 sima->flag |= SI_PREVSPACE;
1923 /* use any area of decent size */
1924 sa= biggest_area(C);
1925 if(sa->spacetype!=SPACE_IMAGE) {
1926 // XXX newspace(sa, SPACE_IMAGE);
1927 sima= sa->spacedata.first;
1929 /* makes ESC go back to prev space */
1930 sima->flag |= SI_PREVSPACE;
1935 sima= sa->spacedata.first;
1937 /* get the correct image, and scale it */
1938 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
1940 if(G.displaymode==2) { // XXX
1942 sima->flag |= SI_FULLWINDOW;
1944 ed_screen_fullarea(C, sa);
1950 /* executes blocking render */
1951 static int screen_render_exec(bContext *C, wmOperator *op)
1953 Scene *scene= CTX_data_scene(C);
1954 Render *re= RE_GetRender(scene->id.name);
1957 re= RE_NewRender(scene->id.name);
1959 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
1961 if(RNA_boolean_get(op->ptr, "anim"))
1962 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
1964 RE_BlenderFrame(re, scene, scene->r.cfra);
1966 // no redraw needed, we leave state as we entered it
1967 ED_update_for_newframe(C, 1);
1969 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
1971 return OPERATOR_FINISHED;
1974 typedef struct RenderJob {
1985 static void render_freejob(void *rjv)
1992 /* called inside thread! */
1993 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
1997 float x1, y1, *rectf= NULL;
1998 int ymin, ymax, xmin, xmax;
2002 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2003 if(ibuf==NULL) return;
2005 /* if renrect argument, we only refresh scanlines */
2007 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2008 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2011 /* xmin here is first subrect x coord, xmax defines subrect width */
2012 xmin = renrect->xmin;
2013 xmax = renrect->xmax - xmin;
2016 ymin= renrect->ymin;
2017 ymax= renrect->ymax - ymin;
2020 renrect->ymin= renrect->ymax;
2023 xmin = ymin = rr->crop;
2024 xmax = rr->rectx - 2*rr->crop;
2025 ymax = rr->recty - 2*rr->crop;
2028 /* xmin ymin is in tile coords. transform to ibuf */
2029 rxmin= rr->tilerect.xmin + xmin;
2030 if(rxmin >= ibuf->x) return;
2031 rymin= rr->tilerect.ymin + ymin;
2032 if(rymin >= ibuf->y) return;
2034 if(rxmin + xmax > ibuf->x)
2035 xmax= ibuf->x - rxmin;
2036 if(rymin + ymax > ibuf->y)
2037 ymax= ibuf->y - rymin;
2038 if(xmax < 1 || ymax < 1) return;
2040 /* find current float rect for display, first case is after composit... still weak */
2047 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2048 rectf= rr->renlay->rectf;
2051 if(rectf==NULL) return;
2053 rectf+= 4*(rr->rectx*ymin + xmin);
2054 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2056 for(y1= 0; y1<ymax; y1++) {
2060 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2061 rc[0]= FTOCHAR(rf[0]);
2062 rc[1]= FTOCHAR(rf[1]);
2063 rc[2]= FTOCHAR(rf[2]);
2064 rc[3]= FTOCHAR(rf[3]);
2066 rectf += 4*rr->rectx;
2070 /* make jobs timer to send notifier */
2071 *(rj->do_update)= 1;
2074 static void render_startjob(void *rjv, short *stop, short *do_update)
2079 rj->do_update= do_update;
2082 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2084 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2087 /* called by render, check job 'stop' value or the global */
2088 static int render_breakjob(void *rjv)
2094 if(rj->stop && *(rj->stop))
2099 /* using context, starts job */
2100 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2102 /* new render clears all callbacks */
2103 Scene *scene= CTX_data_scene(C);
2109 /* only one job at a time */
2110 if(WM_jobs_test(CTX_wm_manager(C), scene))
2111 return OPERATOR_CANCELLED;
2113 /* handle UI stuff */
2116 /* flush multires changes (for sculpt) */
2117 multires_force_update(CTX_data_active_object(C));
2119 // get editmode results
2121 // get view3d layer, local layer, make this nice api call to render
2124 /* ensure at least 1 area shows result */
2125 screen_set_image_output(C);
2127 /* job custom data */
2128 rj= MEM_callocN(sizeof(RenderJob), "render job");
2130 rj->win= CTX_wm_window(C);
2131 rj->anim= RNA_boolean_get(op->ptr, "anim");
2132 rj->iuser.scene= scene;
2136 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2137 WM_jobs_customdata(steve, rj, render_freejob);
2138 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2139 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2141 /* get a render result image, and make sure it is empty */
2142 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2143 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2146 /* setup new render */
2147 re= RE_NewRender(scene->id.name);
2148 RE_test_break_cb(re, rj, render_breakjob);
2149 RE_display_draw_cb(re, rj, image_rect_update);
2153 // BKE_report in render!
2154 // RE_error_cb(re, error_cb);
2156 WM_jobs_start(steve);
2161 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2163 return OPERATOR_FINISHED;
2167 /* contextual render, using current scene, view3d? */
2168 void SCREEN_OT_render(wmOperatorType *ot)
2172 ot->idname= "SCREEN_OT_render";
2175 ot->invoke= screen_render_invoke;
2176 ot->exec= screen_render_exec;
2178 ot->poll= ED_operator_screenactive;
2180 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2181 RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2184 /* *********************** cancel render viewer *************** */
2186 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2188 ScrArea *sa= CTX_wm_area(C);
2189 SpaceImage *sima= sa->spacedata.first;
2191 if(sima->flag & SI_PREVSPACE) {
2192 sima->flag &= ~SI_PREVSPACE;
2193 ED_area_prevspace(C);
2195 else if(sima->flag & SI_FULLWINDOW) {
2196 sima->flag &= ~SI_FULLWINDOW;
2197 ED_screen_full_prevspace(C);
2200 return OPERATOR_FINISHED;
2203 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2206 ot->name= "Cancel Render View";
2207 ot->idname= "SCREEN_OT_render_view_cancel";
2210 ot->exec= render_view_cancel_exec;
2211 ot->poll= ED_operator_image_active;
2215 /* **************** Assigning operatortypes to global list, adding handlers **************** */
2217 /* called in spacetypes.c */
2218 void ED_operatortypes_screen(void)
2220 /* generic UI stuff */
2221 WM_operatortype_append(SCREEN_OT_actionzone);
2222 WM_operatortype_append(SCREEN_OT_repeat_last);
2223 WM_operatortype_append(SCREEN_OT_repeat_history);
2224 WM_operatortype_append(SCREEN_OT_redo_last);
2227 WM_operatortype_append(SCREEN_OT_area_move);
2228 WM_operatortype_append(SCREEN_OT_area_split);
2229 WM_operatortype_append(SCREEN_OT_area_join);
2230 WM_operatortype_append(SCREEN_OT_area_rip);
2231 WM_operatortype_append(SCREEN_OT_region_split);
2232 WM_operatortype_append(SCREEN_OT_region_foursplit);
2233 WM_operatortype_append(SCREEN_OT_region_flip);
2234 WM_operatortype_append(SCREEN_OT_screen_set);
2235 WM_operatortype_append(SCREEN_OT_screen_full_area);
2238 WM_operatortype_append(SCREEN_OT_frame_offset);
2239 WM_operatortype_append(SCREEN_OT_animation_play);
2242 WM_operatortype_append(SCREEN_OT_render);
2243 WM_operatortype_append(SCREEN_OT_render_view_cancel);
2245 /* tools shared by more space types */
2246 WM_operatortype_append(ED_OT_undo);
2247 WM_operatortype_append(ED_OT_redo);
2251 /* called in spacetypes.c */
2252 void ED_keymap_screen(wmWindowManager *wm)
2254 ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2256 /* standard timers */
2257 WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
2259 WM_keymap_verify_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0);
2261 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2262 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0);
2263 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);
2264 WM_keymap_verify_item(keymap, "SCREEN_OT_area_rip", RKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2265 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2266 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2267 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2268 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2269 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2272 WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2273 WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2275 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2276 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2277 WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2278 WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2281 WM_keymap_add_item(keymap, "ED_FILE_OT_load", RETKEY, KM_PRESS, 0, 0);
2282 WM_keymap_add_item(keymap, "ED_FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2285 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2286 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2287 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2288 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2291 WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2292 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2295 keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2296 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2297 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2298 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2299 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);