summary refs log tree commit diff
path: root/src/Widgets.h
blob: 0e57dab2d0381fac9f7661e895e5cbd2a3005d78 (plain)
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#ifndef CC_WIDGETS_H
#define CC_WIDGETS_H
#include "Gui.h"
#include "BlockID.h"
#include "Constants.h"
#include "Entity.h"
#include "Inventory.h"
#include "IsometricDrawer.h"
/* Contains all 2D widget implementations.
   Copyright 2014-2023 ClassiCube | Licensed under BSD-3
*/
struct FontDesc;

/* A text label. */
struct TextWidget {
	Widget_Body
	struct Texture tex;
	PackedCol color;
};
#define TEXTWIDGET_MAX 4

/* Initialises a text widget. */
CC_NOINLINE void TextWidget_Init(struct TextWidget* w);
/* Initialises then adds a text widget. */
CC_NOINLINE void TextWidget_Add(void* screen, struct TextWidget* w);
/* Draws the given text into a texture, then updates the position and size of this widget. */
CC_NOINLINE void TextWidget_Set(struct TextWidget* w, const cc_string* text, struct FontDesc* font);
/* Shorthand for TextWidget_Set using String_FromReadonly */
CC_NOINLINE void TextWidget_SetConst(struct TextWidget* w, const char* text, struct FontDesc* font);


typedef void (*Button_Get)(cc_string* raw);
typedef void (*Button_Set)(const cc_string* raw);
/* A labelled button that can be clicked on. */
struct ButtonWidget {
	Widget_Body
	struct Texture tex;
	PackedCol color;
	int minWidth, minHeight;
	const char* optName;
	Button_Get GetValue;
	Button_Set SetValue;
};
#define BUTTONWIDGET_MAX 12

/* Initialises a button widget. */
CC_NOINLINE void ButtonWidget_Init(struct ButtonWidget* w, int minWidth, Widget_LeftClick onClick);
/* Initialises then adds a button widget. */
CC_NOINLINE void ButtonWidget_Add(void* screen, struct ButtonWidget* w, int minWidth, Widget_LeftClick onClick);
/* Draws the given text into a texture, then updates the position and size of this widget. */
CC_NOINLINE void ButtonWidget_Set(struct ButtonWidget* w, const cc_string* text, struct FontDesc* font);
/* Shorthand for ButtonWidget_Set using String_FromReadonly */
CC_NOINLINE void ButtonWidget_SetConst(struct ButtonWidget* w, const char* text, struct FontDesc* font);

/* Clickable and draggable scrollbar. */
struct ScrollbarWidget {
	Widget_Body
	int topRow, rowsTotal, rowsVisible;
	float scrollingAcc;
	int dragOffset;
	int draggingId, padding;
	int borderX, borderY;
	int nubsWidth, offsets[3];
};
/* Resets state of the given scrollbar widget to default. */
CC_NOINLINE void ScrollbarWidget_Create(struct ScrollbarWidget* w, int width);

#define HOTBAR_CORE_VERTICES (INVENTORY_BLOCKS_PER_HOTBAR * ISOMETRICDRAWER_MAXVERTICES)
/* A row of blocks with a background. */
struct HotbarWidget {
	Widget_Body
	struct Texture selTex, backTex;
	float slotWidth, selWidth;
	float slotXOffset, elemSize;
	float scrollAcc, scale;
	cc_bool altHandled;
	struct Texture ellipsisTex;
	int state[HOTBAR_CORE_VERTICES / 4];
	int verticesCount;
	int touchId[HOTBAR_MAX_INDEX];
	float touchTime[HOTBAR_MAX_INDEX];
};
#define HOTBAR_MAX_VERTICES (4 + 4 + HOTBAR_CORE_VERTICES)

/* Resets state of the given hotbar widget to default. */
CC_NOINLINE void HotbarWidget_Create(struct HotbarWidget* w);
CC_NOINLINE void HotbarWidget_SetFont(struct HotbarWidget* w, struct FontDesc* font);
CC_NOINLINE void HotbarWidget_Update(struct HotbarWidget* w, float delta);

