Blender V5.0
screen_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10#include <cstring>
11#include <fmt/format.h>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_build_config.h"
16#include "BLI_listbase.h"
17#include "BLI_math_rotation.h"
18#include "BLI_math_vector.h"
19#include "BLI_time.h"
20#include "BLI_utildefines.h"
21
22#include "BLT_translation.hh"
23
24#include "DNA_anim_types.h"
25#include "DNA_armature_types.h"
26#include "DNA_curve_types.h"
27#include "DNA_lattice_types.h"
28#include "DNA_meta_types.h"
29#include "DNA_node_types.h"
30#include "DNA_object_types.h"
31#include "DNA_scene_types.h"
32#include "DNA_userdef_types.h"
33#include "DNA_workspace_types.h"
34
35#include "BKE_callbacks.hh"
36#include "BKE_context.hh"
37#include "BKE_editmesh.hh"
38#include "BKE_fcurve.hh"
39#include "BKE_global.hh"
40#include "BKE_icons.h"
41#include "BKE_layer.hh"
42#include "BKE_lib_id.hh"
43#include "BKE_library.hh"
44#include "BKE_main.hh"
45#include "BKE_mask.h"
46#include "BKE_object.hh"
47#include "BKE_report.hh"
48#include "BKE_scene.hh"
49#include "BKE_screen.hh"
50#include "BKE_sound.h"
51#include "BKE_workspace.hh"
52
53#include "WM_api.hh"
54#include "WM_types.hh"
55
56#include "DEG_depsgraph.hh"
58
59#include "ED_anim_api.hh"
60#include "ED_armature.hh"
61#include "ED_buttons.hh"
62#include "ED_fileselect.hh"
63#include "ED_image.hh"
65#include "ED_mesh.hh"
66#include "ED_object.hh"
67#include "ED_scene.hh"
68#include "ED_screen.hh"
69#include "ED_screen_types.hh"
70#include "ED_sequencer.hh"
71#include "ED_space_graph.hh"
72#include "ED_view3d.hh"
73
74#include "RNA_access.hh"
75#include "RNA_define.hh"
76#include "RNA_enum_types.hh"
77#include "RNA_prototypes.hh"
78
79#include "UI_interface.hh"
81#include "UI_resources.hh"
82#include "UI_view2d.hh"
83
84#include "GPU_capabilities.hh"
85
86#include "wm_window.hh"
87
88#include "screen_intern.hh" /* own module include */
89
90using blender::Vector;
91
92#define KM_MODAL_CANCEL 1
93#define KM_MODAL_APPLY 2
94#define KM_MODAL_SNAP_ON 3
95#define KM_MODAL_SNAP_OFF 4
96
97/* -------------------------------------------------------------------- */
100
102{
103 if (CTX_wm_window(C) == nullptr) {
104 return false;
105 }
106 if (CTX_wm_screen(C) == nullptr) {
107 return false;
108 }
109 if (CTX_wm_region(C) == nullptr) {
110 return false;
111 }
112 return true;
113}
114
116{
117 if (CTX_wm_window(C) == nullptr) {
118 return false;
119 }
120 if (CTX_wm_screen(C) == nullptr) {
121 return false;
122 }
123 if (CTX_wm_area(C) == nullptr) {
124 return false;
125 }
126 return true;
127}
128
130{
131 if (CTX_wm_window(C) == nullptr) {
132 return false;
133 }
134 if (CTX_wm_screen(C) == nullptr) {
135 return false;
136 }
137 return true;
138}
139
141{
142 if (CTX_wm_window(C) == nullptr) {
143 return false;
144 }
145 if (CTX_wm_screen(C) == nullptr) {
146 return false;
147 }
148 /* In case of sequencer, scene may not be set. */
149 if (CTX_wm_space_seq(C) != nullptr) {
150 return CTX_data_sequencer_scene(C) != nullptr;
151 }
152 return true;
153}
154
156{
157 if (G.background) {
158 return false;
159 }
161}
162
163/* XXX added this to prevent anim state to change during renders */
165{
166 if (G.is_rendering) {
167 return false;
168 }
169 if (CTX_wm_window(C) == nullptr) {
170 return false;
171 }
172 if (CTX_wm_screen(C) == nullptr) {
173 return false;
174 }
175 return true;
176}
177
179{
180 if (CTX_wm_window(C) == nullptr) {
181 return false;
182 }
183 bScreen *screen = CTX_wm_screen(C);
184 if (screen == nullptr) {
185 return false;
186 }
187 if (screen->active_region != nullptr) {
188 return false;
189 }
190 return true;
191}
192
194{
195 Scene *scene = CTX_data_scene(C);
196 if (scene) {
197 return true;
198 }
199 return false;
200}
201
203{
205 if (scene == nullptr || !BKE_id_is_editable(CTX_data_main(C), &scene->id)) {
206 return false;
207 }
208 return true;
209}
210
212{
213 Scene *scene = CTX_data_scene(C);
214 if (scene == nullptr || !BKE_id_is_editable(CTX_data_main(C), &scene->id)) {
215 return false;
216 }
217 return true;
218}
219
221{
223 if (scene == nullptr || !BKE_id_is_editable(CTX_data_main(C), &scene->id)) {
224 return false;
225 }
226 return true;
227}
228
230{
231 Scene *scene = CTX_data_scene(C);
233
234 if (scene == nullptr || !ID_IS_EDITABLE(scene)) {
235 return false;
236 }
237 if (CTX_data_edit_object(C)) {
238 return false;
239 }
240
241 /* add a check for ob->mode too? */
242 if (obact && (obact->mode != OB_MODE_OBJECT)) {
243 return false;
244 }
245
246 return true;
247}
248
250{
252 CTX_wm_operator_poll_msg_set(C, "Only supported in object mode");
253 return false;
254 }
255
256 return true;
257}
258
260{
262 return false;
263 }
265 return false;
266 }
267 return true;
268}
269
270static bool ed_spacetype_test(bContext *C, int type)
271{
274 return sl && (sl->spacetype == type);
275 }
276 return false;
277}
278
283
285{
286 if (CTX_wm_region_view3d(C)) {
287 return true;
288 }
289
290 CTX_wm_operator_poll_msg_set(C, "expected a view3d region");
291 return false;
292}
293
295{
296 ARegion *region = CTX_wm_region(C);
297 if (region == nullptr) {
298 return false;
299 }
300 wmGizmoMap *gzmap = region->runtime->gizmo_map;
301 if (gzmap == nullptr) {
302 return false;
303 }
304 return true;
305}
306
308{
312 return true;
313 }
314 }
315
316 CTX_wm_operator_poll_msg_set(C, "expected a timeline/animation area to be active");
317 return false;
318}
319
324
326{
328 CTX_wm_operator_poll_msg_set(C, "Expected an active Outliner");
329 return false;
330 }
331 const ARegion *region = CTX_wm_region(C);
332 if (!(region && region->regiontype == RGN_TYPE_WINDOW)) {
333 CTX_wm_operator_poll_msg_set(C, "Expected an Outliner region");
334 return false;
335 }
336 return true;
337}
338
340{
343 Object *obedit = CTX_data_edit_object(C);
344 if (ob && ob == obedit) {
345 return false;
346 }
347 return true;
348 }
349 return false;
350}
351
356
364
372
377
382
387
389{
390 SpaceNode *snode = CTX_wm_space_node(C);
391
392 if (snode && snode->edittree) {
393 return true;
394 }
395
396 return false;
397}
398
400{
401 SpaceNode *snode = CTX_wm_space_node(C);
402
403 if (snode && snode->edittree && BKE_id_is_editable(CTX_data_main(C), &snode->edittree->id)) {
404 return true;
405 }
406
407 return false;
408}
409
414
419
424
429
434
439
444
445static bool ed_object_hidden(const Object *ob)
446{
447 /* if hidden but in edit mode, we still display, can happen with animation */
448 return ((ob->visibility_flag & OB_HIDE_VIEWPORT) && !(ob->mode & OB_MODE_EDIT));
449}
450
452{
454 return (ob != nullptr);
455}
456
458{
460 return ((ob != nullptr) && !ed_object_hidden(ob));
461}
462
464{
465 if (ob == nullptr) {
466 CTX_wm_operator_poll_msg_set(C, "Context missing active object");
467 return false;
468 }
469
470 if (!BKE_id_is_editable(CTX_data_main(C), (ID *)ob)) {
471 CTX_wm_operator_poll_msg_set(C, "Cannot edit library linked or non-editable override object");
472 return false;
473 }
474
475 if (ed_object_hidden(ob)) {
476 CTX_wm_operator_poll_msg_set(C, "Cannot edit hidden object");
477 return false;
478 }
479
480 return true;
481}
482
488
493
499
506
513
515{
516 Mesh *mesh = ED_mesh_context(C);
517 return (mesh != nullptr) && ID_IS_EDITABLE(mesh) && !ID_IS_OVERRIDE_LIBRARY(mesh);
518}
519
521{
522 Object *obedit = CTX_data_edit_object(C);
523 if (obedit && obedit->type == OB_MESH) {
524 return nullptr != BKE_editmesh_from_object(obedit);
525 }
526 return false;
527}
528
533
535{
537 return true;
538 }
539
540 CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editmesh");
541 return false;
542}
543
545{
546 Object *obedit = CTX_data_edit_object(C);
547 if (obedit && obedit->type == OB_ARMATURE) {
548 return nullptr != ((bArmature *)obedit->data)->edbo;
549 }
550 return false;
551}
552
561{
562 if (obact != nullptr && !(obact->mode & OB_MODE_EDIT)) {
563 if (obact == BKE_object_pose_armature_get(obact)) {
564 return true;
565 }
566 }
567
568 CTX_wm_operator_poll_msg_set(C, "No object, or not exclusively in pose mode");
569 return false;
570}
571
578
580{
582
584 return false;
585 }
586
587 if (ID_IS_OVERRIDE_LIBRARY(obact)) {
588 CTX_wm_operator_poll_msg_set(C, "Object is a local library override");
589 return false;
590 }
591
592 return true;
593}
594
596{
598
599 if (obpose && !(obpose->mode & OB_MODE_EDIT)) {
600 if (BKE_object_pose_context_check(obpose)) {
601 return true;
602 }
603 }
604
605 return false;
606}
607
609{
611
612 if (obact && !(obact->mode & OB_MODE_EDIT)) {
613 Object *obpose = BKE_object_pose_armature_get(obact);
614 if (obpose != nullptr) {
615 if ((obact == obpose) || (obact->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
616 return true;
617 }
618 }
619 }
620
621 return false;
622}
623
625{
626 if (ED_operator_posemode(C)) {
627 Main *bmain = CTX_data_main(C);
629 bArmature *arm = static_cast<bArmature *>(ob->data);
630 return (BKE_id_is_editable(bmain, &ob->id) && BKE_id_is_editable(bmain, &arm->id));
631 }
632 return false;
633}
634
636{
638 Object *obedit = CTX_data_edit_object(C);
639 return ED_space_image_show_uvedit(sima, obedit);
640}
641
643{
645 Object *obedit = CTX_data_edit_object(C);
646 return sima && ED_space_image_show_uvedit(sima, obedit);
647}
648
650{
651 Object *obedit = CTX_data_edit_object(C);
652 BMEditMesh *em = nullptr;
653
654 if (obedit && obedit->type == OB_MESH) {
655 em = BKE_editmesh_from_object(obedit);
656 }
657
658 if (em && (em->bm->totface)) {
659 return true;
660 }
661
662 return false;
663}
664
666{
667 Object *obedit = CTX_data_edit_object(C);
668 if (obedit && ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
669 return nullptr != ((Curve *)obedit->data)->editnurb;
670 }
671 return false;
672}
673
675{
677 return true;
678 }
679
680 CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editcurve");
681 return false;
682}
683
685{
686 Object *obedit = CTX_data_edit_object(C);
687 if (obedit && obedit->type == OB_CURVES_LEGACY) {
688 return nullptr != ((Curve *)obedit->data)->editnurb;
689 }
690 return false;
691}
692
694{
695 Object *obedit = CTX_data_edit_object(C);
696 if (obedit && obedit->type == OB_CURVES_LEGACY) {
697 Curve *cu = (Curve *)obedit->data;
698
699 return (cu->flag & CU_3D) && (nullptr != cu->editnurb);
700 }
701 return false;
702}
703
705{
706 Object *obedit = CTX_data_edit_object(C);
707 if (obedit && obedit->type == OB_SURF) {
708 return nullptr != ((Curve *)obedit->data)->editnurb;
709 }
710 return false;
711}
712
714{
715 Object *obedit = CTX_data_edit_object(C);
716 if (obedit && obedit->type == OB_FONT) {
717 if (((Curve *)obedit->data)->editfont) {
718 return true;
719 }
720 }
721 CTX_wm_operator_poll_msg_set(C, "expected an active edit-font object");
722 return false;
723}
724
726{
727 Object *obedit = CTX_data_edit_object(C);
728 if (obedit && obedit->type == OB_LATTICE) {
729 return nullptr != ((Lattice *)obedit->data)->editlatt;
730 }
731 return false;
732}
733
735{
736 Object *obedit = CTX_data_edit_object(C);
737 if (obedit && obedit->type == OB_MBALL) {
738 return nullptr != ((MetaBall *)obedit->data)->editelems;
739 }
740 return false;
741}
742
744{
745 Camera *cam = static_cast<Camera *>(CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data);
746 return (cam != nullptr && ID_IS_EDITABLE(cam));
747}
748
750
751/* -------------------------------------------------------------------- */
754
756{
758 /* no full window splitting allowed */
760 return false;
761 }
762 return true;
763 }
764 return false;
765}
766
772{
773 G.moving |= G_TRANSFORM_WM;
774}
775
778{
779 G.moving &= ~G_TRANSFORM_WM;
780
781 /* Full refresh after `G.moving` is cleared otherwise tool gizmos
782 * won't be refreshed with the modified flag, see: #143629. */
784}
785
787
788/* -------------------------------------------------------------------- */
791
792/* operator state vars used:
793 * none
794 *
795 * functions:
796 *
797 * apply() set action-zone event
798 *
799 * exit() free customdata
800 *
801 * callbacks:
802 *
803 * exec() never used
804 *
805 * invoke() check if in zone
806 * add customdata, put mouseco and area in it
807 * add modal handler
808 *
809 * modal() accept modal events while doing it
810 * call apply() with gesture info, active window, nonactive window
811 * call exit() and remove handler when LMB confirm
812 */
813
821
822/* quick poll to save operators to be created and handled */
824{
825 wmWindow *win = CTX_wm_window(C);
826 if (win && win->eventstate) {
828 if (screen) {
829 const int *xy = &win->eventstate->xy[0];
830
831 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
832 LISTBASE_FOREACH (AZone *, az, &area->actionzones) {
833 if (BLI_rcti_isect_pt_v(&az->rect, xy)) {
834 return true;
835 }
836 }
837 }
838 }
839 }
840 return false;
841}
842
843/* the debug drawing of the click_rect is in area_draw_azone_fullscreen, keep both in sync */
845 rcti *rect, const short /*x1*/, const short /*y1*/, const short x2, const short y2)
846{
847 BLI_rcti_init(rect, x2 - U.widget_unit, x2, y2 - U.widget_unit, y2);
848}
849
850static bool azone_clipped_rect_calc(const AZone *az, rcti *r_rect_clip)
851{
852 const ARegion *region = az->region;
853 *r_rect_clip = az->rect;
854 if (az->type == AZONE_REGION) {
855 if (region->overlap && (region->v2d.keeptot != V2D_KEEPTOT_STRICT) &&
856 /* Only when this isn't hidden (where it's displayed as an button that expands). */
857 region->runtime->visible)
858 {
859 /* A floating region to be resized, clip by the visible region. */
860 switch (az->edge) {
863 r_rect_clip->xmin = max_ii(
864 r_rect_clip->xmin,
865 (region->winrct.xmin +
866 UI_view2d_view_to_region_x(&region->v2d, region->v2d.tot.xmin)) -
868 r_rect_clip->xmax = min_ii(
869 r_rect_clip->xmax,
870 (region->winrct.xmin +
871 UI_view2d_view_to_region_x(&region->v2d, region->v2d.tot.xmax)) +
873 return true;
874 }
876 case AE_RIGHT_TO_TOPLEFT: {
877 r_rect_clip->ymin = max_ii(
878 r_rect_clip->ymin,
879 (region->winrct.ymin +
880 UI_view2d_view_to_region_y(&region->v2d, region->v2d.tot.ymin)) -
882 r_rect_clip->ymax = min_ii(
883 r_rect_clip->ymax,
884 (region->winrct.ymin +
885 UI_view2d_view_to_region_y(&region->v2d, region->v2d.tot.ymax)) +
887 return true;
888 }
889 }
890 }
891 }
892 return false;
893}
894
895/* Return the azone's calculated rect. */
896static void area_actionzone_get_rect(AZone *az, rcti *r_rect)
897{
898 if (az->type == AZONE_REGION_SCROLL) {
899 const bool is_horizontal = az->direction == AZ_SCROLL_HOR;
900 const bool is_vertical = az->direction == AZ_SCROLL_VERT;
901 const bool is_right = is_vertical && bool(az->region->v2d.scroll & V2D_SCROLL_RIGHT);
902 const bool is_left = is_vertical && bool(az->region->v2d.scroll & V2D_SCROLL_LEFT);
903 const bool is_top = is_horizontal && bool(az->region->v2d.scroll & V2D_SCROLL_TOP);
904 const bool is_bottom = is_horizontal && bool(az->region->v2d.scroll & V2D_SCROLL_BOTTOM);
905 /* For scroll azones use the area around the region's scroll-bar location. */
906 rcti scroller_vert = is_horizontal ? az->region->v2d.hor : az->region->v2d.vert;
907 BLI_rcti_translate(&scroller_vert, az->region->winrct.xmin, az->region->winrct.ymin);
908
909 /* Pull the zone in from edge and match the visible hit zone. */
910 const int edge_padding = int(-3.0f * UI_SCALE_FAC);
911 r_rect->xmin = scroller_vert.xmin - (is_right ? V2D_SCROLL_HIDE_HEIGHT : edge_padding);
912 r_rect->ymin = scroller_vert.ymin - (is_top ? V2D_SCROLL_HIDE_WIDTH : edge_padding);
913 r_rect->xmax = scroller_vert.xmax + (is_left ? V2D_SCROLL_HIDE_HEIGHT : edge_padding);
914 r_rect->ymax = scroller_vert.ymax + (is_bottom ? V2D_SCROLL_HIDE_WIDTH : edge_padding);
915 }
916 else {
917 azone_clipped_rect_calc(az, r_rect);
918 }
919}
920
921static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const bool test_only)
922{
923 AZone *az = nullptr;
924
925 for (az = static_cast<AZone *>(area->actionzones.first); az; az = az->next) {
926 rcti az_rect;
927 area_actionzone_get_rect(az, &az_rect);
928 if (BLI_rcti_isect_pt_v(&az_rect, xy)) {
929
930 if (az->type == AZONE_AREA) {
931 break;
932 }
933 if (az->type == AZONE_REGION) {
934 const ARegion *region = az->region;
935 const int local_xy[2] = {xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin};
936
937 /* Respect button sections: Clusters of buttons (separated using separator-spacers) are
938 * drawn with a background, in-between them the region is fully transparent (if "Region
939 * Overlap" is enabled). Only allow dragging visible edges, so at the button sections. */
940 if (region->runtime->visible && region->overlap &&
943 {
944 az = nullptr;
945 break;
946 }
947
948 break;
949 }
950 if (az->type == AZONE_FULLSCREEN) {
951 rcti click_rect;
952 fullscreen_click_rcti_init(&click_rect, az->x1, az->y1, az->x2, az->y2);
953 const bool click_isect = BLI_rcti_isect_pt_v(&click_rect, xy);
954
955 if (test_only) {
956 if (click_isect) {
957 break;
958 }
959 }
960 else {
961 if (click_isect) {
962 az->alpha = 1.0f;
963 }
964 else {
965 const int mouse_sq = square_i(xy[0] - az->x2) + square_i(xy[1] - az->y2);
966 const int spot_sq = square_i(UI_AZONESPOTW_RIGHT);
967 const int fadein_sq = square_i(AZONEFADEIN);
968 const int fadeout_sq = square_i(AZONEFADEOUT);
969
970 if (mouse_sq < spot_sq) {
971 az->alpha = 1.0f;
972 }
973 else if (mouse_sq < fadein_sq) {
974 az->alpha = 1.0f;
975 }
976 else if (mouse_sq < fadeout_sq) {
977 az->alpha = 1.0f - float(mouse_sq - fadein_sq) / float(fadeout_sq - fadein_sq);
978 }
979 else {
980 az->alpha = 0.0f;
981 }
982
983 /* fade in/out but no click */
984 az = nullptr;
985 }
986
987 /* XXX force redraw to show/hide the action zone */
988 ED_area_tag_redraw(area);
989 break;
990 }
991 }
992 else if (az->type == AZONE_REGION_SCROLL && az->region->runtime->visible) {
993 /* If the region is not visible we can ignore this scroll-bar zone. */
994 ARegion *region = az->region;
995 View2D *v2d = &region->v2d;
996 int scroll_flag = 0;
997 const int isect_value = UI_view2d_mouse_in_scrollers_ex(region, v2d, xy, &scroll_flag);
998
999 /* Check if we even have scroll bars. */
1000 if (((az->direction == AZ_SCROLL_HOR) && !(scroll_flag & V2D_SCROLL_HORIZONTAL)) ||
1001 ((az->direction == AZ_SCROLL_VERT) && !(scroll_flag & V2D_SCROLL_VERTICAL)))
1002 {
1003 /* No scroll-bars, do nothing. */
1004 }
1005 else if (test_only) {
1006 if (isect_value != 0) {
1007 break;
1008 }
1009 }
1010 else {
1011 bool redraw = false;
1012
1013 if (isect_value == 'h') {
1014 if (az->direction == AZ_SCROLL_HOR) {
1015 az->alpha = 1.0f;
1016 v2d->alpha_hor = 255;
1017 redraw = true;
1018 }
1019 }
1020 else if (isect_value == 'v') {
1021 if (az->direction == AZ_SCROLL_VERT) {
1022 az->alpha = 1.0f;
1023 v2d->alpha_vert = 255;
1024 redraw = true;
1025 }
1026 }
1027 else {
1028 const int local_xy[2] = {xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin};
1029 float dist_fac = 0.0f, alpha = 0.0f;
1030
1031 if (az->direction == AZ_SCROLL_HOR) {
1032 dist_fac = BLI_rcti_length_y(&v2d->hor, local_xy[1]) / V2D_SCROLL_HIDE_WIDTH;
1033 CLAMP(dist_fac, 0.0f, 1.0f);
1034 alpha = 1.0f - dist_fac;
1035
1036 v2d->alpha_hor = alpha * 255;
1037 }
1038 else if (az->direction == AZ_SCROLL_VERT) {
1039 dist_fac = BLI_rcti_length_x(&v2d->vert, local_xy[0]) / V2D_SCROLL_HIDE_HEIGHT;
1040 CLAMP(dist_fac, 0.0f, 1.0f);
1041 alpha = 1.0f - dist_fac;
1042
1043 v2d->alpha_vert = alpha * 255;
1044 }
1045 az->alpha = alpha;
1046 redraw = true;
1047 }
1048
1049 if (redraw) {
1051 }
1052 /* Don't return! */
1053 }
1054 }
1055 }
1056 else if (!test_only && !IS_EQF(az->alpha, 0.0f)) {
1057 if (az->type == AZONE_FULLSCREEN) {
1058 az->alpha = 0.0f;
1061 }
1062 else if (az->type == AZONE_REGION_SCROLL && az->region->runtime->visible) {
1063 /* If the region is not visible we can ignore this scroll-bar zone. */
1064 if (az->direction == AZ_SCROLL_VERT) {
1065 az->alpha = az->region->v2d.alpha_vert = 0;
1068 }
1069 else if (az->direction == AZ_SCROLL_HOR) {
1070 az->alpha = az->region->v2d.alpha_hor = 0;
1073 }
1074 else {
1075 BLI_assert(false);
1076 }
1077 }
1078 }
1079 }
1080
1081 return az;
1082}
1083
1084/* Finds an action-zone by position in entire screen so azones can overlap. */
1085static AZone *screen_actionzone_find_xy(bScreen *screen, const int xy[2])
1086{
1087 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1088 AZone *az = area_actionzone_refresh_xy(area, xy, true);
1089 if (az != nullptr) {
1090 return az;
1091 }
1092 }
1093 return nullptr;
1094}
1095
1096/* Returns the area that the azone belongs to */
1097static ScrArea *screen_actionzone_area(bScreen *screen, const AZone *az)
1098{
1099 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1100 LISTBASE_FOREACH (AZone *, zone, &area->actionzones) {
1101 if (zone == az) {
1102 return area;
1103 }
1104 }
1105 }
1106 return nullptr;
1107}
1108
1110{
1111 return area_actionzone_refresh_xy(area, xy, true);
1112}
1113
1115{
1116 return area_actionzone_refresh_xy(area, xy, false);
1117}
1118
1120{
1121 sActionzoneData *sad = static_cast<sActionzoneData *>(op->customdata);
1122 if (sad) {
1123 MEM_freeN(sad);
1124 }
1125 op->customdata = nullptr;
1126
1128}
1129
1130/* send EVT_ACTIONZONE event */
1131static void actionzone_apply(bContext *C, wmOperator *op, int type)
1132{
1133 wmWindow *win = CTX_wm_window(C);
1134
1135 wmEvent event;
1136 wm_event_init_from_window(win, &event);
1137
1138 if (type == AZONE_AREA) {
1139 event.type = EVT_ACTIONZONE_AREA;
1140 }
1141 else if (type == AZONE_FULLSCREEN) {
1142 event.type = EVT_ACTIONZONE_FULLSCREEN;
1143 }
1144 else {
1145 event.type = EVT_ACTIONZONE_REGION;
1146 }
1147
1148 event.val = KM_NOTHING;
1149 event.flag = eWM_EventFlag(0);
1150 event.customdata = op->customdata;
1151 event.customdata_free = true;
1152 op->customdata = nullptr;
1153
1154 WM_event_add(win, &event);
1155}
1156
1158{
1159 bScreen *screen = CTX_wm_screen(C);
1160 AZone *az = screen_actionzone_find_xy(screen, event->xy);
1161
1162 /* Quick escape - Scroll azones only hide/unhide the scroll-bars,
1163 * they have their own handling. */
1164 if (az == nullptr || ELEM(az->type, AZONE_REGION_SCROLL)) {
1165 return OPERATOR_PASS_THROUGH;
1166 }
1167
1168 /* ok we do the action-zone */
1169 sActionzoneData *sad = static_cast<sActionzoneData *>(
1170 op->customdata = MEM_callocN(sizeof(sActionzoneData), "sActionzoneData"));
1171 sad->sa1 = screen_actionzone_area(screen, az);
1172 sad->az = az;
1173 sad->x = event->xy[0];
1174 sad->y = event->xy[1];
1175 sad->modifier = RNA_int_get(op->ptr, "modifier");
1176
1177 /* region azone directly reacts on mouse clicks */
1178 if (ELEM(sad->az->type, AZONE_REGION, AZONE_FULLSCREEN)) {
1179 actionzone_apply(C, op, sad->az->type);
1180 actionzone_exit(op);
1181 return OPERATOR_FINISHED;
1182 }
1183
1184 if (sad->az->type == AZONE_AREA && sad->modifier == 0) {
1185 actionzone_apply(C, op, sad->az->type);
1186 actionzone_exit(op);
1187 return OPERATOR_FINISHED;
1188 }
1189
1190 /* add modal handler */
1194}
1195
1197{
1198 bScreen *screen = CTX_wm_screen(C);
1199 sActionzoneData *sad = static_cast<sActionzoneData *>(op->customdata);
1200
1201 switch (event->type) {
1202 case MOUSEMOVE: {
1203 const int delta_x = (event->xy[0] - sad->x);
1204 const int delta_y = (event->xy[1] - sad->y);
1205
1206 /* Movement in dominant direction. */
1207 const int delta_max = max_ii(abs(delta_x), abs(delta_y));
1208
1209 /* Movement in dominant direction before action taken. */
1210 const int join_threshold = (0.6 * U.widget_unit);
1211 const int split_threshold = (1.2 * U.widget_unit);
1212 const int area_threshold = (0.1 * U.widget_unit);
1213
1214 /* Calculate gesture cardinal direction. */
1215 if (delta_y > abs(delta_x)) {
1217 }
1218 else if (delta_x >= abs(delta_y)) {
1220 }
1221 else if (delta_y < -abs(delta_x)) {
1223 }
1224 else {
1226 }
1227
1228 bool is_gesture;
1229 if (sad->az->type == AZONE_AREA) {
1230 wmWindow *win = CTX_wm_window(C);
1231
1232 rcti screen_rect;
1233 WM_window_screen_rect_calc(win, &screen_rect);
1234
1235 /* Have we dragged off the zone and are not on an edge? */
1236 if ((ED_area_actionzone_find_xy(sad->sa1, event->xy) != sad->az) &&
1238 AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) ==
1239 nullptr))
1240 {
1241
1242 /* What area are we now in? */
1243 ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
1244
1245 if (sad->modifier == 1) {
1246 /* Duplicate area into new window. */
1248 is_gesture = (delta_max > area_threshold);
1249 }
1250 else if (sad->modifier == 2) {
1251 /* Swap areas. */
1253 is_gesture = true;
1254 }
1255 else if (area == sad->sa1) {
1256 /* Same area, so possible split. */
1257 WM_cursor_set(win,
1260 is_gesture = (delta_max > split_threshold);
1261 }
1262 else if (!area || area->global) {
1263 /* No area or Top bar or Status bar. */
1265 is_gesture = false;
1266 }
1267 else {
1268 /* Different area, so possible join. */
1269 if (sad->gesture_dir == SCREEN_DIR_N) {
1271 }
1272 else if (sad->gesture_dir == SCREEN_DIR_S) {
1274 }
1275 else if (sad->gesture_dir == SCREEN_DIR_E) {
1277 }
1278 else {
1281 }
1282 is_gesture = (delta_max > join_threshold);
1283 }
1284 }
1285 else {
1286#if defined(__APPLE__)
1287 const int cursor = WM_CURSOR_HAND_CLOSED;
1288#else
1289 const int cursor = WM_CURSOR_MOVE;
1290#endif
1291 WM_cursor_set(win, cursor);
1292 is_gesture = false;
1293 }
1294 }
1295 else {
1296 is_gesture = (delta_max > area_threshold);
1297 }
1298
1299 /* gesture is large enough? */
1300 if (is_gesture) {
1301 /* second area, for join when (sa1 != sa2) */
1302 sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
1303 /* apply sends event */
1304 actionzone_apply(C, op, sad->az->type);
1305 actionzone_exit(op);
1306
1307 return OPERATOR_FINISHED;
1308 }
1309 break;
1310 }
1311 case EVT_ESCKEY:
1312 actionzone_exit(op);
1313 return OPERATOR_CANCELLED;
1314 case LEFTMOUSE:
1315 actionzone_exit(op);
1316 return OPERATOR_CANCELLED;
1317 default: {
1318 break;
1319 }
1320 }
1321
1323}
1324
1325static void actionzone_cancel(bContext * /*C*/, wmOperator *op)
1326{
1327 actionzone_exit(op);
1328}
1329
1331{
1332 /* identifiers */
1333 ot->name = "Handle Area Action Zones";
1334 ot->description = "Handle area action zones for mouse actions/gestures";
1335 ot->idname = "SCREEN_OT_actionzone";
1336
1337 ot->invoke = actionzone_invoke;
1338 ot->modal = actionzone_modal;
1339 ot->poll = actionzone_area_poll;
1340 ot->cancel = actionzone_cancel;
1341
1342 /* flags */
1344
1345 RNA_def_int(ot->srna, "modifier", 0, 0, 2, "Modifier", "Modifier state", 0, 2);
1346}
1347
1349
1350/* -------------------------------------------------------------------- */
1353
1355 const int cursor[2],
1356 ScrArea **r_sa1,
1357 ScrArea **r_sa2)
1358{
1359 wmWindow *win = CTX_wm_window(C);
1360 bScreen *screen = CTX_wm_screen(C);
1361 rcti window_rect;
1362 WM_window_rect_calc(win, &window_rect);
1364 AREAMAP_FROM_SCREEN(screen), &window_rect, cursor[0], cursor[1]);
1365 *r_sa1 = nullptr;
1366 *r_sa2 = nullptr;
1367 if (actedge == nullptr) {
1368 return nullptr;
1369 }
1370 int borderwidth = (4 * UI_SCALE_FAC);
1371 ScrArea *sa1, *sa2;
1372 if (screen_geom_edge_is_horizontal(actedge)) {
1374 screen, SPACE_TYPE_ANY, blender::int2{cursor[0], cursor[1] + borderwidth});
1376 screen, SPACE_TYPE_ANY, blender::int2{cursor[0], cursor[1] - borderwidth});
1377 }
1378 else {
1380 screen, SPACE_TYPE_ANY, blender::int2{cursor[0] + borderwidth, cursor[1]});
1382 screen, SPACE_TYPE_ANY, blender::int2{cursor[0] - borderwidth, cursor[1]});
1383 }
1384 bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2)));
1385 if (!isGlobal) {
1386 *r_sa1 = sa1;
1387 *r_sa2 = sa2;
1388 }
1389 return actedge;
1390}
1391
1393
1394/* -------------------------------------------------------------------- */
1397
1398/* operator state vars used:
1399 * sa1 start area
1400 * sa2 area to swap with
1401 *
1402 * functions:
1403 *
1404 * init() set custom data for operator, based on action-zone event custom data
1405 *
1406 * cancel() cancel the operator
1407 *
1408 * exit() cleanup, send notifier
1409 *
1410 * callbacks:
1411 *
1412 * invoke() gets called on Shift-LMB drag in action-zone
1413 * exec() execute without any user interaction, based on properties
1414 * call init(), add handler
1415 *
1416 * modal() accept modal events while doing it
1417 */
1418
1421};
1422
1423static bool area_swap_init(wmOperator *op, const wmEvent *event)
1424{
1425 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
1426
1427 if (sad == nullptr || sad->sa1 == nullptr) {
1428 return false;
1429 }
1430
1431 sAreaSwapData *sd = MEM_callocN<sAreaSwapData>("sAreaSwapData");
1432 sd->sa1 = sad->sa1;
1433 sd->sa2 = sad->sa2;
1434 op->customdata = sd;
1435
1436 return true;
1437}
1438
1440{
1441 sAreaSwapData *sd = static_cast<sAreaSwapData *>(op->customdata);
1442 MEM_freeN(sd);
1443 op->customdata = nullptr;
1444
1446 ED_workspace_status_text(C, nullptr);
1447}
1448
1450{
1451 area_swap_exit(C, op);
1452}
1453
1455{
1456 if (!area_swap_init(op, event)) {
1457 return OPERATOR_PASS_THROUGH;
1458 }
1459
1460 /* add modal handler */
1463
1465}
1466
1468{
1469 sActionzoneData *sad = static_cast<sActionzoneData *>(op->customdata);
1470
1471 switch (event->type) {
1472 case MOUSEMOVE: {
1473 /* Second area to swap with. */
1477 status.item(IFACE_("Select Area"), ICON_MOUSE_LMB);
1478 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
1479 break;
1480 }
1481 case LEFTMOUSE: /* release LMB */
1482 if (event->val == KM_RELEASE) {
1483 if (!sad->sa2 || sad->sa1 == sad->sa2) {
1484 area_swap_cancel(C, op);
1485 return OPERATOR_CANCELLED;
1486 }
1487
1488 ED_area_tag_redraw(sad->sa1);
1489 ED_area_tag_redraw(sad->sa2);
1490
1491 ED_area_swapspace(C, sad->sa1, sad->sa2);
1492
1493 area_swap_exit(C, op);
1494
1496
1497 return OPERATOR_FINISHED;
1498 }
1499 break;
1500
1501 case EVT_ESCKEY:
1502 area_swap_cancel(C, op);
1503 return OPERATOR_CANCELLED;
1504 default: {
1505 break;
1506 }
1507 }
1509}
1510
1512{
1513 ScrArea *sa1, *sa2;
1514 int cursor[2];
1515 RNA_int_get_array(op->ptr, "cursor", cursor);
1516 screen_area_edge_from_cursor(C, cursor, &sa1, &sa2);
1517 if (sa1 == nullptr || sa2 == nullptr) {
1518 return OPERATOR_CANCELLED;
1519 }
1520 ED_area_swapspace(C, sa1, sa2);
1521 return OPERATOR_FINISHED;
1522}
1523
1525{
1526 ot->name = "Swap Areas";
1527 ot->description = "Swap selected areas screen positions";
1528 ot->idname = "SCREEN_OT_area_swap";
1529
1530 ot->invoke = area_swap_invoke;
1531 ot->modal = area_swap_modal;
1532 ot->exec = area_swap_exec;
1533 ot->poll = screen_active_editable;
1534 ot->cancel = area_swap_cancel;
1535
1536 ot->flag = OPTYPE_BLOCKING;
1537
1538 /* rna */
1540 ot->srna, "cursor", 2, nullptr, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX);
1541}
1542
1544
1545/* -------------------------------------------------------------------- */
1550
1552static void area_dupli_fn(bScreen * /*screen*/, ScrArea *area, void *user_data)
1553{
1554 ScrArea *area_src = static_cast<ScrArea *>(user_data);
1555 ED_area_data_copy(area, area_src, true);
1556 ED_area_tag_redraw(area);
1557}
1558
1559/* operator callback */
1560static bool area_dupli_open(bContext *C, ScrArea *area, const blender::int2 position)
1561{
1562 const wmWindow *win = CTX_wm_window(C);
1563 const rcti window_rect = {win->posx + position.x,
1564 win->posx + position.x + area->winx,
1565 win->posy + position.y,
1566 win->posy + position.y + area->winy};
1567
1568 /* Create new window. No need to set space_type since it will be copied over. */
1569 wmWindow *newwin = WM_window_open(C,
1570 nullptr,
1571 &window_rect,
1573 false,
1574 false,
1575 false,
1577 /* Initialize area from callback. */
1579 (void *)area);
1580 return (newwin != nullptr);
1581}
1582
1584{
1585 ScrArea *area = CTX_wm_area(C);
1586 if (event && event->customdata) {
1587 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
1588 if (sad == nullptr) {
1589 return OPERATOR_PASS_THROUGH;
1590 }
1591 area = sad->sa1;
1592 }
1593
1594 bool newwin = area_dupli_open(C, area, blender::int2(area->totrct.xmin, area->totrct.ymin));
1595
1596 if (newwin) {
1597 /* screen, areas init */
1599 }
1600 else {
1601 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
1602 }
1603
1604 if (event && event->customdata) {
1605 actionzone_exit(op);
1606 }
1607
1608 return newwin ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1609}
1610
1612{
1613 ot->name = "Duplicate Area into New Window";
1614 ot->description = "Duplicate selected area into new window";
1615 ot->idname = "SCREEN_OT_area_dupli";
1616
1617 ot->invoke = area_dupli_invoke;
1618 ot->poll = ED_operator_areaactive;
1619}
1620
1622
1623/* -------------------------------------------------------------------- */
1628
1637{
1638 bScreen *screen = CTX_wm_screen(C);
1639 ScrArea *area = CTX_wm_area(C);
1640
1641 /* This operator is script-able, so the area passed could be invalid. */
1642 if (BLI_findindex(&screen->areabase, area) == -1) {
1643 BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen");
1644 return OPERATOR_CANCELLED;
1645 }
1646
1647 float inner[4] = {0.0f, 0.0f, 0.0f, 0.7f};
1649 CTX_wm_window(C), CTX_wm_screen(C), &area->totrct, inner, nullptr, AREA_CLOSE_FADEOUT);
1650
1651 if (!screen_area_close(C, op->reports, screen, area)) {
1652 BKE_report(op->reports, RPT_ERROR, "Unable to close area");
1653 return OPERATOR_CANCELLED;
1654 }
1655
1656 /* Ensure the event loop doesn't attempt to continue handling events.
1657 *
1658 * This causes execution from the Python console fail to return to the prompt as it should.
1659 * This glitch could be solved in the event loop handling as other operators may also
1660 * destructively manipulate windowing data. */
1661 CTX_wm_window_set(C, nullptr);
1662
1664
1665 return OPERATOR_FINISHED;
1666}
1667
1669{
1670 if (!ED_operator_areaactive(C)) {
1671 return false;
1672 }
1673
1674 ScrArea *area = CTX_wm_area(C);
1675
1676 if (ED_area_is_global(area)) {
1677 return false;
1678 }
1679
1680 bScreen *screen = CTX_wm_screen(C);
1681
1682 /* Can this area join with ANY other area? */
1683 LISTBASE_FOREACH (ScrArea *, ar, &screen->areabase) {
1684 if (area_getorientation(ar, area) != -1) {
1685 return true;
1686 }
1687 }
1688
1689 return false;
1690}
1691
1693{
1694 ot->name = "Close Area";
1695 ot->description = "Close selected area";
1696 ot->idname = "SCREEN_OT_area_close";
1697 ot->exec = area_close_exec;
1698 ot->poll = area_close_poll;
1699}
1700
1702
1703/* -------------------------------------------------------------------- */
1706
1707/* operator state vars used:
1708 * x, y mouse coord near edge
1709 * delta movement of edge
1710 *
1711 * functions:
1712 *
1713 * init() set default property values, find edge based on mouse coords, test
1714 * if the edge can be moved, select edges, calculate min and max movement
1715 *
1716 * apply() apply delta on selection
1717 *
1718 * exit() cleanup, send notifier
1719 *
1720 * cancel() cancel moving
1721 *
1722 * callbacks:
1723 *
1724 * exec() execute without any user interaction, based on properties
1725 * call init(), apply(), exit()
1726 *
1727 * invoke() gets called on mouse click near edge
1728 * call init(), add handler
1729 *
1730 * modal() accept modal events while doing it
1731 * call apply() with delta motion
1732 * call exit() and remove handler
1733 */
1734
1736 /* Snapping disabled */
1737 SNAP_NONE = 0, /* Snap to an invisible grid with a unit defined in AREAGRID */
1738 SNAP_AREAGRID, /* Snap to fraction (half, third.. etc) and adjacent edges. */
1739 SNAP_FRACTION_AND_ADJACENT, /* Snap to either bigger or smaller, nothing in-between (used for
1740 * global areas). This has priority over other snap types, if it is
1741 * used, toggling SNAP_FRACTION_AND_ADJACENT doesn't work. */
1743};
1744
1755
1756/* helper call to move area-edge, sets limits
1757 * need window bounds in order to get correct limits */
1759 bScreen *screen,
1760 const eScreenAxis dir_axis,
1761 int *bigger,
1762 int *smaller,
1763 bool *use_bigger_smaller_snap)
1764{
1765 /* we check all areas and test for free space with MINSIZE */
1766 *bigger = *smaller = 100000;
1767
1768 if (use_bigger_smaller_snap != nullptr) {
1769 *use_bigger_smaller_snap = false;
1771 int size_min = ED_area_global_min_size_y(area) - 1;
1772 int size_max = ED_area_global_max_size_y(area) - 1;
1773
1774 size_min = max_ii(size_min, 0);
1775 BLI_assert(size_min <= size_max);
1776
1777 /* logic here is only tested for lower edge :) */
1778 /* left edge */
1779 if (area->v1->editflag && area->v2->editflag) {
1780 *smaller = area->v4->vec.x - size_max;
1781 *bigger = area->v4->vec.x - size_min;
1782 *use_bigger_smaller_snap = true;
1783 return;
1784 }
1785 /* top edge */
1786 if (area->v2->editflag && area->v3->editflag) {
1787 *smaller = area->v1->vec.y + size_min;
1788 *bigger = area->v1->vec.y + size_max;
1789 *use_bigger_smaller_snap = true;
1790 return;
1791 }
1792 /* right edge */
1793 if (area->v3->editflag && area->v4->editflag) {
1794 *smaller = area->v1->vec.x + size_min;
1795 *bigger = area->v1->vec.x + size_max;
1796 *use_bigger_smaller_snap = true;
1797 return;
1798 }
1799 /* lower edge */
1800 if (area->v4->editflag && area->v1->editflag) {
1801 *smaller = area->v2->vec.y - size_max;
1802 *bigger = area->v2->vec.y - size_min;
1803 *use_bigger_smaller_snap = true;
1804 return;
1805 }
1806 }
1807 }
1808
1809 rcti window_rect;
1810 WM_window_rect_calc(win, &window_rect);
1811
1812 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1813 if (dir_axis == SCREEN_AXIS_H) {
1814 const int y1 = area->winy - ED_area_headersize();
1815 /* if top or down edge selected, test height */
1816 if (area->v1->editflag && area->v4->editflag) {
1817 *bigger = min_ii(*bigger, y1);
1818 }
1819 else if (area->v2->editflag && area->v3->editflag) {
1820 *smaller = min_ii(*smaller, y1);
1821 }
1822 }
1823 else {
1824 const int x1 = area->winx - int(AREAMINX * UI_SCALE_FAC) - 1;
1825 /* if left or right edge selected, test width */
1826 if (area->v1->editflag && area->v2->editflag) {
1827 *bigger = min_ii(*bigger, x1);
1828 }
1829 else if (area->v3->editflag && area->v4->editflag) {
1830 *smaller = min_ii(*smaller, x1);
1831 }
1832 }
1833 }
1834}
1835
1836static void area_move_draw_cb(const wmWindow *win, void *userdata)
1837{
1838 const wmOperator *op = static_cast<const wmOperator *>(userdata);
1839 const sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
1840 const double now = BLI_time_now_seconds();
1841 float factor = 1.0f;
1842 if (now < md->end_time) {
1843 factor = pow((now - md->start_time) / (md->end_time - md->start_time), 2);
1844 md->screen->do_refresh = true;
1845 }
1846 screen_draw_move_highlight(win, md->screen, md->dir_axis, factor);
1847}
1848
1849static void area_move_out_draw_cb(const wmWindow *win, void *userdata)
1850{
1851 const sAreaMoveData *md = static_cast<sAreaMoveData *>(userdata);
1852 const double now = BLI_time_now_seconds();
1853 float factor = 1.0f;
1854 if (now > md->end_time) {
1856 MEM_freeN(md);
1857 return;
1858 }
1859 if (now < md->end_time) {
1860 factor = 1.0f - pow((now - md->start_time) / (md->end_time - md->start_time), 2);
1861 md->screen->do_refresh = true;
1862 }
1863 screen_draw_move_highlight(win, md->screen, md->dir_axis, factor);
1864}
1865
1866/* validate selection inside screen, set variables OK */
1867/* return false: init failed */
1869{
1870 bScreen *screen = CTX_wm_screen(C);
1871 wmWindow *win = CTX_wm_window(C);
1872 ScrArea *area = CTX_wm_area(C);
1873
1874 /* required properties */
1875 int x = RNA_int_get(op->ptr, "x");
1876 int y = RNA_int_get(op->ptr, "y");
1877
1878 /* setup */
1879 ScrEdge *actedge = screen_geom_find_active_scredge(win, screen, x, y);
1880
1881 if (area) {
1882 /* Favor scroll bars and action zones over expanded edge zone. */
1883 const int xy[2] = {x, y};
1884 if (ED_area_actionzone_find_xy(area, xy)) {
1885 return false;
1886 }
1887 }
1888
1889 if (actedge == nullptr) {
1890 return false;
1891 }
1892
1893 sAreaMoveData *md = MEM_callocN<sAreaMoveData>("sAreaMoveData");
1894 op->customdata = md;
1895
1897 if (md->dir_axis == SCREEN_AXIS_H) {
1898 md->origval = actedge->v1->vec.y;
1899 }
1900 else {
1901 md->origval = actedge->v1->vec.x;
1902 }
1903
1905 /* now all vertices with 'flag == 1' are the ones that can be moved. Move this to editflag */
1906 ED_screen_verts_iter(win, screen, v1)
1907 {
1908 v1->editflag = v1->flag;
1909 }
1910
1911 bool use_bigger_smaller_snap = false;
1913 win, screen, md->dir_axis, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
1914
1915 md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID;
1916
1917 md->screen = screen;
1921
1922 return true;
1923}
1924
1925static int area_snap_calc_location(const bScreen *screen,
1926 const enum AreaMoveSnapType snap_type,
1927 const int delta,
1928 const int origval,
1929 const eScreenAxis dir_axis,
1930 const int bigger,
1931 const int smaller)
1932{
1933 BLI_assert(snap_type != SNAP_NONE);
1934 int m_cursor_final = -1;
1935 const int m_cursor = origval + delta;
1936 const int m_span = float(bigger + smaller);
1937 const int m_min = origval - smaller;
1938 // const int axis_max = axis_min + m_span;
1939
1940 switch (snap_type) {
1941 case SNAP_AREAGRID: {
1942 m_cursor_final = m_cursor;
1943 if (!ELEM(delta, bigger, -smaller)) {
1944 m_cursor_final -= (m_cursor % AREAGRID);
1945 CLAMP(m_cursor_final, origval - smaller, origval + bigger);
1946 }
1947
1948 /* Slight snap to vertical minimum and maximum. */
1949 const int snap_threshold = int(float(ED_area_headersize()) * 0.6f);
1950 if (m_cursor_final < (m_min + snap_threshold)) {
1951 m_cursor_final = m_min;
1952 }
1953 else if (m_cursor_final > (origval + bigger - snap_threshold)) {
1954 m_cursor_final = origval + bigger;
1955 }
1956 } break;
1957
1959 m_cursor_final = (m_cursor >= bigger) ? bigger : smaller;
1960 break;
1961
1963 const int axis = (dir_axis == SCREEN_AXIS_V) ? 0 : 1;
1964 int snap_dist_best = INT_MAX;
1965 {
1966 const float div_array[] = {
1967 0.0f,
1968 1.0f / 12.0f,
1969 2.0f / 12.0f,
1970 3.0f / 12.0f,
1971 4.0f / 12.0f,
1972 5.0f / 12.0f,
1973 6.0f / 12.0f,
1974 7.0f / 12.0f,
1975 8.0f / 12.0f,
1976 9.0f / 12.0f,
1977 10.0f / 12.0f,
1978 11.0f / 12.0f,
1979 1.0f,
1980 };
1981 /* Test the snap to the best division. */
1982 for (int i = 0; i < ARRAY_SIZE(div_array); i++) {
1983 const int m_cursor_test = m_min + round_fl_to_int(m_span * div_array[i]);
1984 const int snap_dist_test = abs(m_cursor - m_cursor_test);
1985 if (snap_dist_best >= snap_dist_test) {
1986 snap_dist_best = snap_dist_test;
1987 m_cursor_final = m_cursor_test;
1988 }
1989 }
1990 }
1991
1992 LISTBASE_FOREACH (const ScrVert *, v1, &screen->vertbase) {
1993 if (!v1->editflag) {
1994 continue;
1995 }
1996 const int v_loc = (&v1->vec.x)[!axis];
1997
1998 LISTBASE_FOREACH (const ScrVert *, v2, &screen->vertbase) {
1999 if (v2->editflag) {
2000 continue;
2001 }
2002 if (v_loc == (&v2->vec.x)[!axis]) {
2003 const int v_loc2 = (&v2->vec.x)[axis];
2004 /* Do not snap to the vertices at the ends. */
2005 if ((origval - smaller) < v_loc2 && v_loc2 < (origval + bigger)) {
2006 const int snap_dist_test = abs(m_cursor - v_loc2);
2007 if (snap_dist_best >= snap_dist_test) {
2008 snap_dist_best = snap_dist_test;
2009 m_cursor_final = v_loc2;
2010 }
2011 }
2012 }
2013 }
2014 }
2015 break;
2016 }
2017 case SNAP_NONE:
2018 break;
2019 }
2020
2022 IN_RANGE_INCL(m_cursor_final, origval - smaller, origval + bigger));
2023
2024 return m_cursor_final;
2025}
2026
2027/* moves selected screen edge amount of delta, used by split & move */
2029 int delta,
2030 const int origval,
2031 const eScreenAxis dir_axis,
2032 const int bigger,
2033 const int smaller,
2034 const enum AreaMoveSnapType snap_type)
2035{
2037 status.item(IFACE_("Confirm"), ICON_MOUSE_LMB);
2038 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
2039 status.item_bool(IFACE_("Snap"), snap_type == SNAP_FRACTION_AND_ADJACENT, ICON_EVENT_CTRL);
2040
2041 wmWindow *win = CTX_wm_window(C);
2042 bScreen *screen = CTX_wm_screen(C);
2043 short final_loc = -1;
2044 bool doredraw = false;
2045
2046 if (snap_type != SNAP_BIGGER_SMALLER_ONLY) {
2047 CLAMP(delta, -smaller, bigger);
2048 }
2049
2050 if (snap_type == SNAP_NONE) {
2051 final_loc = origval + delta;
2052 }
2053 else {
2054 final_loc = area_snap_calc_location(
2055 screen, snap_type, delta, origval, dir_axis, bigger, smaller);
2056 }
2057
2058 BLI_assert(final_loc != -1);
2059 short axis = (dir_axis == SCREEN_AXIS_V) ? 0 : 1;
2060
2061 ED_screen_verts_iter(win, screen, v1)
2062 {
2063 if (v1->editflag) {
2064 short oldval = (&v1->vec.x)[axis];
2065 (&v1->vec.x)[axis] = final_loc;
2066
2067 if (oldval == final_loc) {
2068 /* nothing will change to the other vertices either. */
2069 break;
2070 }
2071 doredraw = true;
2072 }
2073 }
2074
2075 /* only redraw if we actually moved a screen vert, for AREAGRID */
2076 if (doredraw) {
2077 bool redraw_all = false;
2078 ED_screen_areas_iter (win, screen, area) {
2079 if (area->v1->editflag || area->v2->editflag || area->v3->editflag || area->v4->editflag) {
2080 if (ED_area_is_global(area)) {
2081 /* Snap to minimum or maximum for global areas. */
2083 if (abs(height - area->global->size_min) < abs(height - area->global->size_max)) {
2084 area->global->cur_fixed_height = area->global->size_min;
2085 }
2086 else {
2087 area->global->cur_fixed_height = area->global->size_max;
2088 }
2089
2090 screen->do_refresh = true;
2091 redraw_all = true;
2092 }
2094 }
2095 }
2096 if (redraw_all) {
2097 ED_screen_areas_iter (win, screen, area) {
2098 ED_area_tag_redraw(area);
2099 }
2100 }
2101
2103
2104 WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, nullptr); /* redraw everything */
2105 /* Update preview thumbnail */
2106 BKE_icon_changed(screen->id.icon_id);
2107 }
2108}
2109
2111{
2112 sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
2113 int delta = RNA_int_get(op->ptr, "delta");
2114
2115 area_move_apply_do(C, delta, md->origval, md->dir_axis, md->bigger, md->smaller, md->snap_type);
2116}
2117
2119{
2120 sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
2121 if (md->draw_callback) {
2123 }
2124
2125 op->customdata = nullptr;
2126
2129 md->win = CTX_wm_window(C);
2131
2132 /* this makes sure aligned edges will result in aligned grabbing */
2135 ED_workspace_status_text(C, nullptr);
2136
2138}
2139
2141{
2142 if (!area_move_init(C, op)) {
2143 return OPERATOR_CANCELLED;
2144 }
2145
2146 area_move_apply(C, op);
2147 area_move_exit(C, op);
2148
2149 return OPERATOR_FINISHED;
2150}
2151
2152/* interaction callback */
2154{
2155 RNA_int_set(op->ptr, "x", event->xy[0]);
2156 RNA_int_set(op->ptr, "y", event->xy[1]);
2157
2158 if (!area_move_init(C, op)) {
2159 return OPERATOR_PASS_THROUGH;
2160 }
2161
2162 sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
2163
2165 status.item(IFACE_("Confirm"), ICON_MOUSE_LMB);
2166 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
2167 status.item_bool(IFACE_("Snap"), md->snap_type == SNAP_FRACTION_AND_ADJACENT, ICON_EVENT_CTRL);
2168
2169 /* add temp handler */
2172
2174}
2175
2177{
2178
2179 RNA_int_set(op->ptr, "delta", 0);
2180 area_move_apply(C, op);
2181 area_move_exit(C, op);
2182}
2183
2184/* modal callback for while moving edges */
2186{
2187 sAreaMoveData *md = static_cast<sAreaMoveData *>(op->customdata);
2188
2189 /* execute the events */
2190 switch (event->type) {
2191 case MOUSEMOVE: {
2192 int x = RNA_int_get(op->ptr, "x");
2193 int y = RNA_int_get(op->ptr, "y");
2194
2195 const int delta = (md->dir_axis == SCREEN_AXIS_V) ? event->xy[0] - x : event->xy[1] - y;
2196 RNA_int_set(op->ptr, "delta", delta);
2197
2198 area_move_apply(C, op);
2199 break;
2200 }
2201 case RIGHTMOUSE: {
2202 area_move_cancel(C, op);
2203 return OPERATOR_CANCELLED;
2204 }
2205 case EVT_MODAL_MAP: {
2206 switch (event->val) {
2207 case KM_MODAL_APPLY:
2208 area_move_exit(C, op);
2209 return OPERATOR_FINISHED;
2210
2211 case KM_MODAL_CANCEL:
2212 area_move_cancel(C, op);
2213 return OPERATOR_CANCELLED;
2214
2215 case KM_MODAL_SNAP_ON:
2218 }
2219 break;
2220
2221 case KM_MODAL_SNAP_OFF:
2224 }
2225 break;
2226 }
2228 status.item(IFACE_("Confirm"), ICON_MOUSE_LMB);
2229 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
2230 status.item_bool(
2231 IFACE_("Snap"), md->snap_type == SNAP_FRACTION_AND_ADJACENT, ICON_EVENT_CTRL);
2232 break;
2233 }
2234 default: {
2235 break;
2236 }
2237 }
2238
2240}
2241
2243{
2244 /* identifiers */
2245 ot->name = "Move Area Edges";
2246 ot->description = "Move selected area edges";
2247 ot->idname = "SCREEN_OT_area_move";
2248
2249 ot->exec = area_move_exec;
2250 ot->invoke = area_move_invoke;
2251 ot->cancel = area_move_cancel;
2252 ot->modal = area_move_modal;
2253 ot->poll = ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
2254
2255 /* flags */
2257
2258 /* rna */
2259 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2260 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2261 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
2262}
2263
2265
2266/* -------------------------------------------------------------------- */
2269
2270/*
2271 * operator state vars:
2272 * fac spit point
2273 * dir direction #SCREEN_AXIS_V or #SCREEN_AXIS_H
2274 *
2275 * operator customdata:
2276 * area pointer to (active) area
2277 * x, y last used mouse pos
2278 * (more, see below)
2279 *
2280 * functions:
2281 *
2282 * init() set default property values, find area based on context
2283 *
2284 * apply() split area based on state vars
2285 *
2286 * exit() cleanup, send notifier
2287 *
2288 * cancel() remove duplicated area
2289 *
2290 * callbacks:
2291 *
2292 * exec() execute without any user interaction, based on state vars
2293 * call init(), apply(), exit()
2294 *
2295 * invoke() gets called on mouse click in action-widget
2296 * call init(), add modal handler
2297 * call apply() with initial motion
2298 *
2299 * modal() accept modal events while doing it
2300 * call move-areas code with delta motion
2301 * call exit() or cancel() and remove handler
2302 */
2303
2305 int origval; /* for move areas */
2306 int bigger, smaller; /* constraints for moving new edge */
2307 int delta; /* delta move edge */
2308 int origmin, origsize; /* to calculate fac, for property storage */
2309 int previewmode; /* draw preview-line, then split. */
2310 void *draw_callback; /* call `screen_draw_split_preview` */
2312
2313 ScrEdge *nedge; /* new edge */
2314 ScrArea *sarea; /* start area */
2315 ScrArea *narea; /* new area */
2316};
2317
2318static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis)
2319{
2320 if (!area || area->global) {
2321 /* Must be a non-global area. */
2322 return false;
2323 }
2324
2325 if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX * UI_SCALE_FAC) ||
2326 (dir_axis == SCREEN_AXIS_H && area->winy <= 2 * ED_area_headersize()))
2327 {
2328 /* Must be at least double minimum sizes to split into two. */
2329 return false;
2330 }
2331
2332 return true;
2333}
2334
2335static void area_split_draw_cb(const wmWindow * /*win*/, void *userdata)
2336{
2337 const wmOperator *op = static_cast<const wmOperator *>(userdata);
2338
2339 sAreaSplitData *sd = static_cast<sAreaSplitData *>(op->customdata);
2340 const eScreenAxis dir_axis = eScreenAxis(RNA_enum_get(op->ptr, "direction"));
2341
2342 if (area_split_allowed(sd->sarea, dir_axis)) {
2343 float fac = RNA_float_get(op->ptr, "factor");
2344 screen_draw_split_preview(sd->sarea, dir_axis, fac);
2345 }
2346}
2347
2348/* generic init, menu case, doesn't need active area */
2350{
2351 /* custom data */
2352 sAreaSplitData *sd = MEM_callocN<sAreaSplitData>("op_area_split");
2353 op->customdata = sd;
2354
2355 sd->sarea = CTX_wm_area(C);
2356
2357 return true;
2358}
2359
2360/* generic init, no UI stuff here, assumes active area */
2362{
2363 ScrArea *area = CTX_wm_area(C);
2364
2365 /* required context */
2366 if (area == nullptr) {
2367 return false;
2368 }
2369
2370 /* required properties */
2371 const eScreenAxis dir_axis = eScreenAxis(RNA_enum_get(op->ptr, "direction"));
2372
2373 /* custom data */
2374 sAreaSplitData *sd = MEM_callocN<sAreaSplitData>("op_area_split");
2375 op->customdata = sd;
2376
2377 sd->sarea = area;
2378 if (dir_axis == SCREEN_AXIS_V) {
2379 sd->origmin = area->v1->vec.x;
2380 sd->origsize = area->v4->vec.x - sd->origmin;
2381 }
2382 else {
2383 sd->origmin = area->v1->vec.y;
2384 sd->origsize = area->v2->vec.y - sd->origmin;
2385 }
2386
2387 return true;
2388}
2389
2390/* with area as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
2391/* used with split operator */
2393{
2394 ScrVert *sav1 = area->v1;
2395 ScrVert *sav2 = area->v2;
2396 ScrVert *sav3 = area->v3;
2397 ScrVert *sav4 = area->v4;
2398 ScrVert *sbv1 = sb->v1;
2399 ScrVert *sbv2 = sb->v2;
2400 ScrVert *sbv3 = sb->v3;
2401 ScrVert *sbv4 = sb->v4;
2402
2403 if (sav1 == sbv4 && sav2 == sbv3) { /* Area to right of sb = W. */
2404 return BKE_screen_find_edge(screen, sav1, sav2);
2405 }
2406 if (sav2 == sbv1 && sav3 == sbv4) { /* Area to bottom of sb = N. */
2407 return BKE_screen_find_edge(screen, sav2, sav3);
2408 }
2409 if (sav3 == sbv2 && sav4 == sbv1) { /* Area to left of sb = E. */
2410 return BKE_screen_find_edge(screen, sav3, sav4);
2411 }
2412 if (sav1 == sbv2 && sav4 == sbv3) { /* Area on top of sb = S. */
2413 return BKE_screen_find_edge(screen, sav1, sav4);
2414 }
2415
2416 return nullptr;
2417}
2418
2419/* do the split, return success */
2421{
2422 const wmWindow *win = CTX_wm_window(C);
2423 bScreen *screen = CTX_wm_screen(C);
2425
2426 float fac = RNA_float_get(op->ptr, "factor");
2427 const eScreenAxis dir_axis = eScreenAxis(RNA_enum_get(op->ptr, "direction"));
2428
2429 if (!area_split_allowed(sd->sarea, dir_axis)) {
2430 return false;
2431 }
2432
2433 sd->narea = area_split(win, screen, sd->sarea, dir_axis, fac, false); /* false = no merge */
2434
2435 if (sd->narea == nullptr) {
2436 return false;
2437 }
2438
2439 sd->nedge = area_findsharededge(screen, sd->sarea, sd->narea);
2440
2441 /* select newly created edge, prepare for moving edge */
2442 ED_screen_verts_iter(win, screen, sv)
2443 {
2444 sv->editflag = 0;
2445 }
2446
2447 sd->nedge->v1->editflag = 1;
2448 sd->nedge->v2->editflag = 1;
2449
2450 if (dir_axis == SCREEN_AXIS_H) {
2451 sd->origval = sd->nedge->v1->vec.y;
2452 }
2453 else {
2454 sd->origval = sd->nedge->v1->vec.x;
2455 }
2456
2459
2461 /* Update preview thumbnail */
2462 BKE_icon_changed(screen->id.icon_id);
2463
2464 /* We have more than one area now, so reset window title. */
2466
2467 return true;
2468}
2469
2471{
2472 if (op->customdata) {
2474 if (sd->sarea) {
2476 }
2477 if (sd->narea) {
2479 }
2480
2481 if (sd->draw_callback) {
2483 }
2484
2485 MEM_freeN(sd);
2486 op->customdata = nullptr;
2487 }
2488
2491 ED_workspace_status_text(C, nullptr);
2492
2493 /* this makes sure aligned edges will result in aligned grabbing */
2496
2498}
2499
2501{
2503 const eScreenAxis dir_axis = eScreenAxis(RNA_enum_get(op->ptr, "direction"));
2504 if (area_split_allowed(sd->sarea, dir_axis)) {
2507 }
2508 else {
2510 }
2511}
2512
2513/* UI callback, adds new handler */
2515{
2516 wmWindow *win = CTX_wm_window(C);
2517 bScreen *screen = CTX_wm_screen(C);
2518
2519 /* no full window splitting allowed */
2520 BLI_assert(screen->state == SCREENNORMAL);
2521
2522 PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction");
2523 PropertyRNA *prop_factor = RNA_struct_find_property(op->ptr, "factor");
2524 PropertyRNA *prop_cursor = RNA_struct_find_property(op->ptr, "cursor");
2525
2526 eScreenAxis dir_axis;
2527 if (event->type == EVT_ACTIONZONE_AREA) {
2528 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
2529
2530 if (sad == nullptr || sad->modifier > 0) {
2531 return OPERATOR_PASS_THROUGH;
2532 }
2533
2534 /* verify *sad itself */
2535 if (sad->sa1 == nullptr || sad->az == nullptr) {
2536 return OPERATOR_PASS_THROUGH;
2537 }
2538
2539 /* is this our *sad? if areas not equal it should be passed on */
2540 if (CTX_wm_area(C) != sad->sa1 || sad->sa1 != sad->sa2) {
2541 return OPERATOR_PASS_THROUGH;
2542 }
2543
2544 /* The factor will be close to 1.0f when near the top-left and the bottom-right corners. */
2545 const float factor_v = float(event->xy[1] - sad->sa1->v1->vec.y) / float(sad->sa1->winy);
2546 const float factor_h = float(event->xy[0] - sad->sa1->v1->vec.x) / float(sad->sa1->winx);
2547 const bool is_left = factor_v < 0.5f;
2548 const bool is_bottom = factor_h < 0.5f;
2549 const bool is_right = !is_left;
2550 const bool is_top = !is_bottom;
2551 float factor;
2552
2553 /* Prepare operator state vars. */
2555 dir_axis = SCREEN_AXIS_H;
2556 factor = factor_h;
2557 }
2558 else {
2559 dir_axis = SCREEN_AXIS_V;
2560 factor = factor_v;
2561 }
2562
2563 if ((is_top && is_left) || (is_bottom && is_right)) {
2564 factor = 1.0f - factor;
2565 }
2566
2567 RNA_property_float_set(op->ptr, prop_factor, factor);
2568
2569 RNA_property_enum_set(op->ptr, prop_dir, dir_axis);
2570
2571 /* general init, also non-UI case, adds customdata, sets area and defaults */
2572 if (!area_split_init(C, op)) {
2573 return OPERATOR_PASS_THROUGH;
2574 }
2575 }
2576 else if (RNA_property_is_set(op->ptr, prop_dir)) {
2577 ScrArea *area = CTX_wm_area(C);
2578 if (area == nullptr) {
2579 return OPERATOR_CANCELLED;
2580 }
2581 dir_axis = eScreenAxis(RNA_property_enum_get(op->ptr, prop_dir));
2582 if (dir_axis == SCREEN_AXIS_H) {
2584 op->ptr, prop_factor, float(event->xy[0] - area->v1->vec.x) / float(area->winx));
2585 }
2586 else {
2588 op->ptr, prop_factor, float(event->xy[1] - area->v1->vec.y) / float(area->winy));
2589 }
2590
2591 if (!area_split_init(C, op)) {
2592 return OPERATOR_CANCELLED;
2593 }
2594 }
2595 else {
2596 int event_co[2];
2597
2598 /* retrieve initial mouse coord, so we can find the active edge */
2599 if (RNA_property_is_set(op->ptr, prop_cursor)) {
2600 RNA_property_int_get_array(op->ptr, prop_cursor, event_co);
2601 }
2602 else {
2603 copy_v2_v2_int(event_co, event->xy);
2604 }
2605
2606 rcti window_rect;
2607 WM_window_rect_calc(win, &window_rect);
2608
2610 AREAMAP_FROM_SCREEN(screen), &window_rect, event_co[0], event_co[1]);
2611 if (actedge == nullptr) {
2612 return OPERATOR_CANCELLED;
2613 }
2614
2616
2617 RNA_property_enum_set(op->ptr, prop_dir, dir_axis);
2618
2619 /* special case, adds customdata, sets defaults */
2620 if (!area_split_menu_init(C, op)) {
2621 return OPERATOR_CANCELLED;
2622 }
2623 }
2624
2626
2627 if (event->type == EVT_ACTIONZONE_AREA) {
2628 /* do the split */
2629 if (area_split_apply(C, op)) {
2630 area_move_set_limits(win, screen, dir_axis, &sd->bigger, &sd->smaller, nullptr);
2631
2632 /* add temp handler for edge move or cancel */
2635
2637 }
2638 }
2639 else {
2640 sd->previewmode = 1;
2642 /* add temp handler for edge move or cancel */
2645
2647 }
2648
2649 return OPERATOR_PASS_THROUGH;
2650}
2651
2652/* function to be called outside UI context, or for redo */
2654{
2655 if (!area_split_init(C, op)) {
2656 return OPERATOR_CANCELLED;
2657 }
2658
2659 area_split_apply(C, op);
2660 area_split_exit(C, op);
2661
2662 return OPERATOR_FINISHED;
2663}
2664
2666{
2668
2669 if (sd->previewmode) {
2670 /* pass */
2671 }
2672 else {
2673 if (screen_area_join(C, op->reports, CTX_wm_screen(C), sd->sarea, sd->narea)) {
2674 if (CTX_wm_area(C) == sd->narea) {
2675 CTX_wm_area_set(C, nullptr);
2676 CTX_wm_region_set(C, nullptr);
2677 }
2678 sd->narea = nullptr;
2679 }
2680 }
2681 area_split_exit(C, op);
2682}
2683
2685{
2687 PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction");
2688 bool update_factor = false;
2689
2690 /* execute the events */
2691 switch (event->type) {
2692 case MOUSEMOVE:
2693 update_factor = true;
2694 break;
2695
2696 case LEFTMOUSE:
2697 if (sd->previewmode) {
2698 float inner[4] = {1.0f, 1.0f, 1.0f, 0.1f};
2699 float outline[4] = {1.0f, 1.0f, 1.0f, 0.3f};
2702 &sd->sarea->totrct,
2703 inner,
2704 outline,
2706 area_split_apply(C, op);
2707 area_split_exit(C, op);
2708 return OPERATOR_FINISHED;
2709 }
2710 else {
2711 if (event->val == KM_RELEASE) { /* mouse up */
2712 area_split_exit(C, op);
2713 return OPERATOR_FINISHED;
2714 }
2715 }
2716 break;
2717
2718 case MIDDLEMOUSE:
2719 case EVT_TABKEY:
2720 if (sd->previewmode == 0) {
2721 /* pass */
2722 }
2723 else {
2724 if (event->val == KM_PRESS) {
2725 if (sd->sarea) {
2726 const eScreenAxis dir_axis = eScreenAxis(RNA_property_enum_get(op->ptr, prop_dir));
2728 op->ptr, prop_dir, (dir_axis == SCREEN_AXIS_V) ? SCREEN_AXIS_H : SCREEN_AXIS_V);
2730 update_factor = true;
2731 }
2732 }
2733 }
2734
2735 break;
2736
2737 case RIGHTMOUSE: /* cancel operation */
2738 case EVT_ESCKEY:
2739 area_split_cancel(C, op);
2740 return OPERATOR_CANCELLED;
2741
2742 case EVT_LEFTCTRLKEY:
2743 case EVT_RIGHTCTRLKEY:
2744 sd->do_snap = event->val == KM_PRESS;
2745 update_factor = true;
2746 break;
2747 default: {
2748 break;
2749 }
2750 }
2751
2752 if (update_factor) {
2753 const eScreenAxis dir_axis = eScreenAxis(RNA_property_enum_get(op->ptr, prop_dir));
2754
2755 sd->delta = (dir_axis == SCREEN_AXIS_V) ? event->xy[0] - sd->origval :
2756 event->xy[1] - sd->origval;
2757
2758 if (sd->previewmode == 0) {
2759 if (sd->do_snap) {
2760 const int snap_loc = area_snap_calc_location(CTX_wm_screen(C),
2762 sd->delta,
2763 sd->origval,
2764 dir_axis,
2765 sd->bigger,
2766 sd->smaller);
2767 sd->delta = snap_loc - sd->origval;
2769 sd->delta,
2770 sd->origval,
2771 dir_axis,
2772 sd->bigger,
2773 sd->smaller,
2775 }
2776 else {
2778 C, sd->delta, sd->origval, dir_axis, sd->bigger, sd->smaller, SNAP_NONE);
2779 }
2780 }
2781 else {
2782 if (sd->sarea) {
2784 }
2785
2787
2788 /* area context not set */
2790
2791 if (sd->sarea) {
2792 ScrArea *area = sd->sarea;
2793 if (dir_axis == SCREEN_AXIS_V) {
2794 sd->origmin = area->v1->vec.x;
2795 sd->origsize = area->v4->vec.x - sd->origmin;
2796 }
2797 else {
2798 sd->origmin = area->v1->vec.y;
2799 sd->origsize = area->v2->vec.y - sd->origmin;
2800 }
2801
2802 if (sd->do_snap) {
2803 area->v1->editflag = area->v2->editflag = area->v3->editflag = area->v4->editflag = 1;
2804
2805 const int snap_loc = area_snap_calc_location(CTX_wm_screen(C),
2807 sd->delta,
2808 sd->origval,
2809 dir_axis,
2810 sd->origmin + sd->origsize,
2811 -sd->origmin);
2812
2813 area->v1->editflag = area->v2->editflag = area->v3->editflag = area->v4->editflag = 0;
2814 sd->delta = snap_loc - sd->origval;
2815 }
2816
2818 }
2819
2820 CTX_wm_screen(C)->do_draw = true;
2821 }
2822
2823 float fac = float(sd->delta + sd->origval - sd->origmin) / sd->origsize;
2824 RNA_float_set(op->ptr, "factor", fac);
2825 }
2826
2828}
2829
2831 {SCREEN_AXIS_H, "HORIZONTAL", 0, "Horizontal", ""},
2832 {SCREEN_AXIS_V, "VERTICAL", 0, "Vertical", ""},
2833 {0, nullptr, 0, nullptr, nullptr},
2834};
2835
2837{
2838 ot->name = "Split Area";
2839 ot->description = "Split selected area into new windows";
2840 ot->idname = "SCREEN_OT_area_split";
2841
2842 ot->exec = area_split_exec;
2843 ot->invoke = area_split_invoke;
2844 ot->modal = area_split_modal;
2845 ot->cancel = area_split_cancel;
2846
2847 ot->poll = screen_active_editable;
2848
2849 /* flags */
2851
2852 /* rna */
2853 RNA_def_enum(ot->srna, "direction", prop_direction_items, SCREEN_AXIS_H, "Direction", "");
2854 RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
2856 ot->srna, "cursor", 2, nullptr, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX);
2857}
2858
2860
2861/* -------------------------------------------------------------------- */
2864
2876
2877static bool is_split_edge(const int alignment, const AZEdge edge)
2878{
2879 return ((alignment == RGN_ALIGN_BOTTOM) && (edge == AE_TOP_TO_BOTTOMRIGHT)) ||
2880 ((alignment == RGN_ALIGN_TOP) && (edge == AE_BOTTOM_TO_TOPLEFT)) ||
2881 ((alignment == RGN_ALIGN_LEFT) && (edge == AE_RIGHT_TO_TOPLEFT)) ||
2882 ((alignment == RGN_ALIGN_RIGHT) && (edge == AE_LEFT_TO_TOPRIGHT));
2883}
2884
2885static void region_scale_draw_cb(const wmWindow * /*win*/, void *userdata)
2886{
2887 const wmOperator *op = static_cast<const wmOperator *>(userdata);
2888 RegionMoveData *rmd = static_cast<RegionMoveData *>(op->customdata);
2890}
2891
2893{
2894 RegionMoveData *rmd = static_cast<RegionMoveData *>(op->customdata);
2895 WM_draw_cb_exit(rmd->win, rmd->draw_callback);
2896
2897 MEM_freeN(rmd);
2898 op->customdata = nullptr;
2899
2901}
2902
2904{
2905 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
2906
2907 if (event->type != EVT_ACTIONZONE_REGION) {
2908 BKE_report(op->reports, RPT_ERROR, "Can only scale region size from an action zone");
2909 return OPERATOR_CANCELLED;
2910 }
2911
2912 AZone *az = sad->az;
2913
2914 if (az->region) {
2915 RegionMoveData *rmd = MEM_callocN<RegionMoveData>("RegionMoveData");
2916
2917 op->customdata = rmd;
2918
2919 rmd->az = az;
2920 /* special case for region within region - this allows the scale of
2921 * the parent region if the azone edge is not the edge splitting
2922 * both regions */
2923 if ((az->region->alignment & RGN_SPLIT_PREV) && az->region->prev &&
2925 {
2926 rmd->region = az->region->prev;
2927 }
2928 /* Flag to always forward scaling to the previous region. */
2929 else if (az->region->prev && (az->region->alignment & RGN_SPLIT_SCALE_PREV)) {
2930 rmd->region = az->region->prev;
2931 }
2932 else {
2933 rmd->region = az->region;
2934 }
2935 rmd->area = sad->sa1;
2936 rmd->edge = az->edge;
2937 copy_v2_v2_int(rmd->orig_xy, event->xy);
2938 rmd->maxsize = ED_area_max_regionsize(rmd->area, rmd->region, rmd->edge);
2939
2940 /* if not set we do now, otherwise it uses type */
2941 if (rmd->region->sizex == 0) {
2942 rmd->region->sizex = rmd->region->winx;
2943 }
2944 if (rmd->region->sizey == 0) {
2945 rmd->region->sizey = rmd->region->winy;
2946 }
2947
2948 /* Reset our saved widths if the region is hidden.
2949 * Otherwise you can't drag it out a second time. */
2950 if (rmd->region->flag & RGN_FLAG_HIDDEN) {
2952 rmd->region->winx = rmd->region->sizex = 0;
2953 }
2954 else {
2955 rmd->region->winy = rmd->region->sizey = 0;
2956 }
2957 }
2958
2959 /* Now copy to region-move-data. */
2961 rmd->origval = rmd->region->sizex;
2962 }
2963 else {
2964 rmd->origval = rmd->region->sizey;
2965 }
2966
2967 CLAMP(rmd->maxsize, 0, 1000);
2968
2969 rmd->win = CTX_wm_window(C);
2972
2973 /* add temp handler */
2976
2978 }
2979
2980 return OPERATOR_FINISHED;
2981}
2982
2984{
2985 if ((rmd->region->flag & RGN_FLAG_HIDDEN) == 0) {
2986 short *size, maxsize = -1;
2987
2989 size = &rmd->region->sizex;
2990 }
2991 else {
2992 size = &rmd->region->sizey;
2993 }
2994
2995 maxsize = rmd->maxsize - (UI_UNIT_Y / UI_SCALE_FAC);
2996
2997 if (*size > maxsize && maxsize > 0) {
2998 *size = maxsize;
2999 }
3000 }
3001}
3002
3004{
3005 /* hidden areas may have bad 'View2D.cur' value,
3006 * correct before displaying. see #45156 */
3007 if (rmd->region->flag & RGN_FLAG_HIDDEN) {
3009 }
3010
3011 region_toggle_hidden(C, rmd->region, false);
3013
3014 if ((rmd->region->flag & RGN_FLAG_HIDDEN) == 0) {
3015 if (rmd->region->regiontype == RGN_TYPE_HEADER) {
3016 ARegion *region_tool_header = BKE_area_find_region_type(rmd->area, RGN_TYPE_TOOL_HEADER);
3017 if (region_tool_header != nullptr) {
3018 if ((region_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER) == 0 &&
3019 (region_tool_header->flag & RGN_FLAG_HIDDEN) != 0)
3020 {
3021 region_toggle_hidden(C, region_tool_header, false);
3022 }
3023 }
3024 }
3025 }
3026}
3027
3029{
3030 RegionMoveData *rmd = static_cast<RegionMoveData *>(op->customdata);
3031 int delta;
3032
3033 /* execute the events */
3034 switch (event->type) {
3035 case MOUSEMOVE: {
3036 const float aspect = (rmd->region->v2d.flag & V2D_IS_INIT) ?
3037 (BLI_rctf_size_x(&rmd->region->v2d.cur) /
3038 (BLI_rcti_size_x(&rmd->region->v2d.mask) + 1)) :
3039 1.0f;
3040 const int snap_size_threshold = (U.widget_unit * 2) / aspect;
3041 bool size_changed = false;
3042
3044 delta = event->xy[0] - rmd->orig_xy[0];
3045 if (rmd->edge == AE_LEFT_TO_TOPRIGHT) {
3046 delta = -delta;
3047 }
3048
3049 /* region sizes now get multiplied */
3050 delta /= UI_SCALE_FAC;
3051
3052 const int size_no_snap = rmd->origval + delta;
3053 rmd->region->sizex = size_no_snap;
3054 /* Clamp before snapping, so the snapping doesn't use a size that's invalid anyway. It will
3055 * check for and respect the max-width too. */
3056 CLAMP(rmd->region->sizex, 0, rmd->maxsize);
3057
3058 if (rmd->region->runtime->type->snap_size) {
3059 short sizex_test = rmd->region->runtime->type->snap_size(
3060 rmd->region, rmd->region->sizex, 0);
3061 if ((abs(rmd->region->sizex - sizex_test) < snap_size_threshold) &&
3062 /* Don't snap to a new size if that would exceed the maximum width. */
3063 sizex_test <= rmd->maxsize)
3064 {
3065 rmd->region->sizex = sizex_test;
3066 }
3067 }
3068 BLI_assert(rmd->region->sizex <= rmd->maxsize);
3069
3070 if (size_no_snap < UI_UNIT_X / aspect) {
3071 rmd->region->sizex = rmd->origval;
3072 if (!(rmd->region->flag & RGN_FLAG_HIDDEN)) {
3074 }
3075 }
3076 else if (rmd->region->flag & RGN_FLAG_HIDDEN) {
3078 }
3079
3080 /* Hiding/unhiding is handled above, but still fix the size as requested. */
3081 if (rmd->region->flag & RGN_FLAG_NO_USER_RESIZE) {
3082 rmd->region->sizex = rmd->origval;
3083 }
3084
3085 if (rmd->region->sizex != rmd->origval) {
3086 size_changed = true;
3087 }
3088 }
3089 else {
3090 delta = event->xy[1] - rmd->orig_xy[1];
3091 if (rmd->edge == AE_BOTTOM_TO_TOPLEFT) {
3092 delta = -delta;
3093 }
3094
3095 /* region sizes now get multiplied */
3096 delta /= UI_SCALE_FAC;
3097
3098 const int size_no_snap = rmd->origval + delta;
3099 rmd->region->sizey = size_no_snap;
3100 /* Clamp before snapping, so the snapping doesn't use a size that's invalid anyway. It will
3101 * check for and respect the max-height too. */
3102 CLAMP(rmd->region->sizey, 0, rmd->maxsize);
3103
3104 if (rmd->region->runtime->type->snap_size) {
3105 short sizey_test = rmd->region->runtime->type->snap_size(
3106 rmd->region, rmd->region->sizey, 1);
3107 if ((abs(rmd->region->sizey - sizey_test) < snap_size_threshold) &&
3108 /* Don't snap to a new size if that would exceed the maximum height. */
3109 (sizey_test <= rmd->maxsize))
3110 {
3111 rmd->region->sizey = sizey_test;
3112 }
3113 }
3114 BLI_assert(rmd->region->sizey <= rmd->maxsize);
3115
3116 /* NOTE: `UI_UNIT_Y / 4` means you need to drag the footer and execute region
3117 * almost all the way down for it to become hidden, this is done
3118 * otherwise its too easy to do this by accident. */
3119 if (size_no_snap < (UI_UNIT_Y / 4) / aspect) {
3120 rmd->region->sizey = rmd->origval;
3121 if (!(rmd->region->flag & RGN_FLAG_HIDDEN)) {
3123 }
3124 }
3125 else if (rmd->region->flag & RGN_FLAG_HIDDEN) {
3127 }
3128
3129 /* Hiding/unhiding is handled above, but still fix the size as requested. */
3130 if (rmd->region->flag & RGN_FLAG_NO_USER_RESIZE) {
3131 rmd->region->sizey = rmd->origval;
3132 }
3133
3134 if (rmd->region->sizey != rmd->origval) {
3135 size_changed = true;
3136 }
3137 }
3138 if (size_changed && rmd->region->runtime->type->on_user_resize) {
3139 rmd->region->runtime->type->on_user_resize(rmd->region);
3140 }
3141 if (size_changed) {
3144 }
3145 else {
3147 }
3148 }
3151
3152 break;
3153 }
3154 case LEFTMOUSE:
3155 if (event->val == KM_RELEASE) {
3156 if (len_manhattan_v2v2_int(event->xy, rmd->orig_xy) <= WM_event_drag_threshold(event)) {
3157 if (rmd->region->flag & RGN_FLAG_HIDDEN) {
3159 }
3160 else if (rmd->region->flag & RGN_FLAG_TOO_SMALL) {
3162 }
3163
3166 }
3167
3169
3170 return OPERATOR_FINISHED;
3171 }
3172 break;
3173
3174 case EVT_ESCKEY:
3177 return OPERATOR_CANCELLED;
3178 default: {
3179 break;
3180 }
3181 }
3182
3184}
3185
3186static void region_scale_cancel(bContext * /*C*/, wmOperator *op)
3187{
3189}
3190
3192{
3193 /* identifiers */
3194 ot->name = "Scale Region Size";
3195 ot->description = "Scale selected area";
3196 ot->idname = "SCREEN_OT_region_scale";
3197
3198 ot->invoke = region_scale_invoke;
3199 ot->modal = region_scale_modal;
3200 ot->cancel = region_scale_cancel;
3201
3202 ot->poll = ED_operator_areaactive;
3203
3204 /* flags */
3206}
3207
3209
3210/* -------------------------------------------------------------------- */
3213
3215 eRegion_Type regiontype)
3216{
3217 return (regiontype == RGN_TYPE_WINDOW &&
3219 (spacetype == SPACE_CLIP && regiontype == RGN_TYPE_PREVIEW);
3220}
3221
3222void ED_areas_do_frame_follow(bContext *C, bool center_view)
3223{
3224 bScreen *screen_ctx = CTX_wm_screen(C);
3225 if (!(screen_ctx->redraws_flag & TIME_FOLLOW)) {
3226 return;
3227 }
3228
3229 const int current_frame = CTX_data_scene(C)->r.cfra;
3231 LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
3232 const bScreen *screen = WM_window_get_active_screen(window);
3233
3234 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
3235 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
3236 /* Only frame/center the current-frame indicator here if editor type supports it */
3238 eRegion_Type(region->regiontype)))
3239 {
3240 continue;
3241 }
3242
3243 if ((current_frame >= region->v2d.cur.xmin) && (current_frame <= region->v2d.cur.xmax)) {
3244 /* The current-frame indicator is already in view, do nothing. */
3245 continue;
3246 }
3247
3248 const float w = BLI_rctf_size_x(&region->v2d.cur);
3249
3250 if (center_view) {
3251 region->v2d.cur.xmax = current_frame + (w / 2);
3252 region->v2d.cur.xmin = current_frame - (w / 2);
3253 continue;
3254 }
3255 if (current_frame < region->v2d.cur.xmin) {
3256 region->v2d.cur.xmax = current_frame;
3257 region->v2d.cur.xmin = region->v2d.cur.xmax - w;
3258 }
3259 else {
3260 region->v2d.cur.xmin = current_frame;
3261 region->v2d.cur.xmax = region->v2d.cur.xmin + w;
3262 }
3263 }
3264 }
3265 }
3266}
3267
3268/* function to be called outside UI context, or for redo */
3270{
3271 const bool is_sequencer = CTX_wm_space_seq(C) != nullptr;
3272 Scene *scene = is_sequencer ? CTX_data_sequencer_scene(C) : CTX_data_scene(C);
3273 if (!scene) {
3274 return OPERATOR_CANCELLED;
3275 }
3276
3277 int delta = RNA_int_get(op->ptr, "delta");
3278
3279 /* In order to jump from e.g. 1.5 to 1 the delta needs to be incremented by 1 since the sub-frame
3280 * is always zeroed. Otherwise it would jump to 0. */
3281 if (delta < 0 && scene->r.subframe > 0) {
3282 delta += 1;
3283 }
3284 scene->r.cfra += delta;
3286 scene->r.subframe = 0.0f;
3287
3289
3291
3293
3295
3296 return OPERATOR_FINISHED;
3297}
3298
3300{
3301 ot->name = "Frame Offset";
3302 ot->idname = "SCREEN_OT_frame_offset";
3303 ot->description = "Move current frame forward/backward by a given number";
3304
3305 ot->exec = frame_offset_exec;
3306
3308 ot->flag = OPTYPE_UNDO_GROUPED;
3309 ot->undo_group = "Frame Change";
3310
3311 /* rna */
3312 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
3313}
3314
3316
3317/* -------------------------------------------------------------------- */
3320
3321/* function to be called outside UI context, or for redo */
3323{
3324 const bool is_sequencer = CTX_wm_space_seq(C) != nullptr;
3325 Scene *scene = is_sequencer ? CTX_data_sequencer_scene(C) : CTX_data_scene(C);
3326 if (!scene) {
3327 return OPERATOR_CANCELLED;
3328 }
3329 wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
3330
3331 /* Don't change scene->r.cfra directly if animtimer is running as this can cause
3332 * first/last frame not to be actually shown (bad since for example physics
3333 * simulations aren't reset properly).
3334 */
3335 if (animtimer) {
3336 ScreenAnimData *sad = static_cast<ScreenAnimData *>(animtimer->customdata);
3337
3339
3340 if (RNA_boolean_get(op->ptr, "end")) {
3341 sad->nextfra = PEFRA;
3342 }
3343 else {
3344 sad->nextfra = PSFRA;
3345 }
3346 }
3347 else {
3348 if (RNA_boolean_get(op->ptr, "end")) {
3349 scene->r.cfra = PEFRA;
3350 }
3351 else {
3352 scene->r.cfra = PSFRA;
3353 }
3354
3356
3358
3360
3362 }
3363
3364 return OPERATOR_FINISHED;
3365}
3366
3368{
3369 ot->name = "Jump to Endpoint";
3370 ot->description = "Jump to first/last frame in frame range";
3371 ot->idname = "SCREEN_OT_frame_jump";
3372
3373 ot->exec = frame_jump_exec;
3374
3376 ot->flag = OPTYPE_UNDO_GROUPED;
3377 ot->undo_group = "Frame Change";
3378
3379 /* rna */
3381 ot->srna, "end", false, "Last Frame", "Jump to the last frame of the frame range");
3382}
3383
3385
3386/* -------------------------------------------------------------------- */
3389
3390/* function to be called outside UI context, or for redo */
3392{
3394 const bool backward = RNA_boolean_get(op->ptr, "backward");
3395
3396 if (scene == nullptr) {
3397 return OPERATOR_CANCELLED;
3398 }
3399
3400 float delta = scene->r.time_jump_delta;
3401
3402 if (scene->r.time_jump_unit == SCE_TIME_JUMP_SECOND) {
3403 delta *= scene->r.frs_sec / scene->r.frs_sec_base;
3404 }
3405
3406 int step = (int)delta;
3407 float fraction = delta - step;
3408 if (backward) {
3409 scene->r.cfra -= step;
3410 scene->r.subframe -= fraction;
3411 }
3412 else {
3413 scene->r.cfra += step;
3414 scene->r.subframe += fraction;
3415 }
3416
3417 /* Check if subframe has a non-fractional component, and roll that into cfra. */
3418 if (scene->r.subframe < 0.0f || scene->r.subframe >= 1.0f) {
3419 const float subframe_offset = floorf(scene->r.subframe);
3420 const int frame_offset = (int)subframe_offset;
3421 scene->r.cfra += frame_offset;
3422 scene->r.subframe -= subframe_offset;
3423 }
3424
3427
3429
3431
3432 return OPERATOR_FINISHED;
3433}
3434
3436{
3437 ot->name = "Jump Time by Delta";
3438 ot->description = "Jump forward/backward by a given number of frames or seconds";
3439 ot->idname = "SCREEN_OT_time_jump";
3440
3441 ot->exec = frame_jump_delta_exec;
3442
3444 ot->flag = OPTYPE_UNDO_GROUPED;
3445 ot->undo_group = "Frame Change";
3446
3447 /* rna */
3448 RNA_def_boolean(ot->srna, "backward", false, "Backwards", "Jump backwards in time");
3449}
3450
3452
3453/* -------------------------------------------------------------------- */
3456
3458{
3459 bAnimContext ac;
3460
3461 if (ANIM_animdata_get_context(&C, &ac) == 0) {
3462 return;
3463 }
3465 summary_to_keylist(&ac, &keylist, 0, {-FLT_MAX, FLT_MAX});
3466}
3467
3469{
3470 bAnimContext ac;
3471
3472 if (ANIM_animdata_get_context(&C, &ac) == 0) {
3473 return;
3474 }
3475
3477
3478 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
3479 FCurve *fcu = static_cast<FCurve *>(ale->key_data);
3480 if (!fcu->bezt) {
3481 continue;
3482 }
3483
3484 const bool use_nla_mapping = ANIM_nla_mapping_allowed(ale);
3485 fcurve_to_keylist(ale->adt, fcu, &keylist, 0, {-FLT_MAX, FLT_MAX}, use_nla_mapping);
3486 }
3487
3488 ANIM_animdata_freelist(&anim_data);
3489}
3490
3491/* This is used for all editors where a more specific function isn't implemented. */
3493{
3494 bDopeSheet ads = {nullptr};
3495
3496 /* Speed up dummy dope-sheet context with flags to perform necessary filtering. */
3497 if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
3498 /* Only selected channels are included. */
3500 }
3501
3502 /* populate tree with keyframe nodes */
3503 scene_to_keylist(&ads, scene, &keylist, 0, {-FLT_MAX, FLT_MAX});
3504
3505 /* Return early when invoked from sequencer with sequencer scene. Objects may belong to different
3506 * scenes and are irrelevant. */
3507 if (CTX_wm_space_seq(&C) != nullptr && scene == CTX_data_sequencer_scene(&C)) {
3508 return;
3509 }
3510
3512 if (ob) {
3513 ob_to_keylist(&ads, ob, &keylist, 0, {-FLT_MAX, FLT_MAX});
3514
3515 if (ob->type == OB_GREASE_PENCIL) {
3516 const bool active_layer_only = !(scene->flag & SCE_KEYS_NO_SELONLY);
3518 nullptr, static_cast<const GreasePencil *>(ob->data), &keylist, 0, active_layer_only);
3519 }
3520 }
3521
3522 {
3524 if (mask) {
3526 mask_to_keylist(&ads, masklay, &keylist);
3527 }
3528 }
3529}
3530
3531/* function to be called outside UI context, or for redo */
3533{
3535 const bool next = RNA_boolean_get(op->ptr, "next");
3536 bool done = false;
3537
3538 /* sanity checks */
3539 if (scene == nullptr) {
3540 return OPERATOR_CANCELLED;
3541 }
3542
3543 AnimKeylist *keylist = ED_keylist_create();
3544
3545 ScrArea *area = CTX_wm_area(C);
3546 switch (area ? eSpace_Type(area->spacetype) : SPACE_EMPTY) {
3547 case SPACE_ACTION: {
3548 keylist_from_dopesheet(*C, *keylist);
3549 break;
3550 }
3551
3552 case SPACE_GRAPH:
3553 keylist_from_graph_editor(*C, *keylist);
3554 break;
3555
3556 default:
3557 keylist_fallback_for_keyframe_jump(*C, scene, *keylist);
3558 break;
3559 }
3560
3561 /* Initialize binary-tree-list for getting keyframes. */
3563
3564 const float cfra = BKE_scene_frame_get(scene);
3565 /* find matching keyframe in the right direction */
3566 const ActKeyColumn *ak;
3567
3568 if (next) {
3569 ak = ED_keylist_find_next(keylist, cfra);
3570 while ((ak != nullptr) && (done == false)) {
3571 if (cfra < ak->cfra) {
3572 BKE_scene_frame_set(scene, ak->cfra);
3573 done = true;
3574 }
3575 else {
3576 ak = ak->next;
3577 }
3578 }
3579 }
3580
3581 else {
3582 ak = ED_keylist_find_prev(keylist, cfra);
3583 while ((ak != nullptr) && (done == false)) {
3584 if (cfra > ak->cfra) {
3585 BKE_scene_frame_set(scene, ak->cfra);
3586 done = true;
3587 }
3588 else {
3589 ak = ak->prev;
3590 }
3591 }
3592 }
3593
3594 /* free temp stuff */
3595 ED_keylist_free(keylist);
3596
3597 /* any success? */
3598 if (done == false) {
3599 BKE_report(op->reports, RPT_INFO, "No more keyframes to jump to in this direction");
3600
3601 return OPERATOR_CANCELLED;
3602 }
3603
3606
3608
3610
3611 return OPERATOR_FINISHED;
3612}
3613
3615{
3617}
3618
3620{
3621 ot->name = "Jump to Keyframe";
3622 ot->description = "Jump to previous/next keyframe";
3623 ot->idname = "SCREEN_OT_keyframe_jump";
3624
3625 ot->exec = keyframe_jump_exec;
3626
3627 ot->poll = keyframe_jump_poll;
3628 ot->flag = OPTYPE_UNDO_GROUPED;
3629 ot->undo_group = "Frame Change";
3630
3631 /* properties */
3632 RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
3633}
3634
3636
3637/* -------------------------------------------------------------------- */
3640
3641/* function to be called outside UI context, or for redo */
3643{
3644 const bool is_sequencer = CTX_wm_space_seq(C) != nullptr;
3645 Scene *scene = is_sequencer ? CTX_data_sequencer_scene(C) : CTX_data_scene(C);
3646 if (!scene) {
3647 return OPERATOR_CANCELLED;
3648 }
3649 int closest = scene->r.cfra;
3650 const bool next = RNA_boolean_get(op->ptr, "next");
3651 bool found = false;
3652
3653 /* find matching marker in the right direction */
3654 LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
3655 if (next) {
3656 if ((marker->frame > scene->r.cfra) && (!found || closest > marker->frame)) {
3657 closest = marker->frame;
3658 found = true;
3659 }
3660 }
3661 else {
3662 if ((marker->frame < scene->r.cfra) && (!found || closest < marker->frame)) {
3663 closest = marker->frame;
3664 found = true;
3665 }
3666 }
3667 }
3668
3669 /* any success? */
3670 if (!found) {
3671 BKE_report(op->reports, RPT_INFO, "No more markers to jump to in this direction");
3672
3673 return OPERATOR_CANCELLED;
3674 }
3675
3676 scene->r.cfra = closest;
3677
3679
3681
3683
3685
3686 return OPERATOR_FINISHED;
3687}
3688
3690{
3691 ot->name = "Jump to Marker";
3692 ot->description = "Jump to previous/next marker";
3693 ot->idname = "SCREEN_OT_marker_jump";
3694
3695 ot->exec = marker_jump_exec;
3696
3698 ot->flag = OPTYPE_UNDO_GROUPED;
3699 ot->undo_group = "Frame Change";
3700
3701 /* properties */
3702 RNA_def_boolean(ot->srna, "next", true, "Next Marker", "");
3703}
3704
3706
3707/* -------------------------------------------------------------------- */
3710
3711/* function to be called outside UI context, or for redo */
3713{
3714 WorkSpace *workspace = CTX_wm_workspace(C);
3715 int delta = RNA_int_get(op->ptr, "delta");
3716
3717 if (ED_workspace_layout_cycle(workspace, delta, C)) {
3718 return OPERATOR_FINISHED;
3719 }
3720
3721 return OPERATOR_CANCELLED;
3722}
3723
3725{
3726 ot->name = "Set Screen";
3727 ot->description = "Cycle through available screens";
3728 ot->idname = "SCREEN_OT_screen_set";
3729
3730 ot->exec = screen_set_exec;
3732
3733 /* rna */
3734 RNA_def_int(ot->srna, "delta", 1, -1, 1, "Delta", "", -1, 1);
3735}
3736
3738
3739/* -------------------------------------------------------------------- */
3742
3743/* function to be called outside UI context, or for redo */
3745{
3746 bScreen *screen = CTX_wm_screen(C);
3747 ScrArea *area = nullptr;
3748 const bool hide_panels = RNA_boolean_get(op->ptr, "use_hide_panels");
3749
3750 BLI_assert(!screen->temp);
3751
3752 /* search current screen for 'full-screen' areas */
3753 /* prevents restoring info header, when mouse is over it */
3754 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
3755 if (area_iter->full) {
3756 area = area_iter;
3757 break;
3758 }
3759 }
3760
3761 if (area == nullptr) {
3762 area = CTX_wm_area(C);
3763 }
3764
3765 if (hide_panels) {
3766 if (!ELEM(screen->state, SCREENNORMAL, SCREENFULL)) {
3767 return OPERATOR_CANCELLED;
3768 }
3770 }
3771 else {
3772 if (!ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
3773 return OPERATOR_CANCELLED;
3774 }
3775 if (BLI_listbase_is_single(&screen->areabase) && screen->state == SCREENNORMAL) {
3776 /* SCREENMAXIMIZED is not useful when a singleton. #144740. */
3777 return OPERATOR_CANCELLED;
3778 }
3780 }
3781
3782 return OPERATOR_FINISHED;
3783}
3784
3786{
3787 const wmWindow *win = CTX_wm_window(C);
3788 const bScreen *screen = CTX_wm_screen(C);
3789 const ScrArea *area = CTX_wm_area(C);
3790 const wmWindowManager *wm = CTX_wm_manager(C);
3791 return ED_operator_areaactive(C) &&
3792 /* Don't allow maximizing global areas but allow minimizing from them. */
3793 ((screen->state != SCREENNORMAL) || !ED_area_is_global(area)) &&
3794 /* Don't change temporary screens. */
3796 /* Don't maximize when dragging. */
3797 BLI_listbase_is_empty(&wm->runtime->drags);
3798}
3799
3801{
3802 PropertyRNA *prop;
3803
3804 ot->name = "Toggle Maximize Area";
3805 ot->description = "Toggle display selected area as fullscreen/maximized";
3806 ot->idname = "SCREEN_OT_screen_full_area";
3807
3810 ot->flag = 0;
3811
3812 prop = RNA_def_boolean(
3813 ot->srna, "use_hide_panels", false, "Hide Panels", "Hide all the panels (Focus Mode)");
3815}
3816
3818
3819/* -------------------------------------------------------------------- */
3822
3823/* operator state vars used:
3824 * x1, y1 mouse coord in first area, which will disappear
3825 * x2, y2 mouse coord in 2nd area, which will become joined
3826 *
3827 * functions:
3828 *
3829 * init() find edge based on state vars
3830 * test if the edge divides two areas,
3831 * store active and nonactive area,
3832 *
3833 * apply() do the actual join
3834 *
3835 * exit() cleanup, send notifier
3836 *
3837 * callbacks:
3838 *
3839 * exec() calls init, apply, exit
3840 *
3841 * invoke() sets mouse coords in x,y
3842 * call init()
3843 * add modal handler
3844 *
3845 * modal() accept modal events while doing it
3846 * call apply() with active window and nonactive window
3847 * call exit() and remove handler when LMB confirm
3848 */
3849
3851 ScrArea *sa1; /* Potential source area (kept). */
3852 ScrArea *sa2; /* Potential target area (removed or reduced). */
3853 eScreenDir dir; /* Direction of potential join. */
3854 eScreenAxis split_dir; /* Direction of split within the source area. */
3855 AreaDockTarget dock_target; /* Position within target we are pointing to. */
3856 float factor; /* dock target size can vary. */
3857 int start_x, start_y; /* Starting mouse position. */
3858 int current_x, current_y; /* Current mouse position. */
3859 float split_fac; /* Split factor in split_dir direction. */
3860 wmWindow *win1; /* Window of source area. */
3861 wmWindow *win2; /* Window of the target area. */
3862 bScreen *screen; /* Screen of the source area. */
3863 double start_time; /* Start time of animation. */
3864 double end_time; /* End time of animation. */
3865 wmWindow *draw_dock_win; /* Window getting docking highlight. */
3866 bool close_win; /* Close the source window when done. */
3867 void *draw_callback; /* call #screen_draw_join_highlight */
3868 void *draw_dock_callback; /* call #screen_draw_dock_highlight, overlay on draw_dock_win. */
3869};
3870
3871static void area_join_draw_cb(const wmWindow *win, void *userdata)
3872{
3873 const wmOperator *op = static_cast<const wmOperator *>(userdata);
3874 sAreaJoinData *sd = static_cast<sAreaJoinData *>(op->customdata);
3875 if (!sd || !sd->sa1) {
3876 return;
3877 }
3878
3879 float factor = 1.0f;
3880 const double now = BLI_time_now_seconds();
3881 if (now < sd->end_time) {
3882 factor = pow((now - sd->start_time) / (sd->end_time - sd->start_time), 2);
3883 sd->screen->do_refresh = true;
3884 }
3885
3886 if (sd->sa1 == sd->sa2 && sd->split_fac > 0.0f) {
3888 }
3889 else if (sd->sa2 && sd->dir != SCREEN_DIR_NONE) {
3890 screen_draw_join_highlight(win, sd->sa1, sd->sa2, sd->dir, factor);
3891 }
3892}
3893
3894static void area_join_dock_cb(const wmWindow *win, void *userdata)
3895{
3896 const wmOperator *op = static_cast<wmOperator *>(userdata);
3897 sAreaJoinData *jd = static_cast<sAreaJoinData *>(op->customdata);
3898 if (!jd || !jd->sa2 || jd->dir != SCREEN_DIR_NONE || jd->sa1 == jd->sa2) {
3899 return;
3900 }
3901
3902 float factor = 1.0f;
3903 const double now = BLI_time_now_seconds();
3904 if (now < jd->end_time) {
3905 factor = pow((now - jd->start_time) / (jd->end_time - jd->start_time), 2);
3906 jd->screen->do_refresh = true;
3907 }
3908
3910 win, jd->sa1, jd->sa2, jd->dock_target, jd->factor, jd->current_x, jd->current_y, factor);
3911}
3912
3914{
3915 if (jd->sa2 && jd->win2 && jd->win2 != jd->draw_dock_win) {
3916 /* Change of highlight window. */
3917 if (jd->draw_dock_callback) {
3919 /* Refresh the entire window. */
3922 {
3923 ED_area_tag_redraw(area);
3924 }
3925 }
3926 if (jd->win2) {
3927 jd->draw_dock_win = jd->win2;
3929 }
3930 }
3931}
3932
3933/* validate selection inside screen, set variables OK */
3934/* return false: init failed */
3935static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *sa2)
3936{
3937 if (sa1 == nullptr && sa2 == nullptr) {
3938 /* Get areas from cursor location if not specified. */
3939 PropertyRNA *prop;
3940 int cursor[2];
3941
3942 prop = RNA_struct_find_property(op->ptr, "source_xy");
3943 if (RNA_property_is_set(op->ptr, prop)) {
3944 RNA_property_int_get_array(op->ptr, prop, cursor);
3946 }
3947
3948 prop = RNA_struct_find_property(op->ptr, "target_xy");
3949 if (RNA_property_is_set(op->ptr, prop)) {
3950 RNA_property_int_get_array(op->ptr, prop, cursor);
3952 }
3953 }
3954 if (sa1 == nullptr) {
3955 return false;
3956 }
3957
3958 sAreaJoinData *jd = MEM_callocN<sAreaJoinData>("op_area_join");
3959 jd->sa1 = sa1;
3960 jd->sa2 = sa2;
3961 jd->dir = area_getorientation(sa1, sa2);
3964 jd->screen = CTX_wm_screen(C);
3967
3968 op->customdata = jd;
3969 return true;
3970}
3971
3972/* apply the join of the areas (space types) */
3974{
3976 if (!jd || (jd->dir == SCREEN_DIR_NONE)) {
3977 return false;
3978 }
3979
3980 bScreen *screen = CTX_wm_screen(C);
3981
3982 /* Rect of the combined areas. */
3983 const bool vertical = SCREEN_DIR_IS_VERTICAL(jd->dir);
3984 rcti combined{};
3985 combined.xmin = vertical ? std::max(jd->sa1->totrct.xmin, jd->sa2->totrct.xmin) :
3986 std::min(jd->sa1->totrct.xmin, jd->sa2->totrct.xmin);
3987 combined.xmax = vertical ? std::min(jd->sa1->totrct.xmax, jd->sa2->totrct.xmax) :
3988 std::max(jd->sa1->totrct.xmax, jd->sa2->totrct.xmax);
3989 combined.ymin = vertical ? std::min(jd->sa1->totrct.ymin, jd->sa2->totrct.ymin) :
3990 std::max(jd->sa1->totrct.ymin, jd->sa2->totrct.ymin);
3991 combined.ymax = vertical ? std::max(jd->sa1->totrct.ymax, jd->sa2->totrct.ymax) :
3992 std::min(jd->sa1->totrct.ymax, jd->sa2->totrct.ymax);
3993 float inner[4] = {1.0f, 1.0f, 1.0f, 0.1f};
3994 float outline[4] = {1.0f, 1.0f, 1.0f, 0.3f};
3996 CTX_wm_window(C), screen, &combined, inner, outline, AREA_JOIN_FADEOUT);
3997
3998 if (!screen_area_join(C, op->reports, screen, jd->sa1, jd->sa2)) {
3999 return false;
4000 }
4001 if (CTX_wm_area(C) == jd->sa2) {
4002 CTX_wm_area_set(C, nullptr);
4003 CTX_wm_region_set(C, nullptr);
4004 }
4005
4006 if (BLI_listbase_is_single(&screen->areabase)) {
4007 /* Areas reduced to just one, so show nicer title. */
4009 }
4010
4011 return true;
4012}
4013
4014/* finish operation */
4016{
4018
4019 if (jd) {
4020 if (jd->draw_callback) {
4022 }
4023 if (jd->draw_dock_callback) {
4025 }
4026
4027 MEM_freeN(jd);
4028 op->customdata = nullptr;
4029 }
4030
4031 /* this makes sure aligned edges will result in aligned grabbing */
4035
4036 ED_workspace_status_text(C, nullptr);
4037
4039}
4040
4042{
4043 if (!area_join_init(C, op, nullptr, nullptr)) {
4044 return OPERATOR_CANCELLED;
4045 }
4046
4048
4049 if (jd->sa2 == nullptr || area_getorientation(jd->sa1, jd->sa2) == SCREEN_DIR_NONE) {
4050 return OPERATOR_CANCELLED;
4051 }
4052
4054
4055 area_join_apply(C, op);
4056 area_join_exit(C, op);
4058
4059 return OPERATOR_FINISHED;
4060}
4061
4062static void area_join_update_data(bContext *C, sAreaJoinData *jd, const wmEvent *event);
4063static int area_join_cursor(sAreaJoinData *jd, const wmEvent *event);
4064
4065/* interaction callback */
4067{
4068 if (event->type == EVT_ACTIONZONE_AREA) {
4069 sActionzoneData *sad = static_cast<sActionzoneData *>(event->customdata);
4070
4071 if (sad == nullptr || sad->modifier > 0 || sad->sa1 == nullptr) {
4072 return OPERATOR_PASS_THROUGH;
4073 }
4074
4075 if (!area_join_init(C, op, sad->sa1, sad->sa2)) {
4076 return OPERATOR_CANCELLED;
4077 }
4078
4080 jd->start_x = sad->x;
4081 jd->start_y = sad->y;
4083
4086 }
4087
4088 /* Launched from menu item or keyboard shortcut. */
4089 if (!area_join_init(C, op, nullptr, nullptr)) {
4090 ScrArea *sa1 = CTX_wm_area(C);
4091 if (!sa1 || ED_area_is_global(sa1) || !area_join_init(C, op, sa1, nullptr)) {
4092 return OPERATOR_CANCELLED;
4093 }
4094 }
4096 jd->sa2 = jd->sa1;
4097 jd->start_x = jd->sa1->totrct.xmin;
4098 jd->start_y = jd->sa1->totrct.ymax;
4099 jd->current_x = event->xy[0];
4100 jd->current_y = event->xy[1];
4102 WM_cursor_set(jd->win1, area_join_cursor(jd, event));
4103 area_join_update_data(C, jd, event);
4108}
4109
4110/* Apply the docking of the area. */
4112{
4114
4115 int offset1;
4116 int offset2;
4117 area_getoffsets(jd->sa1, jd->sa2, area_getorientation(jd->sa1, jd->sa2), &offset1, &offset2);
4118
4119 /* Check before making changes. */
4120 bool aligned_neighbors = (offset1 == 0 && offset2 == 0);
4121 bool same_area = (jd->sa1 == jd->sa2);
4122
4123 if (!(jd->dock_target == AreaDockTarget::Center)) {
4127
4128 float fac = jd->factor;
4130 fac = 1.0f - fac;
4131 }
4132
4133 ScrArea *newa = area_split(
4134 jd->win2, WM_window_get_active_screen(jd->win2), jd->sa2, dir, fac, true);
4135
4136 if (jd->factor <= 0.5f) {
4137 jd->sa2 = newa;
4138 }
4139 else {
4140 /* Force full rebuild. #130732 */
4141 ED_area_tag_redraw(newa);
4142 }
4143 }
4144
4145 if (same_area) {
4147 return;
4148 }
4149
4150 float inner[4] = {1.0f, 1.0f, 1.0f, 0.15f};
4151 float outline[4] = {1.0f, 1.0f, 1.0f, 0.4f};
4155 jd->win2, CTX_wm_screen(C), &jd->sa2->totrct, inner, outline, AREA_DOCK_FADEOUT);
4156
4157 if (!aligned_neighbors || !screen_area_join(C, op->reports, CTX_wm_screen(C), jd->sa1, jd->sa2))
4158 {
4159 ED_area_swapspace(C, jd->sa2, jd->sa1);
4162 {
4163 jd->close_win = true;
4164 /* Clear the active region in each screen, otherwise they are pointing
4165 * at incorrect regions and will cause errors in uiTemplateInputStatus. */
4168 }
4169 else {
4170 float inner[4] = {0.0f, 0.0f, 0.0f, 0.7f};
4172 jd->win1, CTX_wm_screen(C), &jd->sa1->totrct, inner, nullptr, AREA_CLOSE_FADEOUT);
4174 }
4175 }
4176
4177 if (jd && jd->sa2 == CTX_wm_area(C)) {
4178 CTX_wm_area_set(C, nullptr);
4179 CTX_wm_region_set(C, nullptr);
4180 }
4181}
4182
4183static int area_join_cursor(sAreaJoinData *jd, const wmEvent *event)
4184{
4185 if (!jd->sa2 && jd->dock_target == AreaDockTarget::None) {
4186 /* Mouse outside window, so can open new window. */
4187 if (event->xy[0] < 0 || event->xy[0] > jd->win1->sizex || event->xy[1] < 1 ||
4188 event->xy[1] > jd->win1->sizey)
4189 {
4190 return WM_CURSOR_PICK_AREA;
4191 }
4192 return WM_CURSOR_STOP;
4193 }
4194
4195 if (jd->win2 && jd->win2->workspace_hook) {
4197 if (screen && screen->temp) {
4198 return WM_CURSOR_STOP;
4199 }
4200 }
4201
4202 if (jd->sa1 && jd->sa1 == jd->sa2) {
4203 if (jd->split_fac >= 0.0001f) {
4204 /* Mouse inside source area, so allow splitting. */
4206 }
4207 return WM_CURSOR_EDIT;
4208 }
4209
4210 if (jd->dir != SCREEN_DIR_NONE) {
4211 /* Joining */
4212 switch (jd->dir) {
4213 case SCREEN_DIR_N:
4214 return WM_CURSOR_N_ARROW;
4215 break;
4216 case SCREEN_DIR_S:
4217 return WM_CURSOR_S_ARROW;
4218 break;
4219 case SCREEN_DIR_W:
4220 return WM_CURSOR_W_ARROW;
4221 break;
4222 default:
4223 return WM_CURSOR_E_ARROW;
4224 }
4225 }
4226
4227 if (jd->dir != SCREEN_DIR_NONE || jd->dock_target != AreaDockTarget::None) {
4228#if defined(__APPLE__)
4229 return WM_CURSOR_HAND_CLOSED;
4230#else
4231 return WM_CURSOR_MOVE;
4232#endif
4233 }
4234
4235 return WM_CURSOR_PICK_AREA;
4236}
4237
4238static float area_docking_snap(const float pos, const wmEvent *event)
4239{
4240 const bool alt = event->modifier & KM_ALT;
4241 const bool ctrl = event->modifier & KM_CTRL;
4242 const float accel = (alt || ctrl) ? 2.5f : 2.0;
4243
4244 float factor = pos * accel;
4245
4246 if (!alt) {
4247 if (factor >= 0.4375f && factor < 0.5f) {
4248 factor = 0.499999f;
4249 }
4250 else if (factor >= 0.5f && factor < 0.5625f) {
4251 factor = 0.500001f;
4252 }
4253 }
4254
4255 if (ctrl) {
4256 if (factor < 0.1875f) {
4257 factor = 0.125f;
4258 }
4259 else if (factor >= 0.1875f && factor < 0.3125f) {
4260 factor = 0.25f;
4261 }
4262 else if (factor >= 0.3125f && factor < 0.4375f) {
4263 factor = 0.375f;
4264 }
4265 else if (factor >= 0.5625f && factor < 0.6875f) {
4266 factor = 0.625f;
4267 }
4268 else if (factor >= 0.6875f && factor < 0.8125f) {
4269 factor = 0.75f;
4270 }
4271 else if (factor > 0.8125f) {
4272 factor = 0.875f;
4273 }
4274 }
4275
4276 return factor;
4277}
4278
4280{
4281 if (!jd->sa2 || !jd->win2) {
4282 return AreaDockTarget::None;
4283 }
4284
4285 if (jd->sa1 == jd->sa2) {
4286 return AreaDockTarget::None;
4287 }
4288
4289 if (jd->win2 && jd->win2->workspace_hook) {
4291 if (screen && screen->temp) {
4292 return AreaDockTarget::None;
4293 }
4294 }
4295
4296 /* Convert to local coordinates in sa2. */
4297 int win1_posx = jd->win1->posx;
4298 int win1_posy = jd->win1->posy;
4299 int win2_posx = jd->win2->posx;
4300 int win2_posy = jd->win2->posy;
4301 WM_window_native_pixel_coords(jd->win1, &win1_posx, &win1_posy);
4302 WM_window_native_pixel_coords(jd->win2, &win2_posx, &win2_posy);
4303
4304 const int x = event->xy[0] + win1_posx - win2_posx - jd->sa2->totrct.xmin;
4305 const int y = event->xy[1] + win1_posy - win2_posy - jd->sa2->totrct.ymin;
4306
4307 jd->current_x = x + jd->sa2->totrct.xmin;
4308 jd->current_y = y + jd->sa2->totrct.ymin;
4309
4310 const float fac_x = float(x) / float(jd->sa2->winx);
4311 const float fac_y = float(y) / float(jd->sa2->winy);
4312 const int min_x = 2 * AREAMINX * UI_SCALE_FAC;
4313 const int min_y = 2 * HEADERY * UI_SCALE_FAC;
4314
4315 if (ELEM(jd->dir, SCREEN_DIR_N, SCREEN_DIR_S)) {
4316 /* Up or Down to immediate neighbor. */
4317 if (event->xy[0] <= jd->sa1->totrct.xmax && event->xy[0] >= jd->sa1->totrct.xmin) {
4318 const int join_y = std::min(jd->sa2->winy * 0.25f, 5 * HEADERY * UI_SCALE_FAC);
4319 if (jd->sa2->winy < min_y || (jd->dir == SCREEN_DIR_N && y < join_y) ||
4320 (jd->dir == SCREEN_DIR_S && (jd->sa2->winy - y) < join_y))
4321 {
4322 return AreaDockTarget::None;
4323 }
4324 }
4325 }
4326
4327 if (ELEM(jd->dir, SCREEN_DIR_W, SCREEN_DIR_E)) {
4328 /* Left or Right to immediate neighbor. */
4329 if (event->xy[1] <= jd->sa1->totrct.ymax && event->xy[1] >= jd->sa1->totrct.ymin) {
4330 const int join_x = std::min(jd->sa2->winx * 0.25f, 5 * AREAMINX * UI_SCALE_FAC);
4331 if (jd->sa2->winx < min_x || (jd->dir == SCREEN_DIR_W && (jd->sa2->winx - x) < join_x) ||
4332 (jd->dir == SCREEN_DIR_E && x < join_x))
4333 {
4334 return AreaDockTarget::None;
4335 }
4336 }
4337 }
4338
4339 /* If we've made it here, then there can be no joining possible. */
4340 jd->dir = SCREEN_DIR_NONE;
4341 jd->factor = 0.5f;
4342
4343 const float min_fac_x = 1.5f * AREAMINX * UI_SCALE_FAC / float(jd->sa2->winx);
4344 const float min_fac_y = 1.5f * HEADERY * UI_SCALE_FAC / float(jd->sa2->winy);
4345
4346 /* if the area is narrow then there are only two docking targets. */
4347 if (jd->sa2->winx < (min_x * 3)) {
4348 if (fac_y > 0.4f && fac_y < 0.6f) {
4350 }
4351 if (float(y) > float(jd->sa2->winy) / 2.0f) {
4352 jd->factor = area_docking_snap(std::max(1.0f - fac_y, min_fac_y), event);
4353 return AreaDockTarget::Top;
4354 }
4355 jd->factor = area_docking_snap(std::max(fac_y, min_fac_y), event);
4357 }
4358 if (jd->sa2->winy < (min_y * 3)) {
4359 if (fac_x > 0.4f && fac_x < 0.6f) {
4361 }
4362 if (float(x) > float(jd->sa2->winx) / 2.0f) {
4363 jd->factor = area_docking_snap(std::max(1.0f - fac_x, min_fac_x), event);
4364 return AreaDockTarget::Right;
4365 }
4366 jd->factor = area_docking_snap(std::max(fac_x, min_fac_x), event);
4367 return AreaDockTarget::Left;
4368 }
4369
4370 /* Are we in the center? But not in same area! */
4371 if (fac_x > 0.4f && fac_x < 0.6f && fac_y > 0.4f && fac_y < 0.6f) {
4373 }
4374
4375 /* Area is large enough for four docking targets. */
4376 const float area_ratio = float(jd->sa2->winx) / float(jd->sa2->winy);
4377 /* Split the area diagonally from top-right to bottom-left. */
4378 const bool upper_left = float(x) / float(y + 1) < area_ratio;
4379 /* Split the area diagonally from top-left to bottom-right. */
4380 const bool lower_left = float(x) / float(jd->sa2->winy - y + 1) < area_ratio;
4381
4382 if (upper_left && !lower_left) {
4383 jd->factor = area_docking_snap(std::max(1.0f - fac_y, min_fac_y), event);
4384 return AreaDockTarget::Top;
4385 }
4386 if (!upper_left && lower_left) {
4387 jd->factor = area_docking_snap(std::max(fac_y, min_fac_y), event);
4389 }
4390 if (upper_left && lower_left) {
4391 jd->factor = area_docking_snap(std::max(fac_x, min_fac_x), event);
4392 return AreaDockTarget::Left;
4393 }
4394 if (!upper_left && !lower_left) {
4395 jd->factor = area_docking_snap(std::max(1.0f - fac_x, min_fac_x), event);
4396 return AreaDockTarget::Right;
4397 }
4398 return AreaDockTarget::None;
4399}
4400
4401static float area_split_factor(bContext *C, sAreaJoinData *jd, const wmEvent *event)
4402{
4403 float fac = (jd->split_dir == SCREEN_AXIS_V) ?
4404 float(event->xy[0] - jd->sa1->totrct.xmin) / float(jd->sa1->winx + 1) :
4405 float(event->xy[1] - jd->sa1->totrct.ymin) / float(jd->sa1->winy + 1);
4406
4407 if (event->modifier & KM_CTRL) {
4408 /* Snapping on. */
4409
4410 /* Find nearest neighboring vertex. */
4411 const int axis = (jd->split_dir == SCREEN_AXIS_V) ? 0 : 1;
4412 int dist = INT_MAX;
4413 int loc = 0;
4414 LISTBASE_FOREACH (const ScrVert *, v1, &CTX_wm_screen(C)->vertbase) {
4415 const int v_loc = (&v1->vec.x)[axis];
4416 const int v_dist = abs(v_loc - event->xy[axis]);
4417 if (v_dist < dist) {
4418 loc = v_loc;
4419 dist = v_dist;
4420 }
4421 }
4422 float near_fac = (axis) ? float(loc - jd->sa1->totrct.ymin) / float(jd->sa1->winy + 1) :
4423 float(loc - jd->sa1->totrct.xmin) / float(jd->sa1->winx + 1);
4424
4425 /* Rounded to nearest 12th. */
4426 float frac_fac = round(fac * 12.0f) / 12.0f;
4427
4428 /* Use nearest neighbor or fractional, whichever is closest. */
4429 fac = (fabs(near_fac - fac) < fabs(frac_fac - fac)) ? near_fac : frac_fac;
4430 }
4431 else {
4432 /* Slight snap to center when no modifiers are held. */
4433 if (fac >= 0.48f && fac < 0.5f) {
4434 fac = 0.499999f;
4435 }
4436 else if (fac >= 0.5f && fac < 0.52f) {
4437 fac = 0.500001f;
4438 }
4439 }
4440
4441 /* Don't allow a new area to be created that is very small. */
4442 const float min_size = float(2.0f * ED_area_headersize());
4443 const float min_fac = min_size / ((jd->split_dir == SCREEN_AXIS_V) ? float(jd->sa1->winx + 1) :
4444 float(jd->sa1->winy + 1));
4445 if (min_fac < 0.5f) {
4446 return std::clamp(fac, min_fac, 1.0f - min_fac);
4447 }
4448 return 0.5f;
4449}
4450
4451static void area_join_update_data(bContext *C, sAreaJoinData *jd, const wmEvent *event)
4452{
4453 ScrArea *area = nullptr;
4454
4455 /* TODO: The following is needed until we have linux-specific implementations of
4456 * getWindowUnderCursor. See #130242. Use active window if there are overlapping. */
4457
4458#if (OS_WINDOWS || OS_MAC)
4460#else
4461 int win_count = 0;
4462 LISTBASE_FOREACH (wmWindow *, win, &CTX_wm_manager(C)->windows) {
4463 int cursor[2];
4464 if (wm_cursor_position_get(win, &cursor[0], &cursor[1])) {
4465 rcti rect;
4466 WM_window_rect_calc(win, &rect);
4467 if (BLI_rcti_isect_pt_v(&rect, cursor)) {
4468 win_count++;
4469 }
4470 }
4471 }
4472
4473 if (win_count > 1) {
4475 }
4476 else {
4478 }
4479#endif
4480
4482 jd->dir = SCREEN_DIR_NONE;
4484 jd->dir = area_getorientation(jd->sa1, area);
4485 jd->dock_target = area_docking_target(jd, event);
4486
4487 if (jd->sa2 != area) {
4490 }
4491
4492 if (jd->sa1 == area) {
4493 const int drag_threshold = 20 * UI_SCALE_FAC;
4494 jd->sa2 = area;
4495 if (!(abs(jd->start_x - event->xy[0]) > drag_threshold ||
4496 abs(jd->start_y - event->xy[1]) > drag_threshold))
4497 {
4498 /* We haven't moved enough to start a split. */
4499 jd->dir = SCREEN_DIR_NONE;
4500 jd->split_fac = 0.0f;
4502 return;
4503 }
4504
4505 eScreenAxis dir = (abs(event->xy[0] - jd->start_x) > abs(event->xy[1] - jd->start_y)) ?
4508 jd->split_dir = dir;
4509 jd->split_fac = area_split_factor(C, jd, event);
4510 return;
4511 }
4512
4513 jd->sa2 = area;
4515 jd->dir = area_getorientation(jd->sa1, jd->sa2);
4516 jd->dock_target = area_docking_target(jd, event);
4517}
4518
4525
4527{
4528 uiPopupMenu *pup = UI_popup_menu_begin(C, "Area Options", ICON_NONE);
4529 uiLayout *layout = UI_popup_menu_layout(pup);
4531
4532 PointerRNA ptr = layout->op("SCREEN_OT_area_split",
4533 IFACE_("Horizontal Split"),
4534 ICON_SPLIT_HORIZONTAL,
4536 UI_ITEM_NONE);
4537 RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H);
4538 RNA_float_set(&ptr, "factor", 0.49999f);
4539 blender::int2 pos = {area->totrct.xmin + area->winx / 2, area->totrct.ymin + area->winy / 2};
4540 RNA_int_set_array(&ptr, "cursor", pos);
4541
4542 ptr = layout->op("SCREEN_OT_area_split",
4543 IFACE_("Vertical Split"),
4544 ICON_SPLIT_VERTICAL,
4546 UI_ITEM_NONE);
4547 RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V);
4548 RNA_float_set(&ptr, "factor", 0.49999f);
4549 RNA_int_set_array(&ptr, "cursor", pos);
4550
4551 layout->separator();
4552
4553 layout->op("SCREEN_OT_area_join", IFACE_("Move/Join/Dock Area"), ICON_AREA_DOCK);
4554
4555 layout->separator();
4556
4557 layout->op("SCREEN_OT_screen_full_area",
4558 area->full ? IFACE_("Restore Areas") : IFACE_("Maximize Area"),
4559 ICON_NONE);
4560
4561 ptr = layout->op("SCREEN_OT_screen_full_area", IFACE_("Focus Mode"), ICON_NONE);
4562 RNA_boolean_set(&ptr, "use_hide_panels", true);
4563
4564 layout->op("SCREEN_OT_area_dupli", std::nullopt, ICON_NONE);
4565 layout->separator();
4566 layout->op("SCREEN_OT_area_close", IFACE_("Close Area"), ICON_X);
4567
4568 UI_popup_menu_end(C, pup);
4569}
4570
4571static bool is_header_azone_location(ScrArea *area, const wmEvent *event)
4572{
4573 if (event->xy[0] > (area->totrct.xmin + UI_HEADER_OFFSET)) {
4574 return false;
4575 }
4576
4578 if (!header || header->flag & RGN_FLAG_HIDDEN) {
4579 return false;
4580 }
4581
4582 const int height = ED_area_headersize();
4583 if (header->alignment == RGN_ALIGN_TOP && event->xy[1] > (area->totrct.ymax - height)) {
4584 return true;
4585 }
4586 if (header->alignment == RGN_ALIGN_BOTTOM && event->xy[1] < (area->totrct.ymin + height)) {
4587 return true;
4588 }
4589
4590 return false;
4591}
4592
4593/* modal callback while selecting area (space) that will be removed */
4595{
4596 if (event->type == WINDEACTIVATE) {
4597 /* This operator can close windows, which can cause it to be re-run. */
4598 area_join_exit(C, op);
4599 return OPERATOR_FINISHED;
4600 }
4601
4602 if (op->customdata == nullptr) {
4603 if (!area_join_init(C, op, nullptr, nullptr)) {
4604 return OPERATOR_CANCELLED;
4605 }
4606 }
4608 if (jd == nullptr) {
4609 return OPERATOR_CANCELLED;
4610 }
4611
4612 /* execute the events */
4613 switch (event->type) {
4614
4615 case MOUSEMOVE: {
4616 area_join_update_data(C, jd, event);
4618 WM_cursor_set(jd->win1, area_join_cursor(jd, event));
4620
4622 if (jd->sa1 && jd->sa1 == jd->sa2) {
4623 if (jd->split_fac == 0.0f) {
4624 status.item(IFACE_("Split/Dock"), ICON_MOUSE_LMB_DRAG);
4625 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4626 }
4627 else {
4628 status.item(IFACE_("Select Split"), ICON_MOUSE_LMB_DRAG);
4629 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4630 status.item_bool(IFACE_("Snap"), event->modifier & KM_CTRL, ICON_EVENT_CTRL);
4631 }
4632 }
4633 else {
4634 if (jd->dock_target == AreaDockTarget::None) {
4635 status.item(IFACE_("Select Area"), ICON_MOUSE_LMB_DRAG);
4636 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4637 }
4638 else {
4639 status.item(IFACE_("Select Location"), ICON_MOUSE_LMB_DRAG);
4640 status.item(IFACE_("Cancel"), ICON_EVENT_ESC);
4641 status.item_bool(CTX_IFACE_(BLT_I18NCONTEXT_ID_SCREEN, "Precision"),
4642 event->modifier & KM_ALT,
4643 ICON_EVENT_ALT);
4644 status.item_bool(IFACE_("Snap"), event->modifier & KM_CTRL, ICON_EVENT_CTRL);
4645 }
4646 }
4647 break;
4648 }
4649 case LEFTMOUSE:
4650 if (event->val == KM_RELEASE) {
4651 area_join_update_data(C, jd, event);
4655 if (jd->dir == SCREEN_DIR_NONE && jd->dock_target == AreaDockTarget::None &&
4656 jd->split_fac == 0.0f && is_header_azone_location(jd->sa1, event))
4657 {
4659 area_join_cancel(C, op);
4660 return OPERATOR_CANCELLED;
4661 }
4662 if (jd->sa1 && !jd->sa2) {
4663 /* Break out into new window if we are really outside the source window bounds. */
4664 if (event->xy[0] < 0 || event->xy[0] > jd->win1->sizex || event->xy[1] < 1 ||
4665 event->xy[1] > jd->win1->sizey)
4666 {
4667 /* We have to clear handlers or we get an error in wm_gizmomap_modal_get. */
4669 area_dupli_open(C, jd->sa1, blender::int2(event->xy[0], event->xy[1] - jd->sa1->winy));
4671 {
4674 {
4675 /* We've pulled a single editor out of the window into empty space.
4676 * Close the source window so we don't end up with a duplicate. */
4677 jd->close_win = true;
4678 }
4679 }
4680 }
4681 }
4682 else if (jd->sa1 && jd->sa1 == jd->sa2) {
4683 /* Same area so split. */
4684 if (area_split_allowed(jd->sa1, jd->split_dir) && jd->split_fac > 0.0001) {
4685 float inner[4] = {1.0f, 1.0f, 1.0f, 0.1f};
4686 float outline[4] = {1.0f, 1.0f, 1.0f, 0.3f};
4688 jd->win1, CTX_wm_screen(C), &jd->sa1->totrct, inner, outline, AREA_SPLIT_FADEOUT);
4689 jd->sa2 = area_split(jd->win2,
4691 jd->sa1,
4692 jd->split_dir,
4693 jd->split_fac,
4694 true);
4695
4696 const bool large_v = jd->split_dir == SCREEN_AXIS_V &&
4697 ((jd->start_x < event->xy[0] && jd->split_fac > 0.5f) ||
4698 (jd->start_x > event->xy[0] && jd->split_fac < 0.5f));
4699
4700 const bool large_h = jd->split_dir == SCREEN_AXIS_H &&
4701 ((jd->start_y < event->xy[1] && jd->split_fac > 0.5f) ||
4702 (jd->start_y > event->xy[1] && jd->split_fac < 0.5f));
4703
4704 if (large_v || large_h) {
4705 /* Swap areas to follow old behavior of new area added based on starting location.
4706 * When from above the new area is above, when from below the new area is below, etc.
4707 * Note that this preserves runtime data, unlike #ED_area_swapspace. */
4708 std::swap(jd->sa1->v1, jd->sa2->v1);
4709 std::swap(jd->sa1->v2, jd->sa2->v2);
4710 std::swap(jd->sa1->v3, jd->sa2->v3);
4711 std::swap(jd->sa1->v4, jd->sa2->v4);
4712 std::swap(jd->sa1->totrct, jd->sa2->totrct);
4713 std::swap(jd->sa1->winx, jd->sa2->winx);
4714 std::swap(jd->sa1->winy, jd->sa2->winy);
4715 }
4716
4719 }
4720 }
4721 else if (jd->sa1 && jd->sa2 && jd->dock_target != AreaDockTarget::None) {
4722 /* Dock this to the new location. */
4723 area_docking_apply(C, op);
4724 }
4725 else if (jd->sa1 && jd->sa2 && jd->dir != SCREEN_DIR_NONE) {
4726 /* Join to neighbor. */
4727 area_join_apply(C, op);
4728 }
4729 else {
4730 area_join_cancel(C, op);
4731 return OPERATOR_CANCELLED;
4732 }
4733
4734 /* Areas changed, update window titles. */
4735 if (jd->win2 && jd->win2 != jd->win1) {
4737 }
4738 if (jd->win1 && !jd->close_win) {
4740 }
4741
4742 const bool do_close_win = jd->close_win;
4743 wmWindow *close_win = jd->win1;
4744 area_join_exit(C, op);
4745 if (do_close_win) {
4746 wm_window_close(C, CTX_wm_manager(C), close_win);
4747 }
4748
4750 return OPERATOR_FINISHED;
4751 }
4752 break;
4753
4754 case RIGHTMOUSE:
4755 case EVT_ESCKEY:
4756 area_join_cancel(C, op);
4757 return OPERATOR_CANCELLED;
4758 default: {
4759 break;
4760 }
4761 }
4762
4764}
4765
4766/* Operator for joining two areas (space types) */
4768{
4769 /* identifiers */
4770 ot->name = "Join Area";
4771 ot->description = "Join selected areas into new window";
4772 ot->idname = "SCREEN_OT_area_join";
4773
4774 /* API callbacks. */
4775 ot->exec = area_join_exec;
4776 ot->invoke = area_join_invoke;
4777 ot->modal = area_join_modal;
4778 ot->poll = screen_active_editable;
4779 ot->cancel = area_join_cancel;
4780
4781 /* flags */
4782 ot->flag = OPTYPE_BLOCKING;
4783
4784 /* rna */
4785 RNA_def_int_vector(ot->srna,
4786 "source_xy",
4787 2,
4788 nullptr,
4789 INT_MIN,
4790 INT_MAX,
4791 "Source location",
4792 "",
4793 INT_MIN,
4794 INT_MAX);
4795 RNA_def_int_vector(ot->srna,
4796 "target_xy",
4797 2,
4798 nullptr,
4799 INT_MIN,
4800 INT_MAX,
4801 "Target location",
4802 "",
4803 INT_MIN,
4804 INT_MAX);
4805}
4806
4808
4809/* -------------------------------------------------------------------- */
4812
4814 wmOperator *op,
4815 const wmEvent *event)
4816{
4817 ScrArea *sa1, *sa2;
4818 if (screen_area_edge_from_cursor(C, event->xy, &sa1, &sa2) == nullptr) {
4819 return OPERATOR_CANCELLED;
4820 }
4821
4823 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
4824 uiLayout *layout = UI_popup_menu_layout(pup);
4825
4826 /* Vertical Split */
4828 ptr = layout->op("SCREEN_OT_area_split",
4829 IFACE_("Vertical Split"),
4830 ICON_SPLIT_VERTICAL,
4832 UI_ITEM_NONE);
4833 /* store initial mouse cursor position. */
4834 RNA_int_set_array(&ptr, "cursor", event->xy);
4835 RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V);
4836
4837 /* Horizontal Split */
4838 ptr = layout->op("SCREEN_OT_area_split",
4839 IFACE_("Horizontal Split"),
4840 ICON_SPLIT_HORIZONTAL,
4842 UI_ITEM_NONE);
4843 /* store initial mouse cursor position. */
4844 RNA_int_set_array(&ptr, "cursor", event->xy);
4845 RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H);
4846
4847 if (sa1 && sa2) {
4848 layout->separator();
4849 }
4850
4851 /* Join needs two very similar areas. */
4852 if (sa1 && sa2) {
4853 eScreenDir dir = area_getorientation(sa1, sa2);
4854 if (dir != SCREEN_DIR_NONE) {
4855 ptr = layout->op("SCREEN_OT_area_join",
4856 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? IFACE_("Join Up") :
4857 IFACE_("Join Right"),
4858 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? ICON_AREA_JOIN_UP : ICON_AREA_JOIN,
4860 UI_ITEM_NONE);
4861 RNA_int_set_array(&ptr, "source_xy", blender::int2{sa2->totrct.xmin, sa2->totrct.ymin});
4862 RNA_int_set_array(&ptr, "target_xy", blender::int2{sa1->totrct.xmin, sa1->totrct.ymin});
4863
4864 ptr = layout->op(
4865 "SCREEN_OT_area_join",
4866 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? IFACE_("Join Down") : IFACE_("Join Left"),
4867 ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) ? ICON_AREA_JOIN_DOWN : ICON_AREA_JOIN_LEFT,
4869 UI_ITEM_NONE);
4870 RNA_int_set_array(&ptr, "source_xy", blender::int2{sa1->totrct.xmin, sa1->totrct.ymin});
4871 RNA_int_set_array(&ptr, "target_xy", blender::int2{sa2->totrct.xmin, sa2->totrct.ymin});
4872
4873 layout->separator();
4874 }
4875 }
4876
4877 /* Swap just needs two areas. */
4878 if (sa1 && sa2) {
4879 ptr = layout->op("SCREEN_OT_area_swap",
4880 IFACE_("Swap Areas"),
4881 ICON_AREA_SWAP,
4883 UI_ITEM_NONE);
4884 RNA_int_set_array(&ptr, "cursor", event->xy);
4885 }
4886
4887 UI_popup_menu_end(C, pup);
4888
4889 return OPERATOR_INTERFACE;
4890}
4891
4893{
4894 /* identifiers */
4895 ot->name = "Area Options";
4896 ot->description = "Operations for splitting and merging";
4897 ot->idname = "SCREEN_OT_area_options";
4898
4899 /* API callbacks. */
4901
4903
4904 /* flags */
4905 ot->flag = OPTYPE_INTERNAL;
4906}
4907
4909
4910/* -------------------------------------------------------------------- */
4913
4915{
4916 Main *bmain = CTX_data_main(C);
4917 int tot = 0;
4918
4919 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
4920 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
4921 if (area->spacedata.first != area->spacedata.last) {
4922 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
4923
4924 BLI_remlink(&area->spacedata, sl);
4925 tot += BLI_listbase_count(&area->spacedata);
4926 BKE_spacedata_freelist(&area->spacedata);
4927 BLI_addtail(&area->spacedata, sl);
4928 }
4929 }
4930 }
4931 BKE_reportf(op->reports, RPT_INFO, "Removed amount of editors: %d", tot);
4932
4933 return OPERATOR_FINISHED;
4934}
4935
4937{
4938 /* identifiers */
4939 ot->name = "Clean Up Space Data";
4940 ot->description = "Remove unused settings for invisible editors";
4941 ot->idname = "SCREEN_OT_spacedata_cleanup";
4942
4943 /* API callbacks. */
4944 ot->exec = spacedata_cleanup_exec;
4945 ot->poll = WM_operator_winactive;
4946}
4947
4949
4950/* -------------------------------------------------------------------- */
4953
4955{
4957 return false;
4958 }
4960 return !BLI_listbase_is_empty(&wm->runtime->operators);
4961}
4962
4964{
4966 wmOperator *lastop = static_cast<wmOperator *>(wm->runtime->operators.last);
4967
4968 /* Seek last registered operator */
4969 while (lastop) {
4970 if (lastop->type->flag & OPTYPE_REGISTER) {
4971 break;
4972 }
4973 lastop = lastop->prev;
4974 }
4975
4976 if (lastop) {
4977 WM_operator_free_all_after(wm, lastop);
4978 WM_operator_repeat_last(C, lastop);
4979 }
4980
4981 return OPERATOR_CANCELLED;
4982}
4983
4985{
4986 /* identifiers */
4987 ot->name = "Repeat Last";
4988 ot->description = "Repeat last action";
4989 ot->idname = "SCREEN_OT_repeat_last";
4990
4991 /* API callbacks. */
4992 ot->exec = repeat_last_exec;
4993
4994 ot->poll = repeat_history_poll;
4995}
4996
4998
4999/* -------------------------------------------------------------------- */
5002
5004 wmOperator *op,
5005 const wmEvent * /*event*/)
5006{
5008
5009 int items = BLI_listbase_count(&wm->runtime->operators);
5010 if (items == 0) {
5011 return OPERATOR_CANCELLED;
5012 }
5013
5015 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
5016 uiLayout *layout = UI_popup_menu_layout(pup);
5017
5018 wmOperator *lastop;
5019 int i;
5020 for (i = items - 1, lastop = static_cast<wmOperator *>(wm->runtime->operators.last); lastop;
5021 lastop = lastop->prev, i--)
5022 {
5023 if ((lastop->type->flag & OPTYPE_REGISTER) && WM_operator_repeat_check(C, lastop)) {
5024 PointerRNA op_ptr = layout->op(
5025 op->type, WM_operatortype_name(lastop->type, lastop->ptr), ICON_NONE);
5026 RNA_int_set(&op_ptr, "index", i);
5027 }
5028 }
5029
5030 UI_popup_menu_end(C, pup);
5031
5032 return OPERATOR_INTERFACE;
5033}
5034
5036{
5038
5039 op = static_cast<wmOperator *>(
5040 BLI_findlink(&wm->runtime->operators, RNA_int_get(op->ptr, "index")));
5041 if (op) {
5042 /* let's put it as last operator in list */
5043 BLI_remlink(&wm->runtime->operators, op);
5044 BLI_addtail(&wm->runtime->operators, op);
5045
5046 WM_operator_repeat(C, op);
5047 }
5048
5049 return OPERATOR_FINISHED;
5050}
5051
5053{
5054 /* identifiers */
5055 ot->name = "Repeat History";
5056 ot->description = "Display menu for previous actions performed";
5057 ot->idname = "SCREEN_OT_repeat_history";
5058
5059 /* API callbacks. */
5060 ot->invoke = repeat_history_invoke;
5061 ot->exec = repeat_history_exec;
5062 ot->poll = repeat_history_poll;
5063
5064 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
5065}
5066
5068
5069/* -------------------------------------------------------------------- */
5072
5074 wmOperator * /*op*/,
5075 const wmEvent * /*event*/)
5076{
5078
5079 if (lastop) {
5080 WM_operator_redo_popup(C, lastop);
5081 }
5082
5083 return OPERATOR_CANCELLED;
5084}
5085
5087{
5088 /* identifiers */
5089 ot->name = "Redo Last";
5090 ot->description = "Display parameters for last action performed";
5091 ot->idname = "SCREEN_OT_redo_last";
5092
5093 /* API callbacks. */
5094 ot->invoke = redo_last_invoke;
5095 ot->poll = repeat_history_poll;
5096}
5097
5099
5100/* -------------------------------------------------------------------- */
5103
5105{
5106 if (rv3d->localvd) {
5107 rv3d->localvd->view = rv3d->view;
5108 rv3d->localvd->view_axis_roll = rv3d->view_axis_roll;
5109 rv3d->localvd->persp = rv3d->persp;
5110 copy_qt_qt(rv3d->localvd->viewquat, rv3d->viewquat);
5111 }
5112}
5113
5115 ScrArea *area, ARegion *region, const char viewlock, const char view, const char persp)
5116{
5117 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
5118 rv3d->rflag &= ~RV3D_WAS_CAMOB;
5119
5120 if (persp == RV3D_CAMOB) {
5122 }
5123
5124 rv3d->viewlock = viewlock;
5125 rv3d->runtime_viewlock = 0;
5126 rv3d->view = view;
5128 rv3d->persp = persp;
5129
5130 ED_view3d_lock(rv3d);
5132 if ((viewlock & RV3D_BOXCLIP) && (persp == RV3D_ORTHO)) {
5133 ED_view3d_quadview_update(area, region, true);
5134 }
5135}
5136
5137/* insert a region in the area region list */
5139{
5140 ARegion *region = CTX_wm_region(C);
5141
5142 /* some rules... */
5143 if (region->regiontype != RGN_TYPE_WINDOW) {
5144 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-split");
5145 }
5146 else if (region->alignment == RGN_ALIGN_QSPLIT) {
5147 /* Exit quad-view */
5148 bScreen *screen = CTX_wm_screen(C);
5149 ScrArea *area = CTX_wm_area(C);
5150
5151 /* keep current region */
5152 region->alignment = 0;
5153
5154 if (area->spacetype == SPACE_VIEW3D) {
5155 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
5156
5157 /* if this is a locked view, use settings from 'User' view */
5158 if (rv3d->viewlock) {
5159 View3D *v3d_user;
5160 ARegion *region_user;
5161
5162 if (ED_view3d_context_user_region(C, &v3d_user, &region_user)) {
5163 if (region != region_user) {
5164 std::swap(region->regiondata, region_user->regiondata);
5165 rv3d = static_cast<RegionView3D *>(region->regiondata);
5166 }
5167 }
5168 }
5169
5171 rv3d->viewlock = 0;
5172
5173 /* FIXME: This fixes missing update to workbench TAA. (see #76216)
5174 * However, it would be nice if the tagging should be done in a more conventional way. */
5175 rv3d->rflag |= RV3D_GPULIGHT_UPDATE;
5176
5177 /* Accumulate locks, in case they're mixed. */
5178 LISTBASE_FOREACH (ARegion *, region_iter, &area->regionbase) {
5179 if (region_iter->regiontype == RGN_TYPE_WINDOW) {
5180 RegionView3D *rv3d_iter = static_cast<RegionView3D *>(region_iter->regiondata);
5181 rv3d->viewlock_quad |= rv3d_iter->viewlock;
5182 }
5183 }
5184 }
5185
5186 LISTBASE_FOREACH_MUTABLE (ARegion *, region_iter, &area->regionbase) {
5187 if (region_iter->alignment == RGN_ALIGN_QSPLIT) {
5188 ED_region_remove(C, area, region_iter);
5189 if (region_iter == screen->active_region) {
5190 screen->active_region = nullptr;
5191 }
5192 }
5193 }
5194 ED_area_tag_redraw(area);
5196 }
5197 else if (region->next) {
5198 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-split");
5199 }
5200 else {
5201 /* Enter quad-view */
5202 ScrArea *area = CTX_wm_area(C);
5203
5204 region->alignment = RGN_ALIGN_QSPLIT;
5205
5206 for (int count = 0; count < 3; count++) {
5207 ARegion *new_region = BKE_area_region_copy(area->type, region);
5208 BLI_addtail(&area->regionbase, new_region);
5209 }
5210
5211 /* lock views and set them */
5212 if (area->spacetype == SPACE_VIEW3D) {
5213 View3D *v3d = static_cast<View3D *>(area->spacedata.first);
5214 int index_qsplit = 0;
5215
5216 /* run ED_view3d_lock() so the correct 'rv3d->viewquat' is set,
5217 * otherwise when restoring rv3d->localvd the 'viewquat' won't
5218 * match the 'view', set on entering localview See: #26315,
5219 *
5220 * We could avoid manipulating rv3d->localvd here if exiting
5221 * localview with a 4-split would assign these view locks */
5222 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
5223 const char viewlock = (rv3d->viewlock_quad & RV3D_VIEWLOCK_INIT) ?
5226
5228 area, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
5230 (region = region->next),
5231 viewlock,
5232 ED_view3d_lock_view_from_index(index_qsplit++),
5233 RV3D_ORTHO);
5235 (region = region->next),
5236 viewlock,
5237 ED_view3d_lock_view_from_index(index_qsplit++),
5238 RV3D_ORTHO);
5239/* forcing camera is distracting */
5240#if 0
5241 if (v3d->camera) {
5242 region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_CAMERA, RV3D_CAMOB);
5243 }
5244 else {
5245 region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_USER, RV3D_PERSP);
5246 }
5247#else
5248 (void)v3d;
5249#endif
5250 }
5251 ED_area_tag_redraw(area);
5253 }
5254
5255 return OPERATOR_FINISHED;
5256}
5257
5259{
5260 /* identifiers */
5261 ot->name = "Toggle Quad View";
5262 ot->description = "Split selected area into camera, front, right, and top views";
5263 ot->idname = "SCREEN_OT_region_quadview";
5264
5265 /* API callbacks. */
5266 ot->exec = region_quadview_exec;
5268 ot->flag = 0;
5269}
5270
5272
5273/* -------------------------------------------------------------------- */
5276
5278{
5279 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "region_type");
5280
5281 ARegion *region;
5282 if (RNA_property_is_set(op->ptr, prop)) {
5284 }
5285 else {
5286 region = CTX_wm_region(C);
5287 }
5288
5289 if (region && (region->alignment != RGN_ALIGN_NONE)) {
5290 ED_region_toggle_hidden(C, region);
5291 }
5292 ED_region_tag_redraw(region);
5293
5294 return OPERATOR_FINISHED;
5295}
5296
5298{
5299 ScrArea *area = CTX_wm_area(C);
5300
5301 /* Don't flip anything around in top-bar. */
5302 if (area && area->spacetype == SPACE_TOPBAR) {
5303 CTX_wm_operator_poll_msg_set(C, "Toggling regions in the Top-bar is not allowed");
5304 return false;
5305 }
5306
5307 return ED_operator_areaactive(C);
5308}
5309
5311{
5312 /* identifiers */
5313 ot->name = "Toggle Region";
5314 ot->idname = "SCREEN_OT_region_toggle";
5315 ot->description = "Hide or unhide the region";
5316
5317 /* API callbacks. */
5318 ot->exec = region_toggle_exec;
5319 ot->poll = region_toggle_poll;
5320 ot->flag = 0;
5321
5322 RNA_def_enum(ot->srna,
5323 "region_type",
5325 0,
5326 "Region Type",
5327 "Type of the region to toggle");
5328}
5329
5331
5332/* -------------------------------------------------------------------- */
5335
5336/* flip a region alignment */
5338{
5339 ARegion *region = CTX_wm_region(C);
5340
5341 if (!region) {
5342 return OPERATOR_CANCELLED;
5343 }
5344
5345 if (region->alignment == RGN_ALIGN_TOP) {
5346 region->alignment = RGN_ALIGN_BOTTOM;
5347 }
5348 else if (region->alignment == RGN_ALIGN_BOTTOM) {
5349 region->alignment = RGN_ALIGN_TOP;
5350 }
5351 else if (region->alignment == RGN_ALIGN_LEFT) {
5352 region->alignment = RGN_ALIGN_RIGHT;
5353 }
5354 else if (region->alignment == RGN_ALIGN_RIGHT) {
5355 region->alignment = RGN_ALIGN_LEFT;
5356 }
5357
5361
5362 return OPERATOR_FINISHED;
5363}
5364
5366{
5367 ScrArea *area = CTX_wm_area(C);
5368
5369 /* Don't flip anything around in top-bar. */
5370 if (area && area->spacetype == SPACE_TOPBAR) {
5371 CTX_wm_operator_poll_msg_set(C, "Flipping regions in the Top-bar is not allowed");
5372 return false;
5373 }
5374
5375 return ED_operator_areaactive(C);
5376}
5377
5379{
5380 /* identifiers */
5381 ot->name = "Flip Region";
5382 ot->idname = "SCREEN_OT_region_flip";
5383 ot->description = "Toggle the region's alignment (left/right or top/bottom)";
5384
5385 /* API callbacks. */
5386 ot->exec = region_flip_exec;
5387 ot->poll = region_flip_poll;
5388 ot->flag = 0;
5389}
5390
5392
5393/* -------------------------------------------------------------------- */
5396
5397/* show/hide header text menus */
5399{
5400 ScrArea *area = CTX_wm_area(C);
5401
5402 area->flag = area->flag ^ HEADER_NO_PULLDOWN;
5403
5404 ED_area_tag_redraw(area);
5406
5407 return OPERATOR_FINISHED;
5408}
5409
5411{
5412 /* identifiers */
5413 ot->name = "Expand/Collapse Header Menus";
5414 ot->idname = "SCREEN_OT_header_toggle_menus";
5415 ot->description = "Expand or collapse the header pull-down menus";
5416
5417 /* API callbacks. */
5419 ot->poll = ED_operator_areaactive;
5420 ot->flag = 0;
5421}
5422
5424
5425/* -------------------------------------------------------------------- */
5428
5429static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
5430{
5431 if (ED_area_is_global(area)) {
5432 return;
5433 }
5434
5436
5437 ptr = layout->op("SCREEN_OT_area_join",
5438 IFACE_("Move/Split Area"),
5439 ICON_AREA_DOCK,
5441 UI_ITEM_NONE);
5442
5443 layout->separator();
5444
5445 layout->op("SCREEN_OT_screen_full_area",
5446 area->full ? IFACE_("Restore Areas") : IFACE_("Maximize Area"),
5447 ICON_NONE);
5448
5449 if (area->spacetype != SPACE_FILE && !area->full) {
5450 ptr = layout->op("SCREEN_OT_screen_full_area",
5451 IFACE_("Focus Mode"),
5452 ICON_NONE,
5454 UI_ITEM_NONE);
5455 RNA_boolean_set(&ptr, "use_hide_panels", true);
5456 }
5457
5458 layout->op("SCREEN_OT_area_dupli", std::nullopt, ICON_NONE);
5459 layout->separator();
5460 layout->op("SCREEN_OT_area_close", std::nullopt, ICON_X);
5461}
5462
5464{
5465 ScrArea *area = CTX_wm_area(C);
5466 {
5468 (ID *)CTX_wm_screen(C), &RNA_Space, area->spacedata.first);
5469 if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
5470 layout->prop(&ptr, "show_region_header", UI_ITEM_NONE, IFACE_("Show Header"), ICON_NONE);
5471 }
5472
5473 ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
5474 uiLayout *col = &layout->column(false);
5475 col->active_set((region_header->flag & RGN_FLAG_HIDDEN) == 0);
5476
5478 col->prop(
5479 &ptr, "show_region_tool_header", UI_ITEM_NONE, IFACE_("Show Tool Settings"), ICON_NONE);
5480 }
5481
5482 col->op("SCREEN_OT_header_toggle_menus",
5483 IFACE_("Show Menus"),
5484 (area->flag & HEADER_NO_PULLDOWN) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT);
5485 }
5486
5487 if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
5488 layout->separator();
5489 ED_screens_region_flip_menu_create(C, layout, nullptr);
5490 layout->separator();
5491 screen_area_menu_items(area, layout);
5492 }
5493}
5494
5496{
5497 ScrArea *area = CTX_wm_area(C);
5498
5499 {
5501 (ID *)CTX_wm_screen(C), &RNA_Space, area->spacedata.first);
5502 layout->prop(&ptr, "show_region_footer", UI_ITEM_NONE, IFACE_("Show Footer"), ICON_NONE);
5503 }
5504
5505 ED_screens_region_flip_menu_create(C, layout, nullptr);
5506 layout->separator();
5507 screen_area_menu_items(area, layout);
5508}
5509
5511{
5512 const ARegion *region = CTX_wm_region(C);
5513 const short region_alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
5514 const char *but_flip_str = region_alignment == RGN_ALIGN_LEFT ? IFACE_("Flip to Right") :
5515 region_alignment == RGN_ALIGN_RIGHT ? IFACE_("Flip to Left") :
5516 region_alignment == RGN_ALIGN_BOTTOM ? IFACE_("Flip to Top") :
5517 IFACE_("Flip to Bottom");
5518
5519 /* default is blender::wm::OpCallContext::InvokeRegionWin, which we don't want here. */
5521
5522 layout->op("SCREEN_OT_region_flip", but_flip_str, ICON_NONE);
5523}
5524
5525static void ed_screens_statusbar_menu_create(uiLayout *layout, void * /*arg*/)
5526{
5527 PointerRNA ptr = RNA_pointer_create_discrete(nullptr, &RNA_PreferencesView, &U);
5528 layout->prop(&ptr, "show_statusbar_stats", UI_ITEM_NONE, IFACE_("Scene Statistics"), ICON_NONE);
5529 layout->prop(
5530 &ptr, "show_statusbar_scene_duration", UI_ITEM_NONE, IFACE_("Scene Duration"), ICON_NONE);
5531 layout->prop(&ptr, "show_statusbar_memory", UI_ITEM_NONE, IFACE_("System Memory"), ICON_NONE);
5533 layout->prop(&ptr, "show_statusbar_vram", UI_ITEM_NONE, IFACE_("Video Memory"), ICON_NONE);
5534 }
5535 layout->prop(
5536 &ptr, "show_extensions_updates", UI_ITEM_NONE, IFACE_("Extensions Updates"), ICON_NONE);
5537 layout->prop(&ptr, "show_statusbar_version", UI_ITEM_NONE, IFACE_("Blender Version"), ICON_NONE);
5538}
5539
5541 wmOperator * /*op*/,
5542 const wmEvent * /*event*/)
5543{
5544 const ScrArea *area = CTX_wm_area(C);
5545 const ARegion *region = CTX_wm_region(C);
5546
5547 if (area && area->spacetype == SPACE_STATUSBAR) {
5548 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Status Bar"), ICON_NONE);
5549 uiLayout *layout = UI_popup_menu_layout(pup);
5550 ed_screens_statusbar_menu_create(layout, nullptr);
5551 UI_popup_menu_end(C, pup);
5552 }
5553 else if (region) {
5555 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE);
5556 uiLayout *layout = UI_popup_menu_layout(pup);
5557 ED_screens_header_tools_menu_create(C, layout, nullptr);
5558 UI_popup_menu_end(C, pup);
5559 }
5560 else if (region->regiontype == RGN_TYPE_FOOTER) {
5561 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE);
5562 uiLayout *layout = UI_popup_menu_layout(pup);
5563 ED_screens_footer_tools_menu_create(C, layout, nullptr);
5564 UI_popup_menu_end(C, pup);
5565 }
5566 else if (region->regiontype == RGN_TYPE_NAV_BAR) {
5567 uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Navigation Bar"), ICON_NONE);
5568 uiLayout *layout = UI_popup_menu_layout(pup);
5569
5570 /* We need blender::wm::OpCallContext::InvokeDefault in case menu item is over another area.
5571 */
5573 layout->op("SCREEN_OT_region_toggle", IFACE_("Hide"), ICON_NONE);
5574
5575 ED_screens_region_flip_menu_create(C, layout, nullptr);
5576 const ScrArea *area = CTX_wm_area(C);
5577 if (area && area->spacetype == SPACE_PROPERTIES) {
5578 layout->menu_fn(IFACE_("Visible Tabs"), ICON_NONE, ED_buttons_visible_tabs_menu, nullptr);
5579 }
5580 UI_popup_menu_end(C, pup);
5581 }
5582 }
5583
5584 return OPERATOR_INTERFACE;
5585}
5586
5588{
5589 /* identifiers */
5590 ot->name = "Region";
5591 ot->description = "Display region context menu";
5592 ot->idname = "SCREEN_OT_region_context_menu";
5593
5594 /* API callbacks. */
5596}
5597
5599
5600/* -------------------------------------------------------------------- */
5605
5606static bool match_region_with_redraws(const ScrArea *area,
5607 eRegion_Type regiontype,
5608 eScreen_Redraws_Flag redraws,
5609 bool from_anim_edit)
5610{
5611 const eSpace_Type spacetype = eSpace_Type(area->spacetype);
5612 if (regiontype == RGN_TYPE_WINDOW) {
5613
5614 switch (spacetype) {
5615 case SPACE_VIEW3D:
5616 if ((redraws & TIME_ALL_3D_WIN) || from_anim_edit) {
5617 return true;
5618 }
5619 break;
5620 case SPACE_GRAPH:
5621 case SPACE_NLA:
5622 if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit) {
5623 return true;
5624 }
5625 break;
5626 case SPACE_ACTION:
5627 /* if only 1 window or 3d windows, we do timeline too
5628 * NOTE: Now we do action editor in all these cases, since timeline is here. */
5629 if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit) {
5630 return true;
5631 }
5632 break;
5633 case SPACE_PROPERTIES:
5634 if (redraws & TIME_ALL_BUTS_WIN) {
5635 return true;
5636 }
5637 break;
5638 case SPACE_SEQ:
5639 if ((redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) || from_anim_edit) {
5640 return true;
5641 }
5642 break;
5643 case SPACE_NODE:
5644 if (redraws & TIME_NODES) {
5645 return true;
5646 }
5647 break;
5648 case SPACE_IMAGE:
5649 if ((redraws & TIME_ALL_IMAGE_WIN) || from_anim_edit) {
5650 return true;
5651 }
5652 break;
5653 case SPACE_CLIP:
5654 if ((redraws & TIME_CLIPS) || from_anim_edit) {
5655 return true;
5656 }
5657 break;
5658 case SPACE_SPREADSHEET:
5659 if (redraws & TIME_SPREADSHEETS) {
5660 return true;
5661 }
5662 break;
5663 default:
5664 break;
5665 }
5666 }
5667 else if (regiontype == RGN_TYPE_UI) {
5668 if (spacetype == SPACE_CLIP) {
5669 /* Track Preview button is on Properties Editor in SpaceClip,
5670 * and it's very common case when users want it be refreshing
5671 * during playback, so asking people to enable special option
5672 * for this is a bit tricky, so add exception here for refreshing
5673 * Properties Editor for SpaceClip always */
5674 return true;
5675 }
5676
5677 if (redraws & TIME_ALL_BUTS_WIN) {
5678 return true;
5679 }
5680 }
5681 else if (regiontype == RGN_TYPE_HEADER) {
5682 /* The Timeline mode of the Dope Sheet shows playback controls in the header. */
5683 if (spacetype == SPACE_ACTION) {
5684 SpaceAction *saction = (SpaceAction *)area->spacedata.first;
5685 return saction->mode == SACTCONT_TIMELINE;
5686 }
5687 }
5688 else if (regiontype == RGN_TYPE_FOOTER) {
5689 /* The footer region in animation editors shows the current frame. */
5690 if (ELEM(spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_SEQ, SPACE_NLA)) {
5691 return true;
5692 }
5693 }
5694 else if (regiontype == RGN_TYPE_PREVIEW) {
5695 switch (spacetype) {
5696 case SPACE_SEQ:
5697 if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) {
5698 return true;
5699 }
5700 break;
5701 case SPACE_CLIP:
5702 return true;
5703 default:
5704 break;
5705 }
5706 }
5707 else if (regiontype == RGN_TYPE_TOOLS) {
5708 switch (spacetype) {
5709 case SPACE_SPREADSHEET:
5710 if (redraws & TIME_SPREADSHEETS) {
5711 return true;
5712 }
5713 break;
5714 default:
5715 break;
5716 }
5717 }
5718
5719 return false;
5720}
5721
5723 bContext *C, ScrArea *area, ARegion *region, const Scene *scene, eScreen_Redraws_Flag redraws)
5724{
5725 /* Do follow time here if editor type supports it */
5726 if ((redraws & TIME_FOLLOW) &&
5728 eRegion_Type(region->regiontype)))
5729 {
5730 float w = BLI_rctf_size_x(&region->v2d.cur);
5731 if (scene->r.cfra < region->v2d.cur.xmin) {
5732 region->v2d.cur.xmax = scene->r.cfra;
5733 region->v2d.cur.xmin = region->v2d.cur.xmax - w;
5734 ED_region_tag_redraw(region);
5735 return;
5736 }
5737 if (scene->r.cfra > region->v2d.cur.xmax) {
5738 region->v2d.cur.xmin = scene->r.cfra;
5739 region->v2d.cur.xmax = region->v2d.cur.xmin + w;
5740 ED_region_tag_redraw(region);
5741 return;
5742 }
5743 }
5744
5745 /* No need to do a full redraw as the current frame indicator is only updated.
5746 * We do need to redraw when this area is in full screen as no other areas
5747 * will be tagged for redrawing. */
5748 if (region->regiontype == RGN_TYPE_WINDOW && !area->full) {
5749 if (ELEM(area->spacetype, SPACE_NLA, SPACE_ACTION)) {
5750 return;
5751 }
5752
5753 /* Drivers Editor needs a full redraw on playback for graph_draw_driver_debug().
5754 * This will make it slower than regular graph editor during playback, but drawing this in
5755 * graph_main_region_draw_overlay() is not feasible because it requires animation filtering
5756 * which has significant overhead which needs to be avoided in the overlay which is redrawn on
5757 * every UI interaction. */
5758 if (area->spacetype == SPACE_GRAPH) {
5759 const SpaceGraph *sipo = static_cast<const SpaceGraph *>(area->spacedata.first);
5760 if (sipo->mode != SIPO_MODE_DRIVERS) {
5761 return;
5762 }
5763 bAnimContext ac;
5764 if (ANIM_animdata_get_context(C, &ac) == false) {
5765 return;
5766 }
5767 if (ac.datatype != ANIMCONT_DRIVERS) {
5768 return;
5769 }
5770 }
5771
5772 if (area->spacetype == SPACE_SEQ) {
5774 return;
5775 }
5776 }
5777 }
5778 ED_region_tag_redraw(region);
5779}
5780
5781// #define PROFILE_AUDIO_SYNC
5782
5784 wmOperator * /*op*/,
5785 const wmEvent *event)
5786{
5787 bScreen *screen = CTX_wm_screen(C);
5788 wmTimer *wt = screen->animtimer;
5789
5790 if (!(wt && wt == event->customdata)) {
5791 return OPERATOR_PASS_THROUGH;
5792 }
5793
5794#ifdef PROFILE_AUDIO_SYNC
5795 static int old_frame = 0;
5796 int newfra_int;
5797#endif
5798
5799 Main *bmain = CTX_data_main(C);
5800 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
5801 Scene *scene = sad->scene;
5802 ViewLayer *view_layer = sad->view_layer;
5803 Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
5804 Scene *scene_eval = (depsgraph != nullptr) ? DEG_get_evaluated_scene(depsgraph) : nullptr;
5806 int sync;
5807 double time;
5808
5809 /* sync, don't sync, or follow scene setting */
5810 if (sad->flag & ANIMPLAY_FLAG_SYNC) {
5811 sync = 1;
5812 }
5813 else if (sad->flag & ANIMPLAY_FLAG_NO_SYNC) {
5814 sync = 0;
5815 }
5816 else {
5817 sync = (scene->flag & SCE_FRAME_DROP);
5818 }
5819
5820 if (scene_eval == nullptr) {
5821 /* Happens when undo/redo system is used during playback, nothing meaningful we can do here. */
5822 }
5823 else if (scene_eval->id.recalc & ID_RECALC_FRAME_CHANGE) {
5824 /* Ignore seek here, the audio will be updated to the scene frame after jump during next
5825 * dependency graph update. */
5826 }
5827 else if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
5828 isfinite(time = BKE_sound_sync_scene(scene_eval)))
5829 {
5830 scene->r.cfra = round(time * scene->frames_per_second());
5831
5832#ifdef PROFILE_AUDIO_SYNC
5833 newfra_int = scene->r.cfra;
5834 if (newfra_int < old_frame) {
5835 printf("back -%d jump detected, frame %d!\n", old_frame - newfra_int, old_frame);
5836 }
5837 else if (newfra_int > old_frame + 1) {
5838 printf("forward +%d jump detected, frame %d!\n", newfra_int - old_frame, old_frame);
5839 }
5840 fflush(stdout);
5841 old_frame = newfra_int;
5842#endif
5843 }
5844 else {
5845 if (sync) {
5846 /* Try to keep the playback in realtime by dropping frames. */
5847
5848 /* How much time (in frames) has passed since the last frame was drawn? */
5849 double delta_frames = wt->time_delta * scene->frames_per_second();
5850
5851 /* Add the remaining fraction from the last time step. */
5852 delta_frames += sad->lagging_frame_count;
5853
5854 if (delta_frames < 1.0) {
5855 /* We can render faster than the scene frame rate. However skipping or delaying frames
5856 * here seems to in practice lead to jittery playback so just step forward a minimum of
5857 * one frame. (Even though this can lead to too fast playback, the jitteriness is more
5858 * annoying)
5859 */
5860 delta_frames = 1.0f;
5861 sad->lagging_frame_count = 0;
5862 }
5863 else {
5864 /* Extract the delta frame fractions that will be skipped when converting to int. */
5865 sad->lagging_frame_count = delta_frames - int(delta_frames);
5866 }
5867
5868 const int step = delta_frames;
5869
5870 /* skip frames */
5871 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5872 scene->r.cfra -= step;
5873 }
5874 else {
5875 scene->r.cfra += step;
5876 }
5877 }
5878 else {
5879 /* one frame +/- */
5880 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5881 scene->r.cfra--;
5882 }
5883 else {
5884 scene->r.cfra++;
5885 }
5886 }
5887 }
5888
5889 /* reset 'jumped' flag before checking if we need to jump... */
5891
5892 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
5893 /* jump back to end? */
5894 if (PRVRANGEON) {
5895 if (scene->r.cfra < scene->r.psfra) {
5896 scene->r.cfra = scene->r.pefra;
5897 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5898 }
5899 }
5900 else {
5901 if (scene->r.cfra < scene->r.sfra) {
5902 scene->r.cfra = scene->r.efra;
5903 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5904 }
5905 }
5906 }
5907 else {
5908 /* jump back to start? */
5909 if (PRVRANGEON) {
5910 if (scene->r.cfra > scene->r.pefra) {
5911 scene->r.cfra = scene->r.psfra;
5912 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5913 }
5914 }
5915 else {
5916 if (scene->r.cfra > scene->r.efra) {
5917 scene->r.cfra = scene->r.sfra;
5918 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5919 }
5920 }
5921 }
5922
5923 /* next frame overridden by user action (pressed jump to first/last frame) */
5925 scene->r.cfra = sad->nextfra;
5927 sad->flag |= ANIMPLAY_FLAG_JUMPED;
5928 }
5929
5930 if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
5932#ifdef PROFILE_AUDIO_SYNC
5933 old_frame = scene->r.cfra;
5934#endif
5935 }
5936
5938
5939 /* Since we follow draw-flags, we can't send notifier but tag regions ourselves. */
5940 if (depsgraph != nullptr) {
5942
5943 /* Updating the frame, and invoking the frame pre/post hooks, can result in the current timer
5944 * being removed. For example, calling `screen.animation_cancel` inside `frame_change_post`. */
5946 return OPERATOR_FINISHED;
5947 }
5948 }
5949
5950 LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
5951 bScreen *win_screen = WM_window_get_active_screen(window);
5952
5953 LISTBASE_FOREACH (ScrArea *, area, &win_screen->areabase) {
5954 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
5955 bool redraw = false;
5956 if (region == sad->region) {
5957 redraw = true;
5958 }
5959 else if (match_region_with_redraws(area,
5960 eRegion_Type(region->regiontype),
5962 sad->from_anim_edit))
5963 {
5964 redraw = true;
5965 }
5966
5967 if (redraw) {
5969 C, area, region, scene, eScreen_Redraws_Flag(sad->redraws));
5970 /* Doesn't trigger a full redraw of the screen but makes sure at least overlay drawing
5971 * (#ARegionType.draw_overlay()) is triggered, which is how the current-frame is drawn.
5972 */
5973 win_screen->do_draw = true;
5974 }
5975 }
5976 }
5977 }
5978
5979 if (U.uiflag & USER_SHOW_FPS) {
5980 /* Update frame rate info too.
5981 * NOTE: this may not be accurate enough, since we might need this after modifiers/etc.
5982 * have been calculated instead of just before updates have been done? */
5983 ED_scene_fps_average_accumulate(scene, U.playback_fps_samples, wt->time_last);
5984 }
5985
5986 /* Recalculate the time-step for the timer now that we've finished calculating this,
5987 * since the frames-per-second value may have been changed.
5988 */
5989 /* TODO: this may make evaluation a bit slower if the value doesn't change...
5990 * any way to avoid this? */
5991 wt->time_step = (1.0 / scene->frames_per_second());
5992
5993 return OPERATOR_FINISHED;
5994}
5995
5997{
5998 /* identifiers */
5999 ot->name = "Animation Step";
6000 ot->description = "Step through animation by position";
6001 ot->idname = "SCREEN_OT_animation_step";
6002
6003 /* API callbacks. */
6005
6007}
6008
6010
6011/* -------------------------------------------------------------------- */
6016
6018{
6019 /* If sound was playing back when we changed any sound settings, we need to make sure that
6020 * we reinitialize the playback state properly. Audaspace pauses playback on re-initializing
6021 * the playback device, so we need to make sure we reinitialize the playback state on our
6022 * end as well. (Otherwise the sound device might be in a weird state and crashes Blender). */
6024 wmWindow *timer_win = nullptr;
6025 const bool is_playing = screen != nullptr;
6026 bool playback_sync = false;
6027 int play_direction = 0;
6028
6029 if (is_playing) {
6030 ScreenAnimData *sad = static_cast<ScreenAnimData *>(screen->animtimer->customdata);
6031 timer_win = screen->animtimer->win;
6032 /* -1 means play backwards. */
6033 play_direction = (sad->flag & ANIMPLAY_FLAG_REVERSE) ? -1 : 1;
6034 playback_sync = sad->flag & ANIMPLAY_FLAG_SYNC;
6035 /* Stop playback. */
6037 }
6038 Main *bmain = CTX_data_main(C);
6039 /* Re-initialize the audio device. */
6040 BKE_sound_init(bmain);
6041 if (is_playing) {
6042 /* We need to set the context window to the window that was playing back previously.
6043 * Otherwise we will attach the new playback timer to an other window.
6044 */
6045 wmWindow *win = CTX_wm_window(C);
6046 CTX_wm_window_set(C, timer_win);
6047 ED_screen_animation_play(C, playback_sync, play_direction);
6048 CTX_wm_window_set(C, win);
6049 }
6050}
6051
6053{
6054 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
6055 bScreen *screen = WM_window_get_active_screen(win);
6056
6057 if (screen->animtimer || screen->scrubbing) {
6058 return screen;
6059 }
6060 }
6061
6062 return nullptr;
6063}
6064
6066{
6067 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
6068 bScreen *screen = WM_window_get_active_screen(win);
6069
6070 if (screen->animtimer) {
6071 return screen;
6072 }
6073 }
6074
6075 return nullptr;
6076}
6077
6079{
6080 Main *bmain = CTX_data_main(C);
6082 wmTimer *wt = screen->animtimer;
6083 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
6084 Scene *scene = sad->scene;
6085
6086 ViewLayer *view_layer = sad->view_layer;
6087 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
6090
6091 /* Only stop sound playback, when playing forward, since there is no sound for reverse
6092 * playback. */
6093 if ((sad->flag & ANIMPLAY_FLAG_REVERSE) == 0) {
6094 BKE_sound_stop_scene(scene_eval);
6095 }
6096
6097 ED_screen_animation_timer(C, scene, view_layer, 0, 0, 0);
6100
6101 /* Triggers redraw of sequencer preview so that it does not show to fps anymore after stopping
6102 * playback. */
6106}
6107
6108static wmOperatorStatus start_playback(bContext *C, int sync, int mode)
6109{
6110 Main *bmain = CTX_data_main(C);
6111 bScreen *screen = CTX_wm_screen(C);
6112
6113 const bool is_sequencer = CTX_wm_space_seq(C) != nullptr;
6114 Scene *scene = is_sequencer ? CTX_data_sequencer_scene(C) : CTX_data_scene(C);
6115 if (!scene) {
6116 return OPERATOR_CANCELLED;
6117 }
6118 ViewLayer *view_layer = is_sequencer ? BKE_view_layer_default_render(scene) :
6120 Depsgraph *depsgraph = is_sequencer ? BKE_scene_ensure_depsgraph(bmain, scene, view_layer) :
6122 if (is_sequencer) {
6124 }
6126
6128
6129 /* Only play sound when playing forward. Reverse sound playback is not implemented. */
6130 if (mode == 1) {
6131 BKE_sound_play_scene(scene_eval);
6132 }
6133
6134 ED_screen_animation_timer(C, scene, view_layer, screen->redraws_flag, sync, mode);
6136
6137 if (screen->animtimer) {
6138 wmTimer *wt = screen->animtimer;
6139 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
6140
6141 sad->region = CTX_wm_region(C);
6142 }
6143
6144 return OPERATOR_FINISHED;
6145}
6146
6148{
6151 return OPERATOR_FINISHED;
6152 }
6153
6154 return start_playback(C, sync, mode);
6155}
6156
6158{
6159 int mode = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
6160 int sync = -1;
6161
6162 if (RNA_struct_property_is_set(op->ptr, "sync")) {
6163 sync = RNA_boolean_get(op->ptr, "sync");
6164 }
6165
6166 return ED_screen_animation_play(C, sync, mode);
6167}
6168
6170{
6171 PropertyRNA *prop;
6172
6173 /* identifiers */
6174 ot->name = "Play Animation";
6175 ot->description = "Play animation";
6176 ot->idname = "SCREEN_OT_animation_play";
6177
6178 /* API callbacks. */
6180
6182
6183 prop = RNA_def_boolean(
6184 ot->srna, "reverse", false, "Play in Reverse", "Animation is played backwards");
6186 prop = RNA_def_boolean(ot->srna, "sync", false, "Sync", "Drop frames to maintain framerate");
6188}
6189
6191
6192/* -------------------------------------------------------------------- */
6195
6197{
6199
6200 if (screen) {
6201 bool restore_start_frame = RNA_boolean_get(op->ptr, "restore_frame") && screen->animtimer;
6202 int frame;
6203 if (restore_start_frame) {
6204 ScreenAnimData *sad = static_cast<ScreenAnimData *>(screen->animtimer->customdata);
6205 frame = sad->sfra;
6206 }
6207
6208 /* Stop playback */
6210 if (restore_start_frame) {
6211 Scene *scene = CTX_data_scene(C);
6212 /* reset current frame and just send a notifier to deal with the rest */
6213 scene->r.cfra = frame;
6215 }
6216 }
6217
6218 return OPERATOR_PASS_THROUGH;
6219}
6220
6222{
6223 /* identifiers */
6224 ot->name = "Cancel Animation";
6225 ot->description = "Cancel animation, returning to the original frame";
6226 ot->idname = "SCREEN_OT_animation_cancel";
6227
6228 /* API callbacks. */
6230
6232
6233 RNA_def_boolean(ot->srna,
6234 "restore_frame",
6235 true,
6236 "Restore Frame",
6237 "Restore the frame when animation was initialized");
6238}
6239
6241
6242/* -------------------------------------------------------------------- */
6245
6246/* operator state vars used: (added by default WM callbacks)
6247 * xmin, ymin
6248 * xmax, ymax
6249 *
6250 * customdata: the wmGesture pointer
6251 *
6252 * callbacks:
6253 *
6254 * exec() has to be filled in by user
6255 *
6256 * invoke() default WM function
6257 * adds modal handler
6258 *
6259 * modal() default WM function
6260 * accept modal events while doing it, calls exec(), handles ESC and border drawing
6261 *
6262 * poll() has to be filled in by user for context
6263 */
6264#if 0
6266{
6267 int event_type = RNA_int_get(op->ptr, "event_type");
6268
6269 if (event_type == LEFTMOUSE) {
6270 printf("box select do select\n");
6271 }
6272 else if (event_type == RIGHTMOUSE) {
6273 printf("box select deselect\n");
6274 }
6275 else {
6276 printf("box select do something\n");
6277 }
6278
6279 return 1;
6280}
6281
6282static void SCREEN_OT_box_select(wmOperatorType *ot)
6283{
6284 /* identifiers */
6285 ot->name = "Box Select";
6286 ot->idname = "SCREEN_OT_box_select";
6287
6288 /* API callbacks. */
6289 ot->exec = box_select_exec;
6290 ot->invoke = WM_gesture_box_invoke;
6291 ot->modal = WM_gesture_box_modal;
6292 ot->cancel = WM_gesture_box_cancel;
6293
6294 ot->poll = ED_operator_areaactive;
6295
6296 /* rna */
6297 RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
6299}
6300#endif
6301
6303
6304/* -------------------------------------------------------------------- */
6309
6311{
6312 bScreen *screen = CTX_wm_screen(C);
6313 ScrArea *area = nullptr;
6314
6315 /* search current screen for 'fullscreen' areas */
6316 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
6317 if (area_iter->full) {
6318 area = area_iter;
6319 break;
6320 }
6321 }
6322 if (!area) {
6323 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
6324 return OPERATOR_CANCELLED;
6325 }
6326
6328
6329 return OPERATOR_FINISHED;
6330}
6331
6333{
6334 /* identifiers */
6335 ot->name = "Back to Previous Screen";
6336 ot->description = "Revert back to the original screen layout, before fullscreen area overlay";
6337 ot->idname = "SCREEN_OT_back_to_previous";
6338
6339 /* API callbacks. */
6340 ot->exec = fullscreen_back_exec;
6342}
6343
6345
6346/* -------------------------------------------------------------------- */
6349
6351{
6352 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "section");
6353 if (prop && RNA_property_is_set(op->ptr, prop)) {
6354 /* Set active section via RNA, so it can fail properly. */
6355
6356 PointerRNA pref_ptr = RNA_pointer_create_discrete(nullptr, &RNA_Preferences, &U);
6357 PropertyRNA *active_section_prop = RNA_struct_find_property(&pref_ptr, "active_section");
6358
6359 RNA_property_enum_set(&pref_ptr, active_section_prop, RNA_property_enum_get(op->ptr, prop));
6360 RNA_property_update(C, &pref_ptr, active_section_prop);
6361 }
6362
6363 /* changes context! */
6365 C, nullptr, SPACE_USERPREF, U.preferences_display_type, false))
6366 {
6367 /* The header only contains the editor switcher and looks empty.
6368 * So hiding in the temp window makes sense. */
6369 ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
6370
6371 region_header->flag |= RGN_FLAG_HIDDEN;
6372 ED_region_visibility_change_update(C, area, region_header);
6373
6374 return OPERATOR_FINISHED;
6375 }
6376 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
6377 return OPERATOR_CANCELLED;
6378}
6379
6381 wmOperatorType * /*ot*/,
6382 PointerRNA *ptr)
6383{
6384 PropertyRNA *prop = RNA_struct_find_property(ptr, "section");
6385 if (RNA_property_is_set(ptr, prop)) {
6386 int section = RNA_property_enum_get(ptr, prop);
6387 const char *section_name;
6388 if (RNA_property_enum_name_gettexted(C, ptr, prop, section, &section_name)) {
6389 return fmt::format(fmt::runtime(TIP_("Show {} preferences")), section_name);
6390 }
6391 }
6392 /* Fall back to default. */
6393 return "";
6394}
6395
6397{
6398 PropertyRNA *prop;
6399
6400 /* identifiers */
6401 ot->name = "Open Preferences...";
6402 ot->description = "Edit user preferences and system settings";
6403 ot->idname = "SCREEN_OT_userpref_show";
6404
6405 /* API callbacks. */
6406 ot->exec = userpref_show_exec;
6407 ot->poll = ED_operator_screenactive_nobackground; /* Not in background as this opens a window. */
6408 ot->get_description = userpref_show_get_description;
6409
6410 prop = RNA_def_enum(ot->srna,
6411 "section",
6413 0,
6414 "",
6415 "Section to activate in the Preferences");
6417}
6418
6420
6421/* -------------------------------------------------------------------- */
6424
6426{
6427 /* Get active property to show driver for
6428 * - Need to grab it first, or else this info disappears
6429 * after we've created the window
6430 */
6431 int index;
6433 PropertyRNA *prop;
6434 uiBut *but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
6435
6436 /* changes context! */
6437 if (WM_window_open_temp(C, IFACE_("Blender Drivers Editor"), SPACE_GRAPH, false)) {
6439
6440 /* activate driver F-Curve for the property under the cursor */
6441 if (but) {
6442 bool driven, special;
6444 C, &ptr, prop, index, nullptr, nullptr, &driven, &special);
6445
6446 if (fcu) {
6447 /* Isolate this F-Curve... */
6448 bAnimContext ac;
6449 if (ANIM_animdata_get_context(C, &ac)) {
6453 ac.data,
6456 fcu,
6458 }
6459 else {
6460 /* Just blindly isolate...
6461 * This isn't the best, and shouldn't happen, but may be enough. */
6463 }
6464 }
6465 }
6466
6467 return OPERATOR_FINISHED;
6468 }
6469 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
6470 return OPERATOR_CANCELLED;
6471}
6472
6474{
6475 /* identifiers */
6476 ot->name = "Show Drivers Editor";
6477 ot->description = "Show drivers editor in a separate window";
6478 ot->idname = "SCREEN_OT_drivers_editor_show";
6479
6480 /* API callbacks. */
6482 ot->poll = ED_operator_screenactive_nobackground; /* Not in background as this opens a window. */
6483}
6484
6486
6487/* -------------------------------------------------------------------- */
6490
6492{
6493 /* changes context! */
6494 if (WM_window_open_temp(C, IFACE_("Blender Info Log"), SPACE_INFO, false)) {
6495 return OPERATOR_FINISHED;
6496 }
6497 BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
6498 return OPERATOR_CANCELLED;
6499}
6500
6502{
6503 /* identifiers */
6504 ot->name = "Show Info Log";
6505 ot->description = "Show info log in a separate window";
6506 ot->idname = "SCREEN_OT_info_log_show";
6507
6508 /* API callbacks. */
6509 ot->exec = info_log_show_exec;
6511}
6512
6514
6515/* -------------------------------------------------------------------- */
6518
6520{
6521 Main *bmain = CTX_data_main(C);
6522 wmWindow *win = CTX_wm_window(C);
6525
6526 WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
6527
6529
6530 return OPERATOR_FINISHED;
6531}
6532
6534{
6535 /* identifiers */
6536 ot->name = "New Screen";
6537 ot->description = "Add a new screen";
6538 ot->idname = "SCREEN_OT_new";
6539
6540 /* API callbacks. */
6541 ot->exec = screen_new_exec;
6542 ot->poll = WM_operator_winactive;
6543}
6544
6546
6547/* -------------------------------------------------------------------- */
6550
6552{
6553 bScreen *screen = CTX_wm_screen(C);
6554 WorkSpace *workspace = CTX_wm_workspace(C);
6555 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
6556
6558
6559 return OPERATOR_FINISHED;
6560}
6561
6563{
6564 /* identifiers */
6565 ot->name = "Delete Screen";
6566 ot->description = "Delete active screen";
6567 ot->idname = "SCREEN_OT_delete";
6568
6569 /* API callbacks. */
6570 ot->exec = screen_delete_exec;
6571}
6572
6574
6575/* -------------------------------------------------------------------- */
6583
6586 ARegion *region, *child_region; /* other region */
6588};
6589
6590#define TIMEOUT 0.1f
6591#define TIMESTEP (1.0f / 60.0f)
6592
6594{
6595 /* check parent too */
6596 if (region->runtime->regiontimer == nullptr &&
6597 (region->alignment & (RGN_SPLIT_PREV | RGN_ALIGN_HIDE_WITH_PREV)) && region->prev)
6598 {
6599 region = region->prev;
6600 }
6601
6602 if (region->runtime->regiontimer) {
6603 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(
6604 region->runtime->regiontimer->customdata);
6605 float alpha;
6606
6607 alpha = float(region->runtime->regiontimer->time_duration) / TIMEOUT;
6608 /* makes sure the blend out works 100% - without area redraws */
6609 if (rgi->hidden) {
6610 alpha = 0.9f - TIMESTEP - alpha;
6611 }
6612
6613 CLAMP(alpha, 0.0f, 1.0f);
6614 return alpha;
6615 }
6616 return 1.0f;
6617}
6618
6619/* assumes region has running region-blend timer */
6620static void region_blend_end(bContext *C, ARegion *region, const bool is_running)
6621{
6622 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(region->runtime->regiontimer->customdata);
6623
6624 /* always send redraw */
6625 ED_region_tag_redraw(region);
6626 if (rgi->child_region) {
6628 }
6629
6630 /* if running timer was hiding, the flag toggle went wrong */
6631 if (is_running) {
6632 if (rgi->hidden) {
6633 rgi->region->flag &= ~RGN_FLAG_HIDDEN;
6634 }
6635 }
6636 else {
6637 if (rgi->hidden) {
6638 rgi->region->flag |= rgi->hidden;
6640 }
6641 /* area decoration needs redraw in end */
6643 }
6644 WM_event_timer_remove(CTX_wm_manager(C), nullptr, region->runtime->regiontimer); /* frees rgi */
6645 region->runtime->regiontimer = nullptr;
6646}
6648{
6650 wmWindow *win = CTX_wm_window(C);
6651
6652 /* end running timer */
6653 if (region->runtime->regiontimer) {
6654
6655 region_blend_end(C, region, true);
6656 }
6657 RegionAlphaInfo *rgi = MEM_callocN<RegionAlphaInfo>("RegionAlphaInfo");
6658
6659 rgi->hidden = region->flag & RGN_FLAG_HIDDEN;
6660 rgi->area = area;
6661 rgi->region = region;
6662 region->flag &= ~RGN_FLAG_HIDDEN;
6663
6664 /* blend in, reinitialize regions because it got unhidden */
6665 if (rgi->hidden == 0) {
6666 ED_area_init(C, win, area);
6667 }
6668 else {
6669 ED_region_visibility_change_update_ex(C, area, region, true, false);
6670 }
6671
6672 if (region->next) {
6674 rgi->child_region = region->next;
6675 }
6676 }
6677
6678 /* new timer */
6679 region->runtime->regiontimer = WM_event_timer_add(wm, win, TIMERREGION, TIMESTEP);
6680 region->runtime->regiontimer->customdata = rgi;
6681}
6682
6683/* timer runs in win->handlers, so it cannot use context to find area/region */
6685{
6686 wmTimer *timer = static_cast<wmTimer *>(event->customdata);
6687
6688 /* event type is TIMERREGION, but we better check */
6689 if (event->type != TIMERREGION || timer == nullptr) {
6690 return OPERATOR_PASS_THROUGH;
6691 }
6692
6693 RegionAlphaInfo *rgi = static_cast<RegionAlphaInfo *>(timer->customdata);
6694
6695 /* always send redraws */
6697 if (rgi->child_region) {
6699 }
6700
6701 /* end timer? */
6702 if (rgi->region->runtime->regiontimer->time_duration > double(TIMEOUT)) {
6703 region_blend_end(C, rgi->region, false);
6705 }
6706
6708}
6709
6711{
6712 /* identifiers */
6713 ot->name = "Region Alpha";
6714 ot->idname = "SCREEN_OT_region_blend";
6715 ot->description = "Blend in and out overlapping region";
6716
6717 /* API callbacks. */
6718 ot->invoke = region_blend_invoke;
6719
6720 /* flags */
6721 ot->flag = OPTYPE_INTERNAL;
6722
6723 /* properties */
6724}
6725
6727
6728/* -------------------------------------------------------------------- */
6731
6733{
6734 ScrArea *area = CTX_wm_area(C);
6735 return (area && !ELEM(area->spacetype, SPACE_TOPBAR, SPACE_STATUSBAR));
6736}
6737
6739{
6740 const int space_type = RNA_enum_get(op->ptr, "space_type");
6741
6742 ScrArea *area = CTX_wm_area(C);
6744 PropertyRNA *prop_type = RNA_struct_find_property(&ptr, "type");
6745 PropertyRNA *prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
6746
6747 if (area->spacetype != space_type) {
6748 /* Set the type. */
6749 RNA_property_enum_set(&ptr, prop_type, space_type);
6750 /* Specify that we want last-used if there are subtypes. */
6751 area->butspacetype_subtype = -1;
6752 RNA_property_update(C, &ptr, prop_type);
6753 }
6754 else {
6755 /* Types match, cycle the subtype. */
6756 const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
6757 const EnumPropertyItem *item;
6758 int item_len;
6759 bool free;
6760 RNA_property_enum_items(C, &ptr, prop_ui_type, &item, &item_len, &free);
6761 int index = RNA_enum_from_value(item, space_type_ui);
6762 for (int i = 1; i < item_len; i++) {
6763 const EnumPropertyItem *item_test = &item[(index + i) % item_len];
6764 if ((item_test->value >> 16) == space_type) {
6765 RNA_property_enum_set(&ptr, prop_ui_type, item_test->value);
6766 RNA_property_update(C, &ptr, prop_ui_type);
6767 break;
6768 }
6769 }
6770 if (free) {
6771 MEM_freeN(item);
6772 }
6773 }
6774
6775 return OPERATOR_FINISHED;
6776}
6777
6779{
6780 /* identifiers */
6781 ot->name = "Cycle Space Type Set";
6782 ot->description = "Set the space type or cycle subtype";
6783 ot->idname = "SCREEN_OT_space_type_set_or_cycle";
6784
6785 /* API callbacks. */
6788
6789 ot->flag = 0;
6790
6791 RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Type", "");
6792}
6793
6795
6796/* -------------------------------------------------------------------- */
6799
6801 {SPACE_CONTEXT_CYCLE_PREV, "PREV", 0, "Previous", ""},
6802 {SPACE_CONTEXT_CYCLE_NEXT, "NEXT", 0, "Next", ""},
6803 {0, nullptr, 0, nullptr, nullptr},
6804};
6805
6807{
6808 ScrArea *area = CTX_wm_area(C);
6809 /* area might be nullptr if called out of window bounds */
6810 return (area && ELEM(area->spacetype, SPACE_PROPERTIES, SPACE_USERPREF));
6811}
6812
6818 const ScrArea *area,
6819 PointerRNA *r_ptr,
6820 PropertyRNA **r_prop)
6821{
6822 const char *propname;
6823
6824 switch (area->spacetype) {
6825 case SPACE_PROPERTIES:
6827 &screen->id, &RNA_SpaceProperties, area->spacedata.first);
6828 propname = "context";
6829 break;
6830 case SPACE_USERPREF:
6831 *r_ptr = RNA_pointer_create_discrete(nullptr, &RNA_Preferences, &U);
6832 propname = "active_section";
6833 break;
6834 default:
6835 BLI_assert(0);
6836 propname = "";
6837 }
6838
6839 *r_prop = RNA_struct_find_property(r_ptr, propname);
6840}
6841
6843 wmOperator *op,
6844 const wmEvent * /*event*/)
6845{
6846 const eScreenCycle direction = eScreenCycle(RNA_enum_get(op->ptr, "direction"));
6847
6849 PropertyRNA *prop;
6851 const int old_context = RNA_property_enum_get(&ptr, prop);
6852 const int new_context = RNA_property_enum_step(
6853 C, &ptr, prop, old_context, direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
6854 RNA_property_enum_set(&ptr, prop, new_context);
6855 RNA_property_update(C, &ptr, prop);
6856
6857 return OPERATOR_FINISHED;
6858}
6859
6861{
6862 /* identifiers */
6863 ot->name = "Cycle Space Context";
6864 ot->description = "Cycle through the editor context by activating the next/previous one";
6865 ot->idname = "SCREEN_OT_space_context_cycle";
6866
6867 /* API callbacks. */
6870
6871 ot->flag = 0;
6872
6873 RNA_def_enum(ot->srna,
6874 "direction",
6877 "Direction",
6878 "Direction to cycle through");
6879}
6880
6882
6883/* -------------------------------------------------------------------- */
6886
6888 wmOperator *op,
6889 const wmEvent * /*event*/)
6890{
6891 wmWindow *win = CTX_wm_window(C);
6892 if (WM_window_is_temp_screen(win)) {
6893 return OPERATOR_CANCELLED;
6894 }
6895
6896 Main *bmain = CTX_data_main(C);
6897 const eScreenCycle direction = eScreenCycle(RNA_enum_get(op->ptr, "direction"));
6898 WorkSpace *workspace_src = WM_window_get_active_workspace(win);
6899
6900 Vector<ID *> ordered = BKE_id_ordered_list(&bmain->workspaces);
6901 if (ordered.size() == 1) {
6902 return OPERATOR_CANCELLED;
6903 }
6904
6905 const int index = ordered.first_index_of(&workspace_src->id);
6906
6907 WorkSpace *workspace_dst = nullptr;
6908 switch (direction) {
6910 workspace_dst = reinterpret_cast<WorkSpace *>(index == 0 ? ordered.last() :
6911 ordered[index - 1]);
6912 break;
6914 workspace_dst = reinterpret_cast<WorkSpace *>(
6915 index == ordered.index_range().last() ? ordered.first() : ordered[index + 1]);
6916 break;
6917 }
6918
6919 win->workspace_hook->temp_workspace_store = workspace_dst;
6921 win->workspace_hook->temp_workspace_store = nullptr;
6922
6923 return OPERATOR_FINISHED;
6924}
6925
6927{
6928 /* identifiers */
6929 ot->name = "Cycle Workspace";
6930 ot->description = "Cycle through workspaces";
6931 ot->idname = "SCREEN_OT_workspace_cycle";
6932
6933 /* API callbacks. */
6936
6937 ot->flag = 0;
6938
6939 RNA_def_enum(ot->srna,
6940 "direction",
6943 "Direction",
6944 "Direction to cycle through");
6945}
6946
6948
6949/* -------------------------------------------------------------------- */
6952
6954{
6955 /* Generic UI stuff. */
6960
6961 /* Screen tools. */
6988
6989 /* Frame changes. */
6995
6999
7000 /* New/delete. */
7003}
7004
7006
7007/* -------------------------------------------------------------------- */
7010
7011static void keymap_modal_set(wmKeyConfig *keyconf)
7012{
7013 static const EnumPropertyItem modal_items[] = {
7014 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
7015 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
7016 {KM_MODAL_SNAP_ON, "SNAP", 0, "Snap On", ""},
7017 {KM_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
7018 {0, nullptr, 0, nullptr, nullptr},
7019 };
7020
7021 /* Standard Modal keymap ------------------------------------------------ */
7022 wmKeyMap *keymap = WM_modalkeymap_ensure(keyconf, "Standard Modal Map", modal_items);
7023
7024 WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
7025}
7026
7027static bool blend_file_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
7028{
7029 if (drag->type == WM_DRAG_PATH) {
7032 return true;
7033 }
7034 }
7035 return false;
7036}
7037
7038static void blend_file_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
7039{
7040 /* copy drag path to properties */
7041 RNA_string_set(drop->ptr, "filepath", WM_drag_get_single_path(drag));
7042}
7043
7044static bool screen_drop_scene_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
7045{
7046 /* Make sure we're dropping the scene outside the asset browser. */
7047 SpaceFile *sfile = CTX_wm_space_file(C);
7048 if (sfile && ED_fileselect_is_asset_browser(sfile)) {
7049 return false;
7050 }
7051 return WM_drag_is_ID_type(drag, ID_SCE);
7052}
7053
7055{
7057 BLI_assert(id);
7058 RNA_int_set(drop->ptr, "session_uid", int(id->session_uid));
7059}
7060
7061static std::string screen_drop_scene_tooltip(bContext * /*C*/,
7062 wmDrag *drag,
7063 const int /*xy*/
7064 [2],
7065 wmDropBox * /*drop*/)
7066{
7067 const char *dragged_scene_name = WM_drag_get_item_name(drag);
7068 wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, ID_SCE);
7069 if (asset_drag) {
7070 switch (asset_drag->import_settings.method) {
7071 case ASSET_IMPORT_LINK:
7072 return fmt::format(fmt::runtime(TIP_("Link {}")), dragged_scene_name);
7073 case ASSET_IMPORT_PACK:
7074 return fmt::format(fmt::runtime(TIP_("Pack {}")), dragged_scene_name);
7076 return fmt::format(fmt::runtime(TIP_("Append {}")), dragged_scene_name);
7078 return fmt::format(fmt::runtime(TIP_("Append (Reuse) {}")), dragged_scene_name);
7079 }
7080 }
7081 return fmt::format(fmt::runtime(TIP_("Set {} as active")), dragged_scene_name);
7082}
7083
7085{
7086 /* Screen Editing ------------------------------------------------ */
7087 WM_keymap_ensure(keyconf, "Screen Editing", SPACE_EMPTY, RGN_TYPE_WINDOW);
7088
7089 /* Screen General ------------------------------------------------ */
7090 WM_keymap_ensure(keyconf, "Screen", SPACE_EMPTY, RGN_TYPE_WINDOW);
7091
7092 /* Anim Playback ------------------------------------------------ */
7093 WM_keymap_ensure(keyconf, "Frames", SPACE_EMPTY, RGN_TYPE_WINDOW);
7094
7095 /* dropbox for entire window */
7098 lb, "WM_OT_drop_blend_file", blend_file_drop_poll, blend_file_drop_copy, nullptr, nullptr);
7099 WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy, nullptr, nullptr);
7100 WM_dropbox_add(lb,
7101 "SCENE_OT_drop_scene_asset",
7106
7107 keymap_modal_set(keyconf);
7108}
7109
@ 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:52
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)
SpaceSeq * CTX_wm_space_seq(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)
Scene * CTX_data_sequencer_scene(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
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:204
ViewLayer * BKE_view_layer_default_render(const Scene *scene)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2523
blender::Vector< ID * > BKE_id_ordered_list(const ListBase *lb)
Definition lib_id.cc:2576
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
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2626
void BKE_scene_frame_set(Scene *scene, float frame)
Definition scene.cc:2389
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3416
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2384
Depsgraph * BKE_scene_get_depsgraph(const Scene *scene, const ViewLayer *view_layer)
Definition scene.cc:3403
void BKE_screen_remove_unused_scrverts(bScreen *screen)
Definition screen.cc:810
void BKE_screen_remove_unused_scredges(bScreen *screen)
Definition screen.cc:765
void BKE_screen_remove_double_scrverts(bScreen *screen)
Definition screen.cc:697
void BKE_spacedata_freelist(ListBase *lb)
Definition screen.cc:305
ScrEdge * BKE_screen_find_edge(const bScreen *screen, ScrVert *v1, ScrVert *v2)
Definition screen.cc:676
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:749
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
ARegion * BKE_area_region_copy(const SpaceType *st, const ARegion *region)
Definition screen.cc:350
double BKE_sound_sync_scene(struct Scene *scene)
void BKE_sound_init(struct Main *bmain)
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:429
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:614
WorkSpace * BKE_workspace_active_get(WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:563
WorkSpaceLayout * BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:587
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_kdtree_nd_ free(KDTree *tree)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
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])
int BLI_rcti_length_x(const rcti *rect, int x)
Definition rct.cc:149
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.cc:566
int BLI_rcti_length_y(const rcti *rect, int y)
Definition rct.cc:160
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#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 CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_ID_SCREEN
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
@ ID_RECALC_FRAME_CHANGE
Definition DNA_ID.h:1125
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ ID_SCE
@ ADS_FILTER_ONLYSEL
@ SACTCONT_TIMELINE
@ FCURVE_ACTIVE
@ FCURVE_SELECTED
@ ASSET_IMPORT_PACK
@ ASSET_IMPORT_LINK
@ ASSET_IMPORT_APPEND_REUSE
@ ASSET_IMPORT_APPEND
@ 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
#define PSFRA
@ AUDIO_SYNC
@ SCE_FRAME_DROP
@ SCE_KEYS_NO_SELONLY
@ SCE_TIME_JUMP_SECOND
#define PRVRANGEON
#define PEFRA
#define HEADERY
@ AREA_FLAG_REGION_SIZE_UPDATE
@ AREA_FLAG_ACTIONZONES_UPDATE
@ HEADER_NO_PULLDOWN
#define RGN_ALIGN_ENUM_FROM_MASK(align)
#define AREAMAP_FROM_SCREEN(screen)
#define AREAMINX
@ 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
@ SCREENFULL
@ SCREENMAXIMIZED
@ SCREENNORMAL
eRegion_Type
@ RGN_TYPE_TOOL_HEADER
@ RGN_TYPE_UI
@ RGN_TYPE_WINDOW
@ RGN_TYPE_PREVIEW
@ RGN_TYPE_NAV_BAR
@ RGN_TYPE_FOOTER
@ RGN_TYPE_HEADER
@ RGN_TYPE_TOOLS
@ 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 UI_SCALE_FAC
#define FRAMENUMBER_MIN_CLAMP(cfra)
@ USER_SHOW_FPS
@ V2D_IS_INIT
@ V2D_KEEPTOT_STRICT
@ V2D_SCROLL_LEFT
@ V2D_SCROLL_HORIZONTAL
@ V2D_SCROLL_TOP
@ V2D_SCROLL_RIGHT
@ V2D_SCROLL_BOTTOM
@ V2D_SCROLL_VERTICAL
@ RV3D_VIEW_AXIS_ROLL_0
@ RV3D_VIEW_CAMERA
@ RV3D_VIEW_USER
@ RV3D_WAS_CAMOB
@ RV3D_GPULIGHT_UPDATE
@ RV3D_VIEWLOCK_INIT
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_ORTHO
@ RV3D_LOCK_ROTATION
@ RV3D_BOXCLIP
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ 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)
void ED_buttons_visible_tabs_menu(bContext *C, uiLayout *layout, void *)
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:93
bool void ED_scene_fps_average_clear(Scene *scene) ATTR_NONNULL(1)
Definition scene_fps.cc:72
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
void ED_screen_global_areas_sync(wmWindow *win)
void ED_screen_animation_timer(bContext *C, Scene *scene, ViewLayer *view_layer, int redraws, int sync, int enable)
void ED_area_init(bContext *C, const wmWindow *win, ScrArea *area)
Definition area.cc:2140
bool ED_workspace_layout_cycle(WorkSpace *workspace, short direction, bContext *C) ATTR_NONNULL()
bool ED_operator_screen_mainwinactive(bContext *C)
int ED_area_max_regionsize(const ScrArea *area, const ARegion *scale_region, const AZEdge edge)
Definition area.cc:762
void ED_region_toggle_hidden(bContext *C, ARegion *region)
Definition area.cc:2373
int ED_area_global_min_size_y(const ScrArea *area)
Definition area.cc:3972
ScrArea * ED_area_find_under_cursor(const bContext *C, int spacetype, const int event_xy[2])
Definition area.cc:3988
#define ED_screen_verts_iter(win, screen, vert_name)
Definition ED_screen.hh:299
#define ED_screen_areas_iter(win, screen, area_name)
Definition ED_screen.hh:296
bool ED_operator_screenactive(bContext *C)
void ED_area_tag_redraw_no_rebuild(ScrArea *area)
Definition area.cc:702
int ED_area_global_max_size_y(const ScrArea *area)
Definition area.cc:3977
bool ED_area_is_global(const ScrArea *area)
Definition area.cc:3983
void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
Definition area.cc:2663
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:638
int ED_area_headersize()
Definition area.cc:3956
bool ED_operator_screenactive_nobackground(bContext *C)
bool ED_operator_region_view3d_active(bContext *C)
void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
Definition area.cc:2351
bool ED_operator_areaactive(bContext *C)
ScrArea * ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, short state)
void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2046
ScrArea * ED_screen_temp_space_open(bContext *C, const char *title, eSpace_Type space_type, int display_type, bool dialog) ATTR_NONNULL(1)
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1024
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:2332
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
void ED_screen_full_prevspace(bContext *C, ScrArea *area)
eScreenCycle
Definition ED_screen.hh:772
@ SPACE_CONTEXT_CYCLE_NEXT
Definition ED_screen.hh:774
@ SPACE_CONTEXT_CYCLE_PREV
Definition ED_screen.hh:773
@ AZ_SCROLL_HOR
@ AZ_SCROLL_VERT
@ 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
@ AE_LEFT_TO_TOPRIGHT
@ AE_RIGHT_TO_TOPLEFT
@ AE_BOTTOM_TO_TOPLEFT
@ AE_TOP_TO_BOTTOMRIGHT
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.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
#define UI_REGION_OVERLAP_MARGIN
#define UI_UNIT_Y
bool UI_drop_color_poll(bContext *C, wmDrag *drag, const wmEvent *event)
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
#define UI_HEADER_OFFSET
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
#define UI_AZONESPOTW_RIGHT
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)
bool UI_region_button_sections_is_inside_x(const ARegion *region, const int mval_x)
#define UI_UNIT_X
#define UI_ITEM_NONE
void UI_view2d_curRect_validate(View2D *v2d)
Definition view2d.cc:828
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:1696
#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:1691
#define V2D_SCROLL_HIDE_HEIGHT
Definition UI_view2d.hh:64
@ WIN_ALIGN_ABSOLUTE
Definition WM_api.hh:374
#define ND_SPACE_SEQUENCER
Definition WM_types.hh:535
#define NC_WINDOW
Definition WM_types.hh:375
@ KM_CTRL
Definition WM_types.hh:279
@ KM_ALT
Definition WM_types.hh:280
eWM_EventFlag
Definition WM_types.hh:671
@ KM_NOTHING
Definition WM_types.hh:310
@ KM_PRESS
Definition WM_types.hh:311
@ KM_RELEASE
Definition WM_types.hh:312
@ WM_DRAG_PATH
Definition WM_types.hh:1208
#define NC_SCREEN
Definition WM_types.hh:377
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO_GROUPED
Definition WM_types.hh:207
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_EDITED
Definition WM_types.hh:584
#define ND_FRAME
Definition WM_types.hh:434
#define ND_TRANSFORM
Definition WM_types.hh:456
#define ND_WORKSPACE_SET
Definition WM_types.hh:428
#define ND_LAYOUTBROWSE
Definition WM_types.hh:422
#define ND_SPACE_SPREADSHEET
Definition WM_types.hh:541
@ WM_TIMER_TAGGED_FOR_REMOVAL
Definition WM_types.hh:948
#define ND_LAYOUTDELETE
Definition WM_types.hh:423
#define NC_SPACE
Definition WM_types.hh:392
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)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
bool ANIM_nla_mapping_allowed(const bAnimListElem *ale)
Definition anim_draw.cc:274
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:2358
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
Definition area.cc:2378
#define U
ATTR_WARN_UNUSED_RESULT const BMVert * v2
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
bool closest(btVector3 &v)
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
nullptr float
static float is_left(const float2 &p0, const float2 &p1, const float2 &p2)
uint pos
uint col
#define filter
#define printf(...)
#define round
#define pow
#define abs
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
int count
void mask_to_keylist(bDopeSheet *, MaskLayer *masklay, AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const int saction_flag, blender::float2 range, const bool use_nla_remapping)
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)
void summary_to_keylist(bAnimContext *ac, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
AnimKeylist * ED_keylist_create()
void ED_keylist_free(AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static wmOperatorStatus box_select_exec(bContext *C, wmOperator *op)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong * next
static ulong state[N]
#define G(x, y, z)
ListBase get_editable_fcurves(bAnimContext &ac)
Object * context_active_object(const bContext *C)
bool has_playback_animation(const Scene *scene)
void sync_active_scene_and_time_with_scene_strip(bContext &C)
VecBase< int32_t, 2 > int2
Object * ED_pose_object_from_context(bContext *C)
Definition pose_edit.cc:58
const int status
#define floorf
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_discrete(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:21
const EnumPropertyItem rna_enum_space_type_items[]
Definition rna_space.cc:73
const EnumPropertyItem rna_enum_preference_section_items[]
void screen_draw_region_scale_highlight(ARegion *region)
void screen_draw_split_preview(ScrArea *area, const eScreenAxis dir_axis, const float factor)
void screen_draw_move_highlight(const wmWindow *win, bScreen *screen, eScreenAxis dir_axis, float anim_factor)
void screen_draw_dock_preview(const wmWindow *win, ScrArea *source, ScrArea *target, AreaDockTarget dock_target, float factor, int x, int y, float anim_factor)
void screen_animate_area_highlight(wmWindow *win, bScreen *screen, const rcti *rect, float inner[4], float outline[4], float seconds)
void screen_draw_join_highlight(const wmWindow *win, ScrArea *sa1, ScrArea *sa2, eScreenDir dir, float anim_factor)
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)
bool screen_area_close(bContext *C, ReportList *reports, bScreen *screen, ScrArea *area)
ScrArea * area_split(const wmWindow *win, bScreen *screen, ScrArea *area, const eScreenAxis dir_axis, const float fac, const bool merge)
int screen_area_join(bContext *C, ReportList *reports, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
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)
ScrEdge * screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map, const rcti *bounds_rect, const int mx, const int my, int safety)
int screen_geom_area_height(const ScrArea *area)
#define AREA_DOCK_FADEOUT
void SCREEN_OT_screenshot(wmOperatorType *ot)
eScreenAxis
@ SCREEN_AXIS_V
@ SCREEN_AXIS_H
#define AREA_MOVE_LINE_FADEIN
#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 AREA_SPLIT_FADEOUT
#define AZONEFADEOUT
AreaDockTarget
#define AREA_CLOSE_FADEOUT
#define AREA_JOIN_FADEOUT
#define AREA_DOCK_FADEIN
#define AREA_MOVE_LINE_FADEOUT
static bool blend_file_drop_poll(bContext *, wmDrag *drag, const wmEvent *)
static wmOperatorStatus screen_delete_exec(bContext *C, wmOperator *)
static wmOperatorStatus space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void area_join_dock_cb(const wmWindow *win, void *userdata)
static wmOperatorStatus frame_jump_delta_exec(bContext *C, wmOperator *op)
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 stop_playback(bContext *C)
static void SCREEN_OT_area_options(wmOperatorType *ot)
bool ED_operator_editarmature(bContext *C)
static void screen_drop_scene_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
static void area_dupli_fn(bScreen *, ScrArea *area, void *user_data)
static void screen_area_menu_items(ScrArea *area, uiLayout *layout)
static wmOperatorStatus area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool ed_operator_posemode_exclusive_ex(bContext *C, Object *obact)
static wmOperatorStatus space_type_set_or_cycle_exec(bContext *C, wmOperator *op)
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 bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis)
static void keymap_modal_set(wmKeyConfig *keyconf)
static void keylist_from_dopesheet(bContext &C, AnimKeylist &keylist)
static wmOperatorStatus area_split_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_region_scale(wmOperatorType *ot)
#define KM_MODAL_APPLY
Definition screen_ops.cc:93
static wmOperatorStatus area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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 wmOperatorStatus userpref_show_exec(bContext *C, wmOperator *op)
bool ED_operator_graphedit_active(bContext *C)
wmOperatorStatus ED_screen_animation_play(bContext *C, int sync, int mode)
bool ED_operator_action_active(bContext *C)
bool ED_operator_sequencer_active_editable(bContext *C)
bool ED_operator_animview_active(bContext *C)
static wmOperatorStatus repeat_history_exec(bContext *C, wmOperator *op)
bool ED_operator_node_editable(bContext *C)
static void SCREEN_OT_info_log_show(wmOperatorType *ot)
bool ED_operator_screen_mainwinactive(bContext *C)
static wmOperatorStatus area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool area_split_menu_init(bContext *C, wmOperator *op)
static wmOperatorStatus header_toggle_menus_exec(bContext *C, wmOperator *)
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)
void ED_reset_audio_device(bContext *C)
static wmOperatorStatus space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus drivers_editor_show_exec(bContext *C, wmOperator *op)
static bool keyframe_jump_poll(bContext *C)
static bool space_context_cycle_poll(bContext *C)
static void keylist_from_graph_editor(bContext &C, AnimKeylist &keylist)
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 area_move_out_draw_cb(const wmWindow *win, void *userdata)
static void SCREEN_OT_animation_play(wmOperatorType *ot)
static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *sa2)
static bool screen_drop_scene_poll(bContext *C, wmDrag *drag, const wmEvent *)
static wmOperatorStatus fullscreen_back_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_workspace_cycle(wmOperatorType *ot)
bool ED_operator_object_active_only(bContext *C)
static wmOperatorStatus start_playback(bContext *C, int sync, int mode)
#define KM_MODAL_CANCEL
Definition screen_ops.cc:92
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)
static wmOperatorStatus area_join_exec(bContext *C, wmOperator *op)
void ED_keymap_screen(wmKeyConfig *keyconf)
static bool operator_screenactive_norender(bContext *C)
static wmOperatorStatus area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus screen_context_menu_invoke(bContext *C, wmOperator *, const wmEvent *)
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)
bool ED_operator_sequencer_scene_editable(bContext *C)
static wmOperatorStatus area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void SCREEN_OT_userpref_show(wmOperatorType *ot)
bool ED_operator_editable_mesh(bContext *C)
#define TIMEOUT
static void SCREEN_OT_actionzone(wmOperatorType *ot)
static void SCREEN_OT_time_jump(wmOperatorType *ot)
static void actionzone_apply(bContext *C, wmOperator *op, int type)
void ED_areas_do_frame_follow(bContext *C, bool center_view)
bool ED_operator_scene(bContext *C)
bool ED_operator_object_active_local_editable(bContext *C)
bool ED_operator_screenactive(bContext *C)
#define KM_MODAL_SNAP_ON
Definition screen_ops.cc:94
bool ED_operator_regionactive(bContext *C)
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 wmOperatorStatus screen_animation_step_invoke(bContext *C, wmOperator *, const wmEvent *event)
static float area_docking_snap(const float pos, const wmEvent *event)
static wmOperatorStatus info_log_show_exec(bContext *C, wmOperator *op)
static void screen_area_touch_menu_create(bContext *C, ScrArea *area)
static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
static wmOperatorStatus frame_offset_exec(bContext *C, wmOperator *op)
static bool match_region_with_redraws(const ScrArea *area, eRegion_Type regiontype, eScreen_Redraws_Flag redraws, bool from_anim_edit)
static wmOperatorStatus screen_maximize_area_exec(bContext *C, wmOperator *op)
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 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 wmOperatorStatus region_blend_invoke(bContext *C, wmOperator *, const wmEvent *event)
static void SCREEN_OT_area_close(wmOperatorType *ot)
static void SCREEN_OT_redo_last(wmOperatorType *ot)
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)
static std::string screen_drop_scene_tooltip(bContext *, wmDrag *drag, const int[2], wmDropBox *)
bool ED_operator_objectmode(bContext *C)
static wmOperatorStatus area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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)
bool ED_operator_scene_editable(bContext *C)
bool ED_operator_asset_browsing_active(bContext *C)
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)
static wmOperatorStatus frame_jump_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus spacedata_cleanup_exec(bContext *C, wmOperator *op)
bool ED_operator_node_active(bContext *C)
static wmOperatorStatus region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
static wmOperatorStatus redo_last_invoke(bContext *C, wmOperator *, const wmEvent *)
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_modal_action_end()
static void SCREEN_OT_frame_offset(wmOperatorType *ot)
static wmOperatorStatus repeat_last_exec(bContext *C, wmOperator *)
static void area_docking_apply(bContext *C, wmOperator *op)
static ScrArea * screen_actionzone_area(bScreen *screen, const AZone *az)
static void area_move_draw_cb(const wmWindow *win, void *userdata)
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 wmOperatorStatus screen_new_exec(bContext *C, wmOperator *)
static void area_join_update_data(bContext *C, sAreaJoinData *jd, const wmEvent *event)
bool ED_operator_posemode_exclusive(bContext *C)
static wmOperatorStatus region_flip_exec(bContext *C, wmOperator *)
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 void region_scale_draw_cb(const wmWindow *, void *userdata)
static wmOperatorStatus repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
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 void area_swap_exit(bContext *C, wmOperator *op)
static wmOperatorStatus region_quadview_exec(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)
bool ED_operator_active_screen_and_scene(bContext *C)
void ED_region_visibility_change_update_animated(bContext *C, ScrArea *area, ARegion *region)
AZone * ED_area_azones_update(ScrArea *area, const int xy[2])
bool ED_operator_object_active_editable_mesh(bContext *C)
static wmOperatorStatus screen_set_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot)
static wmOperatorStatus actionzone_modal(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 void SCREEN_OT_new(wmOperatorType *ot)
static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
static wmOperatorStatus screen_animation_play_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:95
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)
bool ED_operator_editmesh_view3d(bContext *C)
static wmOperatorStatus area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
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 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 wmOperatorStatus actionzone_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 wmOperatorStatus area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool area_join_apply(bContext *C, wmOperator *op)
static bool is_header_azone_location(ScrArea *area, 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)
bool ED_operator_object_active_editable_ex(bContext *C, const Object *ob)
static void SCREEN_OT_area_move(wmOperatorType *ot)
static void screen_modal_action_begin()
static void SCREEN_OT_marker_jump(wmOperatorType *ot)
bool ED_operator_editlattice(bContext *C)
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 *)
static wmOperatorStatus region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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 wmOperatorStatus area_move_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem space_context_cycle_direction[]
bool ED_operator_uvedit(bContext *C)
static void keylist_fallback_for_keyframe_jump(bContext &C, Scene *scene, AnimKeylist &keylist)
static wmOperatorStatus marker_jump_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus region_toggle_exec(bContext *C, wmOperator *op)
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)
static wmOperatorStatus screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_operator_region_gizmo_active(bContext *C)
static void area_join_exit(bContext *C, wmOperator *op)
static bool area_move_init(bContext *C, wmOperator *op)
bool ED_operator_sequencer_scene(bContext *C)
static void area_move_cancel(bContext *C, wmOperator *op)
static void blend_file_drop_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static wmOperatorStatus screen_animation_cancel_exec(bContext *C, wmOperator *op)
bool ED_operator_objectmode_poll_msg(bContext *C)
static bool screen_maximize_area_poll(bContext *C)
static void SCREEN_OT_region_blend(wmOperatorType *ot)
bool ED_operator_buttons_active(bContext *C)
static void area_join_draw_cb(const wmWindow *win, void *userdata)
static ScrEdge * screen_area_edge_from_cursor(const bContext *C, const int cursor[2], ScrArea **r_sa1, ScrArea **r_sa2)
static wmOperatorStatus area_swap_exec(bContext *C, wmOperator *op)
static wmOperatorStatus keyframe_jump_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_region_toggle(wmOperatorType *ot)
static wmOperatorStatus area_close_exec(bContext *C, wmOperator *op)
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 * regiondata
struct ARegion * prev
ARegionRuntimeHandle * runtime
struct ARegion * next
float alpha
AZEdge edge
ARegion * region
AZone * next
AZScrollDirection direction
ActKeyColumn * prev
ActKeyColumn * next
eAssetImportMethod method
int totface
EditNurb * editnurb
BezTriple * bezt
Definition DNA_ID.h:414
unsigned int recalc
Definition DNA_ID.h:445
int icon_id
Definition DNA_ID.h:444
unsigned int session_uid
Definition DNA_ID.h:462
void * first
ListBase screens
Definition BKE_main.hh:292
ListBase workspaces
Definition BKE_main.hh:315
short visibility_flag
void * data
Definition RNA_types.hh:53
ARegion * child_region
wmWindow * win
ARegion * region
struct RegionView3D * localvd
float time_jump_delta
struct RenderData r
ListBase markers
struct AudioData audio
ListBase areabase
ScrVert * v2
ListBase actionzones
ScrVert * v3
ListBase spacedata
short butspacetype_subtype
struct SpaceType * type
bScreen * full
ScrVert * v1
ListBase regionbase
ScrGlobalAreaData * global
ScrVert * v4
ScrVert * v1
ScrVert * v2
ViewLayer * view_layer
struct bNodeTree * edittree
char alpha_vert
short keeptot
struct Object * camera
Wrapper for bScreen.
eAnimCont_Types datatype
ScrArea * area
short redraws_flag
ListBase vertbase
struct wmTimer * animtimer
ListBase areabase
struct ARegion * active_region
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
eScreenDir gesture_dir
wmWindow * draw_dock_win
ScrArea * sa1
eScreenAxis split_dir
wmWindow * win1
AreaDockTarget dock_target
void * draw_dock_callback
wmWindow * win2
eScreenDir dir
bScreen * screen
void * draw_callback
ScrArea * sa2
eScreenAxis dir_axis
AreaMoveSnapType snap_type
void * draw_callback
wmWindow * win
bScreen * screen
ScrEdge * nedge
ScrArea * narea
ScrArea * sarea
ScrArea * sa1
ScrArea * sa2
void operator_context_set(blender::wm::OpCallContext opcontext)
uiLayout & column(bool align)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
void menu_fn(blender::StringRefNull name, int icon, uiMenuCreateFunc func, void *arg)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
short y
short x
AssetImportSettings import_settings
Definition WM_types.hh:1244
eWM_DragDataType type
Definition WM_types.hh:1331
PointerRNA * ptr
Definition WM_types.hh:1420
wmEventModifierFlag modifier
Definition WM_types.hh:774
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int xy[2]
Definition WM_types.hh:761
void * customdata
Definition WM_types.hh:807
struct ReportList * reports
struct wmOperator * prev
struct wmOperatorType * type
struct PointerRNA * ptr
double time_delta
Definition WM_types.hh:970
wmTimerFlags flags
Definition WM_types.hh:963
void * customdata
Definition WM_types.hh:965
wmWindow * win
Definition WM_types.hh:956
double time_step
Definition WM_types.hh:959
double time_last
Definition WM_types.hh:973
WindowManagerRuntimeHandle * runtime
struct wmEvent * eventstate
ScrAreaMap global_areas
struct WorkSpaceInstanceHook * workspace_hook
i
Definition text_draw.cc:230
wmTimer * timer
void WM_operator_free_all_after(wmWindowManager *wm, wmOperator *op)
Definition wm.cc:294
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:41
@ WM_CURSOR_S_ARROW
Definition wm_cursors.hh:48
@ WM_CURSOR_Y_MOVE
Definition wm_cursors.hh:40
@ WM_CURSOR_PICK_AREA
Definition wm_cursors.hh:62
@ WM_CURSOR_MOVE
Definition wm_cursors.hh:21
@ WM_CURSOR_E_ARROW
Definition wm_cursors.hh:49
@ WM_CURSOR_EDIT
Definition wm_cursors.hh:19
@ WM_CURSOR_N_ARROW
Definition wm_cursors.hh:47
@ WM_CURSOR_STOP
Definition wm_cursors.hh:18
@ WM_CURSOR_V_SPLIT
Definition wm_cursors.hh:42
@ WM_CURSOR_SWAP_AREA
Definition wm_cursors.hh:38
@ WM_CURSOR_X_MOVE
Definition wm_cursors.hh:39
@ WM_CURSOR_W_ARROW
Definition wm_cursors.hh:50
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)
void WM_drag_free_imported_drag_ID(Main *bmain, wmDrag *drag, wmDropBox *drop)
const char * WM_drag_get_item_name(wmDrag *drag)
int WM_drag_get_path_file_type(const wmDrag *drag)
bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
const char * WM_drag_get_single_path(const wmDrag *drag)
ID * WM_drag_get_local_ID_or_import_from_asset(const bContext *C, const wmDrag *drag, int idcode)
ListBase * WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
wmDragAsset * WM_drag_get_asset_data(const wmDrag *drag, int idcode)
int xy[2]
Definition wm_draw.cc:178
void * WM_draw_cb_activate(wmWindow *win, void(*draw)(const wmWindow *win, void *customdata), void *customdata)
Definition wm_draw.cc:635
void WM_draw_cb_exit(wmWindow *win, void *handle)
Definition wm_draw.cc:648
int WM_event_drag_threshold(const wmEvent *event)
bool WM_operator_repeat_check(const bContext *, wmOperator *op)
wmOperatorStatus WM_operator_repeat_last(bContext *C, wmOperator *op)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
wmOperatorStatus WM_operator_repeat(bContext *C, wmOperator *op)
wmEvent * WM_event_add(wmWindow *win, const wmEvent *event_to_add)
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:932
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:895
void WM_operator_properties_border(wmOperatorType *ot)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
wmOperatorStatus WM_operator_redo_popup(bContext *C, wmOperator *op)
bool WM_operator_winactive(bContext *C)
wmOperator * WM_operator_last_redo(const bContext *C)
wmWindow * WM_window_open_temp(bContext *C, const char *title, int space_type, bool dialog)
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:463
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)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
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)
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:541
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
bScreen * WM_window_get_active_screen(const wmWindow *win)