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
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/* -------------------------------------------------------------------- */
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 }
138 return ED_operator_screenactive(C);
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);
192 Object *obact = CTX_data_active_object(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{
211 if (!ED_operator_objectmode(C)) {
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{
232 if (ED_operator_areaactive(C)) {
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{
269 if (ED_operator_areaactive(C)) {
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
318{
321 }
322 return false;
323}
324
326{
329 }
330 return false;
331}
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
455{
457 return ((ob != nullptr) && ID_IS_EDITABLE(ob) && !ed_object_hidden(ob) &&
458 (ob->type == OB_MESH) && ID_IS_EDITABLE(ob->data) && !ID_IS_OVERRIDE_LIBRARY(ob->data));
459}
460
462{
464 return ((ob != nullptr) && ID_IS_EDITABLE(ob) && !ed_object_hidden(ob) &&
465 (ob->type == OB_FONT) && ID_IS_EDITABLE(ob->data) && !ID_IS_OVERRIDE_LIBRARY(ob->data));
466}
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
537 if (!ed_operator_posemode_exclusive_ex(C, obact)) {
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{
564 Object *obact = CTX_data_active_object(C);
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
702/* -------------------------------------------------------------------- */
707{
709 /* no full window splitting allowed */
710 if (CTX_wm_screen(C)->state != SCREENNORMAL) {
711 return false;
712 }
713 return true;
714 }
715 return false;
716}
717
720/* -------------------------------------------------------------------- */
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;
988 area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
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;
995 area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
997 }
998 else if (az->direction == AZ_SCROLL_HOR) {
999 az->alpha = az->region->v2d.alpha_hor = 0;
1000 area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
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
1263
1264 /* flags */
1266
1267 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "Modifier", "Modifier state", 0, 2);
1268}
1269
1272/* -------------------------------------------------------------------- */
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
1316/* -------------------------------------------------------------------- */
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
1363{
1366 ED_workspace_status_text(C, nullptr);
1367}
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
1452
1454
1455 /* rna */
1457 ot->srna, "cursor", 2, nullptr, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX);
1458}
1459
1462/* -------------------------------------------------------------------- */
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
1533}
1534
1537/* -------------------------------------------------------------------- */
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";
1609}
1610
1613/* -------------------------------------------------------------------- */
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
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
2141/* -------------------------------------------------------------------- */
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
2710
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
2725/* -------------------------------------------------------------------- */
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
3087
3089
3090 /* flags */
3092}
3093
3096/* -------------------------------------------------------------------- */
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;
3160 FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
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
3179
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
3190/* -------------------------------------------------------------------- */
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
3241
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
3253/* -------------------------------------------------------------------- */
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 {
3301 Mask *mask = CTX_data_edit_mask(C);
3302 if (mask) {
3303 MaskLayer *masklay = BKE_mask_layer_active(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
3370
3373 ot->undo_group = "Frame Change";
3374
3375 /* properties */
3376 RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
3377}
3378
3381/* -------------------------------------------------------------------- */
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
3434
3437 ot->undo_group = "Frame Change";
3438
3439 /* properties */
3440 RNA_def_boolean(ot->srna, "next", true, "Next Marker", "");
3441}
3442
3445/* -------------------------------------------------------------------- */
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
3470
3471 /* rna */
3472 RNA_def_int(ot->srna, "delta", 1, -1, 1, "Delta", "", -1, 1);
3473}
3474
3477/* -------------------------------------------------------------------- */
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
3552/* -------------------------------------------------------------------- */
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);
3802 WM_event_add_notifier(C, NC_WINDOW, nullptr);
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 }
3837
3838 if (same_area) {
3840 return;
3841 }
3842
3843 if (!aligned_neighbors || !screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)) {
3844 ED_area_swapspace(C, jd->sa2, jd->sa1);
3847 {
3848 jd->close_win = true;
3849 }
3850 else {
3852 }
3853 }
3854
3855 if (jd && jd->sa2 == CTX_wm_area(C)) {
3856 CTX_wm_area_set(C, nullptr);
3857 CTX_wm_region_set(C, nullptr);
3858 }
3859}
3860
3861static int area_join_cursor(sAreaJoinData *jd, const wmEvent *event)
3862{
3863 if (!jd->sa2 && jd->dock_target == AreaDockTarget::None) {
3864 /* Mouse outside window, so can open new window. */
3865 if (event->xy[0] < 0 || event->xy[0] > jd->win1->sizex || event->xy[1] < 1 ||
3866 event->xy[1] > jd->win1->sizey)
3867 {
3868 return WM_CURSOR_PICK_AREA;
3869 }
3870 return WM_CURSOR_STOP;
3871 }
3872
3873 if (jd->win2 && jd->win2->workspace_hook) {
3875 if (screen && screen->temp) {
3876 return WM_CURSOR_STOP;
3877 }
3878 }
3879
3880 if (jd->sa1 && jd->sa1 == jd->sa2) {
3881 if (jd->split_fac >= 0.0001f) {
3882 /* Mouse inside source area, so allow splitting. */
3884 }
3885 return WM_CURSOR_EDIT;
3886 }
3887
3888 if (jd->dir != SCREEN_DIR_NONE || jd->dock_target != AreaDockTarget::None) {
3889#if defined(__APPLE__)
3890 return WM_CURSOR_HAND_CLOSED;
3891#else
3892 return WM_CURSOR_MOVE;
3893#endif
3894 }
3895
3896 return WM_CURSOR_PICK_AREA;
3897}
3898
3899static float area_docking_snap(const float pos, const wmEvent *event)
3900{
3901 const bool alt = event->modifier & KM_ALT;
3902 const bool ctrl = event->modifier & KM_CTRL;
3903 const float accel = (alt || ctrl) ? 2.5f : 2.0;
3904
3905 float factor = pos * accel;
3906
3907 if (!alt) {
3908 if (factor >= 0.4375f && factor < 0.5f) {
3909 factor = 0.499999f;
3910 }
3911 else if (factor >= 0.5f && factor < 0.5625f) {
3912 factor = 0.500001f;
3913 }
3914 }
3915
3916 if (ctrl) {
3917 if (factor < 0.1875f) {
3918 factor = 0.125f;
3919 }
3920 else if (factor >= 0.1875f && factor < 0.3125f) {
3921 factor = 0.25f;
3922 }
3923 else if (factor >= 0.3125f && factor < 0.4375f) {
3924 factor = 0.375f;
3925 }
3926 else if (factor >= 0.5625f && factor < 0.6875f) {
3927 factor = 0.625f;
3928 }
3929 else if (factor >= 0.6875f && factor < 0.8125f) {
3930 factor = 0.75f;
3931 }
3932 else if (factor > 0.8125f) {
3933 factor = 0.875f;
3934 }
3935 }
3936
3937 return factor;
3938}
3939
3941{
3942 if (!jd->sa2 || !jd->win2) {
3943 return AreaDockTarget::None;
3944 }
3945
3946 if (jd->sa1 == jd->sa2) {
3947 return AreaDockTarget::None;
3948 }
3949
3950 if (jd->win2 && jd->win2->workspace_hook) {
3952 if (screen && screen->temp) {
3953 return AreaDockTarget::None;
3954 }
3955 }
3956
3957 /* Convert to local coordinates in sa2. */
3958 int win1_posx = jd->win1->posx;
3959 int win1_posy = jd->win1->posy;
3960 int win2_posx = jd->win2->posx;
3961 int win2_posy = jd->win2->posy;
3962 WM_window_native_pixel_coords(jd->win1, &win1_posx, &win1_posy);
3963 WM_window_native_pixel_coords(jd->win2, &win2_posx, &win2_posy);
3964
3965 const int x = event->xy[0] + win1_posx - win2_posx - jd->sa2->totrct.xmin;
3966 const int y = event->xy[1] + win1_posy - win2_posy - jd->sa2->totrct.ymin;
3967
3968 jd->current_x = x + jd->sa2->totrct.xmin;
3969 jd->current_y = y + jd->sa2->totrct.ymin;
3970
3971 const float fac_x = float(x) / float(jd->sa2->winx);
3972 const float fac_y = float(y) / float(jd->sa2->winy);
3973 const int min_x = 2 * AREAMINX * UI_SCALE_FAC;
3974 const int min_y = 2 * HEADERY * UI_SCALE_FAC;
3975
3976 if (ELEM(jd->dir, SCREEN_DIR_N, SCREEN_DIR_S)) {
3977 /* Up or Down to immediate neighbor. */
3978 if (event->xy[0] <= jd->sa1->totrct.xmax && event->xy[0] >= jd->sa1->totrct.xmin) {
3979 const int join_y = std::min(jd->sa2->winy * 0.25f, 5 * HEADERY * UI_SCALE_FAC);
3980 if (jd->sa2->winy < min_y || (jd->dir == SCREEN_DIR_N && y < join_y) ||
3981 (jd->dir == SCREEN_DIR_S && (jd->sa2->winy - y) < join_y))
3982 {
3983 return AreaDockTarget::None;
3984 }
3985 }
3986 }
3987
3988 if (ELEM(jd->dir, SCREEN_DIR_W, SCREEN_DIR_E)) {
3989 /* Left or Right to immediate neighbor. */
3990 if (event->xy[1] <= jd->sa1->totrct.ymax && event->xy[1] >= jd->sa1->totrct.ymin) {
3991 const int join_x = std::min(jd->sa2->winx * 0.25f, 5 * AREAMINX * UI_SCALE_FAC);
3992 if (jd->sa2->winx < min_x || (jd->dir == SCREEN_DIR_W && (jd->sa2->winx - x) < join_x) ||
3993 (jd->dir == SCREEN_DIR_E && x < join_x))
3994 {
3995 return AreaDockTarget::None;
3996 }
3997 }
3998 }
3999
4000 /* If we've made it here, then there can be no joining possible. */
4001 jd->dir = SCREEN_DIR_NONE;
4002 jd->factor = 0.5f;
4003
4004 /* if the area is narrow then there are only two docking targets. */
4005 if (jd->sa2->winx < min_x) {
4006 if (fac_y > 0.4f && fac_y < 0.6f) {
4008 }
4009 if (float(y) > float(jd->sa2->winy) / 2.0f) {
4010 jd->factor = area_docking_snap(1.0f - float(y) / float(jd->sa2->winy), event);
4011 return AreaDockTarget::Top;
4012 }
4013 else {
4014 jd->factor = area_docking_snap(float(y) / float(jd->sa2->winy), event);
4016 }
4017 }
4018 if (jd->sa2->winy < min_y) {
4019 if (fac_x > 0.4f && fac_x < 0.6f) {
4021 }
4022 if (float(x) > float(jd->sa2->winx) / 2.0f) {
4023 jd->factor = area_docking_snap(1.0f - float(x) / float(jd->sa2->winx), event);
4024 return AreaDockTarget::Right;
4025 }
4026 else {
4027 jd->factor = area_docking_snap(float(x) / float(jd->sa2->winx), event);
4028 return AreaDockTarget::Left;
4029 }
4030 }
4031
4032 /* Are we in the center? But not in same area! */
4033 if (fac_x > 0.4f && fac_x < 0.6f && fac_y > 0.4f && fac_y < 0.6f) {
4035 }
4036
4037 /* Area is large enough for four docking targets. */
4038 const float area_ratio = float(jd->sa2->winx) / float(jd->sa2->winy);
4039 /* Split the area diagonally from top-right to bottom-left. */
4040 const bool upper_left = float(x) / float(y + 1) < area_ratio;
4041 /* Split the area diagonally from top-left to bottom-right. */
4042 const bool lower_left = float(x) / float(jd->sa2->winy - y + 1) < area_ratio;
4043
4044 if (upper_left && !lower_left) {
4045 jd->factor = area_docking_snap(1.0f - float(y) / float(jd->sa2->winy), event);
4046 return AreaDockTarget::Top;
4047 }
4048 if (!upper_left && lower_left) {
4049 jd->factor = area_docking_snap(float(y) / float(jd->sa2->winy), event);
4051 }
4052 if (upper_left && lower_left) {
4053 jd->factor = area_docking_snap(float(x) / float(jd->sa2->winx), event);
4054 return AreaDockTarget::Left;
4055 }
4056 if (!upper_left && !lower_left) {
4057 jd->factor = area_docking_snap(1.0f - float(x) / float(jd->sa2->winx), event);
4058 return AreaDockTarget::Right;
4059 }
4060 return AreaDockTarget::None;
4061}
4062
4063static float area_split_factor(bContext *C, sAreaJoinData *jd, const wmEvent *event)
4064{
4065 float fac = (jd->split_dir == SCREEN_AXIS_V) ?
4066 float(event->xy[0] - jd->sa1->totrct.xmin) / float(jd->sa1->winx + 1) :
4067 float(event->xy[1] - jd->sa1->totrct.ymin) / float(jd->sa1->winy + 1);
4068
4069 if (event->modifier & KM_CTRL) {
4070 /* Snapping on. */
4071
4072 /* Find nearest neighboring vertex. */
4073 const int axis = (jd->split_dir == SCREEN_AXIS_V) ? 0 : 1;
4074 int dist = INT_MAX;
4075 int loc = 0;
4076 LISTBASE_FOREACH (const ScrVert *, v1, &CTX_wm_screen(C)->vertbase) {
4077 const int v_loc = (&v1->vec.x)[axis];
4078 const int v_dist = abs(v_loc - event->xy[axis]);
4079 if (v_dist < dist) {
4080 loc = v_loc;
4081 dist = v_dist;
4082 }
4083 }
4084 float near_fac = (axis) ? float(loc - jd->sa1->totrct.ymin) / float(jd->sa1->winy + 1) :
4085 float(loc - jd->sa1->totrct.xmin) / float(jd->sa1->winx + 1);
4086
4087 /* Rounded to nearest 12th. */
4088 float frac_fac = round(fac * 12.0f) / 12.0f;
4089
4090 /* Use nearest neighbor or fractional, whichever is closest. */
4091 fac = (fabs(near_fac - fac) < fabs(frac_fac - fac)) ? near_fac : frac_fac;
4092 }
4093
4094 return std::clamp(fac, 0.001f, 0.999f);
4095}
4096
4097static void area_join_update_data(bContext *C, sAreaJoinData *jd, const wmEvent *event)
4098{
4099 ScrArea *area = nullptr;
4100
4101 /* TODO: The following is needed until we have linux-specific implementations of
4102 * getWindowUnderCursor. See #130242. Use active window if there are overlapping. */
4103
4104#if (OS_WINDOWS || OS_MAC)
4105 area = ED_area_find_under_cursor(C, SPACE_TYPE_ANY, event->xy);
4106#else
4107 int win_count = 0;
4108 LISTBASE_FOREACH (wmWindow *, win, &CTX_wm_manager(C)->windows) {
4109 int cursor[2];
4110 if (wm_cursor_position_get(win, &cursor[0], &cursor[1])) {
4111 rcti rect;
4112 WM_window_rect_calc(win, &rect);
4113 if (BLI_rcti_isect_pt_v(&rect, cursor)) {
4114 win_count++;
4115 }
4116 }
4117 }
4118
4119 if (win_count > 1) {
4121 }
4122 else {
4123 area = ED_area_find_under_cursor(C, SPACE_TYPE_ANY, event->xy);
4124 }
4125#endif
4126
4128 jd->dir = SCREEN_DIR_NONE;
4130 jd->dir = area_getorientation(jd->sa1, jd->sa2);
4131 jd->dock_target = area_docking_target(jd, event);
4132
4133 if (jd->sa1 == area) {
4134 jd->sa2 = area;
4135 if (!(abs(jd->start_x - event->xy[0]) > (10 * U.pixelsize) ||
4136 abs(jd->start_y - event->xy[1]) > (10 * U.pixelsize)))
4137 {
4138 /* We haven't moved enough to start a split. */
4139 jd->dir = SCREEN_DIR_NONE;
4141 return;
4142 }
4143
4144 jd->split_dir = (abs(event->xy[0] - jd->start_x) > abs(event->xy[1] - jd->start_y)) ?
4147 jd->split_fac = area_split_factor(C, jd, event);
4148 return;
4149 }
4150
4151 jd->sa2 = area;
4153 jd->dir = area_getorientation(jd->sa1, jd->sa2);
4154 jd->dock_target = area_docking_target(jd, event);
4155}
4156
4158{
4159 WM_event_add_notifier(C, NC_WINDOW, nullptr);
4161 area_join_exit(C, op);
4162}
4163
4164/* modal callback while selecting area (space) that will be removed */
4165static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
4166{
4167 if (event->type == WINDEACTIVATE) {
4168 /* This operator can close windows, which can cause it to be re-run. */
4169 area_join_exit(C, op);
4170 return OPERATOR_FINISHED;
4171 }
4172
4173 if (op->customdata == nullptr) {
4174 if (!area_join_init(C, op, nullptr, nullptr)) {
4175 return OPERATOR_CANCELLED;
4176 }
4177 }
4179 if (jd == nullptr) {
4180 return OPERATOR_CANCELLED;
4181 }
4182
4183 /* execute the events */
4184 switch (event->type) {
4185
4186 case MOUSEMOVE: {
4187 area_join_update_data(C, jd, event);
4189 WM_cursor_set(jd->win1, area_join_cursor(jd, event));
4190 WM_event_add_notifier(C, NC_WINDOW, nullptr);
4191
4192 WorkspaceStatus status(C);
4193 if (jd->sa1 && jd->sa1 == jd->sa2) {
4194 status.item(IFACE_("Select Split"), ICON_MOUSE_LMB);
4195 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4196 status.item_bool(IFACE_("Snap"), event->modifier & KM_CTRL, ICON_EVENT_CTRL);
4197 }
4198 else {
4199 if (jd->dock_target == AreaDockTarget::None) {
4200 status.item(IFACE_("Select Area"), ICON_MOUSE_LMB);
4201 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4202 }
4203 else {
4204 status.item(IFACE_("Select Location"), ICON_MOUSE_LMB);
4205 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4206 status.item_bool(IFACE_("Precision"), event->modifier & KM_ALT, ICON_EVENT_ALT);
4207 status.item_bool(IFACE_("Snap"), event->modifier & KM_CTRL, ICON_EVENT_CTRL);
4208 }
4209 }
4210 break;
4211 }
4212 case LEFTMOUSE:
4213 if (event->val == KM_RELEASE) {
4214 area_join_update_data(C, jd, event);
4218 if (jd->sa1 && !jd->sa2) {
4219 /* Break out into new window if we are really outside the source window bounds. */
4220 if (event->xy[0] < 0 || event->xy[0] > jd->win1->sizex || event->xy[1] < 1 ||
4221 event->xy[1] > jd->win1->sizey)
4222 {
4223 /* We have to clear handlers or we get an error in wm_gizmomap_modal_get. */
4225 area_dupli_open(C, jd->sa1, blender::int2(event->xy[0], event->xy[1] - jd->sa1->winy));
4229 {
4230 /* We've pulled a single editor out of the window into empty space.
4231 * Close the source window so we don't end up with a duplicate. */
4232 jd->close_win = true;
4233 }
4234 }
4235 }
4236 }
4237 else if (jd->sa1 && jd->sa1 == jd->sa2) {
4238 /* Same area so split. */
4239 if (area_split_allowed(jd->sa1, jd->split_dir) && jd->split_fac > 0.0001) {
4240 jd->sa2 = area_split(jd->win2,
4242 jd->sa1,
4243 jd->split_dir,
4244 jd->split_fac,
4245 true);
4246
4247 const bool large_v = jd->split_dir == SCREEN_AXIS_V &&
4248 ((jd->start_x < event->xy[0] && jd->split_fac > 0.5f) ||
4249 (jd->start_x > event->xy[0] && jd->split_fac < 0.5f));
4250
4251 const bool large_h = jd->split_dir == SCREEN_AXIS_H &&
4252 ((jd->start_y < event->xy[1] && jd->split_fac > 0.5f) ||
4253 (jd->start_y > event->xy[1] && jd->split_fac < 0.5f));
4254
4255 if (large_v || large_h) {
4256 /* Swap areas to follow old behavior of new area added based on starting location. If
4257 * from above the new area is above, if from below the new area is below, etc. Note
4258 * that this preserves runtime data, unlike ED_area_swapspace. */
4259 std::swap(jd->sa1->v1, jd->sa2->v1);
4260 std::swap(jd->sa1->v2, jd->sa2->v2);
4261 std::swap(jd->sa1->v3, jd->sa2->v3);
4262 std::swap(jd->sa1->v4, jd->sa2->v4);
4263 std::swap(jd->sa1->totrct, jd->sa2->totrct);
4264 std::swap(jd->sa1->winx, jd->sa2->winx);
4265 std::swap(jd->sa1->winy, jd->sa2->winy);
4266 }
4267
4270 }
4271 }
4272 else if (jd->sa1 && jd->sa2 && jd->dock_target != AreaDockTarget::None) {
4273 /* Dock this to the new location. */
4274 area_docking_apply(C, op);
4275 }
4276 else if (jd->sa1 && jd->sa2 && jd->dir != SCREEN_DIR_NONE) {
4277 /* Join to neighbor. */
4278 area_join_apply(C, op);
4279 }
4280 else {
4281 area_join_cancel(C, op);
4282 return OPERATOR_CANCELLED;
4283 }
4284
4285 /* Areas changed, update window titles. */
4286 if (jd->win2 && jd->win2 != jd->win1) {
4288 }
4289 if (jd->win1 && !jd->close_win) {
4291 }
4292
4293 const bool do_close_win = jd->close_win;
4294 wmWindow *close_win = jd->win1;
4295 area_join_exit(C, op);
4296 if (do_close_win) {
4297 wm_window_close(C, CTX_wm_manager(C), close_win);
4298 }
4299
4301 return OPERATOR_FINISHED;
4302 }
4303 break;
4304
4305 case RIGHTMOUSE:
4306 case EVT_ESCKEY:
4307 area_join_cancel(C, op);
4308 return OPERATOR_CANCELLED;
4309 }
4310
4312}
4313
4314/* Operator for joining two areas (space types) */
4316{
4317 /* identifiers */
4318 ot->name = "Join Area";
4319 ot->description = "Join selected areas into new window";
4320 ot->idname = "SCREEN_OT_area_join";
4321
4322 /* api callbacks */
4328
4329 /* flags */
4331
4332 /* rna */
4334 "source_xy",
4335 2,
4336 nullptr,
4337 INT_MIN,
4338 INT_MAX,
4339 "Source location",
4340 "",
4341 INT_MIN,
4342 INT_MAX);
4344 "target_xy",
4345 2,
4346 nullptr,
4347 INT_MIN,
4348 INT_MAX,
4349 "Target location",
4350 "",
4351 INT_MIN,
4352 INT_MAX);
4353}
4354
4357/* -------------------------------------------------------------------- */
4362{
4363 ScrArea *sa1, *sa2;
4364 if (screen_area_edge_from_cursor(C, event->xy, &sa1, &sa2) == nullptr) {
4365 return OPERATOR_CANCELLED;
4366 }
4367
4369 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
4370 uiLayout *layout = UI_popup_menu_layout(pup);
4371
4372 /* Vertical Split */
4374 uiItemFullO(layout,
4375 "SCREEN_OT_area_split",
4376 IFACE_("Vertical Split"),
4377 ICON_SPLIT_VERTICAL,
4378 nullptr,
4381 &ptr);
4382 /* store initial mouse cursor position. */
4383 RNA_int_set_array(&ptr, "cursor", event->xy);
4384 RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V);
4385
4386 /* Horizontal Split */
4387 uiItemFullO(layout,
4388 "SCREEN_OT_area_split",
4389 IFACE_("Horizontal Split"),
4390 ICON_SPLIT_HORIZONTAL,
4391 nullptr,
4394 &ptr);
4395 /* store initial mouse cursor position. */
4396 RNA_int_set_array(&ptr, "cursor", event->xy);
4397 RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H);
4398
4399 if (sa1 && sa2) {
4400 uiItemS(layout);
4401 }
4402
4403 /* Join needs two very similar areas. */
4404 if (sa1 && sa2) {
4405 eScreenDir dir = area_getorientation(sa1, sa2);
4406 if (dir != SCREEN_DIR_NONE) {
4407 uiItemFullO(layout,
4408 "SCREEN_OT_area_join",
4409 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? IFACE_("Join Up") : IFACE_("Join Right"),
4410 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? ICON_AREA_JOIN_UP : ICON_AREA_JOIN,
4411 nullptr,
4414 &ptr);
4415 RNA_int_set_array(&ptr, "source_xy", blender::int2{sa2->totrct.xmin, sa2->totrct.ymin});
4416 RNA_int_set_array(&ptr, "target_xy", blender::int2{sa1->totrct.xmin, sa1->totrct.ymin});
4417
4419 layout,
4420 "SCREEN_OT_area_join",
4421 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? IFACE_("Join Down") : IFACE_("Join Left"),
4422 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? ICON_AREA_JOIN_DOWN : ICON_AREA_JOIN_LEFT,
4423 nullptr,
4426 &ptr);
4427 RNA_int_set_array(&ptr, "source_xy", blender::int2{sa1->totrct.xmin, sa1->totrct.ymin});
4428 RNA_int_set_array(&ptr, "target_xy", blender::int2{sa2->totrct.xmin, sa2->totrct.ymin});
4429
4430 uiItemS(layout);
4431 }
4432 }
4433
4434 /* Swap just needs two areas. */
4435 if (sa1 && sa2) {
4436 uiItemFullO(layout,
4437 "SCREEN_OT_area_swap",
4438 IFACE_("Swap Areas"),
4439 ICON_AREA_SWAP,
4440 nullptr,
4443 &ptr);
4444 RNA_int_set_array(&ptr, "cursor", event->xy);
4445 }
4446
4447 UI_popup_menu_end(C, pup);
4448
4449 return OPERATOR_INTERFACE;
4450}
4451
4453{
4454 /* identifiers */
4455 ot->name = "Area Options";
4456 ot->description = "Operations for splitting and merging";
4457 ot->idname = "SCREEN_OT_area_options";
4458
4459 /* api callbacks */
4461
4463
4464 /* flags */
4466}
4467
4470/* -------------------------------------------------------------------- */
4475{
4476 Main *bmain = CTX_data_main(C);
4477 int tot = 0;
4478
4479 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
4480 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
4481 if (area->spacedata.first != area->spacedata.last) {
4482 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
4483
4484 BLI_remlink(&area->spacedata, sl);
4485 tot += BLI_listbase_count(&area->spacedata);
4486 BKE_spacedata_freelist(&area->spacedata);
4487 BLI_addtail(&area->spacedata, sl);
4488 }
4489 }
4490 }
4491 BKE_reportf(op->reports, RPT_INFO, "Removed amount of editors: %d", tot);
4492
4493 return OPERATOR_FINISHED;
4494}
4495
4497{
4498 /* identifiers */
4499 ot->name = "Clean Up Space Data";
4500 ot->description = "Remove unused settings for invisible editors";
4501 ot->idname = "SCREEN_OT_spacedata_cleanup";
4502
4503 /* api callbacks */
4506}
4507
4510/* -------------------------------------------------------------------- */
4515{
4516 if (!ED_operator_screenactive(C)) {
4517 return false;
4518 }
4520 return !BLI_listbase_is_empty(&wm->operators);
4521}
4522
4523static int repeat_last_exec(bContext *C, wmOperator * /*op*/)
4524{
4526 wmOperator *lastop = static_cast<wmOperator *>(wm->operators.last);
4527
4528 /* Seek last registered operator */
4529 while (lastop) {
4530 if (lastop->type->flag & OPTYPE_REGISTER) {
4531 break;
4532 }
4533 lastop = lastop->prev;
4534 }
4535
4536 if (lastop) {
4537 WM_operator_free_all_after(wm, lastop);
4538 WM_operator_repeat_last(C, lastop);
4539 }
4540
4541 return OPERATOR_CANCELLED;
4542}
4543
4545{
4546 /* identifiers */
4547 ot->name = "Repeat Last";
4548 ot->description = "Repeat last action";
4549 ot->idname = "SCREEN_OT_repeat_last";
4550
4551 /* api callbacks */
4553
4555}
4556
4559/* -------------------------------------------------------------------- */
4563static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
4564{
4566
4567 int items = BLI_listbase_count(&wm->operators);
4568 if (items == 0) {
4569 return OPERATOR_CANCELLED;
4570 }
4571
4573 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
4574 uiLayout *layout = UI_popup_menu_layout(pup);
4575
4576 wmOperator *lastop;
4577 int i;
4578 for (i = items - 1, lastop = static_cast<wmOperator *>(wm->operators.last); lastop;
4579 lastop = lastop->prev, i--)
4580 {
4581 if ((lastop->type->flag & OPTYPE_REGISTER) && WM_operator_repeat_check(C, lastop)) {
4582 uiItemIntO(layout,
4583 WM_operatortype_name(lastop->type, lastop->ptr).c_str(),
4584 ICON_NONE,
4585 op->type->idname,
4586 "index",
4587 i);
4588 }
4589 }
4590
4591 UI_popup_menu_end(C, pup);
4592
4593 return OPERATOR_INTERFACE;
4594}
4595
4597{
4599
4600 op = static_cast<wmOperator *>(BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index")));
4601 if (op) {
4602 /* let's put it as last operator in list */
4603 BLI_remlink(&wm->operators, op);
4604 BLI_addtail(&wm->operators, op);
4605
4606 WM_operator_repeat(C, op);
4607 }
4608
4609 return OPERATOR_FINISHED;
4610}
4611
4613{
4614 /* identifiers */
4615 ot->name = "Repeat History";
4616 ot->description = "Display menu for previous actions performed";
4617 ot->idname = "SCREEN_OT_repeat_history";
4618
4619 /* api callbacks */
4623
4624 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
4625}
4626
4629/* -------------------------------------------------------------------- */
4633static int redo_last_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
4634{
4635 wmOperator *lastop = WM_operator_last_redo(C);
4636
4637 if (lastop) {
4638 WM_operator_redo_popup(C, lastop);
4639 }
4640
4641 return OPERATOR_CANCELLED;
4642}
4643
4645{
4646 /* identifiers */
4647 ot->name = "Redo Last";
4648 ot->description = "Display parameters for last action performed";
4649 ot->idname = "SCREEN_OT_redo_last";
4650
4651 /* api callbacks */
4654}
4655
4658/* -------------------------------------------------------------------- */
4663{
4664 if (rv3d->localvd) {
4665 rv3d->localvd->view = rv3d->view;
4666 rv3d->localvd->view_axis_roll = rv3d->view_axis_roll;
4667 rv3d->localvd->persp = rv3d->persp;
4668 copy_qt_qt(rv3d->localvd->viewquat, rv3d->viewquat);
4669 }
4670}
4671
4673 ScrArea *area, ARegion *region, const char viewlock, const char view, const char persp)
4674{
4675 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
4676
4677 if (persp == RV3D_CAMOB) {
4679 }
4680
4681 rv3d->viewlock = viewlock;
4682 rv3d->runtime_viewlock = 0;
4683 rv3d->view = view;
4685 rv3d->persp = persp;
4686
4687 ED_view3d_lock(rv3d);
4689 if ((viewlock & RV3D_BOXCLIP) && (persp == RV3D_ORTHO)) {
4690 ED_view3d_quadview_update(area, region, true);
4691 }
4692}
4693
4694/* insert a region in the area region list */
4696{
4697 ARegion *region = CTX_wm_region(C);
4698
4699 /* some rules... */
4700 if (region->regiontype != RGN_TYPE_WINDOW) {
4701 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-split");
4702 }
4703 else if (region->alignment == RGN_ALIGN_QSPLIT) {
4704 /* Exit quad-view */
4705 ScrArea *area = CTX_wm_area(C);
4706
4707 /* keep current region */
4708 region->alignment = 0;
4709
4710 if (area->spacetype == SPACE_VIEW3D) {
4711 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
4712
4713 /* if this is a locked view, use settings from 'User' view */
4714 if (rv3d->viewlock) {
4715 View3D *v3d_user;
4716 ARegion *region_user;
4717
4718 if (ED_view3d_context_user_region(C, &v3d_user, &region_user)) {
4719 if (region != region_user) {
4720 std::swap(region->regiondata, region_user->regiondata);
4721 rv3d = static_cast<RegionView3D *>(region->regiondata);
4722 }
4723 }
4724 }
4725
4727 rv3d->viewlock = 0;
4728
4729 /* FIXME: This fixes missing update to workbench TAA. (see #76216)
4730 * However, it would be nice if the tagging should be done in a more conventional way. */
4731 rv3d->rflag |= RV3D_GPULIGHT_UPDATE;
4732
4733 /* Accumulate locks, in case they're mixed. */
4734 LISTBASE_FOREACH (ARegion *, region_iter, &area->regionbase) {
4735 if (region_iter->regiontype == RGN_TYPE_WINDOW) {
4736 RegionView3D *rv3d_iter = static_cast<RegionView3D *>(region_iter->regiondata);
4737 rv3d->viewlock_quad |= rv3d_iter->viewlock;
4738 }
4739 }
4740 }
4741
4742 LISTBASE_FOREACH_MUTABLE (ARegion *, region_iter, &area->regionbase) {
4743 if (region_iter->alignment == RGN_ALIGN_QSPLIT) {
4744 ED_region_remove(C, area, region_iter);
4745 }
4746 }
4747 ED_area_tag_redraw(area);
4749 }
4750 else if (region->next) {
4751 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-split");
4752 }
4753 else {
4754 /* Enter quad-view */
4755 ScrArea *area = CTX_wm_area(C);
4756
4757 region->alignment = RGN_ALIGN_QSPLIT;
4758
4759 for (int count = 0; count < 3; count++) {
4760 ARegion *new_region = BKE_area_region_copy(area->type, region);
4761 BLI_addtail(&area->regionbase, new_region);
4762 }
4763
4764 /* lock views and set them */
4765 if (area->spacetype == SPACE_VIEW3D) {
4766 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
4767 int index_qsplit = 0;
4768
4769 /* run ED_view3d_lock() so the correct 'rv3d->viewquat' is set,
4770 * otherwise when restoring rv3d->localvd the 'viewquat' won't
4771 * match the 'view', set on entering localview See: #26315,
4772 *
4773 * We could avoid manipulating rv3d->localvd here if exiting
4774 * localview with a 4-split would assign these view locks */
4775 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
4776 const char viewlock = (rv3d->viewlock_quad & RV3D_VIEWLOCK_INIT) ?
4779
4781 area, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
4783 (region = region->next),
4784 viewlock,
4785 ED_view3d_lock_view_from_index(index_qsplit++),
4786 RV3D_ORTHO);
4788 (region = region->next),
4789 viewlock,
4790 ED_view3d_lock_view_from_index(index_qsplit++),
4791 RV3D_ORTHO);
4792/* forcing camera is distracting */
4793#if 0
4794 if (v3d->camera) {
4795 region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_CAMERA, RV3D_CAMOB);
4796 }
4797 else {
4798 region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_USER, RV3D_PERSP);
4799 }
4800#else
4801 (void)v3d;
4802#endif
4803 }
4804 ED_area_tag_redraw(area);
4806 }
4807
4808 return OPERATOR_FINISHED;
4809}
4810
4812{
4813 /* identifiers */
4814 ot->name = "Toggle Quad View";
4815 ot->description = "Split selected area into camera, front, right, and top views";
4816 ot->idname = "SCREEN_OT_region_quadview";
4817
4818 /* api callbacks */
4821 ot->flag = 0;
4822}
4823
4826/* -------------------------------------------------------------------- */
4831{
4832 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "region_type");
4833
4834 ARegion *region;
4835 if (RNA_property_is_set(op->ptr, prop)) {
4837 }
4838 else {
4839 region = CTX_wm_region(C);
4840 }
4841
4842 if (region && (region->alignment != RGN_ALIGN_NONE)) {
4843 ED_region_toggle_hidden(C, region);
4844 }
4845 ED_region_tag_redraw(region);
4846
4847 return OPERATOR_FINISHED;
4848}
4849
4851{
4852 ScrArea *area = CTX_wm_area(C);
4853
4854 /* Don't flip anything around in top-bar. */
4855 if (area && area->spacetype == SPACE_TOPBAR) {
4856 CTX_wm_operator_poll_msg_set(C, "Toggling regions in the Top-bar is not allowed");
4857 return false;
4858 }
4859
4860 return ED_operator_areaactive(C);
4861}
4862
4864{
4865 /* identifiers */
4866 ot->name = "Toggle Region";
4867 ot->idname = "SCREEN_OT_region_toggle";
4868 ot->description = "Hide or unhide the region";
4869
4870 /* api callbacks */
4873 ot->flag = 0;
4874
4876 "region_type",
4878 0,
4879 "Region Type",
4880 "Type of the region to toggle");
4881}
4882
4885/* -------------------------------------------------------------------- */
4889/* flip a region alignment */
4890static int region_flip_exec(bContext *C, wmOperator * /*op*/)
4891{
4892 ARegion *region = CTX_wm_region(C);
4893
4894 if (!region) {
4895 return OPERATOR_CANCELLED;
4896 }
4897
4898 if (region->alignment == RGN_ALIGN_TOP) {
4899 region->alignment = RGN_ALIGN_BOTTOM;
4900 }
4901 else if (region->alignment == RGN_ALIGN_BOTTOM) {
4902 region->alignment = RGN_ALIGN_TOP;
4903 }
4904 else if (region->alignment == RGN_ALIGN_LEFT) {
4905 region->alignment = RGN_ALIGN_RIGHT;
4906 }
4907 else if (region->alignment == RGN_ALIGN_RIGHT) {
4908 region->alignment = RGN_ALIGN_LEFT;
4909 }
4910
4914
4915 return OPERATOR_FINISHED;
4916}
4917
4919{
4920 ScrArea *area = CTX_wm_area(C);
4921
4922 /* Don't flip anything around in top-bar. */
4923 if (area && area->spacetype == SPACE_TOPBAR) {
4924 CTX_wm_operator_poll_msg_set(C, "Flipping regions in the Top-bar is not allowed");
4925 return false;
4926 }
4927
4928 return ED_operator_areaactive(C);
4929}
4930
4932{
4933 /* identifiers */
4934 ot->name = "Flip Region";
4935 ot->idname = "SCREEN_OT_region_flip";
4936 ot->description = "Toggle the region's alignment (left/right or top/bottom)";
4937
4938 /* api callbacks */
4941 ot->flag = 0;
4942}
4943
4946/* -------------------------------------------------------------------- */
4950/* show/hide header text menus */
4952{
4953 ScrArea *area = CTX_wm_area(C);
4954
4955 area->flag = area->flag ^ HEADER_NO_PULLDOWN;
4956
4957 ED_area_tag_redraw(area);
4959
4960 return OPERATOR_FINISHED;
4961}
4962
4964{
4965 /* identifiers */
4966 ot->name = "Expand/Collapse Header Menus";
4967 ot->idname = "SCREEN_OT_header_toggle_menus";
4968 ot->description = "Expand or collapse the header pulldown menus";
4969
4970 /* api callbacks */
4973 ot->flag = 0;
4974}
4975
4978/* -------------------------------------------------------------------- */
4982static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
4983{
4984 if (ED_area_is_global(area)) {
4985 return;
4986 }
4987
4989
4990 uiItemFullO(layout,
4991 "SCREEN_OT_area_join",
4992 IFACE_("Move/Split Area"),
4993 ICON_AREA_DOCK,
4994 nullptr,
4997 &ptr);
4998
4999 uiItemS(layout);
5000
5001 uiItemO(layout,
5002 area->full ? IFACE_("Restore Areas") : IFACE_("Maximize Area"),
5003 ICON_NONE,
5004 "SCREEN_OT_screen_full_area");
5005
5006 if (area->spacetype != SPACE_FILE && !area->full) {
5007 uiItemFullO(layout,
5008 "SCREEN_OT_screen_full_area",
5009 IFACE_("Full Screen Area"),
5010 ICON_NONE,
5011 nullptr,
5014 &ptr);
5015 RNA_boolean_set(&ptr, "use_hide_panels", true);
5016 }
5017
5018 uiItemO(layout, nullptr, ICON_NONE, "SCREEN_OT_area_dupli");
5019 uiItemS(layout);
5020 uiItemO(layout, nullptr, ICON_X, "SCREEN_OT_area_close");
5021}
5022
5024{
5025 ScrArea *area = CTX_wm_area(C);
5026 {
5027 PointerRNA ptr = RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, area->spacedata.first);
5028 if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
5029 uiItemR(layout, &ptr, "show_region_header", UI_ITEM_NONE, IFACE_("Show Header"), ICON_NONE);
5030 }
5031
5032 ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
5033 uiLayout *col = uiLayoutColumn(layout, false);
5034 uiLayoutSetActive(col, (region_header->flag & RGN_FLAG_HIDDEN) == 0);
5035
5037 uiItemR(col,
5038 &ptr,
5039 "show_region_tool_header",
5041 IFACE_("Show Tool Settings"),
5042 ICON_NONE);
5043 }
5044
5045 uiItemO(col,
5046 IFACE_("Show Menus"),
5047 (area->flag & HEADER_NO_PULLDOWN) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT,
5048 "SCREEN_OT_header_toggle_menus");
5049 }
5050
5051 if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
5052 uiItemS(layout);
5053 ED_screens_region_flip_menu_create(C, layout, nullptr);
5054 uiItemS(layout);
5055 screen_area_menu_items(area, layout);
5056 }
5057}
5058
5060{
5061 ScrArea *area = CTX_wm_area(C);
5062
5063 {
5064 PointerRNA ptr = RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, area->spacedata.first);
5065 uiItemR(layout, &ptr, "show_region_footer", UI_ITEM_NONE, IFACE_("Show Footer"), ICON_NONE);
5066 }
5067
5068 ED_screens_region_flip_menu_create(C, layout, nullptr);
5069 uiItemS(layout);
5070 screen_area_menu_items(area, layout);
5071}
5072
5074{
5075 const ARegion *region = CTX_wm_region(C);
5076 const short region_alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
5077 const char *but_flip_str = region_alignment == RGN_ALIGN_LEFT ? IFACE_("Flip to Right") :
5078 region_alignment == RGN_ALIGN_RIGHT ? IFACE_("Flip to Left") :
5079 region_alignment == RGN_ALIGN_BOTTOM ? IFACE_("Flip to Top") :
5080 IFACE_("Flip to Bottom");
5081
5082 /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
5084
5085 uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
5086}
5087
5088static void ed_screens_statusbar_menu_create(uiLayout *layout, void * /*arg*/)
5089{
5090 PointerRNA ptr = RNA_pointer_create(nullptr, &RNA_PreferencesView, &U);
5091 uiItemR(
5092 layout, &ptr, "show_statusbar_stats", UI_ITEM_NONE, IFACE_("Scene Statistics"), ICON_NONE);
5093 uiItemR(layout,
5094 &ptr,
5095 "show_statusbar_scene_duration",
5097 IFACE_("Scene Duration"),
5098 ICON_NONE);
5099 uiItemR(layout, &ptr, "show_statusbar_memory", UI_ITEM_NONE, IFACE_("System Memory"), ICON_NONE);
5101 uiItemR(layout, &ptr, "show_statusbar_vram", UI_ITEM_NONE, IFACE_("Video Memory"), ICON_NONE);
5102 }
5103 uiItemR(layout,
5104 &ptr,
5105 "show_extensions_updates",
5107 IFACE_("Extensions Updates"),
5108 ICON_NONE);
5109 uiItemR(
5110 layout, &ptr, "show_statusbar_version", UI_ITEM_NONE, IFACE_("Blender Version"), ICON_NONE);
5111}
5112
5113static int screen_context_menu_invoke(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
5114{
5115 const ScrArea *area = CTX_wm_area(C);
5116 const ARegion *region = CTX_wm_region(C);
5117
5118 if (area && area->spacetype == SPACE_STATUSBAR) {
5119 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Status Bar"), ICON_NONE);
5120 uiLayout *layout = UI_popup_menu_layout(pup);
5121 ed_screens_statusbar_menu_create(layout, nullptr);
5122 UI_popup_menu_end(C, pup);
5123 }
5124 else if (region) {
5125 if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
5126 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE);
5127 uiLayout *layout = UI_popup_menu_layout(pup);
5128 ED_screens_header_tools_menu_create(C, layout, nullptr);
5129 UI_popup_menu_end(C, pup);
5130 }
5131 else if (region->regiontype == RGN_TYPE_FOOTER) {
5132 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE);
5133 uiLayout *layout = UI_popup_menu_layout(pup);
5134 ED_screens_footer_tools_menu_create(C, layout, nullptr);
5135 UI_popup_menu_end(C, pup);
5136 }
5137 else if (region->regiontype == RGN_TYPE_NAV_BAR) {
5138 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Navigation Bar"), ICON_NONE);
5139 uiLayout *layout = UI_popup_menu_layout(pup);
5140 ED_screens_region_flip_menu_create(C, layout, nullptr);
5141 UI_popup_menu_end(C, pup);
5142 }
5143 }
5144
5145 return OPERATOR_INTERFACE;
5146}
5147
5149{
5150 /* identifiers */
5151 ot->name = "Region";
5152 ot->description = "Display region context menu";
5153 ot->idname = "SCREEN_OT_region_context_menu";
5154
5155 /* api callbacks */
5157}
5158
5161/* -------------------------------------------------------------------- */
5167static bool match_region_with_redraws(const ScrArea *area,
5168 eRegion_Type regiontype,
5169 eScreen_Redraws_Flag redraws,
5170 bool from_anim_edit)
5171{
5172 const eSpace_Type spacetype = eSpace_Type(area->spacetype);
5173 if (regiontype == RGN_TYPE_WINDOW) {
5174
5175 switch (spacetype) {
5176 case SPACE_VIEW3D:
5177 if ((redraws & TIME_ALL_3D_WIN) || from_anim_edit) {
5178 return true;
5179 }
5180 break;
5181 case SPACE_GRAPH:
5182 case SPACE_NLA:
5183 if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit) {
5184 return true;
5185 }
5186 break;
5187 case SPACE_ACTION:
5188 /* if only 1 window or 3d windows, we do timeline too
5189 * NOTE: Now we do action editor in all these cases, since timeline is here. */
5190 if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit) {
5191 return true;
5192 }
5193 break;
5194 case SPACE_PROPERTIES:
5195 if (redraws & TIME_ALL_BUTS_WIN) {
5196 return true;
5197 }
5198 break;
5199 case SPACE_SEQ:
5200 if ((redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) || from_anim_edit) {
5201 return true;
5202 }
5203 break;
5204 case SPACE_NODE:
5205 if (redraws & TIME_NODES) {
5206 return true;
5207 }
5208 break;
5209 case SPACE_IMAGE:
5210 if ((redraws & TIME_ALL_IMAGE_WIN) || from_anim_edit) {
5211 return true;
5212 }
5213 break;
5214 case SPACE_CLIP:
5215 if ((redraws & TIME_CLIPS) || from_anim_edit) {
5216 return true;
5217 }
5218 break;
5219 case SPACE_SPREADSHEET:
5220 if (redraws & TIME_SPREADSHEETS) {
5221 return true;
5222 }
5223 break;
5224 default:
5225 break;
5226 }
5227 }
5228 else if (regiontype == RGN_TYPE_UI) {
5229 if (spacetype == SPACE_CLIP) {
5230 /* Track Preview button is on Properties Editor in SpaceClip,
5231 * and it's very common case when users want it be refreshing
5232 * during playback, so asking people to enable special option
5233 * for this is a bit tricky, so add exception here for refreshing
5234 * Properties Editor for SpaceClip always */
5235 return true;
5236 }
5237
5238 if (redraws & TIME_ALL_BUTS_WIN) {
5239 return true;
5240 }
5241 }
5242 else if (regiontype == RGN_TYPE_HEADER) {
5243 if (spacetype == SPACE_ACTION) {
5244 /* The timeline shows the current frame in the header. Other headers
5245 * don't need to be updated. */
5246 SpaceAction *saction = (SpaceAction *)area->spacedata.first;
5247 return saction->mode == SACTCONT_TIMELINE;
5248 }
5249 }
5250 else if (regiontype == RGN_TYPE_PREVIEW) {
5251 switch (spacetype) {
5252 case SPACE_SEQ:
5253 if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) {
5254 return true;
5255 }
5256 break;
5257 case SPACE_CLIP:
5258 return true;
5259 default:
5260 break;
5261 }
5262 }
5263 return false;
5264}
5265
5267 bContext *C, ScrArea *area, ARegion *region, const Scene *scene, eScreen_Redraws_Flag redraws)
5268{
5269 /* Do follow time here if editor type supports it */
5270 if ((redraws & TIME_FOLLOW) &&
5272 eRegion_Type(region->regiontype)))
5273 {
5274 float w = BLI_rctf_size_x(&region->v2d.cur);
5275 if (scene->r.cfra < region->v2d.cur.xmin) {
5276 region->v2d.cur.xmax = scene->r.cfra;
5277 region->v2d.cur.xmin = region->v2d.cur.xmax - w;
5278 ED_region_tag_redraw(region);
5279 return;
5280 }
5281 if (scene->r.cfra > region->v2d.cur.xmax) {
5282 region->v2d.cur.xmin = scene->r.cfra;
5283 region->v2d.cur.xmax = region->v2d.cur.xmin + w;
5284 ED_region_tag_redraw(region);
5285 return;
5286 }
5287 }
5288
5289 /* No need to do a full redraw as the current frame indicator is only updated.
5290 * We do need to redraw when this area is in full screen as no other areas
5291 * will be tagged for redrawing. */
5292 if (region->regiontype == RGN_TYPE_WINDOW && !area->full) {
5293 if (ELEM(area->spacetype, SPACE_NLA, SPACE_ACTION)) {
5294 return;
5295 }
5296
5297 /* Drivers Editor needs a full redraw on playback for graph_draw_driver_debug().
5298 * This will make it slower than regular graph editor during playback, but drawing this in
5299 * graph_main_region_draw_overlay() is not feasible because it requires animation filtering
5300 * which has significant overhead which needs to be avoided in the overlay which is redrawn on
5301 * every UI interaction. */
5302 if (area->spacetype == SPACE_GRAPH) {
5303 const SpaceGraph *sipo = static_cast<const SpaceGraph *>(area->spacedata.first);
5304 if (sipo->mode != SIPO_MODE_DRIVERS) {
5305 return;
5306 }
5307 bAnimContext ac;
5308 if (ANIM_animdata_get_context(C, &ac) == false) {
5309 return;
5310 }
5311 if (ac.datatype != ANIMCONT_DRIVERS) {
5312 return;
5313 }
5314 }
5315
5316 if (area->spacetype == SPACE_SEQ) {
5317 const SpaceSeq *sseq = static_cast<const SpaceSeq *>(area->spacedata.first);
5319 return;
5320 }
5321 }
5322 }
5323 ED_region_tag_redraw(region);
5324}
5325
5326// #define PROFILE_AUDIO_SYNCH
5327
5328static int screen_animation_step_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
5329{
5330 bScreen *screen = CTX_wm_screen(C);
5331 wmTimer *wt = screen->animtimer;
5332
5333 if (!(wt && wt == event->customdata)) {
5334 return OPERATOR_PASS_THROUGH;
5335 }
5336
5337 wmWindow *win = CTX_wm_window(C);
5338
5339#ifdef PROFILE_AUDIO_SYNCH
5340 static int old_frame = 0;
5341 int newfra_int;
5342#endif
5343
5344 Main *bmain = CTX_data_main(C);
5345 Scene *scene = CTX_data_scene(C);
5346 ViewLayer *view_layer = WM_window_get_active_view_layer(win);
5347 Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
5348 Scene *scene_eval = (depsgraph != nullptr) ? DEG_get_evaluated_scene(depsgraph) : nullptr;
5349 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
5351 int sync;
5352 double time;
5353
5354 /* sync, don't sync, or follow scene setting */
5355 if (sad->flag & ANIMPLAY_FLAG_SYNC) {
5356 sync = 1;
5357 }
5358 else if (sad->flag & ANIMPLAY_FLAG_NO_SYNC) {
5359 sync = 0;
5360 }
5361 else {
5362 sync = (scene->flag & SCE_FRAME_DROP);
5363 }
5364
5365 if (scene_eval == nullptr) {
5366 /* Happens when undo/redo system is used during playback, nothing meaningful we can do here. */
5367 }
5368 else if (scene_eval->id.recalc & ID_RECALC_FRAME_CHANGE) {
5369 /* Ignore seek here, the audio will be updated to the scene frame after jump during next
5370 * dependency graph update. */
5371 }
5372 else if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
5373 isfinite(time = BKE_sound_sync_scene(scene_eval)))
5374 {
5375 double newfra = time * FPS;
5376
5377 /* give some space here to avoid jumps */
5378 if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra) {
5379 scene->r.cfra++;
5380 }
5381 else {
5382 scene->r.cfra = max_ii(scene->r.cfra, round(newfra));
5383 }
5384
5385#ifdef PROFILE_AUDIO_SYNCH
5386 newfra_int = scene->r.cfra;
5387 if (newfra_int < old_frame) {
5388 printf("back jump detected, frame %d!\n", newfra_int);
5389 }
5390 else if (newfra_int > old_frame + 1) {
5391 printf("forward jump detected, frame %d!\n", newfra_int);
5392 }
5393 fflush(stdout);
5394 old_frame = newfra_int;
5395#endif
5396 }
5397 else {
5398 if (sync) {
5399 /* Try to keep the playback in realtime by dropping frames. */
5400
5401 /* How much time (in frames) has passed since the last frame was drawn? */
5402 double delta_frames = wt->time_delta * FPS;
5403
5404 /* Add the remaining fraction from the last time step. */
5405 delta_frames += sad->lagging_frame_count;
5406
5407 if (delta_frames < 1.0) {
5408 /* We can render faster than the scene frame rate. However skipping or delaying frames
5409 * here seems to in practice lead to jittery playback so just step forward a minimum of
5410 * one frame. (Even though this can lead to too fast playback, the jitteriness is more
5411 * annoying)
5412 */
5413 delta_frames = 1.0f;
5414 sad->lagging_frame_count = 0;
5415 }
5416 else {
5417 /* Extract the delta frame fractions that will be skipped when converting to int. */
5418 sad->lagging_frame_count = delta_frames - int(delta_frames);
5419 }
5420
5421 const int step = delta_frames;
5422
5423 /* skip frames */
5424 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5425 scene->r.cfra -= step;
5426 }
5427 else {
5428 scene->r.cfra += step;
5429 }
5430 }
5431 else {
5432 /* one frame +/- */
5433 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5434 scene->r.cfra--;
5435 }
5436 else {
5437 scene->r.cfra++;
5438 }
5439 }
5440 }
5441
5442 /* reset 'jumped' flag before checking if we need to jump... */
5443 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
5444
5445 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5446 /* jump back to end? */
5447 if (PRVRANGEON) {
5448 if (scene->r.cfra < scene->r.psfra) {
5449 scene->r.cfra = scene->r.pefra;
5450 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5451 }
5452 }
5453 else {
5454 if (scene->r.cfra < scene->r.sfra) {
5455 scene->r.cfra = scene->r.efra;
5456 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5457 }
5458 }
5459 }
5460 else {
5461 /* jump back to start? */
5462 if (PRVRANGEON) {
5463 if (scene->r.cfra > scene->r.pefra) {
5464 scene->r.cfra = scene->r.psfra;
5465 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5466 }
5467 }
5468 else {
5469 if (scene->r.cfra > scene->r.efra) {
5470 scene->r.cfra = scene->r.sfra;
5471 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5472 }
5473 }
5474 }
5475
5476 /* next frame overridden by user action (pressed jump to first/last frame) */
5478 scene->r.cfra = sad->nextfra;
5479 sad->flag &= ~ANIMPLAY_FLAG_USE_NEXT_FRAME;
5480 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5481 }
5482
5483 if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
5485#ifdef PROFILE_AUDIO_SYNCH
5486 old_frame = scene->r.cfra;
5487#endif
5488 }
5489
5490 /* Since we follow draw-flags, we can't send notifier but tag regions ourselves. */
5491 if (depsgraph != nullptr) {
5493 }
5494
5495 LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
5496 const bScreen *win_screen = WM_window_get_active_screen(window);
5497
5498 LISTBASE_FOREACH (ScrArea *, area, &win_screen->areabase) {
5499 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
5500 bool redraw = false;
5501 if (region == sad->region) {
5502 redraw = true;
5503 }
5504 else if (match_region_with_redraws(area,
5505 eRegion_Type(region->regiontype),
5507 sad->from_anim_edit))
5508 {
5509 redraw = true;
5510 }
5511
5512 if (redraw) {
5514 C, area, region, scene, eScreen_Redraws_Flag(sad->redraws));
5515 }
5516 }
5517 }
5518 }
5519
5520 if (U.uiflag & USER_SHOW_FPS) {
5521 /* Update frame rate info too.
5522 * NOTE: this may not be accurate enough, since we might need this after modifiers/etc.
5523 * have been calculated instead of just before updates have been done? */
5524 ED_scene_fps_average_accumulate(scene, U.playback_fps_samples, wt->time_last);
5525 }
5526
5527 /* Recalculate the time-step for the timer now that we've finished calculating this,
5528 * since the frames-per-second value may have been changed.
5529 */
5530 /* TODO: this may make evaluation a bit slower if the value doesn't change...
5531 * any way to avoid this? */
5532 wt->time_step = (1.0 / FPS);
5533
5534 return OPERATOR_FINISHED;
5535}
5536
5538{
5539 /* identifiers */
5540 ot->name = "Animation Step";
5541 ot->description = "Step through animation by position";
5542 ot->idname = "SCREEN_OT_animation_step";
5543
5544 /* api callbacks */
5546
5548}
5549
5552/* -------------------------------------------------------------------- */
5559{
5560 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
5561 bScreen *screen = WM_window_get_active_screen(win);
5562
5563 if (screen->animtimer || screen->scrubbing) {
5564 return screen;
5565 }
5566 }
5567
5568 return nullptr;
5569}
5570
5572{
5573 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
5574 bScreen *screen = WM_window_get_active_screen(win);
5575
5576 if (screen->animtimer) {
5577 return screen;
5578 }
5579 }
5580
5581 return nullptr;
5582}
5583
5584int ED_screen_animation_play(bContext *C, int sync, int mode)
5585{
5586 bScreen *screen = CTX_wm_screen(C);
5587 Scene *scene = CTX_data_scene(C);
5590 Main *bmain = DEG_get_bmain(depsgraph);
5591
5593 /* stop playback now */
5594 ED_screen_animation_timer(C, 0, 0, 0);
5596 BKE_sound_stop_scene(scene_eval);
5597
5599 bmain, &scene->id, depsgraph, BKE_CB_EVT_ANIMATION_PLAYBACK_POST);
5600
5601 /* Triggers redraw of sequencer preview so that it does not show to fps anymore after stopping
5602 * playback. */
5606 }
5607 else {
5609 bmain, &scene->id, depsgraph, BKE_CB_EVT_ANIMATION_PLAYBACK_PRE);
5610
5611 /* these settings are currently only available from a menu in the TimeLine */
5612 if (mode == 1) { /* XXX only play audio forwards!? */
5613 BKE_sound_play_scene(scene_eval);
5614 }
5615
5616 ED_screen_animation_timer(C, screen->redraws_flag, sync, mode);
5618
5619 if (screen->animtimer) {
5620 wmTimer *wt = screen->animtimer;
5621 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
5622
5623 sad->region = CTX_wm_region(C);
5624 }
5625 }
5626
5627 return OPERATOR_FINISHED;
5628}
5629
5631{
5632 int mode = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
5633 int sync = -1;
5634
5635 if (RNA_struct_property_is_set(op->ptr, "sync")) {
5636 sync = RNA_boolean_get(op->ptr, "sync");
5637 }
5638
5639 return ED_screen_animation_play(C, sync, mode);
5640}
5641
5643{
5644 PropertyRNA *prop;
5645
5646 /* identifiers */
5647 ot->name = "Play Animation";
5648 ot->description = "Play animation";
5649 ot->idname = "SCREEN_OT_animation_play";
5650
5651 /* api callbacks */
5653
5655
5656 prop = RNA_def_boolean(
5657 ot->srna, "reverse", false, "Play in Reverse", "Animation is played backwards");
5659 prop = RNA_def_boolean(ot->srna, "sync", false, "Sync", "Drop frames to maintain framerate");
5661}
5662
5665/* -------------------------------------------------------------------- */
5670{
5672
5673 if (screen) {
5674 if (RNA_boolean_get(op->ptr, "restore_frame") && screen->animtimer) {
5675 ScreenAnimData *sad = static_cast<ScreenAnimData *>(screen->animtimer->customdata);
5676 Scene *scene = CTX_data_scene(C);
5677
5678 /* reset current frame before stopping, and just send a notifier to deal with the rest
5679 * (since playback still needs to be stopped)
5680 */
5681 scene->r.cfra = sad->sfra;
5682
5684 }
5685
5686 /* call the other "toggling" operator to clean up now */
5687 ED_screen_animation_play(C, 0, 0);
5688 }
5689
5690 return OPERATOR_PASS_THROUGH;
5691}
5692
5694{
5695 /* identifiers */
5696 ot->name = "Cancel Animation";
5697 ot->description = "Cancel animation, returning to the original frame";
5698 ot->idname = "SCREEN_OT_animation_cancel";
5699
5700 /* api callbacks */
5702
5704
5706 "restore_frame",
5707 true,
5708 "Restore Frame",
5709 "Restore the frame when animation was initialized");
5710}
5711
5714/* -------------------------------------------------------------------- */
5718/* operator state vars used: (added by default WM callbacks)
5719 * xmin, ymin
5720 * xmax, ymax
5721 *
5722 * customdata: the wmGesture pointer
5723 *
5724 * callbacks:
5725 *
5726 * exec() has to be filled in by user
5727 *
5728 * invoke() default WM function
5729 * adds modal handler
5730 *
5731 * modal() default WM function
5732 * accept modal events while doing it, calls exec(), handles ESC and border drawing
5733 *
5734 * poll() has to be filled in by user for context
5735 */
5736#if 0
5737static int box_select_exec(bContext *C, wmOperator *op)
5738{
5739 int event_type = RNA_int_get(op->ptr, "event_type");
5740
5741 if (event_type == LEFTMOUSE) {
5742 printf("box select do select\n");
5743 }
5744 else if (event_type == RIGHTMOUSE) {
5745 printf("box select deselect\n");
5746 }
5747 else {
5748 printf("box select do something\n");
5749 }
5750
5751 return 1;
5752}
5753
5754static void SCREEN_OT_box_select(wmOperatorType *ot)
5755{
5756 /* identifiers */
5757 ot->name = "Box Select";
5758 ot->idname = "SCREEN_OT_box_select";
5759
5760 /* api callbacks */
5765
5767
5768 /* rna */
5769 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
5771}
5772#endif
5773
5776/* -------------------------------------------------------------------- */
5783{
5784 bScreen *screen = CTX_wm_screen(C);
5785 ScrArea *area = nullptr;
5786
5787 /* search current screen for 'fullscreen' areas */
5788 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
5789 if (area_iter->full) {
5790 area = area_iter;
5791 break;
5792 }
5793 }
5794 if (!area) {
5795 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
5796 return OPERATOR_CANCELLED;
5797 }
5798
5799 ED_screen_full_prevspace(C, area);
5800
5801 return OPERATOR_FINISHED;
5802}
5803
5805{
5806 /* identifiers */
5807 ot->name = "Back to Previous Screen";
5808 ot->description = "Revert back to the original screen layout, before fullscreen area overlay";
5809 ot->idname = "SCREEN_OT_back_to_previous";
5810
5811 /* api callbacks */
5814}
5815
5818/* -------------------------------------------------------------------- */
5823{
5824 wmWindow *win_cur = CTX_wm_window(C);
5825 /* Use eventstate, not event from _invoke, so this can be called through exec(). */
5826 const wmEvent *event = win_cur->eventstate;
5827 int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_SCALE_FAC;
5828 int sizey = 520 * UI_SCALE_FAC;
5829
5830 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "section");
5831 if (prop && RNA_property_is_set(op->ptr, prop)) {
5832 /* Set active section via RNA, so it can fail properly. */
5833
5834 PointerRNA pref_ptr = RNA_pointer_create(nullptr, &RNA_Preferences, &U);
5835 PropertyRNA *active_section_prop = RNA_struct_find_property(&pref_ptr, "active_section");
5836
5837 RNA_property_enum_set(&pref_ptr, active_section_prop, RNA_property_enum_get(op->ptr, prop));
5838 RNA_property_update(C, &pref_ptr, active_section_prop);
5839 }
5840
5841 const rcti window_rect = {
5842 /*xmin*/ event->xy[0],
5843 /*xmax*/ event->xy[0] + sizex,
5844 /*ymin*/ event->xy[1],
5845 /*ymax*/ event->xy[1] + sizey,
5846 };
5847
5848 /* changes context! */
5849 if (WM_window_open(C,
5850 nullptr,
5851 &window_rect,
5853 false,
5854 false,
5855 true,
5857 nullptr,
5858 nullptr) != nullptr)
5859 {
5860 /* The header only contains the editor switcher and looks empty.
5861 * So hiding in the temp window makes sense. */
5862 ScrArea *area = CTX_wm_area(C);
5864
5865 region->flag |= RGN_FLAG_HIDDEN;
5866 ED_region_visibility_change_update(C, area, region);
5867
5868 return OPERATOR_FINISHED;
5869 }
5870 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
5871 return OPERATOR_CANCELLED;
5872}
5873
5875 wmOperatorType * /*ot*/,
5876 PointerRNA *ptr)
5877{
5878 PropertyRNA *prop = RNA_struct_find_property(ptr, "section");
5879 if (RNA_property_is_set(ptr, prop)) {
5880 int section = RNA_property_enum_get(ptr, prop);
5881 const char *section_name;
5882 if (RNA_property_enum_name_gettexted(C, ptr, prop, section, &section_name)) {
5883 return fmt::format(TIP_("Show {} preferences"), section_name);
5884 }
5885 }
5886 /* Fallback to default. */
5887 return "";
5888}
5889
5891{
5892 PropertyRNA *prop;
5893
5894 /* identifiers */
5895 ot->name = "Open Preferences...";
5896 ot->description = "Edit user preferences and system settings";
5897 ot->idname = "SCREEN_OT_userpref_show";
5898
5899 /* api callbacks */
5901 ot->poll = ED_operator_screenactive_nobackground; /* Not in background as this opens a window. */
5903
5904 prop = RNA_def_enum(ot->srna,
5905 "section",
5907 0,
5908 "",
5909 "Section to activate in the Preferences");
5911}
5912
5915/* -------------------------------------------------------------------- */
5920{
5921 wmWindow *win_cur = CTX_wm_window(C);
5922 /* Use eventstate, not event from _invoke, so this can be called through exec(). */
5923 const wmEvent *event = win_cur->eventstate;
5924
5925 int sizex = 900 * UI_SCALE_FAC;
5926 int sizey = 580 * UI_SCALE_FAC;
5927
5928 /* Get active property to show driver for
5929 * - Need to grab it first, or else this info disappears
5930 * after we've created the window
5931 */
5932 int index;
5934 PropertyRNA *prop;
5935 uiBut *but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
5936
5937 const rcti window_rect = {
5938 /*xmin*/ event->xy[0],
5939 /*xmax*/ event->xy[0] + sizex,
5940 /*ymin*/ event->xy[1],
5941 /*ymax*/ event->xy[1] + sizey,
5942 };
5943
5944 /* changes context! */
5945 if (WM_window_open(C,
5946 IFACE_("Blender Drivers Editor"),
5947 &window_rect,
5949 false,
5950 false,
5951 true,
5953 nullptr,
5954 nullptr) != nullptr)
5955 {
5957
5958 /* activate driver F-Curve for the property under the cursor */
5959 if (but) {
5960 bool driven, special;
5962 C, &ptr, prop, index, nullptr, nullptr, &driven, &special);
5963
5964 if (fcu) {
5965 /* Isolate this F-Curve... */
5966 bAnimContext ac;
5967 if (ANIM_animdata_get_context(C, &ac)) {
5971 ac.data,
5973 eAnimFilter_Flags(filter),
5974 fcu,
5976 }
5977 else {
5978 /* Just blindly isolate...
5979 * This isn't the best, and shouldn't happen, but may be enough. */
5981 }
5982 }
5983 }
5984
5985 return OPERATOR_FINISHED;
5986 }
5987 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
5988 return OPERATOR_CANCELLED;
5989}
5990
5992{
5993 /* identifiers */
5994 ot->name = "Show Drivers Editor";
5995 ot->description = "Show drivers editor in a separate window";
5996 ot->idname = "SCREEN_OT_drivers_editor_show";
5997
5998 /* api callbacks */
6000 ot->poll = ED_operator_screenactive_nobackground; /* Not in background as this opens a window. */
6001}
6002
6005/* -------------------------------------------------------------------- */
6010{
6011 wmWindow *win_cur = CTX_wm_window(C);
6012 /* Use eventstate, not event from _invoke, so this can be called through exec(). */
6013 const wmEvent *event = win_cur->eventstate;
6014 const int shift_y = 480;
6015 const int mx = event->xy[0];
6016 const int my = event->xy[1] + shift_y;
6017 int sizex = 900 * UI_SCALE_FAC;
6018 int sizey = 580 * UI_SCALE_FAC;
6019
6020 const rcti window_rect = {
6021 /*xmin*/ mx,
6022 /*xmax*/ mx + sizex,
6023 /*ymin*/ my,
6024 /*ymax*/ my + sizey,
6025 };
6026
6027 /* changes context! */
6028 if (WM_window_open(C,
6029 IFACE_("Blender Info Log"),
6030 &window_rect,
6031 SPACE_INFO,
6032 false,
6033 false,
6034 true,
6036 nullptr,
6037 nullptr) != nullptr)
6038 {
6039 return OPERATOR_FINISHED;
6040 }
6041 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
6042 return OPERATOR_CANCELLED;
6043}
6044
6046{
6047 /* identifiers */
6048 ot->name = "Show Info Log";
6049 ot->description = "Show info log in a separate window";
6050 ot->idname = "SCREEN_OT_info_log_show";
6051
6052 /* api callbacks */
6055}
6056
6059/* -------------------------------------------------------------------- */
6063static int screen_new_exec(bContext *C, wmOperator * /*op*/)
6064{
6065 Main *bmain = CTX_data_main(C);
6066 wmWindow *win = CTX_wm_window(C);
6069
6070 WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
6071
6073
6074 return OPERATOR_FINISHED;
6075}
6076
6078{
6079 /* identifiers */
6080 ot->name = "New Screen";
6081 ot->description = "Add a new screen";
6082 ot->idname = "SCREEN_OT_new";
6083
6084 /* api callbacks */
6087}
6088
6091/* -------------------------------------------------------------------- */
6096{
6097 bScreen *screen = CTX_wm_screen(C);
6098 WorkSpace *workspace = CTX_wm_workspace(C);
6099 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
6100
6102
6103 return OPERATOR_FINISHED;
6104}
6105
6107{
6108 /* identifiers */
6109 ot->name = "Delete Screen";
6110 ot->description = "Delete active screen";
6111 ot->idname = "SCREEN_OT_delete";
6112
6113 /* api callbacks */
6115}
6116
6119/* -------------------------------------------------------------------- */
6130 ARegion *region, *child_region; /* other region */
6132};
6133
6134#define TIMEOUT 0.1f
6135#define TIMESTEP (1.0f / 60.0f)
6136
6138{
6139 /* check parent too */
6140 if (region->regiontimer == nullptr &&
6141 (region->alignment & (RGN_SPLIT_PREV | RGN_ALIGN_HIDE_WITH_PREV)) && region->prev)
6142 {
6143 region = region->prev;
6144 }
6145
6146 if (region->regiontimer) {
6147 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(region->regiontimer->customdata);
6148 float alpha;
6149
6150 alpha = float(region->regiontimer->time_duration) / TIMEOUT;
6151 /* makes sure the blend out works 100% - without area redraws */
6152 if (rgi->hidden) {
6153 alpha = 0.9f - TIMESTEP - alpha;
6154 }
6155
6156 CLAMP(alpha, 0.0f, 1.0f);
6157 return alpha;
6158 }
6159 return 1.0f;
6160}
6161
6162/* assumes region has running region-blend timer */
6163static void region_blend_end(bContext *C, ARegion *region, const bool is_running)
6164{
6165 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(region->regiontimer->customdata);
6166
6167 /* always send redraw */
6168 ED_region_tag_redraw(region);
6169 if (rgi->child_region) {
6171 }
6172
6173 /* if running timer was hiding, the flag toggle went wrong */
6174 if (is_running) {
6175 if (rgi->hidden) {
6176 rgi->region->flag &= ~RGN_FLAG_HIDDEN;
6177 }
6178 }
6179 else {
6180 if (rgi->hidden) {
6181 rgi->region->flag |= rgi->hidden;
6183 }
6184 /* area decoration needs redraw in end */
6186 }
6187 WM_event_timer_remove(CTX_wm_manager(C), nullptr, region->regiontimer); /* frees rgi */
6188 region->regiontimer = nullptr;
6189}
6191{
6193 wmWindow *win = CTX_wm_window(C);
6194
6195 /* end running timer */
6196 if (region->regiontimer) {
6197
6198 region_blend_end(C, region, true);
6199 }
6200 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(
6201 MEM_callocN(sizeof(RegionAlphaInfo), "RegionAlphaInfo"));
6202
6203 rgi->hidden = region->flag & RGN_FLAG_HIDDEN;
6204 rgi->area = area;
6205 rgi->region = region;
6206 region->flag &= ~RGN_FLAG_HIDDEN;
6207
6208 /* blend in, reinitialize regions because it got unhidden */
6209 if (rgi->hidden == 0) {
6210 ED_area_init(wm, win, area);
6211 }
6212 else {
6213 ED_region_visibility_change_update_ex(C, area, region, true, false);
6214 }
6215
6216 if (region->next) {
6217 if (region->next->alignment & (RGN_SPLIT_PREV | RGN_ALIGN_HIDE_WITH_PREV)) {
6218 rgi->child_region = region->next;
6219 }
6220 }
6221
6222 /* new timer */
6224 region->regiontimer->customdata = rgi;
6225}
6226
6227/* timer runs in win->handlers, so it cannot use context to find area/region */
6228static int region_blend_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
6229{
6230 wmTimer *timer = static_cast<wmTimer *>(event->customdata);
6231
6232 /* event type is TIMERREGION, but we better check */
6233 if (event->type != TIMERREGION || timer == nullptr) {
6234 return OPERATOR_PASS_THROUGH;
6235 }
6236
6237 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(timer->customdata);
6238
6239 /* always send redraws */
6241 if (rgi->child_region) {
6243 }
6244
6245 /* end timer? */
6246 if (rgi->region->regiontimer->time_duration > double(TIMEOUT)) {
6247 region_blend_end(C, rgi->region, false);
6249 }
6250
6252}
6253
6255{
6256 /* identifiers */
6257 ot->name = "Region Alpha";
6258 ot->idname = "SCREEN_OT_region_blend";
6259 ot->description = "Blend in and out overlapping region";
6260
6261 /* api callbacks */
6263
6264 /* flags */
6266
6267 /* properties */
6268}
6269
6272/* -------------------------------------------------------------------- */
6277{
6278 ScrArea *area = CTX_wm_area(C);
6279 return (area && !ELEM(area->spacetype, SPACE_TOPBAR, SPACE_STATUSBAR));
6280}
6281
6283{
6284 const int space_type = RNA_enum_get(op->ptr, "space_type");
6285
6286 ScrArea *area = CTX_wm_area(C);
6287 PointerRNA ptr = RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Area, area);
6288 PropertyRNA *prop_type = RNA_struct_find_property(&ptr, "type");
6289 PropertyRNA *prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
6290
6291 if (area->spacetype != space_type) {
6292 /* Set the type. */
6293 RNA_property_enum_set(&ptr, prop_type, space_type);
6294 RNA_property_update(C, &ptr, prop_type);
6295 }
6296 else {
6297 /* Types match, cycle the subtype. */
6298 const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
6299 const EnumPropertyItem *item;
6300 int item_len;
6301 bool free;
6302 RNA_property_enum_items(C, &ptr, prop_ui_type, &item, &item_len, &free);
6303 int index = RNA_enum_from_value(item, space_type_ui);
6304 for (int i = 1; i < item_len; i++) {
6305 const EnumPropertyItem *item_test = &item[(index + i) % item_len];
6306 if ((item_test->value >> 16) == space_type) {
6307 RNA_property_enum_set(&ptr, prop_ui_type, item_test->value);
6308 RNA_property_update(C, &ptr, prop_ui_type);
6309 break;
6310 }
6311 }
6312 if (free) {
6313 MEM_freeN((void *)item);
6314 }
6315 }
6316
6317 return OPERATOR_FINISHED;
6318}
6319
6321{
6322 /* identifiers */
6323 ot->name = "Cycle Space Type Set";
6324 ot->description = "Set the space type or cycle subtype";
6325 ot->idname = "SCREEN_OT_space_type_set_or_cycle";
6326
6327 /* api callbacks */
6330
6331 ot->flag = 0;
6332
6333 RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Type", "");
6334}
6335
6338/* -------------------------------------------------------------------- */
6343 {SPACE_CONTEXT_CYCLE_PREV, "PREV", 0, "Previous", ""},
6344 {SPACE_CONTEXT_CYCLE_NEXT, "NEXT", 0, "Next", ""},
6345 {0, nullptr, 0, nullptr, nullptr},
6346};
6347
6349{
6350 ScrArea *area = CTX_wm_area(C);
6351 /* area might be nullptr if called out of window bounds */
6352 return (area && ELEM(area->spacetype, SPACE_PROPERTIES, SPACE_USERPREF));
6353}
6354
6360 const ScrArea *area,
6361 PointerRNA *r_ptr,
6362 PropertyRNA **r_prop)
6363{
6364 const char *propname;
6365
6366 switch (area->spacetype) {
6367 case SPACE_PROPERTIES:
6368 *r_ptr = RNA_pointer_create(&screen->id, &RNA_SpaceProperties, area->spacedata.first);
6369 propname = "context";
6370 break;
6371 case SPACE_USERPREF:
6372 *r_ptr = RNA_pointer_create(nullptr, &RNA_Preferences, &U);
6373 propname = "active_section";
6374 break;
6375 default:
6376 BLI_assert(0);
6377 propname = "";
6378 }
6379
6380 *r_prop = RNA_struct_find_property(r_ptr, propname);
6381}
6382
6383static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
6384{
6385 const eScreenCycle direction = eScreenCycle(RNA_enum_get(op->ptr, "direction"));
6386
6388 PropertyRNA *prop;
6390 const int old_context = RNA_property_enum_get(&ptr, prop);
6391 const int new_context = RNA_property_enum_step(
6392 C, &ptr, prop, old_context, direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
6393 RNA_property_enum_set(&ptr, prop, new_context);
6394 RNA_property_update(C, &ptr, prop);
6395
6396 return OPERATOR_FINISHED;
6397}
6398
6400{
6401 /* identifiers */
6402 ot->name = "Cycle Space Context";
6403 ot->description = "Cycle through the editor context by activating the next/previous one";
6404 ot->idname = "SCREEN_OT_space_context_cycle";
6405
6406 /* api callbacks */
6409
6410 ot->flag = 0;
6411
6413 "direction",
6416 "Direction",
6417 "Direction to cycle through");
6418}
6419
6422/* -------------------------------------------------------------------- */
6426static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
6427{
6428 wmWindow *win = CTX_wm_window(C);
6429 if (WM_window_is_temp_screen(win)) {
6430 return OPERATOR_CANCELLED;
6431 }
6432
6433 Main *bmain = CTX_data_main(C);
6434 const eScreenCycle direction = eScreenCycle(RNA_enum_get(op->ptr, "direction"));
6435 WorkSpace *workspace_src = WM_window_get_active_workspace(win);
6436
6437 Vector<ID *> ordered = BKE_id_ordered_list(&bmain->workspaces);
6438 if (ordered.size() == 1) {
6439 return OPERATOR_CANCELLED;
6440 }
6441
6442 const int index = ordered.first_index_of(&workspace_src->id);
6443
6444 WorkSpace *workspace_dst = nullptr;
6445 switch (direction) {
6447 workspace_dst = reinterpret_cast<WorkSpace *>(index == 0 ? ordered.last() :
6448 ordered[index - 1]);
6449 break;
6451 workspace_dst = reinterpret_cast<WorkSpace *>(
6452 index == ordered.index_range().last() ? ordered.first() : ordered[index + 1]);
6453 break;
6454 }
6455
6456 win->workspace_hook->temp_workspace_store = workspace_dst;
6458 win->workspace_hook->temp_workspace_store = nullptr;
6459
6460 return OPERATOR_FINISHED;
6461}
6462
6464{
6465 /* identifiers */
6466 ot->name = "Cycle Workspace";
6467 ot->description = "Cycle through workspaces";
6468 ot->idname = "SCREEN_OT_workspace_cycle";
6469
6470 /* api callbacks */
6473
6474 ot->flag = 0;
6475
6477 "direction",
6480 "Direction",
6481 "Direction to cycle through");
6482}
6483
6486/* -------------------------------------------------------------------- */
6491{
6492 /* Generic UI stuff. */
6497
6498 /* Screen tools. */
6525
6526 /* Frame changes. */
6531
6535
6536 /* New/delete. */
6539}
6540
6543/* -------------------------------------------------------------------- */
6547static void keymap_modal_set(wmKeyConfig *keyconf)
6548{
6549 static const EnumPropertyItem modal_items[] = {
6550 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
6551 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
6552 {KM_MODAL_SNAP_ON, "SNAP", 0, "Snap On", ""},
6553 {KM_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
6554 {0, nullptr, 0, nullptr, nullptr},
6555 };
6556
6557 /* Standard Modal keymap ------------------------------------------------ */
6558 wmKeyMap *keymap = WM_modalkeymap_ensure(keyconf, "Standard Modal Map", modal_items);
6559
6560 WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
6561}
6562
6563static bool blend_file_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
6564{
6565 if (drag->type == WM_DRAG_PATH) {
6568 return true;
6569 }
6570 }
6571 return false;
6572}
6573
6574static void blend_file_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
6575{
6576 /* copy drag path to properties */
6577 RNA_string_set(drop->ptr, "filepath", WM_drag_get_single_path(drag));
6578}
6579
6581{
6582 /* Screen Editing ------------------------------------------------ */
6583 WM_keymap_ensure(keyconf, "Screen Editing", SPACE_EMPTY, RGN_TYPE_WINDOW);
6584
6585 /* Screen General ------------------------------------------------ */
6586 WM_keymap_ensure(keyconf, "Screen", SPACE_EMPTY, RGN_TYPE_WINDOW);
6587
6588 /* Anim Playback ------------------------------------------------ */
6589 WM_keymap_ensure(keyconf, "Frames", SPACE_EMPTY, RGN_TYPE_WINDOW);
6590
6591 /* dropbox for entire window */
6594 lb, "WM_OT_drop_blend_file", blend_file_drop_poll, blend_file_drop_copy, nullptr, nullptr);
6595 WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy, nullptr, nullptr);
6596
6597 keymap_modal_set(keyconf);
6598}
6599
@ 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
@ SCE_FRAME_DROP
@ SCE_KEYS_NO_SELONLY
#define FPS
@ AUDIO_SYNC
#define PRVRANGEON
#define PEFRA
#define HEADERY
@ SCREENFULL
@ SCREENMAXIMIZED
@ SCREENNORMAL
#define RGN_ALIGN_ENUM_FROM_MASK(align)
@ HEADER_NO_PULLDOWN
@ 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)
#define AREAMINX
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
@ RGN_FLAG_RESIZE_RESPECT_BUTTON_SECTIONS
@ RGN_FLAG_HIDDEN
@ RGN_FLAG_NO_USER_RESIZE
@ RGN_FLAG_TOO_SMALL
@ RGN_FLAG_HIDDEN_BY_USER
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
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_IS_INIT
@ V2D_SCROLL_LEFT
@ V2D_SCROLL_HORIZONTAL
@ V2D_SCROLL_TOP
@ V2D_SCROLL_RIGHT
@ V2D_SCROLL_BOTTOM
@ V2D_SCROLL_VERTICAL
@ V2D_KEEPTOT_STRICT
@ RV3D_GPULIGHT_UPDATE
@ RV3D_VIEWLOCK_INIT
@ RV3D_VIEW_AXIS_ROLL_0
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_ORTHO
@ RV3D_LOCK_ROTATION
@ RV3D_BOXCLIP
@ RV3D_VIEW_CAMERA
@ RV3D_VIEW_USER
@ 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()
void ED_region_toggle_hidden(bContext *C, ARegion *region)
Definition area.cc:2276
int ED_area_global_min_size_y(const ScrArea *area)
Definition area.cc:3682
ScrArea * ED_area_find_under_cursor(const bContext *C, int spacetype, const int event_xy[2])
Definition area.cc:3698
#define ED_screen_verts_iter(win, screen, vert_name)
Definition ED_screen.hh:284
#define ED_screen_areas_iter(win, screen, area_name)
Definition ED_screen.hh:281
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:3687
bool ED_area_is_global(const ScrArea *area)
Definition area.cc:3693
void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
Definition area.cc:2566
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:653
int ED_area_headersize()
Definition area.cc:3666
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
Definition area.cc:2254
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:2235
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:2036
void ED_screen_full_prevspace(bContext *C, ScrArea *area)
eScreenCycle
Definition ED_screen.hh:739
@ SPACE_CONTEXT_CYCLE_NEXT
Definition ED_screen.hh:741
@ SPACE_CONTEXT_CYCLE_PREV
Definition ED_screen.hh:740
@ ANIMPLAY_FLAG_JUMPED
@ ANIMPLAY_FLAG_NO_SYNC
@ ANIMPLAY_FLAG_REVERSE
@ ANIMPLAY_FLAG_SYNC
@ ANIMPLAY_FLAG_USE_NEXT_FRAME
@ AZONE_REGION
@ AZONE_FULLSCREEN
@ AZONE_REGION_SCROLL
@ AZONE_AREA
@ AZ_SCROLL_HOR
@ AZ_SCROLL_VERT
@ 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 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
@ 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_WINDOW
Definition WM_types.hh:342
eWM_EventFlag
Definition WM_types.hh:637
@ KM_NOTHING
Definition WM_types.hh:283
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#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
@ WM_DRAG_PATH
Definition WM_types.hh:1160
@ KM_CTRL
Definition WM_types.hh:256
@ KM_ALT
Definition WM_types.hh:257
#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
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:2261
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
Definition area.cc:2281
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
unsigned int U
Definition btGjkEpa3.h:78
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
constexpr int64_t last(const int64_t n=0) const
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
double time
const Depsgraph * depsgraph
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
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)
static ulong * next
static ulong state[N]
#define G(x, y, z)
Object * context_active_object(const bContext *C)
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 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
void * last
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
ListBase areabase
ScrVert * v2
ScrVert * v3
ScrVert * v1
ScrVert * v4
ScrVert * v1
ScrVert * v2
struct bNodeTree * edittree
char alpha_vert
struct Object * camera
Wrapper for bScreen.
eAnimCont_Types datatype
short redraws_flag
struct wmTimer * animtimer
ListBase areabase
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 * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
std::string(* get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1074
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
const char * undo_group
Definition WM_types.hh:998
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
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)