#define TABLE_MAX_VERTICES (8 * 10 * ISOMETRICDRAWER_MAXVERTICES)
/* A table of blocks. */
struct TableWidget {
	Widget_Body
	int blocksCount, blocksPerRow;
	int rowsTotal, rowsVisible;
	int lastCreatedIndex;
	int selectedIndex, cellSizeX, cellSizeY;
	float normBlockSize, selBlockSize;
	GfxResourceID vb;
	cc_bool pendingClose, everCreated;
	float scale;
	float padXAcc, padYAcc;

	BlockID blocks[BLOCK_COUNT];
	struct ScrollbarWidget scroll;
	int lastX, lastY, paddingX;
	int paddingL, paddingR, paddingT, paddingB;
	void (*UpdateTitle)(BlockID block);

	int state[TABLE_MAX_VERTICES / 4];
	int verticesCount;
};

CC_NOINLINE void TableWidget_Add(void* screen, struct TableWidget* w, int sbWidth);
/* Sets the selected block in the table to the given block. */
/* Also adjusts scrollbar and moves cursor to be over the given block. */
CC_NOINLINE void TableWidget_SetToBlock(struct TableWidget* w, BlockID block);
CC_NOINLINE void TableWidget_SetToIndex(struct TableWidget* w, int index);
CC_NOINLINE void TableWidget_RecreateBlocks(struct TableWidget* w);
CC_NOINLINE void TableWidget_OnInventoryChanged(struct TableWidget* w);
CC_NOINLINE void TableWidget_RecreateTitle(struct TableWidget* w, cc_bool force);


#define INPUTWIDGET_MAX_LINES 3
#define INPUTWIDGET_LEN STRING_SIZE
struct InputWidget {
	Widget_Body
	struct FontDesc* font;
	int  (*GetMaxLines)(void);
	void (*RemakeTexture)(void* elem);  /* Remakes the raw texture containing all the chat lines. Also updates dimensions. */
	void (*OnPressedEnter)(void* elem); /* Invoked when the user presses enter. */
	cc_bool (*AllowedChar)(void* elem, char c);
	void (*OnTextChanged)(void* elem); /* Callback invoked whenever text changes. */

	cc_string text; /* The actual raw text */
	cc_string lines[INPUTWIDGET_MAX_LINES];   /* text of each line after word wrapping */
	int lineWidths[INPUTWIDGET_MAX_LINES]; /* Width of each line in pixels */
	int lineHeight; /* Height of a line in pixels */
	struct Texture inputTex;
	int prefixWidth;
	cc_bool convertPercents;

	cc_uint8 padding;
	cc_bool showCaret;
	int caretWidth;
	int caretX, caretY; /* Coordinates of caret in lines */
	int caretPos;       /* Position of caret, -1 for at end of string */
	int caretOffset;
	PackedCol caretCol;
	struct Texture caretTex;
	float caretAccumulator;
};

/* Removes all characters and then deletes the input texture. */
CC_NOINLINE void InputWidget_Clear(struct InputWidget* w);
/* Tries appending all characters from the given string, then update the input texture. */
CC_NOINLINE void InputWidget_AppendText(struct InputWidget* w, const cc_string* text);
/* Tries appending the given character, then updates the input texture. */
CC_NOINLINE void InputWidget_Append(struct InputWidget* w, char c);
/* Redraws text and recalculates associated state. */
/* Also calls OnscreenKeyboard_SetText with the text in the input widget. */
/* This way native text input state stays synchronised with the input widget. */
/* (e.g. may only accept numerical input, so 'c' gets stripped from str) */
CC_NOINLINE void InputWidget_UpdateText(struct InputWidget* w);
/* Shorthand for InputWidget_Clear followed by InputWidget_AppendText, */
/* then calls OnscreenKeyboard_SetText with the text in the input widget. */
/* This way native text input state stays synchronised with the input widget. */
/* (e.g. may only accept numerical input, so 'c' gets stripped from str) */
CC_NOINLINE void InputWidget_SetText(struct InputWidget* w, const cc_string* str);


