BlenderDev/hotkey
Wikipedia,自由的百科全书
是否开启国际化支持是由一个名叫International Fonts的按钮实现的。 所以我们只要现在源代码中确定这个按钮的位置。 搜索"International Fonts", 发现它在space.c中。
space.c uiDefButBitS(block, TOG, USER_DOTRANSLATE, B_DOLANGUIFONT, "International Fonts",
xpos,y2,mpref,buth, &(U.transopts), 0, 0, 0, 0, "Activate international interface");
可能你需要去了解一下uiDefButBitS的实现(interface.c中), 了解它对你洞悉Blender的UI机制有很大帮助, 之后可能深入到SDNA。这些是你的事情了, 我说我的。
如果你查找USER_DOTRANSLATE的定义会发现在DNA_userdef_types.h中有:
- define USER_DOTRANSLATE 32
为什么uiDefButBitS这一行又给出了&(U.transopts), 一个地址? 其实, uiDefButBitS绕来绕去, 就是想将按钮和U.transopts的某一位(二进制)联系在一起, 而这位是0还是1控制了是否开启国际化支持。 U.transopts控制了国际化支持的参数, 你应该看出来了, transopts是tranlation options的缩写。 我们只要改变相应位值就可以开启或关闭国际化支持。
究竟是哪位呢, 你可以看程序马上猜到是第5位, 00100000中是1的那一位。为了检验这个假设我帮你写了一段程序:
- define USER_DOTRANSLATE 32
static int findBitIndex(unsigned int x) {
if (!x || (x&(x-1))!=0) { /* x&(x-1) strips lowest bit */
return -1;
} else {
int idx= 0;
if (x&0xFFFF0000) idx+=16, x>>=16;
if (x&0xFF00) idx+=8, x>>=8;
if (x&0xF0) idx+=4, x>>=4;
if (x&0xC) idx+=2, x>>=2;
if (x&0x2) idx+=1;
return idx; }
}
void main() {
printf("%x", findBitIndex(USER_TR_TOOLTIPS));
}
想办法定义一个快捷键, 灵感从何而来?答案:Quit Blender。我们知道, Ctrl+Q可以退出Blender。代码在哪里呢?搜索"Quit Blender"后发现它藏在editscreen.c中。 控制它就可以实现添加一个快捷键, 我们暂时定成Ctrl+I。
在 else if (event==QKEY) {
if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT);
else {
if(val && (G.qual & LR_CTRLKEY)) {
if(okee("Quit Blender")) exit_usiblender();
}
towin= 0;
}
} 后面加上
- ifdef INTERNATIONAL
else if (event==IKEY && (val && (G.qual & LR_CTRLKEY))) {
U.transopts^=1<<findBitIndex(USER_DOTRANSLATE);
if(U.transopts & USER_DOTRANSLATE)
start_interface_font();
else
G.ui_international = FALSE;
allqueue(REDRAWALL, 0);
}
- endif
解释一下, 1. IKEY就是I, event==IKEY检查是否按住了I。 LR_CTRLKEY自然就是左Ctrl, val && (G.qual & LR_CTRLKEY)检查是否按住了左Ctrl。 2. U.transopts^=1<<findBitIndex(USER_DOTRANSLATE);这句就是让U.transopts第5位求反。^是异或操作符, 嗯, 老师教过你异或也是可以求反的吧。如果他(or她)没教过, 好好诅咒他(or她)吧。 3. 由于你调用了findBitIndex, 它在interface.c中定义 static int findBitIndex(unsigned int x){...} 所以你要去改成int findBitIndex(unsigned int x){...} 也许你还要extern声明一下(在editscreen.c中, 包括对start_interface_fontd的声明), 不过不声明也不会得到什么错误, 只会warning一下。觉得很可怜。所以, 为了你良好的习惯, just do it。 extern int findBitIndex(unsigned int x); extern void start_interface_font(void); 4. 至于
if(U.transopts & USER_DOTRANSLATE)
start_interface_font();
else
G.ui_international = FALSE;
allqueue(REDRAWALL, 0);
你去查找B_DOLANGUIFONT便可知道, 这段代码其实就是你按下International Fonts按钮后要执行的。所以, 直接copy来用。
总结一下, 整个过程一是你要改U.transopts, 顺便改G.ui_international,刷新屏幕(REDRAWALL);二是你要定义个快捷键完成这些操作。 最后, 希望我说的你都了解了。
附: 了解uiDefButBitS的实现过程需要查看interface.c中的下面代码:
这些代码环环相扣, 其实就是实现了C++中的思想, 或者我们也可以把它们看成高级API和低级API。
uiBut *uiDefButBitS(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip) {
return uiDefButBit(block, type|SHO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
}
static uiBut *uiDefButBit(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) {
int bitIdx= findBitIndex(bit);
if (bitIdx==-1) {
return NULL;
} else {
return uiDefBut(block, type|BIT|bitIdx, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
}
}
static int findBitIndex(unsigned int x) {
if (!x || (x&(x-1))!=0) { /* x&(x-1) strips lowest bit */
return -1;
} else {
int idx= 0;
if (x&0xFFFF0000) idx+=16, x>>=16;
if (x&0xFF00) idx+=8, x>>=8;
if (x&0xF0) idx+=4, x>>=4;
if (x&0xC) idx+=2, x>>=2;
if (x&0x2) idx+=1;
return idx; }
}
uiBut *uiDefBut(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) {
uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
ui_check_but(but); return but;
}
static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) {
uiBut *but;
short slen;
if(type & BUTPOIN) { /* a pointer is required */
if(poin==NULL) {
/* if pointer is zero, button is removed and not drawn */
BIF_ThemeColor(block->themecol);
glRects(x1, y1, x1+x2, y1+y2);
return NULL;
}
}
but= MEM_callocN(sizeof(uiBut), "uiBut");
but->type= type & BUTTYPE; but->pointype= type & BUTPOIN; but->bit= type & BIT; but->bitnr= type & 31; but->icon = 0;
BLI_addtail(&block->buttons, but);
but->retval= retval;
if( strlen(str)>=UI_MAX_NAME_STR-1 ) {
but->str= MEM_callocN( strlen(str)+2, "uiDefBut");
strcpy(but->str, str);
}
else {
but->str= but->strdata;
strcpy(but->str, str);
}
but->x1= x1;
but->y1= y1;
if(block->autofill) {
but->x2= x2;
but->y2= y2;
}
else {
but->x2= (x1+x2);
but->y2= (y1+y2);
}
but->poin= poin;
but->min= min;
but->max= max;
but->a1= a1;
but->a2= a2;
but->tip= tip;
but->font= block->curfont;
but->lock= UIlock;
but->lockstr= UIlockstr;
but->aspect= block->aspect; but->win= block->win; but->block= block; // pointer back, used for frontbuffer status, and picker
if(block->themecol==TH_AUTO) but->themecol= ui_auto_themecol(but);
else but->themecol= block->themecol;
if (but->type==BUTM) {
but->butm_func= block->butm_func;
but->butm_func_arg= block->butm_func_arg;
} else {
but->func= block->func;
but->func_arg1= block->func_arg1;
but->func_arg2= block->func_arg2;
}
ui_set_embossfunc(but, block->dt); but->pos= -1; /* cursor invisible */
if(but->type==NUM) { /* add a space to name */
slen= strlen(but->str);
if(slen>0 && slen<UI_MAX_NAME_STR-2) {
if(but->str[slen-1]!=' ') {
but->str[slen]= ' ';
but->str[slen+1]= 0;
}
}
}
if(but->type==HSVCUBE) { /* hsv buttons temp storage */
float rgb[3];
ui_get_but_vectorf(but, rgb);
rgb_to_hsv(rgb[0], rgb[1], rgb[2], but->hsv, but->hsv+1, but->hsv+2);
}
if ELEM8(but->type, HSVSLI , NUMSLI, MENU, TEX, LABEL, IDPOIN, BLOCK, BUTM) {
but->flag |= UI_TEXT_LEFT;
}
if(but->type==BUT_TOGDUAL) {
but->flag |= UI_ICON_LEFT;
}
if(but->type==ROUNDBOX)
but->flag |= UI_NO_HILITE;
but->flag |= (block->flag & UI_BUT_ALIGN);
if(block->flag & UI_BLOCK_NO_HILITE)
but->flag |= UI_NO_HILITE;
return but;
}
