Blender V4.3
area_query.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include "DNA_userdef_types.h"
12
13#include "BLI_math_base.h"
14#include "BLI_utildefines.h"
15
16#include "ED_screen.hh"
17
18#include "UI_interface.hh"
19#include "UI_view2d.hh"
20
21bool ED_region_overlap_isect_x(const ARegion *region, const int event_x)
22{
23 BLI_assert(region->overlap);
24 /* No contents, skip it. */
25 if (region->v2d.mask.xmin == region->v2d.mask.xmax) {
26 return false;
27 }
28 return BLI_rctf_isect_x(&region->v2d.tot,
29 UI_view2d_region_to_view_x(&region->v2d, event_x - region->winrct.xmin));
30}
31
32bool ED_region_overlap_isect_y(const ARegion *region, const int event_y)
33{
34 BLI_assert(region->overlap);
35 /* No contents, skip it. */
36 if (region->v2d.mask.ymin == region->v2d.mask.ymax) {
37 return false;
38 }
39 return BLI_rctf_isect_y(&region->v2d.tot,
40 UI_view2d_region_to_view_y(&region->v2d, event_y - region->winrct.ymin));
41}
42
43bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2])
44{
45 return (ED_region_overlap_isect_x(region, event_xy[0]) &&
46 ED_region_overlap_isect_y(region, event_xy[1]));
47}
48
49bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2])
50{
51 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
52 if (ED_region_is_overlap(area->spacetype, region->regiontype)) {
53 if (ED_region_overlap_isect_xy(region, event_xy)) {
54 return true;
55 }
56 }
57 }
58 return false;
59}
60
61bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter)
62{
63 *r_region_gutter = region->winrct;
64 if (UI_panel_category_is_visible(region)) {
65 const int category_tabs_width = round_fl_to_int(UI_view2d_scale_get_x(&region->v2d) *
67 const int alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
68
69 if (alignment == RGN_ALIGN_LEFT) {
70 r_region_gutter->xmax = r_region_gutter->xmin + category_tabs_width;
71 }
72 else if (alignment == RGN_ALIGN_RIGHT) {
73 r_region_gutter->xmin = r_region_gutter->xmax - category_tabs_width;
74 }
75 else {
76 BLI_assert_msg(0, "Unsupported alignment");
77 }
78 return true;
79 }
80 return false;
81}
82
83bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2])
84{
85 rcti region_gutter;
86 if (ED_region_panel_category_gutter_calc_rect(region, &region_gutter)) {
87 return BLI_rcti_isect_pt_v(&region_gutter, event_xy);
88 }
89 return false;
90}
91
93 const int event_x,
94 const int margin)
95{
96 BLI_assert(region->overlap);
97 /* No contents, skip it. */
98 if (region->v2d.mask.xmin == region->v2d.mask.xmax) {
99 return false;
100 }
101 int region_x = event_x - region->winrct.xmin;
102 return ((region->v2d.tot.xmin <= UI_view2d_region_to_view_x(&region->v2d, region_x + margin)) &&
103 (region->v2d.tot.xmax >= UI_view2d_region_to_view_x(&region->v2d, region_x - margin)));
104}
105
107 const int event_y,
108 const int margin)
109{
110 BLI_assert(region->overlap);
111 /* No contents, skip it. */
112 if (region->v2d.mask.ymin == region->v2d.mask.ymax) {
113 return false;
114 }
115 int region_y = event_y - region->winrct.ymin;
116 return ((region->v2d.tot.ymin <= UI_view2d_region_to_view_y(&region->v2d, region_y + margin)) &&
117 (region->v2d.tot.ymax >= UI_view2d_region_to_view_y(&region->v2d, region_y - margin)));
118}
119
121 const int event_xy[2],
122 const int margin)
123{
124 return (ED_region_overlap_isect_x_with_margin(region, event_xy[0], margin) &&
125 ED_region_overlap_isect_y_with_margin(region, event_xy[1], margin));
126}
127
128bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
129{
130 /* Only use the margin when inside the region. */
131 if (BLI_rcti_isect_pt_v(&region->winrct, event_xy)) {
132 if (region->overlap) {
133 const int overlap_margin = UI_REGION_OVERLAP_MARGIN;
134 /* Note the View2D.tot isn't reliable for headers with spacers otherwise
135 * we'd check #ED_region_overlap_isect_xy_with_margin for both bases. */
136 if (region->v2d.keeptot == V2D_KEEPTOT_STRICT) {
137 /* Header. */
138 rcti rect;
139 BLI_rcti_init_pt_radius(&rect, event_xy, overlap_margin);
140 if (UI_region_but_find_rect_over(region, &rect) == nullptr) {
141 return false;
142 }
143 }
144 else {
145 /* Side-bar & any other kind of overlapping region. */
146
147 const int alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
148
149 /* Check alignment to avoid region tabs being clipped out
150 * by only clipping a single axis for aligned regions. */
151 if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
152 if (!ED_region_overlap_isect_x_with_margin(region, event_xy[0], overlap_margin)) {
153 return false;
154 }
155 }
156 else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
157 if (ED_region_panel_category_gutter_isect_xy(region, event_xy)) {
158 /* pass */
159 }
160 else if (!ED_region_overlap_isect_y_with_margin(region, event_xy[1], overlap_margin)) {
161 return false;
162 }
163 }
164 else {
165 /* No panel categories for horizontal regions currently. */
166 if (!ED_region_overlap_isect_xy_with_margin(region, event_xy, overlap_margin)) {
167 return false;
168 }
169 }
170 }
171 }
172 return true;
173 }
174 return false;
175}
176
178 const int regiontype,
179 const int event_xy[2])
180{
181 if (!area) {
182 return nullptr;
183 }
184
185 /* Check overlapped regions first. */
186 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
187 if (!region->overlap) {
188 continue;
189 }
190 if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
191 if (ED_region_contains_xy(region, event_xy)) {
192 return region;
193 }
194 }
195 }
196 /* Now non-overlapping ones. */
197 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
198 if (region->overlap) {
199 continue;
200 }
201 if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
202 if (ED_region_contains_xy(region, event_xy)) {
203 return region;
204 }
205 }
206 }
207
208 return nullptr;
209}
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define LISTBASE_FOREACH(type, var, list)
MINLINE int round_fl_to_int(float a)
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
bool BLI_rctf_isect_x(const rctf *rect, float x)
Definition rct.c:93
void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size)
Definition rct.c:470
bool BLI_rctf_isect_y(const rctf *rect, float y)
Definition rct.c:104
#define ELEM(...)
#define RGN_ALIGN_ENUM_FROM_MASK(align)
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_TOP
@ RGN_ALIGN_RIGHT
#define RGN_TYPE_ANY
@ V2D_KEEPTOT_STRICT
bool ED_region_is_overlap(int spacetype, int regiontype)
Definition area.cc:1407
#define UI_REGION_OVERLAP_MARGIN
uiBut * UI_region_but_find_rect_over(const ARegion *region, const rcti *rect_px)
bool UI_panel_category_is_visible(const ARegion *region)
#define UI_PANEL_CATEGORY_MARGIN_WIDTH
float UI_view2d_region_to_view_y(const View2D *v2d, float y)
Definition view2d.cc:1657
float UI_view2d_region_to_view_x(const View2D *v2d, float x)
Definition view2d.cc:1652
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1916
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2])
Definition area_query.cc:83
ARegion * ED_area_find_region_xy_visual(const ScrArea *area, const int regiontype, const int event_xy[2])
bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2])
Definition area_query.cc:49
bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
bool ED_region_overlap_isect_x_with_margin(const ARegion *region, const int event_x, const int margin)
Definition area_query.cc:92
bool ED_region_overlap_isect_y(const ARegion *region, const int event_y)
Definition area_query.cc:32
bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2])
Definition area_query.cc:43
bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter)
Definition area_query.cc:61
bool ED_region_overlap_isect_x(const ARegion *region, const int event_x)
Definition area_query.cc:21
bool ED_region_overlap_isect_y_with_margin(const ARegion *region, const int event_y, const int margin)
bool ED_region_overlap_isect_xy_with_margin(const ARegion *region, const int event_xy[2], const int margin)
int xmin
int xmax