struct MenuInputDesc;
struct MenuInputVTABLE {
	/* Returns a description of the range of valid values (e.g. "0 - 100") */
	void (*GetRange)(struct MenuInputDesc*         d, cc_string* range);
	/* Whether the given character is acceptable for this input */
	cc_bool (*IsValidChar)(struct MenuInputDesc*   d, char c);
	/* Whether the characters of the given string are acceptable for this input */
	/* e.g. for an integer, '-' is only valid for the first character */
	cc_bool (*IsValidString)(struct MenuInputDesc* d, const cc_string* s);
	/* Whether the characters of the given string produce a valid value */
	cc_bool (*IsValidValue)(struct MenuInputDesc*  d, const cc_string* s);
	/* Gets the default value for this input. */
	void (*GetDefault)(struct MenuInputDesc*       d, cc_string* value);
	/* Whether the given input button was processed */
	/* E.g. Int input accepts using lef/right to increment/decrement */
	cc_bool (*ProcessInput)(struct MenuInputDesc*  d, cc_string* value, int btn);
};

struct MenuInputDesc {
	const struct MenuInputVTABLE* VTABLE;
	union {
		struct { const char* const* Names; int Count; } e;
		struct { int Min, Max, Default; } i;
		struct { float Min, Max, Default; } f;
		struct { PackedCol Default; } h;
	} meta;
};

extern const struct MenuInputVTABLE HexInput_VTABLE;
extern const struct MenuInputVTABLE IntInput_VTABLE;
extern const struct MenuInputVTABLE SeedInput_VTABLE;
extern const struct MenuInputVTABLE FloatInput_VTABLE;
extern const struct MenuInputVTABLE PathInput_VTABLE;
extern const struct MenuInputVTABLE StringInput_VTABLE;

#define MenuInput_Hex(v, def) v.VTABLE = &HexInput_VTABLE; v.meta.h.Default = def;
#define MenuInput_Int(v, lo, hi, def) v.VTABLE = &IntInput_VTABLE; v.meta.i.Min = lo; v.meta.i.Max = hi; v.meta.i.Default = def;
#define MenuInput_Seed(v) v.VTABLE = &SeedInput_VTABLE; v.meta.i.Min = Int32_MinValue; v.meta.i.Max = Int32_MaxValue;
#define MenuInput_Float(v, lo, hi, def) v.VTABLE = &FloatInput_VTABLE; v.meta.f.Min = lo; v.meta.f.Max = hi; v.meta.f.Default = def;
#define MenuInput_Path(v) v.VTABLE = &PathInput_VTABLE;
#define MenuInput_Enum(v, names, count) v.VTABLE = NULL; v.meta.e.Names = names; v.meta.e.Count = count;
#define MenuInput_String(v) v.VTABLE = &StringInput_VTABLE;

struct TextInputWidget {
	struct InputWidget base;
	int minWidth, minHeight;
	struct MenuInputDesc desc;
	char _textBuffer[INPUTWIDGET_LEN];
	/* variables for on-screen keyboard */
	const char* onscreenPlaceholder;
	int onscreenType;
};
#define MENUINPUTWIDGET_MAX 8

CC_NOINLINE void TextInputWidget_Create(struct TextInputWidget* w, int width, const cc_string* text, struct MenuInputDesc* d);
CC_NOINLINE void TextInputWidget_Add(void* screen, struct TextInputWidget* w, int width, const cc_string* text, struct MenuInputDesc* d);
/* Sets the font used, then redraws the input widget. */
CC_NOINLINE void TextInputWidget_SetFont(struct TextInputWidget* w, struct FontDesc* font);


struct ChatInputWidget {
	struct InputWidget base;
	int typingLogPos;
	cc_string origStr;
	char _textBuffer[INPUTWIDGET_MAX_LINES * INPUTWIDGET_LEN];
	char _origBuffer[INPUTWIDGET_MAX_LINES * INPUTWIDGET_LEN];	
};

CC_NOINLINE void ChatInputWidget_Create(struct ChatInputWidget* w);
CC_NOINLINE void ChatInputWidget_SetFont(struct ChatInputWidget* w, struct FontDesc* font);


