Vuo  2.3.2
VuoTextEdit.h
Go to the documentation of this file.
1 
10 #pragma once
11 
12 #include "VuoText.h"
13 
17 #ifndef STB_TEXTEDIT_CHARTYPE
18 #define STB_TEXTEDIT_CHARTYPE uint64_t
19 #endif
20 
21 #include <stdlib.h>
22 #include "VuoHeap.h"
23 #include "VuoImageText.h"
24 #include "stb_textedit.h"
25 #include "VuoClipboard.h"
26 #include "VuoModifierKey.h"
27 
28 #define COMMAND_HI ((((uint64_t)VuoModifierKey_Command) << 32))
29 #define CONTROL_HI ((((uint64_t)VuoModifierKey_Control) << 32))
30 #define OPTION_HI ((((uint64_t)VuoModifierKey_Option) << 32))
31 #define SHIFT_HI ((((uint64_t)VuoModifierKey_Shift) << 32))
32 
33 #define KEYCODE_COPY 0x3
34 #define KEYCODE_PASTE 0x16
35 #define KEYCODE_CUT 0x18
36 #define KEYCODE_ESC 0x1b
37 #define KEYCODE_TAB 0x9
38 #define KEYCODE_RETURN 0xD
39 #define KEYCODE_ENTER 0x3
40 
42 static char STB_TEXTEDIT_NEWLINE = '\n';
43 
44 #define STB_TEXTEDIT_K_LEFT 0x0001C
45 #define STB_TEXTEDIT_K_RIGHT 0x0001D
46 #define STB_TEXTEDIT_K_UP 0x0001E
47 #define STB_TEXTEDIT_K_DOWN 0x0001F
48 #define STB_TEXTEDIT_K_LINESTART (COMMAND_HI | STB_TEXTEDIT_K_LEFT)
49 #define STB_TEXTEDIT_K_LINESTART2 0x1
50 #define STB_TEXTEDIT_K_LINEEND (COMMAND_HI | STB_TEXTEDIT_K_RIGHT)
51 #define STB_TEXTEDIT_K_LINEEND2 0x4
52 #define STB_TEXTEDIT_K_TEXTSTART (COMMAND_HI | STB_TEXTEDIT_K_UP)
53 #define STB_TEXTEDIT_K_TEXTSTART2 (CONTROL_HI | 0x41)
54 #define STB_TEXTEDIT_K_TEXTEND (COMMAND_HI | STB_TEXTEDIT_K_DOWN)
55 #define STB_TEXTEDIT_K_TEXTEND2 (CONTROL_HI | 0x45)
56 #define STB_TEXTEDIT_K_DELETE 0x7f
57 #define STB_TEXTEDIT_K_BACKSPACE 0x00008
58 #define STB_TEXTEDIT_K_UNDO (COMMAND_HI | 0x1A)
59 #define STB_TEXTEDIT_K_REDO (COMMAND_HI | 0x19)
60 #define STB_TEXTEDIT_K_REDO2 ((COMMAND_HI | SHIFT_HI) | 0x1A)
61 #define STB_TEXTEDIT_K_WORDLEFT (OPTION_HI | STB_TEXTEDIT_K_LEFT)
62 #define STB_TEXTEDIT_K_WORDRIGHT (OPTION_HI | STB_TEXTEDIT_K_RIGHT)
63 #define STB_TEXTEDIT_K_DELETEWORD (OPTION_HI | STB_TEXTEDIT_K_BACKSPACE)
64 #define STB_TEXTEDIT_K_DELETEWORDRIGHT (OPTION_HI | STB_TEXTEDIT_K_DELETE)
65 #define STB_TEXTEDIT_K_DELETELINE (COMMAND_HI | STB_TEXTEDIT_K_BACKSPACE)
66 #define STB_TEXTEDIT_K_DELETELINERIGHT (COMMAND_HI | STB_TEXTEDIT_K_DELETE)
67 #define STB_TEXTEDIT_K_SHIFT SHIFT_HI
68 #define STB_TEXTEDIT_K_SELECTALL (COMMAND_HI | 0x1)
69 
71 #define STB_TEXTEDIT_GETWIDTH_NEWLINE 0
72 
77 
82 {
83  return ((uint64_t)utf32) | (((uint64_t)modifiers) << 32);
84 }
85 
91 {
92  uint32_t* utf32 = VuoText_getUtf32Values(text, length);
93  STB_TEXTEDIT_CHARTYPE* stbchars = (STB_TEXTEDIT_CHARTYPE*) malloc(sizeof(STB_TEXTEDIT_CHARTYPE) * (*length));
94  for(int i = 0; i < (*length); i++)
95  stbchars[i] = utf32[i];
96  free(utf32);
97  return stbchars;
98 }
99 
104 {
105  return VuoText_length(*obj);
106 }
107 
111 static bool VuoTextEdit_isNewLine(uint32_t utf32_char)
112 {
113  return utf32_char >= 0xA && utf32_char <= 0xD;
114 }
115 
119 static bool VuoTextEdit_isWhiteSpace(uint32_t utf32_char)
120 {
121  // control code or one of those weird white space chars between 0x2000-A
122  if( utf32_char < 33 || (utf32_char >= 0x2000 && utf32_char <= 0x200A) )
123  return true;
124 
125  return false;
126 }
127 
132 static bool VuoTextEdit_isSeparator(uint32_t utf32_char)
133 {
134  // control code or one of those weird white space chars between 0x2000-A
135  if( VuoTextEdit_isWhiteSpace(utf32_char) )
136  return true;
137 
138  size_t length = 0;
139 
140  uint32_t* separators = VuoText_getUtf32Values("./\\()\"'-:,;<>~!@#$%%^&*|+=[]{}`~?", &length);
141 
142  for(size_t i = 0; i < length; i++)
143  {
144  if(utf32_char == separators[i])
145  {
146  free(separators);
147  return true;
148  }
149  }
150 
151  free(separators);
152 
153  return false;
154 }
155 
159 static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state);
160 
165 static void VuoTextEdit_selectFromCursorToSeparator(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, bool (*separatorFunc)(uint32_t))
166 {
167  if(VuoText_isEmpty(*str))
168  return;
169 
171 
172  size_t len = 0;
173  uint32_t* chars = VuoText_getUtf32Values(*str, &len);
174  // select_start can be greater if placeholder text is present
175  int start = MIN(len, state->select_start);
176  state->select_start = 0;
177 
178  for(int i = start; i > 0; i--)
179  {
180  if( (*separatorFunc)(chars[i]) )
181  {
182  state->select_start = i + 1;
183  break;
184  }
185  }
186 
187  int prev_end = state->select_end;
188  state->select_end = len;
189  state->cursor = len;
190 
191  for(int i = prev_end; i < len; i++)
192  {
193  if( (*separatorFunc)(chars[i]) )
194  {
195  state->select_end = i;
196  state->cursor = i;
197  break;
198  }
199  }
200 }
201 
205 static void VuoTextEdit_copy(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
206 {
207  int start = MIN(state->select_start, state->select_end);
208  int end = MAX(state->select_start, state->select_end);
209  VuoText selection = VuoText_substring(*str, start + 1, end - start);
210  VuoLocal(selection);
211  VuoClipboard_setText(selection);
212 }
213 
217 static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
218 
222 static int VuoTextEdit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
223 {
224  if( state->select_start != state->select_end )
225  {
226  VuoTextEdit_copy(str, state);
227  stb_textedit_cut(str, state);
228  return 1;
229  }
230  return 0;
231 }
232 
236 static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len);
237 
242 {
243  if(idx < 0)
244  return -1;
245 
246  // @todo It's inefficient to keep allocating a full utf32 array for a single char
247  size_t length;
248 
249  uint32_t* utf32 = VuoText_getUtf32Values(*obj, &length);
250 
251  if(idx >= length)
252  return -1;
253 
254  return (STB_TEXTEDIT_CHARTYPE) utf32[idx];
255 }
256 
262 {
263  int count = 1;
264 
265  for(int ii = 0; ii < STB_TEXTEDIT_STRINGLEN(str); ii++)
267  count++;
268 
269  return count;
270 }
271 
276 {
277  VuoList_VuoInteger newLines = VuoText_findOccurrences(text, "\n");
278  VuoLocal(newLines);
279 
280  VuoText res;
281 
282  if(VuoListGetCount_VuoInteger(newLines) >= maxLines)
283  {
284  VuoInteger trunc = VuoListGetValue_VuoInteger(newLines, maxLines);
285  // Subtract 1 because we don't want the \n
286  res = VuoText_substring(text, 1, trunc - 1);
287  }
288  else
289  {
290  res = VuoText_make(text);
291  }
292 
293  return res;
294 }
295 
299 static void VuoTextEdit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
300 {
301  VuoText clipboard = VuoClipboard_getContents();
302  VuoLocal(clipboard);
303 
304  int lineCount = stb_textedit_linecount(str);
305  // +1 because line_count is a count of \n, not lines.
306  VuoText res = VuoTextEdit_truncateLines(clipboard, (state->line_count - lineCount) + 1);
307  VuoLocal(res);
308 
309  size_t len = 0;
310  uint64_t* clip64 = VuoTextEdit_makeCharArrayWithVuoText(res, &len);
311  stb_textedit_paste(str, state, clip64, len);
312  free(clip64);
313 }
314 
318 static int stb_text_locate_coord(STB_TexteditState *state, float x, float y)
319 {
320  if (!state->textImageData)
321  return 0;
322 
323  return VuoImageTextData_getNearestCharToPoint((VuoImageTextData) state->textImageData, VuoPoint2d_make(x, y));
324 }
325 
330 static void stb_textedit_find_charpos(StbFindState* find, STB_TEXTEDIT_STRING *str, int n, STB_TexteditState* state)
331 {
332  VuoImageTextData data = (VuoImageTextData)state->textImageData;
333 
334  unsigned int lineIndex = 0;
335  VuoPoint2d position = VuoImageTextData_getPositionForCharIndex(data, n, &lineIndex);
336 
337  find->x = position.x;
338  find->y = position.y;
339  find->height = data->lineHeight;
340  find->first_char = VuoImageTextData_getCharIndexForLine(data, lineIndex);
341  find->length = data->lineCounts[lineIndex];
342  find->prev_first = VuoImageTextData_getCharIndexForLine(data, MAX(0, ((int)lineIndex) - 1));
343 }
344 
348 static int VuoTextEdit_findLineIndex(int charIndex, STB_TexteditState* state)
349 {
350  VuoImageTextData data = (VuoImageTextData) state->textImageData;
351  unsigned int lineIndex = 0;
352  VuoImageTextData_getPositionForCharIndex(data, charIndex, &lineIndex);
353  return VuoImageTextData_getCharIndexForLine(data, lineIndex);
354 }
355 
360 {
361  // fprintf(stderr, "raw: %llu (%llu) hi: %llu lo: %u\n", key, (OPTION_HI | 0xd), key & VuoModifierKey_Any, (uint32_t) ((key & ~VuoModifierKey_Any) & 0xFFFF));
362 
363  uint32_t lo = (uint32_t) (key & 0xFFFF);
364 
365  if (lo == KEYCODE_RETURN)
366  return STB_TEXTEDIT_NEWLINE;
367  else if (lo == KEYCODE_TAB)
368  return '\t';
369 
370  return lo > 31 && lo < UINT32_MAX ? lo : 0;
371 }
372 
374 #define STB_TEXTEDIT_IS_SPACE(x) VuoTextEdit_isSeparator(((uint32_t)x))
375 
377 #define STB_TEXTEDIT_IS_SEPARATOR(x) VuoTextEdit_isSeparator(((uint32_t)x))
378 
386 static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int n, int i, STB_TexteditState* state)
387 {
388  VuoImageTextData data = (VuoImageTextData) state->textImageData;
389  return data->charAdvance[n + i];
390 }
391 
395 static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx, STB_TexteditState* state)
396 {
397  unsigned int len = 1;
398  VuoRectangle rect = VuoImageTextData_layoutRowAtIndex((VuoImageTextData) state->textImageData, line_start_idx, &len);
399  r->x0 = rect.center.x - (rect.size.x * .5);
400  r->x1 = rect.size.x;
401  r->baseline_y_delta = rect.size.y;
402  r->ymin = rect.center.y - (rect.size.y * .5f);
403  r->ymax = rect.size.y;
404  r->num_chars = len;
405 }
406 
410 static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n)
411 {
412  VuoText old = *obj;
413  *obj = VuoText_removeAt(old, pos + 1, n);
414  VuoRetain(*obj);
415  VuoRelease(old);
416 }
417 
421 static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const STB_TEXTEDIT_CHARTYPE* new_text, int new_text_len)
422 {
423  uint32_t new_text_32[new_text_len];
424 
425  for(int i = 0; i < new_text_len; i++)
426  new_text_32[i] = (uint32_t) (new_text[i] & 0xFFFF);
427 
428  VuoText old = *obj;
429  VuoText ascii = VuoText_makeFromUtf32(new_text_32, new_text_len);
430  VuoLocal(ascii);
431  *obj = VuoText_insert(old, pos + 1, ascii);
432  VuoRelease(old);
433  VuoRetain(*obj);
434  return true;
435 }