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 */
|
/* Styled text draw */
|
||||||
void uiStyleFontSet(struct uiFontStyle *fs);
|
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 uiStyleFontDraw(struct uiFontStyle *fs, struct rcti *rect, const char *str);
|
||||||
void uiStyleFontDrawRotated(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 <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
@@ -585,6 +586,77 @@ int uiButActiveOnly(const bContext *C, uiBlock *block, uiBut *but)
|
|||||||
return 1;
|
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)
|
void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
|
||||||
{
|
{
|
||||||
uiBut *but;
|
uiBut *but;
|
||||||
@@ -658,6 +730,7 @@ void uiEndBlock(const bContext *C, uiBlock *block)
|
|||||||
/* handle pending stuff */
|
/* handle pending stuff */
|
||||||
if(block->layouts.first) uiBlockLayoutResolve(block, NULL, NULL);
|
if(block->layouts.first) uiBlockLayoutResolve(block, NULL, NULL);
|
||||||
ui_block_do_align(block);
|
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);
|
if(block->flag & UI_BLOCK_LOOP) ui_menu_block_set_keymaps(C, block);
|
||||||
|
|
||||||
/* after keymaps! */
|
/* after keymaps! */
|
||||||
|
|||||||
@@ -5635,8 +5635,65 @@ int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu,
|
|||||||
|
|
||||||
retval= WM_UI_HANDLER_BREAK;
|
retval= WM_UI_HANDLER_BREAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -237,9 +237,10 @@ struct uiBut {
|
|||||||
struct IDProperty *opproperties;
|
struct IDProperty *opproperties;
|
||||||
struct PointerRNA *opptr;
|
struct PointerRNA *opptr;
|
||||||
short opcontext;
|
short opcontext;
|
||||||
|
unsigned char menu_key; /* 'a'-'z', always lower case */
|
||||||
|
|
||||||
/* Draggable data, type is WM_DRAG_... */
|
/* Draggable data, type is WM_DRAG_... */
|
||||||
short dragtype;
|
char dragtype;
|
||||||
void *dragpoin;
|
void *dragpoin;
|
||||||
struct ImBuf *imb;
|
struct ImBuf *imb;
|
||||||
float imb_scale;
|
float imb_scale;
|
||||||
|
|||||||
@@ -136,7 +136,9 @@ static uiFont *uifont_to_blfont(int id)
|
|||||||
|
|
||||||
/* *************** draw ************************ */
|
/* *************** 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;
|
float height;
|
||||||
int xofs=0, yofs;
|
int xofs=0, yofs;
|
||||||
@@ -171,6 +173,16 @@ void uiStyleFontDraw(uiFontStyle *fs, rcti *rect, const char *str)
|
|||||||
BLF_disable(fs->uifont_id, BLF_SHADOW);
|
BLF_disable(fs->uifont_id, BLF_SHADOW);
|
||||||
if (fs->kerning == 1)
|
if (fs->kerning == 1)
|
||||||
BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
|
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 */
|
/* drawn same as above, but at 90 degree angle */
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "BLI_math.h"
|
#include "BLI_math.h"
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
#include "BLI_rect.h"
|
#include "BLI_rect.h"
|
||||||
|
#include "BLI_string.h"
|
||||||
|
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_curve.h"
|
#include "BKE_curve.h"
|
||||||
@@ -961,6 +962,9 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
|
|||||||
// int transopts;
|
// int transopts;
|
||||||
char *cpoin = NULL;
|
char *cpoin = NULL;
|
||||||
|
|
||||||
|
/* for underline drawing */
|
||||||
|
float font_xofs, font_yofs;
|
||||||
|
|
||||||
uiStyleFontSet(fstyle);
|
uiStyleFontSet(fstyle);
|
||||||
|
|
||||||
if(but->editstr || (but->flag & UI_TEXT_LEFT))
|
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);
|
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 */
|
/* part text right aligned */
|
||||||
if(cpoin) {
|
if(cpoin) {
|
||||||
|
|||||||
Reference in New Issue
Block a user