rename api functions...
[blender.git] / source / blender / editors / interface / interface_handlers.c
index d370dfe1abf2decdc71782f6d77b4803a85cdcb3..dc7ea930e4505688c41073f8595c0f620d35b8c5 100644 (file)
@@ -78,6 +78,9 @@
 #include "WM_api.h"
 #include "WM_types.h"
 
+/* place the mouse at the scaled down location when un-grabbing */
+#define USE_CONT_MOUSE_CORRECT
+
 /* proto */
 static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to);
 static void ui_add_link(bContext *C, uiBut *from, uiBut *to);
@@ -152,6 +155,12 @@ typedef struct uiHandleButtonData {
        float dragf, dragfstart;
        CBData *dragcbd;
 
+#ifdef USE_CONT_MOUSE_CORRECT
+       /* when ungrabbing buttons which are #ui_is_a_warp_but(), we may want to position them
+        * FLT_MAX signifies do-nothing, use #ui_block_to_window_fl() to get this into a usable space  */
+       float ungrab_mval[2];
+#endif
+
        /* menu open (watch uiFreeActiveButtons) */
        uiPopupBlockHandle *menu;
        int menuretval;
@@ -695,7 +704,9 @@ static int ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, wmEvent *event)
        
        BLI_rcti_rctf_copy(&rect, &but->rect);
        
-       if (but->imb) ;  /* use button size itself */
+       if (but->imb) {
+               /* use button size itself */
+       }
        else if (but->flag & UI_ICON_LEFT) {
                rect.xmax = rect.xmin + (BLI_rcti_size_y(&rect));
        }
@@ -763,7 +774,7 @@ static void ui_delete_active_linkline(uiBlock *block)
                                                                        (*(link->ppoin))[b] = (*(link->ppoin))[a];
                                                                        b++;
                                                                }
-                                                       }       
+                                                       }
                                                        (*(link->totlink))--;
                                                }
                                        }
@@ -843,7 +854,7 @@ static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to)
        RNA_pointer_create((ID *)ob, &RNA_Object, ob, &object_ptr);
        
        WM_operator_properties_create(&props_ptr, "LOGIC_OT_controller_add");
