Repository navigation
Expand file tree
/
Copy pathButtonComponent.h
More file actions
127 lines (103 loc) · 4.07 KB
/
Copy pathButtonComponent.h
File metadata and controls
127 lines (103 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once
#include <stdint.h>
#include <functional>
#include <vector>
#include <deki/Component.h>
#include <deki/reflection/Property.h>
#include <deki/reflection/ObjectRef.h>
#include "FocusSystem.h"
namespace Deki
{
class Object;
}
namespace DekiInput
{
class InputCollider;
}
namespace Deki2D
{
/// What a button is doing, for visual feedback.
enum class ButtonState : uint8_t
{
Normal = 0,
Hovered = 1, // Mouse or finger over the button
Pressed = 2,
Disabled = 3 // Ignores input
};
using ButtonCallback = std::function<void()>;
/// Button behaviour only: clicks, hover and state. Drawing is left to a style
/// component that watches the state.
///
/// It gets input from a DekiInput::InputCollider, on the same object or
/// another one, named by `inputCollider` (as a Unity button needs a
/// Collider2D). It fires callbacks on click, press, release and hover.
///
/// The arrow keys and a trackball reach it through FocusSystem: while it has
/// keyboard focus it shows the Hovered state, and Enter or Space clicks it.
///
/// Example:
///
/// auto* entity = new Deki::Object("Button");
/// auto* collider = entity->AddComponent<DekiInput::InputCollider>();
/// collider->width = 100;
/// collider->height = 40;
/// auto* button = entity->AddComponent<ButtonComponent>();
/// button->inputCollider.Set(entity);
/// button->AddOnClickCallback([]() { /* handle the click */ });
DEKI_CATEGORY("2D")
DEKI_DESCRIPTION("Makes the object a button: tracks hover and press, and fires a click callback.")
class ButtonComponent : public Deki::Component, public IFocusable
{
public:
DEKI_EXPORT
DEKI_TOOLTIP("The hit area that makes this button clickable. Without one the button has no way to notice a press.")
Deki::ObjectRef<DekiInput::InputCollider> inputCollider;
DEKI_EXPORT
DEKI_TOOLTIP(
"Normal, hovered, pressed or disabled. Set by input; a style component watches it to decide what to draw.")
ButtonState state;
DEKI_EXPORT
DEKI_TOOLTIP(
"A disabled button ignores input and reports the disabled state, so it can be greyed out rather than hidden.")
bool isEnabled;
// Runtime-only listeners, added with the Add*Callback methods
std::vector<ButtonCallback> onClick;
std::vector<ButtonCallback> onPress;
std::vector<ButtonCallback> onRelease;
std::vector<ButtonCallback> onHoverEnter;
std::vector<ButtonCallback> onHoverExit;
std::vector<std::function<void(ButtonState)>> onStateChanged;
ButtonComponent();
virtual ~ButtonComponent();
// Deki::Component lifecycle
void Start() override;
/// Sets the state and fires the hover and state-changed callbacks it causes.
void SetState(ButtonState newState);
ButtonState GetState() const { return state; }
/// Enables or disables the button. Disabling it also drops any press in
/// progress.
void SetEnabled(bool enabled);
bool IsEnabled() const { return isEnabled; }
// Each adds one more listener
void AddOnClickCallback(const ButtonCallback& callback);
void AddOnPressCallback(const ButtonCallback& callback);
void AddOnReleaseCallback(const ButtonCallback& callback);
void AddOnHoverEnterCallback(const ButtonCallback& callback);
void AddOnHoverExitCallback(const ButtonCallback& callback);
void AddOnStateChangedCallback(const std::function<void(ButtonState)>& callback);
/// Cancels a press in progress, such as when scrolling starts. The button
/// returns to Normal and fires release but not click.
void CancelPress();
/// Clicks it as a tap would: press, release and click, in that order.
void Click();
// IFocusable
Deki::Object* GetFocusObject() const override { return GetOwner(); }
bool CanFocus() const override { return isEnabled; }
void GetFocusSize(float& w, float& h) const override;
void OnFocusChanged(bool focused) override;
bool OnFocusKey(uint32_t key, uint32_t character) override;
private:
bool m_WasPressedInside = false;
void InvokeCallbacks(const std::vector<ButtonCallback>& callbacks);
};
} // namespace Deki2D