Blender V4.3
screen_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10#include <cstring>
11#include <fmt/format.h>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_build_config.h"
16#include "BLI_math_rotation.h"
17#include "BLI_math_vector.h"
18#include "BLI_utildefines.h"
19
20#include "BLT_translation.hh"
21
22#include "DNA_anim_types.h"
23#include "DNA_armature_types.h"
24#include "DNA_curve_types.h"
25#include "DNA_lattice_types.h"
26#include "DNA_meta_types.h"
27#include "DNA_node_types.h"
28#include "DNA_object_types.h"
29#include "DNA_scene_types.h"
30#include "DNA_userdef_types.h"
31#include "DNA_workspace_types.h"
32
33#include "BKE_callbacks.hh"
34#include "BKE_context.hh"
35#include "BKE_editmesh.hh"
36#include "BKE_fcurve.hh"
37#include "BKE_global.hh"
38#include "BKE_icons.h"
39#include "BKE_lib_id.hh"
40#include "BKE_main.hh"
41#include "BKE_mask.h"
42#include "BKE_object.hh"
43#include "BKE_report.hh"
44#include "BKE_scene.hh"
45#include "BKE_screen.hh"
46#include "BKE_sound.h"
47#include "BKE_workspace.hh"
48
49#include "WM_api.hh"
50#include "WM_types.hh"
51
52#include "DEG_depsgraph.hh"
54
55#include "ED_anim_api.hh"
56#include "ED_armature.hh"
57#include "ED_fileselect.hh"
58#include "ED_image.hh"
60#include "ED_mesh.hh"
61#include "ED_object.hh"
62#include "ED_scene.hh"
63#include "ED_screen.hh"
64#include "ED_screen_types.hh"
65#include "ED_sequencer.hh"
66#include "ED_view3d.hh"
67
68#include "RNA_access.hh"
69#include "RNA_define.hh"
70#include "RNA_enum_types.hh"
71#include "RNA_prototypes.hh"
72
73#include "UI_interface.hh"
74#include "UI_resources.hh"
75#include "UI_view2d.hh"
76
77#include "GPU_capabilities.hh"
78
79#include "wm_window.hh"
80
81#include "screen_intern.hh" /* own module include */
82
83using blender::Vector;
84
85#define KM_MODAL_CANCEL 1
86#define KM_MODAL_APPLY 2
87#define KM_MODAL_SNAP_ON 3
88#define KM_MODAL_SNAP_OFF 4
89
90/* -------------------------------------------------------------------- */
93
95{
96 if (CTX_wm_window(C) == nullptr) {
97 return false;
98 }
99 if (CTX_wm_screen(C) == nullptr) {
100 return false;
101 }
102 if (CTX_wm_region(C) == nullptr) {
103 return false;
104 }
105 return true;
106}
107
109{
110 if (CTX_wm_window(C) == nullptr) {
111 return false;
112 }
113 if (CTX_wm_screen(C) == nullptr) {
114 return false;
115 }
116 if (CTX_wm_area(C) == nullptr) {
117 return false;
118 }
119 return true;
120}
121
123{
124 if (CTX_wm_window(C) == nullptr) {
125 return false;
126 }
127 if (CTX_wm_screen(C) == nullptr) {
128 return false;
129 }
130 return true;
131}
132
134{
135 if (G.background) {
136 return false;
137 }
139}
140
141/* XXX added this to prevent anim state to change during renders */
143{
144 if (G.is_rendering) {
145 return false;
146 }
147 if (CTX_wm_window(C) == nullptr) {
148 return false;
149 }
150 if (CTX_wm_screen(C) == nullptr) {
151 return false;
152 }
153 return true;
154}
155
157{
158 if (CTX_wm_window(C) == nullptr) {
159 return false;
160 }
161 bScreen *screen = CTX_wm_screen(C);
162 if (screen == nullptr) {
163 return false;
164 }
165 if (screen->active_region != nullptr) {
166 return false;
167 }
168 return true;
169}
170
172{
173 Scene *scene = CTX_data_scene(C);
174 if (scene) {
175 return true;
176 }
177 return false;
178}
179
181{
182 Scene *scene = CTX_data_scene(C);
183 if (scene == nullptr || !BKE_id_is_editable(CTX_data_main(C), &scene->id)) {
184 return false;
185 }
186 return true;
187}
188
190{
191 Scene *scene = CTX_data_scene(C);
193
194 if (scene == nullptr || !ID_IS_EDITABLE(scene)) {
195 return false;
196 }
197 if (CTX_data_edit_object(C)) {
198 return false;
199 }
200
201 /* add a check for ob->mode too? */
202 if (obact && (obact->mode != OB_MODE_OBJECT)) {
203 return false;
204 }
205
206 return true;
207}
208
210{
212 CTX_wm_operator_poll_msg_set(C, "Only supported in object mode");
213 return false;
214 }
215
216 return true;
217}
218
220{
222 return false;
223 }
225 return false;
226 }
227 return true;
228}
229
230static bool ed_spacetype_test(bContext *C, int type)
231{
234 return sl && (sl->spacetype == type);
235 }
236 return false;
237}
238
243
245{
246 if (CTX_wm_region_view3d(C)) {
247 return true;
248 }
249
250 CTX_wm_operator_poll_msg_set(C, "expected a view3d region");
251 return false;
252}
253
255{
256 ARegion *region = CTX_wm_region(C);
257 if (region == nullptr) {
258 return false;
259 }
260 wmGizmoMap *gzmap = region->gizmo_map;
261 if (gzmap == nullptr) {
262 return false;
263 }
264 return true;
265}
266
268{
272 return true;
273 }
274 }
275
276 CTX_wm_operator_poll_msg_set(C, "expected a timeline/animation area to be active");
277 return false;
278}
279
284
286{
288 CTX_wm_operator_poll_msg_set(C, "Expected an active Outliner");
289 return false;
290 }
291 const ARegion *region = CTX_wm_region(C);
292 if (!(region && region->regiontype == RGN_TYPE_WINDOW)) {
293 CTX_wm_operator_poll_msg_set(C, "Expected an Outliner region");
294 return false;
295 }
296 return true;
297}
298
300{
303 Object *obedit = CTX_data_edit_object(C);
304 if (ob && ob == obedit) {
305 return false;
306 }
307 return true;
308 }
309 return false;
310}
311
316
324
332
337
342
347
349{
350 SpaceNode *snode = CTX_wm_space_node(C);
351
352 if (snode && snode->edittree) {
353 return true;
354 }
355
356 return false;
357}
358
360{
361 SpaceNode *snode = CTX_wm_space_node(C);
362
363 if (snode && snode->edittree && BKE_id_is_editable(CTX_data_main(C), &snode->edittree->id)) {
364 return true;
365 }
366
367 return false;
368}
369
374
379
384
389
394
399
404
405static bool ed_object_hidden(const Object *ob)
406{
407 /* if hidden but in edit mode, we still display, can happen with animation */
408 return ((ob->visibility_flag & OB_HIDE_VIEWPORT) && !(ob->mode & OB_MODE_EDIT));
409}
410
412{
414 return ((ob != nullptr) && !ed_object_hidden(ob));
415}
416
418{
419 if (ob == nullptr) {
420 CTX_wm_operator_poll_msg_set(C, "Context missing active object");
421 return false;
422 }
423
424 if (!BKE_id_is_editable(CTX_data_main(C), (ID *)ob)) {
425 CTX_wm_operator_poll_msg_set(C, "Cannot edit library linked or non-editable override object");
426 return false;
427 }
428
429 if (ed_object_hidden(ob)) {
430 CTX_wm_operator_poll_msg_set(C, "Cannot edit hidden object");
431 return false;
432 }
433
434 return true;
435}
436
442
447
453
460
467
469{
470 Mesh *mesh = ED_mesh_context(C);
471 return (mesh != nullptr) && ID_IS_EDITABLE(mesh) && !ID_IS_OVERRIDE_LIBRARY(mesh);
472}
473
475{
476 Object *obedit = CTX_data_edit_object(C);
477 if (obedit && obedit->type == OB_MESH) {
478 return nullptr != BKE_editmesh_from_object(obedit);
479 }
480 return false;
481}
482
487
489{
491 return true;
492 }
493
494 CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editmesh");
495 return false;
496}
497
499{
500 Object *obedit = CTX_data_edit_object(C);
501 if (obedit && obedit->type == OB_ARMATURE) {
502 return nullptr != ((bArmature *)obedit->data)->edbo;
503 }
504 return false;
505}
506
515{
516 if (obact != nullptr && !(obact->mode & OB_MODE_EDIT)) {
517 if (obact == BKE_object_pose_armature_get(obact)) {
518 return true;
519 }
520 }
521
522 CTX_wm_operator_poll_msg_set(C, "No object, or not exclusively in pose mode");
523 return false;
524}
525
532
534{
536
538 return false;
539 }
540
541 if (ID_IS_OVERRIDE_LIBRARY(obact)) {
542 CTX_wm_operator_poll_msg_set(C, "Object is a local library override");
543 return false;
544 }
545
546 return true;
547}
548
550{
552
553 if (obpose && !(obpose->mode & OB_MODE_EDIT)) {
554 if (BKE_object_pose_context_check(obpose)) {
555 return true;
556 }
557 }
558
559 return false;
560}
561
563{
565
566 if (obact && !(obact->mode & OB_MODE_EDIT)) {
567 Object *obpose = BKE_object_pose_armature_get(obact);
568 if (obpose != nullptr) {
569 if ((obact == obpose) || (obact->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
570 return true;
571 }
572 }
573 }
574
575 return false;
576}
577
579{
580 if (ED_operator_posemode(C)) {
581 Main *bmain = CTX_data_main(C);
583 bArmature *arm = static_cast<bArmature *>(ob->data);
584 return (BKE_id_is_editable(bmain, &ob->id) && BKE_id_is_editable(bmain, &arm->id));
585 }
586 return false;
587}
588
590{
592 Object *obedit = CTX_data_edit_object(C);
593 return ED_space_image_show_uvedit(sima, obedit);
594}
595
597{
599 Object *obedit = CTX_data_edit_object(C);
600 return sima && ED_space_image_show_uvedit(sima, obedit);
601}
602
604{
605 Object *obedit = CTX_data_edit_object(C);
606 BMEditMesh *em = nullptr;
607
608 if (obedit && obedit->type == OB_MESH) {
609 em = BKE_editmesh_from_object(obedit);
610 }
611
612 if (em && (em->bm->totface)) {
613 return true;
614 }
615
616 return false;
617}
618
620{
621 Object *obedit = CTX_data_edit_object(C);
622 if (obedit && ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
623 return nullptr != ((Curve *)obedit->data)->editnurb;
624 }
625 return false;
626}
627
629{
631 return true;
632 }
633
634 CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editcurve");
635 return false;
636}
637
639{
640 Object *obedit = CTX_data_edit_object(C);
641 if (obedit && obedit->type == OB_CURVES_LEGACY) {
642 return nullptr != ((Curve *)obedit->data)->editnurb;
643 }
644 return false;
645}
646
648{
649 Object *obedit = CTX_data_edit_object(C);
650 if (obedit && obedit->type == OB_CURVES_LEGACY) {
651 Curve *cu = (Curve *)obedit->data;
652
653 return (cu->flag & CU_3D) && (nullptr != cu->editnurb);
654 }
655 return false;
656}
657
659{
660 Object *obedit = CTX_data_edit_object(C);
661 if (obedit && obedit->type == OB_SURF) {
662 return nullptr != ((Curve *)obedit->data)->editnurb;
663 }
664 return false;
665}
666
668{
669 Object *obedit = CTX_data_edit_object(C);
670 if (obedit && obedit->type == OB_FONT) {
671 return nullptr != ((Curve *)obedit->data)->editfont;
672 }
673 return false;
674}
675
677{
678 Object *obedit = CTX_data_edit_object(C);
679 if (obedit && obedit->type == OB_LATTICE) {
680 return nullptr != ((Lattice *)obedit->data)->editlatt;
681 }
682 return false;
683}
684
686{
687 Object *obedit = CTX_data_edit_object(C);
688 if (obedit && obedit->type == OB_MBALL) {
689 return nullptr != ((MetaBall *)obedit->data)->editelems;
690 }
691 return false;
692}
693
695{
696 Camera *cam = static_cast<Camera *>(CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data);
697 return (cam != nullptr && ID_IS_EDITABLE(cam));
698}
699
701
702/* -------------------------------------------------------------------- */
705
707{
709 /* no full window splitting allowed */
711 return false;
712 }
713 return true;
714 }
715 return false;
716}
717
719
720/* -------------------------------------------------------------------- */
723
724/* operator state vars used:
725 * none
726 *
727 * functions:
728 *
729 * apply() set action-zone event
730 *
731 * exit() free customdata
732 *
733 * callbacks:
734 *
735 * exec() never used
736 *
737 * invoke() check if in zone
738 * add customdata, put mouseco and area in it
739 * add modal handler
740 *
741 * modal() accept modal events while doing it
742 * call apply() with gesture info, active window, nonactive window
743 * call exit() and remove handler when LMB confirm
744 */
745
753
754/* quick poll to save operators to be created and handled */
756{
757 wmWindow *win = CTX_wm_window(C);
758 if (win && win->eventstate) {
760 if (screen) {
761 const int *xy = &win->eventstate->xy[0];
762
763 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
764 LISTBASE_FOREACH (AZone *, az, &area->actionzones) {
765 if (BLI_rcti_isect_pt_v(&az->rect, xy)) {
766 return true;
767 }
768 }
769 }
770 }
771 }
772 return false;
773}
774
775/* the debug drawing of the click_rect is in area_draw_azone_fullscreen, keep both in sync */
777 rcti *rect, const short /*x1*/, const short /*y1*/, const short x2, const short y2)
778{
779 BLI_rcti_init(rect, x2 - U.widget_unit, x2, y2 - U.widget_unit, y2);
780}
781
782static bool azone_clipped_rect_calc(const AZone *az, rcti *r_rect_clip)
783{
784 const ARegion *region = az->region;
785 *r_rect_clip = az->rect;
786 if (az->type == AZONE_REGION) {
787 if (region->overlap && (region->v2d.keeptot != V2D_KEEPTOT_STRICT) &&
788 /* Only when this isn't hidden (where it's displayed as an button that expands). */
789 region->visible)
790 {
791 /* A floating region to be resized, clip by the visible region. */
792 switch (az->edge) {
795 r_rect_clip->xmin = max_ii(
796 r_rect_clip->xmin,
797 (region->winrct.xmin +
798 UI_view2d_view_to_region_x(&region->v2d, region->v2d.tot.xmin)) -
800 r_rect_clip->xmax = min_ii(
801 r_rect_clip->xmax,
802 (region->winrct.xmin +
803 UI_view2d_view_to_region_x(&region->v2d, region->v2d.tot.xmax)) +
805 return true;
806 }
808 case AE_RIGHT_TO_TOPLEFT: {
809 r_rect_clip->ymin = max_ii(
810 r_rect_clip->ymin,
811 (region->winrct.ymin +
812 UI_view2d_view_to_region_y(&region->v2d, region->v2d.tot.ymin)) -
814 r_rect_clip->ymax = min_ii(
815 r_rect_clip->ymax,
816 (region->winrct.ymin +
817 UI_view2d_view_to_region_y(&region->v2d, region->v2d.tot.ymax)) +
819 return true;
820 }
821 }
822 }
823 }
824 return false;
825}
826
827/* Return the azone's calculated rect. */
828static void area_actionzone_get_rect(AZone *az, rcti *r_rect)
829{
830 if (az->type == AZONE_REGION_SCROLL) {
831 const bool is_horizontal = az->direction == AZ_SCROLL_HOR;
832 const bool is_vertical = az->direction == AZ_SCROLL_VERT;
833 const bool is_right = is_vertical && bool(az->region->v2d.scroll & V2D_SCROLL_RIGHT);
834 const bool is_left = is_vertical && bool(az->region->v2d.scroll & V2D_SCROLL_LEFT);
835 const bool is_top = is_horizontal && bool(az->region->v2d.scroll & V2D_SCROLL_TOP);
836 const bool is_botton = is_horizontal && bool(az->region->v2d.scroll & V2D_SCROLL_BOTTOM);
837 /* For scroll azones use the area around the region's scroll-bar location. */
838 rcti scroller_vert = is_horizontal ? az->region->v2d.hor : az->region->v2d.vert;
839 BLI_rcti_translate(&scroller_vert, az->region->winrct.xmin, az->region->winrct.ymin);
840 r_rect->xmin = scroller_vert.xmin - (is_right ? V2D_SCROLL_HIDE_HEIGHT : 0);
841 r_rect->ymin = scroller_vert.ymin - (is_top ? V2D_SCROLL_HIDE_WIDTH : 0);
842 r_rect->xmax = scroller_vert.xmax + (is_left ? V2D_SCROLL_HIDE_HEIGHT : 0);
843 r_rect->ymax = scroller_vert.ymax + (is_botton ? V2D_SCROLL_HIDE_WIDTH : 0);
844 }
845 else {
846 azone_clipped_rect_calc(az, r_rect);
847 }
848}
849
850static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const bool test_only)
851{
852 AZone *az = nullptr;
853
854 for (az = static_cast<AZone *>(area->actionzones.first); az; az = az->next) {
855 rcti az_rect;
856 area_actionzone_get_rect(az, &az_rect);
857 if (BLI_rcti_isect_pt_v(&az_rect, xy)) {
858
859 if (az->type == AZONE_AREA) {
860 break;
861 }
862 if (az->type == AZONE_REGION) {
863 const ARegion *region = az->region;
864 const int local_xy[2] = {xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin};
865
866 /* Respect button sections: Clusters of buttons (separated using separator-spacers) are
867 * drawn with a background, in-between them the region is fully transparent (if "Region
868 * Overlap" is enabled). Only allow dragging visible edges, so at the button sections. */
869 if (region->visible && region->overlap &&
872 {
873 az = nullptr;
874 break;
875 }
876
877 break;
878 }
879 if (az->type == AZONE_FULLSCREEN) {
880 rcti click_rect;
881 fullscreen_click_rcti_init(&click_rect, az->x1, az->y1, az->x2, az->y2);
882 const bool click_isect = BLI_rcti_isect_pt_v(&click_rect, xy);
883
884 if (test_only) {
885 if (click_isect) {
886 break;
887 }
888 }
889 else {
890 if (click_isect) {
891 az->alpha = 1.0f;
892 }
893 else {
894 const int mouse_sq = square_i(xy[0] - az->x2) + square_i(xy[1] - az->y2);
895 const int spot_sq = square_i(AZONESPOTW);
896 const int fadein_sq = square_i(AZONEFADEIN);
897 const int fadeout_sq = square_i(AZONEFADEOUT);
898
899 if (mouse_sq < spot_sq) {
900 az->alpha = 1.0f;
901 }
902 else if (mouse_sq < fadein_sq) {
903 az->alpha = 1.0f;
904 }
905 else if (mouse_sq < fadeout_sq) {
906 az->alpha = 1.0f - float(mouse_sq - fadein_sq) / float(fadeout_sq - fadein_sq);
907 }
908 else {
909 az->alpha = 0.0f;
910 }
911
912 /* fade in/out but no click */
913 az = nullptr;
914 }
915
916 /* XXX force redraw to show/hide the action zone */
917 ED_area_tag_redraw(area);
918 break;
919 }
920 }
921 else if (az->type == AZONE_REGION_SCROLL && az->region->visible) {
922 /* If the region is not visible we can ignore this scroll-bar zone. */
923 ARegion *region = az->region;
924 View2D *v2d = &region->v2d;
925 int scroll_flag = 0;
926 const int isect_value = UI_view2d_mouse_in_scrollers_ex(region, v2d, xy, &scroll_flag);
927
928 /* Check if we even have scroll bars. */
929 if (((az->direction == AZ_SCROLL_HOR) && !(scroll_flag & V2D_SCROLL_HORIZONTAL)) ||
930 ((az->direction == AZ_SCROLL_VERT) && !(scroll_flag & V2D_SCROLL_VERTICAL)))
931 {
932 /* No scroll-bars, do nothing. */
933 }
934 else if (test_only) {
935 if (isect_value != 0) {
936 break;
937 }
938 }
939 else {
940 bool redraw = false;
941
942 if (isect_value == 'h') {
943 if (az->direction == AZ_SCROLL_HOR) {
944 az->alpha = 1.0f;
945 v2d->alpha_hor = 255;
946 redraw = true;
947 }
948 }
949 else if (isect_value == 'v') {
950 if (az->direction == AZ_SCROLL_VERT) {
951 az->alpha = 1.0f;
952 v2d->alpha_vert = 255;
953 redraw = true;
954 }
955 }
956 else {
957 const int local_xy[2] = {xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin};
958 float dist_fac = 0.0f, alpha = 0.0f;
959
960 if (az->direction == AZ_SCROLL_HOR) {
961 dist_fac = BLI_rcti_length_y(&v2d->hor, local_xy[1]) / V2D_SCROLL_HIDE_WIDTH;
962 CLAMP(dist_fac, 0.0f, 1.0f);
963 alpha = 1.0f - dist_fac;
964
965 v2d->alpha_hor = alpha * 255;
966 }
967 else if (az->direction == AZ_SCROLL_VERT) {
968 dist_fac = BLI_rcti_length_x(&v2d->vert, local_xy[0]) / V2D_SCROLL_HIDE_HEIGHT;
969 CLAMP(dist_fac, 0.0f, 1.0f);
970 alpha = 1.0f - dist_fac;
971
972 v2d->alpha_vert = alpha * 255;
973 }
974 az->alpha = alpha;
975 redraw = true;
976 }
977
978 if (redraw) {
980 }
981 /* Don't return! */
982 }
983 }
984 }
985 else if (!test_only && !IS_EQF(az->alpha, 0.0f)) {
986 if (az->type == AZONE_FULLSCREEN) {
987 az->alpha = 0.0f;
990 }
991 else if (az->type == AZONE_REGION_SCROLL && az->region->visible) {
992 /* If the region is not visible we can ignore this scroll-bar zone. */
993 if (az->direction == AZ_SCROLL_VERT) {
994 az->alpha = az->region->v2d.alpha_vert = 0;
997 }
998 else if (az->direction == AZ_SCROLL_HOR) {
999 az->alpha = az->region->v2d.alpha_hor = 0;
1002 }
1003 else {
1004 BLI_assert(false);
1005 }
1006 }
1007 }
1008 }
1009
1010 return az;
1011}
1012
1013/* Finds an action-zone by position in entire screen so azones can overlap. */
1014static AZone *screen_actionzone_find_xy(bScreen *screen, const int xy[2])
1015{
1016 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1017 AZone *az = area_actionzone_refresh_xy(area, xy, true);
1018 if (az != nullptr) {
1019 return az;
1020 }
1021 }
1022 return nullptr;
1023}
1024
1025/* Returns the area that the azone belongs to */
1026static ScrArea *screen_actionzone_area(bScreen *screen, const AZone *az)
1027{
1028 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1029 LISTBASE_FOREACH (AZone *, zone, &area->actionzones) {
1030 if (zone == az) {
1031 return area;
1032 }
1033 }
1034 }
1035 return nullptr;
1036}
1037
1039{
1040 return area_actionzone_refresh_xy(area, xy, true);
1041}
1042
1044{
1045 return area_actionzone_refresh_xy(area, xy, false);
1046}
1047
1049{
1051
1052 G.moving &= ~G_TRANSFORM_WM;
1053}
1054
1055/* send EVT_ACTIONZONE event */
1056static void actionzone_apply(bContext *C, wmOperator *op, int type)
1057{
1058 wmWindow *win = CTX_wm_window(C);
1059
1060 wmEvent event;
1061 wm_event_init_from_window(win, &event);
1062
1063 if (type == AZONE_AREA) {
1064 event.type = EVT_ACTIONZONE_AREA;
1065 }
1066 else if (type == AZONE_FULLSCREEN) {
1067 event.type = EVT_ACTIONZONE_FULLSCREEN;
1068 }
1069 else {
1070 event.type = EVT_ACTIONZONE_REGION;
1071 }
1072
1073 event.val = KM_NOTHING;
1074 event.flag = eWM_EventFlag(0);
1075 event.customdata = op->customdata;
1076 event.customdata_free = true;
1077 op->customdata = nullptr;
1078
1079 wm_event_add(win, &event);
1080}
1081
1082static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1083{
1084 bScreen *screen = CTX_wm_screen(C);
1085 AZone *az = screen_actionzone_find_xy(screen, event->xy);
1086
1087 /* Quick escape - Scroll azones only hide/unhide the scroll-bars,
1088 * they have their own handling. */
1089 if (az == nullptr || ELEM(az->type, AZONE_REGION_SCROLL)) {
1090 return OPERATOR_PASS_THROUGH;
1091 }
1092
1093 /* ok we do the action-zone */
1094 sActionzoneData *sad = static_cast<sActionzoneData *>(
1095 op->customdata = MEM_callocN(sizeof(sActionzoneData), "sActionzoneData"));
1096 sad->sa1 = screen_actionzone_area(screen, az);
1097 sad->az = az;
1098 sad->x = event->xy[0];
1099 sad->y = event->xy[1];
1100 sad->modifier = RNA_int_get(op->ptr, "modifier");
1101
1102 /* region azone directly reacts on mouse clicks */
1103 if (ELEM(sad->az->type, AZONE_REGION, AZONE_FULLSCREEN)) {
1104 actionzone_apply(C, op, sad->az->type);
1105 actionzone_exit(op);
1106 return OPERATOR_FINISHED;
1107 }
1108
1109 if (sad->az->type == AZONE_AREA && sad->modifier == 0) {
1110 actionzone_apply(C, op, sad->az->type);
1111 actionzone_exit(op);
1112 return OPERATOR_FINISHED;
1113 }
1114
1115 /* add modal handler */
1116 G.moving |= G_TRANSFORM_WM;
1119}
1120
1121static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
1122{
1123 bScreen *screen = CTX_wm_screen(C);
1124 sActionzoneData *sad = static_cast<sActionzoneData *>(op->customdata);
1125
1126 switch (event->type) {
1127 case MOUSEMOVE: {
1128 const int delta_x = (event->xy[0] - sad->x);
1129 const int delta_y = (event->xy[1] - sad->y);
1130
1131 /* Movement in dominant direction. */
1132 const int delta_max = max_ii(abs(delta_x), abs(delta_y));
1133
1134 /* Movement in dominant direction before action taken. */
1135 const int join_threshold = (0.6 * U.widget_unit);
1136 const int split_threshold = (1.2 * U.widget_unit);
1137 const int area_threshold = (0.1 * U.widget_unit);
1138
1139 /* Calculate gesture cardinal direction. */
1140 if (delta_y > abs(delta_x)) {
1142 }
1143 else if (delta_x >= abs(delta_y)) {
1145 }
1146 else if (delta_y < -abs(delta_x)) {
1148 }
1149 else {
1151 }
1152
1153 bool is_gesture;
1154 if (sad->az->type == AZONE_AREA) {
1155 wmWindow *win = CTX_wm_window(C);
1156
1157 rcti screen_rect;
1158 WM_window_screen_rect_calc(win, &screen_rect);
1159
1160 /* Have we dragged off the zone and are not on an edge? */
1161 if ((ED_area_actionzone_find_xy(sad->sa1, event->xy) != sad->az) &&
1163 AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) ==
1164 nullptr))
1165 {
1166
1167 /* What area are we now in? */
1168 ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
1169
1170 if (sad->modifier == 1) {
1171 /* Duplicate area into new window. */
1173 is_gesture = (delta_max > area_threshold);
1174 }
1175 else if (sad->modifier == 2) {
1176 /* Swap areas. */
1178 is_gesture = true;
1179 }
1180 else if (area == sad->sa1) {
1181 /* Same area, so possible split. */
1182 WM_cursor_set(win,
1185 is_gesture = (delta_max > split_threshold);
1186 }
1187 else if (!area || area->global) {
1188 /* No area or Top bar or Status bar. */
1190 is_gesture = false;
1191 }
1192 else {
1193 /* Different area, so possible join. */
1194 if (sad->gesture_dir == SCREEN_DIR_N) {
1196 }
1197 else if (sad->gesture_dir == SCREEN_DIR_S) {
1199 }
1200 else if (sad->gesture_dir == SCREEN_DIR_E) {
1202 }
1203 else {
1206 }
1207 is_gesture = (delta_max > join_threshold);
1208 }
1209 }
1210 else {
1211#if defined(__APPLE__)
1212 const int cursor = WM_CURSOR_HAND_CLOSED;
1213#else
1214 const int cursor = WM_CURSOR_MOVE;
1215#endif
1216 WM_cursor_set(win, cursor);
1217 is_gesture = false;
1218 }
1219 }
1220 else {
1221 is_gesture = (delta_max > area_threshold);
1222 }
1223
1224 /* gesture is large enough? */
1225 if (is_gesture) {
1226 /* second area, for join when (sa1 != sa2) */
1227 sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
1228 /* apply sends event */
1229 actionzone_apply(C, op, sad->az->type);
1230 actionzone_exit(op);
1231
1232 return OPERATOR_FINISHED;
1233 }
1234 break;
1235 }
1236 case EVT_ESCKEY:
1237 actionzone_exit(op);
1238 return OPERATOR_CANCELLED;
1239 case LEFTMOUSE:
1240 actionzone_exit(op);
1241 return OPERATOR_CANCELLED;
1242 }
1243
1245}
1246
1247static void actionzone_cancel(bContext * /*C*/, wmOperator *op)
1248{
1249 actionzone_exit(op);
1250}
1251
1253{
1254 /* identifiers */
1255 ot->name = "Handle Area Action Zones";
1256 ot->description = "Handle area action zones for mouse actions/gestures";
1257 ot->idname = "SCREEN_OT_actionzone";
1258
1259 ot->invoke = actionzone_invoke;
1260 ot->modal = actionzone_modal;
1261 ot->poll = actionzone_area_poll;
1262 ot->cancel = actionzone_cancel;
1263
1264 /* flags */
1266
1267 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "Modifier", "Modifier state", 0, 2);
1268}
1269
1271
1272/* -------------------------------------------------------------------- */
1275
1277 const int cursor[2],
1278 ScrArea **r_sa1,
1279 ScrArea **r_sa2)
1280{
1281 wmWindow *win = CTX_wm_window(C);
1282 bScreen *screen = CTX_wm_screen(C);
1283 rcti window_rect;
1284 WM_window_rect_calc(win, &window_rect);
1286 AREAMAP_FROM_SCREEN(screen), &window_rect, cursor[0], cursor[1]);
1287 *r_sa1 = nullptr;
1288 *r_sa2 = nullptr;
1289 if (actedge == nullptr) {
1290 return nullptr;
1291 }
1292 int borderwidth = (4 * UI_SCALE_FAC);
1293 ScrArea *sa1, *sa2;
1294 if (screen_geom_edge_is_horizontal(actedge)) {
1296 screen, SPACE_TYPE_ANY, blender::int2{cursor[0], cursor[1] + borderwidth});
1298 screen, SPACE_TYPE_ANY, blender::int2{cursor[0], cursor[1] - borderwidth});
1299 }
1300 else {
1302 screen, SPACE_TYPE_ANY, blender::int2{cursor[0] + borderwidth, cursor[1]});
1304 screen, SPACE_TYPE_ANY, blender::int2{cursor[0] - borderwidth, cursor[1]});
1305 }
1306 bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2)));
1307 if (!isGlobal) {
1308 *r_sa1 = sa1;
1309 *r_sa2 = sa2;
1310 }
1311 return actedge;
1312}
1313
1315
1316/* -------------------------------------------------------------------- */
1319
1320/* operator state vars used:
1321 * sa1 start area
1322 * sa2 area to swap with
1323 *
1324 * functions:
1325 *
1326 * init() set custom data for operator, based on action-zone event custom data
1327 *
1328 * cancel() cancel the operator
1329 *
1330 * exit() cleanup, send notifier
1331 *
1332 * callbacks:
1333 *
1334 * invoke() gets called on Shift-LMB drag in action-zone
1335 * exec() execute without any user interaction, based on properties
1336 * call init(), add handler
1337 *
1338 * modal() accept modal events while doing it
1339 */
1340
1343};
1344
1345static bool area_swap_init(wmOperator *op, const wmEvent *event)
1346{
1347 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
1348
1349 if (sad == nullptr || sad->sa1 == nullptr) {
1350 return false;
1351 }
1352
1353 sAreaSwapData *sd = static_cast<sAreaSwapData *>(
1354 MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData"));
1355 sd->sa1 = sad->sa1;
1356 sd->sa2 = sad->sa2;
1357 op->customdata = sd;
1358
1359 return true;
1360}
1361
1368
1370{
1371 area_swap_exit(C, op);
1372}
1373
1374static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1375{
1376 if (!area_swap_init(op, event)) {
1377 return OPERATOR_PASS_THROUGH;
1378 }
1379
1380 /* add modal handler */
1383
1385}
1386
1387static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
1388{
1389 sActionzoneData *sad = static_cast<sActionzoneData *>(op->customdata);
1390
1391 switch (event->type) {
1392 case MOUSEMOVE: {
1393 /* Second area to swap with. */
1396 WorkspaceStatus status(C);
1397 status.item(IFACE_("Select Area"), ICON_MOUSE_LMB);
1398 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
1399 break;
1400 }
1401 case LEFTMOUSE: /* release LMB */
1402 if (event->val == KM_RELEASE) {
1403 if (!sad->sa2 || sad->sa1 == sad->sa2) {
1404 area_swap_cancel(C, op);
1405 return OPERATOR_CANCELLED;
1406 }
1407
1408 ED_area_tag_redraw(sad->sa1);
1409 ED_area_tag_redraw(sad->sa2);
1410
1411 ED_area_swapspace(C, sad->sa1, sad->sa2);
1412
1413 area_swap_exit(C, op);
1414
1416
1417 return OPERATOR_FINISHED;
1418 }
1419 break;
1420
1421 case EVT_ESCKEY:
1422 area_swap_cancel(C, op);
1423 return OPERATOR_CANCELLED;
1424 }
1426}
1427
1429{
1430 ScrArea *sa1, *sa2;
1431 int cursor[2];
1432 RNA_int_get_array(op->ptr, "cursor", cursor);
1433 screen_area_edge_from_cursor(C, cursor, &sa1, &sa2);
1434 if (sa1 == nullptr || sa2 == nullptr) {
1435 return OPERATOR_CANCELLED;
1436 }
1437 ED_area_swapspace(C, sa1, sa2);
1438 return OPERATOR_FINISHED;
1439}
1440
1442{
1443 ot->name = "Swap Areas";
1444 ot->description = "Swap selected areas screen positions";
1445 ot->idname = "SCREEN_OT_area_swap";
1446
1447 ot->invoke = area_swap_invoke;
1448 ot->modal = area_swap_modal;
1449 ot->exec = area_swap_exec;
1450 ot->poll = screen_active_editable;
1451 ot->cancel = area_swap_cancel;
1452
1453 ot->flag = OPTYPE_BLOCKING;
1454
1455 /* rna */
1457 ot->srna, "cursor", 2, nullptr, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX);
1458}
1459
1461
1462/* -------------------------------------------------------------------- */
1467
1469static void area_dupli_fn(bScreen * /*screen*/, ScrArea *area, void *user_data)
1470{
1471 ScrArea *area_src = static_cast<ScrArea *>(user_data);
1472 ED_area_data_copy(area, area_src, true);
1473 ED_area_tag_redraw(area);
1474};
1475
1476/* operator callback */
1477static bool area_dupli_open(bContext *C, ScrArea *area, const blender::int2 position)
1478{
1479 const rcti window_rect = {
1480 position.x, position.x + area->winx, position.y, position.y + area->winy};
1481
1482 /* Create new window. No need to set space_type since it will be copied over. */
1483 wmWindow *newwin = WM_window_open(C,
1484 nullptr,
1485 &window_rect,
1487 false,
1488 false,
1489 false,
1491 /* Initialize area from callback. */
1493 (void *)area);
1494 return (newwin != nullptr);
1495}
1496
1497static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1498{
1499 ScrArea *area = CTX_wm_area(C);
1500 if (event && event->customdata) {
1501 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
1502 if (sad == nullptr) {
1503 return OPERATOR_PASS_THROUGH;
1504 }
1505 area = sad->sa1;
1506 }
1507
1508 bool newwin = area_dupli_open(C, area, blender::int2(area->totrct.xmin, area->totrct.ymin));
1509
1510 if (newwin) {
1511 /* screen, areas init */
1513 }
1514 else {
1515 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
1516 }
1517
1518 if (event && event->customdata) {
1519 actionzone_exit(op);
1520 }
1521
1522 return newwin ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1523}
1524
1526{
1527 ot->name = "Duplicate Area into New Window";
1528 ot->description = "Duplicate selected area into new window";
1529 ot->idname = "SCREEN_OT_area_dupli";
1530
1531 ot->invoke = area_dupli_invoke;
1532 ot->poll = ED_operator_areaactive;
1533}
1534
1536
1537/* -------------------------------------------------------------------- */
1542
1551{
1552 bScreen *screen = CTX_wm_screen(C);
1553 ScrArea *area = CTX_wm_area(C);
1554
1555 /* This operator is script-able, so the area passed could be invalid. */
1556 if (BLI_findindex(&screen->areabase, area) == -1) {
1557 BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen");
1558 return OPERATOR_CANCELLED;
1559 }
1560
1561 if (!screen_area_close(C, screen, area)) {
1562 BKE_report(op->reports, RPT_ERROR, "Unable to close area");
1563 return OPERATOR_CANCELLED;
1564 }
1565
1566 /* Ensure the event loop doesn't attempt to continue handling events.
1567 *
1568 * This causes execution from the Python console fail to return to the prompt as it should.
1569 * This glitch could be solved in the event loop handling as other operators may also
1570 * destructively manipulate windowing data. */
1571 CTX_wm_window_set(C, nullptr);
1572
1574
1575 return OPERATOR_FINISHED;
1576}
1577
1579{
1580 if (!ED_operator_areaactive(C)) {
1581 return false;
1582 }
1583
1584 ScrArea *area = CTX_wm_area(C);
1585
1586 if (ED_area_is_global(area)) {
1587 return false;
1588 }
1589
1590 bScreen *screen = CTX_wm_screen(C);
1591
1592 /* Can this area join with ANY other area? */
1593 LISTBASE_FOREACH (ScrArea *, ar, &screen->areabase) {
1594 if (area_getorientation(ar, area) != -1) {
1595 return true;
1596 }
1597 }
1598
1599 return false;
1600}
1601
1603{
1604 ot->name = "Close Area";
1605 ot->description = "Close selected area";
1606 ot->idname = "SCREEN_OT_area_close";
1607 ot->exec = area_close_exec;
1608 ot->poll = area_close_poll;
1609}
1610
1612
1613/* -------------------------------------------------------------------- */
1616
1617/* operator state vars used:
1618 * x, y mouse coord near edge
1619 * delta movement of edge
1620 *
1621 * functions:
1622 *
1623 * init() set default property values, find edge based on mouse coords, test
1624 * if the edge can be moved, select edges, calculate min and max movement
1625 *
1626 * apply() apply delta on selection
1627 *
1628 * exit() cleanup, send notifier
1629 *
1630 * cancel() cancel moving
1631 *
1632 * callbacks:
1633 *
1634 * exec() execute without any user interaction, based on properties
1635 * call init(), apply(), exit()
1636 *
1637 * invoke() gets called on mouse click near edge
1638 * call init(), add handler
1639 *
1640 * modal() accept modal events while doing it
1641 * call apply() with delta motion
1642 * call exit() and remove handler
1643 */
1644
1646 /* Snapping disabled */
1647 SNAP_NONE = 0, /* Snap to an invisible grid with a unit defined in AREAGRID */
1648 SNAP_AREAGRID, /* Snap to fraction (half, third.. etc) and adjacent edges. */
1649 SNAP_FRACTION_AND_ADJACENT, /* Snap to either bigger or smaller, nothing in-between (used for
1650 * global areas). This has priority over other snap types, if it is
1651 * used, toggling SNAP_FRACTION_AND_ADJACENT doesn't work. */
1653};
1654
1662
1663/* helper call to move area-edge, sets limits
1664 * need window bounds in order to get correct limits */
1666 bScreen *screen,
1667 const eScreenAxis dir_axis,
1668 int *bigger,
1669 int *smaller,
1670 bool *use_bigger_smaller_snap)
1671{
1672 /* we check all areas and test for free space with MINSIZE */
1673 *bigger = *smaller = 100000;
1674
1675 if (use_bigger_smaller_snap != nullptr) {
1676 *use_bigger_smaller_snap = false;
1678 int size_min = ED_area_global_min_size_y(area) - 1;
1679 int size_max = ED_area_global_max_size_y(area) - 1;
1680
1681 size_min = max_ii(size_min, 0);
1682 BLI_assert(size_min <= size_max);
1683
1684 /* logic here is only tested for lower edge :) */
1685 /* left edge */
1686 if (area->v1->editflag && area->v2->editflag) {
1687 *smaller = area->v4->vec.x - size_max;
1688 *bigger = area->v4->vec.x - size_min;
1689 *use_bigger_smaller_snap = true;
1690 return;
1691 }
1692 /* top edge */
1693 if (area->v2->editflag && area->v3->editflag) {
1694 *smaller = area->v1->vec.y + size_min;
1695 *bigger = area->v1->vec.y + size_max;
1696 *use_bigger_smaller_snap = true;
1697 return;
1698 }
1699 /* right edge */
1700 if (area->v3->editflag && area->v4->editflag) {
1701 *smaller = area->v1->vec.x + size_min;
1702 *bigger = area->v1->vec.x + size_max;
1703 *use_bigger_smaller_snap = true;
1704 return;
1705 }
1706 /* lower edge */
1707 if (area->v4->editflag && area->v1->editflag) {
1708 *smaller = area->v2->vec.y - size_max;
1709 *bigger = area->v2->vec.y - size_min;
1710 *use_bigger_smaller_snap = true;
1711 return;
1712 }
1713 }
1714 }
1715
1716 rcti window_rect;
1717 WM_window_rect_calc(win, &window_rect);
1718
1719 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1720 if (dir_axis == SCREEN_AXIS_H) {
1721 int areamin = ED_area_headersize();
1722
1723 if (area->v1->vec.y > window_rect.ymin) {
1724 areamin += U.pixelsize;
1725 }
1726 if (area->v2->vec.y < (window_rect.ymax - 1)) {
1727 areamin += U.pixelsize;
1728 }
1729
1730 int y1 = screen_geom_area_height(area) - areamin - int(U.pixelsize);
1731
1732 /* if top or down edge selected, test height */
1733 if (area->v1->editflag && area->v4->editflag) {
1734 *bigger = min_ii(*bigger, y1);
1735 }
1736 else if (area->v2->editflag && area->v3->editflag) {
1737 *smaller = min_ii(*smaller, y1);
1738 }
1739 }
1740 else {
1741 int areamin = AREAMINX * UI_SCALE_FAC;
1742
1743 if (area->v1->vec.x > window_rect.xmin) {
1744 areamin += U.pixelsize;
1745 }
1746 if (area->v4->vec.x < (window_rect.xmax - 1)) {
1747 areamin += U.pixelsize;
1748 }
1749
1750 int x1 = screen_geom_area_width(area) - areamin - int(U.pixelsize);
1751
1752 /* if left or right edge selected, test width */
1753 if (area->v1->editflag && area->v2->editflag) {
1754 *bigger = min_ii(*bigger, x1);
1755 }
1756 else if (area->v3->editflag && area->v4->editflag) {
1757 *smaller = min_ii(*smaller, x1);
1758 }
1759 }
1760 }
1761}
1762
1763static void area_move_draw_cb(const wmWindow * /*win*/, void *userdata)
1764{
1765 const wmOperator *op = static_cast<const wmOperator *>(userdata);
1766 const sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
1768}
1769
1770/* validate selection inside screen, set variables OK */
1771/* return false: init failed */
1773{
1774 bScreen *screen = CTX_wm_screen(C);
1775 wmWindow *win = CTX_wm_window(C);
1776
1777 /* required properties */
1778 int x = RNA_int_get(op->ptr, "x");
1779 int y = RNA_int_get(op->ptr, "y");
1780
1781 /* setup */
1782 ScrEdge *actedge = screen_geom_find_active_scredge(win, screen, x, y);
1783 if (actedge == nullptr) {
1784 return false;
1785 }
1786
1787 sAreaMoveData *md = static_cast<sAreaMoveData *>(
1788 MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData"));
1789 op->customdata = md;
1790
1792 if (md->dir_axis == SCREEN_AXIS_H) {
1793 md->origval = actedge->v1->vec.y;
1794 }
1795 else {
1796 md->origval = actedge->v1->vec.x;
1797 }
1798
1800 /* now all vertices with 'flag == 1' are the ones that can be moved. Move this to editflag */
1801 ED_screen_verts_iter(win, screen, v1)
1802 {
1803 v1->editflag = v1->flag;
1804 }
1805
1806 bool use_bigger_smaller_snap = false;
1808 win, screen, md->dir_axis, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
1809
1810 md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID;
1811
1812 md->screen = screen;
1814
1815 return true;
1816}
1817
1818static int area_snap_calc_location(const bScreen *screen,
1819 const enum AreaMoveSnapType snap_type,
1820 const int delta,
1821 const int origval,
1822 const eScreenAxis dir_axis,
1823 const int bigger,
1824 const int smaller)
1825{
1826 BLI_assert(snap_type != SNAP_NONE);
1827 int m_cursor_final = -1;
1828 const int m_cursor = origval + delta;
1829 const int m_span = float(bigger + smaller);
1830 const int m_min = origval - smaller;
1831 // const int axis_max = axis_min + m_span;
1832
1833 switch (snap_type) {
1834 case SNAP_AREAGRID:
1835 m_cursor_final = m_cursor;
1836 if (!ELEM(delta, bigger, -smaller)) {
1837 m_cursor_final -= (m_cursor % AREAGRID);
1838 CLAMP(m_cursor_final, origval - smaller, origval + bigger);
1839 }
1840 break;
1841
1843 m_cursor_final = (m_cursor >= bigger) ? bigger : smaller;
1844 break;
1845
1847 const int axis = (dir_axis == SCREEN_AXIS_V) ? 0 : 1;
1848 int snap_dist_best = INT_MAX;
1849 {
1850 const float div_array[] = {
1851 0.0f,
1852 1.0f / 12.0f,
1853 2.0f / 12.0f,
1854 3.0f / 12.0f,
1855 4.0f / 12.0f,
1856 5.0f / 12.0f,
1857 6.0f / 12.0f,
1858 7.0f / 12.0f,
1859 8.0f / 12.0f,
1860 9.0f / 12.0f,
1861 10.0f / 12.0f,
1862 11.0f / 12.0f,
1863 1.0f,
1864 };
1865 /* Test the snap to the best division. */
1866 for (int i = 0; i < ARRAY_SIZE(div_array); i++) {
1867 const int m_cursor_test = m_min + round_fl_to_int(m_span * div_array[i]);
1868 const int snap_dist_test = abs(m_cursor - m_cursor_test);
1869 if (snap_dist_best >= snap_dist_test) {
1870 snap_dist_best = snap_dist_test;
1871 m_cursor_final = m_cursor_test;
1872 }
1873 }
1874 }
1875
1876 LISTBASE_FOREACH (const ScrVert *, v1, &screen->vertbase) {
1877 if (!v1->editflag) {
1878 continue;
1879 }
1880 const int v_loc = (&v1->vec.x)[!axis];
1881
1882 LISTBASE_FOREACH (const ScrVert *, v2, &screen->vertbase) {
1883 if (v2->editflag) {
1884 continue;
1885 }
1886 if (v_loc == (&v2->vec.x)[!axis]) {
1887 const int v_loc2 = (&v2->vec.x)[axis];
1888 /* Do not snap to the vertices at the ends. */
1889 if ((origval - smaller) < v_loc2 && v_loc2 < (origval + bigger)) {
1890 const int snap_dist_test = abs(m_cursor - v_loc2);
1891 if (snap_dist_best >= snap_dist_test) {
1892 snap_dist_best = snap_dist_test;
1893 m_cursor_final = v_loc2;
1894 }
1895 }
1896 }
1897 }
1898 }
1899 break;
1900 }
1901 case SNAP_NONE:
1902 break;
1903 }
1904
1906 IN_RANGE_INCL(m_cursor_final, origval - smaller, origval + bigger));
1907
1908 return m_cursor_final;
1909}
1910
1911/* moves selected screen edge amount of delta, used by split & move */
1913 int delta,
1914 const int origval,
1915 const eScreenAxis dir_axis,
1916 const int bigger,
1917 const int smaller,
1918 const enum AreaMoveSnapType snap_type)
1919{
1920 WorkspaceStatus status(C);
1921 status.item(IFACE_("Confirm"), ICON_MOUSE_LMB);
1922 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
1923 status.item_bool(IFACE_("Snap"), snap_type == SNAP_FRACTION_AND_ADJACENT, ICON_EVENT_CTRL);
1924
1925 wmWindow *win = CTX_wm_window(C);
1926 bScreen *screen = CTX_wm_screen(C);
1927 short final_loc = -1;
1928 bool doredraw = false;
1929
1930 if (snap_type != SNAP_BIGGER_SMALLER_ONLY) {
1931 CLAMP(delta, -smaller, bigger);
1932 }
1933
1934 if (snap_type == SNAP_NONE) {
1935 final_loc = origval + delta;
1936 }
1937 else {
1938 final_loc = area_snap_calc_location(
1939 screen, snap_type, delta, origval, dir_axis, bigger, smaller);
1940 }
1941
1942 BLI_assert(final_loc != -1);
1943 short axis = (dir_axis == SCREEN_AXIS_V) ? 0 : 1;
1944
1945 ED_screen_verts_iter(win, screen, v1)
1946 {
1947 if (v1->editflag) {
1948 short oldval = (&v1->vec.x)[axis];
1949 (&v1->vec.x)[axis] = final_loc;
1950
1951 if (oldval == final_loc) {
1952 /* nothing will change to the other vertices either. */
1953 break;
1954 }
1955 doredraw = true;
1956 }
1957 }
1958
1959 /* only redraw if we actually moved a screen vert, for AREAGRID */
1960 if (doredraw) {
1961 bool redraw_all = false;
1962 ED_screen_areas_iter (win, screen, area) {
1963 if (area->v1->editflag || area->v2->editflag || area->v3->editflag || area->v4->editflag) {
1964 if (ED_area_is_global(area)) {
1965 /* Snap to minimum or maximum for global areas. */
1967 if (abs(height - area->global->size_min) < abs(height - area->global->size_max)) {
1968 area->global->cur_fixed_height = area->global->size_min;
1969 }
1970 else {
1971 area->global->cur_fixed_height = area->global->size_max;
1972 }
1973
1974 screen->do_refresh = true;
1975 redraw_all = true;
1976 }
1978 }
1979 }
1980 if (redraw_all) {
1981 ED_screen_areas_iter (win, screen, area) {
1982 ED_area_tag_redraw(area);
1983 }
1984 }
1985
1987
1988 WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, nullptr); /* redraw everything */
1989 /* Update preview thumbnail */
1990 BKE_icon_changed(screen->id.icon_id);
1991 }
1992}
1993
1995{
1996 sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
1997 int delta = RNA_int_get(op->ptr, "delta");
1998
1999 area_move_apply_do(C, delta, md->origval, md->dir_axis, md->bigger, md->smaller, md->snap_type);
2000}
2001
2003{
2004 sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
2005 if (md->draw_callback) {
2007 }
2008
2010
2011 /* this makes sure aligned edges will result in aligned grabbing */
2014 ED_workspace_status_text(C, nullptr);
2015 G.moving &= ~G_TRANSFORM_WM;
2016}
2017
2019{
2020 if (!area_move_init(C, op)) {
2021 return OPERATOR_CANCELLED;
2022 }
2023
2024 area_move_apply(C, op);
2025 area_move_exit(C, op);
2026
2027 return OPERATOR_FINISHED;
2028}
2029
2030/* interaction callback */
2031static int area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2032{
2033 RNA_int_set(op->ptr, "x", event->xy[0]);
2034 RNA_int_set(op->ptr, "y", event->xy[1]);
2035
2036 if (!area_move_init(C, op)) {
2037 return OPERATOR_PASS_THROUGH;
2038 }
2039
2040 sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
2041
2042 WorkspaceStatus status(C);
2043 status.item(IFACE_("Confirm"), ICON_MOUSE_LMB);
2044 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
2045 status.item_bool(IFACE_("Snap"), md->snap_type == SNAP_FRACTION_AND_ADJACENT, ICON_EVENT_CTRL);
2046
2047 /* add temp handler */
2048 G.moving |= G_TRANSFORM_WM;
2050
2052}
2053
2055{
2056
2057 RNA_int_set(op->ptr, "delta", 0);
2058 area_move_apply(C, op);
2059 area_move_exit(C, op);
2060}
2061
2062/* modal callback for while moving edges */
2063static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
2064{
2065 sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
2066
2067 /* execute the events */
2068 switch (event->type) {
2069 case MOUSEMOVE: {
2070 int x = RNA_int_get(op->ptr, "x");
2071 int y = RNA_int_get(op->ptr, "y");
2072
2073 const int delta = (md->dir_axis == SCREEN_AXIS_V) ? event->xy[0] - x : event->xy[1] - y;
2074 RNA_int_set(op->ptr, "delta", delta);
2075
2076 area_move_apply(C, op);
2077 break;
2078 }
2079 case RIGHTMOUSE: {
2080 area_move_cancel(C, op);
2081 return OPERATOR_CANCELLED;
2082 }
2083 case EVT_MODAL_MAP: {
2084 switch (event->val) {
2085 case KM_MODAL_APPLY:
2086 area_move_exit(C, op);
2087 return OPERATOR_FINISHED;
2088
2089 case KM_MODAL_CANCEL:
2090 area_move_cancel(C, op);
2091 return OPERATOR_CANCELLED;
2092
2093 case KM_MODAL_SNAP_ON:
2096 }
2097 break;
2098
2099 case KM_MODAL_SNAP_OFF:
2102 }
2103 break;
2104 }
2105 WorkspaceStatus status(C);
2106 status.item(IFACE_("Confirm"), ICON_MOUSE_LMB);
2107 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
2108 status.item_bool(
2109 IFACE_("Snap"), md->snap_type == SNAP_FRACTION_AND_ADJACENT, ICON_EVENT_CTRL);
2110 break;
2111 }
2112 }
2113
2115}
2116
2118{
2119 /* identifiers */
2120 ot->name = "Move Area Edges";
2121 ot->description = "Move selected area edges";
2122 ot->idname = "SCREEN_OT_area_move";
2123
2124 ot->exec = area_move_exec;
2125 ot->invoke = area_move_invoke;
2126 ot->cancel = area_move_cancel;
2127 ot->modal = area_move_modal;
2128 ot->poll = ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
2129
2130 /* flags */
2132
2133 /* rna */
2134 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2135 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2136 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
2137}
2138
2140
2141/* -------------------------------------------------------------------- */
2144
2145/*
2146 * operator state vars:
2147 * fac spit point
2148 * dir direction #SCREEN_AXIS_V or #SCREEN_AXIS_H
2149 *
2150 * operator customdata:
2151 * area pointer to (active) area
2152 * x, y last used mouse pos
2153 * (more, see below)
2154 *
2155 * functions:
2156 *
2157 * init() set default property values, find area based on context
2158 *
2159 * apply() split area based on state vars
2160 *
2161 * exit() cleanup, send notifier
2162 *
2163 * cancel() remove duplicated area
2164 *
2165 * callbacks:
2166 *
2167 * exec() execute without any user interaction, based on state vars
2168 * call init(), apply(), exit()
2169 *
2170 * invoke() gets called on mouse click in action-widget
2171 * call init(), add modal handler
2172 * call apply() with initial motion
2173 *
2174 * modal() accept modal events while doing it
2175 * call move-areas code with delta motion
2176 * call exit() or cancel() and remove handler
2177 */
2178
2180 int origval; /* for move areas */
2181 int bigger, smaller; /* constraints for moving new edge */
2182 int delta; /* delta move edge */
2183 int origmin, origsize; /* to calculate fac, for property storage */
2184 int previewmode; /* draw preview-line, then split. */
2185 void *draw_callback; /* call `screen_draw_split_preview` */
2187
2188 ScrEdge *nedge; /* new edge */
2189 ScrArea *sarea; /* start area */
2190 ScrArea *narea; /* new area */
2191};
2192
2193static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis)
2194{
2195 if (!area || area->global) {
2196 /* Must be a non-global area. */
2197 return false;
2198 }
2199
2200 if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX * UI_SCALE_FAC) ||
2201 (dir_axis == SCREEN_AXIS_H && area->winy <= 2 * ED_area_headersize()))
2202 {
2203 /* Must be at least double minimum sizes to split into two. */
2204 return false;
2205 }
2206
2207 return true;
2208}
2209
2210static void area_split_draw_cb(const wmWindow * /*win*/, void *userdata)
2211{
2212 const wmOperator *op = static_cast<const wmOperator *>(userdata);
2213
2214 sAreaSplitData *sd = static_cast<sAreaSplitData *>(op->customdata);
2215 const eScreenAxis dir_axis = eScreenAxis(RNA_enum_get(op->ptr, "direction"));
2216
2217 if (area_split_allowed(sd->sarea, dir_axis)) {
2218 float fac = RNA_float_get(op->ptr, "factor");
2219 screen_draw_split_preview(sd->sarea, dir_axis, fac);
2220 }
2221}
2222
2223/* generic init, menu case, doesn't need active area */
2225{
2226 /* custom data */
2227 sAreaSplitData *sd = (sAreaSplitData *)MEM_callocN(sizeof(sAreaSplitData), "op_area_split");
2228 op->customdata = sd;
2229
2230 sd->sarea = CTX_wm_area(C);
2231
2232 return true;
2233}
2234
2235/* generic init, no UI stuff here, assumes active area */
2237{
2238 ScrArea *area = CTX_wm_area(C);
2239
2240 /* required context */
2241 if (area == nullptr) {
2242 return false;
2243 }
2244
2245 /* required properties */
2246 const eScreenAxis dir_axis = eScreenAxis(RNA_enum_get(op->ptr, "direction"));
2247
2248 /* custom data */
2249 sAreaSplitData *sd = (sAreaSplitData *)MEM_callocN(sizeof(sAreaSplitData), "op_area_split");
2250 op->customdata = sd;
2251
2252 sd->sarea = area;
2253 if (dir_axis == SCREEN_AXIS_V) {
2254 sd->origmin = area->v1->vec.x;
2255 sd->origsize = area->v4->vec.x - sd->origmin;
2256 }
2257 else {
2258 sd->origmin = area->v1->vec.y;
2259 sd->origsize = area->v2->vec.y - sd->origmin;
2260 }
2261
2262 return true;
2263}
2264
2265/* with area as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
2266/* used with split operator */
2268{
2269 ScrVert *sav1 = area->v1;
2270 ScrVert *sav2 = area->v2;
2271 ScrVert *sav3 = area->v3;
2272 ScrVert *sav4 = area->v4;
2273 ScrVert *sbv1 = sb->v1;
2274 ScrVert *sbv2 = sb->v2;
2275 ScrVert *sbv3 = sb->v3;
2276 ScrVert *sbv4 = sb->v4;
2277
2278 if (sav1 == sbv4 && sav2 == sbv3) { /* Area to right of sb = W. */
2279 return BKE_screen_find_edge(screen, sav1, sav2);
2280 }
2281 if (sav2 == sbv1 && sav3 == sbv4) { /* Area to bottom of sb = N. */
2282 return BKE_screen_find_edge(screen, sav2, sav3);
2283 }
2284 if (sav3 == sbv2 && sav4 == sbv1) { /* Area to left of sb = E. */
2285 return BKE_screen_find_edge(screen, sav3, sav4);
2286 }
2287 if (sav1 == sbv2 && sav4 == sbv3) { /* Area on top of sb = S. */
2288 return BKE_screen_find_edge(screen, sav1, sav4);
2289 }
2290
2291 return nullptr;
2292}
2293
2294/* do the split, return success */
2296{
2297 const wmWindow *win = CTX_wm_window(C);
2298 bScreen *screen = CTX_wm_screen(C);
2300
2301 float fac = RNA_float_get(op->ptr, "factor");
2302 const eScreenAxis dir_axis = eScreenAxis(RNA_enum_get(op->ptr, "direction"));
2303
2304 if (!area_split_allowed(sd->sarea, dir_axis)) {
2305 return false;
2306 }
2307
2308 sd->narea = area_split(win, screen, sd->sarea, dir_axis, fac, false); /* false = no merge */
2309
2310 if (sd->narea == nullptr) {
2311 return false;
2312 }
2313
2314 sd->nedge = area_findsharededge(screen, sd->sarea, sd->narea);
2315
2316 /* select newly created edge, prepare for moving edge */
2317 ED_screen_verts_iter(win, screen, sv)
2318 {
2319 sv->editflag = 0;
2320 }
2321
2322 sd->nedge->v1->editflag = 1;
2323 sd->nedge->v2->editflag = 1;
2324
2325 if (dir_axis == SCREEN_AXIS_H) {
2326 sd->origval = sd->nedge->v1->vec.y;
2327 }
2328 else {
2329 sd->origval = sd->nedge->v1->vec.x;
2330 }
2331
2334
2336 /* Update preview thumbnail */
2337 BKE_icon_changed(screen->id.icon_id);
2338
2339 /* We have more than one area now, so reset window title. */
2341
2342 return true;
2343}
2344
2346{
2347 if (op->customdata) {
2349 if (sd->sarea) {
2351 }
2352 if (sd->narea) {
2354 }
2355
2356 if (sd->draw_callback) {
2358 }
2359
2360 MEM_freeN(op->customdata);
2361 op->customdata = nullptr;
2362 }
2363
2366 ED_workspace_status_text(C, nullptr);
2367
2368 /* this makes sure aligned edges will result in aligned grabbing */
2371
2372 G.moving &= ~G_TRANSFORM_WM;
2373}
2374
2376{
2378 const eScreenAxis dir_axis = eScreenAxis(RNA_enum_get(op->ptr, "direction"));
2379 if (area_split_allowed(sd->sarea, dir_axis)) {
2382 }
2383 else {
2385 }
2386}
2387
2388/* UI callback, adds new handler */
2389static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2390{
2391 wmWindow *win = CTX_wm_window(C);
2392 bScreen *screen = CTX_wm_screen(C);
2393
2394 /* no full window splitting allowed */
2395 BLI_assert(screen->state == SCREENNORMAL);
2396
2397 PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction");
2398 PropertyRNA *prop_factor = RNA_struct_find_property(op->ptr, "factor");
2399 PropertyRNA *prop_cursor = RNA_struct_find_property(op->ptr, "cursor");
2400
2401 eScreenAxis dir_axis;
2402 if (event->type == EVT_ACTIONZONE_AREA) {
2403 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
2404
2405 if (sad == nullptr || sad->modifier > 0) {
2406 return OPERATOR_PASS_THROUGH;
2407 }
2408
2409 /* verify *sad itself */
2410 if (sad->sa1 == nullptr || sad->az == nullptr) {
2411 return OPERATOR_PASS_THROUGH;
2412 }
2413
2414 /* is this our *sad? if areas not equal it should be passed on */
2415 if (CTX_wm_area(C) != sad->sa1 || sad->sa1 != sad->sa2) {
2416 return OPERATOR_PASS_THROUGH;
2417 }
2418
2419 /* The factor will be close to 1.0f when near the top-left and the bottom-right corners. */
2420 const float factor_v = float(event->xy[1] - sad->sa1->v1->vec.y) / float(sad->sa1->winy);
2421 const float factor_h = float(event->xy[0] - sad->sa1->v1->vec.x) / float(sad->sa1->winx);
2422 const bool is_left = factor_v < 0.5f;
2423 const bool is_bottom = factor_h < 0.5f;
2424 const bool is_right = !is_left;
2425 const bool is_top = !is_bottom;
2426 float factor;
2427
2428 /* Prepare operator state vars. */
2430 dir_axis = SCREEN_AXIS_H;
2431 factor = factor_h;
2432 }
2433 else {
2434 dir_axis = SCREEN_AXIS_V;
2435 factor = factor_v;
2436 }
2437
2438 if ((is_top && is_left) || (is_bottom && is_right)) {
2439 factor = 1.0f - factor;
2440 }
2441
2442 RNA_property_float_set(op->ptr, prop_factor, factor);
2443
2444 RNA_property_enum_set(op->ptr, prop_dir, dir_axis);
2445
2446 /* general init, also non-UI case, adds customdata, sets area and defaults */
2447 if (!area_split_init(C, op)) {
2448 return OPERATOR_PASS_THROUGH;
2449 }
2450 }
2451 else if (RNA_property_is_set(op->ptr, prop_dir)) {
2452 ScrArea *area = CTX_wm_area(C);
2453 if (area == nullptr) {
2454 return OPERATOR_CANCELLED;
2455 }
2456 dir_axis = eScreenAxis(RNA_property_enum_get(op->ptr, prop_dir));
2457 if (dir_axis == SCREEN_AXIS_H) {
2459 op->ptr, prop_factor, float(event->xy[0] - area->v1->vec.x) / float(area->winx));
2460 }
2461 else {
2463 op->ptr, prop_factor, float(event->xy[1] - area->v1->vec.y) / float(area->winy));
2464 }
2465
2466 if (!area_split_init(C, op)) {
2467 return OPERATOR_CANCELLED;
2468 }
2469 }
2470 else {
2471 int event_co[2];
2472
2473 /* retrieve initial mouse coord, so we can find the active edge */
2474 if (RNA_property_is_set(op->ptr, prop_cursor)) {
2475 RNA_property_int_get_array(op->ptr, prop_cursor, event_co);
2476 }
2477 else {
2478 copy_v2_v2_int(event_co, event->xy);
2479 }
2480
2481 rcti window_rect;
2482 WM_window_rect_calc(win, &window_rect);
2483
2485 AREAMAP_FROM_SCREEN(screen), &window_rect, event_co[0], event_co[1]);
2486 if (actedge == nullptr) {
2487 return OPERATOR_CANCELLED;
2488 }
2489
2491
2492 RNA_property_enum_set(op->ptr, prop_dir, dir_axis);
2493
2494 /* special case, adds customdata, sets defaults */
2495 if (!area_split_menu_init(C, op)) {
2496 return OPERATOR_CANCELLED;
2497 }
2498 }
2499
2501
2502 if (event->type == EVT_ACTIONZONE_AREA) {
2503 /* do the split */
2504 if (area_split_apply(C, op)) {
2505 area_move_set_limits(win, screen, dir_axis, &sd->bigger, &sd->smaller, nullptr);
2506
2507 /* add temp handler for edge move or cancel */
2508 G.moving |= G_TRANSFORM_WM;
2510
2512 }
2513 }
2514 else {
2515 sd->previewmode = 1;
2517 /* add temp handler for edge move or cancel */
2520
2522 }
2523
2524 return OPERATOR_PASS_THROUGH;
2525}
2526
2527/* function to be called outside UI context, or for redo */
2529{
2530 if (!area_split_init(C, op)) {
2531 return OPERATOR_CANCELLED;
2532 }
2533
2534 area_split_apply(C, op);
2535 area_split_exit(C, op);
2536
2537 return OPERATOR_FINISHED;
2538}
2539
2541{
2543
2544 if (sd->previewmode) {
2545 /* pass */
2546 }
2547 else {
2548 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
2549 if (CTX_wm_area(C) == sd->narea) {
2550 CTX_wm_area_set(C, nullptr);
2551 CTX_wm_region_set(C, nullptr);
2552 }
2553 sd->narea = nullptr;
2554 }
2555 }
2556 area_split_exit(C, op);
2557}
2558
2559static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
2560{
2562 PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction");
2563 bool update_factor = false;
2564
2565 /* execute the events */
2566 switch (event->type) {
2567 case MOUSEMOVE:
2568 update_factor = true;
2569 break;
2570
2571 case LEFTMOUSE:
2572 if (sd->previewmode) {
2573 area_split_apply(C, op);
2574 area_split_exit(C, op);
2575 return OPERATOR_FINISHED;
2576 }
2577 else {
2578 if (event->val == KM_RELEASE) { /* mouse up */
2579 area_split_exit(C, op);
2580 return OPERATOR_FINISHED;
2581 }
2582 }
2583 break;
2584
2585 case MIDDLEMOUSE:
2586 case EVT_TABKEY:
2587 if (sd->previewmode == 0) {
2588 /* pass */
2589 }
2590 else {
2591 if (event->val == KM_PRESS) {
2592 if (sd->sarea) {
2593 const eScreenAxis dir_axis = eScreenAxis(RNA_property_enum_get(op->ptr, prop_dir));
2595 op->ptr, prop_dir, (dir_axis == SCREEN_AXIS_V) ? SCREEN_AXIS_H : SCREEN_AXIS_V);
2597 update_factor = true;
2598 }
2599 }
2600 }
2601
2602 break;
2603
2604 case RIGHTMOUSE: /* cancel operation */
2605 case EVT_ESCKEY:
2606 area_split_cancel(C, op);
2607 return OPERATOR_CANCELLED;
2608
2609 case EVT_LEFTCTRLKEY:
2610 case EVT_RIGHTCTRLKEY:
2611 sd->do_snap = event->val == KM_PRESS;
2612 update_factor = true;
2613 break;
2614 }
2615
2616 if (update_factor) {
2617 const eScreenAxis dir_axis = eScreenAxis(RNA_property_enum_get(op->ptr, prop_dir));
2618
2619 sd->delta = (dir_axis == SCREEN_AXIS_V) ? event->xy[0] - sd->origval :
2620 event->xy[1] - sd->origval;
2621
2622 if (sd->previewmode == 0) {
2623 if (sd->do_snap) {
2624 const int snap_loc = area_snap_calc_location(CTX_wm_screen(C),
2626 sd->delta,
2627 sd->origval,
2628 dir_axis,
2629 sd->bigger,
2630 sd->smaller);
2631 sd->delta = snap_loc - sd->origval;
2633 sd->delta,
2634 sd->origval,
2635 dir_axis,
2636 sd->bigger,
2637 sd->smaller,
2639 }
2640 else {
2642 C, sd->delta, sd->origval, dir_axis, sd->bigger, sd->smaller, SNAP_NONE);
2643 }
2644 }
2645 else {
2646 if (sd->sarea) {
2648 }
2649
2651
2652 /* area context not set */
2654
2655 if (sd->sarea) {
2656 ScrArea *area = sd->sarea;
2657 if (dir_axis == SCREEN_AXIS_V) {
2658 sd->origmin = area->v1->vec.x;
2659 sd->origsize = area->v4->vec.x - sd->origmin;
2660 }
2661 else {
2662 sd->origmin = area->v1->vec.y;
2663 sd->origsize = area->v2->vec.y - sd->origmin;
2664 }
2665
2666 if (sd->do_snap) {
2667 area->v1->editflag = area->v2->editflag = area->v3->editflag = area->v4->editflag = 1;
2668
2669 const int snap_loc = area_snap_calc_location(CTX_wm_screen(C),
2671 sd->delta,
2672 sd->origval,
2673 dir_axis,
2674 sd->origmin + sd->origsize,
2675 -sd->origmin);
2676
2677 area->v1->editflag = area->v2->editflag = area->v3->editflag = area->v4->editflag = 0;
2678 sd->delta = snap_loc - sd->origval;
2679 }
2680
2682 }
2683
2684 CTX_wm_screen(C)->do_draw = true;
2685 }
2686
2687 float fac = float(sd->delta + sd->origval - sd->origmin) / sd->origsize;
2688 RNA_float_set(op->ptr, "factor", fac);
2689 }
2690
2692}
2693
2695 {SCREEN_AXIS_H, "HORIZONTAL", 0, "Horizontal", ""},
2696 {SCREEN_AXIS_V, "VERTICAL", 0, "Vertical", ""},
2697 {0, nullptr, 0, nullptr, nullptr},
2698};
2699
2701{
2702 ot->name = "Split Area";
2703 ot->description = "Split selected area into new windows";
2704 ot->idname = "SCREEN_OT_area_split";
2705
2706 ot->exec = area_split_exec;
2707 ot->invoke = area_split_invoke;
2708 ot->modal = area_split_modal;
2709 ot->cancel = area_split_cancel;
2710
2711 ot->poll = screen_active_editable;
2712
2713 /* flags */
2715
2716 /* rna */
2717 RNA_def_enum(ot->srna, "direction", prop_direction_items, SCREEN_AXIS_H, "Direction", "");
2718 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
2720 ot->srna, "cursor", 2, nullptr, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX);
2721}
2722
2724
2725/* -------------------------------------------------------------------- */
2728
2738
2739static int area_max_regionsize(ScrArea *area, ARegion *scale_region, AZEdge edge)
2740{
2741 int dist;
2742
2743 /* regions in regions. */
2744 if (scale_region->alignment & RGN_SPLIT_PREV) {
2745 const int align = RGN_ALIGN_ENUM_FROM_MASK(scale_region->alignment);
2746
2747 if (ELEM(align, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
2748 ARegion *region = scale_region->prev;
2749 dist = region->winy + scale_region->winy - U.pixelsize;
2750 }
2751 else /* if (ELEM(align, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) */ {
2752 ARegion *region = scale_region->prev;
2753 dist = region->winx + scale_region->winx - U.pixelsize;
2754 }
2755 }
2756 else {
2758 dist = BLI_rcti_size_x(&area->totrct);
2759 }
2760 else { /* AE_BOTTOM_TO_TOPLEFT, AE_TOP_TO_BOTTOMRIGHT */
2761 dist = BLI_rcti_size_y(&area->totrct);
2762 }
2763
2764 /* Subtract the width of regions on opposite side
2765 * prevents dragging regions into other opposite regions. */
2766 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2767 if (region == scale_region) {
2768 continue;
2769 }
2770
2771 if (scale_region->alignment == RGN_ALIGN_LEFT && region->alignment == RGN_ALIGN_RIGHT) {
2772 dist -= region->winx;
2773 }
2774 else if (scale_region->alignment == RGN_ALIGN_RIGHT && region->alignment == RGN_ALIGN_LEFT) {
2775 dist -= region->winx;
2776 }
2777 else if (scale_region->alignment == RGN_ALIGN_TOP &&
2778 (region->alignment == RGN_ALIGN_BOTTOM || ELEM(region->regiontype,
2783 {
2784 dist -= region->winy;
2785 }
2786 else if (scale_region->alignment == RGN_ALIGN_BOTTOM &&
2787 (region->alignment == RGN_ALIGN_TOP || ELEM(region->regiontype,
2792 {
2793 dist -= region->winy;
2794 }
2795 }
2796 }
2797
2798 dist /= UI_SCALE_FAC;
2799 return dist;
2800}
2801
2802static bool is_split_edge(const int alignment, const AZEdge edge)
2803{
2804 return ((alignment == RGN_ALIGN_BOTTOM) && (edge == AE_TOP_TO_BOTTOMRIGHT)) ||
2805 ((alignment == RGN_ALIGN_TOP) && (edge == AE_BOTTOM_TO_TOPLEFT)) ||
2806 ((alignment == RGN_ALIGN_LEFT) && (edge == AE_RIGHT_TO_TOPLEFT)) ||
2807 ((alignment == RGN_ALIGN_RIGHT) && (edge == AE_LEFT_TO_TOPRIGHT));
2808}
2809
2811{
2812 MEM_freeN(op->customdata);
2813 op->customdata = nullptr;
2814
2815 G.moving &= ~G_TRANSFORM_WM;
2816}
2817
2818static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2819{
2820 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
2821
2822 if (event->type != EVT_ACTIONZONE_REGION) {
2823 BKE_report(op->reports, RPT_ERROR, "Can only scale region size from an action zone");
2824 return OPERATOR_CANCELLED;
2825 }
2826
2827 AZone *az = sad->az;
2828
2829 if (az->region) {
2830 RegionMoveData *rmd = static_cast<RegionMoveData *>(
2831 MEM_callocN(sizeof(RegionMoveData), "RegionMoveData"));
2832
2833 op->customdata = rmd;
2834
2835 rmd->az = az;
2836 /* special case for region within region - this allows the scale of
2837 * the parent region if the azone edge is not the edge splitting
2838 * both regions */
2839 if ((az->region->alignment & RGN_SPLIT_PREV) && az->region->prev &&
2841 {
2842 rmd->region = az->region->prev;
2843 }
2844 /* Flag to always forward scaling to the previous region. */
2845 else if (az->region->prev && (az->region->alignment & RGN_SPLIT_SCALE_PREV)) {
2846 rmd->region = az->region->prev;
2847 }
2848 else {
2849 rmd->region = az->region;
2850 }
2851 rmd->area = sad->sa1;
2852 rmd->edge = az->edge;
2853 copy_v2_v2_int(rmd->orig_xy, event->xy);
2854 rmd->maxsize = area_max_regionsize(rmd->area, rmd->region, rmd->edge);
2855
2856 /* if not set we do now, otherwise it uses type */
2857 if (rmd->region->sizex == 0) {
2858 rmd->region->sizex = rmd->region->winx;
2859 }
2860 if (rmd->region->sizey == 0) {
2861 rmd->region->sizey = rmd->region->winy;
2862 }
2863
2864 /* Now copy to region-move-data. */
2866 rmd->origval = rmd->region->sizex;
2867 }
2868 else {
2869 rmd->origval = rmd->region->sizey;
2870 }
2871
2872 CLAMP(rmd->maxsize, 0, 1000);
2873
2874 /* add temp handler */
2875 G.moving |= G_TRANSFORM_WM;
2877
2879 }
2880
2881 return OPERATOR_FINISHED;
2882}
2883
2885{
2886 if ((rmd->region->flag & RGN_FLAG_HIDDEN) == 0) {
2887 short *size, maxsize = -1;
2888
2890 size = &rmd->region->sizex;
2891 }
2892 else {
2893 size = &rmd->region->sizey;
2894 }
2895
2896 maxsize = rmd->maxsize - (UI_UNIT_Y / UI_SCALE_FAC);
2897
2898 if (*size > maxsize && maxsize > 0) {
2899 *size = maxsize;
2900 }
2901 }
2902}
2903
2905{
2906 /* hidden areas may have bad 'View2D.cur' value,
2907 * correct before displaying. see #45156 */
2908 if (rmd->region->flag & RGN_FLAG_HIDDEN) {
2910 }
2911
2912 region_toggle_hidden(C, rmd->region, false);
2914
2915 if ((rmd->region->flag & RGN_FLAG_HIDDEN) == 0) {
2916 if (rmd->region->regiontype == RGN_TYPE_HEADER) {
2917 ARegion *region_tool_header = BKE_area_find_region_type(rmd->area, RGN_TYPE_TOOL_HEADER);
2918 if (region_tool_header != nullptr) {
2919 if ((region_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER) == 0 &&
2920 (region_tool_header->flag & RGN_FLAG_HIDDEN) != 0)
2921 {
2922 region_toggle_hidden(C, region_tool_header, false);
2923 }
2924 }
2925 }
2926 }
2927}
2928
2929static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
2930{
2931 RegionMoveData *rmd = static_cast<RegionMoveData *>(op->customdata);
2932 int delta;
2933
2934 /* execute the events */
2935 switch (event->type) {
2936 case MOUSEMOVE: {
2937 const float aspect = (rmd->region->v2d.flag & V2D_IS_INIT) ?
2938 (BLI_rctf_size_x(&rmd->region->v2d.cur) /
2939 (BLI_rcti_size_x(&rmd->region->v2d.mask) + 1)) :
2940 1.0f;
2941 const int snap_size_threshold = (U.widget_unit * 2) / aspect;
2942 bool size_changed = false;
2943
2945 delta = event->xy[0] - rmd->orig_xy[0];
2946 if (rmd->edge == AE_LEFT_TO_TOPRIGHT) {
2947 delta = -delta;
2948 }
2949
2950 /* region sizes now get multiplied */
2951 delta /= UI_SCALE_FAC;
2952
2953 const int size_no_snap = rmd->origval + delta;
2954 rmd->region->sizex = size_no_snap;
2955 /* Clamp before snapping, so the snapping doesn't use a size that's invalid anyway. It will
2956 * check for and respect the max-width too. */
2957 CLAMP(rmd->region->sizex, 0, rmd->maxsize);
2958
2959 if (rmd->region->type->snap_size) {
2960 short sizex_test = rmd->region->type->snap_size(rmd->region, rmd->region->sizex, 0);
2961 if ((abs(rmd->region->sizex - sizex_test) < snap_size_threshold) &&
2962 /* Don't snap to a new size if that would exceed the maximum width. */
2963 sizex_test <= rmd->maxsize)
2964 {
2965 rmd->region->sizex = sizex_test;
2966 }
2967 }
2968 BLI_assert(rmd->region->sizex <= rmd->maxsize);
2969
2970 if (size_no_snap < UI_UNIT_X / aspect) {
2971 rmd->region->sizex = rmd->origval;
2972 if (!(rmd->region->flag & RGN_FLAG_HIDDEN)) {
2974 }
2975 }
2976 else if (rmd->region->flag & RGN_FLAG_HIDDEN) {
2978 }
2979
2980 /* Hiding/unhiding is handled above, but still fix the size as requested. */
2981 if (rmd->region->flag & RGN_FLAG_NO_USER_RESIZE) {
2982 rmd->region->sizex = rmd->origval;
2983 }
2984
2985 if (rmd->region->sizex != rmd->origval) {
2986 size_changed = true;
2987 }
2988 }
2989 else {
2990 delta = event->xy[1] - rmd->orig_xy[1];
2991 if (rmd->edge == AE_BOTTOM_TO_TOPLEFT) {
2992 delta = -delta;
2993 }
2994
2995 /* region sizes now get multiplied */
2996 delta /= UI_SCALE_FAC;
2997
2998 const int size_no_snap = rmd->origval + delta;
2999 rmd->region->sizey = size_no_snap;
3000 /* Clamp before snapping, so the snapping doesn't use a size that's invalid anyway. It will
3001 * check for and respect the max-height too. */
3002 CLAMP(rmd->region->sizey, 0, rmd->maxsize);
3003
3004 if (rmd->region->type->snap_size) {
3005 short sizey_test = rmd->region->type->snap_size(rmd->region, rmd->region->sizey, 1);
3006 if ((abs(rmd->region->sizey - sizey_test) < snap_size_threshold) &&
3007 /* Don't snap to a new size if that would exceed the maximum height. */
3008 (sizey_test <= rmd->maxsize))
3009 {
3010 rmd->region->sizey = sizey_test;
3011 }
3012 }
3013 BLI_assert(rmd->region->sizey <= rmd->maxsize);
3014
3015 /* NOTE: `UI_UNIT_Y / 4` means you need to drag the footer and execute region
3016 * almost all the way down for it to become hidden, this is done
3017 * otherwise its too easy to do this by accident. */
3018 if (size_no_snap < (UI_UNIT_Y / 4) / aspect) {
3019 rmd->region->sizey = rmd->origval;
3020 if (!(rmd->region->flag & RGN_FLAG_HIDDEN)) {
3022 }
3023 }
3024 else if (rmd->region->flag & RGN_FLAG_HIDDEN) {
3026 }
3027
3028 /* Hiding/unhiding is handled above, but still fix the size as requested. */
3029 if (rmd->region->flag & RGN_FLAG_NO_USER_RESIZE) {
3030 rmd->region->sizey = rmd->origval;
3031 }
3032
3033 if (rmd->region->sizey != rmd->origval) {
3034 size_changed = true;
3035 }
3036 }
3037 if (size_changed && rmd->region->type->on_user_resize) {
3038 rmd->region->type->on_user_resize(rmd->region);
3039 }
3042
3043 break;
3044 }
3045 case LEFTMOUSE:
3046 if (event->val == KM_RELEASE) {
3048 if (rmd->region->flag & RGN_FLAG_HIDDEN) {
3050 }
3051 else if (rmd->region->flag & RGN_FLAG_TOO_SMALL) {
3053 }
3054
3057 }
3058
3060
3061 return OPERATOR_FINISHED;
3062 }
3063 break;
3064
3065 case EVT_ESCKEY:
3066 break;
3067 }
3068
3070}
3071
3072static void region_scale_cancel(bContext * /*C*/, wmOperator *op)
3073{
3075}
3076
3078{
3079 /* identifiers */
3080 ot->name = "Scale Region Size";
3081 ot->description = "Scale selected area";
3082 ot->idname = "SCREEN_OT_region_scale";
3083
3084 ot->invoke = region_scale_invoke;
3085 ot->modal = region_scale_modal;
3086 ot->cancel = region_scale_cancel;
3087
3088 ot->poll = ED_operator_areaactive;
3089
3090 /* flags */
3092}
3093
3095
3096/* -------------------------------------------------------------------- */
3099
3101 eRegion_Type regiontype)
3102{
3103 return (regiontype == RGN_TYPE_WINDOW &&
3105 (spacetype == SPACE_CLIP && regiontype == RGN_TYPE_PREVIEW);
3106}
3107
3108static void areas_do_frame_follow(bContext *C, bool middle)
3109{
3110 bScreen *screen_ctx = CTX_wm_screen(C);
3111 Scene *scene = CTX_data_scene(C);
3113 LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
3114 const bScreen *screen = WM_window_get_active_screen(window);
3115
3116 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
3117 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3118 /* do follow here if editor type supports it */
3119 if ((screen_ctx->redraws_flag & TIME_FOLLOW) &&
3121 eRegion_Type(region->regiontype)))
3122 {
3123 float w = BLI_rctf_size_x(&region->v2d.cur);
3124
3125 if (middle) {
3126 if ((scene->r.cfra < region->v2d.cur.xmin) || (scene->r.cfra > region->v2d.cur.xmax)) {
3127 region->v2d.cur.xmax = scene->r.cfra + (w / 2);
3128 region->v2d.cur.xmin = scene->r.cfra - (w / 2);
3129 }
3130 }
3131 else {
3132 if (scene->r.cfra < region->v2d.cur.xmin) {
3133 region->v2d.cur.xmax = scene->r.cfra;
3134 region->v2d.cur.xmin = region->v2d.cur.xmax - w;
3135 }
3136 else if (scene->r.cfra > region->v2d.cur.xmax) {
3137 region->v2d.cur.xmin = scene->r.cfra;
3138 region->v2d.cur.xmax = region->v2d.cur.xmin + w;
3139 }
3140 }
3141 }
3142 }
3143 }
3144 }
3145}
3146
3147/* function to be called outside UI context, or for redo */
3149{
3150 Scene *scene = CTX_data_scene(C);
3151
3152 int delta = RNA_int_get(op->ptr, "delta");
3153
3154 /* In order to jump from e.g. 1.5 to 1 the delta needs to be incremented by 1 since the sub-frame
3155 * is always zeroed. Otherwise it would jump to 0. */
3156 if (delta < 0 && scene->r.subframe > 0) {
3157 delta += 1;
3158 }
3159 scene->r.cfra += delta;
3161 scene->r.subframe = 0.0f;
3162
3163 areas_do_frame_follow(C, false);
3164
3166
3168
3169 return OPERATOR_FINISHED;
3170}
3171
3173{
3174 ot->name = "Frame Offset";
3175 ot->idname = "SCREEN_OT_frame_offset";
3176 ot->description = "Move current frame forward/backward by a given number";
3177
3178 ot->exec = frame_offset_exec;
3179
3181 ot->flag = OPTYPE_UNDO_GROUPED;
3182 ot->undo_group = "Frame Change";
3183
3184 /* rna */
3185 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
3186}
3187
3189
3190/* -------------------------------------------------------------------- */
3193
3194/* function to be called outside UI context, or for redo */
3196{
3197 Scene *scene = CTX_data_scene(C);
3198 wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
3199
3200 /* Don't change scene->r.cfra directly if animtimer is running as this can cause
3201 * first/last frame not to be actually shown (bad since for example physics
3202 * simulations aren't reset properly).
3203 */
3204 if (animtimer) {
3205 ScreenAnimData *sad = static_cast<ScreenAnimData *>(animtimer->customdata);
3206
3208
3209 if (RNA_boolean_get(op->ptr, "end")) {
3210 sad->nextfra = PEFRA;
3211 }
3212 else {
3213 sad->nextfra = PSFRA;
3214 }
3215 }
3216 else {
3217 if (RNA_boolean_get(op->ptr, "end")) {
3218 scene->r.cfra = PEFRA;
3219 }
3220 else {
3221 scene->r.cfra = PSFRA;
3222 }
3223
3224 areas_do_frame_follow(C, true);
3225
3227
3229 }
3230
3231 return OPERATOR_FINISHED;
3232}
3233
3235{
3236 ot->name = "Jump to Endpoint";
3237 ot->description = "Jump to first/last frame in frame range";
3238 ot->idname = "SCREEN_OT_frame_jump";
3239
3240 ot->exec = frame_jump_exec;
3241
3243 ot->flag = OPTYPE_UNDO_GROUPED;
3244 ot->undo_group = "Frame Change";
3245
3246 /* rna */
3248 ot->srna, "end", false, "Last Frame", "Jump to the last frame of the frame range");
3249}
3250
3252
3253/* -------------------------------------------------------------------- */
3256
3257/* function to be called outside UI context, or for redo */
3259{
3260 Scene *scene = CTX_data_scene(C);
3262 bDopeSheet ads = {nullptr};
3263 const bool next = RNA_boolean_get(op->ptr, "next");
3264 bool done = false;
3265
3266 /* sanity checks */
3267 if (scene == nullptr) {
3268 return OPERATOR_CANCELLED;
3269 }
3270
3271 const float cfra = BKE_scene_frame_get(scene);
3272
3273 /* Initialize binary-tree-list for getting keyframes. */
3274 AnimKeylist *keylist = ED_keylist_create();
3275
3276 /* Speed up dummy dope-sheet context with flags to perform necessary filtering. */
3277 if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
3278 /* Only selected channels are included. */
3280 }
3281
3282 /* populate tree with keyframe nodes */
3283 scene_to_keylist(&ads, scene, keylist, 0, {-FLT_MAX, FLT_MAX});
3284
3285 if (ob) {
3286 ob_to_keylist(&ads, ob, keylist, 0, {-FLT_MAX, FLT_MAX});
3287
3288 if (ob->type == OB_GPENCIL_LEGACY) {
3289 const bool active = !(scene->flag & SCE_KEYS_NO_SELONLY);
3290 gpencil_to_keylist(&ads, static_cast<bGPdata *>(ob->data), keylist, active);
3291 }
3292
3293 if (ob->type == OB_GREASE_PENCIL) {
3294 const bool active_layer_only = !(scene->flag & SCE_KEYS_NO_SELONLY);
3296 nullptr, static_cast<const GreasePencil *>(ob->data), keylist, 0, active_layer_only);
3297 }
3298 }
3299
3300 {
3302 if (mask) {
3304 mask_to_keylist(&ads, masklay, keylist);
3305 }
3306 }
3308
3309 /* find matching keyframe in the right direction */
3310 const ActKeyColumn *ak;
3311
3312 if (next) {
3313 ak = ED_keylist_find_next(keylist, cfra);
3314 while ((ak != nullptr) && (done == false)) {
3315 if (cfra < ak->cfra) {
3316 BKE_scene_frame_set(scene, ak->cfra);
3317 done = true;
3318 }
3319 else {
3320 ak = ak->next;
3321 }
3322 }
3323 }
3324
3325 else {
3326 ak = ED_keylist_find_prev(keylist, cfra);
3327 while ((ak != nullptr) && (done == false)) {
3328 if (cfra > ak->cfra) {
3329 BKE_scene_frame_set(scene, ak->cfra);
3330 done = true;
3331 }
3332 else {
3333 ak = ak->prev;
3334 }
3335 }
3336 }
3337
3338 /* free temp stuff */
3339 ED_keylist_free(keylist);
3340
3341 /* any success? */
3342 if (done == false) {
3343 BKE_report(op->reports, RPT_INFO, "No more keyframes to jump to in this direction");
3344
3345 return OPERATOR_CANCELLED;
3346 }
3347
3348 areas_do_frame_follow(C, true);
3349
3351
3353
3354 return OPERATOR_FINISHED;
3355}
3356
3358{
3359 /* There is a keyframe jump operator specifically for the Graph Editor. */
3361}
3362
3364{
3365 ot->name = "Jump to Keyframe";
3366 ot->description = "Jump to previous/next keyframe";
3367 ot->idname = "SCREEN_OT_keyframe_jump";
3368
3369 ot->exec = keyframe_jump_exec;
3370
3371 ot->poll = keyframe_jump_poll;
3372 ot->flag = OPTYPE_UNDO_GROUPED;
3373 ot->undo_group = "Frame Change";
3374
3375 /* properties */
3376 RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
3377}
3378
3380
3381/* -------------------------------------------------------------------- */
3384
3385/* function to be called outside UI context, or for redo */
3387{
3388 Scene *scene = CTX_data_scene(C);
3389 int closest = scene->r.cfra;
3390 const bool next = RNA_boolean_get(op->ptr, "next");
3391 bool found = false;
3392
3393 /* find matching marker in the right direction */
3394 LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
3395 if (next) {
3396 if ((marker->frame > scene->r.cfra) && (!found || closest > marker->frame)) {
3397 closest = marker->frame;
3398 found = true;
3399 }
3400 }
3401 else {
3402 if ((marker->frame < scene->r.cfra) && (!found || closest < marker->frame)) {
3403 closest = marker->frame;
3404 found = true;
3405 }
3406 }
3407 }
3408
3409 /* any success? */
3410 if (!found) {
3411 BKE_report(op->reports, RPT_INFO, "No more markers to jump to in this direction");
3412
3413 return OPERATOR_CANCELLED;
3414 }
3415
3416 scene->r.cfra = closest;
3417
3418 areas_do_frame_follow(C, true);
3419
3421
3423
3424 return OPERATOR_FINISHED;
3425}
3426
3428{
3429 ot->name = "Jump to Marker";
3430 ot->description = "Jump to previous/next marker";
3431 ot->idname = "SCREEN_OT_marker_jump";
3432
3433 ot->exec = marker_jump_exec;
3434
3436 ot->flag = OPTYPE_UNDO_GROUPED;
3437 ot->undo_group = "Frame Change";
3438
3439 /* properties */
3440 RNA_def_boolean(ot->srna, "next", true, "Next Marker", "");
3441}
3442
3444
3445/* -------------------------------------------------------------------- */
3448
3449/* function to be called outside UI context, or for redo */
3451{
3452 WorkSpace *workspace = CTX_wm_workspace(C);
3453 int delta = RNA_int_get(op->ptr, "delta");
3454
3455 if (ED_workspace_layout_cycle(workspace, delta, C)) {
3456 return OPERATOR_FINISHED;
3457 }
3458
3459 return OPERATOR_CANCELLED;
3460}
3461
3463{
3464 ot->name = "Set Screen";
3465 ot->description = "Cycle through available screens";
3466 ot->idname = "SCREEN_OT_screen_set";
3467
3468 ot->exec = screen_set_exec;
3470
3471 /* rna */
3472 RNA_def_int(ot->srna, "delta", 1, -1, 1, "Delta", "", -1, 1);
3473}
3474
3476
3477/* -------------------------------------------------------------------- */
3480
3481/* function to be called outside UI context, or for redo */
3483{
3484 bScreen *screen = CTX_wm_screen(C);
3485 ScrArea *area = nullptr;
3486 const bool hide_panels = RNA_boolean_get(op->ptr, "use_hide_panels");
3487
3488 BLI_assert(!screen->temp);
3489
3490 /* search current screen for 'full-screen' areas */
3491 /* prevents restoring info header, when mouse is over it */
3492 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
3493 if (area_iter->full) {
3494 area = area_iter;
3495 break;
3496 }
3497 }
3498
3499 if (area == nullptr) {
3500 area = CTX_wm_area(C);
3501 }
3502
3503 if (hide_panels) {
3504 if (!ELEM(screen->state, SCREENNORMAL, SCREENFULL)) {
3505 return OPERATOR_CANCELLED;
3506 }
3508 }
3509 else {
3510 if (!ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
3511 return OPERATOR_CANCELLED;
3512 }
3514 }
3515
3516 return OPERATOR_FINISHED;
3517}
3518
3520{
3521 const wmWindow *win = CTX_wm_window(C);
3522 const bScreen *screen = CTX_wm_screen(C);
3523 const ScrArea *area = CTX_wm_area(C);
3524 const wmWindowManager *wm = CTX_wm_manager(C);
3525 return ED_operator_areaactive(C) &&
3526 /* Don't allow maximizing global areas but allow minimizing from them. */
3527 ((screen->state != SCREENNORMAL) || !ED_area_is_global(area)) &&
3528 /* Don't change temporary screens. */
3530 /* Don't maximize when dragging. */
3532}
3533
3535{
3536 PropertyRNA *prop;
3537
3538 ot->name = "Toggle Maximize Area";
3539 ot->description = "Toggle display selected area as fullscreen/maximized";
3540 ot->idname = "SCREEN_OT_screen_full_area";
3541
3544 ot->flag = 0;
3545
3546 prop = RNA_def_boolean(ot->srna, "use_hide_panels", false, "Hide Panels", "Hide all the panels");
3548}
3549
3551
3552/* -------------------------------------------------------------------- */
3555
3556/* operator state vars used:
3557 * x1, y1 mouse coord in first area, which will disappear
3558 * x2, y2 mouse coord in 2nd area, which will become joined
3559 *
3560 * functions:
3561 *
3562 * init() find edge based on state vars
3563 * test if the edge divides two areas,
3564 * store active and nonactive area,
3565 *
3566 * apply() do the actual join
3567 *
3568 * exit() cleanup, send notifier
3569 *
3570 * callbacks:
3571 *
3572 * exec() calls init, apply, exit
3573 *
3574 * invoke() sets mouse coords in x,y
3575 * call init()
3576 * add modal handler
3577 *
3578 * modal() accept modal events while doing it
3579 * call apply() with active window and nonactive window
3580 * call exit() and remove handler when LMB confirm
3581 */
3582
3584 ScrArea *sa1; /* Potential source area (kept). */
3585 ScrArea *sa2; /* Potential target area (removed or reduced). */
3586 eScreenDir dir; /* Direction of potential join. */
3587 eScreenAxis split_dir; /* Direction of split within the source area. */
3588 AreaDockTarget dock_target; /* Position within target we are pointing to. */
3589 float factor; /* dock target size can vary. */
3590 int start_x, start_y; /* Starting mouse position. */
3591 int current_x, current_y; /* Current mouse position. */
3592 float split_fac; /* Split factor in split_dir direction. */
3593 wmWindow *win1; /* Window of source area. */
3594 wmWindow *win2; /* Window of the target area. */
3595 wmWindow *draw_dock_win; /* Window getting docking highlight. */
3596 bool close_win; /* Close the source window when done. */
3597 void *draw_callback; /* call #screen_draw_join_highlight */
3598 void *draw_dock_callback; /* call #screen_draw_dock_highlight, overlay on draw_dock_win. */
3599};
3600
3601static void area_join_draw_cb(const wmWindow *win, void *userdata)
3602{
3603 const wmOperator *op = static_cast<const wmOperator *>(userdata);
3604 sAreaJoinData *sd = static_cast<sAreaJoinData *>(op->customdata);
3605 if (!sd || !sd->sa1) {
3606 return;
3607 }
3608
3609 if (sd->sa1 == sd->sa2) {
3611 }
3612 else {
3613 screen_draw_join_highlight(win, sd->sa1, sd->sa2, sd->dir);
3614 }
3615}
3616
3617static void area_join_dock_cb(const wmWindow * /*win*/, void *userdata)
3618{
3619 const wmOperator *op = static_cast<wmOperator *>(userdata);
3620 sAreaJoinData *jd = static_cast<sAreaJoinData *>(op->customdata);
3621 if (!jd || !jd->sa2 || jd->dir != SCREEN_DIR_NONE || jd->sa1 == jd->sa2) {
3622 return;
3623 }
3625 jd->sa1, jd->sa2, jd->dock_target, jd->factor, jd->current_x, jd->current_y);
3626}
3627
3629{
3630 if (jd->sa2 && jd->win2 && jd->win2 != jd->draw_dock_win) {
3631 /* Change of highlight window. */
3632 if (jd->draw_dock_callback) {
3634 /* Refresh the entire window. */
3637 {
3638 ED_area_tag_redraw(area);
3639 }
3640 }
3641 if (jd->win2) {
3642 jd->draw_dock_win = jd->win2;
3644 }
3645 }
3646}
3647
3648/* validate selection inside screen, set variables OK */
3649/* return false: init failed */
3650static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *sa2)
3651{
3652 if (sa1 == nullptr && sa2 == nullptr) {
3653 /* Get areas from cursor location if not specified. */
3654 PropertyRNA *prop;
3655 int cursor[2];
3656
3657 prop = RNA_struct_find_property(op->ptr, "source_xy");
3658 if (RNA_property_is_set(op->ptr, prop)) {
3659 RNA_property_int_get_array(op->ptr, prop, cursor);
3661 }
3662
3663 prop = RNA_struct_find_property(op->ptr, "target_xy");
3664 if (RNA_property_is_set(op->ptr, prop)) {
3665 RNA_property_int_get_array(op->ptr, prop, cursor);
3667 }
3668 }
3669 if (sa1 == nullptr) {
3670 return false;
3671 }
3672
3673 sAreaJoinData *jd = static_cast<sAreaJoinData *>(
3674 MEM_callocN(sizeof(sAreaJoinData), "op_area_join"));
3675 jd->sa1 = sa1;
3676 jd->sa2 = sa2;
3677 jd->dir = area_getorientation(sa1, sa2);
3680
3681 op->customdata = jd;
3682 return true;
3683}
3684
3685/* apply the join of the areas (space types) */
3687{
3689 if (!jd || (jd->dir == SCREEN_DIR_NONE)) {
3690 return false;
3691 }
3692
3693 bScreen *screen = CTX_wm_screen(C);
3694
3695 if (!screen_area_join(C, screen, jd->sa1, jd->sa2)) {
3696 return false;
3697 }
3698 if (CTX_wm_area(C) == jd->sa2) {
3699 CTX_wm_area_set(C, nullptr);
3700 CTX_wm_region_set(C, nullptr);
3701 }
3702
3703 if (BLI_listbase_is_single(&screen->areabase)) {
3704 /* Areas reduced to just one, so show nicer title. */
3706 }
3707
3708 return true;
3709}
3710
3711/* finish operation */
3713{
3715
3716 if (jd) {
3717 if (jd->draw_callback) {
3719 }
3720 if (jd->draw_dock_callback) {
3722 }
3723
3724 MEM_freeN(jd);
3725 op->customdata = nullptr;
3726 }
3727
3728 /* this makes sure aligned edges will result in aligned grabbing */
3732
3733 ED_workspace_status_text(C, nullptr);
3734
3735 G.moving &= ~G_TRANSFORM_WM;
3736}
3737
3739{
3740 if (!area_join_init(C, op, nullptr, nullptr)) {
3741 return OPERATOR_CANCELLED;
3742 }
3743
3745
3746 if (jd->sa2 == nullptr || area_getorientation(jd->sa1, jd->sa2) == SCREEN_DIR_NONE) {
3747 return OPERATOR_CANCELLED;
3748 }
3749
3751
3752 area_join_apply(C, op);
3753 area_join_exit(C, op);
3755
3756 return OPERATOR_FINISHED;
3757}
3758
3759static void area_join_update_data(bContext *C, sAreaJoinData *jd, const wmEvent *event);
3760static int area_join_cursor(sAreaJoinData *jd, const wmEvent *event);
3761
3762/* interaction callback */
3763static int area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3764{
3765 if (event->type == EVT_ACTIONZONE_AREA) {
3766 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
3767
3768 if (sad == nullptr || sad->modifier > 0 || sad->sa1 == nullptr) {
3769 return OPERATOR_PASS_THROUGH;
3770 }
3771
3772 if (!area_join_init(C, op, sad->sa1, sad->sa2)) {
3773 return OPERATOR_CANCELLED;
3774 }
3775
3777 jd->start_x = sad->x;
3778 jd->start_y = sad->y;
3780
3783 }
3784
3785 /* Launched from menu item or keyboard shortcut. */
3786 if (!area_join_init(C, op, nullptr, nullptr)) {
3787 ScrArea *sa1 = CTX_wm_area(C);
3788 if (!sa1 || ED_area_is_global(sa1) || !area_join_init(C, op, sa1, nullptr)) {
3789 return OPERATOR_CANCELLED;
3790 }
3791 }
3793 jd->sa2 = jd->sa1;
3794 jd->start_x = jd->sa1->totrct.xmin;
3795 jd->start_y = jd->sa1->totrct.ymax;
3796 jd->current_x = event->xy[0];
3797 jd->current_y = event->xy[1];
3799 WM_cursor_set(jd->win1, area_join_cursor(jd, event));
3800 area_join_update_data(C, jd, event);
3805}
3806
3807/* Apply the docking of the area. */
3809{
3811
3812 int offset1;
3813 int offset2;
3814 area_getoffsets(jd->sa1, jd->sa2, area_getorientation(jd->sa1, jd->sa2), &offset1, &offset2);
3815
3816 /* Check before making changes. */
3817 bool aligned_neighbors = (offset1 == 0 && offset2 == 0);
3818 bool same_area = (jd->sa1 == jd->sa2);
3819
3820 if (!(jd->dock_target == AreaDockTarget::Center)) {
3824
3825 float fac = jd->factor;
3827 fac = 1.0f - fac;
3828 }
3829
3830 ScrArea *newa = area_split(
3831 jd->win2, WM_window_get_active_screen(jd->win2), jd->sa2, dir, fac, true);
3832
3833 if (jd->factor <= 0.5f) {
3834 jd->sa2 = newa;
3835 }
3836 else {
3837 /* Force full rebuild. #130732 */
3838 ED_area_tag_redraw(newa);
3839 }
3840 }
3841
3842 if (same_area) {
3844 return;
3845 }
3846
3847 if (!aligned_neighbors || !screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)) {
3848 ED_area_swapspace(C, jd->sa2, jd->sa1);
3851 {
3852 jd->close_win = true;
3853 }
3854 else {
3856 }
3857 }
3858
3859 if (jd && jd->sa2 == CTX_wm_area(C)) {
3860 CTX_wm_area_set(C, nullptr);
3861 CTX_wm_region_set(C, nullptr);
3862 }
3863}
3864
3865static int area_join_cursor(sAreaJoinData *jd, const wmEvent *event)
3866{
3867 if (!jd->sa2 && jd->dock_target == AreaDockTarget::None) {
3868 /* Mouse outside window, so can open new window. */
3869 if (event->xy[0] < 0 || event->xy[0] > jd->win1->sizex || event->xy[1] < 1 ||
3870 event->xy[1] > jd->win1->sizey)
3871 {
3872 return WM_CURSOR_PICK_AREA;
3873 }
3874 return WM_CURSOR_STOP;
3875 }
3876
3877 if (jd->win2 && jd->win2->workspace_hook) {
3879 if (screen && screen->temp) {
3880 return WM_CURSOR_STOP;
3881 }
3882 }
3883
3884 if (jd->sa1 && jd->sa1 == jd->sa2) {
3885 if (jd->split_fac >= 0.0001f) {
3886 /* Mouse inside source area, so allow splitting. */
3888 }
3889 return WM_CURSOR_EDIT;
3890 }
3891
3892 if (jd->dir != SCREEN_DIR_NONE || jd->dock_target != AreaDockTarget::None) {
3893#if defined(__APPLE__)
3894 return WM_CURSOR_HAND_CLOSED;
3895#else
3896 return WM_CURSOR_MOVE;
3897#endif
3898 }
3899
3900 return WM_CURSOR_PICK_AREA;
3901}
3902
3903static float area_docking_snap(const float pos, const wmEvent *event)
3904{
3905 const bool alt = event->modifier & KM_ALT;
3906 const bool ctrl = event->modifier & KM_CTRL;
3907 const float accel = (alt || ctrl) ? 2.5f : 2.0;
3908
3909 float factor = pos * accel;
3910
3911 if (!alt) {
3912 if (factor >= 0.4375f && factor < 0.5f) {
3913 factor = 0.499999f;
3914 }
3915 else if (factor >= 0.5f && factor < 0.5625f) {
3916 factor = 0.500001f;
3917 }
3918 }
3919
3920 if (ctrl) {
3921 if (factor < 0.1875f) {
3922 factor = 0.125f;
3923 }
3924 else if (factor >= 0.1875f && factor < 0.3125f) {
3925 factor = 0.25f;
3926 }
3927 else if (factor >= 0.3125f && factor < 0.4375f) {
3928 factor = 0.375f;
3929 }
3930 else if (factor >= 0.5625f && factor < 0.6875f) {
3931 factor = 0.625f;
3932 }
3933 else if (factor >= 0.6875f && factor < 0.8125f) {
3934 factor = 0.75f;
3935 }
3936 else if (factor > 0.8125f) {
3937 factor = 0.875f;
3938 }
3939 }
3940
3941 return factor;
3942}
3943
3945{
3946 if (!jd->sa2 || !jd->win2) {
3947 return AreaDockTarget::None;
3948 }
3949
3950 if (jd->sa1 == jd->sa2) {
3951 return AreaDockTarget::None;
3952 }
3953
3954 if (jd->win2 && jd->win2->workspace_hook) {
3956 if (screen && screen->temp) {
3957 return AreaDockTarget::None;
3958 }
3959 }
3960
3961 /* Convert to local coordinates in sa2. */
3962 int win1_posx = jd->win1->posx;
3963 int win1_posy = jd->win1->posy;
3964 int win2_posx = jd->win2->posx;
3965 int win2_posy = jd->win2->posy;
3966 WM_window_native_pixel_coords(jd->win1, &win1_posx, &win1_posy);
3967 WM_window_native_pixel_coords(jd->win2, &win2_posx, &win2_posy);
3968
3969 const int x = event->xy[0] + win1_posx - win2_posx - jd->sa2->totrct.xmin;
3970 const int y = event->xy[1] + win1_posy - win2_posy - jd->sa2->totrct.ymin;
3971
3972 jd->current_x = x + jd->sa2->totrct.xmin;
3973 jd->current_y = y + jd->sa2->totrct.ymin;
3974
3975 const float fac_x = float(x) / float(jd->sa2->winx);
3976 const float fac_y = float(y) / float(jd->sa2->winy);
3977 const int min_x = 2 * AREAMINX * UI_SCALE_FAC;
3978 const int min_y = 2 * HEADERY * UI_SCALE_FAC;
3979
3980 if (ELEM(jd->dir, SCREEN_DIR_N, SCREEN_DIR_S)) {
3981 /* Up or Down to immediate neighbor. */
3982 if (event->xy[0] <= jd->sa1->totrct.xmax && event->xy[0] >= jd->sa1->totrct.xmin) {
3983 const int join_y = std::min(jd->sa2->winy * 0.25f, 5 * HEADERY * UI_SCALE_FAC);
3984 if (jd->sa2->winy < min_y || (jd->dir == SCREEN_DIR_N && y < join_y) ||
3985 (jd->dir == SCREEN_DIR_S && (jd->sa2->winy - y) < join_y))
3986 {
3987 return AreaDockTarget::None;
3988 }
3989 }
3990 }
3991
3992 if (ELEM(jd->dir, SCREEN_DIR_W, SCREEN_DIR_E)) {
3993 /* Left or Right to immediate neighbor. */
3994 if (event->xy[1] <= jd->sa1->totrct.ymax && event->xy[1] >= jd->sa1->totrct.ymin) {
3995 const int join_x = std::min(jd->sa2->winx * 0.25f, 5 * AREAMINX * UI_SCALE_FAC);
3996 if (jd->sa2->winx < min_x || (jd->dir == SCREEN_DIR_W && (jd->sa2->winx - x) < join_x) ||
3997 (jd->dir == SCREEN_DIR_E && x < join_x))
3998 {
3999 return AreaDockTarget::None;
4000 }
4001 }
4002 }
4003
4004 /* If we've made it here, then there can be no joining possible. */
4005 jd->dir = SCREEN_DIR_NONE;
4006 jd->factor = 0.5f;
4007
4008 /* if the area is narrow then there are only two docking targets. */
4009 if (jd->sa2->winx < min_x) {
4010 if (fac_y > 0.4f && fac_y < 0.6f) {
4012 }
4013 if (float(y) > float(jd->sa2->winy) / 2.0f) {
4014 jd->factor = area_docking_snap(1.0f - float(y) / float(jd->sa2->winy), event);
4015 return AreaDockTarget::Top;
4016 }
4017 else {
4018 jd->factor = area_docking_snap(float(y) / float(jd->sa2->winy), event);
4020 }
4021 }
4022 if (jd->sa2->winy < min_y) {
4023 if (fac_x > 0.4f && fac_x < 0.6f) {
4025 }
4026 if (float(x) > float(jd->sa2->winx) / 2.0f) {
4027 jd->factor = area_docking_snap(1.0f - float(x) / float(jd->sa2->winx), event);
4028 return AreaDockTarget::Right;
4029 }
4030 else {
4031 jd->factor = area_docking_snap(float(x) / float(jd->sa2->winx), event);
4032 return AreaDockTarget::Left;
4033 }
4034 }
4035
4036 /* Are we in the center? But not in same area! */
4037 if (fac_x > 0.4f && fac_x < 0.6f && fac_y > 0.4f && fac_y < 0.6f) {
4039 }
4040
4041 /* Area is large enough for four docking targets. */
4042 const float area_ratio = float(jd->sa2->winx) / float(jd->sa2->winy);
4043 /* Split the area diagonally from top-right to bottom-left. */
4044 const bool upper_left = float(x) / float(y + 1) < area_ratio;
4045 /* Split the area diagonally from top-left to bottom-right. */
4046 const bool lower_left = float(x) / float(jd->sa2->winy - y + 1) < area_ratio;
4047
4048 if (upper_left && !lower_left) {
4049 jd->factor = area_docking_snap(1.0f - float(y) / float(jd->sa2->winy), event);
4050 return AreaDockTarget::Top;
4051 }
4052 if (!upper_left && lower_left) {
4053 jd->factor = area_docking_snap(float(y) / float(jd->sa2->winy), event);
4055 }
4056 if (upper_left && lower_left) {
4057 jd->factor = area_docking_snap(float(x) / float(jd->sa2->winx), event);
4058 return AreaDockTarget::Left;
4059 }
4060 if (!upper_left && !lower_left) {
4061 jd->factor = area_docking_snap(1.0f - float(x) / float(jd->sa2->winx), event);
4062 return AreaDockTarget::Right;
4063 }
4064 return AreaDockTarget::None;
4065}
4066
4067static float area_split_factor(bContext *C, sAreaJoinData *jd, const wmEvent *event)
4068{
4069 float fac = (jd->split_dir == SCREEN_AXIS_V) ?
4070 float(event->xy[0] - jd->sa1->totrct.xmin) / float(jd->sa1->winx + 1) :
4071 float(event->xy[1] - jd->sa1->totrct.ymin) / float(jd->sa1->winy + 1);
4072
4073 if (event->modifier & KM_CTRL) {
4074 /* Snapping on. */
4075
4076 /* Find nearest neighboring vertex. */
4077 const int axis = (jd->split_dir == SCREEN_AXIS_V) ? 0 : 1;
4078 int dist = INT_MAX;
4079 int loc = 0;
4080 LISTBASE_FOREACH (const ScrVert *, v1, &CTX_wm_screen(C)->vertbase) {
4081 const int v_loc = (&v1->vec.x)[axis];
4082 const int v_dist = abs(v_loc - event->xy[axis]);
4083 if (v_dist < dist) {
4084 loc = v_loc;
4085 dist = v_dist;
4086 }
4087 }
4088 float near_fac = (axis) ? float(loc - jd->sa1->totrct.ymin) / float(jd->sa1->winy + 1) :
4089 float(loc - jd->sa1->totrct.xmin) / float(jd->sa1->winx + 1);
4090
4091 /* Rounded to nearest 12th. */
4092 float frac_fac = round(fac * 12.0f) / 12.0f;
4093
4094 /* Use nearest neighbor or fractional, whichever is closest. */
4095 fac = (fabs(near_fac - fac) < fabs(frac_fac - fac)) ? near_fac : frac_fac;
4096 }
4097
4098 return std::clamp(fac, 0.001f, 0.999f);
4099}
4100
4101static void area_join_update_data(bContext *C, sAreaJoinData *jd, const wmEvent *event)
4102{
4103 ScrArea *area = nullptr;
4104
4105 /* TODO: The following is needed until we have linux-specific implementations of
4106 * getWindowUnderCursor. See #130242. Use active window if there are overlapping. */
4107
4108#if (OS_WINDOWS || OS_MAC)
4110#else
4111 int win_count = 0;
4112 LISTBASE_FOREACH (wmWindow *, win, &CTX_wm_manager(C)->windows) {
4113 int cursor[2];
4114 if (wm_cursor_position_get(win, &cursor[0], &cursor[1])) {
4115 rcti rect;
4116 WM_window_rect_calc(win, &rect);
4117 if (BLI_rcti_isect_pt_v(&rect, cursor)) {
4118 win_count++;
4119 }
4120 }
4121 }
4122
4123 if (win_count > 1) {
4125 }
4126 else {
4128 }
4129#endif
4130
4132 jd->dir = SCREEN_DIR_NONE;
4134 jd->dir = area_getorientation(jd->sa1, jd->sa2);
4135 jd->dock_target = area_docking_target(jd, event);
4136
4137 if (jd->sa1 == area) {
4138 jd->sa2 = area;
4139 if (!(abs(jd->start_x - event->xy[0]) > (10 * U.pixelsize) ||
4140 abs(jd->start_y - event->xy[1]) > (10 * U.pixelsize)))
4141 {
4142 /* We haven't moved enough to start a split. */
4143 jd->dir = SCREEN_DIR_NONE;
4145 return;
4146 }
4147
4148 jd->split_dir = (abs(event->xy[0] - jd->start_x) > abs(event->xy[1] - jd->start_y)) ?
4151 jd->split_fac = area_split_factor(C, jd, event);
4152 return;
4153 }
4154
4155 jd->sa2 = area;
4157 jd->dir = area_getorientation(jd->sa1, jd->sa2);
4158 jd->dock_target = area_docking_target(jd, event);
4159}
4160
4167
4168/* modal callback while selecting area (space) that will be removed */
4169static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
4170{
4171 if (event->type == WINDEACTIVATE) {
4172 /* This operator can close windows, which can cause it to be re-run. */
4173 area_join_exit(C, op);
4174 return OPERATOR_FINISHED;
4175 }
4176
4177 if (op->customdata == nullptr) {
4178 if (!area_join_init(C, op, nullptr, nullptr)) {
4179 return OPERATOR_CANCELLED;
4180 }
4181 }
4183 if (jd == nullptr) {
4184 return OPERATOR_CANCELLED;
4185 }
4186
4187 /* execute the events */
4188 switch (event->type) {
4189
4190 case MOUSEMOVE: {
4191 area_join_update_data(C, jd, event);
4193 WM_cursor_set(jd->win1, area_join_cursor(jd, event));
4195
4196 WorkspaceStatus status(C);
4197 if (jd->sa1 && jd->sa1 == jd->sa2) {
4198 status.item(IFACE_("Select Split"), ICON_MOUSE_LMB);
4199 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4200 status.item_bool(IFACE_("Snap"), event->modifier & KM_CTRL, ICON_EVENT_CTRL);
4201 }
4202 else {
4203 if (jd->dock_target == AreaDockTarget::None) {
4204 status.item(IFACE_("Select Area"), ICON_MOUSE_LMB);
4205 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4206 }
4207 else {
4208 status.item(IFACE_("Select Location"), ICON_MOUSE_LMB);
4209 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4210 status.item_bool(IFACE_("Precision"), event->modifier & KM_ALT, ICON_EVENT_ALT);
4211 status.item_bool(IFACE_("Snap"), event->modifier & KM_CTRL, ICON_EVENT_CTRL);
4212 }
4213 }
4214 break;
4215 }
4216 case LEFTMOUSE:
4217 if (event->val == KM_RELEASE) {
4218 area_join_update_data(C, jd, event);
4222 if (jd->sa1 && !jd->sa2) {
4223 /* Break out into new window if we are really outside the source window bounds. */
4224 if (event->xy[0] < 0 || event->xy[0] > jd->win1->sizex || event->xy[1] < 1 ||
4225 event->xy[1] > jd->win1->sizey)
4226 {
4227 /* We have to clear handlers or we get an error in wm_gizmomap_modal_get. */
4229 area_dupli_open(C, jd->sa1, blender::int2(event->xy[0], event->xy[1] - jd->sa1->winy));
4233 {
4234 /* We've pulled a single editor out of the window into empty space.
4235 * Close the source window so we don't end up with a duplicate. */
4236 jd->close_win = true;
4237 }
4238 }
4239 }
4240 }
4241 else if (jd->sa1 && jd->sa1 == jd->sa2) {
4242 /* Same area so split. */
4243 if (area_split_allowed(jd->sa1, jd->split_dir) && jd->split_fac > 0.0001) {
4244 jd->sa2 = area_split(jd->win2,
4246 jd->sa1,
4247 jd->split_dir,
4248 jd->split_fac,
4249 true);
4250
4251 const bool large_v = jd->split_dir == SCREEN_AXIS_V &&
4252 ((jd->start_x < event->xy[0] && jd->split_fac > 0.5f) ||
4253 (jd->start_x > event->xy[0] && jd->split_fac < 0.5f));
4254
4255 const bool large_h = jd->split_dir == SCREEN_AXIS_H &&
4256 ((jd->start_y < event->xy[1] && jd->split_fac > 0.5f) ||
4257 (jd->start_y > event->xy[1] && jd->split_fac < 0.5f));
4258
4259 if (large_v || large_h) {
4260 /* Swap areas to follow old behavior of new area added based on starting location. If
4261 * from above the new area is above, if from below the new area is below, etc. Note
4262 * that this preserves runtime data, unlike ED_area_swapspace. */
4263 std::swap(jd->sa1->v1, jd->sa2->v1);
4264 std::swap(jd->sa1->v2, jd->sa2->v2);
4265 std::swap(jd->sa1->v3, jd->sa2->v3);
4266 std::swap(jd->sa1->v4, jd->sa2->v4);
4267 std::swap(jd->sa1->totrct, jd->sa2->totrct);
4268 std::swap(jd->sa1->winx, jd->sa2->winx);
4269 std::swap(jd->sa1->winy, jd->sa2->winy);
4270 }
4271
4274 }
4275 }
4276 else if (jd->sa1 && jd->sa2 && jd->dock_target != AreaDockTarget::None) {
4277 /* Dock this to the new location. */
4278 area_docking_apply(C, op);
4279 }
4280 else if (jd->sa1 && jd->sa2 && jd->dir != SCREEN_DIR_NONE) {
4281 /* Join to neighbor. */
4282 area_join_apply(C, op);
4283 }
4284 else {
4285 area_join_cancel(C, op);
4286 return OPERATOR_CANCELLED;
4287 }
4288
4289 /* Areas changed, update window titles. */
4290 if (jd->win2 && jd->win2 != jd->win1) {
4292 }
4293 if (jd->win1 && !jd->close_win) {
4295 }
4296
4297 const bool do_close_win = jd->close_win;
4298 wmWindow *close_win = jd->win1;
4299 area_join_exit(C, op);
4300 if (do_close_win) {
4301 wm_window_close(C, CTX_wm_manager(C), close_win);
4302 }
4303
4305 return OPERATOR_FINISHED;
4306 }
4307 break;
4308
4309 case RIGHTMOUSE:
4310 case EVT_ESCKEY:
4311 area_join_cancel(C, op);
4312 return OPERATOR_CANCELLED;
4313 }
4314
4316}
4317
4318/* Operator for joining two areas (space types) */
4320{
4321 /* identifiers */
4322 ot->name = "Join Area";
4323 ot->description = "Join selected areas into new window";
4324 ot->idname = "SCREEN_OT_area_join";
4325
4326 /* api callbacks */
4327 ot->exec = area_join_exec;
4328 ot->invoke = area_join_invoke;
4329 ot->modal = area_join_modal;
4330 ot->poll = screen_active_editable;
4331 ot->cancel = area_join_cancel;
4332
4333 /* flags */
4334 ot->flag = OPTYPE_BLOCKING;
4335
4336 /* rna */
4337 RNA_def_int_vector(ot->srna,
4338 "source_xy",
4339 2,
4340 nullptr,
4341 INT_MIN,
4342 INT_MAX,
4343 "Source location",
4344 "",
4345 INT_MIN,
4346 INT_MAX);
4347 RNA_def_int_vector(ot->srna,
4348 "target_xy",
4349 2,
4350 nullptr,
4351 INT_MIN,
4352 INT_MAX,
4353 "Target location",
4354 "",
4355 INT_MIN,
4356 INT_MAX);
4357}
4358
4360
4361/* -------------------------------------------------------------------- */
4364
4366{
4367 ScrArea *sa1, *sa2;
4368 if (screen_area_edge_from_cursor(C, event->xy, &sa1, &sa2) == nullptr) {
4369 return OPERATOR_CANCELLED;
4370 }
4371
4373 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
4374 uiLayout *layout = UI_popup_menu_layout(pup);
4375
4376 /* Vertical Split */
4378 uiItemFullO(layout,
4379 "SCREEN_OT_area_split",
4380 IFACE_("Vertical Split"),
4381 ICON_SPLIT_VERTICAL,
4382 nullptr,
4385 &ptr);
4386 /* store initial mouse cursor position. */
4387 RNA_int_set_array(&ptr, "cursor", event->xy);
4388 RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V);
4389
4390 /* Horizontal Split */
4391 uiItemFullO(layout,
4392 "SCREEN_OT_area_split",
4393 IFACE_("Horizontal Split"),
4394 ICON_SPLIT_HORIZONTAL,
4395 nullptr,
4398 &ptr);
4399 /* store initial mouse cursor position. */
4400 RNA_int_set_array(&ptr, "cursor", event->xy);
4401 RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H);
4402
4403 if (sa1 && sa2) {
4404 uiItemS(layout);
4405 }
4406
4407 /* Join needs two very similar areas. */
4408 if (sa1 && sa2) {
4409 eScreenDir dir = area_getorientation(sa1, sa2);
4410 if (dir != SCREEN_DIR_NONE) {
4411 uiItemFullO(layout,
4412 "SCREEN_OT_area_join",
4413 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? IFACE_("Join Up") : IFACE_("Join Right"),
4414 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? ICON_AREA_JOIN_UP : ICON_AREA_JOIN,
4415 nullptr,
4418 &ptr);
4419 RNA_int_set_array(&ptr, "source_xy", blender::int2{sa2->totrct.xmin, sa2->totrct.ymin});
4420 RNA_int_set_array(&ptr, "target_xy", blender::int2{sa1->totrct.xmin, sa1->totrct.ymin});
4421
4423 layout,
4424 "SCREEN_OT_area_join",
4425 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? IFACE_("Join Down") : IFACE_("Join Left"),
4426 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? ICON_AREA_JOIN_DOWN : ICON_AREA_JOIN_LEFT,
4427 nullptr,
4430 &ptr);
4431 RNA_int_set_array(&ptr, "source_xy", blender::int2{sa1->totrct.xmin, sa1->totrct.ymin});
4432 RNA_int_set_array(&ptr, "target_xy", blender::int2{sa2->totrct.xmin, sa2->totrct.ymin});
4433
4434 uiItemS(layout);
4435 }
4436 }
4437
4438 /* Swap just needs two areas. */
4439 if (sa1 && sa2) {
4440 uiItemFullO(layout,
4441 "SCREEN_OT_area_swap",
4442 IFACE_("Swap Areas"),
4443 ICON_AREA_SWAP,
4444 nullptr,
4447 &ptr);
4448 RNA_int_set_array(&ptr, "cursor", event->xy);
4449 }
4450
4451 UI_popup_menu_end(C, pup);
4452
4453 return OPERATOR_INTERFACE;
4454}
4455
4457{
4458 /* identifiers */
4459 ot->name = "Area Options";
4460 ot->description = "Operations for splitting and merging";
4461 ot->idname = "SCREEN_OT_area_options";
4462
4463 /* api callbacks */
4465
4467
4468 /* flags */
4469 ot->flag = OPTYPE_INTERNAL;
4470}
4471
4473
4474/* -------------------------------------------------------------------- */
4477
4479{
4480 Main *bmain = CTX_data_main(C);
4481 int tot = 0;
4482
4483 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
4484 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
4485 if (area->spacedata.first != area->spacedata.last) {
4486 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
4487
4488 BLI_remlink(&area->spacedata, sl);
4489 tot += BLI_listbase_count(&area->spacedata);
4490 BKE_spacedata_freelist(&area->spacedata);
4491 BLI_addtail(&area->spacedata, sl);
4492 }
4493 }
4494 }
4495 BKE_reportf(op->reports, RPT_INFO, "Removed amount of editors: %d", tot);
4496
4497 return OPERATOR_FINISHED;
4498}
4499
4501{
4502 /* identifiers */
4503 ot->name = "Clean Up Space Data";
4504 ot->description = "Remove unused settings for invisible editors";
4505 ot->idname = "SCREEN_OT_spacedata_cleanup";
4506
4507 /* api callbacks */
4508 ot->exec = spacedata_cleanup_exec;
4509 ot->poll = WM_operator_winactive;
4510}
4511
4513
4514/* -------------------------------------------------------------------- */
4517
4519{
4521 return false;
4522 }
4524 return !BLI_listbase_is_empty(&wm->operators);
4525}
4526
4528{
4530 wmOperator *lastop = static_cast<wmOperator *>(wm->operators.last);
4531
4532 /* Seek last registered operator */
4533 while (lastop) {
4534 if (lastop->type->flag & OPTYPE_REGISTER) {
4535 break;
4536 }
4537 lastop = lastop->prev;
4538 }
4539
4540 if (lastop) {
4541 WM_operator_free_all_after(wm, lastop);
4542 WM_operator_repeat_last(C, lastop);
4543 }
4544
4545 return OPERATOR_CANCELLED;
4546}
4547
4549{
4550 /* identifiers */
4551 ot->name = "Repeat Last";
4552 ot->description = "Repeat last action";
4553 ot->idname = "SCREEN_OT_repeat_last";
4554
4555 /* api callbacks */
4556 ot->exec = repeat_last_exec;
4557
4558 ot->poll = repeat_history_poll;
4559}
4560
4562
4563/* -------------------------------------------------------------------- */
4566
4567static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
4568{
4570
4571 int items = BLI_listbase_count(&wm->operators);
4572 if (items == 0) {
4573 return OPERATOR_CANCELLED;
4574 }
4575
4577 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
4578 uiLayout *layout = UI_popup_menu_layout(pup);
4579
4580 wmOperator *lastop;
4581 int i;
4582 for (i = items - 1, lastop = static_cast<wmOperator *>(wm->operators.last); lastop;
4583 lastop = lastop->prev, i--)
4584 {
4585 if ((lastop->type->flag & OPTYPE_REGISTER) && WM_operator_repeat_check(C, lastop)) {
4586 uiItemIntO(layout,
4587 WM_operatortype_name(lastop->type, lastop->ptr).c_str(),
4588 ICON_NONE,
4589 op->type->idname,
4590 "index",
4591 i);
4592 }
4593 }
4594
4595 UI_popup_menu_end(C, pup);
4596
4597 return OPERATOR_INTERFACE;
4598}
4599
4601{
4603
4604 op = static_cast<wmOperator *>(BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index")));
4605 if (op) {
4606 /* let's put it as last operator in list */
4607 BLI_remlink(&wm->operators, op);
4608 BLI_addtail(&wm->operators, op);
4609
4610 WM_operator_repeat(C, op);
4611 }
4612
4613 return OPERATOR_FINISHED;
4614}
4615
4617{
4618 /* identifiers */
4619 ot->name = "Repeat History";
4620 ot->description = "Display menu for previous actions performed";
4621 ot->idname = "SCREEN_OT_repeat_history";
4622
4623 /* api callbacks */
4624 ot->invoke = repeat_history_invoke;
4625 ot->exec = repeat_history_exec;
4626 ot->poll = repeat_history_poll;
4627
4628 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
4629}
4630
4632
4633/* -------------------------------------------------------------------- */
4636
4637static int redo_last_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
4638{
4640
4641 if (lastop) {
4642 WM_operator_redo_popup(C, lastop);
4643 }
4644
4645 return OPERATOR_CANCELLED;
4646}
4647
4649{
4650 /* identifiers */
4651 ot->name = "Redo Last";
4652 ot->description = "Display parameters for last action performed";
4653 ot->idname = "SCREEN_OT_redo_last";
4654
4655 /* api callbacks */
4656 ot->invoke = redo_last_invoke;
4657 ot->poll = repeat_history_poll;
4658}
4659
4661
4662/* -------------------------------------------------------------------- */
4665
4667{
4668 if (rv3d->localvd) {
4669 rv3d->localvd->view = rv3d->view;
4670 rv3d->localvd->view_axis_roll = rv3d->view_axis_roll;
4671 rv3d->localvd->persp = rv3d->persp;
4672 copy_qt_qt(rv3d->localvd->viewquat, rv3d->viewquat);
4673 }
4674}
4675
4677 ScrArea *area, ARegion *region, const char viewlock, const char view, const char persp)
4678{
4679 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
4680
4681 if (persp == RV3D_CAMOB) {
4683 }
4684
4685 rv3d->viewlock = viewlock;
4686 rv3d->runtime_viewlock = 0;
4687 rv3d->view = view;
4689 rv3d->persp = persp;
4690
4691 ED_view3d_lock(rv3d);
4693 if ((viewlock & RV3D_BOXCLIP) && (persp == RV3D_ORTHO)) {
4694 ED_view3d_quadview_update(area, region, true);
4695 }
4696}
4697
4698/* insert a region in the area region list */
4700{
4701 ARegion *region = CTX_wm_region(C);
4702
4703 /* some rules... */
4704 if (region->regiontype != RGN_TYPE_WINDOW) {
4705 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-split");
4706 }
4707 else if (region->alignment == RGN_ALIGN_QSPLIT) {
4708 /* Exit quad-view */
4709 ScrArea *area = CTX_wm_area(C);
4710
4711 /* keep current region */
4712 region->alignment = 0;
4713
4714 if (area->spacetype == SPACE_VIEW3D) {
4715 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
4716
4717 /* if this is a locked view, use settings from 'User' view */
4718 if (rv3d->viewlock) {
4719 View3D *v3d_user;
4720 ARegion *region_user;
4721
4722 if (ED_view3d_context_user_region(C, &v3d_user, &region_user)) {
4723 if (region != region_user) {
4724 std::swap(region->regiondata, region_user->regiondata);
4725 rv3d = static_cast<RegionView3D *>(region->regiondata);
4726 }
4727 }
4728 }
4729
4731 rv3d->viewlock = 0;
4732
4733 /* FIXME: This fixes missing update to workbench TAA. (see #76216)
4734 * However, it would be nice if the tagging should be done in a more conventional way. */
4735 rv3d->rflag |= RV3D_GPULIGHT_UPDATE;
4736
4737 /* Accumulate locks, in case they're mixed. */
4738 LISTBASE_FOREACH (ARegion *, region_iter, &area->regionbase) {
4739 if (region_iter->regiontype == RGN_TYPE_WINDOW) {
4740 RegionView3D *rv3d_iter = static_cast<RegionView3D *>(region_iter->regiondata);
4741 rv3d->viewlock_quad |= rv3d_iter->viewlock;
4742 }
4743 }
4744 }
4745
4746 LISTBASE_FOREACH_MUTABLE (ARegion *, region_iter, &area->regionbase) {
4747 if (region_iter->alignment == RGN_ALIGN_QSPLIT) {
4748 ED_region_remove(C, area, region_iter);
4749 }
4750 }
4751 ED_area_tag_redraw(area);
4753 }
4754 else if (region->next) {
4755 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-split");
4756 }
4757 else {
4758 /* Enter quad-view */
4759 ScrArea *area = CTX_wm_area(C);
4760
4761 region->alignment = RGN_ALIGN_QSPLIT;
4762
4763 for (int count = 0; count < 3; count++) {
4764 ARegion *new_region = BKE_area_region_copy(area->type, region);
4765 BLI_addtail(&area->regionbase, new_region);
4766 }
4767
4768 /* lock views and set them */
4769 if (area->spacetype == SPACE_VIEW3D) {
4770 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
4771 int index_qsplit = 0;
4772
4773 /* run ED_view3d_lock() so the correct 'rv3d->viewquat' is set,
4774 * otherwise when restoring rv3d->localvd the 'viewquat' won't
4775 * match the 'view', set on entering localview See: #26315,
4776 *
4777 * We could avoid manipulating rv3d->localvd here if exiting
4778 * localview with a 4-split would assign these view locks */
4779 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
4780 const char viewlock = (rv3d->viewlock_quad & RV3D_VIEWLOCK_INIT) ?
4783
4785 area, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
4787 (region = region->next),
4788 viewlock,
4789 ED_view3d_lock_view_from_index(index_qsplit++),
4790 RV3D_ORTHO);
4792 (region = region->next),
4793 viewlock,
4794 ED_view3d_lock_view_from_index(index_qsplit++),
4795 RV3D_ORTHO);
4796/* forcing camera is distracting */
4797#if 0
4798 if (v3d->camera) {
4799 region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_CAMERA, RV3D_CAMOB);
4800 }
4801 else {
4802 region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_USER, RV3D_PERSP);
4803 }
4804#else
4805 (void)v3d;
4806#endif
4807 }
4808 ED_area_tag_redraw(area);
4810 }
4811
4812 return OPERATOR_FINISHED;
4813}
4814
4816{
4817 /* identifiers */
4818 ot->name = "Toggle Quad View";
4819 ot->description = "Split selected area into camera, front, right, and top views";
4820 ot->idname = "SCREEN_OT_region_quadview";
4821
4822 /* api callbacks */
4823 ot->exec = region_quadview_exec;
4825 ot->flag = 0;
4826}
4827
4829
4830/* -------------------------------------------------------------------- */
4833
4835{
4836 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "region_type");
4837
4838 ARegion *region;
4839 if (RNA_property_is_set(op->ptr, prop)) {
4841 }
4842 else {
4843 region = CTX_wm_region(C);
4844 }
4845
4846 if (region && (region->alignment != RGN_ALIGN_NONE)) {
4847 ED_region_toggle_hidden(C, region);
4848 }
4849 ED_region_tag_redraw(region);
4850
4851 return OPERATOR_FINISHED;
4852}
4853
4855{
4856 ScrArea *area = CTX_wm_area(C);
4857
4858 /* Don't flip anything around in top-bar. */
4859 if (area && area->spacetype == SPACE_TOPBAR) {
4860 CTX_wm_operator_poll_msg_set(C, "Toggling regions in the Top-bar is not allowed");
4861 return false;
4862 }
4863
4864 return ED_operator_areaactive(C);
4865}
4866
4868{
4869 /* identifiers */
4870 ot->name = "Toggle Region";
4871 ot->idname = "SCREEN_OT_region_toggle";
4872 ot->description = "Hide or unhide the region";
4873
4874 /* api callbacks */
4875 ot->exec = region_toggle_exec;
4876 ot->poll = region_toggle_poll;
4877 ot->flag = 0;
4878
4879 RNA_def_enum(ot->srna,
4880 "region_type",
4882 0,
4883 "Region Type",
4884 "Type of the region to toggle");
4885}
4886
4888
4889/* -------------------------------------------------------------------- */
4892
4893/* flip a region alignment */
4895{
4896 ARegion *region = CTX_wm_region(C);
4897
4898 if (!region) {
4899 return OPERATOR_CANCELLED;
4900 }
4901
4902 if (region->alignment == RGN_ALIGN_TOP) {
4903 region->alignment = RGN_ALIGN_BOTTOM;
4904 }
4905 else if (region->alignment == RGN_ALIGN_BOTTOM) {
4906 region->alignment = RGN_ALIGN_TOP;
4907 }
4908 else if (region->alignment == RGN_ALIGN_LEFT) {
4909 region->alignment = RGN_ALIGN_RIGHT;
4910 }
4911 else if (region->alignment == RGN_ALIGN_RIGHT) {
4912 region->alignment = RGN_ALIGN_LEFT;
4913 }
4914
4918
4919 return OPERATOR_FINISHED;
4920}
4921
4923{
4924 ScrArea *area = CTX_wm_area(C);
4925
4926 /* Don't flip anything around in top-bar. */
4927 if (area && area->spacetype == SPACE_TOPBAR) {
4928 CTX_wm_operator_poll_msg_set(C, "Flipping regions in the Top-bar is not allowed");
4929 return false;
4930 }
4931
4932 return ED_operator_areaactive(C);
4933}
4934
4936{
4937 /* identifiers */
4938 ot->name = "Flip Region";
4939 ot->idname = "SCREEN_OT_region_flip";
4940 ot->description = "Toggle the region's alignment (left/right or top/bottom)";
4941
4942 /* api callbacks */
4943 ot->exec = region_flip_exec;
4944 ot->poll = region_flip_poll;
4945 ot->flag = 0;
4946}
4947
4949
4950/* -------------------------------------------------------------------- */
4953
4954/* show/hide header text menus */
4956{
4957 ScrArea *area = CTX_wm_area(C);
4958
4959 area->flag = area->flag ^ HEADER_NO_PULLDOWN;
4960
4961 ED_area_tag_redraw(area);
4963
4964 return OPERATOR_FINISHED;
4965}
4966
4968{
4969 /* identifiers */
4970 ot->name = "Expand/Collapse Header Menus";
4971 ot->idname = "SCREEN_OT_header_toggle_menus";
4972 ot->description = "Expand or collapse the header pulldown menus";
4973
4974 /* api callbacks */
4976 ot->poll = ED_operator_areaactive;
4977 ot->flag = 0;
4978}
4979
4981
4982/* -------------------------------------------------------------------- */
4985
4986static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
4987{
4988 if (ED_area_is_global(area)) {
4989 return;
4990 }
4991
4993
4994 uiItemFullO(layout,
4995 "SCREEN_OT_area_join",
4996 IFACE_("Move/Split Area"),
4997 ICON_AREA_DOCK,
4998 nullptr,
5001 &ptr);
5002
5003 uiItemS(layout);
5004
5005 uiItemO(layout,
5006 area->full ? IFACE_("Restore Areas") : IFACE_("Maximize Area"),
5007 ICON_NONE,
5008 "SCREEN_OT_screen_full_area");
5009
5010 if (area->spacetype != SPACE_FILE && !area->full) {
5011 uiItemFullO(layout,
5012 "SCREEN_OT_screen_full_area",
5013 IFACE_("Full Screen Area"),
5014 ICON_NONE,
5015 nullptr,
5018 &ptr);
5019 RNA_boolean_set(&ptr, "use_hide_panels", true);
5020 }
5021
5022 uiItemO(layout, nullptr, ICON_NONE, "SCREEN_OT_area_dupli");
5023 uiItemS(layout);
5024 uiItemO(layout, nullptr, ICON_X, "SCREEN_OT_area_close");
5025}
5026
5028{
5029 ScrArea *area = CTX_wm_area(C);
5030 {
5032 if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
5033 uiItemR(layout, &ptr, "show_region_header", UI_ITEM_NONE, IFACE_("Show Header"), ICON_NONE);
5034 }
5035
5036 ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
5037 uiLayout *col = uiLayoutColumn(layout, false);
5038 uiLayoutSetActive(col, (region_header->flag & RGN_FLAG_HIDDEN) == 0);
5039
5041 uiItemR(col,
5042 &ptr,
5043 "show_region_tool_header",
5045 IFACE_("Show Tool Settings"),
5046 ICON_NONE);
5047 }
5048
5049 uiItemO(col,
5050 IFACE_("Show Menus"),
5051 (area->flag & HEADER_NO_PULLDOWN) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT,
5052 "SCREEN_OT_header_toggle_menus");
5053 }
5054
5055 if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
5056 uiItemS(layout);
5057 ED_screens_region_flip_menu_create(C, layout, nullptr);
5058 uiItemS(layout);
5059 screen_area_menu_items(area, layout);
5060 }
5061}
5062
5064{
5065 ScrArea *area = CTX_wm_area(C);
5066
5067 {
5069 uiItemR(layout, &ptr, "show_region_footer", UI_ITEM_NONE, IFACE_("Show Footer"), ICON_NONE);
5070 }
5071
5072 ED_screens_region_flip_menu_create(C, layout, nullptr);
5073 uiItemS(layout);
5074 screen_area_menu_items(area, layout);
5075}
5076
5078{
5079 const ARegion *region = CTX_wm_region(C);
5080 const short region_alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
5081 const char *but_flip_str = region_alignment == RGN_ALIGN_LEFT ? IFACE_("Flip to Right") :
5082 region_alignment == RGN_ALIGN_RIGHT ? IFACE_("Flip to Left") :
5083 region_alignment == RGN_ALIGN_BOTTOM ? IFACE_("Flip to Top") :
5084 IFACE_("Flip to Bottom");
5085
5086 /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
5088
5089 uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
5090}
5091
5092static void ed_screens_statusbar_menu_create(uiLayout *layout, void * /*arg*/)
5093{
5094 PointerRNA ptr = RNA_pointer_create(nullptr, &RNA_PreferencesView, &U);
5095 uiItemR(
5096 layout, &ptr, "show_statusbar_stats", UI_ITEM_NONE, IFACE_("Scene Statistics"), ICON_NONE);
5097 uiItemR(layout,
5098 &ptr,
5099 "show_statusbar_scene_duration",
5101 IFACE_("Scene Duration"),
5102 ICON_NONE);
5103 uiItemR(layout, &ptr, "show_statusbar_memory", UI_ITEM_NONE, IFACE_("System Memory"), ICON_NONE);
5105 uiItemR(layout, &ptr, "show_statusbar_vram", UI_ITEM_NONE, IFACE_("Video Memory"), ICON_NONE);
5106 }
5107 uiItemR(layout,
5108 &ptr,
5109 "show_extensions_updates",
5111 IFACE_("Extensions Updates"),
5112 ICON_NONE);
5113 uiItemR(
5114 layout, &ptr, "show_statusbar_version", UI_ITEM_NONE, IFACE_("Blender Version"), ICON_NONE);
5115}
5116
5117static int screen_context_menu_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
5118{
5119 const ScrArea *area = CTX_wm_area(C);
5120 const ARegion *region = CTX_wm_region(C);
5121
5122 if (area && area->spacetype == SPACE_STATUSBAR) {
5123 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Status Bar"), ICON_NONE);
5124 uiLayout *layout = UI_popup_menu_layout(pup);
5125 ed_screens_statusbar_menu_create(layout, nullptr);
5126 UI_popup_menu_end(C, pup);
5127 }
5128 else if (region) {
5130 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE);
5131 uiLayout *layout = UI_popup_menu_layout(pup);
5132 ED_screens_header_tools_menu_create(C, layout, nullptr);
5133 UI_popup_menu_end(C, pup);
5134 }
5135 else if (region->regiontype == RGN_TYPE_FOOTER) {
5136 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE);
5137 uiLayout *layout = UI_popup_menu_layout(pup);
5138 ED_screens_footer_tools_menu_create(C, layout, nullptr);
5139 UI_popup_menu_end(C, pup);
5140 }
5141 else if (region->regiontype == RGN_TYPE_NAV_BAR) {
5142 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Navigation Bar"), ICON_NONE);
5143 uiLayout *layout = UI_popup_menu_layout(pup);
5144 ED_screens_region_flip_menu_create(C, layout, nullptr);
5145 UI_popup_menu_end(C, pup);
5146 }
5147 }
5148
5149 return OPERATOR_INTERFACE;
5150}
5151
5153{
5154 /* identifiers */
5155 ot->name = "Region";
5156 ot->description = "Display region context menu";
5157 ot->idname = "SCREEN_OT_region_context_menu";
5158
5159 /* api callbacks */
5161}
5162
5164
5165/* -------------------------------------------------------------------- */
5170
5171static bool match_region_with_redraws(const ScrArea *area,
5172 eRegion_Type regiontype,
5173 eScreen_Redraws_Flag redraws,
5174 bool from_anim_edit)
5175{
5176 const eSpace_Type spacetype = eSpace_Type(area->spacetype);
5177 if (regiontype == RGN_TYPE_WINDOW) {
5178
5179 switch (spacetype) {
5180 case SPACE_VIEW3D:
5181 if ((redraws & TIME_ALL_3D_WIN) || from_anim_edit) {
5182 return true;
5183 }
5184 break;
5185 case SPACE_GRAPH:
5186 case SPACE_NLA:
5187 if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit) {
5188 return true;
5189 }
5190 break;
5191 case SPACE_ACTION:
5192 /* if only 1 window or 3d windows, we do timeline too
5193 * NOTE: Now we do action editor in all these cases, since timeline is here. */
5194 if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit) {
5195 return true;
5196 }
5197 break;
5198 case SPACE_PROPERTIES:
5199 if (redraws & TIME_ALL_BUTS_WIN) {
5200 return true;
5201 }
5202 break;
5203 case SPACE_SEQ:
5204 if ((redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) || from_anim_edit) {
5205 return true;
5206 }
5207 break;
5208 case SPACE_NODE:
5209 if (redraws & TIME_NODES) {
5210 return true;
5211 }
5212 break;
5213 case SPACE_IMAGE:
5214 if ((redraws & TIME_ALL_IMAGE_WIN) || from_anim_edit) {
5215 return true;
5216 }
5217 break;
5218 case SPACE_CLIP:
5219 if ((redraws & TIME_CLIPS) || from_anim_edit) {
5220 return true;
5221 }
5222 break;
5223 case SPACE_SPREADSHEET:
5224 if (redraws & TIME_SPREADSHEETS) {
5225 return true;
5226 }
5227 break;
5228 default:
5229 break;
5230 }
5231 }
5232 else if (regiontype == RGN_TYPE_UI) {
5233 if (spacetype == SPACE_CLIP) {
5234 /* Track Preview button is on Properties Editor in SpaceClip,
5235 * and it's very common case when users want it be refreshing
5236 * during playback, so asking people to enable special option
5237 * for this is a bit tricky, so add exception here for refreshing
5238 * Properties Editor for SpaceClip always */
5239 return true;
5240 }
5241
5242 if (redraws & TIME_ALL_BUTS_WIN) {
5243 return true;
5244 }
5245 }
5246 else if (regiontype == RGN_TYPE_HEADER) {
5247 if (spacetype == SPACE_ACTION) {
5248 /* The timeline shows the current frame in the header. Other headers
5249 * don't need to be updated. */
5250 SpaceAction *saction = (SpaceAction *)area->spacedata.first;
5251 return saction->mode == SACTCONT_TIMELINE;
5252 }
5253 }
5254 else if (regiontype == RGN_TYPE_PREVIEW) {
5255 switch (spacetype) {
5256 case SPACE_SEQ:
5257 if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) {
5258 return true;
5259 }
5260 break;
5261 case SPACE_CLIP:
5262 return true;
5263 default:
5264 break;
5265 }
5266 }
5267 return false;
5268}
5269
5271 bContext *C, ScrArea *area, ARegion *region, const Scene *scene, eScreen_Redraws_Flag redraws)
5272{
5273 /* Do follow time here if editor type supports it */
5274 if ((redraws & TIME_FOLLOW) &&
5276 eRegion_Type(region->regiontype)))
5277 {
5278 float w = BLI_rctf_size_x(&region->v2d.cur);
5279 if (scene->r.cfra < region->v2d.cur.xmin) {
5280 region->v2d.cur.xmax = scene->r.cfra;
5281 region->v2d.cur.xmin = region->v2d.cur.xmax - w;
5282 ED_region_tag_redraw(region);
5283 return;
5284 }
5285 if (scene->r.cfra > region->v2d.cur.xmax) {
5286 region->v2d.cur.xmin = scene->r.cfra;
5287 region->v2d.cur.xmax = region->v2d.cur.xmin + w;
5288 ED_region_tag_redraw(region);
5289 return;
5290 }
5291 }
5292
5293 /* No need to do a full redraw as the current frame indicator is only updated.
5294 * We do need to redraw when this area is in full screen as no other areas
5295 * will be tagged for redrawing. */
5296 if (region->regiontype == RGN_TYPE_WINDOW && !area->full) {
5297 if (ELEM(area->spacetype, SPACE_NLA, SPACE_ACTION)) {
5298 return;
5299 }
5300
5301 /* Drivers Editor needs a full redraw on playback for graph_draw_driver_debug().
5302 * This will make it slower than regular graph editor during playback, but drawing this in
5303 * graph_main_region_draw_overlay() is not feasible because it requires animation filtering
5304 * which has significant overhead which needs to be avoided in the overlay which is redrawn on
5305 * every UI interaction. */
5306 if (area->spacetype == SPACE_GRAPH) {
5307 const SpaceGraph *sipo = static_cast<const SpaceGraph *>(area->spacedata.first);
5308 if (sipo->mode != SIPO_MODE_DRIVERS) {
5309 return;
5310 }
5311 bAnimContext ac;
5312 if (ANIM_animdata_get_context(C, &ac) == false) {
5313 return;
5314 }
5315 if (ac.datatype != ANIMCONT_DRIVERS) {
5316 return;
5317 }
5318 }
5319
5320 if (area->spacetype == SPACE_SEQ) {
5321 const SpaceSeq *sseq = static_cast<const SpaceSeq *>(area->spacedata.first);
5323 return;
5324 }
5325 }
5326 }
5327 ED_region_tag_redraw(region);
5328}
5329
5330// #define PROFILE_AUDIO_SYNCH
5331
5332static int screen_animation_step_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
5333{
5334 bScreen *screen = CTX_wm_screen(C);
5335 wmTimer *wt = screen->animtimer;
5336
5337 if (!(wt && wt == event->customdata)) {
5338 return OPERATOR_PASS_THROUGH;
5339 }
5340
5341 wmWindow *win = CTX_wm_window(C);
5342
5343#ifdef PROFILE_AUDIO_SYNCH
5344 static int old_frame = 0;
5345 int newfra_int;
5346#endif
5347
5348 Main *bmain = CTX_data_main(C);
5349 Scene *scene = CTX_data_scene(C);
5350 ViewLayer *view_layer = WM_window_get_active_view_layer(win);
5351 Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
5352 Scene *scene_eval = (depsgraph != nullptr) ? DEG_get_evaluated_scene(depsgraph) : nullptr;
5353 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
5355 int sync;
5356 double time;
5357
5358 /* sync, don't sync, or follow scene setting */
5359 if (sad->flag & ANIMPLAY_FLAG_SYNC) {
5360 sync = 1;
5361 }
5362 else if (sad->flag & ANIMPLAY_FLAG_NO_SYNC) {
5363 sync = 0;
5364 }
5365 else {
5366 sync = (scene->flag & SCE_FRAME_DROP);
5367 }
5368
5369 if (scene_eval == nullptr) {
5370 /* Happens when undo/redo system is used during playback, nothing meaningful we can do here. */
5371 }
5372 else if (scene_eval->id.recalc & ID_RECALC_FRAME_CHANGE) {
5373 /* Ignore seek here, the audio will be updated to the scene frame after jump during next
5374 * dependency graph update. */
5375 }
5376 else if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
5377 isfinite(time = BKE_sound_sync_scene(scene_eval)))
5378 {
5379 double newfra = time * FPS;
5380
5381 /* give some space here to avoid jumps */
5382 if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra) {
5383 scene->r.cfra++;
5384 }
5385 else {
5386 scene->r.cfra = max_ii(scene->r.cfra, round(newfra));
5387 }
5388
5389#ifdef PROFILE_AUDIO_SYNCH
5390 newfra_int = scene->r.cfra;
5391 if (newfra_int < old_frame) {
5392 printf("back jump detected, frame %d!\n", newfra_int);
5393 }
5394 else if (newfra_int > old_frame + 1) {
5395 printf("forward jump detected, frame %d!\n", newfra_int);
5396 }
5397 fflush(stdout);
5398 old_frame = newfra_int;
5399#endif
5400 }
5401 else {
5402 if (sync) {
5403 /* Try to keep the playback in realtime by dropping frames. */
5404
5405 /* How much time (in frames) has passed since the last frame was drawn? */
5406 double delta_frames = wt->time_delta * FPS;
5407
5408 /* Add the remaining fraction from the last time step. */
5409 delta_frames += sad->lagging_frame_count;
5410
5411 if (delta_frames < 1.0) {
5412 /* We can render faster than the scene frame rate. However skipping or delaying frames
5413 * here seems to in practice lead to jittery playback so just step forward a minimum of
5414 * one frame. (Even though this can lead to too fast playback, the jitteriness is more
5415 * annoying)
5416 */
5417 delta_frames = 1.0f;
5418 sad->lagging_frame_count = 0;
5419 }
5420 else {
5421 /* Extract the delta frame fractions that will be skipped when converting to int. */
5422 sad->lagging_frame_count = delta_frames - int(delta_frames);
5423 }
5424
5425 const int step = delta_frames;
5426
5427 /* skip frames */
5428 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5429 scene->r.cfra -= step;
5430 }
5431 else {
5432 scene->r.cfra += step;
5433 }
5434 }
5435 else {
5436 /* one frame +/- */
5437 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5438 scene->r.cfra--;
5439 }
5440 else {
5441 scene->r.cfra++;
5442 }
5443 }
5444 }
5445
5446 /* reset 'jumped' flag before checking if we need to jump... */
5448
5449 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5450 /* jump back to end? */
5451 if (PRVRANGEON) {
5452 if (scene->r.cfra < scene->r.psfra) {
5453 scene->r.cfra = scene->r.pefra;
5454 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5455 }
5456 }
5457 else {
5458 if (scene->r.cfra < scene->r.sfra) {
5459 scene->r.cfra = scene->r.efra;
5460 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5461 }
5462 }
5463 }
5464 else {
5465 /* jump back to start? */
5466 if (PRVRANGEON) {
5467 if (scene->r.cfra > scene->r.pefra) {
5468 scene->r.cfra = scene->r.psfra;
5469 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5470 }
5471 }
5472 else {
5473 if (scene->r.cfra > scene->r.efra) {
5474 scene->r.cfra = scene->r.sfra;
5475 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5476 }
5477 }
5478 }
5479
5480 /* next frame overridden by user action (pressed jump to first/last frame) */
5482 scene->r.cfra = sad->nextfra;
5484 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5485 }
5486
5487 if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
5489#ifdef PROFILE_AUDIO_SYNCH
5490 old_frame = scene->r.cfra;
5491#endif
5492 }
5493
5494 /* Since we follow draw-flags, we can't send notifier but tag regions ourselves. */
5495 if (depsgraph != nullptr) {
5497 }
5498
5499 LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
5500 const bScreen *win_screen = WM_window_get_active_screen(window);
5501
5502 LISTBASE_FOREACH (ScrArea *, area, &win_screen->areabase) {
5503 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
5504 bool redraw = false;
5505 if (region == sad->region) {
5506 redraw = true;
5507 }
5508 else if (match_region_with_redraws(area,
5509 eRegion_Type(region->regiontype),
5511 sad->from_anim_edit))
5512 {
5513 redraw = true;
5514 }
5515
5516 if (redraw) {
5518 C, area, region, scene, eScreen_Redraws_Flag(sad->redraws));
5519 }
5520 }
5521 }
5522 }
5523
5524 if (U.uiflag & USER_SHOW_FPS) {
5525 /* Update frame rate info too.
5526 * NOTE: this may not be accurate enough, since we might need this after modifiers/etc.
5527 * have been calculated instead of just before updates have been done? */
5528 ED_scene_fps_average_accumulate(scene, U.playback_fps_samples, wt->time_last);
5529 }
5530
5531 /* Recalculate the time-step for the timer now that we've finished calculating this,
5532 * since the frames-per-second value may have been changed.
5533 */
5534 /* TODO: this may make evaluation a bit slower if the value doesn't change...
5535 * any way to avoid this? */
5536 wt->time_step = (1.0 / FPS);
5537
5538 return OPERATOR_FINISHED;
5539}
5540
5542{
5543 /* identifiers */
5544 ot->name = "Animation Step";
5545 ot->description = "Step through animation by position";
5546 ot->idname = "SCREEN_OT_animation_step";
5547
5548 /* api callbacks */
5550
5552}
5553
5555
5556/* -------------------------------------------------------------------- */
5561
5563{
5564 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
5565 bScreen *screen = WM_window_get_active_screen(win);
5566
5567 if (screen->animtimer || screen->scrubbing) {
5568 return screen;
5569 }
5570 }
5571
5572 return nullptr;
5573}
5574
5576{
5577 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
5578 bScreen *screen = WM_window_get_active_screen(win);
5579
5580 if (screen->animtimer) {
5581 return screen;
5582 }
5583 }
5584
5585 return nullptr;
5586}
5587
5588int ED_screen_animation_play(bContext *C, int sync, int mode)
5589{
5590 bScreen *screen = CTX_wm_screen(C);
5591 Scene *scene = CTX_data_scene(C);
5594 Main *bmain = DEG_get_bmain(depsgraph);
5595
5597 /* stop playback now */
5598 ED_screen_animation_timer(C, 0, 0, 0);
5600 BKE_sound_stop_scene(scene_eval);
5601
5604
5605 /* Triggers redraw of sequencer preview so that it does not show to fps anymore after stopping
5606 * playback. */
5610 }
5611 else {
5614
5615 /* these settings are currently only available from a menu in the TimeLine */
5616 if (mode == 1) { /* XXX only play audio forwards!? */
5617 BKE_sound_play_scene(scene_eval);
5618 }
5619
5620 ED_screen_animation_timer(C, screen->redraws_flag, sync, mode);
5622
5623 if (screen->animtimer) {
5624 wmTimer *wt = screen->animtimer;
5625 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
5626
5627 sad->region = CTX_wm_region(C);
5628 }
5629 }
5630
5631 return OPERATOR_FINISHED;
5632}
5633
5635{
5636 int mode = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
5637 int sync = -1;
5638
5639 if (RNA_struct_property_is_set(op->ptr, "sync")) {
5640 sync = RNA_boolean_get(op->ptr, "sync");
5641 }
5642
5643 return ED_screen_animation_play(C, sync, mode);
5644}
5645
5647{
5648 PropertyRNA *prop;
5649
5650 /* identifiers */
5651 ot->name = "Play Animation";
5652 ot->description = "Play animation";
5653 ot->idname = "SCREEN_OT_animation_play";
5654
5655 /* api callbacks */
5657
5659
5660 prop = RNA_def_boolean(
5661 ot->srna, "reverse", false, "Play in Reverse", "Animation is played backwards");
5663 prop = RNA_def_boolean(ot->srna, "sync", false, "Sync", "Drop frames to maintain framerate");
5665}
5666
5668
5669/* -------------------------------------------------------------------- */
5672
5674{
5676
5677 if (screen) {
5678 if (RNA_boolean_get(op->ptr, "restore_frame") && screen->animtimer) {
5679 ScreenAnimData *sad = static_cast<ScreenAnimData *>(screen->animtimer->customdata);
5680 Scene *scene = CTX_data_scene(C);
5681
5682 /* reset current frame before stopping, and just send a notifier to deal with the rest
5683 * (since playback still needs to be stopped)
5684 */
5685 scene->r.cfra = sad->sfra;
5686
5688 }
5689
5690 /* call the other "toggling" operator to clean up now */
5692 }
5693
5694 return OPERATOR_PASS_THROUGH;
5695}
5696
5698{
5699 /* identifiers */
5700 ot->name = "Cancel Animation";
5701 ot->description = "Cancel animation, returning to the original frame";
5702 ot->idname = "SCREEN_OT_animation_cancel";
5703
5704 /* api callbacks */
5706
5708
5709 RNA_def_boolean(ot->srna,
5710 "restore_frame",
5711 true,
5712 "Restore Frame",
5713 "Restore the frame when animation was initialized");
5714}
5715
5717
5718/* -------------------------------------------------------------------- */
5721
5722/* operator state vars used: (added by default WM callbacks)
5723 * xmin, ymin
5724 * xmax, ymax
5725 *
5726 * customdata: the wmGesture pointer
5727 *
5728 * callbacks:
5729 *
5730 * exec() has to be filled in by user
5731 *
5732 * invoke() default WM function
5733 * adds modal handler
5734 *
5735 * modal() default WM function
5736 * accept modal events while doing it, calls exec(), handles ESC and border drawing
5737 *
5738 * poll() has to be filled in by user for context
5739 */
5740#if 0
5741static int box_select_exec(bContext *C, wmOperator *op)
5742{
5743 int event_type = RNA_int_get(op->ptr, "event_type");
5744
5745 if (event_type == LEFTMOUSE) {
5746 printf("box select do select\n");
5747 }
5748 else if (event_type == RIGHTMOUSE) {
5749 printf("box select deselect\n");
5750 }
5751 else {
5752 printf("box select do something\n");
5753 }
5754
5755 return 1;
5756}
5757
5758static void SCREEN_OT_box_select(wmOperatorType *ot)
5759{
5760 /* identifiers */
5761 ot->name = "Box Select";
5762 ot->idname = "SCREEN_OT_box_select";
5763
5764 /* api callbacks */
5765 ot->exec = box_select_exec;
5766 ot->invoke = WM_gesture_box_invoke;
5767 ot->modal = WM_gesture_box_modal;
5768 ot->cancel = WM_gesture_box_cancel;
5769
5770 ot->poll = ED_operator_areaactive;
5771
5772 /* rna */
5773 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
5775}
5776#endif
5777
5779
5780/* -------------------------------------------------------------------- */
5785
5787{
5788 bScreen *screen = CTX_wm_screen(C);
5789 ScrArea *area = nullptr;
5790
5791 /* search current screen for 'fullscreen' areas */
5792 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
5793 if (area_iter->full) {
5794 area = area_iter;
5795 break;
5796 }
5797 }
5798 if (!area) {
5799 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
5800 return OPERATOR_CANCELLED;
5801 }
5802
5804
5805 return OPERATOR_FINISHED;
5806}
5807
5809{
5810 /* identifiers */
5811 ot->name = "Back to Previous Screen";
5812 ot->description = "Revert back to the original screen layout, before fullscreen area overlay";
5813 ot->idname = "SCREEN_OT_back_to_previous";
5814
5815 /* api callbacks */
5816 ot->exec = fullscreen_back_exec;
5818}
5819
5821
5822/* -------------------------------------------------------------------- */
5825
5827{
5828 wmWindow *win_cur = CTX_wm_window(C);
5829 /* Use eventstate, not event from _invoke, so this can be called through exec(). */
5830 const wmEvent *event = win_cur->eventstate;
5831 int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_SCALE_FAC;
5832 int sizey = 520 * UI_SCALE_FAC;
5833
5834 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "section");
5835 if (prop && RNA_property_is_set(op->ptr, prop)) {
5836 /* Set active section via RNA, so it can fail properly. */
5837
5838 PointerRNA pref_ptr = RNA_pointer_create(nullptr, &RNA_Preferences, &U);
5839 PropertyRNA *active_section_prop = RNA_struct_find_property(&pref_ptr, "active_section");
5840
5841 RNA_property_enum_set(&pref_ptr, active_section_prop, RNA_property_enum_get(op->ptr, prop));
5842 RNA_property_update(C, &pref_ptr, active_section_prop);
5843 }
5844
5845 const rcti window_rect = {
5846 /*xmin*/ event->xy[0],
5847 /*xmax*/ event->xy[0] + sizex,
5848 /*ymin*/ event->xy[1],
5849 /*ymax*/ event->xy[1] + sizey,
5850 };
5851
5852 /* changes context! */
5853 if (WM_window_open(C,
5854 nullptr,
5855 &window_rect,
5857 false,
5858 false,
5859 true,
5861 nullptr,
5862 nullptr) != nullptr)
5863 {
5864 /* The header only contains the editor switcher and looks empty.
5865 * So hiding in the temp window makes sense. */
5866 ScrArea *area = CTX_wm_area(C);
5868
5869 region->flag |= RGN_FLAG_HIDDEN;
5871
5872 return OPERATOR_FINISHED;
5873 }
5874 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
5875 return OPERATOR_CANCELLED;
5876}
5877
5879 wmOperatorType * /*ot*/,
5880 PointerRNA *ptr)
5881{
5882 PropertyRNA *prop = RNA_struct_find_property(ptr, "section");
5883 if (RNA_property_is_set(ptr, prop)) {
5884 int section = RNA_property_enum_get(ptr, prop);
5885 const char *section_name;
5886 if (RNA_property_enum_name_gettexted(C, ptr, prop, section, &section_name)) {
5887 return fmt::format(TIP_("Show {} preferences"), section_name);
5888 }
5889 }
5890 /* Fallback to default. */
5891 return "";
5892}
5893
5895{
5896 PropertyRNA *prop;
5897
5898 /* identifiers */
5899 ot->name = "Open Preferences...";
5900 ot->description = "Edit user preferences and system settings";
5901 ot->idname = "SCREEN_OT_userpref_show";
5902
5903 /* api callbacks */
5904 ot->exec = userpref_show_exec;
5905 ot->poll = ED_operator_screenactive_nobackground; /* Not in background as this opens a window. */
5906 ot->get_description = userpref_show_get_description;
5907
5908 prop = RNA_def_enum(ot->srna,
5909 "section",
5911 0,
5912 "",
5913 "Section to activate in the Preferences");
5915}
5916
5918
5919/* -------------------------------------------------------------------- */
5922
5924{
5925 wmWindow *win_cur = CTX_wm_window(C);
5926 /* Use eventstate, not event from _invoke, so this can be called through exec(). */
5927 const wmEvent *event = win_cur->eventstate;
5928
5929 int sizex = 900 * UI_SCALE_FAC;
5930 int sizey = 580 * UI_SCALE_FAC;
5931
5932 /* Get active property to show driver for
5933 * - Need to grab it first, or else this info disappears
5934 * after we've created the window
5935 */
5936 int index;
5938 PropertyRNA *prop;
5939 uiBut *but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
5940
5941 const rcti window_rect = {
5942 /*xmin*/ event->xy[0],
5943 /*xmax*/ event->xy[0] + sizex,
5944 /*ymin*/ event->xy[1],
5945 /*ymax*/ event->xy[1] + sizey,
5946 };
5947
5948 /* changes context! */
5949 if (WM_window_open(C,
5950 IFACE_("Blender Drivers Editor"),
5951 &window_rect,
5953 false,
5954 false,
5955 true,
5957 nullptr,
5958 nullptr) != nullptr)
5959 {
5961
5962 /* activate driver F-Curve for the property under the cursor */
5963 if (but) {
5964 bool driven, special;
5966 C, &ptr, prop, index, nullptr, nullptr, &driven, &special);
5967
5968 if (fcu) {
5969 /* Isolate this F-Curve... */
5970 bAnimContext ac;
5971 if (ANIM_animdata_get_context(C, &ac)) {
5975 ac.data,
5978 fcu,
5980 }
5981 else {
5982 /* Just blindly isolate...
5983 * This isn't the best, and shouldn't happen, but may be enough. */
5985 }
5986 }
5987 }
5988
5989 return OPERATOR_FINISHED;
5990 }
5991 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
5992 return OPERATOR_CANCELLED;
5993}
5994
5996{
5997 /* identifiers */
5998 ot->name = "Show Drivers Editor";
5999 ot->description = "Show drivers editor in a separate window";
6000 ot->idname = "SCREEN_OT_drivers_editor_show";
6001
6002 /* api callbacks */
6004 ot->poll = ED_operator_screenactive_nobackground; /* Not in background as this opens a window. */
6005}
6006
6008
6009/* -------------------------------------------------------------------- */
6012
6014{
6015 wmWindow *win_cur = CTX_wm_window(C);
6016 /* Use eventstate, not event from _invoke, so this can be called through exec(). */
6017 const wmEvent *event = win_cur->eventstate;
6018 const int shift_y = 480;
6019 const int mx = event->xy[0];
6020 const int my = event->xy[1] + shift_y;
6021 int sizex = 900 * UI_SCALE_FAC;
6022 int sizey = 580 * UI_SCALE_FAC;
6023
6024 const rcti window_rect = {
6025 /*xmin*/ mx,
6026 /*xmax*/ mx + sizex,
6027 /*ymin*/ my,
6028 /*ymax*/ my + sizey,
6029 };
6030
6031 /* changes context! */
6032 if (WM_window_open(C,
6033 IFACE_("Blender Info Log"),
6034 &window_rect,
6035 SPACE_INFO,
6036 false,
6037 false,
6038 true,
6040 nullptr,
6041 nullptr) != nullptr)
6042 {
6043 return OPERATOR_FINISHED;
6044 }
6045 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
6046 return OPERATOR_CANCELLED;
6047}
6048
6050{
6051 /* identifiers */
6052 ot->name = "Show Info Log";
6053 ot->description = "Show info log in a separate window";
6054 ot->idname = "SCREEN_OT_info_log_show";
6055
6056 /* api callbacks */
6057 ot->exec = info_log_show_exec;
6059}
6060
6062
6063/* -------------------------------------------------------------------- */
6066
6067static int screen_new_exec(bContext *C, wmOperator * /*op*/)
6068{
6069 Main *bmain = CTX_data_main(C);
6070 wmWindow *win = CTX_wm_window(C);
6073
6074 WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
6075
6077
6078 return OPERATOR_FINISHED;
6079}
6080
6082{
6083 /* identifiers */
6084 ot->name = "New Screen";
6085 ot->description = "Add a new screen";
6086 ot->idname = "SCREEN_OT_new";
6087
6088 /* api callbacks */
6089 ot->exec = screen_new_exec;
6090 ot->poll = WM_operator_winactive;
6091}
6092
6094
6095/* -------------------------------------------------------------------- */
6098
6100{
6101 bScreen *screen = CTX_wm_screen(C);
6102 WorkSpace *workspace = CTX_wm_workspace(C);
6103 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
6104
6106
6107 return OPERATOR_FINISHED;
6108}
6109
6111{
6112 /* identifiers */
6113 ot->name = "Delete Screen";
6114 ot->description = "Delete active screen";
6115 ot->idname = "SCREEN_OT_delete";
6116
6117 /* api callbacks */
6118 ot->exec = screen_delete_exec;
6119}
6120
6122
6123/* -------------------------------------------------------------------- */
6131
6134 ARegion *region, *child_region; /* other region */
6136};
6137
6138#define TIMEOUT 0.1f
6139#define TIMESTEP (1.0f / 60.0f)
6140
6142{
6143 /* check parent too */
6144 if (region->regiontimer == nullptr &&
6145 (region->alignment & (RGN_SPLIT_PREV | RGN_ALIGN_HIDE_WITH_PREV)) && region->prev)
6146 {
6147 region = region->prev;
6148 }
6149
6150 if (region->regiontimer) {
6151 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(region->regiontimer->customdata);
6152 float alpha;
6153
6154 alpha = float(region->regiontimer->time_duration) / TIMEOUT;
6155 /* makes sure the blend out works 100% - without area redraws */
6156 if (rgi->hidden) {
6157 alpha = 0.9f - TIMESTEP - alpha;
6158 }
6159
6160 CLAMP(alpha, 0.0f, 1.0f);
6161 return alpha;
6162 }
6163 return 1.0f;
6164}
6165
6166/* assumes region has running region-blend timer */
6167static void region_blend_end(bContext *C, ARegion *region, const bool is_running)
6168{
6169 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(region->regiontimer->customdata);
6170
6171 /* always send redraw */
6172 ED_region_tag_redraw(region);
6173 if (rgi->child_region) {
6175 }
6176
6177 /* if running timer was hiding, the flag toggle went wrong */
6178 if (is_running) {
6179 if (rgi->hidden) {
6180 rgi->region->flag &= ~RGN_FLAG_HIDDEN;
6181 }
6182 }
6183 else {
6184 if (rgi->hidden) {
6185 rgi->region->flag |= rgi->hidden;
6187 }
6188 /* area decoration needs redraw in end */
6190 }
6191 WM_event_timer_remove(CTX_wm_manager(C), nullptr, region->regiontimer); /* frees rgi */
6192 region->regiontimer = nullptr;
6193}
6195{
6197 wmWindow *win = CTX_wm_window(C);
6198
6199 /* end running timer */
6200 if (region->regiontimer) {
6201
6202 region_blend_end(C, region, true);
6203 }
6204 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(
6205 MEM_callocN(sizeof(RegionAlphaInfo), "RegionAlphaInfo"));
6206
6207 rgi->hidden = region->flag & RGN_FLAG_HIDDEN;
6208 rgi->area = area;
6209 rgi->region = region;
6210 region->flag &= ~RGN_FLAG_HIDDEN;
6211
6212 /* blend in, reinitialize regions because it got unhidden */
6213 if (rgi->hidden == 0) {
6214 ED_area_init(wm, win, area);
6215 }
6216 else {
6217 ED_region_visibility_change_update_ex(C, area, region, true, false);
6218 }
6219
6220 if (region->next) {
6222 rgi->child_region = region->next;
6223 }
6224 }
6225
6226 /* new timer */
6228 region->regiontimer->customdata = rgi;
6229}
6230
6231/* timer runs in win->handlers, so it cannot use context to find area/region */
6232static int region_blend_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
6233{
6234 wmTimer *timer = static_cast<wmTimer *>(event->customdata);
6235
6236 /* event type is TIMERREGION, but we better check */
6237 if (event->type != TIMERREGION || timer == nullptr) {
6238 return OPERATOR_PASS_THROUGH;
6239 }
6240
6241 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(timer->customdata);
6242
6243 /* always send redraws */
6245 if (rgi->child_region) {
6247 }
6248
6249 /* end timer? */
6250 if (rgi->region->regiontimer->time_duration > double(TIMEOUT)) {
6251 region_blend_end(C, rgi->region, false);
6253 }
6254
6256}
6257
6259{
6260 /* identifiers */
6261 ot->name = "Region Alpha";
6262 ot->idname = "SCREEN_OT_region_blend";
6263 ot->description = "Blend in and out overlapping region";
6264
6265 /* api callbacks */
6266 ot->invoke = region_blend_invoke;
6267
6268 /* flags */
6269 ot->flag = OPTYPE_INTERNAL;
6270
6271 /* properties */
6272}
6273
6275
6276/* -------------------------------------------------------------------- */
6279
6281{
6282 ScrArea *area = CTX_wm_area(C);
6283 return (area && !ELEM(area->spacetype, SPACE_TOPBAR, SPACE_STATUSBAR));
6284}
6285
6287{
6288 const int space_type = RNA_enum_get(op->ptr, "space_type");
6289
6290 ScrArea *area = CTX_wm_area(C);
6291 PointerRNA ptr = RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Area, area);
6292 PropertyRNA *prop_type = RNA_struct_find_property(&ptr, "type");
6293 PropertyRNA *prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
6294
6295 if (area->spacetype != space_type) {
6296 /* Set the type. */
6297 RNA_property_enum_set(&ptr, prop_type, space_type);
6298 RNA_property_update(C, &ptr, prop_type);
6299 }
6300 else {
6301 /* Types match, cycle the subtype. */
6302 const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
6303 const EnumPropertyItem *item;
6304 int item_len;
6305 bool free;
6306 RNA_property_enum_items(C, &ptr, prop_ui_type, &item, &item_len, &free);
6307 int index = RNA_enum_from_value(item, space_type_ui);
6308 for (int i = 1; i < item_len; i++) {
6309 const EnumPropertyItem *item_test = &item[(index + i) % item_len];
6310 if ((item_test->value >> 16) == space_type) {
6311 RNA_property_enum_set(&ptr, prop_ui_type, item_test->value);
6312 RNA_property_update(C, &ptr, prop_ui_type);
6313 break;
6314 }
6315 }
6316 if (free) {
6317 MEM_freeN((void *)item);
6318 }
6319 }
6320
6321 return OPERATOR_FINISHED;
6322}
6323
6325{
6326 /* identifiers */
6327 ot->name = "Cycle Space Type Set";
6328 ot->description = "Set the space type or cycle subtype";
6329 ot->idname = "SCREEN_OT_space_type_set_or_cycle";
6330
6331 /* api callbacks */
6334
6335 ot->flag = 0;
6336
6337 RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Type", "");
6338}
6339
6341
6342/* -------------------------------------------------------------------- */
6345
6347 {SPACE_CONTEXT_CYCLE_PREV, "PREV", 0, "Previous", ""},
6348 {SPACE_CONTEXT_CYCLE_NEXT, "NEXT", 0, "Next", ""},
6349 {0, nullptr, 0, nullptr, nullptr},
6350};
6351
6353{
6354 ScrArea *area = CTX_wm_area(C);
6355 /* area might be nullptr if called out of window bounds */
6356 return (area && ELEM(area->spacetype, SPACE_PROPERTIES, SPACE_USERPREF));
6357}
6358
6364 const ScrArea *area,
6365 PointerRNA *r_ptr,
6366 PropertyRNA **r_prop)
6367{
6368 const char *propname;
6369
6370 switch (area->spacetype) {
6371 case SPACE_PROPERTIES:
6372 *r_ptr = RNA_pointer_create(&screen->id, &RNA_SpaceProperties, area->spacedata.first);
6373 propname = "context";
6374 break;
6375 case SPACE_USERPREF:
6376 *r_ptr = RNA_pointer_create(nullptr, &RNA_Preferences, &U);
6377 propname = "active_section";
6378 break;
6379 default:
6380 BLI_assert(0);
6381 propname = "";
6382 }
6383
6384 *r_prop = RNA_struct_find_property(r_ptr, propname);
6385}
6386
6387static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
6388{
6389 const eScreenCycle direction = eScreenCycle(RNA_enum_get(op->ptr, "direction"));
6390
6392 PropertyRNA *prop;
6394 const int old_context = RNA_property_enum_get(&ptr, prop);
6395 const int new_context = RNA_property_enum_step(
6396 C, &ptr, prop, old_context, direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
6397 RNA_property_enum_set(&ptr, prop, new_context);
6398 RNA_property_update(C, &ptr, prop);
6399
6400 return OPERATOR_FINISHED;
6401}
6402
6404{
6405 /* identifiers */
6406 ot->name = "Cycle Space Context";
6407 ot->description = "Cycle through the editor context by activating the next/previous one";
6408 ot->idname = "SCREEN_OT_space_context_cycle";
6409
6410 /* api callbacks */
6413
6414 ot->flag = 0;
6415
6416 RNA_def_enum(ot->srna,
6417 "direction",
6420 "Direction",
6421 "Direction to cycle through");
6422}
6423
6425
6426/* -------------------------------------------------------------------- */
6429
6430static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
6431{
6432 wmWindow *win = CTX_wm_window(C);
6433 if (WM_window_is_temp_screen(win)) {
6434 return OPERATOR_CANCELLED;
6435 }
6436
6437 Main *bmain = CTX_data_main(C);
6438 const eScreenCycle direction = eScreenCycle(RNA_enum_get(op->ptr, "direction"));
6439 WorkSpace *workspace_src = WM_window_get_active_workspace(win);
6440
6441 Vector<ID *> ordered = BKE_id_ordered_list(&bmain->workspaces);
6442 if (ordered.size() == 1) {
6443 return OPERATOR_CANCELLED;
6444 }
6445
6446 const int index = ordered.first_index_of(&workspace_src->id);
6447
6448 WorkSpace *workspace_dst = nullptr;
6449 switch (direction) {
6451 workspace_dst = reinterpret_cast<WorkSpace *>(index == 0 ? ordered.last() :
6452 ordered[index - 1]);
6453 break;
6455 workspace_dst = reinterpret_cast<WorkSpace *>(
6456 index == ordered.index_range().last() ? ordered.first() : ordered[index + 1]);
6457 break;
6458 }
6459
6460 win->workspace_hook->temp_workspace_store = workspace_dst;
6462 win->workspace_hook->temp_workspace_store = nullptr;
6463
6464 return OPERATOR_FINISHED;
6465}
6466
6468{
6469 /* identifiers */
6470 ot->name = "Cycle Workspace";
6471 ot->description = "Cycle through workspaces";
6472 ot->idname = "SCREEN_OT_workspace_cycle";
6473
6474 /* api callbacks */
6477
6478 ot->flag = 0;
6479
6480 RNA_def_enum(ot->srna,
6481 "direction",
6484 "Direction",
6485 "Direction to cycle through");
6486}
6487
6489
6490/* -------------------------------------------------------------------- */
6493
6495{
6496 /* Generic UI stuff. */
6501
6502 /* Screen tools. */
6529
6530 /* Frame changes. */
6535
6539
6540 /* New/delete. */
6543}
6544
6546
6547/* -------------------------------------------------------------------- */
6550
6551static void keymap_modal_set(wmKeyConfig *keyconf)
6552{
6553 static const EnumPropertyItem modal_items[] = {
6554 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
6555 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
6556 {KM_MODAL_SNAP_ON, "SNAP", 0, "Snap On", ""},
6557 {KM_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
6558 {0, nullptr, 0, nullptr, nullptr},
6559 };
6560
6561 /* Standard Modal keymap ------------------------------------------------ */
6562 wmKeyMap *keymap = WM_modalkeymap_ensure(keyconf, "Standard Modal Map", modal_items);
6563
6564 WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
6565}
6566
6567static bool blend_file_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
6568{
6569 if (drag->type == WM_DRAG_PATH) {
6572 return true;
6573 }
6574 }
6575 return false;
6576}
6577
6578static void blend_file_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
6579{
6580 /* copy drag path to properties */
6581 RNA_string_set(drop->ptr, "filepath", WM_drag_get_single_path(drag));
6582}
6583
6585{
6586 /* Screen Editing ------------------------------------------------ */
6587 WM_keymap_ensure(keyconf, "Screen Editing", SPACE_EMPTY, RGN_TYPE_WINDOW);
6588
6589 /* Screen General ------------------------------------------------ */
6590 WM_keymap_ensure(keyconf, "Screen", SPACE_EMPTY, RGN_TYPE_WINDOW);
6591
6592 /* Anim Playback ------------------------------------------------ */
6593 WM_keymap_ensure(keyconf, "Frames", SPACE_EMPTY, RGN_TYPE_WINDOW);
6594
6595 /* dropbox for entire window */
6598 lb, "WM_OT_drop_blend_file", blend_file_drop_poll, blend_file_drop_copy, nullptr, nullptr);
6599 WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy, nullptr, nullptr);
6600
6601 keymap_modal_set(keyconf);
6602}
6603
@ BKE_CB_EVT_ANIMATION_PLAYBACK_PRE
@ BKE_CB_EVT_ANIMATION_PLAYBACK_POST
void BKE_callback_exec_id_depsgraph(Main *bmain, ID *id, Depsgraph *depsgraph, eCbEvent evt)
Definition callbacks.cc:53
WorkSpace * CTX_wm_workspace(const bContext *C)
SpaceImage * CTX_wm_space_image(const bContext *C)
bScreen * CTX_wm_screen(const bContext *C)
Mask * CTX_data_edit_mask(const bContext *C)
SpaceFile * CTX_wm_space_file(const bContext *C)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
SpaceNode * CTX_wm_space_node(const bContext *C)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
SpaceLink * CTX_wm_space_data(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
void CTX_wm_window_set(bContext *C, wmWindow *win)
Main * CTX_data_main(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:63
FCurve * BKE_fcurve_find_by_rna_context_ui(bContext *C, const PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **r_animdata, bAction **r_action, bool *r_driven, bool *r_special)
@ G_TRANSFORM_WM
void BKE_icon_changed(int icon_id)
Definition icons.cc:205
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2456
blender::Vector< ID * > BKE_id_ordered_list(const ListBase *lb)
Definition lib_id.cc:2505
struct MaskLayer * BKE_mask_layer_active(struct Mask *mask)
General operations, lookup, etc. for blender objects.
bool BKE_object_pose_context_check(const Object *ob)
Object * BKE_object_pose_armature_get(Object *ob)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_scene_frame_set(Scene *scene, float frame)
Definition scene.cc:2336
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2331
Depsgraph * BKE_scene_get_depsgraph(const Scene *scene, const ViewLayer *view_layer)
Definition scene.cc:3364
void BKE_screen_remove_unused_scrverts(bScreen *screen)
Definition screen.cc:779
void BKE_screen_remove_unused_scredges(bScreen *screen)
Definition screen.cc:734
void BKE_screen_remove_double_scrverts(bScreen *screen)
Definition screen.cc:666
void BKE_spacedata_freelist(ListBase *lb)
Definition screen.cc:291
ScrEdge * BKE_screen_find_edge(const bScreen *screen, ScrVert *v1, ScrVert *v2)
Definition screen.cc:645
ScrArea ScrArea * BKE_screen_find_area_xy(const bScreen *screen, int spacetype, const int xy[2]) ATTR_NONNULL(1
void BKE_screen_remove_double_scredges(bScreen *screen)
Definition screen.cc:718
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:815
ARegion * BKE_area_region_copy(const SpaceType *st, const ARegion *region)
Definition screen.cc:335
double BKE_sound_sync_scene(struct Scene *scene)
void BKE_sound_stop_scene(struct Scene *scene)
void BKE_sound_play_scene(struct Scene *scene)
WorkSpaceLayout * BKE_workspace_layout_find(const WorkSpace *workspace, const bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition workspace.cc:427
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:613
WorkSpace * BKE_workspace_active_get(WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:562
WorkSpaceLayout * BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:586
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_kdtree_nd_ free(KDTree *tree)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int round_fl_to_int(float a)
MINLINE int min_ii(int a, int b)
MINLINE int square_i(int a)
MINLINE int max_ii(int a, int b)
void copy_qt_qt(float q[4], const float a[4])
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE int len_manhattan_v2v2_int(const int a[2], const int b[2]) ATTR_WARN_UNUSED_RESULT
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
int BLI_rcti_length_x(const rcti *rect, int x)
Definition rct.c:149
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.c:560
int BLI_rcti_length_y(const rcti *rect, int y)
Definition rct.c:160
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
#define CLAMP(a, b, c)
#define ARRAY_SIZE(arr)
#define ELEM(...)
#define IS_EQF(a, b)
#define IN_RANGE_INCL(a, b, c)
#define TIP_(msgid)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
Main * DEG_get_bmain(const Depsgraph *graph)
@ ID_RECALC_FRAME_CHANGE
Definition DNA_ID.h:1092
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ ADS_FILTER_ONLYSEL
@ SACTCONT_TIMELINE
@ FCURVE_ACTIVE
@ FCURVE_SELECTED
@ CU_3D
#define OB_MODE_ALL_WEIGHT_PAINT
@ OB_MODE_EDIT
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
@ OB_HIDE_VIEWPORT
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_MESH
@ OB_CURVES_LEGACY
@ OB_GPENCIL_LEGACY
#define PSFRA
@ AUDIO_SYNC
#define FPS
@ SCE_FRAME_DROP
@ SCE_KEYS_NO_SELONLY
#define PRVRANGEON
#define PEFRA
#define HEADERY
#define RGN_ALIGN_ENUM_FROM_MASK(align)
@ RGN_SPLIT_SCALE_PREV
@ RGN_ALIGN_HIDE_WITH_PREV
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_TOP
@ RGN_ALIGN_RIGHT
@ RGN_SPLIT_PREV
@ RGN_ALIGN_NONE
@ RGN_ALIGN_QSPLIT
#define AREAMAP_FROM_SCREEN(screen)
@ AREA_FLAG_ACTIONZONES_UPDATE
@ HEADER_NO_PULLDOWN
#define AREAMINX
@ RGN_FLAG_RESIZE_RESPECT_BUTTON_SECTIONS
@ RGN_FLAG_HIDDEN
@ RGN_FLAG_NO_USER_RESIZE
@ RGN_FLAG_TOO_SMALL
@ RGN_FLAG_HIDDEN_BY_USER
eRegion_Type
@ RGN_TYPE_TOOL_HEADER
@ RGN_TYPE_UI
@ RGN_TYPE_ASSET_SHELF_HEADER
@ RGN_TYPE_WINDOW
@ RGN_TYPE_PREVIEW
@ RGN_TYPE_NAV_BAR
@ RGN_TYPE_FOOTER
@ RGN_TYPE_HEADER
eScreen_Redraws_Flag
@ TIME_SEQ
@ TIME_ALL_IMAGE_WIN
@ TIME_ALL_BUTS_WIN
@ TIME_FOLLOW
@ TIME_REGION
@ TIME_ALL_3D_WIN
@ TIME_SPREADSHEETS
@ TIME_CLIPS
@ TIME_NODES
@ TIME_ALL_ANIM_WIN
#define AREAGRID
@ SCREENFULL
@ SCREENMAXIMIZED
@ SCREENNORMAL
eFileSel_File_Types
@ FILE_TYPE_BLENDER
@ FILE_TYPE_BLENDER_BACKUP
eSpace_Type
@ SPACE_CLIP
@ SPACE_ACTION
@ SPACE_CONSOLE
@ SPACE_OUTLINER
@ SPACE_STATUSBAR
@ SPACE_TOPBAR
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPACE_USERPREF
@ SPACE_FILE
@ SPACE_PROPERTIES
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_EMPTY
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SPACE_INFO
@ SIPO_MODE_DRIVERS
#define SPACE_TYPE_ANY
#define FRAMENUMBER_MIN_CLAMP(cfra)
@ USER_SHOW_FPS
#define UI_SCALE_FAC
@ V2D_SCROLL_LEFT
@ V2D_SCROLL_HORIZONTAL
@ V2D_SCROLL_TOP
@ V2D_SCROLL_RIGHT
@ V2D_SCROLL_BOTTOM
@ V2D_SCROLL_VERTICAL
@ V2D_IS_INIT
@ V2D_KEEPTOT_STRICT
@ RV3D_VIEW_AXIS_ROLL_0
@ RV3D_VIEWLOCK_INIT
@ RV3D_GPULIGHT_UPDATE
@ RV3D_VIEW_CAMERA
@ RV3D_VIEW_USER
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_ORTHO
@ RV3D_LOCK_ROTATION
@ RV3D_BOXCLIP
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ ACHANNEL_SETFLAG_CLEAR
@ ANIMTYPE_FCURVE
eAnimCont_Types
@ ANIMCONT_DRIVERS
eAnimFilter_Flags
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_NODUPLIS
void ED_drivers_editor_init(bContext *C, ScrArea *area)
bool ED_fileselect_is_file_browser(const SpaceFile *sfile)
Definition filesel.cc:462
bool ED_fileselect_is_asset_browser(const SpaceFile *sfile)
Definition filesel.cc:467
bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
Mesh * ED_mesh_context(bContext *C)
void ED_scene_fps_average_accumulate(Scene *scene, short fps_samples, double ltime) ATTR_NONNULL(1)
Definition scene_fps.cc:92
bool void ED_scene_fps_average_clear(Scene *scene) ATTR_NONNULL(1)
Definition scene_fps.cc:71
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
void ED_screen_global_areas_sync(wmWindow *win)
bool ED_workspace_layout_cycle(WorkSpace *workspace, short direction, bContext *C) ATTR_NONNULL()
bool ED_operator_screen_mainwinactive(bContext *C)
void ED_region_toggle_hidden(bContext *C, ARegion *region)
Definition area.cc:2280
int ED_area_global_min_size_y(const ScrArea *area)
Definition area.cc:3686
ScrArea * ED_area_find_under_cursor(const bContext *C, int spacetype, const int event_xy[2])
Definition area.cc:3702
#define ED_screen_verts_iter(win, screen, vert_name)
Definition ED_screen.hh:288
#define ED_screen_areas_iter(win, screen, area_name)
Definition ED_screen.hh:285
bool ED_operator_screenactive(bContext *C)
void ED_area_tag_redraw_no_rebuild(ScrArea *area)
Definition area.cc:717
int ED_area_global_max_size_y(const ScrArea *area)
Definition area.cc:3691
bool ED_area_is_global(const ScrArea *area)
Definition area.cc:3697
void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
Definition area.cc:2570
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:653
int ED_area_headersize()
Definition area.cc:3670
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
bool ED_operator_screenactive_nobackground(bContext *C)
bool ED_operator_region_view3d_active(bContext *C)
void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
Definition area.cc:2258
bool ED_operator_areaactive(bContext *C)
ScrArea * ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, short state)
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
WorkSpaceLayout * ED_workspace_layout_duplicate(Main *bmain, WorkSpace *workspace, const WorkSpaceLayout *layout_old, wmWindow *win) ATTR_NONNULL()
void ED_region_visibility_change_update_ex(bContext *C, ScrArea *area, ARegion *region, bool is_hidden, bool do_init)
Definition area.cc:2239
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2053
void ED_screen_full_prevspace(bContext *C, ScrArea *area)
eScreenCycle
Definition ED_screen.hh:743
@ SPACE_CONTEXT_CYCLE_NEXT
Definition ED_screen.hh:745
@ SPACE_CONTEXT_CYCLE_PREV
Definition ED_screen.hh:744
@ ANIMPLAY_FLAG_JUMPED
@ ANIMPLAY_FLAG_NO_SYNC
@ ANIMPLAY_FLAG_REVERSE
@ ANIMPLAY_FLAG_SYNC
@ ANIMPLAY_FLAG_USE_NEXT_FRAME
@ AZ_SCROLL_HOR
@ AZ_SCROLL_VERT
@ AZONE_REGION
@ AZONE_FULLSCREEN
@ AZONE_REGION_SCROLL
@ AZONE_AREA
@ AE_LEFT_TO_TOPRIGHT
@ AE_RIGHT_TO_TOPLEFT
@ AE_BOTTOM_TO_TOPLEFT
@ AE_TOP_TO_BOTTOMRIGHT
bool ED_space_sequencer_has_playback_animation(const SpaceSeq *sseq, const Scene *scene)
bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_region)
bool ED_view3d_lock(RegionView3D *rv3d)
char ED_view3d_lock_view_from_index(int index)
void ED_view3d_lastview_store(RegionView3D *rv3d)
void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
static AppView * view
bool GPU_mem_stats_supported()
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
#define C
Definition RandGen.cpp:29
#define UI_REGION_OVERLAP_MARGIN
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
#define UI_NAVIGATION_REGION_WIDTH
bool UI_drop_color_poll(bContext *C, wmDrag *drag, const wmEvent *event)
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
void uiItemS(uiLayout *layout)
#define UI_ITEM_NONE
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiBut * UI_context_active_but_prop_get(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_drop_color_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
bool UI_region_button_sections_is_inside_x(const ARegion *region, const int mval_x)
#define UI_UNIT_X
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
void UI_view2d_curRect_validate(View2D *v2d)
Definition view2d.cc:824
char UI_view2d_mouse_in_scrollers_ex(const ARegion *region, const View2D *v2d, const int xy[2], int *r_scroll) ATTR_NONNULL(1
float UI_view2d_view_to_region_y(const View2D *v2d, float y)
Definition view2d.cc:1691
#define V2D_SCROLL_HIDE_WIDTH
Definition UI_view2d.hh:63
float UI_view2d_view_to_region_x(const View2D *v2d, float x)
Definition view2d.cc:1686
#define V2D_SCROLL_HIDE_HEIGHT
Definition UI_view2d.hh:64
@ WIN_ALIGN_LOCATION_CENTER
Definition WM_api.hh:340
@ WIN_ALIGN_ABSOLUTE
Definition WM_api.hh:339
#define ND_SPACE_SEQUENCER
Definition WM_types.hh:501
#define NC_WINDOW
Definition WM_types.hh:342
eWM_EventFlag
Definition WM_types.hh:637
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO_GROUPED
Definition WM_types.hh:187
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_SCREEN
Definition WM_types.hh:344
#define NC_SCENE
Definition WM_types.hh:345
#define NA_EDITED
Definition WM_types.hh:550
#define WM_EVENT_CURSOR_MOTION_THRESHOLD
Definition WM_types.hh:809
#define ND_FRAME
Definition WM_types.hh:401
#define ND_TRANSFORM
Definition WM_types.hh:423
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
#define ND_WORKSPACE_SET
Definition WM_types.hh:395
@ KM_NOTHING
Definition WM_types.hh:283
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
@ WM_DRAG_PATH
Definition WM_types.hh:1160
#define ND_LAYOUTBROWSE
Definition WM_types.hh:389
#define ND_SPACE_SPREADSHEET
Definition WM_types.hh:507
#define ND_LAYOUTDELETE
Definition WM_types.hh:390
#define NC_SPACE
Definition WM_types.hh:359
@ KM_CTRL
Definition WM_types.hh:256
@ KM_ALT
Definition WM_types.hh:257
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type)
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
Definition area.cc:2265
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
Definition area.cc:2285
#define U
ATTR_WARN_UNUSED_RESULT const BMVert * v2
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
bool closest(btVector3 &v)
void item_bool(std::string text, bool inverted, int icon1, int icon2=0)
Definition area.cc:924
void item(std::string text, int icon1, int icon2=0)
Definition area.cc:908
int64_t size() const
const T & last(const int64_t n=0) const
IndexRange index_range() const
int64_t first_index_of(const T &value) const
const T & first() const
static float is_left(const float p0[2], const float p1[2], const float p2[2])
#define printf
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
int count
void mask_to_keylist(bDopeSheet *, MaskLayer *masklay, AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, AnimKeylist *keylist, const bool active)
void scene_to_keylist(bDopeSheet *ads, Scene *sce, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void ob_to_keylist(bDopeSheet *ads, Object *ob, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void grease_pencil_data_block_to_keylist(AnimData *adt, const GreasePencil *grease_pencil, AnimKeylist *keylist, const int saction_flag, const bool active_layer_only)
void ED_keylist_prepare_for_direct_access(AnimKeylist *keylist)
AnimKeylist * ED_keylist_create()
void ED_keylist_free(AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static int box_select_exec(bContext *C, wmOperator *op)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float4 mask(const int4 mask, const float4 a)
static ulong * next
static ulong state[N]
#define G(x, y, z)
Object * context_active_object(const bContext *C)
VecBase< int32_t, 2 > int2
Object * ED_pose_object_from_context(bContext *C)
Definition pose_edit.cc:59
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
int RNA_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_enum_name_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_name)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_int_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const int *default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_region_type_items[]
Definition rna_screen.cc:24
const EnumPropertyItem rna_enum_space_type_items[]
Definition rna_space.cc:97
const EnumPropertyItem rna_enum_preference_section_items[]
void screen_draw_dock_preview(ScrArea *source, ScrArea *target, AreaDockTarget dock_target, float factor, int x, int y)
void screen_draw_split_preview(ScrArea *area, const eScreenAxis dir_axis, const float factor)
void screen_draw_move_highlight(bScreen *screen, eScreenAxis dir_axis)
void screen_draw_join_highlight(const wmWindow *win, ScrArea *sa1, ScrArea *sa2, eScreenDir dir)
void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2)
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
ScrArea * area_split(const wmWindow *win, bScreen *screen, ScrArea *area, const eScreenAxis dir_axis, const float fac, const bool merge)
bool screen_area_close(bContext *C, bScreen *screen, ScrArea *area)
ScrEdge * screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map, const rcti *bounds_rect, const int mx, const int my)
ScrEdge * screen_geom_find_active_scredge(const wmWindow *win, const bScreen *screen, const int mx, const int my)
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
bool screen_geom_edge_is_horizontal(ScrEdge *se)
int screen_geom_area_width(const ScrArea *area)
int screen_geom_area_height(const ScrArea *area)
void SCREEN_OT_screenshot(wmOperatorType *ot)
#define AZONESPOTW
eScreenAxis
@ SCREEN_AXIS_V
@ SCREEN_AXIS_H
#define AZONEFADEIN
void SCREEN_OT_screenshot_area(wmOperatorType *ot)
#define SCREEN_DIR_IS_VERTICAL(dir)
eScreenDir
@ SCREEN_DIR_W
@ SCREEN_DIR_N
@ SCREEN_DIR_E
@ SCREEN_DIR_S
@ SCREEN_DIR_NONE
#define AZONEFADEOUT
AreaDockTarget
static bool blend_file_drop_poll(bContext *, wmDrag *drag, const wmEvent *)
static void screen_animation_region_tag_redraw(bContext *C, ScrArea *area, ARegion *region, const Scene *scene, eScreen_Redraws_Flag redraws)
static float area_split_factor(bContext *C, sAreaJoinData *jd, const wmEvent *event)
static void view3d_localview_update_rv3d(RegionView3D *rv3d)
bool ED_operator_spreadsheet_active(bContext *C)
bool ED_operator_region_outliner_active(bContext *C)
static void SCREEN_OT_area_options(wmOperatorType *ot)
bool ED_operator_editarmature(bContext *C)
static int frame_jump_exec(bContext *C, wmOperator *op)
static void area_dupli_fn(bScreen *, ScrArea *area, void *user_data)
static int screen_context_menu_invoke(bContext *C, wmOperator *, const wmEvent *)
static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
static int area_split_exec(bContext *C, wmOperator *op)
static bool ed_operator_posemode_exclusive_ex(bContext *C, Object *obact)
static int redo_last_invoke(bContext *C, wmOperator *, const wmEvent *)
static void area_swap_cancel(bContext *C, wmOperator *op)
static void actionzone_exit(wmOperator *op)
static void SCREEN_OT_region_context_menu(wmOperatorType *ot)
static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis)
static void keymap_modal_set(wmKeyConfig *keyconf)
static void SCREEN_OT_region_scale(wmOperatorType *ot)
#define KM_MODAL_APPLY
Definition screen_ops.cc:86
static int screen_maximize_area_exec(bContext *C, wmOperator *op)
static void fullscreen_click_rcti_init(rcti *rect, const short, const short, const short x2, const short y2)
bool ED_operator_uvmap(bContext *C)
static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_operator_graphedit_active(bContext *C)
bool ED_operator_action_active(bContext *C)
bool ED_operator_sequencer_active_editable(bContext *C)
bool ED_operator_animview_active(bContext *C)
static int area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_operator_node_editable(bContext *C)
static void SCREEN_OT_info_log_show(wmOperatorType *ot)
bool ED_operator_screen_mainwinactive(bContext *C)
static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
static int area_max_regionsize(ScrArea *area, ARegion *scale_region, AZEdge edge)
static bool area_split_menu_init(bContext *C, wmOperator *op)
AZone * ED_area_actionzone_find_xy(ScrArea *area, const int xy[2])
static void area_move_set_limits(wmWindow *win, bScreen *screen, const eScreenAxis dir_axis, int *bigger, int *smaller, bool *use_bigger_smaller_snap)
static void region_scale_validate_size(RegionMoveData *rmd)
static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool keyframe_jump_poll(bContext *C)
static bool space_context_cycle_poll(bContext *C)
static bool area_split_apply(bContext *C, wmOperator *op)
bool ED_operator_console_active(bContext *C)
static void context_cycle_prop_get(bScreen *screen, const ScrArea *area, PointerRNA *r_ptr, PropertyRNA **r_prop)
float ED_region_blend_alpha(ARegion *region)
static void SCREEN_OT_animation_play(wmOperatorType *ot)
static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *sa2)
static void SCREEN_OT_workspace_cycle(wmOperatorType *ot)
#define KM_MODAL_CANCEL
Definition screen_ops.cc:85
static void area_move_exit(bContext *C, wmOperator *op)
bool ED_operator_info_active(bContext *C)
static void area_join_dock_cb_window(sAreaJoinData *jd, wmOperator *op)
void ED_keymap_screen(wmKeyConfig *keyconf)
static int screen_animation_play_exec(bContext *C, wmOperator *op)
static int area_snap_calc_location(const bScreen *screen, const enum AreaMoveSnapType snap_type, const int delta, const int origval, const eScreenAxis dir_axis, const int bigger, const int smaller)
static void SCREEN_OT_userpref_show(wmOperatorType *ot)
bool ED_operator_editable_mesh(bContext *C)
static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event)
#define TIMEOUT
static void SCREEN_OT_actionzone(wmOperatorType *ot)
static int screen_delete_exec(bContext *C, wmOperator *)
static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void actionzone_apply(bContext *C, wmOperator *op, int type)
bool ED_operator_scene(bContext *C)
bool ED_operator_object_active_local_editable(bContext *C)
static int region_toggle_exec(bContext *C, wmOperator *op)
bool ED_operator_screenactive(bContext *C)
#define KM_MODAL_SNAP_ON
Definition screen_ops.cc:87
bool ED_operator_regionactive(bContext *C)
Definition screen_ops.cc:94
static void area_actionzone_get_rect(AZone *az, rcti *r_rect)
static bool actionzone_area_poll(bContext *C)
bool ED_operator_editsurfcurve_region_view3d(bContext *C)
static float area_docking_snap(const float pos, const wmEvent *event)
int ED_screen_animation_play(bContext *C, int sync, int mode)
static int marker_jump_exec(bContext *C, wmOperator *op)
static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
static int header_toggle_menus_exec(bContext *C, wmOperator *)
static bool match_region_with_redraws(const ScrArea *area, eRegion_Type regiontype, eScreen_Redraws_Flag redraws, bool from_anim_edit)
static void SCREEN_OT_back_to_previous(wmOperatorType *ot)
static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
static bool space_type_set_or_cycle_poll(bContext *C)
static int drivers_editor_show_exec(bContext *C, wmOperator *op)
static bool ed_spacetype_test(bContext *C, int type)
static int area_join_cursor(sAreaJoinData *jd, const wmEvent *event)
bool ED_operator_object_active(bContext *C)
bool ED_operator_editsurfcurve(bContext *C)
static void SCREEN_OT_frame_jump(wmOperatorType *ot)
static void SCREEN_OT_area_close(wmOperatorType *ot)
static void SCREEN_OT_redo_last(wmOperatorType *ot)
static int space_type_set_or_cycle_exec(bContext *C, wmOperator *op)
AreaMoveSnapType
@ SNAP_FRACTION_AND_ADJACENT
@ SNAP_BIGGER_SMALLER_ONLY
@ SNAP_NONE
@ SNAP_AREAGRID
static void actionzone_cancel(bContext *, wmOperator *op)
static bool area_swap_init(wmOperator *op, const wmEvent *event)
static void area_move_apply(bContext *C, wmOperator *op)
#define TIMESTEP
bool ED_operator_editcurve_3d(bContext *C)
bool ED_operator_objectmode(bContext *C)
static int screen_new_exec(bContext *C, wmOperator *)
static bool area_split_init(bContext *C, wmOperator *op)
bool ED_operator_sequencer_active(bContext *C)
static void SCREEN_OT_animation_step(wmOperatorType *ot)
static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
bScreen * ED_screen_animation_no_scrub(const wmWindowManager *wm)
static int area_join_exec(bContext *C, wmOperator *op)
bool ED_operator_scene_editable(bContext *C)
bool ED_operator_asset_browsing_active(bContext *C)
static int repeat_last_exec(bContext *C, wmOperator *)
static int screen_animation_step_invoke(bContext *C, wmOperator *, const wmEvent *event)
static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void SCREEN_OT_delete(wmOperatorType *ot)
bool ED_operator_objectmode_with_view3d_poll_msg(bContext *C)
static AZone * area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const bool test_only)
bool ED_operator_image_active(bContext *C)
static void SCREEN_OT_space_type_set_or_cycle(wmOperatorType *ot)
void ED_operatortypes_screen()
bool ED_operator_view3d_active(bContext *C)
void ED_screens_region_flip_menu_create(bContext *C, uiLayout *layout, void *)
static const EnumPropertyItem prop_direction_items[]
static int info_log_show_exec(bContext *C, wmOperator *op)
static int spacedata_cleanup_exec(bContext *C, wmOperator *op)
bool ED_operator_node_active(bContext *C)
static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
static bool azone_clipped_rect_calc(const AZone *az, rcti *r_rect_clip)
static bool repeat_history_poll(bContext *C)
bool ED_operator_posemode_local(bContext *C)
static void SCREEN_OT_frame_offset(wmOperatorType *ot)
static void area_docking_apply(bContext *C, wmOperator *op)
static ScrArea * screen_actionzone_area(bScreen *screen, const AZone *az)
static int repeat_history_exec(bContext *C, wmOperator *op)
bool ED_operator_nla_active(bContext *C)
static AZone * screen_actionzone_find_xy(bScreen *screen, const int xy[2])
bool ED_operator_object_active_local_editable_ex(bContext *C, const Object *ob)
bool ED_operator_screenactive_nobackground(bContext *C)
bool ED_operator_uvedit_space_image(bContext *C)
static void region_scale_exit(wmOperator *op)
static void SCREEN_OT_space_context_cycle(wmOperatorType *ot)
bool ED_operator_region_view3d_active(bContext *C)
bool ED_operator_object_active_editable(bContext *C)
static void area_join_update_data(bContext *C, sAreaJoinData *jd, const wmEvent *event)
bool ED_operator_posemode_exclusive(bContext *C)
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
static bool region_toggle_poll(bContext *C)
static ScrEdge * area_findsharededge(bScreen *screen, ScrArea *area, ScrArea *sb)
static int region_quadview_exec(bContext *C, wmOperator *op)
bool ED_operator_editcurve(bContext *C)
static void area_split_exit(bContext *C, wmOperator *op)
static bool area_close_poll(bContext *C)
static void SCREEN_OT_area_swap(wmOperatorType *ot)
static int frame_offset_exec(bContext *C, wmOperator *op)
static void area_swap_exit(bContext *C, wmOperator *op)
bool ED_operator_areaactive(bContext *C)
bool ED_operator_editmesh_region_view3d(bContext *C)
bool ED_operator_file_browsing_active(bContext *C)
static void SCREEN_OT_area_split(wmOperatorType *ot)
void ED_region_visibility_change_update_animated(bContext *C, ScrArea *area, ARegion *region)
AZone * ED_area_azones_update(ScrArea *area, const int xy[2])
static int region_blend_invoke(bContext *C, wmOperator *, const wmEvent *event)
bool ED_operator_object_active_editable_mesh(bContext *C)
static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot)
static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_operator_posemode_context(bContext *C)
static void SCREEN_OT_repeat_history(wmOperatorType *ot)
bool ED_operator_posemode(bContext *C)
bool ED_operator_editmball(bContext *C)
static int area_move_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_new(wmOperatorType *ot)
static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
static int userpref_show_exec(bContext *C, wmOperator *op)
void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *)
bool ED_operator_camera_poll(bContext *C)
static void SCREEN_OT_area_dupli(wmOperatorType *ot)
#define KM_MODAL_SNAP_OFF
Definition screen_ops.cc:88
bool ED_operator_file_active(bContext *C)
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
static bool screen_animation_region_supports_time_follow(eSpace_Type spacetype, eRegion_Type regiontype)
static void SCREEN_OT_region_quadview(wmOperatorType *ot)
static void SCREEN_OT_screen_set(wmOperatorType *ot)
static AreaDockTarget area_docking_target(sAreaJoinData *jd, const wmEvent *event)
static void area_move_draw_cb(const wmWindow *, void *userdata)
bool ED_operator_editmesh_view3d(bContext *C)
static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void area_split_cancel(bContext *C, wmOperator *op)
static bool screen_active_editable(bContext *C)
bool ED_operator_object_active_local_editable_posemode_exclusive(bContext *C)
static bool ED_operator_screenactive_norender(bContext *C)
static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void area_move_apply_do(bContext *C, int delta, const int origval, const eScreenAxis dir_axis, const int bigger, const int smaller, const enum AreaMoveSnapType snap_type)
static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void region_scale_cancel(bContext *, wmOperator *op)
bool ED_operator_editsurf(bContext *C)
static void SCREEN_OT_repeat_last(wmOperatorType *ot)
static bool area_join_apply(bContext *C, wmOperator *op)
static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void region_blend_end(bContext *C, ARegion *region, const bool is_running)
static void SCREEN_OT_drivers_editor_show(wmOperatorType *ot)
static void areas_do_frame_follow(bContext *C, bool middle)
bool ED_operator_object_active_editable_ex(bContext *C, const Object *ob)
static void SCREEN_OT_area_move(wmOperatorType *ot)
static void SCREEN_OT_marker_jump(wmOperatorType *ot)
bool ED_operator_editlattice(bContext *C)
static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int fullscreen_back_exec(bContext *C, wmOperator *op)
bool ED_operator_outliner_active_no_editobject(bContext *C)
static bool region_flip_poll(bContext *C)
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *)
bool ED_operator_editmesh(bContext *C)
static void ed_screens_statusbar_menu_create(uiLayout *layout, void *)
static bool ed_object_hidden(const Object *ob)
static const EnumPropertyItem space_context_cycle_direction[]
static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *)
bool ED_operator_uvedit(bContext *C)
static int region_flip_exec(bContext *C, wmOperator *)
static void area_join_cancel(bContext *C, wmOperator *op)
bool ED_operator_outliner_active(bContext *C)
bool ED_operator_object_active_editable_font(bContext *C)
static void region_quadview_init_rv3d(ScrArea *area, ARegion *region, const char viewlock, const char view, const char persp)
static void SCREEN_OT_region_flip(wmOperatorType *ot)
bool ED_operator_region_gizmo_active(bContext *C)
static void area_join_exit(bContext *C, wmOperator *op)
static void area_join_dock_cb(const wmWindow *, void *userdata)
static bool area_move_init(bContext *C, wmOperator *op)
static void area_move_cancel(bContext *C, wmOperator *op)
static void blend_file_drop_copy(bContext *, wmDrag *drag, wmDropBox *drop)
bool ED_operator_objectmode_poll_msg(bContext *C)
static int area_close_exec(bContext *C, wmOperator *op)
static bool screen_maximize_area_poll(bContext *C)
static void SCREEN_OT_region_blend(wmOperatorType *ot)
static int area_swap_exec(bContext *C, wmOperator *op)
bool ED_operator_buttons_active(bContext *C)
static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void area_join_draw_cb(const wmWindow *win, void *userdata)
static int keyframe_jump_exec(bContext *C, wmOperator *op)
static ScrEdge * screen_area_edge_from_cursor(const bContext *C, const int cursor[2], ScrArea **r_sa1, ScrArea **r_sa2)
static int screen_set_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_region_toggle(wmOperatorType *ot)
static bool area_dupli_open(bContext *C, ScrArea *area, const blender::int2 position)
static void SCREEN_OT_area_join(wmOperatorType *ot)
bool ED_operator_editfont(bContext *C)
static void area_split_draw_cb(const wmWindow *, void *userdata)
static std::string userpref_show_get_description(bContext *C, wmOperatorType *, PointerRNA *ptr)
static bool is_split_edge(const int alignment, const AZEdge edge)
#define FLT_MAX
Definition stdcycles.h:14
void(* on_user_resize)(const ARegion *region)
int(* snap_size)(const ARegion *region, int size, int axis)
struct wmTimer * regiontimer
void * regiondata
struct ARegion * prev
struct ARegion * next
struct wmGizmoMap * gizmo_map
struct ARegionType * type
float alpha
AZEdge edge
ARegion * region
AZone * next
AZScrollDirection direction
ActKeyColumn * prev
ActKeyColumn * next
int totface
EditNurb * editnurb
Definition DNA_ID.h:413
unsigned int recalc
Definition DNA_ID.h:437
int icon_id
Definition DNA_ID.h:436
void * last
void * first
ListBase screens
Definition BKE_main.hh:225
ListBase workspaces
Definition BKE_main.hh:246
short visibility_flag
void * data
Definition RNA_types.hh:42
ARegion * child_region
ARegion * region
struct RegionView3D * localvd
struct RenderData r
ListBase markers
struct AudioData audio
ListBase areabase
ScrVert * v2
ListBase actionzones
ScrVert * v3
ListBase spacedata
struct SpaceType * type
bScreen * full
ScrVert * v1
ListBase regionbase
ScrGlobalAreaData * global
ScrVert * v4
ScrVert * v1
ScrVert * v2
struct bNodeTree * edittree
char alpha_vert
short keeptot
struct Object * camera
Wrapper for bScreen.
eAnimCont_Types datatype
short redraws_flag
ListBase vertbase
struct wmTimer * animtimer
ListBase areabase
struct ARegion * active_region
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
eScreenDir gesture_dir
wmWindow * draw_dock_win
ScrArea * sa1
eScreenAxis split_dir
wmWindow * win1
AreaDockTarget dock_target
void * draw_dock_callback
wmWindow * win2
eScreenDir dir
void * draw_callback
ScrArea * sa2
eScreenAxis dir_axis
AreaMoveSnapType snap_type
void * draw_callback
bScreen * screen
ScrEdge * nedge
ScrArea * narea
ScrArea * sarea
ScrArea * sa1
ScrArea * sa2
short y
short x
eWM_DragDataType type
Definition WM_types.hh:1282
PointerRNA * ptr
Definition WM_types.hh:1368
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
uint8_t modifier
Definition WM_types.hh:739
short type
Definition WM_types.hh:722
void * customdata
Definition WM_types.hh:772
const char * idname
Definition WM_types.hh:992
struct ReportList * reports
struct wmOperator * prev
struct wmOperatorType * type
struct PointerRNA * ptr
double time_delta
Definition WM_types.hh:927
void * customdata
Definition WM_types.hh:922
double time_duration
Definition WM_types.hh:925
double time_step
Definition WM_types.hh:916
double time_last
Definition WM_types.hh:930
struct wmEvent * eventstate
ScrAreaMap global_areas
struct WorkSpaceInstanceHook * workspace_hook
ccl_device_inline int abs(int x)
Definition util/math.h:120
wmTimer * timer
void WM_operator_free_all_after(wmWindowManager *wm, wmOperator *op)
Definition wm.cc:318
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_set(wmWindow *win, int curs)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_DEFAULT
Definition wm_cursors.hh:15
@ WM_CURSOR_HAND_CLOSED
Definition wm_cursors.hh:23
@ WM_CURSOR_H_SPLIT
Definition wm_cursors.hh:40
@ WM_CURSOR_S_ARROW
Definition wm_cursors.hh:47
@ WM_CURSOR_PICK_AREA
Definition wm_cursors.hh:61
@ WM_CURSOR_MOVE
Definition wm_cursors.hh:21
@ WM_CURSOR_E_ARROW
Definition wm_cursors.hh:48
@ WM_CURSOR_EDIT
Definition wm_cursors.hh:19
@ WM_CURSOR_N_ARROW
Definition wm_cursors.hh:46
@ WM_CURSOR_STOP
Definition wm_cursors.hh:18
@ WM_CURSOR_V_SPLIT
Definition wm_cursors.hh:41
@ WM_CURSOR_SWAP_AREA
Definition wm_cursors.hh:37
@ WM_CURSOR_W_ARROW
Definition wm_cursors.hh:49
wmDropBox * WM_dropbox_add(ListBase *lb, const char *idname, bool(*poll)(bContext *C, wmDrag *drag, const wmEvent *event), void(*copy)(bContext *C, wmDrag *drag, wmDropBox *drop), void(*cancel)(Main *bmain, wmDrag *drag, wmDropBox *drop), WMDropboxTooltipFunc tooltip)
int WM_drag_get_path_file_type(const wmDrag *drag)
const char * WM_drag_get_single_path(const wmDrag *drag)
ListBase * WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
int xy[2]
Definition wm_draw.cc:170
void * WM_draw_cb_activate(wmWindow *win, void(*draw)(const wmWindow *win, void *customdata), void *customdata)
Definition wm_draw.cc:607
void WM_draw_cb_exit(wmWindow *win, void *handle)
Definition wm_draw.cc:620
int WM_operator_repeat_last(bContext *C, wmOperator *op)
wmEvent * wm_event_add(wmWindow *win, const wmEvent *event_to_add)
bool WM_operator_repeat_check(const bContext *, wmOperator *op)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
int WM_operator_repeat(bContext *C, wmOperator *op)
void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void wm_event_init_from_window(wmWindow *win, wmEvent *event)
void WM_event_add_mousemove(wmWindow *win)
@ RIGHTMOUSE
@ EVT_MODAL_MAP
@ EVT_RIGHTCTRLKEY
@ EVT_ACTIONZONE_FULLSCREEN
@ EVT_ACTIONZONE_REGION
@ EVT_TABKEY
@ EVT_LEFTCTRLKEY
@ EVT_ACTIONZONE_AREA
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
@ EVT_ESCKEY
@ WINDEACTIVATE
@ TIMERREGION
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:933
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:897
void WM_operator_properties_border(wmOperatorType *ot)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
int WM_operator_redo_popup(bContext *C, wmOperator *op)
bool WM_operator_winactive(bContext *C)
wmOperator * WM_operator_last_redo(const bContext *C)
void WM_window_native_pixel_coords(const wmWindow *win, int *x, int *y)
bool wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition wm_window.cc:429
wmWindow * WM_window_open(bContext *C, const char *title, const rcti *rect_unscaled, int space_type, bool toplevel, bool dialog, bool temp, eWindowAlignment alignment, void(*area_setup_fn)(bScreen *screen, ScrArea *area, void *user_data), void *area_setup_user_data)
Definition wm_window.cc:950
bool WM_window_is_temp_screen(const wmWindow *win)
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
wmWindow * WM_window_find_by_area(wmWindowManager *wm, const ScrArea *area)
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
void WM_window_title(wmWindowManager *wm, wmWindow *win, const char *title)
Definition wm_window.cc:485
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const int event_type, const double time_step)
bScreen * WM_window_get_active_screen(const wmWindow *win)