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 = VuoLayer_makeEmpty();
212  VuoRetain(highlights);
213  VuoLayer textCursor = VuoLayer_makeEmpty();
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.sceneObject = text;
247  textLayer.sceneObject.name = VuoText_make("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  backgroundLayer.sceneObject.transform.translation = VuoPoint3d_add(backgroundLayer.sceneObject.transform.translation, offset);
372  borderLayer.sceneObject.transform.translation = VuoPoint3d_add(borderLayer.sceneObject.transform.translation, offset);
373 
374  if(hasLabel || hasPlaceholder)
375  {
376  textLayer.sceneObject.transform.translation = VuoPoint3d_add(textLayer.sceneObject.transform.translation, offset);
377  for(auto& highlight : *((std::vector<VuoLayer> *) highlights))
378  highlight.sceneObject.transform.translation = VuoPoint3d_add(highlight.sceneObject.transform.translation, offset);
379  textCursor.sceneObject.transform.translation = VuoPoint3d_add(textCursor.sceneObject.transform.translation, 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  textLayer.sceneObject.transform.translation.x += textOffset.x;
391  textLayer.sceneObject.transform.translation.y += textOffset.y;
392 
393  // the text layer is already transformed by the text renderer to account for font anchor,
394  // so add it after the alignment of text billboard for highlight and cursor
395  if(h != VuoHorizontalAlignment_Center)
396  textOffset.x += (h == VuoHorizontalAlignment_Left ? textSize.x : -textSize.x) * .5;
397 
398  if(v != VuoVerticalAlignment_Center)
399  textOffset.y += (v == VuoVerticalAlignment_Bottom ? textSize.y : -textSize.y) * .5;
400 
401  for(auto& highlight : *((std::vector<VuoLayer> *) highlights))
402  {
403  highlight.sceneObject.transform.translation.x += textOffset.x;
404  highlight.sceneObject.transform.translation.y += textOffset.y;
405  }
406 
407  textCursor.sceneObject.transform.translation.x += textOffset.x;
408  textCursor.sceneObject.transform.translation.y += textOffset.y;
409  }
410 
411  VuoListAppendValue_VuoLayer(layers, borderLayer);
412  VuoListAppendValue_VuoLayer(layers, backgroundLayer);
413 
414 #if THEME_DEBUG
415  for(int i = 1; i <= VuoListGetCount_VuoLayer(characterBounds); i++)
416  {
417  VuoLayer l = VuoListGetValue_VuoLayer(characterBounds, i);
418  l.sceneObject.transform.translation = VuoPoint3d_add(l.sceneObject.transform.translation, offset);
419 
420  // VLog("textOffset [%i]: %.2f %.2f", i, textOffset.x, textOffset.y);
421  l.sceneObject.transform.translation.x += textOffset.x;
422  l.sceneObject.transform.translation.y += textOffset.y;
423 
424  VuoListAppendValue_VuoLayer(layers, l);
425  }
426 #endif
427 
428  if(hasLabel || hasPlaceholder)
429  {
430  VuoListAppendValue_VuoLayer(layers, textLayer);
431  for(unsigned int i = 0; i < VuoListGetCount_VuoLayer(highlights); i++)
432  VuoListAppendValue_VuoLayer(layers, VuoListGetValue_VuoLayer(highlights, i+1));
433  VuoListAppendValue_VuoLayer(layers, textCursor);
434  }
435 
436  VuoRelease(highlights);
437 
438  return VuoLayer_makeGroup(layers, VuoTransform2d_make(position, 0, VuoPoint2d_make(1,1)));
439  }
440 };
441 
443 
448  VuoFont labelFont,
449  VuoFont placeholderFont,
450  VuoAnchor labelAnchor,
451  VuoPoint2d labelPadding,
452  VuoColor color,
453  VuoColor hoveredColor,
454  VuoColor pressedColor,
455  VuoColor borderColor,
456  VuoReal borderThickness,
457  VuoReal cornerRoundness)
458 {
459  return reinterpret_cast<VuoUiTheme>(new VuoUiThemeTextFieldRounded(
460  labelFont,
461  placeholderFont,
462  labelAnchor,
463  labelPadding,
464  color,
465  hoveredColor,
466  pressedColor,
467  borderColor,
468  borderThickness,
469  cornerRoundness));
470 }