diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index 59a623a968..9db098f315 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -196,6 +196,40 @@ static std::string KeycodeToString(uint16_t keycode) return str; } +/** + * A short representation of the keycode, for printing as a hotkey hint. + * @param keycode The keycode to convert to a string. + * @return A string representation of this keycode. + */ +std::string KeycodeToShortString(uint16_t keycode) +{ + std::string str; + if (keycode & WKC_SHIFT) { + // TODO + str += "ยป"; + } + if (keycode & WKC_CTRL) { + str += "^"; + } + if (keycode & WKC_ALT) { + str += "A+"; + } + if (keycode & WKC_META) { + str += "M+"; + } + keycode = keycode & ~WKC_SPECIAL_KEYS; + + for (const auto &kn : _keycode_to_name) { + if (kn.keycode == keycode) { + str += kn.name; + return str; + } + } + assert(keycode < 128); + str.push_back(keycode); + return str; +} + /** * Convert all keycodes attached to a hotkey to a single string. If multiple * keycodes are attached to the hotkey they are split by a comma. @@ -350,3 +384,12 @@ void HandleGlobalHotkeys([[maybe_unused]] char32_t key, uint16_t keycode) } } +const Hotkey* HotkeyList::GetHotkeyByNum(int num) const +{ + for (const Hotkey &hotkey : this->items) { + if (hotkey.num == num) { + return &hotkey; + } + } + return (const Hotkey*) nullptr; +} diff --git a/src/hotkeys.h b/src/hotkeys.h index 88b714590b..436dc70f78 100644 --- a/src/hotkeys.h +++ b/src/hotkeys.h @@ -44,6 +44,7 @@ struct HotkeyList { void Save(IniFile &ini) const; int CheckMatch(uint16_t keycode, bool global_only = false) const; + const Hotkey* GetHotkeyByNum(int num) const; GlobalHotkeyHandlerFunc global_hotkey_handler; private: @@ -64,5 +65,6 @@ void SaveHotkeysToConfig(); void HandleGlobalHotkeys(char32_t key, uint16_t keycode); +std::string KeycodeToShortString(uint16_t keycode); #endif /* HOTKEYS_H */ diff --git a/src/widget.cpp b/src/widget.cpp index a9d68d2669..0b82f623dd 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -27,6 +27,9 @@ #include "safeguards.h" +#include "widgets/toolbar_widget.h" +#include "hotkeys.h" + WidgetDimensions WidgetDimensions::scaled = {}; static std::string GetStringForWidget(const Window *w, const NWidgetCore *nwid, bool secondary = false) @@ -3108,6 +3111,63 @@ void NWidgetLeaf::Draw(const Window *w) } DrawOutline(w, this); + + // TODO: Draw hints only if Alt is being held. + if (!this->IsDisabled()) { + this->DrawHotkeyHint(w); + } +} + +void NWidgetLeaf::DrawHotkeyHint(const Window* w) { + // TODO: Use global hotkey for autoroads for rail, road, tram, etc. if + // they have been set. + + // TODO: Rect is wrong for edit boxes, and the kind of hint we're showing + // will look bad anyway. + Rect r = this->GetCurrentRect().Shrink(1); + if (w->window_desc.cls == WC_MAIN_TOOLBAR && this->index == WID_TN_FAST_FORWARD) { + // Special-case hint text for Fast-forwards because it's not really a hotkey + DrawStringMultiLine(r, "Tab", TC_WHITE, SA_LEFT | SA_BOTTOM, false, FS_NORMAL); + } else if (w->window_desc.hotkeys != nullptr) { + // Widget IDs can coincidentally overlap with hotkey IDs if + // they aren't assigned properly. Avoid this. + auto hk = w->window_desc.hotkeys->GetHotkeyByNum(this->index); + if (hk != nullptr) { + if (hk->keycodes.size()) { + // Find the "best" of the available keycodes + auto keycode = *(hk->keycodes.begin()); + for (auto k : hk->keycodes) { + if (!(keycode & WKC_GLOBAL_HOTKEY) && (k & WKC_GLOBAL_HOTKEY)) { + keycode = k; + } else if ('A' <= (k & ~WKC_SPECIAL_KEYS) && (k & ~WKC_SPECIAL_KEYS) <= 'Z') { + keycode = k; + } + } + + // Convert to a string + // TODO: Glyphs for Shift, Alt, etc. Colour for global. + // - On screen keyboard has a sprite for shift. + auto s = KeycodeToShortString(keycode); + + // Choose the font-size + auto availableSize = Dimension(r.right - r.left, r.bottom - r.top); + auto desiredSize = GetStringBoundingBox(s, FS_NORMAL); + auto fontsize = FS_NORMAL; + if (availableSize < desiredSize) { + fontsize = FS_SMALL; + } + + // Display the hints! + // TODO: not as readable as my mockup :( + // - Outline or a bolder font could help. + auto colour = TC_WHITE; + if (keycode & WKC_GLOBAL_HOTKEY) { + colour = TC_YELLOW; + } + DrawStringMultiLine(r, s, colour, SA_LEFT | SA_BOTTOM, false, fontsize); + } + } + } } /** diff --git a/src/widget_type.h b/src/widget_type.h index b7bb0ce925..09791892d1 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -922,6 +922,7 @@ public: void SetupSmallestSize(Window *w) override; void Draw(const Window *w) override; + void DrawHotkeyHint(const Window* window); bool ButtonHit(const Point &pt);