Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2009-10-16 16:08:47 +0400
committerJoshua Leung <aligorith@gmail.com>2009-10-16 16:08:47 +0400
commitf6494ff3cf132e326cd18b4ec74b9d9ee61406fa (patch)
treecdd953ed1a304c1c32e9f01457a0eb820d0296e8
parent6846abb2cae3efd3e5b9943d7eba3423cbef9da3 (diff)
ShapeKey Editor (sub-mode of DopeSheet Editor)
Special priority request from Durian team to get this sub-editor of the DopeSheet Editor restored. Originally I was kindof planning to drop it, but obviously it still has a role! It now supports all the modern features that the DopeSheet supports, complete with selection, muting, locking, DopeSheet summary, and all the other tools that you know and love from the other views. Also, this no longer uses the old hacky sliders that 2.4x used (instead it uses RNA-based ones), so should function just the same as other DopeSheet views).
-rw-r--r--source/blender/blenkernel/BKE_key.h1
-rw-r--r--source/blender/blenkernel/intern/key.c25
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c198
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c32
-rw-r--r--source/blender/editors/animation/anim_filter.c82
-rw-r--r--source/blender/editors/include/ED_anim_api.h10
-rw-r--r--source/blender/makesdna/DNA_key_types.h6
7 files changed, 314 insertions, 40 deletions
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 4bfa6a41099..1b4cbc1cf2a 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -65,6 +65,7 @@ struct Key *ob_get_key(struct Object *ob);
struct KeyBlock *ob_get_keyblock(struct Object *ob);
struct KeyBlock *key_get_keyblock(struct Key *key, int index);
struct KeyBlock *key_get_named_keyblock(struct Key *key, const char name[]);
+char *key_get_curValue_rnaPath(struct Key *key, struct KeyBlock *kb);
// needed for the GE
void do_rel_key(int start, int end, int tot, char *basispoin, struct Key *key, int mode);
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index b6e4ffd6cc3..3fffdef478b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -35,6 +35,8 @@
#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+
#include "DNA_anim_types.h"
#include "DNA_curve_types.h"
#include "DNA_key_types.h"
@@ -57,7 +59,7 @@
#include "BKE_object.h"
#include "BKE_utildefines.h"
-#include "BLI_blenlib.h"
+#include "RNA_access.h"
#ifdef HAVE_CONFIG_H
@@ -1489,3 +1491,24 @@ KeyBlock *key_get_named_keyblock(Key *key, const char name[])
return NULL;
}
+
+/* Get RNA-Path for 'value' setting of the given ShapeKey
+ * NOTE: the user needs to free the returned string once they're finishe with it
+ */
+char *key_get_curValue_rnaPath(Key *key, KeyBlock *kb)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* sanity checks */
+ if ELEM(NULL, key, kb)
+ return NULL;
+
+ /* create the RNA pointer */
+ RNA_pointer_create(key, &RNA_ShapeKey, kb, &ptr);
+ /* get pointer to the property too */
+ prop= RNA_struct_find_property(&ptr, "value");
+
+ /* return the path */
+ return RNA_path_from_ID_to_property(&ptr, prop);
+}
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 7c9814eda7b..2cd41b0ffb7 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -1386,7 +1386,7 @@ static int acf_dsskey_setting_flag(int setting, short *neg)
switch (setting) {
case ACHANNEL_SETTING_EXPAND: /* expanded */
- return KEYBLOCK_DS_EXPAND;
+ return KEY_DS_EXPAND;
case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
return ADT_NLA_EVAL_OFF;
@@ -1737,28 +1737,91 @@ static bAnimChannelType ACF_DSARM=
/* ShapeKey Entry ------------------------------------------- */
-// XXX ... this is currently obsolete...
-#if 0
-static void dummy_olddraw_shapekeys ()
+/* name for ShapeKey */
+static void acf_shapekey_name(bAnimListElem *ale, char *name)
{
- case ANIMTYPE_SHAPEKEY: /* shapekey channel */
- {
- KeyBlock *kb = (KeyBlock *)ale->data;
+ KeyBlock *kb= (KeyBlock *)ale->data;
+
+ /* just copy the name... */
+ if (kb && name) {
+ /* if the KeyBlock had a name, use it, otherwise use the index */
+ if (kb->name[0])
+ strcpy(name, kb->name);
+ else
+ sprintf(name, "Key %d", ale->index);
+ }
+}
+
+/* check if some setting exists for this channel */
+static short acf_shapekey_setting_valid(bAnimContext *ac, bAnimListElem *ale, int setting)
+{
+ switch (setting) {
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted */
+ case ACHANNEL_SETTING_PROTECT: /* protected */
+ return 1;
+
+ /* nothing else is supported */
+ default:
+ return 0;
+ }
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_shapekey_setting_flag(int setting, short *neg)
+{
+ /* clear extra return data first */
+ *neg= 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_MUTE: /* mute */
+ return KEYBLOCK_MUTE;
- indent = 0;
- special = -1;
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return KEYBLOCK_SEL;
- offset= (ale->id) ? 21 : 0;
+ case ACHANNEL_SETTING_PROTECT: /* locked */
+ return KEYBLOCK_LOCKED;
- if (kb->name[0] == '\0')
- sprintf(name, "Key %d", ale->index);
- else
- strcpy(name, kb->name);
+ default: /* unsupported */
+ return 0;
}
- break;
}
-#endif
+
+/* get pointer to the setting */
+static void *acf_shapekey_setting_ptr(bAnimListElem *ale, int setting, short *type)
+{
+ KeyBlock *kb= (KeyBlock *)ale->data;
+
+ /* clear extra return data first */
+ *type= 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted */
+ case ACHANNEL_SETTING_PROTECT: /* protected */
+ GET_ACF_FLAG_PTR(kb->flag)
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+/* shapekey expander type define */
+static bAnimChannelType ACF_SHAPEKEY=
+{
+ acf_generic_channel_backdrop, /* backdrop */
+ acf_generic_indention_0, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_shapekey_name, /* name */
+ NULL, /* icon */
+
+ acf_shapekey_setting_valid, /* has setting */
+ acf_shapekey_setting_flag, /* flag for setting */
+ acf_shapekey_setting_ptr /* pointer for setting */
+};
/* Grease Pencil entries ------------------------------------------- */
// XXX ... this is currently not restored yet
@@ -1923,7 +1986,7 @@ void ANIM_init_channel_typeinfo_data (void)
animchannelTypeInfo[type++]= &ACF_DSMBALL; /* MetaBall Channel */
animchannelTypeInfo[type++]= &ACF_DSARM; /* Armature Channel */
- animchannelTypeInfo[type++]= NULL; /* ShapeKey */ // XXX this is no longer used for now...
+ animchannelTypeInfo[type++]= &ACF_SHAPEKEY; /* ShapeKey */
// XXX not restored yet
animchannelTypeInfo[type++]= NULL; /* Grease Pencil Datablock */
@@ -2237,7 +2300,57 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
}
}
-
+/* callback for shapekey widget sliders - insert keyframes */
+static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, void *kb_poin)
+{
+ Key *key= (Key *)key_poin;
+ KeyBlock *kb= (KeyBlock *)kb_poin;
+ char *rna_path= key_get_curValue_rnaPath(key, kb);
+
+ Scene *scene= CTX_data_scene(C);
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ short flag=0, done=0;
+ float cfra;
+
+ /* get current frame */
+ // NOTE: this will do for now...
+ cfra= (float)CFRA;
+
+ /* get flags for keyframing */
+ if (IS_AUTOKEY_FLAG(INSERTNEEDED))
+ flag |= INSERTKEY_NEEDED;
+ if (IS_AUTOKEY_FLAG(AUTOMATKEY))
+ flag |= INSERTKEY_MATRIX;
+ if (IS_AUTOKEY_MODE(scene, EDITKEYS))
+ flag |= INSERTKEY_REPLACE;
+
+
+ /* get RNA pointer, and resolve the path */
+ RNA_id_pointer_create((ID *)key, &id_ptr);
+
+ /* try to resolve the path stored in the F-Curve */
+ if (RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop)) {
+ /* find or create new F-Curve */
+ // XXX is the group name for this ok?
+ bAction *act= verify_adt_action((ID *)key, 1);
+ FCurve *fcu= verify_fcurve(act, NULL, rna_path, 0, 1);
+
+ /* set the special 'replace' flag if on a keyframe */
+ if (fcurve_frame_has_keyframe(fcu, cfra, 0))
+ flag |= INSERTKEY_REPLACE;
+
+ /* insert a keyframe for this F-Curve */
+ done= insert_keyframe_direct(ptr, prop, fcu, cfra, flag);
+
+ if (done)
+ WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
+ }
+
+ /* free the path */
+ if (rna_path)
+ MEM_freeN(rna_path);
+}
/* Draw a widget for some setting */
static void draw_setting_widget (bAnimContext *ac, bAnimListElem *ale, bAnimChannelType *acf, uiBlock *block, int xpos, int ypos, int setting)
@@ -2445,7 +2558,7 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b
* and wouldn't be able to auto-keyframe...
* - slider should start before the toggles (if they're visible) to keep a clean line down the side
*/
- if ((draw_sliders) && (ale->type == ANIMTYPE_FCURVE)) {
+ if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
/* adjust offset */
offset += SLIDER_WIDTH;
@@ -2453,20 +2566,49 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b
uiBlockSetEmboss(block, UI_EMBOSS);
if (ale->id) { /* Slider using RNA Access -------------------- */
- FCurve *fcu= (FCurve *)ale->data;
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
+ char *rna_path = NULL;
+ int array_index = 0;
+ short free_path = 0;
- /* get RNA pointer, and resolve the path */
- RNA_id_pointer_create(ale->id, &id_ptr);
+ /* get destination info */
+ if (ale->type == ANIMTYPE_FCURVE) {
+ FCurve *fcu= (FCurve *)ale->data;
+
+ rna_path= fcu->rna_path;
+ array_index= fcu->array_index;
+ }
+ else if (ale->type == ANIMTYPE_SHAPEKEY) {
+ KeyBlock *kb= (KeyBlock *)ale->data;
+ Key *key= (Key *)ale->id;
+
+ rna_path= key_get_curValue_rnaPath(key, kb);
+ free_path= 1;
+ }
- /* try to resolve the path */
- if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) {
- uiBut *but;
+ /* only if RNA-Path found */
+ if (rna_path) {
+ /* get RNA pointer, and resolve the path */
+ RNA_id_pointer_create(ale->id, &id_ptr);
+
+ /* try to resolve the path */
+ if (RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop)) {
+ uiBut *but;
+
+ /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */
+ but= uiDefAutoButR(block, &ptr, prop, array_index, "", 0, (int)v2d->cur.xmax-offset, ymid, SLIDER_WIDTH, (int)ymaxc-yminc);
+
+ /* assign keyframing function according to slider type */
+ if (ale->type == ANIMTYPE_SHAPEKEY)
+ uiButSetFunc(but, achannel_setting_slider_shapekey_cb, ale->id, ale->data);
+ else
+ uiButSetFunc(but, achannel_setting_slider_cb, ale->id, ale->data);
+ }
- /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */
- but= uiDefAutoButR(block, &ptr, prop, fcu->array_index, "", 0, (int)v2d->cur.xmax-offset, ymid, SLIDER_WIDTH, (int)ymaxc-yminc);
- uiButSetFunc(but, achannel_setting_slider_cb, ale->id, fcu);
+ /* free the path if necessary */
+ if (free_path)
+ MEM_freeN(rna_path);
}
}
else { /* Special Slider for stuff without RNA Access ---------- */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 3b6c7fad471..efdad53f89f 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -238,6 +238,10 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
if (ale->flag & FCURVE_SELECTED)
sel= ACHANNEL_SETFLAG_CLEAR;
break;
+ case ANIMTYPE_SHAPEKEY:
+ if (ale->flag & KEYBLOCK_SEL)
+ sel= ACHANNEL_SETFLAG_CLEAR;
+ break;
case ANIMTYPE_NLATRACK:
if (ale->flag & NLATRACK_SELECTED)
sel= ACHANNEL_SETFLAG_CLEAR;
@@ -307,6 +311,13 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
fcu->flag &= ~FCURVE_ACTIVE;
}
break;
+ case ANIMTYPE_SHAPEKEY:
+ {
+ KeyBlock *kb= (KeyBlock *)ale->data;
+
+ ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL);
+ }
+ break;
case ANIMTYPE_NLATRACK:
{
NlaTrack *nlt= (NlaTrack *)ale->data;
@@ -1520,6 +1531,24 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
notifierFlags |= ND_ANIMCHAN_SELECT;
}
break;
+ case ANIMTYPE_SHAPEKEY:
+ {
+ KeyBlock *kb= (KeyBlock *)ale->data;
+
+ /* select/deselect */
+ if (selectmode == SELECT_INVERT) {
+ /* inverse selection status of this ShapeKey only */
+ kb->flag ^= KEYBLOCK_SEL;
+ }
+ else {
+ /* select ShapeKey by itself */
+ ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ kb->flag |= KEYBLOCK_SEL;
+ }
+
+ notifierFlags |= ND_ANIMCHAN_SELECT;
+ }
+ break;
case ANIMTYPE_GPDATABLOCK:
{
bGPdata *gpd= (bGPdata *)ale->data;
@@ -1557,9 +1586,6 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
#endif // XXX future of this is unclear
}
break;
- case ANIMTYPE_SHAPEKEY:
- /* TODO: shapekey channels cannot be selected atm... */
- break;
default:
printf("Error: Invalid channel type in mouse_anim_channels() \n");
}
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index ea097420d1a..84da3662661 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -647,6 +647,36 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s
ale->datatype= ALE_FCURVE;
}
break;
+
+ case ANIMTYPE_SHAPEKEY:
+ {
+ KeyBlock *kb= (KeyBlock *)data;
+ Key *key= (Key *)ale->id;
+
+ ale->flag= kb->flag;
+
+ /* whether we have keyframes depends on whether there is a Key block to find it from */
+ if (key) {
+ /* index of shapekey is defined by place in key's list */
+ ale->index= BLI_findindex(&key->block, kb);
+
+ /* the corresponding keyframes are from the animdata */
+ if (ale->adt && ale->adt->action) {
+ bAction *act= ale->adt->action;
+ char *rna_path = key_get_curValue_rnaPath(key, kb);
+
+ /* try to find the F-Curve which corresponds to this exactly,
+ * then free the MEM_alloc'd string
+ */
+ if (rna_path) {
+ ale->key_data= list_find_fcurve(&act->curves, rna_path, 0);
+ MEM_freeN(rna_path);
+ }
+ }
+ ale->datatype= (ale->key_data)? ALE_FCURVE : ALE_NONE;
+ }
+ }
+ break;
case ANIMTYPE_GPLAYER:
{
@@ -892,7 +922,51 @@ static int animdata_filter_nla (ListBase *anim_data, bDopeSheet *ads, AnimData *
/* return the number of items added to the list */
return items;
}
-
+
+/* Include ShapeKey Data for ShapeKey Editor */
+static int animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode)
+{
+ int items = 0;
+
+ /* check if channels or only F-Curves */
+ if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {
+ bAnimListElem *ale;
+ KeyBlock *kb;
+
+ /* loop through the channels adding ShapeKeys as appropriate */
+ for (kb= key->block.first; kb; kb= kb->next) {
+ /* skip the first one, since that's the non-animateable basis */
+ // XXX maybe in future this may become handy?
+ if (kb == key->block.first) continue;
+
+ /* only work with this channel and its subchannels if it is editable */
+ if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
+ /* only include this track if selected in a way consistent with the filtering requirements */
+ if ( ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb)) ) {
+ // TODO: consider 'active' too?
+
+ /* owner-id here must be key so that the F-Curve can be resolved... */
+ ale= make_new_animlistelem(kb, ANIMTYPE_SHAPEKEY, NULL, ANIMTYPE_NONE, (ID *)key);
+
+ if (ale) {
+ BLI_addtail(anim_data, ale);
+ items++;
+ }
+ }
+ }
+ }
+ }
+ else {
+ /* just use the action associated with the shapekey */
+ // FIXME: is owner-id and having no owner/dopesheet really fine?
+ if (key->adt && key->adt->action)
+ items= animdata_filter_action(anim_data, NULL, key->adt->action, filter_mode, NULL, ANIMTYPE_NONE, (ID *)key);
+ }
+
+ /* return the number of items added to the list */
+ return items;
+}
+
#if 0
// FIXME: switch this to use the bDopeSheet...
static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode)
@@ -1944,9 +2018,11 @@ int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode
}
break;
- case ANIMCONT_SHAPEKEY:
+ case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
{
- //items= animdata_filter_shapekey(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
+ /* the check for the DopeSheet summary is included here since the summary works here too */
+ if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
+ items= animdata_filter_shapekey(anim_data, data, filter_mode);
}
break;
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 271827c2aba..316f1b58d33 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -99,7 +99,7 @@ typedef struct bAnimListElem {
void *data; /* source data this elem represents */
int type; /* one of the ANIMTYPE_* values */
int flag; /* copy of elem's flags for quick access */
- int index; /* copy of adrcode where applicable */
+ int index; /* for un-named data, the index of the data in it's collection */
void *key_data; /* motion data - mostly F-Curves, but can be other types too */
short datatype; /* type of motion data to expect */
@@ -144,7 +144,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSMBALL,
ANIMTYPE_DSARM,
- ANIMTYPE_SHAPEKEY, // XXX probably can become depreceated???
+ ANIMTYPE_SHAPEKEY,
ANIMTYPE_GPDATABLOCK,
ANIMTYPE_GPLAYER,
@@ -209,7 +209,7 @@ typedef enum eAnimFilter_Flags {
#define FILTER_MAT_OBJC(ob) ((ob->nlaflag & OB_ADS_SHOWMATS))
#define FILTER_PART_OBJC(ob) ((ob->nlaflag & OB_ADS_SHOWPARTS))
/* 'Sub-object' channels (flags stored in Data block) */
-#define FILTER_SKE_OBJD(key) ((key->flag & KEYBLOCK_DS_EXPAND))
+#define FILTER_SKE_OBJD(key) ((key->flag & KEY_DS_EXPAND))
#define FILTER_MAT_OBJD(ma) ((ma->flag & MA_DS_EXPAND))
#define FILTER_LAM_OBJD(la) ((la->flag & LA_DS_EXPAND))
#define FILTER_CAM_OBJD(ca) ((ca->flag & CAM_DS_EXPAND))
@@ -232,6 +232,10 @@ typedef enum eAnimFilter_Flags {
#define EDITABLE_FCU(fcu) ((fcu->flag & FCURVE_PROTECTED)==0)
#define SEL_FCU(fcu) (fcu->flag & (FCURVE_ACTIVE|FCURVE_SELECTED))
+/* ShapeKey mode only */
+#define EDITABLE_SHAPEKEY(kb) ((kb->flag & KEYBLOCK_LOCKED)==0)
+#define SEL_SHAPEKEY(kb) (kb->flag & KEYBLOCK_SEL)
+
/* Grease Pencil only */
/* Grease Pencil datablock settings */
#define EXPANDED_GPD(gpd) (gpd->flag & GP_DATA_EXPAND)
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
index c42e555d562..e86abf12424 100644
--- a/source/blender/makesdna/DNA_key_types.h
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -80,6 +80,7 @@ typedef struct Key {
#define KEY_RELATIVE 1
/* key->flag */
+#define KEY_DS_EXPAND 1
/* keyblock->type */
#define KEY_LINEAR 0
@@ -87,8 +88,9 @@ typedef struct Key {
#define KEY_BSPLINE 2
/* keyblock->flag */
-#define KEYBLOCK_MUTE 1
-#define KEYBLOCK_DS_EXPAND 2
+#define KEYBLOCK_MUTE (1<<0)
+#define KEYBLOCK_SEL (1<<1)
+#define KEYBLOCK_LOCKED (1<<2)
#endif