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.
This commit is contained in:
@@ -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);
|
||||
|
||||
|
@@ -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! */
|
||||
|
@@ -5635,11 +5635,68 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* here we check return conditions for menus */
|
||||
if(block->flag & UI_BLOCK_LOOP) {
|
||||
/* if we click outside the block, verify if we clicked on the
|
||||
|
@@ -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;
|
||||
|
@@ -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 */
|
||||
|
@@ -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) {
|
||||
|
Reference in New Issue
Block a user