Commit: 3ec4d0b51bf3a76725e39a57b0f30bec3edc6882
Author: Campbell Barton
Date:   Thu Nov 2 04:30:07 2017 +1100
Branches: master
https://developer.blender.org/rB3ec4d0b51bf3a76725e39a57b0f30bec3edc6882

UI: Add UILayout.operator_menu_hold

This is an operator button that opens a menu when the button is held.

===================================================================

M       source/blender/editors/include/UI_interface.h
M       source/blender/editors/interface/interface.c
M       source/blender/editors/interface/interface_handlers.c
M       source/blender/editors/interface/interface_intern.h
M       source/blender/editors/interface/interface_layout.c
M       source/blender/editors/interface/interface_regions.c
M       source/blender/editors/interface/interface_widgets.c
M       source/blender/makesrna/intern/rna_ui_api.c

===================================================================

diff --git a/source/blender/editors/include/UI_interface.h 
b/source/blender/editors/include/UI_interface.h
index 8b4f094cb8d..a609a3b51fd 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -136,6 +136,7 @@ enum {
 
 /* block->flag bits 14-17 are identical to but->drawflag bits */
 
+#define UI_BLOCK_POPUP_HOLD  (1 << 18)
 #define UI_BLOCK_LIST_ITEM   (1 << 19)
 #define UI_BLOCK_RADIAL      (1 << 20)
 
@@ -354,6 +355,7 @@ typedef struct uiSearchItems uiSearchItems;
 typedef void (*uiButHandleFunc)(struct bContext *C, void *arg1, void *arg2);
 typedef void (*uiButHandleRenameFunc)(struct bContext *C, void *arg, char 
*origstr);
 typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2);
+typedef void (*uiButHandleHoldFunc)(struct bContext *C, struct ARegion 
*butregion, uiBut *but);
 typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
 typedef struct ARegion *(*uiButSearchCreateFunc)(struct bContext *C, struct 
ARegion *butregion, uiBut *but);
 typedef void (*uiButSearchFunc)(const struct bContext *C, void *arg, const 
char *str, uiSearchItems *items);
@@ -395,6 +397,7 @@ void UI_popup_menu_reports(struct bContext *C, struct 
ReportList *reports) ATTR_
 int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct 
ReportList *reports) ATTR_NONNULL(1, 2);
 
 void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const 
bool enable);
+void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut 
*but);
 
 /* Pie menus */
 typedef struct uiPieMenu uiPieMenu;
@@ -726,6 +729,8 @@ bool UI_textbutton_activate_but(const struct bContext *C, 
uiBut *but);
 
 void UI_but_focus_on_enter_event(struct wmWindow *win, uiBut *but);
 
+void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
+
 /* Autocomplete
  *
  * Tab complete helper functions, for use in uiButCompleteFunc callbacks.
@@ -988,6 +993,11 @@ void uiItemFullO(
         uiLayout *layout, const char *idname, const char *name, int icon,
         struct IDProperty *properties, int context, int flag,
         PointerRNA *r_opptr);
+void uiItemFullOMenuHold_ptr(
+        uiLayout *layout, struct wmOperatorType *ot, const char *name, int 
icon,
+        struct IDProperty *properties, int context, int flag,
+        const char *menu_id,  /* extra menu arg. */
+        PointerRNA *r_opptr);
 
 void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, 
int flag, const char *name, int icon);
 void uiItemFullR(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA 
*prop, int index, int value, int flag, const char *name, int icon);
diff --git a/source/blender/editors/interface/interface.c 
b/source/blender/editors/interface/interface.c
index dc4c1b71066..bc2397d8e47 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2672,6 +2672,10 @@ static void ui_but_free(const bContext *C, uiBut *but)
                MEM_freeN(but->tip_argN);
        }
 
