1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup edinterface
19 *
20 * Utilities to inspect the interface, extract information.
21 */
22
23 #include "BLI_listbase.h"
24 #include "BLI_math.h"
25 #include "BLI_rect.h"
26 #include "BLI_utildefines.h"
27
28 #include "DNA_screen_types.h"
29
30 #include "UI_interface.h"
31 #include "UI_view2d.h"
32
33 #include "RNA_access.h"
34
35 #include "interface_intern.h"
36
37 #include "WM_api.h"
38 #include "WM_types.h"
39
40 /* -------------------------------------------------------------------- */
41 /** \name Button (#uiBut) State
42 * \{ */
43
ui_but_is_editable(const uiBut * but)44 bool ui_but_is_editable(const uiBut *but)
45 {
46 return !ELEM(but->type,
47 UI_BTYPE_LABEL,
48 UI_BTYPE_SEPR,
49 UI_BTYPE_SEPR_LINE,
50 UI_BTYPE_ROUNDBOX,
51 UI_BTYPE_LISTBOX,
52 UI_BTYPE_PROGRESS_BAR);
53 }
54
ui_but_is_editable_as_text(const uiBut * but)55 bool ui_but_is_editable_as_text(const uiBut *but)
56 {
57 return ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_SEARCH_MENU);
58 }
59
ui_but_is_toggle(const uiBut * but)60 bool ui_but_is_toggle(const uiBut *but)
61 {
62 return ELEM(but->type,
63 UI_BTYPE_BUT_TOGGLE,
64 UI_BTYPE_TOGGLE,
65 UI_BTYPE_ICON_TOGGLE,
66 UI_BTYPE_ICON_TOGGLE_N,
67 UI_BTYPE_TOGGLE_N,
68 UI_BTYPE_CHECKBOX,
69 UI_BTYPE_CHECKBOX_N,
70 UI_BTYPE_ROW);
71 }
72
73 /**
74 * Can we mouse over the button or is it hidden/disabled/layout.
75 * \note ctrl is kind of a hack currently,
76 * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
77 */
ui_but_is_interactive(const uiBut * but,const bool labeledit)78 bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
79 {
80 /* note, UI_BTYPE_LABEL is included for highlights, this allows drags */
81 if ((but->type == UI_BTYPE_LABEL) && but->dragpoin == NULL) {
82 return false;
83 }
84 if (ELEM(but->type, UI_BTYPE_ROUNDBOX, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_LISTBOX)) {
85 return false;
86 }
87 if (but->flag & UI_HIDDEN) {
88 return false;
89 }
90 if (but->flag & UI_SCROLLED) {
91 return false;
92 }
93 if ((but->type == UI_BTYPE_TEXT) && (but->emboss == UI_EMBOSS_NONE) && !labeledit) {
94 return false;
95 }
96 if ((but->type == UI_BTYPE_LISTROW) && labeledit) {
97 return false;
98 }
99
100 return true;
101 }
102
103 /* file selectors are exempt from utf-8 checks */
UI_but_is_utf8(const uiBut * but)104 bool UI_but_is_utf8(const uiBut *but)
105 {
106 if (but->rnaprop) {
107 const int subtype = RNA_property_subtype(but->rnaprop);
108 return !(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING));
109 }
110 return !(but->flag & UI_BUT_NO_UTF8);
111 }
112
113 #ifdef USE_UI_POPOVER_ONCE
ui_but_is_popover_once_compat(const uiBut * but)114 bool ui_but_is_popover_once_compat(const uiBut *but)
115 {
116 return (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_DECORATOR) || ui_but_is_toggle(but));
117 }
118 #endif
119
ui_but_has_array_value(const uiBut * but)120 bool ui_but_has_array_value(const uiBut *but)
121 {
122 return (but->rnapoin.data && but->rnaprop &&
123 ELEM(RNA_property_subtype(but->rnaprop),
124 PROP_COLOR,
125 PROP_TRANSLATION,
126 PROP_DIRECTION,
127 PROP_VELOCITY,
128 PROP_ACCELERATION,
129 PROP_MATRIX,
130 PROP_EULER,
131 PROP_QUATERNION,
132 PROP_AXISANGLE,
133 PROP_XYZ,
134 PROP_XYZ_LENGTH,
135 PROP_COLOR_GAMMA,
136 PROP_COORDS));
137 }
138
139 static wmOperatorType *g_ot_tool_set_by_id = NULL;
UI_but_is_tool(const uiBut * but)140 bool UI_but_is_tool(const uiBut *but)
141 {
142 /* very evil! */
143 if (but->optype != NULL) {
144 if (g_ot_tool_set_by_id == NULL) {
145 g_ot_tool_set_by_id = WM_operatortype_find("WM_OT_tool_set_by_id", false);
146 }
147 if (but->optype == g_ot_tool_set_by_id) {
148 return true;
149 }
150 }
151 return false;
152 }
153
UI_but_has_tooltip_label(const uiBut * but)154 bool UI_but_has_tooltip_label(const uiBut *but)
155 {
156 if ((but->drawstr[0] == '\0') && !ui_block_is_popover(but->block)) {
157 return UI_but_is_tool(but);
158 }
159 return false;
160 }
161
ui_but_icon(const uiBut * but)162 int ui_but_icon(const uiBut *but)
163 {
164 if (!(but->flag & UI_HAS_ICON)) {
165 return ICON_NONE;
166 }
167
168 /* Consecutive icons can be toggle between. */
169 if (but->drawflag & UI_BUT_ICON_REVERSE) {
170 return but->icon - but->iconadd;
171 }
172 return but->icon + but->iconadd;
173 }
174
175 /** \} */
176
177 /* -------------------------------------------------------------------- */
178 /** \name Button (#uiBut) Spatial
179 * \{ */
180
ui_but_pie_dir(RadialDirection dir,float vec[2])181 void ui_but_pie_dir(RadialDirection dir, float vec[2])
182 {
183 float angle;
184
185 BLI_assert(dir != UI_RADIAL_NONE);
186
187 angle = DEG2RADF((float)ui_radial_dir_to_angle[dir]);
188 vec[0] = cosf(angle);
189 vec[1] = sinf(angle);
190 }
191
ui_but_isect_pie_seg(const uiBlock * block,const uiBut * but)192 static bool ui_but_isect_pie_seg(const uiBlock *block, const uiBut *but)
193 {
194 const float angle_range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_4 :
195 M_PI_4 / 2.0;
196 float vec[2];
197
198 if (block->pie_data.flags & UI_PIE_INVALID_DIR) {
199 return false;
200 }
201
202 ui_but_pie_dir(but->pie_dir, vec);
203
204 if (saacos(dot_v2v2(vec, block->pie_data.pie_dir)) < angle_range) {
205 return true;
206 }
207
208 return false;
209 }
210
ui_but_contains_pt(const uiBut * but,float mx,float my)211 bool ui_but_contains_pt(const uiBut *but, float mx, float my)
212 {
213 return BLI_rctf_isect_pt(&but->rect, mx, my);
214 }
215
ui_but_contains_rect(const uiBut * but,const rctf * rect)216 bool ui_but_contains_rect(const uiBut *but, const rctf *rect)
217 {
218 return BLI_rctf_isect(&but->rect, rect, NULL);
219 }
220
ui_but_contains_point_px(const uiBut * but,const ARegion * region,int x,int y)221 bool ui_but_contains_point_px(const uiBut *but, const ARegion *region, int x, int y)
222 {
223 uiBlock *block = but->block;
224 if (!ui_region_contains_point_px(region, x, y)) {
225 return false;
226 }
227
228 float mx = x, my = y;
229 ui_window_to_block_fl(region, block, &mx, &my);
230
231 if (but->pie_dir != UI_RADIAL_NONE) {
232 if (!ui_but_isect_pie_seg(block, but)) {
233 return false;
234 }
235 }
236 else if (!ui_but_contains_pt(but, mx, my)) {
237 return false;
238 }
239
240 return true;
241 }
242
ui_but_contains_point_px_icon(const uiBut * but,ARegion * region,const wmEvent * event)243 bool ui_but_contains_point_px_icon(const uiBut *but, ARegion *region, const wmEvent *event)
244 {
245 rcti rect;
246 int x = event->x, y = event->y;
247
248 ui_window_to_block(region, but->block, &x, &y);
249
250 BLI_rcti_rctf_copy(&rect, &but->rect);
251
252 if (but->imb || but->type == UI_BTYPE_COLOR) {
253 /* use button size itself */
254 }
255 else if (but->drawflag & UI_BUT_ICON_LEFT) {
256 rect.xmax = rect.xmin + (BLI_rcti_size_y(&rect));
257 }
258 else {
259 const int delta = BLI_rcti_size_x(&rect) - BLI_rcti_size_y(&rect);
260 rect.xmin += delta / 2;
261 rect.xmax -= delta / 2;
262 }
263
264 return BLI_rcti_isect_pt(&rect, x, y);
265 }
266
267 /* x and y are only used in case event is NULL... */
ui_but_find_mouse_over_ex(ARegion * region,const int x,const int y,const bool labeledit)268 uiBut *ui_but_find_mouse_over_ex(ARegion *region, const int x, const int y, const bool labeledit)
269 {
270 uiBut *butover = NULL;
271
272 if (!ui_region_contains_point_px(region, x, y)) {
273 return NULL;
274 }
275 LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
276 float mx = x, my = y;
277 ui_window_to_block_fl(region, block, &mx, &my);
278
279 LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
280 if (ui_but_is_interactive(but, labeledit)) {
281 if (but->pie_dir != UI_RADIAL_NONE) {
282 if (ui_but_isect_pie_seg(block, but)) {
283 butover = but;
284 break;
285 }
286 }
287 else if (ui_but_contains_pt(but, mx, my)) {
288 butover = but;
289 break;
290 }
291 }
292 }
293
294 /* CLIP_EVENTS prevents the event from reaching other blocks */
295 if (block->flag & UI_BLOCK_CLIP_EVENTS) {
296 /* check if mouse is inside block */
297 if (BLI_rctf_isect_pt(&block->rect, mx, my)) {
298 break;
299 }
300 }
301 }
302
303 return butover;
304 }
305
ui_but_find_mouse_over(ARegion * region,const wmEvent * event)306 uiBut *ui_but_find_mouse_over(ARegion *region, const wmEvent *event)
307 {
308 return ui_but_find_mouse_over_ex(region, event->x, event->y, event->ctrl != 0);
309 }
310
ui_but_find_rect_over(const struct ARegion * region,const rcti * rect_px)311 uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)
312 {
313 if (!ui_region_contains_rect_px(region, rect_px)) {
314 return NULL;
315 }
316
317 /* Currently no need to expose this at the moment. */
318 const bool labeledit = true;
319 rctf rect_px_fl;
320 BLI_rctf_rcti_copy(&rect_px_fl, rect_px);
321 uiBut *butover = NULL;
322
323 LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
324 rctf rect_block;
325 ui_window_to_block_rctf(region, block, &rect_block, &rect_px_fl);
326
327 LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
328 if (ui_but_is_interactive(but, labeledit)) {
329 /* No pie menu support. */
330 BLI_assert(but->pie_dir == UI_RADIAL_NONE);
331 if (ui_but_contains_rect(but, &rect_block)) {
332 butover = but;
333 break;
334 }
335 }
336 }
337
338 /* CLIP_EVENTS prevents the event from reaching other blocks */
339 if (block->flag & UI_BLOCK_CLIP_EVENTS) {
340 /* check if mouse is inside block */
341 if (BLI_rctf_isect(&block->rect, &rect_block, NULL)) {
342 break;
343 }
344 }
345 }
346 return butover;
347 }
348
ui_list_find_mouse_over_ex(ARegion * region,int x,int y)349 uiBut *ui_list_find_mouse_over_ex(ARegion *region, int x, int y)
350 {
351 if (!ui_region_contains_point_px(region, x, y)) {
352 return NULL;
353 }
354 LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
355 float mx = x, my = y;
356 ui_window_to_block_fl(region, block, &mx, &my);
357 LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
358 if (but->type == UI_BTYPE_LISTBOX && ui_but_contains_pt(but, mx, my)) {
359 return but;
360 }
361 }
362 }
363
364 return NULL;
365 }
366
ui_list_find_mouse_over(ARegion * region,const wmEvent * event)367 uiBut *ui_list_find_mouse_over(ARegion *region, const wmEvent *event)
368 {
369 return ui_list_find_mouse_over_ex(region, event->x, event->y);
370 }
371
372 /** \} */
373
374 /* -------------------------------------------------------------------- */
375 /** \name Button (#uiBut) Relations
376 * \{ */
377
ui_but_prev(uiBut * but)378 uiBut *ui_but_prev(uiBut *but)
379 {
380 while (but->prev) {
381 but = but->prev;
382 if (ui_but_is_editable(but)) {
383 return but;
384 }
385 }
386 return NULL;
387 }
388
ui_but_next(uiBut * but)389 uiBut *ui_but_next(uiBut *but)
390 {
391 while (but->next) {
392 but = but->next;
393 if (ui_but_is_editable(but)) {
394 return but;
395 }
396 }
397 return NULL;
398 }
399
ui_but_first(uiBlock * block)400 uiBut *ui_but_first(uiBlock *block)
401 {
402 LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
403 if (ui_but_is_editable(but)) {
404 return but;
405 }
406 }
407 return NULL;
408 }
409
ui_but_last(uiBlock * block)410 uiBut *ui_but_last(uiBlock *block)
411 {
412 uiBut *but;
413
414 but = block->buttons.last;
415 while (but) {
416 if (ui_but_is_editable(but)) {
417 return but;
418 }
419 but = but->prev;
420 }
421 return NULL;
422 }
423
ui_but_is_cursor_warp(const uiBut * but)424 bool ui_but_is_cursor_warp(const uiBut *but)
425 {
426 if (U.uiflag & USER_CONTINUOUS_MOUSE) {
427 if (ELEM(but->type,
428 UI_BTYPE_NUM,
429 UI_BTYPE_NUM_SLIDER,
430 UI_BTYPE_TRACK_PREVIEW,
431 UI_BTYPE_HSVCUBE,
432 UI_BTYPE_HSVCIRCLE,
433 UI_BTYPE_CURVE,
434 UI_BTYPE_CURVEPROFILE)) {
435 return true;
436 }
437 }
438
439 return false;
440 }
441
ui_but_contains_password(const uiBut * but)442 bool ui_but_contains_password(const uiBut *but)
443 {
444 return but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD);
445 }
446
447 /** \} */
448
449 /* -------------------------------------------------------------------- */
450 /** \name Button (#uiBut) Text
451 * \{ */
452
ui_but_drawstr_len_without_sep_char(const uiBut * but)453 size_t ui_but_drawstr_len_without_sep_char(const uiBut *but)
454 {
455 if (but->flag & UI_BUT_HAS_SEP_CHAR) {
456 const char *str_sep = strrchr(but->drawstr, UI_SEP_CHAR);
457 if (str_sep != NULL) {
458 return (str_sep - but->drawstr);
459 }
460 }
461 return strlen(but->drawstr);
462 }
463
ui_but_tip_len_only_first_line(const uiBut * but)464 size_t ui_but_tip_len_only_first_line(const uiBut *but)
465 {
466 if (but->tip == NULL) {
467 return 0;
468 }
469
470 const char *str_sep = strchr(but->tip, '\n');
471 if (str_sep != NULL) {
472 return (str_sep - but->tip);
473 }
474 return strlen(but->tip);
475 }
476
477 /** \} */
478
479 /* -------------------------------------------------------------------- */
480 /** \name Block (#uiBlock) State
481 * \{ */
482
ui_block_is_menu(const uiBlock * block)483 bool ui_block_is_menu(const uiBlock *block)
484 {
485 return (((block->flag & UI_BLOCK_LOOP) != 0) &&
486 /* non-menu popups use keep-open, so check this is off */
487 ((block->flag & UI_BLOCK_KEEP_OPEN) == 0));
488 }
489
ui_block_is_popover(const uiBlock * block)490 bool ui_block_is_popover(const uiBlock *block)
491 {
492 return (block->flag & UI_BLOCK_POPOVER) != 0;
493 }
494
ui_block_is_pie_menu(const uiBlock * block)495 bool ui_block_is_pie_menu(const uiBlock *block)
496 {
497 return ((block->flag & UI_BLOCK_RADIAL) != 0);
498 }
499
ui_block_is_popup_any(const uiBlock * block)500 bool ui_block_is_popup_any(const uiBlock *block)
501 {
502 return (ui_block_is_menu(block) || ui_block_is_popover(block) || ui_block_is_pie_menu(block));
503 }
504
ui_but_next_non_separator(const uiBut * but)505 static const uiBut *ui_but_next_non_separator(const uiBut *but)
506 {
507 for (; but; but = but->next) {
508 if (!ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
509 return but;
510 }
511 }
512 return NULL;
513 }
514
UI_block_is_empty_ex(const uiBlock * block,const bool skip_title)515 bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title)
516 {
517 const uiBut *but = block->buttons.first;
518 if (skip_title) {
519 /* Skip the first label, since popups often have a title,
520 * we may want to consider the block empty in this case. */
521 but = ui_but_next_non_separator(but);
522 if (but && but->type == UI_BTYPE_LABEL) {
523 but = but->next;
524 }
525 }
526 return (ui_but_next_non_separator(but) == NULL);
527 }
528
UI_block_is_empty(const uiBlock * block)529 bool UI_block_is_empty(const uiBlock *block)
530 {
531 return UI_block_is_empty_ex(block, false);
532 }
533
UI_block_can_add_separator(const uiBlock * block)534 bool UI_block_can_add_separator(const uiBlock *block)
535 {
536 if (ui_block_is_menu(block) && !ui_block_is_pie_menu(block)) {
537 const uiBut *but = block->buttons.last;
538 return (but && !ELEM(but->type, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR));
539 }
540 return true;
541 }
542
543 /** \} */
544
545 /* -------------------------------------------------------------------- */
546 /** \name Block (#uiBlock) Spatial
547 * \{ */
548
ui_block_find_mouse_over_ex(const ARegion * region,const int x,const int y,bool only_clip)549 uiBlock *ui_block_find_mouse_over_ex(const ARegion *region,
550 const int x,
551 const int y,
552 bool only_clip)
553 {
554 if (!ui_region_contains_point_px(region, x, y)) {
555 return NULL;
556 }
557 LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
558 if (only_clip) {
559 if ((block->flag & UI_BLOCK_CLIP_EVENTS) == 0) {
560 continue;
561 }
562 }
563 float mx = x, my = y;
564 ui_window_to_block_fl(region, block, &mx, &my);
565 if (BLI_rctf_isect_pt(&block->rect, mx, my)) {
566 return block;
567 }
568 }
569 return NULL;
570 }
571
ui_block_find_mouse_over(const ARegion * region,const wmEvent * event,bool only_clip)572 uiBlock *ui_block_find_mouse_over(const ARegion *region, const wmEvent *event, bool only_clip)
573 {
574 return ui_block_find_mouse_over_ex(region, event->x, event->y, only_clip);
575 }
576
577 /** \} */
578
579 /* -------------------------------------------------------------------- */
580 /** \name Region (#ARegion) State
581 * \{ */
582
ui_region_find_active_but(ARegion * region)583 uiBut *ui_region_find_active_but(ARegion *region)
584 {
585 LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
586 LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
587 if (but->active) {
588 return but;
589 }
590 }
591 }
592
593 return NULL;
594 }
595
ui_region_find_first_but_test_flag(ARegion * region,int flag_include,int flag_exclude)596 uiBut *ui_region_find_first_but_test_flag(ARegion *region, int flag_include, int flag_exclude)
597 {
598 LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
599 LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
600 if (((but->flag & flag_include) == flag_include) && ((but->flag & flag_exclude) == 0)) {
601 return but;
602 }
603 }
604 }
605
606 return NULL;
607 }
608
609 /** \} */
610
611 /* -------------------------------------------------------------------- */
612 /** \name Region (#ARegion) Spatial
613 * \{ */
614
ui_region_contains_point_px(const ARegion * region,int x,int y)615 bool ui_region_contains_point_px(const ARegion *region, int x, int y)
616 {
617 rcti winrct;
618 ui_region_winrct_get_no_margin(region, &winrct);
619 if (!BLI_rcti_isect_pt(&winrct, x, y)) {
620 return false;
621 }
622
623 /* also, check that with view2d, that the mouse is not over the scroll-bars
624 * NOTE: care is needed here, since the mask rect may include the scroll-bars
625 * even when they are not visible, so we need to make a copy of the mask to
626 * use to check
627 */
628 if (region->v2d.mask.xmin != region->v2d.mask.xmax) {
629 const View2D *v2d = ®ion->v2d;
630 int mx = x, my = y;
631
632 ui_window_to_region(region, &mx, &my);
633 if (!BLI_rcti_isect_pt(&v2d->mask, mx, my) ||
634 UI_view2d_mouse_in_scrollers(region, ®ion->v2d, x, y)) {
635 return false;
636 }
637 }
638
639 return true;
640 }
641
ui_region_contains_rect_px(const ARegion * region,const rcti * rect_px)642 bool ui_region_contains_rect_px(const ARegion *region, const rcti *rect_px)
643 {
644 rcti winrct;
645 ui_region_winrct_get_no_margin(region, &winrct);
646 if (!BLI_rcti_isect(&winrct, rect_px, NULL)) {
647 return false;
648 }
649
650 /* See comment in 'ui_region_contains_point_px' */
651 if (region->v2d.mask.xmin != region->v2d.mask.xmax) {
652 const View2D *v2d = ®ion->v2d;
653 rcti rect_region;
654 ui_window_to_region_rcti(region, &rect_region, rect_px);
655 if (!BLI_rcti_isect(&v2d->mask, &rect_region, NULL) ||
656 UI_view2d_rect_in_scrollers(region, ®ion->v2d, rect_px)) {
657 return false;
658 }
659 }
660
661 return true;
662 }
663
664 /** \} */
665
666 /* -------------------------------------------------------------------- */
667 /** \name Screen (#bScreen) Spatial
668 * \{ */
669
670 /** Check if the cursor is over any popups. */
ui_screen_region_find_mouse_over_ex(bScreen * screen,int x,int y)671 ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, int x, int y)
672 {
673 LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
674 rcti winrct;
675
676 ui_region_winrct_get_no_margin(region, &winrct);
677
678 if (BLI_rcti_isect_pt(&winrct, x, y)) {
679 return region;
680 }
681 }
682 return NULL;
683 }
684
ui_screen_region_find_mouse_over(bScreen * screen,const wmEvent * event)685 ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const wmEvent *event)
686 {
687 return ui_screen_region_find_mouse_over_ex(screen, event->x, event->y);
688 }
689
690 /** \} */
691
692 /* -------------------------------------------------------------------- */
693 /** \name Manage Internal State
694 * \{ */
695
ui_interface_tag_script_reload_queries(void)696 void ui_interface_tag_script_reload_queries(void)
697 {
698 g_ot_tool_set_by_id = NULL;
699 }
700
701 /** \} */
702