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