UI: refactor queries into interface_query.c
authorCampbell Barton <ideasman42@gmail.com>
Fri, 22 Mar 2019 07:51:04 +0000 (18:51 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 22 Mar 2019 12:38:24 +0000 (23:38 +1100)
interface_handlers.c is quite large (over 10k lines),
move general button utility functions into a separate file.

source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_query.c

index ed0a919..a8e4d17 100644 (file)
@@ -391,12 +391,6 @@ typedef struct uiAfterFunc {
 } uiAfterFunc;
 
 
-static bool ui_but_is_interactive(const uiBut *but, const bool labeledit);
-static bool ui_but_contains_pt(const uiBut *but, float mx, float my);
-static bool ui_but_contains_point_px(ARegion *ar, const uiBut *but, int x, int y);
-static bool ui_but_contains_point_px_icon(const uiBut *but, ARegion *ar, const wmEvent *event);
-static bool ui_region_contains_point_px(const ARegion *ar, int x, int y);
-static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit);
 static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
 static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state);
 static void button_activate_exit(
@@ -422,200 +416,10 @@ static bool but_copypaste_curve_alive = false;
 /** \name UI Queries
  * \{ */
 
-void ui_but_pie_dir(RadialDirection dir, float vec[2])
+bool ui_but_is_editing(const uiBut *but)
 {
-       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;
-}
-
-static bool ui_but_contains_pt(const uiBut *but, float mx, float my)
-{
-       return BLI_rctf_isect_pt(&but->rect, mx, my);
-}
-
-static bool ui_but_contains_point_px(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;
-}
-
-static 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);
-}
-
-static 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;
-}
-
-/* x and y are only used in case event is NULL... */
-static 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);
-}
-
-static 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;
-}
-
-static uiBut *ui_list_find_mouse_over(ARegion *ar, const wmEvent *event)
-{
-       return ui_list_find_mouse_over_ex(ar, event->x, event->y);
+       uiHandleButtonData *data = but->active;
+       return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING));
 }
 
 /* assumes event type is MOUSEPAN */
@@ -651,91 +455,6 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
        }
 }
 
-static uiBut *ui_but_prev(uiBut *but)
-{
-       while (but->prev) {
-               but = but->prev;
-               if (ui_but_is_editable(but)) return but;
-       }
-       return NULL;
-}
-
-static uiBut *ui_but_next(uiBut *but)
-{
-       while (but->next) {
-               but = but->next;
-               if (ui_but_is_editable(but)) return but;
-       }
-       return NULL;
-}
-
-static 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;
-}
-
-static 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;
-}
-
-static 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;
-}
-
-static bool ui_but_contains_password(const uiBut *but)
-{
-       return but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD);
-}
-
-/**
- * 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.
- */
-static 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;
-}
-
 static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b)
 {
        return ((but_a->type == but_b->type) &&
@@ -775,30 +494,6 @@ uiBut *ui_but_find_select_in_enum(uiBut *but, int direction)
        return but_found;
 }
 
-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;
-}
-
-bool ui_but_is_active(ARegion *ar)
-{
-       return (ui_but_find_active_in_region(ar) != NULL);
-}
-
-bool ui_but_is_editing(uiBut *but)
-{
-       uiHandleButtonData *data = but->active;
-       return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING));
-}
-
 static float ui_mouse_scale_warp_factor(const bool shift)
 {
        return shift ? 0.05f : 1.0f;
@@ -815,18 +510,6 @@ static void ui_mouse_scale_warp(
        *r_my = (data->dragstarty * (1.0f - fac) + my * fac);
 }
 
-/* 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);
-       }
-}
-
 /** \} */
 
 /* -------------------------------------------------------------------- */
@@ -2521,14 +2204,6 @@ static void ui_but_paste_numeric_value(bContext *C, uiBut *but, uiHandleButtonDa
        }
 }
 
-static bool ui_but_has_array_value(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));
-}
-
 static void ui_but_paste_normalized_vector(bContext *C, uiBut *but, char *buf_paste)
 {
        float xyz[3];
index 84608e8..fbfb37b 100644 (file)
@@ -490,7 +490,6 @@ extern bool ui_but_is_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
 extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
 extern bool ui_but_is_compatible(const uiBut *but_a, const uiBut *but_b) ATTR_WARN_UNUSED_RESULT;
 extern bool ui_but_is_rna_valid(uiBut *but) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_but_is_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
 extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
 
 extern int  ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
@@ -686,14 +685,10 @@ extern void ui_but_activate_over(struct bContext *C, struct ARegion *ar, uiBut *
 extern void ui_but_execute_begin(struct bContext *C, struct ARegion *ar, uiBut *but, void **active_back);
 extern void ui_but_execute_end(struct bContext *C, struct ARegion *ar, uiBut *but, void *active_back);
 extern void ui_but_active_free(const struct bContext *C, uiBut *but);
-extern bool ui_but_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_but_is_editing(uiBut *but);
 extern int ui_but_menu_direction(uiBut *but);
 extern void ui_but_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
 extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction);
-extern uiBut *ui_but_find_active_in_region(struct ARegion *ar);
-extern uiBut *ui_but_find_mouse_over(struct ARegion *ar, const struct wmEvent *event);
-void ui_but_pie_dir(RadialDirection dir, float vec[2]);
+bool ui_but_is_editing(const uiBut *but);
 float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
 
 void ui_but_add_shortcut(uiBut *but, const char *key_str, const bool do_strip);
@@ -807,15 +802,47 @@ void ui_but_anim_decorate_cb(struct bContext *C, void *arg_but, void *arg_dummy)
 void ui_but_anim_decorate_update_from_flag(uiBut *but);
 
 /* interface_query.c */
-bool ui_but_is_editable(const uiBut *but);
-bool ui_but_is_editable_as_text(const uiBut *but);
-bool ui_but_is_toggle(const uiBut *but);
-bool ui_but_is_popover_once_compat(const uiBut *but);
-
-extern bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
-extern bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_utf8(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+void ui_but_pie_dir(RadialDirection dir, float vec[2]);
+
+bool ui_but_is_cursor_warp(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+
+bool ui_but_contains_pt(
+        const uiBut *but, float mx, float my) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_contains_point_px_icon(
+        const uiBut *but, struct  ARegion *ar, const struct wmEvent *event) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_contains_point_px(
+        const struct ARegion *ar, const uiBut *but, int x, int y) ATTR_WARN_UNUSED_RESULT;
+bool ui_region_contains_point_px(
+        const struct ARegion *ar, int x, int y) ATTR_WARN_UNUSED_RESULT;
+
+uiBut *ui_list_find_mouse_over(ARegion *ar, const struct wmEvent *event) ATTR_WARN_UNUSED_RESULT;
+
+uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_but_find_mouse_over(struct ARegion *ar, const struct wmEvent *event) ATTR_WARN_UNUSED_RESULT;
+
+uiBut *ui_list_find_mouse_over_ex(struct ARegion *ar, int x, int y) ATTR_WARN_UNUSED_RESULT;
+
+bool ui_but_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
+bool ui_but_contains_password(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+
+uiBut *ui_but_prev(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_but_next(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_but_first(uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_but_last(uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+
+bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+
+uiBut *ui_but_find_active_in_region(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
 
 /* interface_context_menu.c */
 bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but);
index ad83bce..d123ac7 100644 (file)
  */
 
 #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"
 
 #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;
+}
+
+/** \} */