Vuo 2.4.4
Loading...
Searching...
No Matches
VuoUiThemeTextFieldRounded.cc
Go to the documentation of this file.
1
11#define THEME_DEBUG 0
12
13#include "VuoUiThemeBase.hh"
14
15extern "C" {
16#include "VuoImage.h"
17#include "VuoImageText.h"
18#include "VuoAnchor.h"
19#include "VuoPoint2d.h"
20}
21
22#include "VuoUiTheme.h"
23#include "VuoSceneText.h"
24#include <vector>
25
27#ifdef VUO_COMPILER
29 "title": "UI Theme: Text Field, Rounded",
30 "dependencies": [
31 "VuoBoolean",
32 "VuoColor",
33 "VuoFont",
34 "VuoImage",
35 "VuoImageText",
36 "VuoLayer",
37 "VuoPoint2d",
38 "VuoReal",
39 "VuoAnchor",
40 "VuoHorizontalAlignment",
41 "VuoVerticalAlignment",
42 "VuoSceneText"
43 ],
44 });
45#endif
47
52{
53private:
54 VuoFont font;
55 VuoAnchor textAnchor;
56 VuoPoint2d textPadding;
57 VuoColor textColor;
58 VuoColor textColorHovered;
59 VuoColor textColorActive;
60 VuoColor backgroundColor;
61 VuoColor backgroundColorHovered;
62 VuoColor backgroundColorActive;
63 VuoColor borderColor;
64 VuoColor borderColorHovered;
65 VuoColor borderColorActive;
66 VuoReal borderThickness;
67 VuoColor cursorColor;
68 VuoColor selectionColor;
69 VuoReal cornerRoundness;
70
71public:
72 static std::string type;
73
77 static VuoSerializable *makeFromJson(json_object *js)
78 {
80 VuoJson_getObjectValue(VuoFont, js, "font", (VuoFont){VuoText_make("Avenir-Medium"), 24, false, (VuoColor){1,1,1,1}, VuoHorizontalAlignment_Left, 1, 1}),
81 VuoJson_getObjectValue(VuoAnchor, js, "textAnchor", VuoAnchor_make(VuoHorizontalAlignment_Left, VuoVerticalAlignment_Top)),
82 VuoJson_getObjectValue(VuoPoint2d, js, "textPadding", (VuoPoint2d){0.02, 0.01}),
83 VuoJson_getObjectValue(VuoColor, js, "textColor", (VuoColor){0, 0, 0, 0.7}),
84 VuoJson_getObjectValue(VuoColor, js, "textColorHovered", (VuoColor){0, 0, 0, 0.8}),
85 VuoJson_getObjectValue(VuoColor, js, "textColorActive", (VuoColor){0, 0, 0, 1}),
86 VuoJson_getObjectValue(VuoColor, js, "backgroundColor", (VuoColor){1, 1, 1, 0.5}),
87 VuoJson_getObjectValue(VuoColor, js, "backgroundColorHovered", (VuoColor){1, 1, 1, 0.6}),
88 VuoJson_getObjectValue(VuoColor, js, "backgroundColorActive", (VuoColor){1, 1, 1, 1}),
89 VuoJson_getObjectValue(VuoColor, js, "borderColor", (VuoColor){.46, .46, .46, 1}),
90 VuoJson_getObjectValue(VuoColor, js, "borderColorHovered", (VuoColor){.46, .48, .49, 1}),
91 VuoJson_getObjectValue(VuoColor, js, "borderColorActive", (VuoColor){.46, .48, 1, 1}),
92 VuoJson_getObjectValue(VuoReal, js, "borderThickness", .005),
93 VuoJson_getObjectValue(VuoColor, js, "cursorColor", (VuoColor){0, 0, 0, 1}),
94 VuoJson_getObjectValue(VuoColor, js, "selectionColor", (VuoColor){.7, .84, 1, 1}),
95 VuoJson_getObjectValue(VuoReal, js, "cornerRoundness", .5));
96 }
97
102 VuoAnchor _textAnchor,
103 VuoPoint2d _textPadding,
104 VuoColor _textColor,
105 VuoColor _textColorHovered,
106 VuoColor _textColorActive,
107 VuoColor _backgroundColor,
108 VuoColor _backgroundColorHovered,
109 VuoColor _backgroundColorActive,
110 VuoColor _borderColor,
111 VuoColor _borderColorHovered,
112 VuoColor _borderColorActive,
113 VuoReal _borderThickness,
114 VuoColor _cursorColor,
115 VuoColor _selectionColor,
116 VuoReal _cornerRoundness)
117 {
118 font = _font;
119 VuoFont_retain(font);
120 textAnchor = _textAnchor;
121 textPadding = _textPadding;
122 textColor = _textColor;
123 textColorHovered = _textColorHovered;
124 textColorActive = _textColorActive;
125 backgroundColor = _backgroundColor;
126 backgroundColorHovered = _backgroundColorHovered;
127 backgroundColorActive = _backgroundColorActive;
128 borderColor = _borderColor;
129 borderColorHovered = _borderColorHovered;
130 borderColorActive = _borderColorActive;
131 borderThickness = _borderThickness;
132 cursorColor = _cursorColor;
133 selectionColor = _selectionColor;
134 cornerRoundness = _cornerRoundness;
135 }
136
138 {
139 VuoFont_release(font);
140 }
141
145 json_object *getJson()
146 {
147 json_object *json = VuoSerializable::getJson();
148 json_object_object_add(json, "font", VuoFont_getJson(font));
149 json_object_object_add(json, "textAnchor", VuoAnchor_getJson(textAnchor));
150 json_object_object_add(json, "textPadding", VuoPoint2d_getJson(textPadding));
151 json_object_object_add(json, "textColor", VuoColor_getJson(textColor));
152 json_object_object_add(json, "textColorHovered", VuoColor_getJson(textColorHovered));
153 json_object_object_add(json, "textColorActive", VuoColor_getJson(textColorActive));
154 json_object_object_add(json, "backgroundColor", VuoColor_getJson(backgroundColor));
155 json_object_object_add(json, "backgroundColorHovered", VuoColor_getJson(backgroundColorHovered));
156 json_object_object_add(json, "backgroundColorActive", VuoColor_getJson(backgroundColorActive));
157 json_object_object_add(json, "borderColor", VuoColor_getJson(borderColor));
158 json_object_object_add(json, "borderColorHovered", VuoColor_getJson(borderColorHovered));
159 json_object_object_add(json, "borderColorActive", VuoColor_getJson(borderColorActive));
160 json_object_object_add(json, "borderThickness", VuoReal_getJson(borderThickness));
161 json_object_object_add(json, "cursorColor", VuoColor_getJson(cursorColor));
162 json_object_object_add(json, "selectionColor", VuoColor_getJson(selectionColor));
163 json_object_object_add(json, "cornerRoundness", VuoReal_getJson(cornerRoundness));
164 return json;
165 }
166
171 {
172 return strdup("Text Field Theme (Rounded)");
173 }
174
178 bool operator==(const VuoSerializable &that)
179 {
181 return VuoFont_areEqual(font, thatSpecialized->font)
182 && VuoAnchor_areEqual(textAnchor, thatSpecialized->textAnchor)
183 && VuoPoint2d_areEqual(textPadding, thatSpecialized->textPadding)
184 && VuoColor_areEqual(textColor, thatSpecialized->textColor)
185 && VuoColor_areEqual(textColorHovered, thatSpecialized->textColorHovered)
186 && VuoColor_areEqual(textColorActive, thatSpecialized->textColorActive)
187 && VuoColor_areEqual(backgroundColor, thatSpecialized->backgroundColor)
188 && VuoColor_areEqual(backgroundColorHovered, thatSpecialized->backgroundColorHovered)
189 && VuoColor_areEqual(backgroundColorActive, thatSpecialized->backgroundColorActive)
190 && VuoColor_areEqual(borderColor, thatSpecialized->borderColor)
191 && VuoColor_areEqual(borderColorHovered, thatSpecialized->borderColorHovered)
192 && VuoColor_areEqual(borderColorActive, thatSpecialized->borderColorActive)
193 && VuoReal_areEqual(borderThickness, thatSpecialized->borderThickness)
194 && VuoColor_areEqual(cursorColor, thatSpecialized->cursorColor)
195 && VuoColor_areEqual(selectionColor, thatSpecialized->selectionColor)
196 && VuoReal_areEqual(cornerRoundness, thatSpecialized->cornerRoundness);
197 }
198
202 bool operator<(const VuoSerializable &that)
203 {
205 VuoType_returnInequality(VuoFont, font, thatSpecialized->font);
206 VuoType_returnInequality(VuoAnchor, textAnchor, thatSpecialized->textAnchor);
207 VuoType_returnInequality(VuoPoint2d, textPadding, thatSpecialized->textPadding);
208 VuoType_returnInequality(VuoColor, textColor, thatSpecialized->textColor);
209 VuoType_returnInequality(VuoColor, textColorHovered, thatSpecialized->textColorHovered);
210 VuoType_returnInequality(VuoColor, textColorActive, thatSpecialized->textColorActive);
211 VuoType_returnInequality(VuoColor, backgroundColor, thatSpecialized->backgroundColor);
212 VuoType_returnInequality(VuoColor, backgroundColorHovered, thatSpecialized->backgroundColorHovered);
213 VuoType_returnInequality(VuoColor, backgroundColorActive, thatSpecialized->backgroundColorActive);
214 VuoType_returnInequality(VuoColor, borderColor, thatSpecialized->borderColor);
215 VuoType_returnInequality(VuoColor, borderColorHovered, thatSpecialized->borderColorHovered);
216 VuoType_returnInequality(VuoColor, borderColorActive, thatSpecialized->borderColorActive);
217 VuoType_returnInequality(VuoReal, borderThickness, thatSpecialized->borderThickness);
218 VuoType_returnInequality(VuoColor, cursorColor, thatSpecialized->cursorColor);
219 VuoType_returnInequality(VuoColor, selectionColor, thatSpecialized->selectionColor);
220 VuoType_returnInequality(VuoReal, cornerRoundness, thatSpecialized->cornerRoundness);
221 return false;
222 }
223
228 VuoLayer render(VuoPoint2d screenSize,
229 VuoReal screenBackingScaleFactor,
230 VuoText text,
231 VuoText placeholderText,
232 int numLines,
233 int cursorIndex,
234 int selectionStart,
235 int selectionEnd,
236 VuoPoint2d position,
237 VuoReal width,
238 VuoAnchor anchor,
239 bool isHovered,
240 bool isFocused,
241 VuoImageTextData* imageTextData)
242 {
244 VuoLocal(layers);
245
246 VuoLayer textLayer = nullptr;
248 VuoRetain(highlights);
249 VuoLayer textCursor = nullptr;
250
251 bool hasText = VuoText_length(text) > 0;
252 bool hasPlaceholder = VuoText_length(placeholderText) > 0;
253 VuoText labelText;
254 if (hasText)
255 labelText = text;
256 else if(isFocused || !hasPlaceholder)
257 labelText = VuoText_make("");
258 else
259 labelText = placeholderText;
260 VuoLocal(labelText);
261
262 float actualWidth = fmax(width, 0.001);
263 float actualHeight;
264
265 VuoPoint2d textSize = VuoPoint2d_make(0,0);
266
267 VuoFont f = font;
268 if (isFocused)
269 f.color = (VuoColor){f.color.r * textColorActive.r,
270 f.color.g * textColorActive.g,
271 f.color.b * textColorActive.b,
272 f.color.a * textColorActive.a};
273 else if (isHovered)
274 f.color = (VuoColor){f.color.r * textColorHovered.r,
275 f.color.g * textColorHovered.g,
276 f.color.b * textColorHovered.b,
277 f.color.a * textColorHovered.a};
278 else
279 f.color = (VuoColor){f.color.r * textColor.r,
280 f.color.g * textColor.g,
281 f.color.b * textColor.b,
282 f.color.a * textColor.a};
283
284 if (!hasText)
285 f.color.a *= .25;
286
287 VuoImageTextData textData = VuoImage_getTextImageData(labelText, f, screenBackingScaleFactor, 1, 0, true);
288
289 if(textData)
290 {
291 textData->billboardAnchor = textAnchor;
292 VuoImageTextData_convertToVuoCoordinates(textData, screenSize.x, screenBackingScaleFactor);
293
294 textSize.x = textData->width;
295 textSize.y = textData->height;
296
297 // Expand the text field width, if needed, to accommodate long text.
298 // (Scrolling would be preferable, but would take much longer to implement.)
299 actualWidth = fmax(width, textData->width);
300
301 actualHeight = textData->lineHeight * numLines;
302
303 VuoSceneObject text = VuoSceneText_make(labelText, f, true, INFINITY, textAnchor);
304 textLayer = (VuoLayer)text;
306 }
307 else
308 {
309 VuoReal lineHeight = VuoImageText_getLineHeight(f, screenSize.x, screenBackingScaleFactor);
310 actualHeight = lineHeight * numLines;
311 textSize.y = lineHeight;
312 }
313
314#if THEME_DEBUG
315 VuoList_VuoLayer characterBounds = VuoListCreate_VuoLayer();
316 VuoLocal(characterBounds);
317
318 if(textData)
319 {
320 for(int i = 0; i < textData->charCount; i++)
321 {
322 // don't draw control characters
323 if(textData->charAdvance[i] < .001)
324 continue;
325
326 // getPositionForCharIndex returns the bottom left corner of the char billboard
327 unsigned int lineIndex;
328 VuoPoint2d p = VuoImageTextData_getPositionForCharIndex(textData, i, &lineIndex);
329 p.x += textData->charAdvance[i] * .5;
330 p.y += textData->lineHeight * .5;
331
332 VuoListAppendValue_VuoLayer(characterBounds,
334 VuoColor_makeWithRGBA(.2,.2,.2,.4),
335 p,
336 0,
337 textData->charAdvance[i] * .95,
338 textData->lineHeight * .95));
339 }
340 }
341#endif
342
343 // if the text isn't placeholder, also render the cursor and selection (if any)
344 if(isFocused)
345 {
346 VuoPoint2d cursorSize = VuoImageText_getTextSize("|", f, screenSize, screenBackingScaleFactor, false);
347 cursorSize.x *= .5f;
348
349 VuoPoint2d cursorPosition;
350
351 if(textData)
352 {
353 cursorPosition = VuoImageTextData_getPositionForCharIndex(textData, cursorIndex, NULL);
354 cursorPosition.y += textData->lineHeight * .5;
355 }
356 else
357 {
358 cursorPosition = VuoPoint2d_make(0, 0);
359 }
360
361 textCursor = VuoLayer_makeColor(VuoText_make("Text Cursor"),
362 cursorColor,
363 cursorPosition,
364 0,
365 cursorSize.x,
366 cursorSize.y);
367
368 int textLength = VuoText_length(text);
369 selectionStart = MIN(selectionStart, textLength);
370 selectionEnd = MIN(selectionEnd, textLength);
371
372 int start = (selectionStart == selectionEnd ? cursorIndex : MIN(selectionStart, selectionEnd));
373 int length = (selectionStart == selectionEnd ? 0 : (MAX(selectionStart, selectionEnd) - start));
374
375 if (hasText && length > 0)
376 {
377 unsigned int lineCount = 0;
378 VuoRectangle* highlightRects = VuoImageTextData_getRectsForHighlight(textData, start, length, &lineCount);
379
380 for(int i = 0; i < lineCount; i++)
381 {
383 highlights,
385 selectionColor,
386 highlightRects[i].center,
387 0,
388 highlightRects[i].size.x,
389 highlightRects[i].size.y) );
390 }
391
392 free(highlightRects);
393 }
394 }
395
396 *imageTextData = textData;
397
398 actualWidth += textPadding.x * 2;
399 actualHeight += textPadding.y * 2;
400
401 actualWidth += borderThickness * 2;
402 actualHeight += borderThickness * 2;
403
404 float outerCornerRoundness = cornerRoundness / numLines;
405 float innerCornerRoundness = (actualHeight - borderThickness * 2 - (actualHeight * (1 - outerCornerRoundness))) / (actualHeight - borderThickness * 2);
406
407 VuoLayer backgroundLayer = VuoLayer_makeRoundedRectangle( VuoText_make("Text Field Background"),
408 isFocused ? backgroundColorActive : (isHovered ? backgroundColorHovered : backgroundColor),
409 VuoPoint2d_make(0,0),
410 0,
411 actualWidth - borderThickness * 2,
412 actualHeight - borderThickness * 2,
413 1,
414 innerCornerRoundness);
415
416 VuoLayer borderLayer = VuoLayer_makeRoundedRectangle( VuoText_make("Text Field Border"),
417 isFocused ? borderColorActive : (isHovered ? borderColorHovered : borderColor),
418 VuoPoint2d_make(0,0),
419 0,
420 actualWidth,
421 actualHeight,
422 1,
423 outerCornerRoundness);
424
425 VuoPoint3d offset = VuoPoint3d_make(0,0,0);
426 VuoPoint3d textOffset = VuoPoint3d_make(0,0,0);
427
428 if (VuoAnchor_getHorizontal(anchor) == VuoHorizontalAlignment_Left)
429 offset.x = actualWidth * .5f;
430 else if (VuoAnchor_getHorizontal(anchor) == VuoHorizontalAlignment_Right)
431 offset.x = -actualWidth * .5f;
432
433 if (VuoAnchor_getVertical(anchor) == VuoVerticalAlignment_Top)
434 offset.y = -actualHeight * .5f;
435 else if (VuoAnchor_getVertical(anchor) == VuoVerticalAlignment_Bottom)
436 offset.y = actualHeight * .5f;
437
438 VuoSceneObject_translate((VuoSceneObject)backgroundLayer, offset);
439 VuoSceneObject_translate((VuoSceneObject)borderLayer, offset);
440
441 {
442 VuoSceneObject_translate((VuoSceneObject)textLayer, offset);
443 for(auto& highlight : *((std::vector<VuoLayer> *) highlights))
444 VuoSceneObject_translate((VuoSceneObject)highlight, offset);
445 VuoSceneObject_translate((VuoSceneObject)textCursor, offset);
446
449
450 if(h != VuoHorizontalAlignment_Center)
451 textOffset.x = ((actualWidth - textPadding.x * 2) * .5) * (h == VuoHorizontalAlignment_Left ? -1 : 1);
452
453 if(v != VuoVerticalAlignment_Center)
454 textOffset.y = ((actualHeight - textPadding.y * 2) * .5) * (v == VuoVerticalAlignment_Bottom ? -1 : 1);
455
456 VuoSceneObject_translate((VuoSceneObject)textLayer, textOffset);
457
458 // the text layer is already transformed by the text renderer to account for font anchor,
459 // so add it after the alignment of text billboard for highlight and cursor
460 if(h != VuoHorizontalAlignment_Center)
461 textOffset.x += (h == VuoHorizontalAlignment_Left ? textSize.x : -textSize.x) * .5;
462
463 if(v != VuoVerticalAlignment_Center)
464 textOffset.y += (v == VuoVerticalAlignment_Bottom ? textSize.y : -textSize.y) * .5;
465
466 for(auto& highlight : *((std::vector<VuoLayer> *) highlights))
467 VuoSceneObject_translate((VuoSceneObject)highlight, textOffset);
468
469 VuoSceneObject_translate((VuoSceneObject)textCursor, textOffset);
470 }
471
472 VuoListAppendValue_VuoLayer(layers, borderLayer);
473 VuoListAppendValue_VuoLayer(layers, backgroundLayer);
474
475#if THEME_DEBUG
476 for(int i = 1; i <= VuoListGetCount_VuoLayer(characterBounds); i++)
477 {
478 VuoLayer l = VuoListGetValue_VuoLayer(characterBounds, i);
479 l.sceneObject.transform.translation = VuoPoint3d_add(l.sceneObject.transform.translation, offset);
480
481 // VLog("textOffset [%i]: %.2f %.2f", i, textOffset.x, textOffset.y);
482 l.sceneObject.transform.translation.x += textOffset.x;
483 l.sceneObject.transform.translation.y += textOffset.y;
484
486 }
487#endif
488
489 if (hasText || hasPlaceholder)
490 {
491 for(unsigned int i = 0; i < VuoListGetCount_VuoLayer(highlights); i++)
493 VuoListAppendValue_VuoLayer(layers, textLayer);
494 VuoListAppendValue_VuoLayer(layers, textCursor);
495 }
496
497 VuoRelease(highlights);
498
499 return VuoLayer_makeGroup(layers, VuoTransform2d_make(position, 0, VuoPoint2d_make(1,1)));
500 }
501};
502
504
509 VuoAnchor textAnchor,
510 VuoPoint2d textPadding,
511 VuoColor textColor,
512 VuoColor textColorHovered,
513 VuoColor textColorActive,
514 VuoColor backgroundColor,
515 VuoColor backgroundColorHovered,
516 VuoColor backgroundColorActive,
517 VuoColor borderColor,
518 VuoColor borderColorHovered,
519 VuoColor borderColorActive,
520 VuoReal borderThickness,
521 VuoColor cursorColor,
522 VuoColor selectionColor,
523 VuoReal cornerRoundness)
524{
525 return reinterpret_cast<VuoUiTheme>(new VuoUiThemeTextFieldRounded(font,
526 textAnchor,
527 textPadding,
528 textColor,
529 textColorHovered,
530 textColorActive,
531 backgroundColor,
532 backgroundColorHovered,
533 backgroundColorActive,
534 borderColor,
535 borderColorHovered,
536 borderColorActive,
537 borderThickness,
538 cursorColor,
539 selectionColor,
540 cornerRoundness));
541}