1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "key_binder.h"
4
5#include <base/color.h>
6
7#include <game/client/components/binds.h>
8#include <game/client/gameclient.h>
9#include <game/client/ui.h>
10#include <game/localization.h>
11
12using namespace FontIcons;
13
14bool CKeyBinder::OnInput(const IInput::CEvent &Event)
15{
16 if(!m_TakeKey)
17 {
18 return false;
19 }
20
21 if(Event.m_Flags & IInput::FLAG_RELEASE)
22 {
23 int ModifierCombination = CBinds::GetModifierMask(pInput: Input());
24 if(ModifierCombination == CBinds::GetModifierMaskOfKey(Key: Event.m_Key))
25 {
26 ModifierCombination = KeyModifier::NONE;
27 }
28 m_Key = {Event.m_Key, ModifierCombination};
29 m_TakeKey = false;
30 }
31 return true;
32}
33
34CKeyBinder::CKeyReaderResult CKeyBinder::DoKeyReader(CButtonContainer *pReaderButton, CButtonContainer *pClearButton, const CUIRect *pRect, const CBindSlot &CurrentBind, bool Activate)
35{
36 CKeyReaderResult Result = {.m_Bind: CurrentBind, .m_Aborted: false};
37
38 CUIRect KeyReaderButton, ClearButton;
39 pRect->VSplitRight(Cut: pRect->h, pLeft: &KeyReaderButton, pRight: &ClearButton);
40
41 const int ClearButtonResult = Ui()->DoButton_FontIcon(
42 pButtonContainer: pClearButton, pText: FONT_ICON_TRASH,
43 Checked: Result.m_Bind == CBindSlot(KEY_UNKNOWN, KeyModifier::NONE) ? 1 : 0,
44 pRect: &ClearButton, Flags: BUTTONFLAG_LEFT, Corners: IGraphics::CORNER_R);
45
46 const int ButtonResult = Ui()->DoButtonLogic(pId: pReaderButton, Checked: 0, pRect: &KeyReaderButton, Flags: BUTTONFLAG_LEFT | BUTTONFLAG_RIGHT);
47 if(ButtonResult == 1 || Activate)
48 {
49 m_pKeyReaderId = pReaderButton;
50 m_TakeKey = true;
51 m_Key = std::nullopt;
52 }
53 else if(ButtonResult == 2 || ClearButtonResult != 0)
54 {
55 Result.m_Bind = CBindSlot(KEY_UNKNOWN, KeyModifier::NONE);
56 }
57
58 if(m_pKeyReaderId == pReaderButton && m_Key.has_value())
59 {
60 if(m_Key.value().m_Key == KEY_ESCAPE)
61 {
62 Result.m_Aborted = true;
63 }
64 else
65 {
66 Result.m_Bind = m_Key.value();
67 }
68 m_pKeyReaderId = nullptr;
69 m_Key = std::nullopt;
70 Ui()->SetActiveItem(nullptr);
71 }
72
73 char aBuf[64];
74 if(m_pKeyReaderId == pReaderButton && m_TakeKey)
75 {
76 str_copy(dst&: aBuf, src: Localize(pStr: "Press a key…"));
77 }
78 else if(Result.m_Bind.m_Key == KEY_UNKNOWN)
79 {
80 aBuf[0] = '\0';
81 }
82 else
83 {
84 GameClient()->m_Binds.GetKeyBindName(Key: Result.m_Bind.m_Key, ModifierMask: Result.m_Bind.m_ModifierMask, pBuf: aBuf, BufSize: sizeof(aBuf));
85 }
86
87 const ColorRGBA Color = m_pKeyReaderId == pReaderButton && m_TakeKey ? ColorRGBA(0.0f, 1.0f, 0.0f, 0.4f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f * Ui()->ButtonColorMul(pId: pReaderButton));
88 KeyReaderButton.Draw(Color, Corners: IGraphics::CORNER_L, Rounding: 5.0f);
89 CUIRect Label;
90 KeyReaderButton.HMargin(Cut: 1.0f, pOtherRect: &Label);
91 Ui()->DoLabel(pRect: &Label, pText: aBuf, Size: Label.h * CUi::ms_FontmodHeight, Align: TEXTALIGN_MC);
92
93 return Result;
94}
95
96bool CKeyBinder::IsActive() const
97{
98 return m_TakeKey;
99}
100