2.5
authorTon Roosendaal <ton@blender.org>
Tue, 28 Jul 2009 16:48:02 +0000 (16:48 +0000)
committerTon Roosendaal <ton@blender.org>
Tue, 28 Jul 2009 16:48:02 +0000 (16:48 +0000)
Keymap feature: RightMouse in pulldown menus allows to assign
a new hotkey.

source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/space_outliner/outliner.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_keymap.c
source/blender/windowmanager/wm_event_types.h

index 8dc766499bcb25323b78d24314b57ff2e64c7f3f..d818f298de7a27a97a2de41ffba8c5519cf24a58 100644 (file)
@@ -206,6 +206,8 @@ typedef struct uiLayout uiLayout;
 #define HSVCIRCLE      (42<<9)
 #define LISTBOX                (43<<9)
 #define LISTROW                (44<<9)
+#define HOTKEYEVT      (45<<9)
+
 #define BUTTYPE                (63<<9)
 
 /* Drawing
@@ -426,6 +428,7 @@ uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int
 uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip);
 
 void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip);
+uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *keypoin, short *modkeypoin, char *tip);
 
 uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, char *tip);
 
index ca3be250a923c4680b55e07362cd54edf99ed25d..f6bf8f2cd312bea0ac44f343e271ea82bbd76b6c 100644 (file)
@@ -739,6 +739,7 @@ static void ui_is_but_sel(uiBut *but)
                case BUT:
                        push= 2;
                        break;
+               case HOTKEYEVT:
                case KEYEVT:
                        push= 2;
                        break;
@@ -1846,7 +1847,33 @@ void ui_check_but(uiBut *but)
                        strcat(but->drawstr, WM_key_event_string((short) ui_get_but_val(but)));
                }
                break;
-
+               
+       case HOTKEYEVT:
+               if (but->flag & UI_SELECT) {
+                       short *sp= (short *)but->func_arg3;
+                       
+                       strcpy(but->drawstr, but->str);
+                       
+                       if(*sp) {
+                               char *str= but->drawstr;
+                               
+                               if(*sp & KM_SHIFT)
+                                       str= strcat(str, "Shift ");
+                               if(*sp & KM_CTRL)
+                                       str= strcat(str, "Ctrl ");
+                               if(*sp & KM_ALT)
+                                       str= strcat(str, "Alt ");
+                               if(*sp & KM_OSKEY)
+                                       str= strcat(str, "Cmd ");
+                       }
+                       else
+                               strcat(but->drawstr, "Press a key  ");
+               } else {
+                       /* XXX todo, button currently only used temporarily */
+                       strcpy(but->drawstr, WM_key_event_string((short) ui_get_but_val(but)));
+               }
+               break;
+               
        case BUT_TOGDUAL:
                /* trying to get the dual-icon to left of text... not very nice */
                if(but->str[0]) {
@@ -2941,6 +2968,17 @@ void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1,
        ui_check_but(but);
 }
 
+/* short pointers hardcoded */
+/* modkeypoin will be set to KM_SHIFT, KM_ALT, KM_CTRL, KM_OSKEY bits */
+uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *keypoin, short *modkeypoin, char *tip)
+{
+       uiBut *but= ui_def_but(block, HOTKEYEVT|SHO, retval, str, x1, y1, x2, y2, keypoin, 0.0, 0.0, 0.0, 0.0, tip);
+       but->func_arg3= modkeypoin; /* XXX hrmf, abuse! */
+       ui_check_but(but);
+       return but;
+}
+
+
 /* arg is pointer to string/name, use uiButSetSearchFunc() below to make this work */
 uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, char *tip)
 {
index 0987f0d2f2a8f6c47da5335f52194c622582c38f..5c3fc890144afa51072ab7b5156c7438d7e07bd1 100644 (file)
@@ -840,6 +840,9 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
                        ui_apply_but_CHARTAB(C, but, data);
                        break;
 #endif
+               case HOTKEYEVT:
+                       ui_apply_but_BUT(C, but, data);
+                       break;
                case LINK:
                case INLINK:
                        ui_apply_but_LINK(C, but, data);
@@ -1801,6 +1804,60 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEv
        return WM_UI_HANDLER_CONTINUE;
 }
 