-       RNA_string_set(&props_ptr, "object", ob->id.name+2);
+       RNA_string_set(&props_ptr, "object", ob->id.name + 2);
 
        /* (3) add a new controller */
        if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, &props_ptr) & OPERATOR_FINISHED) {
@@ -1052,7 +1063,7 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
                        break;
                case HSVSLI:
                        break;
-               case TOG3:      
+               case TOG3:
                        ui_apply_but_TOG3(C, but, data);
                        break;
                case MENU:
@@ -1098,10 +1109,10 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
                case INLINK:
                        ui_apply_but_LINK(C, but, data);
                        break;
-               case BUT_IMAGE: 
+               case BUT_IMAGE:
                        ui_apply_but_IMAGE(C, but, data);
                        break;
-               case HISTOGRAM: 
+               case HISTOGRAM:
                        ui_apply_but_HISTOGRAM(C, but, data);
                        break;
                case WAVEFORM:
@@ -1175,7 +1186,9 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
        /* numeric value */
        if (ELEM4(but->type, NUM, NUMABS, NUMSLI, HSVSLI)) {
                
-               if (but->poin == NULL && but->rnapoin.data == NULL) ;
+               if (but->poin == NULL && but->rnapoin.data == NULL) {
+                       /* pass */
+               }
                else if (mode == 'c') {
                        ui_get_but_string(but, buf, sizeof(buf));
                        WM_clipboard_text_set(buf, 0);
@@ -1196,7 +1209,9 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
        else if (but->type == COLOR) {
                float rgb[3];
                
-               if (but->poin == NULL && but->rnapoin.data == NULL) ;
+               if (but->poin == NULL && but->rnapoin.data == NULL) {
+                       /* pass */
+               }
                else if (mode == 'c') {
 
                        ui_get_but_vectorf(but, rgb);
@@ -1225,7 +1240,9 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
        else if (ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) {
                uiHandleButtonData *active_data = but->active;
 
-               if (but->poin == NULL && but->rnapoin.data == NULL) ;
+               if (but->poin == NULL && but->rnapoin.data == NULL) {
+                       /* pass */
+               }
                else if (mode == 'c') {
                        button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
                        BLI_strncpy(buf, active_data->str, UI_MAX_DRAW_STR);
@@ -1326,7 +1343,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, sho
        }
        
        /* mouse dragged outside the widget to the left */
-       if (x < startx && but->ofs > 0) {       
+       if (x < startx && but->ofs > 0) {
                int i = but->ofs;
 
                origstr[but->ofs] = 0;
@@ -1359,7 +1376,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, sho
 
                while (TRUE) {
                        /* XXX does not take zoom level into account */
-                       cdist = startx + aspect_sqrt *BLF_width(fstyle->uifont_id, origstr + but->ofs);
+                       cdist = startx + aspect_sqrt * BLF_width(fstyle->uifont_id, origstr + but->ofs);
 
                        /* check if position is found */
                        if (cdist < x) {
@@ -1570,7 +1587,7 @@ static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int directio
                                but->pos -= step;
                                changed = 1;
                        }
-               } 
+               }
        }
 
        return changed;
@@ -1605,6 +1622,7 @@ static int ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, int paste
        
        /* paste */
        if (paste) {
+               /* TODO, ensure UTF8 ui_is_but_utf8() - campbell */
                /* extract the first line from the clipboard */
                p = pbuf = WM_clipboard_text_get(0);
 
@@ -1658,7 +1676,7 @@ static int ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, int paste
                if (cut)
                        if ((but->selend - but->selsta) > 0)
                                changed = ui_textedit_delete_selection(but, data);
-       } 
+       }
 
        return changed;
 }
@@ -2139,7 +2157,7 @@ static void ui_blockopen_begin(bContext *C, uiBut *but, uiHandleButtonData *data
        }
 
        /* this makes adjacent blocks auto open from now on */
-       //if (but->block->auto_open ==) but->block->auto_open = 1;
+       //if (but->block->auto_open == 0) but->block->auto_open = 1;
 }
 
 static void ui_blockopen_end(bContext *C, uiBut *but, uiHandleButtonData *data)
@@ -2157,6 +2175,16 @@ static void ui_blockopen_end(bContext *C, uiBut *but, uiHandleButtonData *data)
        }
 }
 
+int ui_button_open_menu_direction(uiBut *but)
+{
+       uiHandleButtonData *data = but->active;
+
+       if (data && data->menu)
+               return data->menu->direction;
+       
+       return 0;
+}
+
 /* ***************** events for different button types *************** */
 
 static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
@@ -2226,7 +2254,7 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
                ED_region_tag_redraw(data->region);
                        
                if (event->val == KM_PRESS) {
-                       if (ISHOTKEY(event->type)) { 
+                       if (ISHOTKEY(event->type)) {
                                
                                if (WM_key_event_string(event->type)[0])
                                        ui_set_but_val(but, event->type);
@@ -2277,7 +2305,9 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
 {
        if (data->state == BUTTON_STATE_HIGHLIGHT) {
                if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN) && event->val == KM_PRESS) {
-                       if (but->dt == UI_EMBOSSN && !event->ctrl) ;
+                       if (but->dt == UI_EMBOSSN && !event->ctrl) {
+                               /* pass */
+                       }
                        else {
                                button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
                                return WM_UI_HANDLER_BREAK;
@@ -2905,7 +2935,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
                                        data->value = temp;
                                else
                                        data->cancel = TRUE;
-                       } 
+                       }
                        else {
                                if (f < tempf) tempf -= 0.01f;
                                else tempf += 0.01f;
@@ -2931,7 +2961,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
 
 static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event)
 {
-       int mx, my /*, click= 0 */;
+       int mx, my /*, click = 0 */;
        int retval = WM_UI_HANDLER_CONTINUE;
        int horizontal = (BLI_rctf_size_x(&but->rect) > BLI_rctf_size_y(&but->rect));
        
@@ -3191,6 +3221,15 @@ static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx,
        
        ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift);
 
+#ifdef USE_CONT_MOUSE_CORRECT
+       if (ui_is_a_warp_but(but)) {
+               /* OK but can go outside bounds */
+               data->ungrab_mval[0] = mx_fl;
+               data->ungrab_mval[1] = my_fl;
+               BLI_rctf_clamp_pt_v(&but->rect, data->ungrab_mval);
+       }
+#endif
+
        if (but->rnaprop) {
                if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
                        color_profile = FALSE;
@@ -3297,7 +3336,7 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, wmNDOF
                case UI_GRAD_V:
                        hsv[2] += ndof->ry * sensitivity;
                        break;
-               case UI_GRAD_V_ALT:     
+               case UI_GRAD_V_ALT:
                        /* vertical 'value' strip */
                        
                        /* exception only for value strip - use the range set in but->min/max */
@@ -3415,6 +3454,22 @@ static int ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data, float
        
        ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift);
 
+#ifdef USE_CONT_MOUSE_CORRECT
+       if (ui_is_a_warp_but(but)) {
+               /* OK but can go outside bounds */
+               data->ungrab_mval[0] = mx_fl;
+               data->ungrab_mval[1] = my_fl;
+               {       /* clamp */
+                       const float radius = min_ff(BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect)) / 2.0f;
+                       const float cent[2] = {BLI_rctf_cent_x(&but->rect), BLI_rctf_cent_y(&but->rect)};
+                       const float len = len_v2v2(cent, data->ungrab_mval);
+                       if (len > radius) {
+                               dist_ensure_v2_v2fl(data->ungrab_mval, cent, radius);
+                       }
+               }
+       }
+#endif
+
        BLI_rcti_rctf_copy(&rect, &but->rect);
 
        ui_get_but_vectorf(but, rgb);
@@ -3692,8 +3747,8 @@ static int ui_numedit_but_CURVE(uiBut *but, uiHandleButtonData *data, int snap,
 
        zoomx = BLI_rctf_size_x(&but->rect) / BLI_rctf_size_x(&cumap->curr);
        zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&cumap->curr);
-       /* offsx= cumap->curr.xmin; */
-       /* offsy= cumap->curr.ymin; */
+       /* offsx = cumap->curr.xmin; */
+       /* offsy = cumap->curr.ymin; */
 
        if (snap) {
                float d[2];
@@ -3706,9 +3761,10 @@ static int ui_numedit_but_CURVE(uiBut *but, uiHandleButtonData *data, int snap,
        }
 
        if (data->dragsel != -1) {
+               CurveMapPoint *cmp_last = NULL;
                const float mval_factor = ui_mouse_scale_warp_factor(shift);
                int moved_point = 0;     /* for ctrl grid, can't use orig coords because of sorting */
-               
+
                fx = (mx - data->draglastx) / zoomx;
                fy = (my - data->draglasty) / zoomy;
 
@@ -3726,6 +3782,8 @@ static int ui_numedit_but_CURVE(uiBut *but, uiHandleButtonData *data, int snap,
                                }
                                if (cmp[a].x != origx || cmp[a].y != origy)
                                        moved_point = 1;
+
+                               cmp_last = &cmp[a];
                        }
                }
 
@@ -3735,6 +3793,18 @@ static int ui_numedit_but_CURVE(uiBut *but, uiHandleButtonData *data, int snap,
                        data->draglastx = mx;
                        data->draglasty = my;
                        changed = 1;
+
+#ifdef USE_CONT_MOUSE_CORRECT
+                       /* note: using 'cmp_last' is weak since there may be multiple points selected,
+                        * but in practice this isnt really an issue */
+                       if (ui_is_a_warp_but(but)) {
+                               /* OK but can go outside bounds */
+                               data->ungrab_mval[0] = but->rect.xmin + ((cmp_last->x - cumap->curr.xmin) * zoomx);
+                               data->ungrab_mval[1] = but->rect.ymin + ((cmp_last->y - cumap->curr.ymin) * zoomy);
+                               BLI_rctf_clamp_pt_v(&but->rect, data->ungrab_mval);
+                       }
+#endif
+
                }
 
                data->dragchange = 1; /* mark for selection */
@@ -3834,7 +3904,7 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt
 
                                                changed = 1;
                                                
-                                               /* reset cmp back to the curve points again, rather than drawing segments */            
+                                               /* reset cmp back to the curve points again, rather than drawing segments */
                                                cmp = cuma->curve;
                                                
                                                /* find newly added point and make it 'sel' */
@@ -3938,7 +4008,7 @@ static int ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int mx
        }
        else {
                /* scale histogram values (dy / 10 for better control) */
-               const float yfac = minf(powf(hist->ymax, 2.0f), 1.0f) * 0.5f;
+               const float yfac = min_ff(powf(hist->ymax, 2.0f), 1.0f) * 0.5f;
                hist->ymax += (dy * 0.1f) * yfac;
        
                /* 0.1 allows us to see HDR colors up to 10 */
@@ -4008,7 +4078,7 @@ static int ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx,
        Scopes *scopes = (Scopes *)but->poin;
        /* rcti rect; */
        int changed = 1;
-       float /* dx, */ dy /* , yfac=1.f */; /* UNUSED */
+       float /* dx, */ dy /* , yfac =1.0f */; /* UNUSED */
 
        /* BLI_rcti_rctf_copy(&rect, &but->rect); */
 
@@ -4438,11 +4508,11 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
        int kmi_id;
        
        /* XXX this guess_opname can potentially return a different keymap than being found on adding later... */
-       km = WM_keymap_guess_opname(C, but->optype->idname);            
+       km = WM_keymap_guess_opname(C, but->optype->idname);
        kmi = WM_keymap_add_item(km, but->optype->idname, AKEY, KM_PRESS, 0, 0);
        kmi_id = kmi->id;
 
-       /* copy properties, prop can be NULL for reset */       
+       /* copy properties, prop can be NULL for reset */
        if (prop)
                prop = IDP_CopyProperty(prop);
        WM_keymap_properties_reset(kmi, prop);
@@ -4450,7 +4520,7 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
        /* update and get pointers again */
        WM_keyconfig_update(wm);
 
-       km = WM_keymap_guess_opname(C, but->optype->idname);            
+       km = WM_keymap_guess_opname(C, but->optype->idname);
        kmi = WM_keymap_item_find_id(km, kmi_id);
 
        RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr);
@@ -4657,8 +4727,8 @@ static int ui_but_menu(bContext *C, uiBut *but)
                
                /* Property Operators */
                
-               /*Copy Property Value
-                *Paste Property Value */
+               /* Copy Property Value
+                * Paste Property Value */
                
                if (length) {
                        uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Reset All to Default Values"),
@@ -4884,7 +4954,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                                button_activate_state(C, but, BUTTON_STATE_EXIT);
                                return WM_UI_HANDLER_BREAK;
                        }
-               } 
+               }
                else if (but->pointype && but->poin == NULL) {
                        /* there's a pointer needed */
                        BKE_reportf(NULL, RPT_WARNING, "DoButton pointer error: %s", but->str);
@@ -5279,12 +5349,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
 
                /* automatic open pulldown block timer */
                if (ELEM3(but->type, BLOCK, PULLDOWN, ICONTEXTROW)) {
-                       if ((data->used_mouse == TRUE) &&
-                           (data->autoopentimer == FALSE) &&
-                           /* don't popup the first time,
-                            * see description on this member for info */
-                           (but->block->auto_is_first_event == FALSE))
-                       {
+                       if (data->used_mouse && !data->autoopentimer) {
                                int time;
 
                                if (but->block->auto_open == TRUE) {  /* test for toolbox */
@@ -5304,8 +5369,6 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
                                        data->autoopentimer = WM_event_add_timer(data->wm, data->window, TIMER, 0.02 * (double)time);
                                }
                        }
-
-                       but->block->auto_is_first_event = FALSE;
                }
        }
        else {
@@ -5329,8 +5392,24 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
        }
        else if (data->state == BUTTON_STATE_NUM_EDITING) {
                ui_numedit_end(but, data);
-               if (ui_is_a_warp_but(but))
-                       WM_cursor_grab_disable(CTX_wm_window(C));
+               if (ui_is_a_warp_but(but)) {
+
+#ifdef USE_CONT_MOUSE_CORRECT
+                       if (data->ungrab_mval[0] != FLT_MAX) {
+                               int mouse_ungrab_xy[2];
+                               ui_block_to_window_fl(data->region, but->block, &data->ungrab_mval[0], &data->ungrab_mval[1]);
+                               mouse_ungrab_xy[0] = data->ungrab_mval[0];
+                               mouse_ungrab_xy[1] = data->ungrab_mval[1];
+
+                               WM_cursor_grab_disable(data->window, mouse_ungrab_xy);
+                       }
+                       else {
+                               WM_cursor_grab_disable(data->window, NULL);
+                       }
+#else
+                       WM_cursor_grab_disable(data->window, );
+#endif
+               }
        }
        /* menu open */
        if (state == BUTTON_STATE_MENU_OPEN)
@@ -5393,6 +5472,10 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
        data->window = CTX_wm_window(C);
        data->region = ar;
 
+#ifdef USE_CONT_MOUSE_CORRECT
+       copy_v2_fl(data->ungrab_mval, FLT_MAX);
+#endif
+
        if (ELEM(but->type, BUT_CURVE, SEARCH_MENU)) {
                /* XXX curve is temp */
        }
@@ -5944,7 +6027,7 @@ static int ui_handle_button_event(bContext *C, wmEvent *event, uiBut *but)
        }
        else {
                retval = ui_do_button(C, block, but, event);
-               // retval= WM_UI_HANDLER_BREAK; XXX why ? 
+               // retval = WM_UI_HANDLER_BREAK; XXX why ?
        }
 
        if (data->state == BUTTON_STATE_EXIT) {
@@ -6226,7 +6309,7 @@ static int ui_menu_scroll(ARegion *ar, uiBlock *block, int my)
        return 0;
 }
 
