diff options
author | Campbell Barton <ideasman42@gmail.com> | 2010-12-14 05:38:29 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2010-12-14 05:38:29 +0300 |
commit | 35f431b3d0edda651fda97cb0156181fab07562c (patch) | |
tree | 463161e5b71e2842ff16e9baf33b925aa872e9e4 | |
parent | 17bd906de3ba02c8d7bf848b1f61465f09fc631c (diff) |
Menu UI feature common in other widget sets:
Automatically assign menu keys based on name, alternative to pressing number 0-9 on menus items.
keys are assigned by first giving each menu item the first character of any word, if that fails any key in the name is used.
- active key is shown underlined.
- only ascii keys are assigned currently.
- can run operators, open menu items.
- currently this only works in cases where number buttons were used (UI_BLOCK_NUMSELECT), but could be enabled for file menu, splash etc by removing this check.
-rw-r--r-- | source/blender/editors/include/UI_interface.h | 2 | ||||
-rw-r--r-- | source/blender/editors/interface/interface.c | 73 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_handlers.c | 57 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_intern.h | 5 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_style.c | 14 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_widgets.c | 39 |
6 files changed, 186 insertions, 4 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index ef74052f217..19e2a86f644 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -749,6 +749,8 @@ void uiIDContextProperty(struct bContext *C, struct PointerRNA *ptr, struct Prop /* Styled text draw */ void uiStyleFontSet(struct uiFontStyle *fs); +void uiStyleFontDrawExt(struct uiFontStyle *fs, struct rcti *rect, const char *str, + float *r_xofs, float *r_yofs); void uiStyleFontDraw(struct uiFontStyle *fs, struct rcti *rect, const char *str); void uiStyleFontDrawRotated(struct uiFontStyle *fs, struct rcti *rect, const char *str); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 60928f03ea7..4e3e9786a5a 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -29,6 +29,7 @@ #include <limits.h> #include <math.h> #include <string.h> +#include <ctype.h> #include "MEM_guardedalloc.h" @@ -585,6 +586,77 @@ int uiButActiveOnly(const bContext *C, uiBlock *block, uiBut *but) return 1; } +/* assigns automatic keybindings to menu items for fast access + * (underline key in menu) */ +static void ui_menu_block_set_keyaccels(uiBlock *block) +{ + uiBut *but; + + unsigned int meny_key_mask= 0; + unsigned char menu_key; + const char *str_pt; + int pass; + int tot_missing= 0; + + /* only do it before bounding */ + if(block->minx != block->maxx) + return; + + for(pass=0; pass<2; pass++) { + /* 2 Passes, on for first letter only, second for any letter if first fails + * fun first pass on all buttons so first word chars always get first priority */ + + for(but=block->buttons.first; but; but=but->next) { + if(!ELEM4(but->type, BUT, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) { + /* pass */ + } + else if(but->menu_key=='\0') { + if(but->str) { + for(str_pt= but->str; *str_pt; ) { + menu_key= tolower(*str_pt); + if((menu_key >= 'a' && menu_key <= 'z') && !(meny_key_mask & 1<<(menu_key-'a'))) { + meny_key_mask |= 1<<(menu_key-'a'); + break; + } + + if(pass==0) { + /* Skip to next delimeter on first pass (be picky) */ + while(isalpha(*str_pt)) + str_pt++; + + if(*str_pt) + str_pt++; + } + else { + /* just step over every char second pass and find first usable key */ + str_pt++; + } + } + + if(*str_pt) { + but->menu_key= menu_key; + } + else { + /* run second pass */ + tot_missing++; + } + + /* if all keys have been used just exit, unlikely */ + if(meny_key_mask == (1<<26)-1) { + return; + } + } + } + } + + /* check if second pass is needed */ + if(!tot_missing) { + break; + } + } +} + + void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) { uiBut *but; @@ -658,6 +730,7 @@ void uiEndBlock(const bContext *C, uiBlock *block) /* handle pending stuff */ if(block->layouts.first) uiBlockLayoutResolve(block, NULL, NULL); ui_block_do_align(block); + if((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT)) ui_menu_block_set_keyaccels(block); /* could use a different flag to check */ if(block->flag & UI_BLOCK_LOOP) ui_menu_block_set_keymaps(C, block); /* after keymaps! */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 85359267ffd..e15696d7e80 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -5635,8 +5635,65 @@ int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu, retval= WM_UI_HANDLER_BREAK; } + break; + + /* Handle keystrokes on menu items */ + case AKEY: + case BKEY: + case CKEY: + case DKEY: + case EKEY: + case FKEY: + case GKEY: + case HKEY: + case IKEY: + case JKEY: + case KKEY: + case LKEY: + case MKEY: + case NKEY: + case OKEY: + case PKEY: + case QKEY: + case RKEY: + case SKEY: + case TKEY: + case UKEY: + case VKEY: + case WKEY: + case XKEY: + case YKEY: + case ZKEY: + { + if(event->val == KM_PRESS) { + count= 0; + for(but= block->buttons.first; but; but= but->next) { + if(but->menu_key==event->type) { + if(but->type == BUT) { + /* mainly for operator buttons */ + ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_APPLY); + } + else if(ELEM(but->type, BLOCK, PULLDOWN)) { + /* open submenus (like right arrow key) */ + ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_OPEN); + } + else if (but->type == MENU) { + /* activate menu items */ + ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE); + } + else { + printf("Error, but->menu_key type: %d\n", but->type); + } + + break; + } + } + + retval= WM_UI_HANDLER_BREAK; + } break; + } } } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index a7c03a6b95d..72f6e72cd5d 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -237,9 +237,10 @@ struct uiBut { struct IDProperty *opproperties; struct PointerRNA *opptr; short opcontext; - + unsigned char menu_key; /* 'a'-'z', always lower case */ + /* Draggable data, type is WM_DRAG_... */ - short dragtype; + char dragtype; void *dragpoin; struct ImBuf *imb; float imb_scale; diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index ec9ac300ca2..af0b2189a99 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -136,7 +136,9 @@ static uiFont *uifont_to_blfont(int id) /* *************** draw ************************ */ -void uiStyleFontDraw(uiFontStyle *fs, rcti *rect, const char *str) + +void uiStyleFontDrawExt(uiFontStyle *fs, rcti *rect, const char *str, + float *r_xofs, float *r_yofs) { float height; int xofs=0, yofs; @@ -171,6 +173,16 @@ void uiStyleFontDraw(uiFontStyle *fs, rcti *rect, const char *str) BLF_disable(fs->uifont_id, BLF_SHADOW); if (fs->kerning == 1) BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); + + *r_xofs= xofs; + *r_yofs= yofs; +} + +void uiStyleFontDraw(uiFontStyle *fs, rcti *rect, const char *str) +{ + float xofs, yofs; + uiStyleFontDrawExt(fs, rect, str, + &xofs, &yofs); } /* drawn same as above, but at 90 degree angle */ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index a3a8e40abe6..319d51cdf75 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -35,6 +35,7 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_rect.h" +#include "BLI_string.h" #include "BKE_context.h" #include "BKE_curve.h" @@ -961,6 +962,9 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b // int transopts; char *cpoin = NULL; + /* for underline drawing */ + float font_xofs, font_yofs; + uiStyleFontSet(fstyle); if(but->editstr || (but->flag & UI_TEXT_LEFT)) @@ -1038,7 +1042,40 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b } glColor3ubv((unsigned char*)wcol->text); - uiStyleFontDraw(fstyle, rect, but->drawstr+but->ofs); + + uiStyleFontDrawExt(fstyle, rect, but->drawstr+but->ofs, &font_xofs, &font_yofs); + + if(but->menu_key != '\0') { + char fixedbuf[128]; + char *str; + + BLI_strncpy(fixedbuf, but->drawstr + but->ofs, sizeof(fixedbuf)); + + str= strchr(fixedbuf, but->menu_key-32); /* upper case */ + if(str==NULL) + str= strchr(fixedbuf, but->menu_key); + + if(str) { + int ul_index= -1; + float ul_advance; + + ul_index= (int)(str - fixedbuf); + + if (fstyle->kerning == 1) { + BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + } + + fixedbuf[ul_index]= '\0'; + ul_advance= BLF_width(fstyle->uifont_id, fixedbuf); + + BLF_position(fstyle->uifont_id, rect->xmin+font_xofs + ul_advance, rect->ymin+font_yofs, 0.0f); + BLF_draw(fstyle->uifont_id, "_", 2); + + if (fstyle->kerning == 1) { + BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + } + } + } /* part text right aligned */ if(cpoin) { |