+static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
+{
+       if(data->state == BUTTON_STATE_HIGHLIGHT) {
+               if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) {
+                       but->drawstr[0]= 0;
+                       button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
+                       return WM_UI_HANDLER_BREAK;
+               }
+       }
+       else if(data->state == BUTTON_STATE_WAIT_KEY_EVENT) {
+               short *sp= (short *)but->func_arg3;
+               
+               if(event->type == MOUSEMOVE)
+                       return WM_UI_HANDLER_CONTINUE;
+               
+               if(ELEM(event->type, ESCKEY, LEFTMOUSE)) {
+                       /* data->cancel doesnt work, this button opens immediate */
+                       ui_set_but_val(but, 0);
+                       button_activate_state(C, but, BUTTON_STATE_EXIT);
+                       return WM_UI_HANDLER_BREAK;
+               }
+               
+               /* always set */
+               *sp= 0; 
+               if(event->shift)
+                       *sp |= KM_SHIFT;
+               if(event->alt)
+                       *sp |= KM_ALT;
+               if(event->ctrl)
+                       *sp |= KM_CTRL;
+               if(event->oskey)
+                       *sp |= KM_OSKEY;
+               
+               ui_check_but(but);
+               ED_region_tag_redraw(data->region);
+                       
+               if(event->val==KM_PRESS) {
+                       if(ISHOTKEY(event->type)) { 
+                               
+                               if(WM_key_event_string(event->type)[0])
+                                       ui_set_but_val(but, event->type);
+                               else
+                                       data->cancel= 1;
+                               
+                               button_activate_state(C, but, BUTTON_STATE_EXIT);
+                               return WM_UI_HANDLER_BREAK;
+                       }
+               }
+       }
+       
+       return WM_UI_HANDLER_CONTINUE;
+}
+
+
 static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event)
 {
        if(data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -3103,6 +3160,67 @@ static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, wmE
        return WM_UI_HANDLER_CONTINUE;
 }
 
+/* callback for hotkey change button/menu */
+static void do_menu_change_hotkey(bContext *C, void *but_v, void *key_v)
+{
+       uiBut *but= but_v;
+       IDProperty *prop= (but->opptr)? but->opptr->data: NULL;
+       short *key= key_v;
+       char buf[512], *butstr, *cpoin;
+       
+       /* signal for escape */
+       if(key[0]==0) return;
+       
+       WM_key_event_operator_change(C, but->optype->idname, but->opcontext, prop, key[0], key[1]);
+
+       /* complex code to change name of button */
+       if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) {
+               
+               butstr= MEM_mallocN(strlen(but->str)+strlen(buf)+2, "menu_block_set_keymaps");
+               
+               /* XXX but->str changed... should not, remove the hotkey from it */
+               cpoin= strchr(but->str, '|');
+               if(cpoin) *cpoin= 0;            
+
+               strcpy(butstr, but->str);
+               strcat(butstr, "|");
+               strcat(butstr, buf);
+               
+               but->str= but->strdata;
+               BLI_strncpy(but->str, butstr, sizeof(but->strdata));
+               MEM_freeN(butstr);
+               
+               ui_check_but(but);
+       }
+                               
+}
+
+
+static uiBlock *menu_change_hotkey(bContext *C, ARegion *ar, void *arg_but)
+{
+       uiBlock *block;
+       uiBut *but= arg_but;
+       wmOperatorType *ot= WM_operatortype_find(but->optype->idname, 1);
+       static short dummy[2];
+       char buf[OP_MAX_TYPENAME+10];
+       
+       dummy[0]= 0;
+       dummy[1]= 0;
+       
+       block= uiBeginBlock(C, ar, "_popup", UI_EMBOSSP);
+       uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_MOVEMOUSE_QUIT|UI_BLOCK_RET_1);
+       
+       BLI_strncpy(buf, ot->name, OP_MAX_TYPENAME);
+       strcat(buf, " |");
+       
+       but= uiDefHotKeyevtButS(block, 0, buf, 0, 0, 200, 20, dummy, dummy+1, "");
+       uiButSetFunc(but, do_menu_change_hotkey, arg_but, dummy);
+
+       uiPopupBoundsBlock(block, 6.0f, 50, -10);
+       uiEndBlock(C, block);
+       
+       return block;
+}
 
 static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
 {
@@ -3145,9 +3263,22 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
                }
                /* handle menu */
                else if(event->type == RIGHTMOUSE && event->val == KM_PRESS) {
-                       button_timers_tooltip_remove(C, but);
-                       ui_but_anim_menu(C, but);
-                       return WM_UI_HANDLER_BREAK;
+                       /* RMB has two options now */
+                       if(but->rnapoin.data && but->rnaprop) {
+                               button_timers_tooltip_remove(C, but);
+                               ui_but_anim_menu(C, but);
+                               return WM_UI_HANDLER_BREAK;
+                       }
+                       else if((but->block->flag & UI_BLOCK_LOOP) && but->optype) {
+                               IDProperty *prop= (but->opptr)? but->opptr->data: NULL;
+                               char buf[512];
+                               
+                               if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) {
+                                       
+                                       uiPupBlock(C, menu_change_hotkey, but);
+
+                               }
+                       }
                }
        }
 
