-
Notifications
You must be signed in to change notification settings - Fork 0
/
ui
222 lines (179 loc) · 7.01 KB
/
ui
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#pragma once
#include "uii"
#include <vector>
namespace ogl
{
struct ProgramRef;
}
namespace text
{
struct FreeTypeRef;
struct FaceRef;
struct TextRenderer;
}
namespace ui
{
struct TextRenderer
{
enum CharType
{
UTF8,
UTF16,
UTF32
};
template <class Char, size_t Size = sizeof(Char)> struct CharTypeFromChar;
template <class Char> struct CharTypeFromChar<Char, 1> { static CharType const value = UTF8; };
template <class Char> struct CharTypeFromChar<Char, 2> { static CharType const value = UTF16; };
template <class Char> struct CharTypeFromChar<Char, 4> { static CharType const value = UTF32; };
virtual glm::aabb<glm::ivec2> selectChar(glm::ivec2 cursorPos, size_t& charIdx, glm::ivec2 insertPos, char const* text, size_t maxChars, CharType type) = 0;
template <class Char>
inline glm::aabb<glm::ivec2> selectChar(glm::ivec2 cursorPos, size_t& charIdx, glm::ivec2 insertPos, Char const* text, size_t maxChars = ~0, CharType type = CharTypeFromChar<Char>::value)
{ return selectChar(cursorPos, charIdx, insertPos, reinterpret_cast<char const*>(text), maxChars, type); }
virtual glm::aabb<glm::ivec2> boundText(char const* text, size_t maxChars, glm::ivec2 insertPos, CharType type) = 0;
template <class Char>
inline glm::aabb<glm::ivec2> boundText(Char const* text, size_t maxChars = ~0, glm::ivec2 insertPos = glm::ivec2(0), CharType type = CharTypeFromChar<Char>::value)
{ return boundText(reinterpret_cast<char const*>(text), maxChars, insertPos, type); }
virtual glm::aabb<glm::ivec2> drawText(glm::ivec2 insertPos, char const* text, size_t maxChars, CharType type) = 0;
template <class Char>
inline glm::aabb<glm::ivec2> drawText(glm::ivec2 insertPos, Char const* text, size_t maxChars = ~0, CharType type = CharTypeFromChar<Char>::value)
{ return drawText(insertPos, reinterpret_cast<char const*>(text), maxChars, type); }
virtual void flushText() = 0;
};
struct UiTextRenderer : TextRenderer
{
text::FreeTypeRef& lib;
text::FaceRef& font;
text::TextRenderer& renderer;
UiTextRenderer(text::FreeTypeRef& lib, text::FaceRef& font, text::TextRenderer& renderer)
: lib(lib), font(font), renderer(renderer) { }
virtual ~UiTextRenderer() { }
glm::aabb<glm::ivec2> selectChar(glm::ivec2 cursorPos, size_t& charIdx, glm::ivec2 insertPos, char const* text, size_t maxChars, CharType type) override;
using TextRenderer::selectChar;
glm::aabb<glm::ivec2> boundText(char const* text, size_t maxChars, glm::ivec2 insertPos, CharType type) override;
using TextRenderer::boundText;
glm::aabb<glm::ivec2> drawText(glm::ivec2 insertPos, char const* text, size_t maxChars, CharType type) override;
using TextRenderer::drawText;
void flushText() override;
static std::unique_ptr<UiTextRenderer> create(text::FreeTypeRef* freeTypeLib, text::FaceRef* font, ogl::ProgramRef* textProgram);
};
struct Mouse
{
bool primary, primaryChanged;
bool secondary, secondaryChanged;
glm::ivec2 pos;
};
struct CaptureState
{
enum T
{
Available,
Owned,
Unavailable
};
};
struct Cursor
{
int row;
int column;
glm::ivec2 pos;
};
struct InputKeys
{
// key in groups <=> key & (mask1 | mask2 | ...) > MatchStart
static unsigned const MatchStart = 0x80000000;
static bool matches(unsigned key, unsigned masks) { return (key & masks) > MatchStart; }
// Values > KeyStart are keys
static unsigned const KeyStart = MatchStart;
static bool isKey(unsigned key) { return key > KeyStart; }
static unsigned const ManipKeyMask = MatchStart + 0x01000000;
static unsigned const DeleteLast = ManipKeyMask + 1;
static unsigned const DeleteNext = ManipKeyMask + 2;
static unsigned const NavKeyMask = MatchStart + 0x02000000;
static unsigned const MoveUp = NavKeyMask + 1;
static unsigned const MoveDown = NavKeyMask + 2;
static unsigned const MoveLeft = NavKeyMask + 3;
static unsigned const MoveRight = NavKeyMask + 4;
static unsigned const ControlKeyMask = MatchStart + 0x04000000;
static unsigned const Control = ControlKeyMask + 1;
static unsigned const Alternative = ControlKeyMask + 2;
static unsigned const SelectKeyMask = MatchStart + 0x08000000;
static unsigned const Select = SelectKeyMask + 1;
};
struct UniversalInterface::Button
{
UniqueElementIdentifier id;
glm::aabb<glm::ivec2> rect;
bool pressed;
};
struct UniversalInterface::Slider
{
UniqueElementIdentifier id;
glm::aabb<glm::ivec2> rect;
float value;
float range;
float valueBase;
};
struct UserInterface
{
struct Options
{
unsigned indent, lineHeight;
int labelDelta, controlBaseline;
explicit Options(unsigned lineHeight = 24, unsigned indent = 3, int labelDelta = 12, int controlBaseline = -3)
: indent(indent)
, lineHeight(lineHeight)
, labelDelta(labelDelta)
, controlBaseline(controlBaseline) { }
};
struct Setup
{
Options options;
glm::aabb<glm::ivec2> rect;
} setup;
struct State
{
std::vector<UniqueElementIdentifier> entryPath;
std::vector<UniqueElementIdentifier> focusPath;
std::vector<UniqueElementIdentifier> capturePath;
std::vector<UniqueElementIdentifier> captureReleasedPath;
Cursor cursor;
bool cursorVisible;
bool focus;
Mouse mouse;
std::vector<unsigned> input;
} state;
struct Context
{
std::vector<UniqueElementIdentifier> parentPath;
std::vector<unsigned> pendingInput;
glm::ivec2 insertPos;
} context;
virtual ~UserInterface() { }
// prepare internal state for next cycle
virtual UniversalInterface& reset() = 0;
virtual UniversalInterface& reset(Mouse const& mouse, stdx::data_range_param<unsigned const> input) = 0;
// override input capture
virtual void capture(stdx::data_range_param<UniqueElementIdentifier> path, UniqueElementIdentifier id) = 0;
virtual CaptureState::T captureState(stdx::data_range_param<UniqueElementIdentifier> path, UniqueElementIdentifier id) const = 0;
virtual bool wasCaptureReleased(stdx::data_range_param<UniqueElementIdentifier> path, UniqueElementIdentifier id) const = 0;
bool capturedOrAcquired(stdx::data_range_param<UniqueElementIdentifier> path, UniqueElementIdentifier id, bool acquire)
{
auto state = captureState(path, id);
if (acquire && state == CaptureState::Available)
{
capture(path, id);
return true;
}
else
return (state == CaptureState::Owned);
}
static std::unique_ptr<UserInterface> create(text::FreeTypeRef* freeTypeLib, text::FaceRef* font, ogl::ProgramRef* textProgram
, ogl::ProgramRef* widgetProgram);
// todo: replace by proper render methods
virtual void flushWidgets() = 0;
virtual void flushText() = 0;
};
void preset_user_interface(UniversalInterface& ui, stdx::fun_ref<void(UniversalInterface&)> target,
char const* defaultFile = nullptr, char const* activeFilePath = nullptr, ui::UniversalInterface::InteractionParam<char const*> activeFileChange = nullptr,
char const* groupName = nullptr, UniqueElementIdentifier id = nullptr);
} // namespace