fix [#30910] Problems: Add Shortcut(s) for "Ctrl Tab" menu

comparing keymaps was too sloppy or too strict, now sloppy keymap comparison works by setting all the operator
properties to their default values if they are not already set, then compare this with the keymap item (ignoring values missing from either one).

... this way any non default keymap setting wont match with an operator menu item which doesnt set this operator at all (a problem sighted in this bug report).


developer notes:
- IDP_EqualsProperties_ex() function adds an argument to treat missing members of either group to act as if there is a match.
- WM_operator_properties_default() function to reset RNA values to their defaults.
- add IDP_spit(), debug only function to print out ID properties.
This commit is contained in:
2012-10-31 20:29:32 +00:00
parent 26541afc8b
commit 1bcadda46b
6 changed files with 139 additions and 18 deletions

View File

@@ -266,6 +266,12 @@ __attribute__((nonnull))
#endif
;
int IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const int is_strict)
#ifdef __GNUC__
__attribute__((warn_unused_result))
#endif
;
int IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2)
#ifdef __GNUC__
__attribute__((warn_unused_result))
@@ -319,4 +325,9 @@ void IDP_UnlinkProperty(struct IDProperty *prop);
#define IDP_IDPArray(prop) ((IDProperty *)(prop)->data.pointer)
#define IDP_Double(prop) (*(double *)&(prop)->data.val)
#ifdef DEBUG
/* for printout only */
void IDP_spit(IDProperty *prop);
#endif
#endif /* __BKE_IDPROP_H__ */

View File

@@ -632,12 +632,14 @@ IDProperty *IDP_GetProperties(ID *id, int create_if_needed)
}
}
int IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
/**
* \param is_strict When FALSE treat missing items as a match */
int IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const int is_strict)
{
if (prop1 == NULL && prop2 == NULL)
return 1;
else if (prop1 == NULL || prop2 == NULL)
return 0;
return is_strict ? 0 : 1;
else if (prop1->type != prop2->type)
return 0;
@@ -661,13 +663,13 @@ int IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
{
IDProperty *link1, *link2;
if (BLI_countlist(&prop1->data.group) != BLI_countlist(&prop2->data.group))
if (is_strict && BLI_countlist(&prop1->data.group) != BLI_countlist(&prop2->data.group))
return 0;
for (link1 = prop1->data.group.first; link1; link1 = link1->next) {
link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
if (!IDP_EqualsProperties(link1, link2))
if (!IDP_EqualsProperties_ex(link1, link2, is_strict))
return 0;
}
@@ -696,6 +698,11 @@ int IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
return 1;
}
int IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
{
return IDP_EqualsProperties_ex(prop1, prop2, TRUE);
}
/* 'val' is never NULL, don't check */
IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *name)
{

View File

@@ -1497,3 +1497,40 @@ PyObject *BPyInit_idprop(void)
return mod;
}
#ifdef DEBUG
/* -------------------------------------------------------------------- */
/* debug only function */
void IDP_spit(IDProperty *prop)
{
if (prop) {
PyGILState_STATE gilstate;
int use_gil = TRUE; /* !PYC_INTERPRETER_ACTIVE; */
PyObject *ret_dict;
PyObject *ret_str;
if (use_gil) {
gilstate = PyGILState_Ensure();
}
/* to_dict() */
ret_dict = BPy_IDGroup_MapDataToPy(prop);
ret_str = PyObject_Repr(ret_dict);
Py_DECREF(ret_dict);
printf("IDProperty: %s\n", _PyUnicode_AsString(ret_str));
Py_DECREF(ret_str);
if (use_gil) {
PyGILState_Release(gilstate);
}
}
else {
printf("IDProperty: <NIL>\n");
}
}
#endif

View File

@@ -214,6 +214,7 @@ int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, short c
void WM_operator_properties_alloc(struct PointerRNA **ptr, struct IDProperty **properties, const char *opstring); /* used for keymap and macro items */
void WM_operator_properties_sanitize(struct PointerRNA *ptr, const short no_context); /* make props context sensitive or not */
int WM_operator_properties_default(struct PointerRNA *ptr, const int do_update);
void WM_operator_properties_reset(struct wmOperator *op);
void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring);
void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperatorType *ot);

View File

