diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-03-22 10:51:04 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-03-22 15:38:24 +0300 |
commit | 2d606187461dd087a8aa6a55ac92b24383ab269a (patch) | |
tree | 5ca2635905c493bb3805c9194b053bf5d292be90 /source/blender/editors/interface/interface_query.c | |
parent | c2584c1fad5140ea7507171f470d345a18ed49d5 (diff) |
UI: refactor queries into interface_query.c
interface_handlers.c is quite large (over 10k lines),
move general button utility functions into a separate file.
Diffstat (limited to 'source/blender/editors/interface/interface_query.c')
-rw-r--r-- | source/blender/editors/interface/interface_query.c | 358 |
1 files changed, 356 insertions, 2 deletions
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index ad83bce97a6..d123ac7278a 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -21,10 +21,15 @@ */ #include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_rect.h" #include "DNA_screen_types.h" #include "UI_interface.h" +#include "UI_view2d.h" + +#include "RNA_access.h" #include "interface_intern.h" @@ -32,9 +37,10 @@ #include "WM_types.h" /* -------------------------------------------------------------------- */ -/** \name Button (uiBut) +/** \name Button (#uiBut) State * \{ */ + bool ui_but_is_editable(const uiBut *but) { return !ELEM( @@ -67,6 +73,43 @@ bool ui_but_is_toggle(const uiBut *but) ); } +/** + * Can we mouse over the button or is it hidden/disabled/layout. + * \note ctrl is kind of a hack currently, + * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed. + */ +bool ui_but_is_interactive(const uiBut *but, const bool labeledit) +{ + /* note, UI_BTYPE_LABEL is included for highlights, this allows drags */ + if ((but->type == UI_BTYPE_LABEL) && but->dragpoin == NULL) + return false; + if (ELEM(but->type, UI_BTYPE_ROUNDBOX, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_LISTBOX)) + return false; + if (but->flag & UI_HIDDEN) + return false; + if (but->flag & UI_SCROLLED) + return false; + if ((but->type == UI_BTYPE_TEXT) && (but->dt == UI_EMBOSS_NONE) && !labeledit) + return false; + if ((but->type == UI_BTYPE_LISTROW) && labeledit) + return false; + + return true; +} + +/* file selectors are exempt from utf-8 checks */ +bool ui_but_is_utf8(const uiBut *but) +{ + if (but->rnaprop) { + const int subtype = RNA_property_subtype(but->rnaprop); + return !(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING)); + } + else { + return !(but->flag & UI_BUT_NO_UTF8); + } +} + + #ifdef USE_UI_POPOVER_ONCE bool ui_but_is_popover_once_compat(const uiBut *but) { @@ -77,6 +120,16 @@ bool ui_but_is_popover_once_compat(const uiBut *but) } #endif +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)); +} + + + bool UI_but_is_tool(const uiBut *but) { /* very evil! */ @@ -103,7 +156,239 @@ bool UI_but_has_tooltip_label(const uiBut *but) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Block (uiBlock) +/** \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]; + + if (block->pie_data.flags & UI_PIE_INVALID_DIR) + return false; + + ui_but_pie_dir(but->pie_dir, vec); + + if (saacos(dot_v2v2(vec, block->pie_data.pie_dir)) < angle_range) + return true; + + return false; +} + +bool ui_but_contains_pt(const uiBut *but, float mx, float my) +{ + return BLI_rctf_isect_pt(&but->rect, mx, my); +} + +bool ui_but_contains_point_px(const ARegion *ar, const uiBut *but, int x, int y) +{ + uiBlock *block = but->block; + float mx, my; + if (!ui_region_contains_point_px(ar, x, y)) + return false; + + mx = x; + my = y; + + ui_window_to_block_fl(ar, block, &mx, &my); + + 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; +} + +bool ui_but_contains_point_px_icon(const uiBut *but, ARegion *ar, const wmEvent *event) +{ + rcti rect; + int x = event->x, y = event->y; + + ui_window_to_block(ar, but->block, &x, &y); + + 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 { + int delta = BLI_rcti_size_x(&rect) - BLI_rcti_size_y(&rect); + rect.xmin += delta / 2; + rect.xmax -= delta / 2; + } + + return BLI_rcti_isect_pt(&rect, x, y); +} + +/* x and y are only used in case event is NULL... */ +uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit) +{ + uiBlock *block; + uiBut *but, *butover = NULL; + float mx, my; + +// if (!win->active) +// return NULL; + if (!ui_region_contains_point_px(ar, x, y)) + return NULL; + + for (block = ar->uiblocks.first; block; block = block->next) { + mx = x; + my = y; + ui_window_to_block_fl(ar, block, &mx, &my); + + for (but = block->buttons.last; but; but = but->prev) { + 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; + } + } + } + + /* 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; + } + } + } + + return butover; +} + +uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event) +{ + return ui_but_find_mouse_over_ex(ar, event->x, event->y, event->ctrl != 0); +} + +uiBut *ui_list_find_mouse_over_ex(ARegion *ar, int x, int y) +{ + uiBlock *block; + uiBut *but; + float mx, my; + + if (!ui_region_contains_point_px(ar, x, y)) + return NULL; + + for (block = ar->uiblocks.first; block; block = block->next) { + mx = x; + my = y; + ui_window_to_block_fl(ar, block, &mx, &my); + + for (but = block->buttons.last; but; but = but->prev) { + if (but->type == UI_BTYPE_LISTBOX && ui_but_contains_pt(but, mx, my)) { + return but; + } + } + } + + return NULL; +} + +uiBut *ui_list_find_mouse_over(ARegion *ar, const wmEvent *event) +{ + return ui_list_find_mouse_over_ex(ar, event->x, event->y); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Button (#uiBut) Relations + * \{ */ + +uiBut *ui_but_prev(uiBut *but) +{ + while (but->prev) { + but = but->prev; + if (ui_but_is_editable(but)) return but; + } + return NULL; +} + +uiBut *ui_but_next(uiBut *but) +{ + while (but->next) { + but = but->next; + if (ui_but_is_editable(but)) return but; + } + return NULL; +} + +uiBut *ui_but_first(uiBlock *block) +{ + uiBut *but; + + but = block->buttons.first; + while (but) { + if (ui_but_is_editable(but)) return but; + but = but->next; + } + return NULL; +} + +uiBut *ui_but_last(uiBlock *block) +{ + uiBut *but; + + but = block->buttons.last; + while (but) { + if (ui_but_is_editable(but)) return but; + 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_HSVCIRCLE, + UI_BTYPE_TRACK_PREVIEW, UI_BTYPE_HSVCUBE, UI_BTYPE_CURVE)) + { + return true; + } + } + + return false; +} + +bool ui_but_contains_password(const uiBut *but) +{ + return but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Block (#uiBlock) State * \{ */ bool ui_block_is_menu(const uiBlock *block) @@ -143,3 +428,72 @@ bool UI_block_is_empty(const uiBlock *block) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Region (#ARegion) State + * \{ */ + +bool ui_but_is_active(ARegion *ar) +{ + return (ui_but_find_active_in_region(ar) != NULL); +} + + +uiBut *ui_but_find_active_in_region(ARegion *ar) +{ + uiBlock *block; + uiBut *but; + + for (block = ar->uiblocks.first; block; block = block->next) + for (but = block->buttons.first; but; but = but->next) + if (but->active) + return but; + + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Region (#ARegion) State + * \{ */ + +bool ui_region_contains_point_px(const ARegion *ar, int x, int y) +{ + rcti winrct; + + /* scale down area rect to exclude shadow */ + ui_region_winrct_get_no_margin(ar, &winrct); + + /* check if the mouse is in the region */ + if (!BLI_rcti_isect_pt(&winrct, x, y)) { + for (uiBlock *block = ar->uiblocks.first; block; block = block->next) + block->auto_open = false; + + return false; + } + + /* also, check that with view2d, that the mouse is not over the scrollbars + * NOTE: care is needed here, since the mask rect may include the scrollbars + * even when they are not visible, so we need to make a copy of the mask to + * use to check + */ + if (ar->v2d.mask.xmin != ar->v2d.mask.xmax) { + const View2D *v2d = &ar->v2d; + int mx, my; + + /* convert window coordinates to region coordinates */ + mx = x; + my = y; + ui_window_to_region(ar, &mx, &my); + + /* check if in the rect */ + if (!BLI_rcti_isect_pt(&v2d->mask, mx, my) || UI_view2d_mouse_in_scrollers(ar, &ar->v2d, x, y)) { + return false; + } + } + + return true; +} + +/** \} */ |