/* Retrieves the text for the i'th line in the group */
typedef cc_string (*TextGroupWidget_Get)(int i);
#define TEXTGROUPWIDGET_LEN (STRING_SIZE + (STRING_SIZE / 2))

/* A group of text labels. */
struct TextGroupWidget {
	Widget_Body
	int lines, defaultHeight;
	struct FontDesc* font;
	/* Whether a line has zero height when that line has no text in it. */
	cc_bool collapsible[GUI_MAX_CHATLINES];
	cc_bool underlineUrls;
	struct Texture* textures;
	TextGroupWidget_Get GetLine;
};

CC_NOINLINE void TextGroupWidget_Create(struct TextGroupWidget* w, int lines, struct Texture* textures, TextGroupWidget_Get getLine);
CC_NOINLINE void TextGroupWidget_SetFont(struct TextGroupWidget* w, struct FontDesc* font);
/* Deletes first line, then moves all other lines upwards, then redraws last line. */
/* NOTE: GetLine must also adjust the lines it returns for this to behave properly. */
CC_NOINLINE void TextGroupWidget_ShiftUp(struct TextGroupWidget* w);
/* Deletes last line, then moves all other lines downwards, then redraws first line. */
/* NOTE: GetLine must also adjust the lines it returns for this to behave properly. */
CC_NOINLINE void TextGroupWidget_ShiftDown(struct TextGroupWidget* w);
/* Returns height of lines, except for the first 0 or more empty lines. */
CC_NOINLINE int  TextGroupWidget_UsedHeight(struct TextGroupWidget* w);
/* Returns either the URL or the line underneath the given coordinates. */
CC_NOINLINE int  TextGroupWidget_GetSelected(struct TextGroupWidget* w, cc_string* text, int mouseX, int mouseY);
/* Redraws the given line, updating the texture and Y position of other lines. */
CC_NOINLINE void TextGroupWidget_Redraw(struct TextGroupWidget* w, int index);
/* Calls TextGroupWidget_Redraw for all lines */
CC_NOINLINE void TextGroupWidget_RedrawAll(struct TextGroupWidget* w);
/* Calls TextGroupWidget_Redraw for all lines which have the given colour code. */
/* Typically only called in response to the ChatEvents.ColCodeChanged event. */
CC_NOINLINE void TextGroupWidget_RedrawAllWithCol(struct TextGroupWidget* w, char col);
/* Gets the text for the i'th line. */
static CC_INLINE cc_string TextGroupWidget_UNSAFE_Get(struct TextGroupWidget* w, int i) { return w->GetLine(i); }


typedef void (*SpecialInputAppendFunc)(void* userData, char c);
struct SpecialInputTab {
	int itemsPerRow, charsPerItem, titleWidth;
	cc_string title, contents;
};

struct SpecialInputWidget {
	Widget_Body
	int elementWidth, elementHeight;
	int selectedIndex;
	cc_bool pendingRedraw;
	struct InputWidget* target;
	struct Texture tex;
	struct FontDesc* font;
	int titleHeight;
	struct SpecialInputTab tabs[5];
	cc_string colString;
	char _colBuffer[DRAWER2D_MAX_COLORS * 4];
};

CC_NOINLINE void SpecialInputWidget_Create(struct SpecialInputWidget* w, struct FontDesc* font, struct InputWidget* target);
CC_NOINLINE void SpecialInputWidget_Redraw(struct SpecialInputWidget* w);
CC_NOINLINE void SpecialInputWidget_UpdateCols(struct SpecialInputWidget* w);
CC_NOINLINE void SpecialInputWidget_SetActive(struct SpecialInputWidget* w, cc_bool active);

#ifdef CC_BUILD_TOUCH
struct ThumbstickWidget {
	Widget_Body 
	float scale; 
};
#define THUMBSTICKWIDGET_PER (4 * 4)
#define THUMBSTICKWIDGET_MAX (THUMBSTICKWIDGET_PER * 2)

void ThumbstickWidget_Init(struct ThumbstickWidget* w);
void ThumbstickWidget_GetMovement(struct ThumbstickWidget* w, float* xMoving, float* zMoving);
#endif
#endif