Vuo  2.0.0
VuoTextFieldInternal.cc
Go to the documentation of this file.
1 
10 #include "VuoTextFieldInternal.h"
11 #include "module.h"
12 
13 extern "C"
14 {
15 #ifdef VUO_COMPILER
17  "title" : "VuoTextFieldInternal",
18  "dependencies" : [ "VuoKeyboard", "VuoClipboard" ],
19  });
20 #endif
21 }
22 
23 #include "VuoUiThemeBase.hh"
24 
28 static VuoText CreateVuoText(const char* string)
29 {
30  VuoText t = VuoText_make(string);
31  VuoRetain(t);
32  return t;
33 }
34 
39 {
40  text = NULL;
41  placeholder = CreateVuoText("Placeholder Text");
42  textImageData = NULL;
43  isHovering = false;
44  isFocused = false;
45  stb_textedit_initialize_state(&textEditState, lines);
46 }
47 
52 {
53  if(text != NULL)
55 
56  if(placeholder != NULL)
58 
60 }
61 
66 {
67  state = new VuoTextFieldState(numLines);
68  lineCount = numLines;
70  screenSize = VuoPoint2d_make(512, 512);
71  screenBackingScaleFactor = 1;
72  position = VuoPoint2d_make(0,0);
73  anchor = VuoAnchor_makeCentered();
74  theme = NULL;
75  validateCharInput = NULL;
76  validateTextInput = NULL;
77 }
78 
83 {
84  delete state;
85 }
86 
91 {
92  state->textEditState.line_count = lines;
93  lineCount = lines;
94  SetText(state->text);
95 }
96 
101 {
102  cursorColor = color;
103 }
104 
108 void VuoTextFieldInternal::SetPosition(VuoPoint2d newPosition)
109 {
110  position = newPosition;
111 }
112 
117 {
118  width = newWidth;
119 }
120 
125 {
126  anchor = newAnchor;
127 }
128 
133 {
134  if(state->text != NULL)
135  VuoRelease(state->text);
136 
137  state->text = VuoTextEdit_truncateLines(text, lineCount);
138 
139  VuoRetain(state->text);
140 }
141 
146 {
147  return VuoText_make(state->text);
148 }
149 
154 {
155  if(state->placeholder != NULL)
156  VuoRelease(state->placeholder);
157  state->placeholder = VuoText_make(text);
158  VuoRetain(state->placeholder);
159 }
160 
165 {
166  theme = newTheme;
167 }
168 
173 void VuoTextFieldInternal::SetValidateCharInputCallback(bool (*validateCharInputCallback)(const VuoText current, uint32_t append))
174 {
175  validateCharInput = validateCharInputCallback;
176 }
177 
182 void VuoTextFieldInternal::SetValidateTextInputCallback(bool (*validateTextInputCallback)(const VuoText current, VuoText* modifiedText))
183 {
184  validateTextInput = validateTextInputCallback;
185 }
186 
190 bool VuoTextFieldInternal::FindTextLayer(const VuoRenderedLayers* renderedLayers, uint64_t id, VuoSceneObject* textLayer, VuoList_VuoSceneObject ancestors)
191 {
192  VuoSceneObject foundObject;
193 
194  if( VuoRenderedLayers_findLayerId(*renderedLayers, id, ancestors, &foundObject) )
195  {
196  bool foundTextLayer = false;
197  VuoList_VuoSceneObject childObjects = VuoSceneObject_getChildObjects(foundObject);
198  unsigned long childObjectCount = VuoListGetCount_VuoSceneObject(childObjects);
199  for (unsigned long i = 1; i <= childObjectCount && !foundTextLayer; ++i)
200  {
201  VuoSceneObject child = VuoListGetValue_VuoSceneObject(childObjects, i);
202 
203  if (VuoText_areEqual("Text", VuoSceneObject_getName(child)))
204  {
205  VuoListAppendValue_VuoSceneObject(ancestors, foundObject);
206  *textLayer = child;
207  return true;
208  }
209  }
210  }
211 
212  return false;
213 }
214 
218 bool VuoTextFieldInternal::GetTextLocalPosition(const VuoRenderedLayers* renderedLayers, uint64_t id, VuoPoint2d point, VuoPoint2d* inverseTransformedPoint)
219 {
220  VuoSceneObject textLayer;
222  VuoLocal(ancestors);
223 
224  if( FindTextLayer(renderedLayers, id, &textLayer, ancestors) )
225  {
226  // transform mouse position to text layer space
227  return VuoRenderedLayers_getInverseTransformedPoint(*renderedLayers, ancestors, textLayer, point, inverseTransformedPoint);
228  }
229 
230  return false;
231 }
232 
237 {
238  if(!state->isFocused)
239  return;
240 
241  size_t utf32_len;
242 
243  uint32_t* unicode = VuoText_getUtf32Values(character, &utf32_len);
244 
245  if(utf32_len != 1)
246  {
247  if(unicode != NULL)
248  free(unicode);
249 
250  return;
251  }
252 
253  uint32_t utf32_char = unicode[0];
254 
255  free(unicode);
256 
257  // VLog("char: 0x%x mod: 0x%x = 0x%llx", unicode[0], modifiers, VuoTextEdit_combineKeyAndModifier(unicode[0], modifiers));
258 
259  if( utf32_char == KEYCODE_ESC ||
260  (!(modifiers & VuoModifierKey_Option) && (
261  utf32_char == KEYCODE_TAB ||
262  utf32_char == KEYCODE_RETURN
263  )
264  )
265  )
266  {
267  state->isFocused = false;
268  OnLostFocus();
269  }
270  else if(utf32_char == KEYCODE_CUT)
271  {
272  VuoTextEdit_cut(&state->text, &state->textEditState);
273  }
274  else if(utf32_char == KEYCODE_COPY)
275  {
276  VuoTextEdit_copy(&state->text, &state->textEditState);
277  }
278  else if(utf32_char == KEYCODE_PASTE)
279  {
280  VuoTextEdit_paste(&state->text, &state->textEditState);
281  }
282  else
283  {
284  // if validateCharInput callback is null, char is a control code, or validInput callback return true
285  if(validateCharInput == NULL || utf32_char < 32 || validateCharInput(state->text, utf32_char))
286  stb_textedit_key(&state->text, &state->textEditState, VuoTextEdit_combineKeyAndModifier(utf32_char, modifiers));
287  }
288 }
289 
297 {
298  bool stateDidChange = false;
299 
300  if(renderedLayers == NULL)
301  return stateDidChange;
302 
303  unsigned long int pixelsWide, pixelsHigh;
304  float backingScaleFactor;
305  if (VuoRenderedLayers_getRenderingDimensions(*renderedLayers, &pixelsWide, &pixelsHigh, &backingScaleFactor)
306  && (screenSize.x != pixelsWide
307  || screenSize.y != pixelsHigh
308  || screenBackingScaleFactor != backingScaleFactor))
309  stateDidChange = true;
310 
311  screenSize.x = pixelsWide;
312  screenSize.y = pixelsHigh;
313  screenBackingScaleFactor = backingScaleFactor;
314 
315  VuoList_VuoInteraction interactions = VuoRenderedLayers_getInteractions(*renderedLayers);
316  if (VuoListGetCount_VuoInteraction(interactions) > 0)
317  {
318  bool wasHovering = state->isHovering;
319  bool wasFocused = state->isFocused;
320 
321  // @todo currently just registers last interaction.
322  for(int i = 1; i <= VuoListGetCount_VuoInteraction(interactions); i++)
323  {
324  VuoInteraction it = VuoListGetValue_VuoInteraction(interactions, i);
325 
326  bool isPointInLayer = VuoRenderedLayers_isPointInLayerId(*renderedLayers, id, it.position);
327  state->isHovering = isPointInLayer;
328  VuoPoint2d inverseTransformedPoint;
329 
330  if(it.type == VuoInteractionType_Press || it.type == VuoInteractionType_Click)
331  {
332  state->isFocused = isPointInLayer;
333 
334  if( state->isFocused && GetTextLocalPosition(renderedLayers, id, it.position, &inverseTransformedPoint) )
335  {
336  if( it.clickCount == 1 )
337  stb_textedit_click(&state->text, &state->textEditState, inverseTransformedPoint.x, inverseTransformedPoint.y);
338  else if( it.clickCount == 2 )
340  else if( it.clickCount == 3 )
342 
343  stateDidChange = true;
344  }
345  }
346  else if(state->isFocused && it.type == VuoInteractionType_Drag)
347  {
348  if( GetTextLocalPosition(renderedLayers, id, it.position, &inverseTransformedPoint) )
349  stateDidChange = stb_textedit_drag(&state->text, &state->textEditState, inverseTransformedPoint.x, inverseTransformedPoint.y);
350  }
351  }
352 
353  if(state->isHovering != wasHovering || state->isFocused != wasFocused)
354  {
355  if(!state->isFocused && wasFocused)
356  OnLostFocus();
357 
358  stateDidChange = true;
359  }
360  }
361 
362  return stateDidChange;
363 }
364 
368 void VuoTextFieldInternal::OnLostFocus()
369 {
370  if(validateTextInput != NULL)
371  {
372  VuoText modifiedText = NULL;
373 
374  if(validateTextInput(state->text, &modifiedText))
375  {
376  SetText(modifiedText);
377 
378  if(modifiedText != NULL)
379  {
380  VuoRetain(modifiedText);
381  VuoRelease(modifiedText);
382  }
383  }
384  }
385 }
386 
391 {
392  if(state->textImageData)
393  {
394  VuoRelease(state->textImageData);
395  state->textImageData = NULL;
396  state->textEditState.textImageData = NULL;
397  }
398 
399  VuoUiThemeTextField* textTheme = static_cast<VuoUiThemeTextField*>(VuoUiTheme_getSpecificTheme(theme, "VuoUiThemeTextField"));
400  VuoLocal(textTheme);
401 
402  VuoLayer layer = textTheme->render(screenSize,
403  screenBackingScaleFactor,
404  cursorColor,
405  state->text,
406  state->placeholder,
407  lineCount,
408  state->textEditState.cursor,
409  state->textEditState.select_start,
410  state->textEditState.select_end,
411  position,
412  width,
413  anchor,
414  state->isHovering,
415  state->isFocused,
416  &state->textImageData);
417 
418  if(state->textImageData)
419  {
420  VuoRetain(state->textImageData);
421  state->textEditState.textImageData = state->textImageData;
422  }
423 
424  VuoLayer_setId(layer, id);
425 
426  return layer;
427 }