@@ -816,7 +816,7 @@ char *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len)
static wmKeyMapItem *wm_keymap_item_find_handlers(
const bContext *C, ListBase *handlers, const char *opname, int UNUSED(opcontext),
IDProperty *properties, int compare_props, int hotkey, wmKeyMap **keymap_r)
IDProperty *properties, int is_strict, int hotkey, wmKeyMap **keymap_r)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmEventHandler *handler;
@@ -834,9 +834,22 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
if (hotkey)
if (!ISHOTKEY(kmi->type))
continue;
if (compare_props) {
if (kmi->ptr && IDP_EqualsProperties(properties, kmi->ptr->data)) {
if (properties) {
/* example of debugging keymaps */
#if 0
if (kmi->ptr) {
if (strcmp("MESH_OT_rip_move", opname) == 0) {
printf("OPERATOR\n");
IDP_spit(properties);
printf("KEYMAP\n");
IDP_spit(kmi->ptr->data);
}
}
#endif
if (kmi->ptr && IDP_EqualsProperties_ex(properties, kmi->ptr->data, is_strict)) {
if (keymap_r) *keymap_r = keymap;
return kmi;
}
@@ -857,7 +870,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
static wmKeyMapItem *wm_keymap_item_find_props(
const bContext *C, const char *opname, int opcontext,
IDProperty *properties, int compare_props, int hotkey, wmKeyMap **keymap_r)
IDProperty *properties, int is_strict, int hotkey, wmKeyMap **keymap_r)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
@@ -866,10 +879,10 @@ static wmKeyMapItem *wm_keymap_item_find_props(
/* look into multiple handler lists to find the item */
if (win)
found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
if (sa && found == NULL)
found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
if (found == NULL) {
if (ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
@@ -878,7 +891,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(
ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
if (ar)
found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
}
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_CHANNELS, WM_OP_INVOKE_REGION_CHANNELS)) {
@@ -886,18 +899,18 @@ static wmKeyMapItem *wm_keymap_item_find_props(
ar = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
if (ar)
found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) {
if (!(ar && ar->regiontype == RGN_TYPE_PREVIEW))
ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
if (ar)
found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
}
else {
if (ar)
found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, hotkey, keymap_r);
found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, hotkey, keymap_r);
}
}
@@ -906,12 +919,28 @@ static wmKeyMapItem *wm_keymap_item_find_props(
static wmKeyMapItem *wm_keymap_item_find(
const bContext *C, const char *opname, int opcontext,
IDProperty *properties, const short hotkey, const short sloppy, wmKeyMap **keymap_r)
IDProperty *properties, const short hotkey, const short UNUSED(sloppy), wmKeyMap **keymap_r)
{
wmKeyMapItem *found = wm_keymap_item_find_props(C, opname, opcontext, properties, 1, hotkey, keymap_r);
if (!found && sloppy)
found = wm_keymap_item_find_props(C, opname, opcontext, NULL, 0, hotkey, keymap_r);
if (!found && properties) {
wmOperatorType *ot = WM_operatortype_find(opname, TRUE);
if (ot) {
/* make a copy of the properties and set any unset props
* to their default values, so the ID property compare function succeeds */
PointerRNA opptr;
IDProperty *properties_default = IDP_CopyProperty(properties);
RNA_pointer_create(NULL, ot->srna, properties_default, &opptr);
if (WM_operator_properties_default(&opptr, TRUE)) {
found = wm_keymap_item_find_props(C, opname, opcontext, properties_default, 0, hotkey, keymap_r);
}
IDP_FreeProperty(properties_default);
MEM_freeN(properties_default);
}
}
return found;
}

View File

@@ -619,6 +619,42 @@ void WM_operator_properties_sanitize(PointerRNA *ptr, const short no_context)
RNA_STRUCT_END;
}
/** set all props to their default,
* \param do_update Only update un-initialized props.
*
* \note, theres nothing spesific to operators here.
* this could be made a general function.
*/
int WM_operator_properties_default(PointerRNA *ptr, const int do_update)
{
int is_change = FALSE;
RNA_STRUCT_BEGIN(ptr, prop)
{
switch (RNA_property_type(prop)) {
case PROP_POINTER:
{
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
if (ptype != &RNA_Struct) {
PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
is_change |= WM_operator_properties_default(&opptr, do_update);
}
break;
}
default:
if ((do_update == FALSE) || (RNA_property_is_set(ptr, prop) == FALSE)) {
if (RNA_property_reset(ptr, prop, -1)) {
is_change = 1;
}
}
break;
}
}
RNA_STRUCT_END;
return is_change;
}
/* remove all props without PROP_SKIP_SAVE */
void WM_operator_properties_reset(wmOperator *op)
{