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