-static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu, int UNUSED(topmenu))
+static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu, int level)
 {
        ARegion *ar;
        uiBlock *block;
@@ -6271,10 +6354,22 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                }
                
                /* first block own event func */
-               if (block->block_event_func && block->block_event_func(C, block, event)) ;
-               /* events not for active search menu button */
+               if (block->block_event_func && block->block_event_func(C, block, event)) {
+                       /* pass */
+               }   /* events not for active search menu button */
                else if (but == NULL || but->type != SEARCH_MENU) {
                        switch (event->type) {
+
+
+                       /* let the parent menu get the event */
+#define     PASS_EVENT_TO_PARENT_IF_NONACTIVE                                 \
+                               if ((level != 0) && (but == NULL)) {                          \
+                                       menu->menuretval = UI_RETURN_OUT | UI_RETURN_OUT_PARENT;  \
+                                       BLI_assert(retval == WM_UI_HANDLER_CONTINUE);             \
+                                       break;                                                    \
+                               } (void)0
+
+
                                /* closing sublevels of pulldowns */
                                case LEFTARROWKEY:
                                        if (event->val == KM_PRESS && (block->flag & UI_BLOCK_LOOP))
@@ -6285,8 +6380,11 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                                        break;
 
                                /* opening sublevels of pulldowns */
-                               case RIGHTARROWKEY:     
+                               case RIGHTARROWKEY:
                                        if (event->val == KM_PRESS && (block->flag & UI_BLOCK_LOOP)) {
+
+                                               PASS_EVENT_TO_PARENT_IF_NONACTIVE;
+
                                                but = ui_but_find_activated(ar);
 
                                                if (!but) {
@@ -6312,6 +6410,9 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                                        }
                                        else if (inside || (block->flag & UI_BLOCK_LOOP)) {
                                                if (event->val == KM_PRESS) {
+
+                                                       PASS_EVENT_TO_PARENT_IF_NONACTIVE;
+
                                                        but = ui_but_find_activated(ar);
                                                        if (but) {
                                                                /* is there a situation where UI_LEFT or UI_RIGHT would also change navigation direction? */
@@ -6391,6 +6492,9 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                                        if (act == 0) act = 10;
 
                                        if ((block->flag & UI_BLOCK_NUMSELECT) && event->val == KM_PRESS) {
+
+                                               PASS_EVENT_TO_PARENT_IF_NONACTIVE;
+
                                                if (event->alt) act += 10;
 
                                                count = 0;
@@ -6468,6 +6572,8 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                                            (event->ctrl  == FALSE) &&
                                            (event->oskey == FALSE))
                                        {
+                                               PASS_EVENT_TO_PARENT_IF_NONACTIVE;
+
                                                for (but = block->buttons.first; but; but = but->next) {
 
                                                        if (but->menu_key == event->type) {
@@ -6515,7 +6621,9 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                                }
                        }
 
-                       if (menu->menuretval) ;
+                       if (menu->menuretval) {
+                               /* pass */
+                       }
                        else if (event->type == ESCKEY && event->val == KM_PRESS) {
                                /* esc cancels this and all preceding menus */
                                menu->menuretval = UI_RETURN_CANCEL;
@@ -6557,6 +6665,10 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
                                                retval = WM_UI_HANDLER_BREAK;
                                }
                        }
+
+                       /* end switch */
+#undef PASS_EVENT_TO_PARENT_IF_NONACTIVE
+
                }
        }
 
@@ -6645,7 +6757,7 @@ static int ui_handle_menu_return_submenu(bContext *C, wmEvent *event, uiPopupBlo
                return WM_UI_HANDLER_BREAK;
 }
 
-static int ui_handle_menus_recursive(bContext *C, wmEvent *event, uiPopupBlockHandle *menu)
+static int ui_handle_menus_recursive(bContext *C, wmEvent *event, uiPopupBlockHandle *menu, int level)
 {
        uiBut *but;
        uiHandleButtonData *data;
@@ -6658,14 +6770,24 @@ static int ui_handle_menus_recursive(bContext *C, wmEvent *event, uiPopupBlockHa
        submenu = (data) ? data->menu : NULL;
 
        if (submenu)
-               retval = ui_handle_menus_recursive(C, event, submenu);
+               retval = ui_handle_menus_recursive(C, event, submenu, level + 1);
 
        /* now handle events for our own menu */
        if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) {
-               if (submenu && submenu->menuretval)
+               if (submenu && submenu->menuretval) {
+                       int do_ret_out_parent = (submenu->menuretval & UI_RETURN_OUT_PARENT);
                        retval = ui_handle_menu_return_submenu(C, event, menu);
-               else
-                       retval = ui_handle_menu_event(C, event, menu, (submenu == NULL));
+                       submenu = NULL;  /* hint not to use this, it may be freed by call above */
+                       (void)submenu;
+                       /* we may wan't to quit the submenu and handle the even in this menu,
+                        * if its important to use it, check 'data->menu' first */
+                       if ((retval == WM_UI_HANDLER_BREAK) && do_ret_out_parent) {
+                               retval = ui_handle_menu_event(C, event, menu, level);
+                       }
+               }
+               else {
+                       retval = ui_handle_menu_event(C, event, menu, level);  /* same as above */
+               }
        }
 
        return retval;
@@ -6753,7 +6875,7 @@ static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(user
                if (data->state == BUTTON_STATE_MENU_OPEN) {
                        /* handle events for menus and their buttons recursively,
                         * this will handle events from the top to the bottom menu */
-                       retval = ui_handle_menus_recursive(C, event, data->menu);
+                       retval = ui_handle_menus_recursive(C, event, data->menu, 0);
 
                        /* handle events for the activated button */
                        if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) {
@@ -6797,7 +6919,7 @@ static int ui_handler_popup(bContext *C, wmEvent *event, void *userdata)
                retval = WM_UI_HANDLER_CONTINUE;
        }
 
-       ui_handle_menus_recursive(C, event, menu);
+       ui_handle_menus_recursive(C, event, menu, 0);
 
        /* free if done, does not free handle itself */
        if (menu->menuretval) {