Vuo  2.0.0
VuoUiThemeTextFieldRounded.cc
Go to the documentation of this file.
1 
10 #define THEME_DEBUG 0
12 
13 #include "VuoUiThemeBase.hh"
14 
15 #include "type.h"
16 
17 extern "C" {
18 #include "VuoImage.h"
19 #include "VuoImageText.h"
20 #include "VuoAnchor.h"
21 #include "VuoPoint2d.h"
22 }
23 
24 #include "VuoUiTheme.h"
25 #include "VuoSceneText.h"
26 #include <vector>
27 
29 #ifdef VUO_COMPILER
31  "title": "UI Theme: Text Field, Rounded",
32  "dependencies": [
33  "VuoBoolean",
34  "VuoColor",
35  "VuoFont",
36  "VuoImage",
37  "VuoImageText",
38  "VuoLayer",
39  "VuoPoint2d",
40  "VuoReal",
41  "VuoAnchor",
42  "VuoHorizontalAlignment",
43  "VuoVerticalAlignment",
44  "VuoSceneText"
45  ],
46  });
47 #endif
48 
54 {
55 private:
56  VuoFont labelFont;
57  VuoFont placeholderFont;
58  VuoAnchor labelPosition;
59  VuoPoint2d labelPadding;
60  VuoColor color;
61  VuoColor hoveredColor;
62  VuoColor pressedColor;
63  VuoColor borderColor;
64  VuoReal borderThickness;
65  VuoReal cornerRoundness;
66 
67 public:
68  static std::string type;
69 
74  {
75  return new VuoUiThemeTextFieldRounded(
76  VuoJson_getObjectValue(VuoFont, js, "labelFont", (VuoFont){NULL, 18, false, VuoColor_makeWithRGBA(0,0,0,1), VuoHorizontalAlignment_Left, 1, 1}),
77  VuoJson_getObjectValue(VuoFont, js, "placeholderFont", (VuoFont){NULL, 18, false, VuoColor_makeWithRGBA(0, 0, 0, 0.25), VuoHorizontalAlignment_Left, 1, 1}),
78  VuoJson_getObjectValue(VuoAnchor, js, "labelPosition", VuoAnchor_make(VuoHorizontalAlignment_Left, VuoVerticalAlignment_Center)),
79  VuoJson_getObjectValue(VuoPoint2d, js, "labelPadding", (VuoPoint2d){0.05, 0.05}),
80  VuoJson_getObjectValue(VuoColor, js, "color", (VuoColor){.95, .95, .95, 1}),
81  VuoJson_getObjectValue(VuoColor, js, "hoveredColor", (VuoColor){.41,.51,.61,1}),
82  VuoJson_getObjectValue(VuoColor, js, "pressedColor", (VuoColor){.35,.45,.55,1}),
83  VuoJson_getObjectValue(VuoColor, js, "borderColor", (VuoColor){.3,.4,.5,1}),
84  VuoJson_getObjectValue(VuoReal, js, "borderThickness", .2),
85  VuoJson_getObjectValue(VuoReal, js, "cornerRoundness", .2));
86  }
87 
92  VuoFont _labelFont,
93  VuoFont _placeholderFont,
94  VuoAnchor _labelPosition,
95  VuoPoint2d _labelPadding,
96  VuoColor _color,
97  VuoColor _hoveredColor,
98  VuoColor _pressedColor,
99  VuoColor _borderColor,
100  VuoReal _borderThickness,
101  VuoReal _cornerRoundness)
102  {
103  labelFont = _labelFont;
104  VuoFont_retain(labelFont);
105  placeholderFont = _placeholderFont;
106  VuoFont_retain(placeholderFont);
107  labelPosition = _labelPosition;
108  labelPadding = _labelPadding;
109  color = _color;
110  hoveredColor = _hoveredColor;
111  pressedColor = _pressedColor;
112  borderColor = _borderColor;
113  borderThickness = _borderThickness;
114  cornerRoundness = _cornerRoundness;
115  }
116 
118  {
119  VuoFont_release(labelFont);
120  VuoFont_release(placeholderFont);
121  }
122 
127  {
129  json_object_object_add(json, "labelFont", VuoFont_getJson(labelFont));
130  json_object_object_add(json, "placeholderFont", VuoFont_getJson(placeholderFont));
131  json_object_object_add(json, "labelPosition", VuoAnchor_getJson(labelPosition));
132  json_object_object_add(json, "labelPadding", VuoPoint2d_getJson(labelPadding));
133  json_object_object_add(json, "color", VuoColor_getJson(color));
134  json_object_object_add(json, "hoveredColor", VuoColor_getJson(hoveredColor));
135  json_object_object_add(json, "pressedColor", VuoColor_getJson(pressedColor));
136  json_object_object_add(json, "borderColor", VuoColor_getJson(borderColor));
137  json_object_object_add(json, "borderThickness", VuoReal_getJson(borderThickness));
138  json_object_object_add(json, "cornerRoundness", VuoReal_getJson(cornerRoundness));
139  return json;
140  }
141 
145  char *getSummary()
146  {
147  return strdup("Text Field Theme (Rounded)");
148  }
149 
153  bool operator==(const VuoSerializable &that)
154  {
156  return VuoFont_areEqual(labelFont, thatSpecialized->labelFont)
157  && VuoFont_areEqual(placeholderFont, thatSpecialized->placeholderFont)
158  && VuoAnchor_areEqual(labelPosition, thatSpecialized->labelPosition)
159  && VuoPoint2d_areEqual(labelPadding, thatSpecialized->labelPadding)
160  && VuoColor_areEqual(color, thatSpecialized->color)
161  && VuoColor_areEqual(hoveredColor, thatSpecialized->hoveredColor)
162  && VuoColor_areEqual(pressedColor, thatSpecialized->pressedColor)
163  && VuoColor_areEqual(borderColor, thatSpecialized->borderColor)
164  && VuoReal_areEqual(borderThickness, thatSpecialized->borderThickness)
165  && VuoReal_areEqual(cornerRoundness, thatSpecialized->cornerRoundness);
166  }
167 
171  bool operator<(const VuoSerializable &that)
172  {
174  VuoType_returnInequality(VuoFont, labelFont, thatSpecialized->labelFont);
175  VuoType_returnInequality(VuoFont, placeholderFont, thatSpecialized->placeholderFont);
176  VuoType_returnInequality(VuoAnchor, labelPosition, thatSpecialized->labelPosition);
177  VuoType_returnInequality(VuoPoint2d, labelPadding, thatSpecialized->labelPadding);
178  VuoType_returnInequality(VuoColor, color, thatSpecialized->color);
179  VuoType_returnInequality(VuoColor, hoveredColor, thatSpecialized->hoveredColor);
180  VuoType_returnInequality(VuoColor, pressedColor, thatSpecialized->pressedColor);
181  VuoType_returnInequality(VuoColor, borderColor, thatSpecialized->borderColor);
182  VuoType_returnInequality(VuoReal, borderThickness, thatSpecialized->borderThickness);
183  VuoType_returnInequality(VuoReal, cornerRoundness, thatSpecialized->cornerRoundness);
184  return false;
185  }
186 
191  VuoLayer render(VuoPoint2d screenSize,
192  VuoReal screenBackingScaleFactor,
193  VuoColor cursorColor,
194  VuoText label,
195  VuoText placeholderText,
196  int numLines,
197  int cursorIndex,
198  int selectionStart,
199  int selectionEnd,
200  VuoPoint2d position,
201  VuoReal width,
202  VuoAnchor anchor,
203  bool isHovered,
204  bool isFocused,
205  VuoImageTextData* imageTextData)
206  {
208  VuoLocal(layers);
209 
210  VuoLayer textLayer = nullptr;
212  VuoRetain(highlights);
213  VuoLayer textCursor = nullptr;
214 
215  bool hasLabel = VuoText_length(label) > 0;
216  bool hasPlaceholder = VuoText_length(placeholderText) > 0;
217  VuoText labelText;
218  if(hasLabel)
219  labelText = label;
220  else if(isFocused || !hasPlaceholder)
221  labelText = VuoText_make("");
222  else
223  labelText = placeholderText;
224  VuoLocal(labelText);
225 
226  float actualWidth = fmax(width, 0.001);
227  float actualHeight;
228 
229  VuoPoint2d textSize = VuoPoint2d_make(0,0);
230 
231  VuoFont& font = ((hasLabel || isFocused) ? labelFont : placeholderFont);
232  VuoImageTextData textData = VuoImage_getTextImageData(labelText, font, screenBackingScaleFactor, 1, 0, false);
233 
234  if(textData)
235  {
236  textData->billboardAnchor = labelPosition;
237  VuoImageTextData_convertToVuoCoordinates(textData, screenSize.x, screenBackingScaleFactor);
238 
239  textSize.x = textData->width;
240  textSize.y = textData->height;
241 
242  // actualWidth = fmax(width, textData->width);
243  actualHeight = textData->lineHeight * numLines;
244 
245  VuoSceneObject text = VuoSceneText_make(labelText, font, true, INFINITY, labelPosition);
246  textLayer = (VuoLayer)text;
248  }
249  else
250  {
251  VuoReal lineHeight = VuoImageText_getLineHeight(font, screenSize.x, screenBackingScaleFactor);
252  actualHeight = lineHeight * numLines;
253  }
254 
255 #if THEME_DEBUG
256  VuoList_VuoLayer characterBounds = VuoListCreate_VuoLayer();
257  VuoLocal(characterBounds);
258 
259  if(textData)
260  {
261  for(int i = 0; i < textData->charCount; i++)
262  {
263  // don't draw control characters
264  if(textData->charAdvance[i] < .001)
265  continue;
266 
267  // getPositionForCharIndex returns the bottom left corner of the char billboard
268  unsigned int lineIndex;
269  VuoPoint2d p = VuoImageTextData_getPositionForCharIndex(textData, i, &lineIndex);
270  p.x += textData->charAdvance[i] * .5;
271  p.y += textData->lineHeight * .5;
272 
273  VuoListAppendValue_VuoLayer(characterBounds,
275  VuoColor_makeWithRGBA(.2,.2,.2,.4),
276  p,
277  0,
278  textData->charAdvance[i] * .95,
279  textData->lineHeight * .95));
280  }
281  }
282 #endif
283 
284  // if the text isn't placeholder, also render the cursor and selection (if any)
285  if(isFocused)
286  {
287  VuoPoint2d cursorSize = VuoImageText_getTextSize("|", font, screenSize, screenBackingScaleFactor, false);
288  cursorSize.x *= .15f;
289 
290  VuoPoint2d cursorPosition;
291 
292  if(textData)
293  {
294  cursorPosition = VuoImageTextData_getPositionForCharIndex(textData, cursorIndex, NULL);
295  cursorPosition.y += textData->lineHeight * .5;
296  }
297  else
298  {
299  cursorPosition = VuoPoint2d_make(0, 0);
300  }
301 
302  textCursor = VuoLayer_makeColor(VuoText_make("Text Cursor"),
303  cursorColor,
304  cursorPosition,
305  0,
306  cursorSize.x,
307  cursorSize.y);
308 
309  int start = (selectionStart == selectionEnd ? cursorIndex : MIN(selectionStart, selectionEnd));
310  int length = (selectionStart == selectionEnd ? 0 : (MAX(selectionStart, selectionEnd) - start));
311 
312  if(hasLabel && length > 0)
313  {
314  unsigned int lineCount = 0;
315  VuoRectangle* highlightRects = VuoImageTextData_getRectsForHighlight(textData, start, length, &lineCount);
316 
317  for(int i = 0; i < lineCount; i++)
318  {
320  highlights,
321  VuoLayer_makeColor(VuoText_make(VuoText_format("Text Highlight %i", i)),
322  VuoColor_makeWithRGBA(borderColor.r, borderColor.g, borderColor.b, .6),
323  highlightRects[i].center,
324  0,
325  highlightRects[i].size.x,
326  highlightRects[i].size.y) );
327  }
328 
329  free(highlightRects);
330  }
331  }
332 
333  *imageTextData = textData;
334 
335  actualWidth += labelPadding.x;
336  actualHeight += labelPadding.y;
337 
338  float border = borderThickness * fmin(actualWidth, actualHeight);
339 
340  VuoLayer backgroundLayer = VuoLayer_makeRoundedRectangle( VuoText_make("Button Background"),
341  color,
342  VuoPoint2d_make(0,0),
343  0,
344  actualWidth - border,
345  actualHeight - border,
346  1,
347  cornerRoundness);
348 
349  VuoLayer borderLayer = VuoLayer_makeRoundedRectangle( VuoText_make("Button Border"),
350  borderColor,
351  VuoPoint2d_make(0,0),
352  0,
353  actualWidth,
354  actualHeight,
355  1,
356  cornerRoundness);
357 
358  VuoPoint3d offset = VuoPoint3d_make(0,0,0);
359  VuoPoint3d textOffset = VuoPoint3d_make(0,0,0);
360 
361  if (VuoAnchor_getHorizontal(anchor) == VuoHorizontalAlignment_Left)
362  offset.x = actualWidth * .5f;
363  else if (VuoAnchor_getHorizontal(anchor) == VuoHorizontalAlignment_Right)
364  offset.x = -actualWidth * .5f;
365 
366  if (VuoAnchor_getVertical(anchor) == VuoVerticalAlignment_Top)
367  offset.y = -actualHeight * .5f;
368  else if (VuoAnchor_getVertical(anchor) == VuoVerticalAlignment_Bottom)
369  offset.y = actualHeight * .5f;
370 
371  VuoSceneObject_translate((VuoSceneObject)backgroundLayer, offset);
372  VuoSceneObject_translate((VuoSceneObject)borderLayer, offset);
373 
374  if(hasLabel || hasPlaceholder)
375  {
376  VuoSceneObject_translate((VuoSceneObject)textLayer, offset);
377  for(auto& highlight : *((std::vector<VuoLayer> *) highlights))
378  VuoSceneObject_translate((VuoSceneObject)highlight, offset);
379  VuoSceneObject_translate((VuoSceneObject)textCursor, offset);
380 
382  VuoVerticalAlignment v = VuoAnchor_getVertical(labelPosition);
383 
384  if(h != VuoHorizontalAlignment_Center)
385  textOffset.x = ((actualWidth - labelPadding.x) * .5) * (h == VuoHorizontalAlignment_Left ? -1 : 1);
386 
387  if(v != VuoVerticalAlignment_Center)
388  textOffset.y = ((actualHeight - labelPadding.y) * .5) * (v == VuoVerticalAlignment_Bottom ? -1 : 1);
389 
390  VuoSceneObject_translate((VuoSceneObject)textLayer, textOffset);
391 
392  // the text layer is already transformed by the text renderer to account for font anchor,
393  // so add it after the alignment of text billboard for highlight and cursor
394  if(h != VuoHorizontalAlignment_Center)
395  textOffset.x += (h == VuoHorizontalAlignment_Left ? textSize.x : -textSize.x) * .5;
396 
397  if(v != VuoVerticalAlignment_Center)
398  textOffset.y += (v == VuoVerticalAlignment_Bottom ? textSize.y : -textSize.y) * .5;
399 
400  for(auto& highlight : *((std::vector<VuoLayer> *) highlights))
401  VuoSceneObject_translate((VuoSceneObject)highlight, textOffset);
402 
403  VuoSceneObject_translate((VuoSceneObject)textCursor, textOffset);
404  }
405 
406  VuoListAppendValue_VuoLayer(layers, borderLayer);
407  VuoListAppendValue_VuoLayer(layers, backgroundLayer);
408 
409 #if THEME_DEBUG
410  for(int i = 1; i <= VuoListGetCount_VuoLayer(characterBounds); i++)
411  {
412  VuoLayer l = VuoListGetValue_VuoLayer(characterBounds, i);
413  l.sceneObject.transform.translation = VuoPoint3d_add(l.sceneObject.transform.translation, offset);
414 
415  // VLog("textOffset [%i]: %.2f %.2f", i, textOffset.x, textOffset.y);
416  l.sceneObject.transform.translation.x += textOffset.x;
417  l.sceneObject.transform.translation.y += textOffset.y;
418 
419  VuoListAppendValue_VuoLayer(layers, l);
420  }
421 #endif
422 
423  if(hasLabel || hasPlaceholder)
424  {
425  VuoListAppendValue_VuoLayer(layers, textLayer);
426  for(unsigned int i = 0; i < VuoListGetCount_VuoLayer(highlights); i++)
427  VuoListAppendValue_VuoLayer(layers, VuoListGetValue_VuoLayer(highlights, i+1));
428  VuoListAppendValue_VuoLayer(layers, textCursor);
429  }
430 
431  VuoRelease(highlights);
432 
433  return VuoLayer_makeGroup(layers, VuoTransform2d_make(position, 0, VuoPoint2d_make(1,1)));
434  }
435 };
436 
438 
443  VuoFont labelFont,
444  VuoFont placeholderFont,
445  VuoAnchor labelAnchor,
446  VuoPoint2d labelPadding,
447  VuoColor color,
448  VuoColor hoveredColor,
449  VuoColor pressedColor,
450  VuoColor borderColor,
451  VuoReal borderThickness,
452  VuoReal cornerRoundness)
453 {
454  return reinterpret_cast<VuoUiTheme>(new VuoUiThemeTextFieldRounded(
455  labelFont,
456  placeholderFont,
457  labelAnchor,
458  labelPadding,
459  color,
460  hoveredColor,
461  pressedColor,
462  borderColor,
463  borderThickness,
464  cornerRoundness));
465 }