@@ -3176,6 +3307,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
        case KEYEVT:
                retval= ui_do_but_KEYEVT(C, but, data, event);
                break;
+       case HOTKEYEVT:
+               retval= ui_do_but_HOTKEYEVT(C, but, data, event);
+               break;
        case TOGBUT: 
        case TOG: 
        case TOGR: 
@@ -3521,6 +3655,10 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
        }
        button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT);
        
+       /* activate right away */
+       if(but->type==HOTKEYEVT)
+               button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
+       
        if(type == BUTTON_ACTIVATE_OPEN) {
                button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
 
index 21ba9cfa7070d2537e736fea2272492bab8bf8bf..b05d9637a693be1ec90e99246b9b61438e199ae7 100644 (file)
@@ -1132,8 +1132,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
                te->name= km->nameid;
                
                if(!(tselem->flag & TSE_CLOSED)) {
+                       a= 0;
                        
-                       for (kmi= km->keymap.first; kmi; kmi= kmi->next) {
+                       for (kmi= km->keymap.first; kmi; kmi= kmi->next, a++) {
                                const char *key= WM_key_event_string(kmi->type);
                                
                                if(key[0]) {
index 36c78d17ab3ddd191b62f1ca3522ff6d9c0657a8..7d3dd47817824015cc0282eaf879d17f395d27dc 100644 (file)
@@ -100,6 +100,7 @@ int                 WM_key_event_is_tweak(short type);
 
 const char     *WM_key_event_string(short type);
 char           *WM_key_event_operator_string(const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, char *str, int len);
+void           WM_key_event_operator_change(const bContext *C, const char *opname, int opcontext, struct IDProperty *properties, short key, short modifier);
 
                        /* handlers */
 
index 1d959665f402270a742bb1d15704183eb3fbc9f9..ad0dd786791c4822cf2b3666a8bc9762c457a55d 100644 (file)
@@ -65,6 +65,8 @@ static void keymap_event_set(wmKeymapItem *kmi, short type, short val, int modif
        }
        else {
                
+               kmi->shift= kmi->ctrl= kmi->alt= kmi->oskey= 0;
+               
                /* defines? */
                if(modifier & KM_SHIFT)
                        kmi->shift= 1;
@@ -232,7 +234,7 @@ static char *wm_keymap_item_to_string(wmKeymapItem *kmi, char *str, int len)
                strcat(buf, "Alt ");
 
        if(kmi->oskey)
-               strcat(buf, "OS ");
+               strcat(buf, "Cmd ");
 
        strcat(buf, WM_key_event_string(kmi->type));
        BLI_strncpy(str, buf, len);
@@ -240,7 +242,7 @@ static char *wm_keymap_item_to_string(wmKeymapItem *kmi, char *str, int len)
        return str;
 }
 
-static char *wm_keymap_item_find(ListBase *handlers, const char *opname, int opcontext, IDProperty *properties, char *str, int len)
+static wmKeymapItem *wm_keymap_item_find_handlers(ListBase *handlers, const char *opname, int opcontext, IDProperty *properties)
 {
        wmEventHandler *handler;
        wmKeymapItem *kmi;
@@ -251,45 +253,66 @@ static char *wm_keymap_item_find(ListBase *handlers, const char *opname, int opc
                        for(kmi=handler->keymap->first; kmi; kmi=kmi->next)
                                if(strcmp(kmi->idname, opname) == 0 && WM_key_event_string(kmi->type)[0])
                                        if(kmi->ptr && IDP_EqualsProperties(properties, kmi->ptr->data))
-                                               return wm_keymap_item_to_string(kmi, str, len);
+                                               return kmi;
        
        return NULL;
 }
 
-char *WM_key_event_operator_string(const bContext *C, const char *opname, int opcontext, IDProperty *properties, char *str, int len)
+static wmKeymapItem *wm_keymap_item_find(const bContext *C, const char *opname, int opcontext, IDProperty *properties)
 {
-       char *found= NULL;
+       wmKeymapItem *found= NULL;
 
        /* look into multiple handler lists to find the item */
        if(CTX_wm_window(C))
-               if((found= wm_keymap_item_find(&CTX_wm_window(C)->handlers, opname, opcontext, properties, str, len)))
-                       return found;
-
-       if(CTX_wm_area(C))
-               if((found= wm_keymap_item_find(&CTX_wm_area(C)->handlers, opname, opcontext, properties, str, len)))
-                       return found;
-
-       if(ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
-               if(CTX_wm_area(C)) {
-                       ARegion *ar= CTX_wm_area(C)->regionbase.first;
-                       for(; ar; ar= ar->next)
-                               if(ar->regiontype==RGN_TYPE_WINDOW)
-                                       break;
-
-                       if(ar)
-                               if((found= wm_keymap_item_find(&ar->handlers, opname, opcontext, properties, str, len)))
-                                       return found;
+               found= wm_keymap_item_find_handlers(&CTX_wm_window(C)->handlers, opname, opcontext, properties);
+       
+
+       if(CTX_wm_area(C) && found==NULL)
+               found= wm_keymap_item_find_handlers(&CTX_wm_area(C)->handlers, opname, opcontext, properties);
+
+       if(found==NULL) {
+               if(ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
+                       if(CTX_wm_area(C)) {
+                               ARegion *ar= CTX_wm_area(C)->regionbase.first;
+                               for(; ar; ar= ar->next)
+                                       if(ar->regiontype==RGN_TYPE_WINDOW)
+                                               break;
+
+                               if(ar)
+                                       found= wm_keymap_item_find_handlers(&ar->handlers, opname, opcontext, properties);
+                       }
+               }
+               else {
+                       if(CTX_wm_region(C))
+                               found= wm_keymap_item_find_handlers(&CTX_wm_region(C)->handlers, opname, opcontext, properties);
                }
        }
-       else {
-               if(CTX_wm_region(C))
-                       if((found= wm_keymap_item_find(&CTX_wm_region(C)->handlers, opname, opcontext, properties, str, len)))
-                               return found;
+       
+       return found;
+}
+
+char *WM_key_event_operator_string(const bContext *C, const char *opname, int opcontext, IDProperty *properties, char *str, int len)
+{
+       wmKeymapItem *found= wm_keymap_item_find(C, opname, opcontext, properties);
+       
+       if(found) {
+               wm_keymap_item_to_string(found, str, len);
+               return str;
        }
 
        return NULL;
 }
 
+/* searches context and changes keymap item, if found */
+void WM_key_event_operator_change(const bContext *C, const char *opname, int opcontext, IDProperty *properties, short key, short modifier)
+{
+       wmKeymapItem *found= wm_keymap_item_find(C, opname, opcontext, properties);
+
+       if(found) {
+               keymap_event_set(found, key, KM_PRESS, modifier, 0);
+       }
+}
+
 /* ********************* */
 
 int WM_key_event_is_tweak(short type)
index 6e7186542de366e75ff98c66cc826fde89a9f98b..ee18a0fb45b8c79b49b5963ea190d92d5702e5d2 100644 (file)
        /* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */
 #define ISKEYBOARD(event)      (event >=' ' && event <=255)
 
+/* test whether event type is acceptable as hotkey, excluding modifiers */
+#define ISHOTKEY(event)        (event >=' ' && event <=320 && !(event>=LEFTCTRLKEY && event<=ESCKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY))
+
+
 /* **************** BLENDER GESTURE EVENTS ********************* */
 
 #define EVT_ACTIONZONE_AREA            0x5000