4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * ***** END GPL LICENSE BLOCK *****
29 #include "MEM_guardedalloc.h"
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_editVert.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_image_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_scene_types.h"
42 #include "BKE_blender.h"
43 #include "BKE_context.h"
44 #include "BKE_customdata.h"
45 #include "BKE_global.h"
46 #include "BKE_image.h"
47 #include "BKE_idprop.h"
48 #include "BKE_library.h"
51 #include "BKE_multires.h"
52 #include "BKE_report.h"
53 #include "BKE_screen.h"
54 #include "BKE_utildefines.h"
60 #include "ED_screen.h"
62 #include "ED_screen_types.h"
64 #include "RE_pipeline.h"
65 #include "IMB_imbuf.h"
66 #include "IMB_imbuf_types.h"
68 #include "RNA_access.h"
69 #include "RNA_define.h"
71 #include "UI_interface.h"
72 #include "UI_resources.h"
74 #include "screen_intern.h" /* own module include */
76 /* ************** Exported Poll tests ********************** */
78 int ED_operator_regionactive(bContext *C)
80 if(CTX_wm_window(C)==NULL) return 0;
81 if(CTX_wm_screen(C)==NULL) return 0;
82 if(CTX_wm_region(C)==NULL) return 0;
86 int ED_operator_areaactive(bContext *C)
88 if(CTX_wm_window(C)==NULL) return 0;
89 if(CTX_wm_screen(C)==NULL) return 0;
90 if(CTX_wm_area(C)==NULL) return 0;
94 int ED_operator_screenactive(bContext *C)
96 if(CTX_wm_window(C)==NULL) return 0;
97 if(CTX_wm_screen(C)==NULL) return 0;
101 /* when mouse is over area-edge */
102 int ED_operator_screen_mainwinactive(bContext *C)
104 if(CTX_wm_window(C)==NULL) return 0;
105 if(CTX_wm_screen(C)==NULL) return 0;
106 if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
110 int ED_operator_scene_editable(bContext *C)
112 Scene *scene= CTX_data_scene(C);
113 if(scene && scene->id.lib==NULL)
118 static int ed_spacetype_test(bContext *C, int type)
120 if(ED_operator_areaactive(C)) {
121 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
122 return sl && (sl->spacetype == type);
127 int ED_operator_view3d_active(bContext *C)
129 return ed_spacetype_test(C, SPACE_VIEW3D);
132 int ED_operator_timeline_active(bContext *C)
134 return ed_spacetype_test(C, SPACE_TIME);
137 int ED_operator_outliner_active(bContext *C)
139 return ed_spacetype_test(C, SPACE_OUTLINER);
142 int ED_operator_file_active(bContext *C)
144 return ed_spacetype_test(C, SPACE_FILE);
147 int ED_operator_action_active(bContext *C)
149 return ed_spacetype_test(C, SPACE_ACTION);
152 int ED_operator_buttons_active(bContext *C)
154 return ed_spacetype_test(C, SPACE_BUTS);
157 int ED_operator_node_active(bContext *C)
159 if(ed_spacetype_test(C, SPACE_NODE)) {
160 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
167 int ED_operator_ipo_active(bContext *C)
169 return ed_spacetype_test(C, SPACE_IPO);
172 int ED_operator_sequencer_active(bContext *C)
174 return ed_spacetype_test(C, SPACE_SEQ);
177 int ED_operator_image_active(bContext *C)
179 return ed_spacetype_test(C, SPACE_IMAGE);
182 int ED_operator_object_active(bContext *C)
184 return NULL != CTX_data_active_object(C);
187 int ED_operator_editmesh(bContext *C)
189 Object *obedit= CTX_data_edit_object(C);
190 if(obedit && obedit->type==OB_MESH)
191 return NULL != ((Mesh *)obedit->data)->edit_mesh;
195 int ED_operator_editarmature(bContext *C)
197 Object *obedit= CTX_data_edit_object(C);
198 if(obedit && obedit->type==OB_ARMATURE)
199 return NULL != ((bArmature *)obedit->data)->edbo;
203 int ED_operator_posemode(bContext *C)
205 Object *obact= CTX_data_active_object(C);
206 Object *obedit= CTX_data_edit_object(C);
208 if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
209 return (obact->flag & OB_POSEMODE)!=0;
215 int ED_operator_uvedit(bContext *C)
217 Object *obedit= CTX_data_edit_object(C);
220 if(obedit && obedit->type==OB_MESH)
221 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
223 if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
224 BKE_mesh_end_editmesh(obedit->data, em);
228 BKE_mesh_end_editmesh(obedit->data, em);
232 int ED_operator_uvmap(bContext *C)
234 Object *obedit= CTX_data_edit_object(C);
237 if(obedit && obedit->type==OB_MESH)
238 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
240 if(em && (em->faces.first)) {
241 BKE_mesh_end_editmesh(obedit->data, em);
245 BKE_mesh_end_editmesh(obedit->data, em);
249 int ED_operator_editsurfcurve(bContext *C)
251 Object *obedit= CTX_data_edit_object(C);
252 if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
253 return NULL != ((Curve *)obedit->data)->editnurb;
258 int ED_operator_editcurve(bContext *C)
260 Object *obedit= CTX_data_edit_object(C);
261 if(obedit && obedit->type==OB_CURVE)
262 return NULL != ((Curve *)obedit->data)->editnurb;
266 int ED_operator_editsurf(bContext *C)
268 Object *obedit= CTX_data_edit_object(C);
269 if(obedit && obedit->type==OB_SURF)
270 return NULL != ((Curve *)obedit->data)->editnurb;
274 int ED_operator_editfont(bContext *C)
276 Object *obedit= CTX_data_edit_object(C);
277 if(obedit && obedit->type==OB_FONT)
278 return NULL != ((Curve *)obedit->data)->editfont;
282 /* *************************** action zone operator ************************** */
284 /* operator state vars used:
289 apply() set actionzone event
291 exit() free customdata
297 invoke() check if in zone
298 add customdata, put mouseco and area in it
301 modal() accept modal events while doing it
302 call apply() with gesture info, active window, nonactive window
303 call exit() and remove handler when LMB confirm
307 typedef struct sActionzoneData {
310 int x, y, gesture_dir, modifier;
313 /* used by other operators too */
314 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
317 sa= scr->areabase.first;
319 if(BLI_in_rcti(&sa->totrct, x, y)) break;
327 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
332 for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
333 if(az->type == AZONE_TRI) {
334 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y))
337 if(az->type == AZONE_QUAD) {
338 if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2)
346 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
348 AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
349 sActionzoneData *sad;
353 return OPERATOR_PASS_THROUGH;
355 /* ok we do the actionzone */
356 sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
357 sad->sa1= CTX_wm_area(C);
359 sad->x= event->x; sad->y= event->y;
361 /* add modal handler */
362 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
364 return OPERATOR_RUNNING_MODAL;
367 static void actionzone_exit(bContext *C, wmOperator *op)
370 MEM_freeN(op->customdata);
371 op->customdata= NULL;
374 /* send EVT_ACTIONZONE event */
375 static void actionzone_apply(bContext *C, wmOperator *op)
378 wmWindow *win= CTX_wm_window(C);
379 sActionzoneData *sad= op->customdata;
380 sad->modifier= RNA_int_get(op->ptr, "modifier");
382 event= *(win->eventstate); /* XXX huh huh? make api call */
383 event.type= EVT_ACTIONZONE;
384 event.customdata= op->customdata;
385 event.customdatafree= TRUE;
386 op->customdata= NULL;
388 wm_event_add(win, &event);
391 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
393 sActionzoneData *sad= op->customdata;
396 switch(event->type) {
398 /* calculate gesture direction */
399 deltax= (event->x - sad->x);
400 deltay= (event->y - sad->y);
402 if(deltay > ABS(deltax))
403 sad->gesture_dir= AZONE_N;
404 else if(deltax > ABS(deltay))
405 sad->gesture_dir= AZONE_E;
406 else if(deltay < -ABS(deltax))
407 sad->gesture_dir= AZONE_S;
409 sad->gesture_dir= AZONE_W;
411 /* gesture is large enough? */
412 if(ABS(deltax) > 12 || ABS(deltay) > 12) {
414 /* second area, for join */
415 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
416 /* apply sends event */
417 actionzone_apply(C, op);
418 actionzone_exit(C, op);
420 return OPERATOR_FINISHED;
425 actionzone_exit(C, op);
426 return OPERATOR_CANCELLED;
429 return OPERATOR_RUNNING_MODAL;
432 void SCREEN_OT_actionzone(wmOperatorType *ot)
435 ot->name= "Handle area action zones";
436 ot->idname= "SCREEN_OT_actionzone";
438 ot->invoke= actionzone_invoke;
439 ot->modal= actionzone_modal;
441 ot->poll= ED_operator_areaactive;
442 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
445 /* ************** swap area operator *********************************** */
447 /* operator state vars used:
449 sa2 area to swap with
453 init() set custom data for operator, based on actionzone event custom data
455 cancel() cancel the operator
457 exit() cleanup, send notifier
461 invoke() gets called on shift+lmb drag in actionzone
462 call init(), add handler
464 modal() accept modal events while doing it
468 typedef struct sAreaSwapData {
472 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
474 sAreaSwapData *sd= NULL;
475 sActionzoneData *sad= event->customdata;
477 if(sad==NULL || sad->sa1==NULL)
480 sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
489 static void area_swap_exit(bContext *C, wmOperator *op)
492 MEM_freeN(op->customdata);
493 op->customdata= NULL;
496 static int area_swap_cancel(bContext *C, wmOperator *op)
498 area_swap_exit(C, op);
499 return OPERATOR_CANCELLED;
502 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
505 if(!area_swap_init(C, op, event))
506 return OPERATOR_PASS_THROUGH;
508 /* add modal handler */
509 WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
510 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
512 return OPERATOR_RUNNING_MODAL;
516 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
518 sActionzoneData *sad= op->customdata;
520 switch(event->type) {
522 /* second area, for join */
523 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
525 case LEFTMOUSE: /* release LMB */
527 if(sad->sa1 == sad->sa2) {
529 return area_swap_cancel(C, op);
531 ED_area_swapspace(C, sad->sa1, sad->sa2);
533 area_swap_exit(C, op);
535 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
537 return OPERATOR_FINISHED;
542 return area_swap_cancel(C, op);
544 return OPERATOR_RUNNING_MODAL;
547 void SCREEN_OT_area_swap(wmOperatorType *ot)
549 ot->name= "Swap areas";
550 ot->idname= "SCREEN_OT_area_swap";
552 ot->invoke= area_swap_invoke;
553 ot->modal= area_swap_modal;
554 ot->poll= ED_operator_areaactive;
557 /* *********** Duplicate area as new window operator ****************** */
559 /* operator callback */
560 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
562 wmWindow *newwin, *win;
566 sActionzoneData *sad= event->customdata;
569 return OPERATOR_PASS_THROUGH;
571 win= CTX_wm_window(C);
572 sc= CTX_wm_screen(C);
575 /* poll() checks area context, but we don't accept full-area windows */
576 if(sc->full != SCREENNORMAL) {
577 actionzone_exit(C, op);
578 return OPERATOR_CANCELLED;
581 /* adds window to WM */
583 BLI_translate_rcti(&rect, win->posx, win->posy);
584 newwin= WM_window_open(C, &rect);
586 /* allocs new screen and adds to newly created window, using window size */
587 newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
588 newwin->screen= newsc;
590 /* copy area to new screen */
591 area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
593 /* screen, areas init */
594 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
596 actionzone_exit(C, op);
598 return OPERATOR_FINISHED;
601 void SCREEN_OT_area_dupli(wmOperatorType *ot)
603 ot->name= "Duplicate Area into New Window";
604 ot->idname= "SCREEN_OT_area_dupli";
606 ot->invoke= area_dupli_invoke;
607 ot->poll= ED_operator_areaactive;
611 /* ************** move area edge operator *********************************** */
613 /* operator state vars used:
614 x, y mouse coord near edge
615 delta movement of edge
619 init() set default property values, find edge based on mouse coords, test
620 if the edge can be moved, select edges, calculate min and max movement
622 apply() apply delta on selection
624 exit() cleanup, send notifier
626 cancel() cancel moving
630 exec() execute without any user interaction, based on properties
631 call init(), apply(), exit()
633 invoke() gets called on mouse click near edge
634 call init(), add handler
636 modal() accept modal events while doing it
637 call apply() with delta motion
638 call exit() and remove handler
642 typedef struct sAreaMoveData {
643 int bigger, smaller, origval;
647 /* helper call to move area-edge, sets limits */
648 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
652 /* we check all areas and test for free space with MINSIZE */
653 *bigger= *smaller= 100000;
655 for(sa= sc->areabase.first; sa; sa= sa->next) {
657 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
659 /* if top or down edge selected, test height */
660 if(sa->v1->flag && sa->v4->flag)
661 *bigger= MIN2(*bigger, y1);
662 else if(sa->v2->flag && sa->v3->flag)
663 *smaller= MIN2(*smaller, y1);
666 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
668 /* if left or right edge selected, test width */
669 if(sa->v1->flag && sa->v2->flag)
670 *bigger= MIN2(*bigger, x1);
671 else if(sa->v3->flag && sa->v4->flag)
672 *smaller= MIN2(*smaller, x1);
677 /* validate selection inside screen, set variables OK */
678 /* return 0: init failed */
679 static int area_move_init (bContext *C, wmOperator *op)
681 bScreen *sc= CTX_wm_screen(C);
686 /* required properties */
687 x= RNA_int_get(op->ptr, "x");
688 y= RNA_int_get(op->ptr, "y");
691 actedge= screen_find_active_scredge(sc, x, y);
692 if(actedge==NULL) return 0;
694 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
697 md->dir= scredge_is_horizontal(actedge)?'h':'v';
698 if(md->dir=='h') md->origval= actedge->v1->vec.y;
699 else md->origval= actedge->v1->vec.x;
701 select_connected_scredge(sc, actedge);
702 /* now all vertices with 'flag==1' are the ones that can be moved. */
704 area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
709 /* moves selected screen edge amount of delta, used by split & move */
710 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
712 wmWindow *win= CTX_wm_window(C);
713 bScreen *sc= CTX_wm_screen(C);
716 delta= CLAMPIS(delta, -smaller, bigger);
718 for (v1= sc->vertbase.first; v1; v1= v1->next) {
720 /* that way a nice AREAGRID */
721 if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
722 v1->vec.x= origval + delta;
723 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
725 if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
726 v1->vec.y= origval + delta;
728 v1->vec.y+= AREAGRID-1;
729 v1->vec.y-= (v1->vec.y % AREAGRID);
731 /* prevent too small top header */
732 if(v1->vec.y > win->sizey-AREAMINY)
733 v1->vec.y= win->sizey-AREAMINY;
738 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
741 static void area_move_apply(bContext *C, wmOperator *op)
743 sAreaMoveData *md= op->customdata;
746 delta= RNA_int_get(op->ptr, "delta");
747 area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
750 static void area_move_exit(bContext *C, wmOperator *op)
753 MEM_freeN(op->customdata);
754 op->customdata= NULL;
756 /* this makes sure aligned edges will result in aligned grabbing */
757 removedouble_scrverts(CTX_wm_screen(C));
758 removedouble_scredges(CTX_wm_screen(C));
761 static int area_move_exec(bContext *C, wmOperator *op)
763 if(!area_move_init(C, op))
764 return OPERATOR_CANCELLED;
766 area_move_apply(C, op);
767 area_move_exit(C, op);
769 return OPERATOR_FINISHED;
772 /* interaction callback */
773 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
775 RNA_int_set(op->ptr, "x", event->x);
776 RNA_int_set(op->ptr, "y", event->y);
778 if(!area_move_init(C, op))
779 return OPERATOR_PASS_THROUGH;
781 /* add temp handler */
782 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
784 return OPERATOR_RUNNING_MODAL;
787 static int area_move_cancel(bContext *C, wmOperator *op)
790 RNA_int_set(op->ptr, "delta", 0);
791 area_move_apply(C, op);
792 area_move_exit(C, op);
794 return OPERATOR_CANCELLED;
797 /* modal callback for while moving edges */
798 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
805 x= RNA_int_get(op->ptr, "x");
806 y= RNA_int_get(op->ptr, "y");
808 /* execute the events */
809 switch(event->type) {
811 delta= (md->dir == 'v')? event->x - x: event->y - y;
812 RNA_int_set(op->ptr, "delta", delta);
814 area_move_apply(C, op);
819 area_move_exit(C, op);
820 return OPERATOR_FINISHED;
825 return area_move_cancel(C, op);
828 return OPERATOR_RUNNING_MODAL;
831 void SCREEN_OT_area_move(wmOperatorType *ot)
834 ot->name= "Move area edges";
835 ot->idname= "SCREEN_OT_area_move";
837 ot->exec= area_move_exec;
838 ot->invoke= area_move_invoke;
839 ot->cancel= area_move_cancel;
840 ot->modal= area_move_modal;
842 ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
845 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
846 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
847 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
850 /* ************** split area operator *********************************** */
855 dir direction 'v' or 'h'
858 area pointer to (active) area
859 x, y last used mouse pos
864 init() set default property values, find area based on context
866 apply() split area based on state vars
868 exit() cleanup, send notifier
870 cancel() remove duplicated area
874 exec() execute without any user interaction, based on state vars
875 call init(), apply(), exit()
877 invoke() gets called on mouse click in action-widget
878 call init(), add modal handler
879 call apply() with initial motion
881 modal() accept modal events while doing it
882 call move-areas code with delta motion
883 call exit() or cancel() and remove handler
887 #define SPLIT_STARTED 1
888 #define SPLIT_PROGRESS 2
890 typedef struct sAreaSplitData
892 int x, y; /* last used mouse position */
894 int origval; /* for move areas */
895 int bigger, smaller; /* constraints for moving new edge */
896 int delta; /* delta move edge */
897 int origmin, origsize; /* to calculate fac, for property storage */
899 ScrEdge *nedge; /* new edge */
900 ScrArea *sarea; /* start area */
901 ScrArea *narea; /* new area */
904 /* generic init, no UI stuff here */
905 static int area_split_init(bContext *C, wmOperator *op)
907 ScrArea *sa= CTX_wm_area(C);
911 /* required context */
912 if(sa==NULL) return 0;
914 /* required properties */
915 dir= RNA_enum_get(op->ptr, "direction");
918 if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
919 if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
922 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
926 sd->origsize= dir=='v' ? sa->winx:sa->winy;
927 sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
932 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
933 /* used with split operator */
934 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
936 ScrVert *sav1= sa->v1;
937 ScrVert *sav2= sa->v2;
938 ScrVert *sav3= sa->v3;
939 ScrVert *sav4= sa->v4;
940 ScrVert *sbv1= sb->v1;
941 ScrVert *sbv2= sb->v2;
942 ScrVert *sbv3= sb->v3;
943 ScrVert *sbv4= sb->v4;
945 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
946 return screen_findedge(screen, sav1, sav2);
948 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
949 return screen_findedge(screen, sav2, sav3);
951 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
952 return screen_findedge(screen, sav3, sav4);
954 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
955 return screen_findedge(screen, sav1, sav4);
962 /* do the split, return success */
963 static int area_split_apply(bContext *C, wmOperator *op)
965 bScreen *sc= CTX_wm_screen(C);
966 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
970 fac= RNA_float_get(op->ptr, "factor");
971 dir= RNA_enum_get(op->ptr, "direction");
973 sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
978 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
980 /* select newly created edge, prepare for moving edge */
981 for(sv= sc->vertbase.first; sv; sv= sv->next)
984 sd->nedge->v1->flag= 1;
985 sd->nedge->v2->flag= 1;
987 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
988 else sd->origval= sd->nedge->v1->vec.x;
990 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
998 static void area_split_exit(bContext *C, wmOperator *op)
1000 if (op->customdata) {
1001 MEM_freeN(op->customdata);
1002 op->customdata = NULL;
1005 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1007 /* this makes sure aligned edges will result in aligned grabbing */
1008 removedouble_scrverts(CTX_wm_screen(C));
1009 removedouble_scredges(CTX_wm_screen(C));
1013 /* UI callback, adds new handler */
1014 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1018 if(event->type==EVT_ACTIONZONE) {
1019 sActionzoneData *sad= event->customdata;
1022 if(sad->modifier>0) {
1023 return OPERATOR_PASS_THROUGH;
1026 /* verify *sad itself */
1027 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1028 return OPERATOR_PASS_THROUGH;
1030 /* is this our *sad? if areas not equal it should be passed on */
1031 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1032 return OPERATOR_PASS_THROUGH;
1034 /* prepare operator state vars */
1035 if(sad->gesture_dir==AZONE_N || sad->gesture_dir==AZONE_S) {
1037 RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1041 RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1043 RNA_enum_set(op->ptr, "direction", dir);
1045 /* general init, also non-UI case, adds customdata, sets area and defaults */
1046 if(!area_split_init(C, op))
1047 return OPERATOR_PASS_THROUGH;
1049 sd= (sAreaSplitData *)op->customdata;
1055 if(area_split_apply(C, op)) {
1056 area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1058 /* add temp handler for edge move or cancel */
1059 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1061 return OPERATOR_RUNNING_MODAL;
1066 /* nonmodal for now */
1067 return op->type->exec(C, op);
1070 return OPERATOR_PASS_THROUGH;
1073 /* function to be called outside UI context, or for redo */
1074 static int area_split_exec(bContext *C, wmOperator *op)
1077 if(!area_split_init(C, op))
1078 return OPERATOR_CANCELLED;
1080 area_split_apply(C, op);
1081 area_split_exit(C, op);
1083 return OPERATOR_FINISHED;
1087 static int area_split_cancel(bContext *C, wmOperator *op)
1089 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1091 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1092 if (CTX_wm_area(C) == sd->narea) {
1093 CTX_wm_area_set(C, NULL);
1094 CTX_wm_region_set(C, NULL);
1098 area_split_exit(C, op);
1100 return OPERATOR_CANCELLED;
1103 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1105 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1109 /* execute the events */
1110 switch(event->type) {
1112 dir= RNA_enum_get(op->ptr, "direction");
1114 sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1115 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1117 fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1118 RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1120 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1124 if(event->val==0) { /* mouse up */
1125 area_split_exit(C, op);
1126 return OPERATOR_FINISHED;
1129 case RIGHTMOUSE: /* cancel operation */
1131 return area_split_cancel(C, op);
1134 return OPERATOR_RUNNING_MODAL;
1137 static EnumPropertyItem prop_direction_items[] = {
1138 {'h', "HORIZONTAL", "Horizontal", ""},
1139 {'v', "VERTICAL", "Vertical", ""},
1140 {0, NULL, NULL, NULL}};
1142 void SCREEN_OT_area_split(wmOperatorType *ot)
1144 ot->name = "Split area";
1145 ot->idname = "SCREEN_OT_area_split";
1147 ot->exec= area_split_exec;
1148 ot->invoke= area_split_invoke;
1149 ot->modal= area_split_modal;
1151 ot->poll= ED_operator_areaactive;
1152 ot->flag= OPTYPE_REGISTER;
1155 RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1156 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1159 /* ************** frame change operator ***************************** */
1162 /* function to be called outside UI context, or for redo */
1163 static int frame_offset_exec(bContext *C, wmOperator *op)
1167 delta = RNA_int_get(op->ptr, "delta");
1169 CTX_data_scene(C)->r.cfra += delta;
1171 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1173 return OPERATOR_FINISHED;
1176 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1178 ot->name = "Frame Offset";
1179 ot->idname = "SCREEN_OT_frame_offset";
1181 ot->exec= frame_offset_exec;
1183 ot->poll= ED_operator_screenactive;
1187 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1190 /* ************** switch screen operator ***************************** */
1193 /* function to be called outside UI context, or for redo */
1194 static int screen_set_exec(bContext *C, wmOperator *op)
1196 bScreen *screen= CTX_wm_screen(C);
1197 ScrArea *sa= CTX_wm_area(C);
1198 int tot= BLI_countlist(&CTX_data_main(C)->screen);
1199 int delta= RNA_int_get(op->ptr, "delta");
1201 /* this screen is 'fake', solve later XXX */
1203 return OPERATOR_CANCELLED;
1207 screen= screen->id.next;
1208 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1209 if(screen->winid==0 && screen->full==0)
1213 else if(delta== -1) {
1215 screen= screen->id.prev;
1216 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1217 if(screen->winid==0 && screen->full==0)
1226 ED_screen_set(C, screen);
1227 return OPERATOR_FINISHED;
1229 return OPERATOR_CANCELLED;
1232 void SCREEN_OT_screen_set(wmOperatorType *ot)
1234 ot->name = "Set Screen";
1235 ot->idname = "SCREEN_OT_screen_set";
1237 ot->exec= screen_set_exec;
1238 ot->poll= ED_operator_screenactive;
1241 RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1242 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1245 /* ************** screen full-area operator ***************************** */
1248 /* function to be called outside UI context, or for redo */
1249 static int screen_full_area_exec(bContext *C, wmOperator *op)
1251 ed_screen_fullarea(C, CTX_wm_area(C));
1252 return OPERATOR_FINISHED;
1255 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1257 ot->name = "Toggle Make Area Fullscreen";
1258 ot->idname = "SCREEN_OT_screen_full_area";
1260 ot->exec= screen_full_area_exec;
1261 ot->poll= ED_operator_areaactive;
1268 /* ************** join area operator ********************************************** */
1270 /* operator state vars used:
1271 x1, y1 mouse coord in first area, which will disappear
1272 x2, y2 mouse coord in 2nd area, which will become joined
1276 init() find edge based on state vars
1277 test if the edge divides two areas,
1278 store active and nonactive area,
1280 apply() do the actual join
1282 exit() cleanup, send notifier
1286 exec() calls init, apply, exit
1288 invoke() sets mouse coords in x,y
1292 modal() accept modal events while doing it
1293 call apply() with active window and nonactive window
1294 call exit() and remove handler when LMB confirm
1298 typedef struct sAreaJoinData
1300 ScrArea *sa1; /* first area to be considered */
1301 ScrArea *sa2; /* second area to be considered */
1302 ScrArea *scr; /* designed for removal */
1307 /* validate selection inside screen, set variables OK */
1308 /* return 0: init failed */
1309 /* XXX todo: find edge based on (x,y) and set other area? */
1310 static int area_join_init(bContext *C, wmOperator *op)
1313 sAreaJoinData* jd= NULL;
1317 /* required properties, make negative to get return 0 if not set by caller */
1318 x1= RNA_int_get(op->ptr, "x1");
1319 y1= RNA_int_get(op->ptr, "y1");
1320 x2= RNA_int_get(op->ptr, "x2");
1321 y2= RNA_int_get(op->ptr, "y2");
1323 sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1324 sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1325 if(sa1==NULL || sa2==NULL || sa1==sa2)
1328 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1331 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1333 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1340 /* apply the join of the areas (space types) */
1341 static int area_join_apply(bContext *C, wmOperator *op)
1343 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1346 if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1349 if (CTX_wm_area(C) == jd->sa2) {
1350 CTX_wm_area_set(C, NULL);
1351 CTX_wm_region_set(C, NULL);
1357 /* finish operation */
1358 static void area_join_exit(bContext *C, wmOperator *op)
1360 if (op->customdata) {
1361 MEM_freeN(op->customdata);
1362 op->customdata = NULL;
1365 /* this makes sure aligned edges will result in aligned grabbing */
1366 removedouble_scredges(CTX_wm_screen(C));
1367 removenotused_scredges(CTX_wm_screen(C));
1368 removenotused_scrverts(CTX_wm_screen(C));
1371 static int area_join_exec(bContext *C, wmOperator *op)
1373 if(!area_join_init(C, op))
1374 return OPERATOR_CANCELLED;
1376 area_join_apply(C, op);
1377 area_join_exit(C, op);
1379 return OPERATOR_FINISHED;
1382 /* interaction callback */
1383 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1386 if(event->type==EVT_ACTIONZONE) {
1387 sActionzoneData *sad= event->customdata;
1389 if(sad->modifier>0) {
1390 return OPERATOR_PASS_THROUGH;
1393 /* verify *sad itself */
1394 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1395 return OPERATOR_PASS_THROUGH;
1397 /* is this our *sad? if areas equal it should be passed on */
1398 if(sad->sa1==sad->sa2)
1399 return OPERATOR_PASS_THROUGH;
1401 /* prepare operator state vars */
1402 RNA_int_set(op->ptr, "x1", sad->x);
1403 RNA_int_set(op->ptr, "y1", sad->y);
1404 RNA_int_set(op->ptr, "x2", event->x);
1405 RNA_int_set(op->ptr, "y2", event->y);
1407 if(!area_join_init(C, op))
1408 return OPERATOR_PASS_THROUGH;
1410 /* add temp handler */
1411 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1413 return OPERATOR_RUNNING_MODAL;
1416 return OPERATOR_PASS_THROUGH;
1419 static int area_join_cancel(bContext *C, wmOperator *op)
1421 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1424 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1425 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1428 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1429 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1432 WM_event_add_notifier(C, NC_WINDOW, NULL);
1434 area_join_exit(C, op);
1436 return OPERATOR_CANCELLED;
1439 /* modal callback while selecting area (space) that will be removed */
1440 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1442 bScreen *sc= CTX_wm_screen(C);
1443 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1445 /* execute the events */
1446 switch(event->type) {
1450 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1454 if (jd->sa1 != sa) {
1455 dir = area_getorientation(sc, jd->sa1, sa);
1457 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1459 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1462 /* we are not bordering on the previously selected area
1463 we check if area has common border with the one marked for removal
1464 in this case we can swap areas.
1466 dir = area_getorientation(sc, sa, jd->sa2);
1468 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1469 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1472 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1473 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1476 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1480 WM_event_add_notifier(C, NC_WINDOW, NULL);
1483 /* we are back in the area previously selected for keeping
1484 * we swap the areas if possible to allow user to choose */
1485 if (jd->sa2 != NULL) {
1486 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1487 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1490 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1491 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1492 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1494 printf("oops, didn't expect that!\n");
1498 dir = area_getorientation(sc, jd->sa1, sa);
1500 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1502 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1505 WM_event_add_notifier(C, NC_WINDOW, NULL);
1512 area_join_apply(C, op);
1513 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1514 area_join_exit(C, op);
1515 return OPERATOR_FINISHED;
1520 return area_join_cancel(C, op);
1523 return OPERATOR_RUNNING_MODAL;
1526 /* Operator for joining two areas (space types) */
1527 void SCREEN_OT_area_join(wmOperatorType *ot)
1530 ot->name= "Join area";
1531 ot->idname= "SCREEN_OT_area_join";
1534 ot->exec= area_join_exec;
1535 ot->invoke= area_join_invoke;
1536 ot->modal= area_join_modal;
1538 ot->poll= ED_operator_areaactive;
1541 RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1542 RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1543 RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1544 RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1547 /* ************** repeat last operator ***************************** */
1549 static int repeat_last_exec(bContext *C, wmOperator *op)
1551 wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1554 WM_operator_repeat(C, lastop);
1556 return OPERATOR_CANCELLED;
1559 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1562 ot->name= "Repeat Last";
1563 ot->idname= "SCREEN_OT_repeat_last";
1566 ot->exec= repeat_last_exec;
1568 ot->poll= ED_operator_screenactive;
1572 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1574 wmWindowManager *wm= CTX_wm_manager(C);
1580 items= BLI_countlist(&wm->operators);
1582 return OPERATOR_CANCELLED;
1584 pup= uiPupMenuBegin(op->type->name, 0);
1585 layout= uiPupMenuLayout(pup);
1587 for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1588 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1590 uiPupMenuEnd(C, pup);
1592 return OPERATOR_CANCELLED;
1595 static int repeat_history_exec(bContext *C, wmOperator *op)
1597 wmWindowManager *wm= CTX_wm_manager(C);
1599 op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1601 /* let's put it as last operator in list */
1602 BLI_remlink(&wm->operators, op);
1603 BLI_addtail(&wm->operators, op);
1605 WM_operator_repeat(C, op);
1608 return OPERATOR_FINISHED;
1611 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1614 ot->name= "Repeat History";
1615 ot->idname= "SCREEN_OT_repeat_history";
1618 ot->invoke= repeat_history_invoke;
1619 ot->exec= repeat_history_exec;
1621 ot->poll= ED_operator_screenactive;
1623 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1626 /* ********************** redo operator ***************************** */
1628 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1630 wmWindowManager *wm= CTX_wm_manager(C);
1633 /* only for operators that are registered and did an undo push */
1634 for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1635 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1639 WM_operator_redo_popup(C, lastop);
1641 return OPERATOR_CANCELLED;
1644 void SCREEN_OT_redo_last(wmOperatorType *ot)
1647 ot->name= "Redo Last";
1648 ot->idname= "SCREEN_OT_redo_last";
1651 ot->invoke= redo_last_invoke;
1653 ot->poll= ED_operator_screenactive;
1656 /* ************** region split operator ***************************** */
1658 /* insert a region in the area region list */
1659 static int region_split_exec(bContext *C, wmOperator *op)
1661 ARegion *ar= CTX_wm_region(C);
1663 if(ar->regiontype==RGN_TYPE_HEADER)
1664 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1665 else if(ar->alignment==RGN_ALIGN_QSPLIT)
1666 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1668 ScrArea *sa= CTX_wm_area(C);
1669 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1670 int dir= RNA_enum_get(op->ptr, "type");
1672 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1674 newar->alignment= ar->alignment;
1677 ar->alignment= RGN_ALIGN_HSPLIT;
1679 ar->alignment= RGN_ALIGN_VSPLIT;
1681 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1684 return OPERATOR_FINISHED;
1687 void SCREEN_OT_region_split(wmOperatorType *ot)
1690 ot->name= "Split Region";
1691 ot->idname= "SCREEN_OT_region_split";
1694 ot->invoke= WM_menu_invoke;
1695 ot->exec= region_split_exec;
1696 ot->poll= ED_operator_areaactive;
1698 RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1701 /* ************** region four-split operator ***************************** */
1703 /* insert a region in the area region list */
1704 static int region_foursplit_exec(bContext *C, wmOperator *op)
1706 ARegion *ar= CTX_wm_region(C);
1709 if(ar->regiontype!=RGN_TYPE_WINDOW)
1710 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1711 else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1712 ScrArea *sa= CTX_wm_area(C);
1715 /* keep current region */
1718 if(sa->spacetype==SPACE_VIEW3D) {
1719 RegionView3D *rv3d= ar->regiondata;
1721 rv3d->rflag &= ~RV3D_CLIPPING;
1724 for(ar= sa->regionbase.first; ar; ar= arn) {
1726 if(ar->alignment==RGN_ALIGN_QSPLIT) {
1727 ED_region_exit(C, ar);
1728 BKE_area_region_free(sa->type, ar);
1729 BLI_remlink(&sa->regionbase, ar);
1733 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1736 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1738 ScrArea *sa= CTX_wm_area(C);
1742 ar->alignment= RGN_ALIGN_QSPLIT;
1744 for(count=0; count<3; count++) {
1745 newar= BKE_area_region_copy(sa->type, ar);
1746 BLI_addtail(&sa->regionbase, newar);
1749 /* lock views and set them */
1750 if(sa->spacetype==SPACE_VIEW3D) {
1753 rv3d= ar->regiondata;
1754 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1757 rv3d= ar->regiondata;
1758 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1761 rv3d= ar->regiondata;
1762 rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1765 rv3d= ar->regiondata;
1766 rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1769 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1773 return OPERATOR_FINISHED;
1776 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1779 ot->name= "Split Region in 4 Parts";
1780 ot->idname= "SCREEN_OT_region_foursplit";
1783 ot->invoke= WM_operator_confirm;
1784 ot->exec= region_foursplit_exec;
1785 ot->poll= ED_operator_areaactive;
1786 ot->flag= OPTYPE_REGISTER;
1791 /* ************** region flip operator ***************************** */
1793 /* flip a region alignment */
1794 static int region_flip_exec(bContext *C, wmOperator *op)
1796 ARegion *ar= CTX_wm_region(C);
1798 if(ar->alignment==RGN_ALIGN_TOP)
1799 ar->alignment= RGN_ALIGN_BOTTOM;
1800 else if(ar->alignment==RGN_ALIGN_BOTTOM)
1801 ar->alignment= RGN_ALIGN_TOP;
1802 else if(ar->alignment==RGN_ALIGN_LEFT)
1803 ar->alignment= RGN_ALIGN_RIGHT;
1804 else if(ar->alignment==RGN_ALIGN_RIGHT)
1805 ar->alignment= RGN_ALIGN_LEFT;
1807 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1808 printf("executed region flip\n");
1810 return OPERATOR_FINISHED;
1813 static void testfunc(bContext *C, void *argv, int arg)
1815 printf("arg %d\n", arg);
1818 static void newlevel1(bContext *C, uiLayout *layout, void *arg)
1820 uiLayoutFunc(layout, testfunc, NULL);
1822 uiItemV(layout, "First", ICON_PROP_ON, 1);
1823 uiItemV(layout, "Second", ICON_PROP_CON, 2);
1824 uiItemV(layout, "Third", ICON_SMOOTHCURVE, 3);
1825 uiItemV(layout, "Fourth", ICON_SHARPCURVE, 4);
1828 static int testing123(bContext *C, wmOperator *op, wmEvent *event)
1830 uiPopupMenu *pup= uiPupMenuBegin("Hello world", 0);
1831 uiLayout *layout= uiPupMenuLayout(pup);
1833 uiLayoutContext(layout, WM_OP_EXEC_DEFAULT);
1834 uiItemO(layout, NULL, ICON_PROP_ON, "SCREEN_OT_region_flip");
1835 uiItemO(layout, NULL, ICON_PROP_CON, "SCREEN_OT_screen_full_area");
1836 uiItemO(layout, NULL, ICON_SMOOTHCURVE, "SCREEN_OT_region_foursplit");
1837 uiItemMenuF(layout, "Submenu", 0, newlevel1);
1839 uiPupMenuEnd(C, pup);
1841 /* this operator is only for a menu, not used further */
1842 return OPERATOR_CANCELLED;
1845 void SCREEN_OT_region_flip(wmOperatorType *ot)
1848 ot->name= "Flip Region";
1849 ot->idname= "SCREEN_OT_region_flip";
1852 ot->invoke= testing123; // XXX WM_operator_confirm;
1853 ot->exec= region_flip_exec;
1855 ot->poll= ED_operator_areaactive;
1856 ot->flag= OPTYPE_REGISTER;
1858 RNA_def_int(ot->srna, "test", 0, INT_MIN, INT_MAX, "test", "", INT_MIN, INT_MAX);
1862 /* ****************** anim player, typically with timer ***************** */
1864 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
1866 bScreen *screen= CTX_wm_screen(C);
1868 if(screen->animtimer==event->customdata) {
1869 Scene *scene= CTX_data_scene(C);
1871 if(scene->audio.flag & AUDIO_SYNC) {
1872 wmTimer *wt= screen->animtimer;
1873 int step = floor(wt->duration * FPS);
1874 scene->r.cfra += step;
1875 wt->duration -= ((float)step)/FPS;
1880 if (scene->r.psfra) {
1881 if(scene->r.cfra > scene->r.pefra)
1882 scene->r.cfra= scene->r.psfra;
1885 if(scene->r.cfra > scene->r.efra)
1886 scene->r.cfra= scene->r.sfra;
1889 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1891 return OPERATOR_FINISHED;
1893 return OPERATOR_PASS_THROUGH;
1896 void SCREEN_OT_animation_play(wmOperatorType *ot)
1899 ot->name= "Animation player";
1900 ot->idname= "SCREEN_OT_animation_play";
1903 ot->invoke= screen_animation_play;
1905 ot->poll= ED_operator_screenactive;
1909 /* ************** border select operator (template) ***************************** */
1911 /* operator state vars used: (added by default WM callbacks)
1915 customdata: the wmGesture pointer
1919 exec() has to be filled in by user
1921 invoke() default WM function
1924 modal() default WM function
1925 accept modal events while doing it, calls exec(), handles ESC and border drawing
1927 poll() has to be filled in by user for context
1930 static int border_select_do(bContext *C, wmOperator *op)
1932 int event_type= RNA_int_get(op->ptr, "event_type");
1934 if(event_type==LEFTMOUSE)
1935 printf("border select do select\n");
1936 else if(event_type==RIGHTMOUSE)
1937 printf("border select deselect\n");
1939 printf("border select do something\n");
1944 void SCREEN_OT_border_select(wmOperatorType *ot)
1947 ot->name= "Border select";
1948 ot->idname= "SCREEN_OT_border_select";
1951 ot->exec= border_select_do;
1952 ot->invoke= WM_border_select_invoke;
1953 ot->modal= WM_border_select_modal;
1955 ot->poll= ED_operator_areaactive;
1958 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1959 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1960 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1961 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1962 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1967 /* ****************************** render invoking ***************** */
1969 /* set callbacks, exported to sequence render too.
1970 Only call in foreground (UI) renders. */
1972 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
1973 /* window as the last possible alternative. */
1974 static ScrArea *biggest_non_image_area(bContext *C)
1976 bScreen *sc= CTX_wm_screen(C);
1977 ScrArea *sa, *big= NULL;
1978 int size, maxsize= 0, bwmaxsize= 0;
1981 for(sa= sc->areabase.first; sa; sa= sa->next) {
1982 if(sa->winx > 10 && sa->winy > 10) {
1983 size= sa->winx*sa->winy;
1984 if(sa->spacetype == SPACE_BUTS) {
1985 if(foundwin == 0 && size > bwmaxsize) {
1990 else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2001 static ScrArea *biggest_area(bContext *C)
2003 bScreen *sc= CTX_wm_screen(C);
2004 ScrArea *sa, *big= NULL;
2005 int size, maxsize= 0;
2007 for(sa= sc->areabase.first; sa; sa= sa->next) {
2008 size= sa->winx*sa->winy;
2009 if(size > maxsize) {
2018 static ScrArea *find_area_showing_r_result(bContext *C)
2020 bScreen *sc= CTX_wm_screen(C);
2024 /* find an imagewindow showing render result */
2025 for(sa=sc->areabase.first; sa; sa= sa->next) {
2026 if(sa->spacetype==SPACE_IMAGE) {
2027 sima= sa->spacedata.first;
2028 if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2035 static void screen_set_image_output(bContext *C)
2040 sa= find_area_showing_r_result(C);
2043 /* find largest open non-image area */
2044 sa= biggest_non_image_area(C);
2046 ED_area_newspace(C, sa, SPACE_IMAGE);
2047 sima= sa->spacedata.first;
2049 /* makes ESC go back to prev space */
2050 sima->flag |= SI_PREVSPACE;
2053 /* use any area of decent size */
2054 sa= biggest_area(C);
2055 if(sa->spacetype!=SPACE_IMAGE) {
2056 // XXX newspace(sa, SPACE_IMAGE);
2057 sima= sa->spacedata.first;
2059 /* makes ESC go back to prev space */
2060 sima->flag |= SI_PREVSPACE;
2065 sima= sa->spacedata.first;
2067 /* get the correct image, and scale it */
2068 sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2070 if(G.displaymode==2) { // XXX
2072 sima->flag |= SI_FULLWINDOW;
2074 ed_screen_fullarea(C, sa);
2080 /* executes blocking render */
2081 static int screen_render_exec(bContext *C, wmOperator *op)
2083 Scene *scene= CTX_data_scene(C);
2084 Render *re= RE_GetRender(scene->id.name);
2087 re= RE_NewRender(scene->id.name);
2089 RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2091 if(RNA_boolean_get(op->ptr, "anim"))
2092 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2094 RE_BlenderFrame(re, scene, scene->r.cfra);
2096 // no redraw needed, we leave state as we entered it
2097 ED_update_for_newframe(C, 1);
2099 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2101 return OPERATOR_FINISHED;
2104 typedef struct RenderJob {
2115 static void render_freejob(void *rjv)
2122 /* called inside thread! */
2123 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2127 float x1, y1, *rectf= NULL;
2128 int ymin, ymax, xmin, xmax;
2132 ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2133 if(ibuf==NULL) return;
2135 /* if renrect argument, we only refresh scanlines */
2137 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2138 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2141 /* xmin here is first subrect x coord, xmax defines subrect width */
2142 xmin = renrect->xmin + rr->crop;
2143 xmax = renrect->xmax - xmin - rr->crop;
2146 ymin= renrect->ymin + rr->crop;
2147 ymax= renrect->ymax - ymin - rr->crop;
2150 renrect->ymin= renrect->ymax;
2154 xmin = ymin = rr->crop;
2155 xmax = rr->rectx - 2*rr->crop;
2156 ymax = rr->recty - 2*rr->crop;
2159 /* xmin ymin is in tile coords. transform to ibuf */
2160 rxmin= rr->tilerect.xmin + xmin;
2161 if(rxmin >= ibuf->x) return;
2162 rymin= rr->tilerect.ymin + ymin;
2163 if(rymin >= ibuf->y) return;
2165 if(rxmin + xmax > ibuf->x)
2166 xmax= ibuf->x - rxmin;
2167 if(rymin + ymax > ibuf->y)
2168 ymax= ibuf->y - rymin;
2170 if(xmax < 1 || ymax < 1) return;
2172 /* find current float rect for display, first case is after composit... still weak */
2179 if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2180 rectf= rr->renlay->rectf;
2183 if(rectf==NULL) return;
2185 rectf+= 4*(rr->rectx*ymin + xmin);
2186 rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2188 for(y1= 0; y1<ymax; y1++) {
2192 /* XXX temp. because crop offset */
2193 if( rectc >= (char *)(ibuf->rect)) {
2194 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2195 rc[0]= FTOCHAR(rf[0]);
2196 rc[1]= FTOCHAR(rf[1]);
2197 rc[2]= FTOCHAR(rf[2]);
2198 rc[3]= FTOCHAR(rf[3]);
2201 rectf += 4*rr->rectx;
2205 /* make jobs timer to send notifier */
2206 *(rj->do_update)= 1;
2209 static void render_startjob(void *rjv, short *stop, short *do_update)
2214 rj->do_update= do_update;
2217 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2219 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2222 /* called by render, check job 'stop' value or the global */
2223 static int render_breakjob(void *rjv)
2229 if(rj->stop && *(rj->stop))
2235 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2237 /* no running blender, remove handler and pass through */
2238 if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2239 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2241 /* running render */
2242 switch (event->type) {
2244 return OPERATOR_RUNNING_MODAL;
2247 return OPERATOR_PASS_THROUGH;
2250 /* using context, starts job */
2251 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2253 /* new render clears all callbacks */
2254 Scene *scene= CTX_data_scene(C);
2260 /* only one job at a time */
2261 if(WM_jobs_test(CTX_wm_manager(C), scene))
2262 return OPERATOR_CANCELLED;
2264 /* handle UI stuff */
2267 /* flush multires changes (for sculpt) */
2268 multires_force_update(CTX_data_active_object(C));
2270 // get editmode results
2272 // get view3d layer, local layer, make this nice api call to render
2275 /* ensure at least 1 area shows result */
2276 screen_set_image_output(C);
2278 /* job custom data */
2279 rj= MEM_callocN(sizeof(RenderJob), "render job");
2281 rj->win= CTX_wm_window(C);
2282 rj->anim= RNA_boolean_get(op->ptr, "anim");
2283 rj->iuser.scene= scene;
2287 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2288 WM_jobs_customdata(steve, rj, render_freejob);
2289 WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2290 WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2292 /* get a render result image, and make sure it is empty */
2293 ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2294 BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2297 /* setup new render */
2298 re= RE_NewRender(scene->id.name);
2299 RE_test_break_cb(re, rj, render_breakjob);
2300 RE_display_draw_cb(re, rj, image_rect_update);
2304 // BKE_report in render!
2305 // RE_error_cb(re, error_cb);
2307 WM_jobs_start(steve);
2312 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2314 /* add modal handler for ESC */
2315 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2317 return OPERATOR_RUNNING_MODAL;
2321 /* contextual render, using current scene, view3d? */
2322 void SCREEN_OT_render(wmOperatorType *ot)
2326 ot->idname= "SCREEN_OT_render";
2329 ot->invoke= screen_render_invoke;
2330 ot->modal= screen_render_modal;
2331 ot->exec= screen_render_exec;
2333 ot->poll= ED_operator_screenactive;
2335 RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2336 RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2339 /* *********************** cancel render viewer *************** */
2341 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2343 ScrArea *sa= CTX_wm_area(C);
2344 SpaceImage *sima= sa->spacedata.first;
2346 if(sima->flag & SI_PREVSPACE) {
2347 sima->flag &= ~SI_PREVSPACE;
2349 if(sima->flag & SI_FULLWINDOW) {
2350 sima->flag &= ~SI_FULLWINDOW;
2351 ED_screen_full_prevspace(C);
2354 ED_area_prevspace(C);
2356 else if(sima->flag & SI_FULLWINDOW) {
2357 sima->flag &= ~SI_FULLWINDOW;
2358 ed_screen_fullarea(C, sa);
2361 return OPERATOR_FINISHED;
2364 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2367 ot->name= "Cancel Render View";
2368 ot->idname= "SCREEN_OT_render_view_cancel";
2371 ot->exec= render_view_cancel_exec;
2372 ot->poll= ED_operator_image_active;
2376 /* **************** Assigning operatortypes to global list, adding handlers **************** */
2378 /* called in spacetypes.c */
2379 void ED_operatortypes_screen(void)
2381 /* generic UI stuff */
2382 WM_operatortype_append(SCREEN_OT_actionzone);
2383 WM_operatortype_append(SCREEN_OT_repeat_last);
2384 WM_operatortype_append(SCREEN_OT_repeat_history);
2385 WM_operatortype_append(SCREEN_OT_redo_last);
2388 WM_operatortype_append(SCREEN_OT_area_move);
2389 WM_operatortype_append(SCREEN_OT_area_split);
2390 WM_operatortype_append(SCREEN_OT_area_join);
2391 WM_operatortype_append(SCREEN_OT_area_dupli);
2392 WM_operatortype_append(SCREEN_OT_area_swap);
2393 WM_operatortype_append(SCREEN_OT_region_split);
2394 WM_operatortype_append(SCREEN_OT_region_foursplit);
2395 WM_operatortype_append(SCREEN_OT_region_flip);
2396 WM_operatortype_append(SCREEN_OT_screen_set);
2397 WM_operatortype_append(SCREEN_OT_screen_full_area);
2398 WM_operatortype_append(SCREEN_OT_screenshot);
2399 WM_operatortype_append(SCREEN_OT_screencast);
2402 WM_operatortype_append(SCREEN_OT_frame_offset);
2403 WM_operatortype_append(SCREEN_OT_animation_play);
2406 WM_operatortype_append(SCREEN_OT_render);
2407 WM_operatortype_append(SCREEN_OT_render_view_cancel);
2409 /* tools shared by more space types */
2410 WM_operatortype_append(ED_OT_undo);
2411 WM_operatortype_append(ED_OT_redo);
2415 /* called in spacetypes.c */
2416 void ED_keymap_screen(wmWindowManager *wm)
2418 ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2420 /* standard timers */
2421 WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
2423 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2424 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2425 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2428 WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2429 WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0);
2430 WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);
2431 WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE, 0, KM_SHIFT, 0);
2432 WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE, 0, KM_ALT, 0);
2433 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2434 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2435 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2436 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2437 WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2438 WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2439 WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2442 WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2443 WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2445 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2446 WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2447 WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2448 WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2450 RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
2451 WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
2454 WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2455 WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2458 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2459 WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2460 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2461 WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2464 WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2465 WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2468 keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2469 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2470 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2471 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2472 RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);