2018-06-30 10:36:40 +02:00
|
|
|
/*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup edinterface
|
2018-06-30 10:36:40 +02:00
|
|
|
*
|
|
|
|
|
* Utilities to inspect the interface, extract information.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-04-03 17:38:58 +02:00
|
|
|
#include "BLI_listbase.h"
|
2019-03-22 18:51:04 +11:00
|
|
|
#include "BLI_math.h"
|
|
|
|
|
#include "BLI_rect.h"
|
2021-08-19 12:49:10 +10:00
|
|
|
#include "BLI_string.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2018-06-30 10:36:40 +02:00
|
|
|
|
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
|
|
|
|
|
|
#include "UI_interface.h"
|
2019-03-22 18:51:04 +11:00
|
|
|
#include "UI_view2d.h"
|
|
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
2018-06-30 10:36:40 +02:00
|
|
|
|
|
|
|
|
#include "interface_intern.h"
|
|
|
|
|
|
2018-06-30 10:58:56 +02:00
|
|
|
#include "WM_api.h"
|
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
2018-06-30 10:36:40 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
2019-03-22 18:51:04 +11:00
|
|
|
/** \name Button (#uiBut) State
|
2018-06-30 10:36:40 +02:00
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bool ui_but_is_editable(const uiBut *but)
|
|
|
|
|
{
|
2018-07-01 19:57:31 +02:00
|
|
|
return !ELEM(but->type,
|
|
|
|
|
UI_BTYPE_LABEL,
|
|
|
|
|
UI_BTYPE_SEPR,
|
|
|
|
|
UI_BTYPE_SEPR_LINE,
|
|
|
|
|
UI_BTYPE_ROUNDBOX,
|
|
|
|
|
UI_BTYPE_LISTBOX,
|
|
|
|
|
UI_BTYPE_PROGRESS_BAR);
|
2018-06-30 10:36:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ui_but_is_editable_as_text(const uiBut *but)
|
|
|
|
|
{
|
2018-07-01 19:57:31 +02:00
|
|
|
return ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_SEARCH_MENU);
|
2018-06-30 10:36:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ui_but_is_toggle(const uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
return ELEM(but->type,
|
|
|
|
|
UI_BTYPE_BUT_TOGGLE,
|
|
|
|
|
UI_BTYPE_TOGGLE,
|
|
|
|
|
UI_BTYPE_ICON_TOGGLE,
|
|
|
|
|
UI_BTYPE_ICON_TOGGLE_N,
|
|
|
|
|
UI_BTYPE_TOGGLE_N,
|
|
|
|
|
UI_BTYPE_CHECKBOX,
|
|
|
|
|
UI_BTYPE_CHECKBOX_N,
|
2021-06-25 07:57:24 +02:00
|
|
|
UI_BTYPE_ROW,
|
2021-09-23 18:56:29 +02:00
|
|
|
UI_BTYPE_TREEROW);
|
2018-06-30 10:36:40 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
|
|
|
|
|
{
|
2021-07-03 23:08:40 +10:00
|
|
|
/* NOTE: #UI_BTYPE_LABEL is included for highlights, this allows drags. */
|
2019-03-25 10:15:20 +11:00
|
|
|
if ((but->type == UI_BTYPE_LABEL) && but->dragpoin == NULL) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if (ELEM(but->type, UI_BTYPE_ROUNDBOX, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_LISTBOX)) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if (but->flag & UI_HIDDEN) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if (but->flag & UI_SCROLLED) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2021-06-28 19:41:28 +02:00
|
|
|
if ((but->type == UI_BTYPE_TEXT) &&
|
|
|
|
|
(ELEM(but->emboss, UI_EMBOSS_NONE, UI_EMBOSS_NONE_OR_STATUS)) && !labeledit) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
if ((but->type == UI_BTYPE_LISTROW) && labeledit) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 16:19:48 +02:00
|
|
|
bool UI_but_is_utf8(const uiBut *but)
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
|
|
|
|
if (but->rnaprop) {
|
|
|
|
|
const int subtype = RNA_property_subtype(but->rnaprop);
|
|
|
|
|
return !(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING));
|
|
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
return !(but->flag & UI_BUT_NO_UTF8);
|
2019-03-22 18:51:04 +11:00
|
|
|
}
|
|
|
|
|
|
2018-06-30 10:58:56 +02:00
|
|
|
#ifdef USE_UI_POPOVER_ONCE
|
|
|
|
|
bool ui_but_is_popover_once_compat(const uiBut *but)
|
|
|
|
|
{
|
2020-08-07 14:34:11 +02:00
|
|
|
return (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_DECORATOR) || ui_but_is_toggle(but));
|
2018-06-30 10:58:56 +02:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
bool ui_but_has_array_value(const uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
return (but->rnapoin.data && but->rnaprop &&
|
|
|
|
|
ELEM(RNA_property_subtype(but->rnaprop),
|
|
|
|
|
PROP_COLOR,
|
|
|
|
|
PROP_TRANSLATION,
|
|
|
|
|
PROP_DIRECTION,
|
|
|
|
|
PROP_VELOCITY,
|
|
|
|
|
PROP_ACCELERATION,
|
|
|
|
|
PROP_MATRIX,
|
|
|
|
|
PROP_EULER,
|
|
|
|
|
PROP_QUATERNION,
|
|
|
|
|
PROP_AXISANGLE,
|
|
|
|
|
PROP_XYZ,
|
|
|
|
|
PROP_XYZ_LENGTH,
|
|
|
|
|
PROP_COLOR_GAMMA,
|
|
|
|
|
PROP_COORDS));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 01:59:31 +10:00
|
|
|
static wmOperatorType *g_ot_tool_set_by_id = NULL;
|
2018-06-30 10:58:56 +02:00
|
|
|
bool UI_but_is_tool(const uiBut *but)
|
|
|
|
|
{
|
2019-10-01 01:36:02 +10:00
|
|
|
/* very evil! */
|
|
|
|
|
if (but->optype != NULL) {
|
2019-10-01 01:59:31 +10:00
|
|
|
if (g_ot_tool_set_by_id == NULL) {
|
|
|
|
|
g_ot_tool_set_by_id = WM_operatortype_find("WM_OT_tool_set_by_id", false);
|
2019-10-01 01:36:02 +10:00
|
|
|
}
|
2019-10-01 01:59:31 +10:00
|
|
|
if (but->optype == g_ot_tool_set_by_id) {
|
2019-10-01 01:36:02 +10:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2018-06-30 10:58:56 +02:00
|
|
|
}
|
|
|
|
|
|
2018-09-05 13:52:19 +10:00
|
|
|
bool UI_but_has_tooltip_label(const uiBut *but)
|
2018-09-04 17:57:59 +10:00
|
|
|
{
|
2018-09-06 11:19:14 +10:00
|
|
|
if ((but->drawstr[0] == '\0') && !ui_block_is_popover(but->block)) {
|
2018-09-04 17:57:59 +10:00
|
|
|
return UI_but_is_tool(but);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-14 23:44:15 +10:00
|
|
|
int ui_but_icon(const uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
if (!(but->flag & UI_HAS_ICON)) {
|
|
|
|
|
return ICON_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Consecutive icons can be toggle between. */
|
|
|
|
|
if (but->drawflag & UI_BUT_ICON_REVERSE) {
|
|
|
|
|
return but->icon - but->iconadd;
|
|
|
|
|
}
|
2020-07-03 14:20:10 +02:00
|
|
|
return but->icon + but->iconadd;
|
2020-04-14 23:44:15 +10:00
|
|
|
}
|
|
|
|
|
|
2018-06-30 10:36:40 +02:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2019-03-22 18:51:04 +11:00
|
|
|
/** \name Button (#uiBut) Spatial
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
void ui_but_pie_dir(RadialDirection dir, float vec[2])
|
|
|
|
|
{
|
|
|
|
|
float angle;
|
|
|
|
|
|
|
|
|
|
BLI_assert(dir != UI_RADIAL_NONE);
|
|
|
|
|
|
|
|
|
|
angle = DEG2RADF((float)ui_radial_dir_to_angle[dir]);
|
|
|
|
|
vec[0] = cosf(angle);
|
|
|
|
|
vec[1] = sinf(angle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ui_but_isect_pie_seg(const uiBlock *block, const uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
const float angle_range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_4 :
|
|
|
|
|
M_PI_4 / 2.0;
|
|
|
|
|
float vec[2];
|
|
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (block->pie_data.flags & UI_PIE_INVALID_DIR) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
|
|
|
|
|
ui_but_pie_dir(but->pie_dir, vec);
|
|
|
|
|
|
2019-03-25 10:15:20 +11:00
|
|
|
if (saacos(dot_v2v2(vec, block->pie_data.pie_dir)) < angle_range) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return true;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ui_but_contains_pt(const uiBut *but, float mx, float my)
|
|
|
|
|
{
|
|
|
|
|
return BLI_rctf_isect_pt(&but->rect, mx, my);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-23 16:43:50 +10:00
|
|
|
bool ui_but_contains_rect(const uiBut *but, const rctf *rect)
|
|
|
|
|
{
|
|
|
|
|
return BLI_rctf_isect(&but->rect, rect, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-20 20:49:02 -03:00
|
|
|
bool ui_but_contains_point_px(const uiBut *but, const ARegion *region, const int xy[2])
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
|
|
|
|
uiBlock *block = but->block;
|
2021-10-20 20:49:02 -03:00
|
|
|
if (!ui_region_contains_point_px(region, xy)) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
|
2021-10-20 20:49:02 -03:00
|
|
|
float mx = xy[0], my = xy[1];
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_window_to_block_fl(region, block, &mx, &my);
|
2019-03-22 18:51:04 +11:00
|
|
|
|
|
|
|
|
if (but->pie_dir != UI_RADIAL_NONE) {
|
|
|
|
|
if (!ui_but_isect_pie_seg(block, but)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!ui_but_contains_pt(but, mx, my)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
bool ui_but_contains_point_px_icon(const uiBut *but, ARegion *region, const wmEvent *event)
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
|
|
|
|
rcti rect;
|
2021-10-20 23:45:30 +11:00
|
|
|
int x = event->xy[0], y = event->xy[1];
|
2019-03-22 18:51:04 +11:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_window_to_block(region, but->block, &x, &y);
|
2019-03-22 18:51:04 +11:00
|
|
|
|
|
|
|
|
BLI_rcti_rctf_copy(&rect, &but->rect);
|
|
|
|
|
|
|
|
|
|
if (but->imb || but->type == UI_BTYPE_COLOR) {
|
|
|
|
|
/* use button size itself */
|
|
|
|
|
}
|
|
|
|
|
else if (but->drawflag & UI_BUT_ICON_LEFT) {
|
|
|
|
|
rect.xmax = rect.xmin + (BLI_rcti_size_y(&rect));
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-08-26 10:11:13 +10:00
|
|
|
const int delta = BLI_rcti_size_x(&rect) - BLI_rcti_size_y(&rect);
|
2019-03-22 18:51:04 +11:00
|
|
|
rect.xmin += delta / 2;
|
|
|
|
|
rect.xmax -= delta / 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return BLI_rcti_isect_pt(&rect, x, y);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 21:46:55 +02:00
|
|
|
static uiBut *ui_but_find(const ARegion *region,
|
|
|
|
|
const uiButFindPollFn find_poll,
|
|
|
|
|
const void *find_custom_data)
|
|
|
|
|
{
|
|
|
|
|
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
|
|
|
|
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
|
|
|
|
if (find_poll && find_poll(but, find_custom_data) == false) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
return but;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-24 14:25:30 +01:00
|
|
|
uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
|
2021-10-20 20:49:02 -03:00
|
|
|
const int xy[2],
|
2021-07-09 21:46:55 +02:00
|
|
|
const bool labeledit,
|
|
|
|
|
const uiButFindPollFn find_poll,
|
|
|
|
|
const void *find_custom_data)
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
2019-04-23 17:12:09 +10:00
|
|
|
uiBut *butover = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-20 20:49:02 -03:00
|
|
|
if (!ui_region_contains_point_px(region, xy)) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return NULL;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
2021-10-20 20:49:02 -03:00
|
|
|
float mx = xy[0], my = xy[1];
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_window_to_block_fl(region, block, &mx, &my);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-18 21:46:29 -04:00
|
|
|
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
2021-07-09 21:46:55 +02:00
|
|
|
if (find_poll && find_poll(but, find_custom_data) == false) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
if (ui_but_is_interactive(but, labeledit)) {
|
|
|
|
|
if (but->pie_dir != UI_RADIAL_NONE) {
|
|
|
|
|
if (ui_but_isect_pie_seg(block, but)) {
|
|
|
|
|
butover = but;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (ui_but_contains_pt(but, mx, my)) {
|
|
|
|
|
butover = but;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
/* CLIP_EVENTS prevents the event from reaching other blocks */
|
|
|
|
|
if (block->flag & UI_BLOCK_CLIP_EVENTS) {
|
|
|
|
|
/* check if mouse is inside block */
|
|
|
|
|
if (BLI_rctf_isect_pt(&block->rect, mx, my)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
return butover;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-24 14:25:30 +01:00
|
|
|
uiBut *ui_but_find_mouse_over(const ARegion *region, const wmEvent *event)
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
2021-10-20 20:49:02 -03:00
|
|
|
return ui_but_find_mouse_over_ex(region, event->xy, event->ctrl != 0, NULL, NULL);
|
2019-03-22 18:51:04 +11:00
|
|
|
}
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)
|
2019-04-23 16:43:50 +10:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
if (!ui_region_contains_rect_px(region, rect_px)) {
|
2019-04-23 16:43:50 +10:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Currently no need to expose this at the moment. */
|
2020-08-26 10:11:13 +10:00
|
|
|
const bool labeledit = true;
|
2019-04-23 16:43:50 +10:00
|
|
|
rctf rect_px_fl;
|
|
|
|
|
BLI_rctf_rcti_copy(&rect_px_fl, rect_px);
|
|
|
|
|
uiBut *butover = NULL;
|
|
|
|
|
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
2019-04-23 16:43:50 +10:00
|
|
|
rctf rect_block;
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_window_to_block_rctf(region, block, &rect_block, &rect_px_fl);
|
2019-04-23 16:43:50 +10:00
|
|
|
|
2020-08-18 21:46:29 -04:00
|
|
|
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
2019-04-23 16:43:50 +10:00
|
|
|
if (ui_but_is_interactive(but, labeledit)) {
|
|
|
|
|
/* No pie menu support. */
|
|
|
|
|
BLI_assert(but->pie_dir == UI_RADIAL_NONE);
|
|
|
|
|
if (ui_but_contains_rect(but, &rect_block)) {
|
|
|
|
|
butover = but;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* CLIP_EVENTS prevents the event from reaching other blocks */
|
|
|
|
|
if (block->flag & UI_BLOCK_CLIP_EVENTS) {
|
|
|
|
|
/* check if mouse is inside block */
|
|
|
|
|
if (BLI_rctf_isect(&block->rect, &rect_block, NULL)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return butover;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-20 20:49:02 -03:00
|
|
|
uiBut *ui_list_find_mouse_over_ex(const ARegion *region, const int xy[2])
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
2021-10-20 20:49:02 -03:00
|
|
|
if (!ui_region_contains_point_px(region, xy)) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return NULL;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
2021-10-20 20:49:02 -03:00
|
|
|
float mx = xy[0], my = xy[1];
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_window_to_block_fl(region, block, &mx, &my);
|
2020-08-18 21:46:29 -04:00
|
|
|
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
|
2019-03-22 18:51:04 +11:00
|
|
|
if (but->type == UI_BTYPE_LISTBOX && ui_but_contains_pt(but, mx, my)) {
|
|
|
|
|
return but;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 21:46:55 +02:00
|
|
|
uiBut *ui_list_find_mouse_over(const ARegion *region, const wmEvent *event)
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
2021-07-09 21:46:55 +02:00
|
|
|
if (event == NULL) {
|
|
|
|
|
/* If there is no info about the mouse, just act as if there is nothing underneath it. */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2021-10-20 20:49:02 -03:00
|
|
|
return ui_list_find_mouse_over_ex(region, event->xy);
|
2019-03-22 18:51:04 +11:00
|
|
|
}
|
|
|
|
|
|
2021-07-09 21:46:55 +02:00
|
|
|
uiList *UI_list_find_mouse_over(const ARegion *region, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
uiBut *list_but = ui_list_find_mouse_over(region, event);
|
|
|
|
|
if (!list_but) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return list_but->custom_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ui_list_contains_row(const uiBut *listbox_but, const uiBut *listrow_but)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(listbox_but->type == UI_BTYPE_LISTBOX);
|
|
|
|
|
BLI_assert(listrow_but->type == UI_BTYPE_LISTROW);
|
|
|
|
|
/* The list box and its rows have the same RNA data (active data pointer/prop). */
|
|
|
|
|
return ui_but_rna_equals(listbox_but, listrow_but);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ui_but_is_listbox_with_row(const uiBut *but, const void *customdata)
|
|
|
|
|
{
|
|
|
|
|
const uiBut *row_but = customdata;
|
|
|
|
|
return (but->type == UI_BTYPE_LISTBOX) && ui_list_contains_row(but, row_but);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiBut *ui_list_find_from_row(const ARegion *region, const uiBut *row_but)
|
|
|
|
|
{
|
|
|
|
|
return ui_but_find(region, ui_but_is_listbox_with_row, row_but);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ui_but_is_listrow(const uiBut *but, const void *UNUSED(customdata))
|
|
|
|
|
{
|
|
|
|
|
return but->type == UI_BTYPE_LISTROW;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-20 20:49:02 -03:00
|
|
|
uiBut *ui_list_row_find_mouse_over(const ARegion *region, const int xy[2])
|
2021-07-09 21:46:55 +02:00
|
|
|
{
|
2021-10-20 20:49:02 -03:00
|
|
|
return ui_but_find_mouse_over_ex(region, xy, false, ui_but_is_listrow, NULL);
|
2021-07-09 21:46:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ListRowFindIndexData {
|
|
|
|
|
int index;
|
|
|
|
|
uiBut *listbox;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static bool ui_but_is_listrow_at_index(const uiBut *but, const void *customdata)
|
|
|
|
|
{
|
|
|
|
|
const struct ListRowFindIndexData *find_data = customdata;
|
|
|
|
|
|
|
|
|
|
return ui_but_is_listrow(but, NULL) && ui_list_contains_row(find_data->listbox, but) &&
|
|
|
|
|
(but->hardmax == find_data->index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiBut *ui_list_row_find_from_index(const ARegion *region, const int index, uiBut *listbox)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(listbox->type == UI_BTYPE_LISTBOX);
|
|
|
|
|
struct ListRowFindIndexData data = {
|
|
|
|
|
.index = index,
|
|
|
|
|
.listbox = listbox,
|
|
|
|
|
};
|
|
|
|
|
return ui_but_find(region, ui_but_is_listrow_at_index, &data);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-30 16:26:56 +02:00
|
|
|
static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata))
|
|
|
|
|
{
|
|
|
|
|
return but->type == UI_BTYPE_TREEROW;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-20 20:49:02 -03:00
|
|
|
uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2])
|
2021-09-30 16:26:56 +02:00
|
|
|
{
|
2021-10-20 20:49:02 -03:00
|
|
|
return ui_but_find_mouse_over_ex(region, xy, false, ui_but_is_treerow, NULL);
|
2021-10-08 19:56:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool ui_but_is_active_treerow(const uiBut *but, const void *customdata)
|
|
|
|
|
{
|
|
|
|
|
if (!ui_but_is_treerow(but, customdata)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const uiButTreeRow *treerow_but = (const uiButTreeRow *)but;
|
|
|
|
|
return UI_tree_view_item_is_active(treerow_but->tree_item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiBut *ui_tree_row_find_active(const ARegion *region)
|
|
|
|
|
{
|
|
|
|
|
return ui_but_find(region, ui_but_is_active_treerow, NULL);
|
2021-09-30 16:26:56 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Button (#uiBut) Relations
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
uiBut *ui_but_prev(uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
while (but->prev) {
|
|
|
|
|
but = but->prev;
|
2019-03-25 10:15:20 +11:00
|
|
|
if (ui_but_is_editable(but)) {
|
|
|
|
|
return but;
|
|
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiBut *ui_but_next(uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
while (but->next) {
|
|
|
|
|
but = but->next;
|
2019-03-25 10:15:20 +11:00
|
|
|
if (ui_but_is_editable(but)) {
|
|
|
|
|
return but;
|
|
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiBut *ui_but_first(uiBlock *block)
|
|
|
|
|
{
|
2020-08-18 21:46:29 -04:00
|
|
|
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
2019-03-25 10:15:20 +11:00
|
|
|
if (ui_but_is_editable(but)) {
|
|
|
|
|
return but;
|
|
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiBut *ui_but_last(uiBlock *block)
|
|
|
|
|
{
|
|
|
|
|
uiBut *but;
|
|
|
|
|
|
|
|
|
|
but = block->buttons.last;
|
|
|
|
|
while (but) {
|
2019-03-25 10:15:20 +11:00
|
|
|
if (ui_but_is_editable(but)) {
|
|
|
|
|
return but;
|
|
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
but = but->prev;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ui_but_is_cursor_warp(const uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
if (U.uiflag & USER_CONTINUOUS_MOUSE) {
|
|
|
|
|
if (ELEM(but->type,
|
|
|
|
|
UI_BTYPE_NUM,
|
|
|
|
|
UI_BTYPE_NUM_SLIDER,
|
|
|
|
|
UI_BTYPE_TRACK_PREVIEW,
|
|
|
|
|
UI_BTYPE_HSVCUBE,
|
2020-09-04 19:26:12 +02:00
|
|
|
UI_BTYPE_HSVCIRCLE,
|
2019-11-20 16:12:32 -05:00
|
|
|
UI_BTYPE_CURVE,
|
|
|
|
|
UI_BTYPE_CURVEPROFILE)) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ui_but_contains_password(const uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
return but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2020-11-18 15:09:34 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Button (#uiBut) Text
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
size_t ui_but_drawstr_len_without_sep_char(const uiBut *but)
|
|
|
|
|
{
|
|
|
|
|
if (but->flag & UI_BUT_HAS_SEP_CHAR) {
|
|
|
|
|
const char *str_sep = strrchr(but->drawstr, UI_SEP_CHAR);
|
|
|
|
|
if (str_sep != NULL) {
|
|
|
|
|
return (str_sep - but->drawstr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return strlen(but->drawstr);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 12:49:10 +10:00
|
|
|
size_t ui_but_drawstr_without_sep_char(const uiBut *but, char *str, size_t str_maxlen)
|
|
|
|
|
{
|
|
|
|
|
size_t str_len_clip = ui_but_drawstr_len_without_sep_char(but);
|
|
|
|
|
return BLI_strncpy_rlen(str, but->drawstr, min_zz(str_len_clip + 1, str_maxlen));
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-18 15:09:34 +11:00
|
|
|
size_t ui_but_tip_len_only_first_line(const uiBut *but)
|
|
|
|
|
{
|
2020-11-19 10:33:08 +01:00
|
|
|
if (but->tip == NULL) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-18 15:09:34 +11:00
|
|
|
const char *str_sep = strchr(but->tip, '\n');
|
|
|
|
|
if (str_sep != NULL) {
|
|
|
|
|
return (str_sep - but->tip);
|
|
|
|
|
}
|
|
|
|
|
return strlen(but->tip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Block (#uiBlock) State
|
2018-06-30 10:36:40 +02:00
|
|
|
* \{ */
|
|
|
|
|
|
2021-07-13 17:06:15 +02:00
|
|
|
uiBut *ui_block_active_but_get(const uiBlock *block)
|
|
|
|
|
{
|
|
|
|
|
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
|
|
|
|
if (but->active) {
|
|
|
|
|
return but;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-30 10:36:40 +02:00
|
|
|
bool ui_block_is_menu(const uiBlock *block)
|
|
|
|
|
{
|
|
|
|
|
return (((block->flag & UI_BLOCK_LOOP) != 0) &&
|
|
|
|
|
/* non-menu popups use keep-open, so check this is off */
|
|
|
|
|
((block->flag & UI_BLOCK_KEEP_OPEN) == 0));
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-31 10:45:35 +10:00
|
|
|
bool ui_block_is_popover(const uiBlock *block)
|
|
|
|
|
{
|
|
|
|
|
return (block->flag & UI_BLOCK_POPOVER) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-30 10:36:40 +02:00
|
|
|
bool ui_block_is_pie_menu(const uiBlock *block)
|
|
|
|
|
{
|
|
|
|
|
return ((block->flag & UI_BLOCK_RADIAL) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-31 10:37:46 +10:00
|
|
|
bool ui_block_is_popup_any(const uiBlock *block)
|
|
|
|
|
{
|
2018-07-31 10:45:35 +10:00
|
|
|
return (ui_block_is_menu(block) || ui_block_is_popover(block) || ui_block_is_pie_menu(block));
|
2018-07-31 10:37:46 +10:00
|
|
|
}
|
|
|
|
|
|
2019-09-20 19:53:17 +10:00
|
|
|
static const uiBut *ui_but_next_non_separator(const uiBut *but)
|
2018-06-30 10:36:40 +02:00
|
|
|
{
|
2019-09-20 19:53:17 +10:00
|
|
|
for (; but; but = but->next) {
|
2018-06-30 10:36:40 +02:00
|
|
|
if (!ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
|
2019-09-20 19:53:17 +10:00
|
|
|
return but;
|
2018-06-30 10:36:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-20 19:53:17 +10:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title)
|
|
|
|
|
{
|
|
|
|
|
const uiBut *but = block->buttons.first;
|
|
|
|
|
if (skip_title) {
|
|
|
|
|
/* Skip the first label, since popups often have a title,
|
|
|
|
|
* we may want to consider the block empty in this case. */
|
|
|
|
|
but = ui_but_next_non_separator(but);
|
|
|
|
|
if (but && but->type == UI_BTYPE_LABEL) {
|
|
|
|
|
but = but->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (ui_but_next_non_separator(but) == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UI_block_is_empty(const uiBlock *block)
|
|
|
|
|
{
|
|
|
|
|
return UI_block_is_empty_ex(block, false);
|
2018-06-30 10:36:40 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-25 14:40:53 +02:00
|
|
|
bool UI_block_can_add_separator(const uiBlock *block)
|
|
|
|
|
{
|
2019-04-30 12:39:05 +02:00
|
|
|
if (ui_block_is_menu(block) && !ui_block_is_pie_menu(block)) {
|
2019-04-25 14:40:53 +02:00
|
|
|
const uiBut *but = block->buttons.last;
|
|
|
|
|
return (but && !ELEM(but->type, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR));
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-30 10:36:40 +02:00
|
|
|
/** \} */
|
2019-03-22 18:51:04 +11:00
|
|
|
|
2020-03-13 01:19:22 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Block (#uiBlock) Spatial
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2021-10-20 20:49:02 -03:00
|
|
|
uiBlock *ui_block_find_mouse_over_ex(const ARegion *region, const int xy[2], bool only_clip)
|
2020-03-13 01:19:22 +11:00
|
|
|
{
|
2021-10-20 20:49:02 -03:00
|
|
|
if (!ui_region_contains_point_px(region, xy)) {
|
2020-03-13 01:19:22 +11:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
2020-03-13 01:19:22 +11:00
|
|
|
if (only_clip) {
|
|
|
|
|
if ((block->flag & UI_BLOCK_CLIP_EVENTS) == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-20 20:49:02 -03:00
|
|
|
float mx = xy[0], my = xy[1];
|
2020-03-13 01:19:22 +11:00
|
|
|
ui_window_to_block_fl(region, block, &mx, &my);
|
|
|
|
|
if (BLI_rctf_isect_pt(&block->rect, mx, my)) {
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiBlock *ui_block_find_mouse_over(const ARegion *region, const wmEvent *event, bool only_clip)
|
|
|
|
|
{
|
2021-10-20 20:49:02 -03:00
|
|
|
return ui_block_find_mouse_over_ex(region, event->xy, only_clip);
|
2020-03-13 01:19:22 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Region (#ARegion) State
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
uiBut *ui_region_find_active_but(ARegion *region)
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
2021-07-13 17:06:15 +02:00
|
|
|
uiBut *but = ui_block_active_but_get(block);
|
|
|
|
|
if (but) {
|
|
|
|
|
return but;
|
2019-03-25 10:15:20 +11:00
|
|
|
}
|
|
|
|
|
}
|
2019-03-22 18:51:04 +11:00
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
uiBut *ui_region_find_first_but_test_flag(ARegion *region, int flag_include, int flag_exclude)
|
2019-03-27 21:39:44 +11:00
|
|
|
{
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
|
|
|
|
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
2019-03-27 21:39:44 +11:00
|
|
|
if (((but->flag & flag_include) == flag_include) && ((but->flag & flag_exclude) == 0)) {
|
|
|
|
|
return but;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2019-04-23 16:43:50 +10:00
|
|
|
/** \name Region (#ARegion) Spatial
|
2019-03-22 18:51:04 +11:00
|
|
|
* \{ */
|
|
|
|
|
|
2021-10-20 20:49:02 -03:00
|
|
|
bool ui_region_contains_point_px(const ARegion *region, const int xy[2])
|
2019-03-22 18:51:04 +11:00
|
|
|
{
|
|
|
|
|
rcti winrct;
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_region_winrct_get_no_margin(region, &winrct);
|
2021-10-20 20:49:02 -03:00
|
|
|
if (!BLI_rcti_isect_pt_v(&winrct, xy)) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-06-12 09:04:10 +10:00
|
|
|
/* also, check that with view2d, that the mouse is not over the scroll-bars
|
|
|
|
|
* NOTE: care is needed here, since the mask rect may include the scroll-bars
|
2019-03-22 18:51:04 +11:00
|
|
|
* even when they are not visible, so we need to make a copy of the mask to
|
|
|
|
|
* use to check
|
|
|
|
|
*/
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->v2d.mask.xmin != region->v2d.mask.xmax) {
|
|
|
|
|
const View2D *v2d = ®ion->v2d;
|
2021-10-20 20:49:02 -03:00
|
|
|
int mx = xy[0], my = xy[1];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_window_to_region(region, &mx, &my);
|
2019-03-22 18:51:04 +11:00
|
|
|
if (!BLI_rcti_isect_pt(&v2d->mask, mx, my) ||
|
2021-10-20 20:49:02 -03:00
|
|
|
UI_view2d_mouse_in_scrollers(region, ®ion->v2d, xy)) {
|
2019-03-22 18:51:04 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
bool ui_region_contains_rect_px(const ARegion *region, const rcti *rect_px)
|
2019-04-23 16:43:50 +10:00
|
|
|
{
|
|
|
|
|
rcti winrct;
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_region_winrct_get_no_margin(region, &winrct);
|
2019-04-23 16:43:50 +10:00
|
|
|
if (!BLI_rcti_isect(&winrct, rect_px, NULL)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See comment in 'ui_region_contains_point_px' */
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->v2d.mask.xmin != region->v2d.mask.xmax) {
|
|
|
|
|
const View2D *v2d = ®ion->v2d;
|
2019-04-23 16:43:50 +10:00
|
|
|
rcti rect_region;
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_window_to_region_rcti(region, &rect_region, rect_px);
|
2019-04-23 16:43:50 +10:00
|
|
|
if (!BLI_rcti_isect(&v2d->mask, &rect_region, NULL) ||
|
2020-03-06 16:56:42 +01:00
|
|
|
UI_view2d_rect_in_scrollers(region, ®ion->v2d, rect_px)) {
|
2019-04-23 16:43:50 +10:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 18:51:04 +11:00
|
|
|
/** \} */
|
2019-07-31 19:10:44 +02:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Screen (#bScreen) Spatial
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2021-10-21 00:56:31 -04:00
|
|
|
ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, const int xy[2])
|
2019-07-31 19:10:44 +02:00
|
|
|
{
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
|
2019-07-31 19:10:44 +02:00
|
|
|
rcti winrct;
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ui_region_winrct_get_no_margin(region, &winrct);
|
2019-07-31 19:10:44 +02:00
|
|
|
|
2021-10-21 00:56:31 -04:00
|
|
|
if (BLI_rcti_isect_pt_v(&winrct, xy)) {
|
2020-03-06 16:56:42 +01:00
|
|
|
return region;
|
2019-07-31 19:10:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const wmEvent *event)
|
|
|
|
|
{
|
2021-10-21 00:56:31 -04:00
|
|
|
return ui_screen_region_find_mouse_over_ex(screen, event->xy);
|
2019-07-31 19:10:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
2019-10-01 01:59:31 +10:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Manage Internal State
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
void ui_interface_tag_script_reload_queries(void)
|
|
|
|
|
{
|
|
|
|
|
g_ot_tool_set_by_id = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|