diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index d4cde172123..6dc15d98766 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -2545,6 +2545,12 @@ bool uiTemplateEventFromKeymapItem(uiLayout *layout, const wmKeyMapItem *kmi, bool text_fallback); +/* Draw keymap item for status bar. Returns number of items consumed, + * as X/Y/Z items may get merged to use less space. */ +int uiTemplateStatusBarModalItem(uiLayout *layout, + const wmKeyMap *keymap, + const EnumPropertyItem *item); + void uiTemplateComponentMenu(uiLayout *layout, PointerRNA *ptr, const char *propname, diff --git a/source/blender/editors/interface/templates/interface_templates.cc b/source/blender/editors/interface/templates/interface_templates.cc index 1c0f36c9333..49436bbe3ee 100644 --- a/source/blender/editors/interface/templates/interface_templates.cc +++ b/source/blender/editors/interface/templates/interface_templates.cc @@ -6519,6 +6519,89 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr) /** \name Event Icon Template * \{ */ +static const wmKeyMapItem *keymap_item_from_enum_item(const wmKeyMap *keymap, + const EnumPropertyItem *item) +{ + if (item == nullptr) { + return nullptr; + } + + for (wmKeyMapItem *kmi = static_cast(keymap->items.first); kmi; kmi = kmi->next) + { + if (kmi->val == KM_RELEASE) { + /* Assume release events just disable something which was toggled on. */ + continue; + } + if (kmi->propvalue == item->value) { + return kmi; + } + } + + return nullptr; +} + +static bool keymap_item_can_collapse(const wmKeyMapItem *kmi_a, const wmKeyMapItem *kmi_b) +{ + return (kmi_a->shift == kmi_b->shift && kmi_a->ctrl == kmi_b->ctrl && kmi_a->alt == kmi_b->alt && + kmi_a->oskey == kmi_b->oskey); +} + +int uiTemplateStatusBarModalItem(uiLayout *layout, + const wmKeyMap *keymap, + const EnumPropertyItem *item) +{ + const wmKeyMapItem *kmi = keymap_item_from_enum_item(keymap, item); + if (kmi == nullptr) { + return 0; + } + + /* Try to merge some known XYZ items to save horizontal space. */ + const EnumPropertyItem *item_y = (item[1].identifier) ? item + 1 : nullptr; + const EnumPropertyItem *item_z = (item_y && item[2].identifier) ? item + 2 : nullptr; + const wmKeyMapItem *kmi_y = keymap_item_from_enum_item(keymap, item_y); + const wmKeyMapItem *kmi_z = keymap_item_from_enum_item(keymap, item_z); + + if (kmi_y && kmi_z && keymap_item_can_collapse(kmi, kmi_y) && + keymap_item_can_collapse(kmi_y, kmi_z)) + { + const char *xyz_label = nullptr; + + if (STREQ(item->identifier, "AXIS_X") && STREQ(item_y->identifier, "AXIS_Y") && + STREQ(item_z->identifier, "AXIS_Z")) + { + xyz_label = IFACE_("Axis"); + } + else if (STREQ(item->identifier, "PLANE_X") && STREQ(item_y->identifier, "PLANE_Y") && + STREQ(item_z->identifier, "PLANE_Z")) + { + xyz_label = IFACE_("Plane"); + } + + if (xyz_label) { + int icon_mod[4]; + int icon = UI_icon_from_keymap_item(kmi, icon_mod); + for (int j = 0; j < ARRAY_SIZE(icon_mod) && icon_mod[j]; j++) { + uiItemL(layout, "", icon_mod[j]); + } + uiItemL(layout, "", icon); + + icon = UI_icon_from_keymap_item(kmi_y, icon_mod); + uiItemL(layout, "", icon); + + icon = UI_icon_from_keymap_item(kmi_z, icon_mod); + uiItemL(layout, "", icon); + + uiItemS_ex(layout, 0.6f); + uiItemL(layout, xyz_label, ICON_NONE); + uiItemS_ex(layout, 0.7f); + return 3; + } + } + + /* Single item without merging. */ + return uiTemplateEventFromKeymapItem(layout, item->name, kmi, false) ? 1 : 0; +} + bool uiTemplateEventFromKeymapItem(uiLayout *layout, const char *text, const wmKeyMapItem *kmi, diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 6ae52037fff..534b90e6459 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -6388,32 +6388,16 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la continue; } - bool show_text = true; - - { - /* WARNING: O(n^2). */ - wmKeyMapItem *kmi = nullptr; - for (kmi = static_cast(keymap->items.first); kmi; kmi = kmi->next) { - if (kmi->propvalue == items[i].value) { - break; - } - } - if (kmi != nullptr) { - if (kmi->val == KM_RELEASE) { - /* Assume release events just disable something which was toggled on. */ - continue; - } - if (uiTemplateEventFromKeymapItem(row, items[i].name, kmi, false)) { - show_text = false; - } - } + const int num_items_used = uiTemplateStatusBarModalItem(row, keymap, items + i); + if (num_items_used > 0) { + /* Skip items in case consecutive items were merged. */ + i += num_items_used - 1; } - if (show_text) { - if (std::optional str = WM_modalkeymap_operator_items_to_string( - op->type, items[i].value, true)) - { - uiItemL(row, fmt::format("{}: {}", *str, items[i].name).c_str(), ICON_NONE); - } + else if (std::optional str = WM_modalkeymap_operator_items_to_string( + op->type, items[i].value, true)) + { + /* Show text instead */ + uiItemL(row, fmt::format("{}: {}", *str, items[i].name).c_str(), ICON_NONE); } } return true;