+       if (but->hold_argN) {
+               MEM_freeN(but->hold_argN);
+       }
+
        if (but->active) {
                /* XXX solve later, buttons should be free-able without context 
ideally,
                 * however they may have open tooltips or popup windows, which 
need to
@@ -4520,6 +4524,12 @@ void UI_but_focus_on_enter_event(wmWindow *win, uiBut 
*but)
        wm_event_add(win, &event);
 }
 
+void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN)
+{
+       but->hold_func = func;
+       but->hold_argN = argN;
+}
+
 void UI_but_string_info_get(bContext *C, uiBut *but, ...)
 {
        va_list args;
diff --git a/source/blender/editors/interface/interface_handlers.c 
b/source/blender/editors/interface/interface_handlers.c
index 0dec751526a..57f9b2ae356 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -304,6 +304,9 @@ typedef struct uiHandleButtonData {
        bool used_mouse;
        wmTimer *autoopentimer;
 
+       /* auto open (hold) */
+       wmTimer *hold_action_timer;
+
        /* text selection/editing */
        /* size of 'str' (including terminator) */
        int maxlen;
@@ -7808,6 +7811,15 @@ static void button_activate_state(bContext *C, uiBut 
*but, uiHandleButtonState s
                data->flashtimer = NULL;
        }
 
+       /* add hold timer if it's used */
+       if (state == BUTTON_STATE_WAIT_RELEASE && (but->hold_func != NULL)) {
+               data->hold_action_timer = WM_event_add_timer(data->wm, 
data->window, TIMER, BUTTON_AUTO_OPEN_THRESH);
+       }
+       else if (data->hold_action_timer) {
+               WM_event_remove_timer(data->wm, data->window, 
data->hold_action_timer);
+               data->hold_action_timer = NULL;
+       }
+
        /* add a blocking ui handler at the window handler for blocking, modal 
states
         * but not for popups, because we already have a window level handler*/
        if (!(but->block->handle && but->block->handle->popup)) {
@@ -8422,6 +8434,25 @@ static int ui_handle_button_event(bContext *C, const 
wmEvent *event, uiBut *but)
                                button_activate_state(C, but, 
BUTTON_STATE_EXIT);
                                break;
 
+                       case TIMER:
+                       {
+                               if (event->customdata == 
data->hold_action_timer) {
+                                       if (true) {
+                                               data->cancel = true;
+                                               button_activate_state(C, but, 
BUTTON_STATE_EXIT);
+                                       }
+                                       else {
+                                               /* Do this so we can still 
mouse-up, closing the menu and running the button.
+                                                * This is nice to support but 
there are times when the button gets left pressed.
+                                                * Keep disavled for now. */
+                                               WM_event_remove_timer(data->wm, 
data->window, data->hold_action_timer);
+                                               data->hold_action_timer = NULL;
+                                       }
+                                       retval = WM_UI_HANDLER_CONTINUE;
+                                       but->hold_func(C, data->region, but);
+                               }
+                               break;
+                       }
                        case MOUSEMOVE:
                                if (ELEM(but->type, UI_BTYPE_LINK, 
UI_BTYPE_INLINK)) {
                                        but->flag |= UI_SELECT;
@@ -9348,21 +9379,29 @@ static int ui_handle_menu_event(
                        if (inside == 0) {
                                uiSafetyRct *saferct = block->saferct.first;
 
-                               if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, 
RIGHTMOUSE) &&
-                                   ELEM(event->val, KM_PRESS, KM_DBL_CLICK))
-                               {
-                                       if ((is_parent_menu == false) && 
(U.uiflag & USER_MENUOPENAUTO) == 0) {
-                                               /* for root menus, allow 
clicking to close */
-                                               if (block->flag & 
(UI_BLOCK_OUT_1))
-                                                       menu->menuretval = 
UI_RETURN_OK;
-                                               else
-                                                       menu->menuretval = 
UI_RETURN_OUT;
+                               if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, 
RIGHTMOUSE)) {
+                                       if (ELEM(event->val, KM_PRESS, 
KM_DBL_CLICK)) {
+                                               if ((is_parent_menu == false) 
&& (U.uiflag & USER_MENUOPENAUTO) == 0) {
+                                                       /* for root menus, 
allow clicking to close */
+                                                       if (block->flag & 
(UI_BLOCK_OUT_1))
+                                                               
menu->menuretval = UI_RETURN_OK;
+                                                       else
+                                                               
menu->menuretval = UI_RETURN_OUT;
+                                               }
+                                               else if (saferct && 
!BLI_rctf_isect_pt(&saferct->parent, event->x, event->y)) {
+                                                       if (block->flag & 
(UI_BLOCK_OUT_1))
+                                                               
menu->menuretval = UI_RETURN_OK;
+                                                       else
+                                                               
menu->menuretval = UI_RETURN_OUT;
+                                               }
                                        }
-                                       else if (saferct && 
!BLI_rctf_isect_pt(&saferct->parent, event->x, event->y)) {
-                                               if (block->flag & 
(UI_BLOCK_OUT_1))
-                                                       menu->menuretval = 
UI_RETURN_OK;
-                                               else
-                                                       menu->menuretval = 
UI_RETURN_OUT;
+                                       else if (ELEM(event->val, KM_RELEASE, 
KM_CLICK)) {
+                                               /* For buttons that use a hold 
function, exit when mouse-up outside the menu. */
+                                               if (block->flag & 
UI_BLOCK_POPUP_HOLD) {
+                                                       /* Note, we could check 
the cursor is over the parent button. */
+                                                       menu->menuretval = 
UI_RETURN_CANCEL;
+                                                       retval = 
WM_UI_HANDLER_CONTINUE;
+                                               }
                                        }
                                }
                        }
diff --git a/source/blender/editors/interface/interface_intern.h 
b/source/blender/editors/interface/interface_intern.h
index ab760c40451..da11c2abab2 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -264,6 +264,10 @@ struct uiBut {
        void *rename_arg1;
        void *rename_orig;
 
+       /* Run an action when holding the button down. */
+       uiButHandleHoldFunc hold_func;
+       void *hold_argN;
+
        uiLink *link;
        short linkto[2];  /* region relative coords */
        
diff --git a/source/blender/editors/interface/interface_layout.c 
b/source/blender/editors/interface/interface_layout.c
index 616fc055c03..33dc74cbe23 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -795,7 +795,7 @@ static void ui_item_disabled(uiLayout *layout, const char 
*name)
  * \param r_opptr: Optional, initialize with operator properties when not NULL.
  * Will always be written to even in the case of errors.
  */
-void uiItemFullO_ptr(
+static uiBut *uiItemFullO_ptr_ex(
         uiLayout *layout, wmOperatorType *ot,
         const char *name, int icon, IDProperty *properties, int context, int 
flag,
         PointerRNA *r_opptr)
@@ -862,6 +862,50 @@ void uiItemFullO_ptr(
                        *r_opptr = *opptr;
                }
        }
+
+       return but;
+}
+
+static void ui_item_hold_menu(struct bContext *C, ARegion *butregion, uiBut 
*but)
+{
+       uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
+       uiLayout *layout = UI_popup_menu_layout(pup);
+       uiBlock *block = layout->root->block;
+       UI_popup_menu_but_set(pup, butregion, but);
+
+       block->flag |= UI_BLOCK_POPUP_HOLD;
+
+       const char *menu_id = but->hold_argN;
+       MenuType *mt = WM_menutype_find(menu_id, true);
+       if (mt) {
+               Menu menu = {NULL};
+               menu.layout = layout;
+               menu.type = mt;
+               mt->draw(C, &menu);
+       }
+       else {
+               uiItemL(layout, "Menu Missing:", ICON_NONE);
+               uiItemL(layout, menu_id, ICON_NONE);
+       }
+       UI_popup_menu_end(C, pup);
+}
+
+void uiItemFullO_ptr(
+        uiLayout *layout, wmOperatorType *ot,
+        const char *name, int icon, IDProperty *properties, int context, int 
flag,
+        PointerRNA *r_opptr)
+{
+       uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, 
r_opptr);
+}
+
+void uiItemFullOMenuHold_ptr(
+        uiLayout *layout, wmOperatorType *ot,
+        const char *name, int icon, IDProperty *properties, int context, int 
flag,
+        const char *menu_id,
+        PointerRNA *r_opptr)
+{
+       uiBut *but = uiItemFullO_ptr_ex(layout, ot, name, icon, properties, 
context, flag, r_opptr);
+       UI_but_func_hold_set(but, ui_item_hold_menu, BLI_strdup(menu_id));
 }


@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to