Commit: 47e7ce696c997313ae30bca0c09d17d6886a155b
Author: Campbell Barton
Date:   Sun Aug 3 20:30:12 2014 +1000
Branches: master
https://developer.blender.org/rB47e7ce696c997313ae30bca0c09d17d6886a155b

Fix for glitch with menus not reliably setting an active item (D674)

When menus are clamped to the window bounds,
its was possible not to have an active menu-item under the mouse,
Making Ctrl+S,Enter not completely reliable.

Changes needed to support this are:

- menu item is activated on popup menus
  (to avoid relying on mouse-over)
- moving mouse away from menu items only de-activates when over a new menu-item.
- Mouse clicks are ignored if they are not directly over the menu item.

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

M       source/blender/editors/interface/interface_handlers.c
M       source/blender/editors/interface/interface_intern.h
M       source/blender/editors/interface/interface_regions.c

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

diff --git a/source/blender/editors/interface/interface_handlers.c 
b/source/blender/editors/interface/interface_handlers.c
index b3f13cc..b5f11c2 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -385,7 +385,7 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int 
*val)
        }
 }
 
-static bool ui_but_is_editable(const uiBut *but)
+bool ui_but_is_editable(const uiBut *but)
 {
        return !ELEM(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, 
PROGRESSBAR);
 }
@@ -7199,6 +7199,17 @@ void ui_button_activate_do(bContext *C, ARegion *ar, 
uiBut *but)
        ui_do_button(C, but->block, but, &event);
 }
 
+/**
+ * Simulate moving the mouse over a button (or navigating to it with arrow 
keys).
+ *
+ * exported so menus can start with a highlighted button,
+ * even if the mouse isnt over it
+ */
+void ui_button_activate_over(bContext *C, ARegion *ar, uiBut *but)
+{
+       button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
+}
+
 void ui_button_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, 
uiBut *but, void **active_back)
 {
        /* note: ideally we would not have to change 'but->active' however
@@ -7261,12 +7272,20 @@ static int ui_handle_button_event(bContext *C, const 
wmEvent *event, uiBut *but)
                                retval = WM_UI_HANDLER_CONTINUE;
                                break;
                        case MOUSEMOVE:
-                               /* verify if we are still over the button, if 
not exit */
-                               if (!ui_mouse_inside_button(ar, but, event->x, 
event->y)) {
-                                       data->cancel = true;
-                                       button_activate_state(C, but, 
BUTTON_STATE_EXIT);
+                       {
+                               uiBut *but_other = ui_but_find_mouse_over(ar, 
event);
+                               bool exit = false;
+
+                               if (!ui_block_is_menu(block) &&
+                                   !ui_mouse_inside_button(ar, but, event->x, 
event->y))
+                               {
+                                       exit = true;
+                               }
+                               else if (but_other && 
ui_but_is_editable(but_other) && (but_other != but)) {
+                                       exit = true;
                                }
-                               else if (ui_but_find_mouse_over(ar, event) != 
but) {
+
+                               if (exit) {
                                        data->cancel = true;
                                        button_activate_state(C, but, 
BUTTON_STATE_EXIT);
                                }
@@ -7277,6 +7296,7 @@ static int ui_handle_button_event(bContext *C, const 
wmEvent *event, uiBut *but)
                                }
 
                                break;
+                       }
                        case TIMER:
                        {
                                /* handle tooltip timer */
@@ -7860,6 +7880,16 @@ static int ui_handle_menu_button(bContext *C, const 
wmEvent *event, uiPopupBlock
        int retval;
 
        if (but) {
+               /* Its possible there is an active menu item NOT under the 
mouse,
+                * in this case ignore mouse clicks outside the button (but 
Enter etc is accepted) */
+               if ((event->type != MOUSEMOVE) && ISMOUSE(event->type)) {
+                       if (!ui_mouse_inside_button(but->active->region, but, 
event->x, event->y)) {
+                               but = NULL;
+                       }
+               }
+       }
+
+       if (but) {
                ScrArea *ctx_area = CTX_wm_area(C);
                ARegion *ctx_region = CTX_wm_region(C);
 
diff --git a/source/blender/editors/interface/interface_intern.h 
b/source/blender/editors/interface/interface_intern.h
index fa8b6b1..7d03aae 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -552,6 +552,7 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct 
uiWidgetColors *wcol
 PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int 
opcontext, bool create_props);
 extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
 extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, 
uiBut *but);
+extern void ui_button_activate_over(struct bContext *C, struct ARegion *ar, 
uiBut *but);
 extern void ui_button_execute_begin(struct bContext *C, struct ARegion *ar, 
uiBut *but, void **active_back);
 extern void ui_button_execute_end(struct bContext *C, struct ARegion *ar, 
uiBut *but, void *active_back);
 extern void ui_button_active_free(const struct bContext *C, uiBut *but);
@@ -559,6 +560,7 @@ extern bool ui_button_is_active(struct ARegion *ar) 
ATTR_WARN_UNUSED_RESULT;
 extern int ui_button_open_menu_direction(uiBut *but);
 extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], 
uiBut *but, const bool restore);
 extern uiBut *ui_but_find_activated(struct ARegion *ar);
+bool ui_but_is_editable(const uiBut *but);
 
 void ui_button_clipboard_free(void);
 void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
diff --git a/source/blender/editors/interface/interface_regions.c 
b/source/blender/editors/interface/interface_regions.c
index 85bf15e..32fb684 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -2408,6 +2408,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, 
uiPopupBlockHandle *handle, voi
        uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
        
        if (pup->popup) {
+               uiBut *but_activate = NULL;
                uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | 
UI_BLOCK_NUMSELECT);
                uiBlockSetDirection(block, direction);
 
@@ -2421,6 +2422,10 @@ static uiBlock *ui_block_func_POPUP(bContext *C, 
uiPopupBlockHandle *handle, voi
                         * block to be under the mouse */
                        offset[0] = -(bt->rect.xmin + 0.8f * 
BLI_rctf_size_x(&bt->rect));
                        offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y);
+
+                       if (ui_but_is_editable(bt)) {
+                               but_activate = bt;
+                       }
                }
                else {
                        /* position mouse at 0.8*width of the button and below 
the tile
@@ -2430,6 +2435,20 @@ static uiBlock *ui_block_func_POPUP(bContext *C, 
uiPopupBlockHandle *handle, voi
                                offset[0] = min_ii(offset[0], -(bt->rect.xmin + 
0.8f * BLI_rctf_size_x(&bt->rect)));
 
                        offset[1] = 2.1 * UI_UNIT_Y;
+
+                       for (bt = block->buttons.first; bt; bt = bt->next) {
+                               if (ui_but_is_editable(bt)) {
+                                       but_activate = bt;
+                                       break;
+                               }
+                       }
+               }
+
+               /* in rare cases this is needed since moving the popup
+                * to be within the window bounds may move it away from the 
mouse,
+                * This ensures we set an item to be active. */
+               if (but_activate) {
+                       ui_button_activate_over(C, handle->region, 
but_activate);
                }
 
                block->minbounds = minwidth;

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

Reply via email to