Blender V4.5
numinput.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "BLI_math_rotation.h"
12#include "BLI_math_vector.h"
13#include "BLI_string.h"
15#include "BLI_string_utf8.h"
16#include "BLI_utildefines.h"
17
18#include "BLT_translation.hh"
19
20#include "BKE_context.hh"
21#include "BKE_report.hh"
22#include "BKE_unit.hh"
23
24#include "DNA_scene_types.h"
25
26#include "WM_api.hh"
27#include "WM_types.hh"
28
29#ifdef WITH_PYTHON
30# include "BPY_extern_run.hh"
31#endif
32
33#include "ED_numinput.hh"
34#include "UI_interface.hh"
35
36/* Numeric input which isn't allowing full numeric editing. */
37#define USE_FAKE_EDIT
38
43enum {
45 NUM_EDIT_FULL = (1 << 9),
46#ifdef USE_FAKE_EDIT
48 NUM_FAKE_EDITED = (1 << 10),
49#endif
50};
51
52/* NumInput.val_flag[] */
53enum {
54 /* (1 << 8) and below are reserved for public flags! */
56 NUM_EDITED = (1 << 9),
57 NUM_INVALID = (1 << 10),
58#ifdef USE_FAKE_EDIT
60 NUM_NEGATE = (1 << 11),
61 NUM_INVERSE = (1 << 12),
62#endif
63};
64
65/* ************************** Functions *************************** */
66
67/* ************************** NUMINPUT **************************** */
68
70{
71 n->idx_max = 0;
74 n->unit_use_radians = false;
75
76 n->flag = 0;
78 zero_v3(n->val);
81
82 n->idx = 0;
83 n->str[0] = '\0';
84 n->str_cur = 0;
85}
86
87void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
88{
89 short j;
90 const int ln = NUM_STR_REP_LEN;
91 int prec = 2; /* draw-only, and avoids too much issues with radian->degrees conversion. */
92
93 for (j = 0; j <= n->idx_max; j++) {
94 /* if AFFECTALL and no number typed and cursor not on number, use first number */
95 const short i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ?
96 0 :
97 j;
98
99 /* Use scale_length if needed! */
100 const float fac = float(BKE_unit_value_scale(unit_settings, n->unit_type[j], 1.0));
101
102 if (n->val_flag[i] & NUM_EDITED) {
103 /* Get the best precision, allows us to draw '10.0001' as '10' instead! */
104 prec = UI_calc_float_precision(prec, double(n->val[i]));
105 if (i == n->idx) {
106 const char *heading_exp = "", *trailing_exp = "";
107 char before_cursor[NUM_STR_REP_LEN];
108 char val[16];
109
110#ifdef USE_FAKE_EDIT
111 if (n->val_flag[i] & NUM_NEGATE) {
112 heading_exp = (n->val_flag[i] & NUM_INVERSE) ? "-1/(" : "-(";
113 trailing_exp = ")";
114 }
115 else if (n->val_flag[i] & NUM_INVERSE) {
116 heading_exp = "1/(";
117 trailing_exp = ")";
118 }
119#endif
120
121 if (n->val_flag[i] & NUM_INVALID) {
122 STRNCPY(val, RPT_("Invalid"));
123 }
124 else {
126 sizeof(val),
127 double(n->val[i] * fac),
128 prec,
129 n->unit_sys,
130 n->unit_type[i],
131 true,
132 false);
133 }
134
135 /* +1 because of trailing '\0' */
136 BLI_strncpy(before_cursor, n->str, n->str_cur + 1);
137 BLI_snprintf(&str[j * ln],
138 ln,
139 "[%s%s|%s%s] = %s",
140 heading_exp,
141 before_cursor,
142 &n->str[n->str_cur],
143 trailing_exp,
144 val);
145 }
146 else {
147 const char *cur = (i == n->idx) ? "|" : "";
148 if (n->unit_use_radians && n->unit_type[i] == B_UNIT_ROTATION) {
149 /* Radian exception... */
150 BLI_snprintf(&str[j * ln], ln, "%s%.6gr%s", cur, n->val[i], cur);
151 }
152 else {
153 char tstr[NUM_STR_REP_LEN];
155 tstr, ln, double(n->val[i]), prec, n->unit_sys, n->unit_type[i], true, false);
156 BLI_snprintf(&str[j * ln], ln, "%s%s%s", cur, tstr, cur);
157 }
158 }
159 }
160 else {
161 const char *cur = (i == n->idx) ? "|" : "";
162 BLI_snprintf(&str[j * ln], ln, "%sNONE%s", cur, cur);
163 }
164 /* We might have cut some multi-bytes UTF8 chars
165 * (e.g. trailing degrees symbol values can become only 'A'). */
166 BLI_str_utf8_invalid_strip(&str[j * ln], strlen(&str[j * ln]));
167 }
168}
169
170bool hasNumInput(const NumInput *n)
171{
172 short i;
173
174#ifdef USE_FAKE_EDIT
175 if (n->flag & NUM_FAKE_EDITED) {
176 return true;
177 }
178#endif
179
180 for (i = 0; i <= n->idx_max; i++) {
181 if (n->val_flag[i] & NUM_EDITED) {
182 return true;
183 }
184 }
185
186 return false;
187}
188
189bool applyNumInput(NumInput *n, float *vec)
190{
191 short i, j;
192 float val;
193
194 if (hasNumInput(n)) {
195 for (j = 0; j <= n->idx_max; j++) {
196#ifdef USE_FAKE_EDIT
197 if (n->flag & NUM_FAKE_EDITED) {
198 val = n->val[j];
199 }
200 else
201#endif
202 {
203 /* if AFFECTALL and no number typed and cursor not on number, use first number */
204 i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j;
205 val = (!(n->val_flag[i] & NUM_EDITED) && n->val_flag[i] & NUM_NULL_ONE) ? 1.0f : n->val[i];
206
207 if (n->val_flag[i] & NUM_NO_NEGATIVE && val < 0.0f) {
208 val = 0.0f;
209 }
210 if (n->val_flag[i] & NUM_NO_FRACTION && val != floorf(val)) {
211 val = floorf(val + 0.5f);
212 if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
213 val = 1.0f;
214 }
215 }
216 else if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
217 val = 0.0001f;
218 }
219 }
220 vec[j] = val;
221 }
222#ifdef USE_FAKE_EDIT
224#endif
225 return true;
226 }
227
228 /* Else, we set the 'org' values for numinput! */
229 for (j = 0; j <= n->idx_max; j++) {
230 n->val[j] = n->val_org[j] = vec[j];
231 }
232 return false;
233}
234
235static void value_to_editstr(NumInput *n, int idx)
236{
237 const int prec = 6; /* editing, higher precision needed. */
240 double(n->val[idx]),
241 prec,
242 n->unit_sys,
243 n->unit_type[idx],
244 true,
245 false);
246}
247
248static bool editstr_insert_at_cursor(NumInput *n, const char *buf, const int buf_len)
249{
250 int cur = n->str_cur;
251 int len = strlen(&n->str[cur]) + 1; /* +1 for the trailing '\0'. */
252 int n_cur = cur + buf_len;
253
254 if (n_cur + len >= NUM_STR_REP_LEN) {
255 return false;
256 }
257
258 memmove(&n->str[n_cur], &n->str[cur], len);
259 memcpy(&n->str[cur], buf, sizeof(char) * buf_len);
260
261 n->str_cur = n_cur;
262 return true;
263}
264
266 const char *str,
267 const UnitSettings &unit,
268 int type,
269 double *r_value,
270 const bool use_single_line_error,
271 char **r_error)
272{
273#ifdef WITH_PYTHON
274 BPy_RunErrInfo err_info{};
275 err_info.use_single_line_error = use_single_line_error;
276 err_info.r_string = r_error;
277
278 const double unit_scale = BKE_unit_value_scale(unit, type, 1.0);
280 char str_unit_convert[256];
281 STRNCPY(str_unit_convert, str);
283 str_unit_convert, sizeof(str_unit_convert), str, unit_scale, unit.system, type);
284
285 return BPY_run_string_as_number(C, nullptr, str_unit_convert, &err_info, r_value);
286 }
287
288 bool success = BPY_run_string_as_number(C, nullptr, str, &err_info, r_value);
289 *r_value = BKE_unit_apply_preferred_unit(unit, type, *r_value);
290 *r_value /= unit_scale;
291 return success;
292
293#else
294 UNUSED_VARS(C, unit, type, use_single_line_error, r_error);
295 *r_value = atof(str);
296 return true;
297#endif
298}
299
300static bool editstr_is_simple_numinput(const char ascii)
301{
302 if (ascii >= '0' && ascii <= '9') {
303 return true;
304 }
305 if (ascii == '.') {
306 return true;
307 }
308 return false;
309}
310
311bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
312{
313 const char *utf8_buf = nullptr;
314 const char event_ascii = WM_event_utf8_to_ascii(event);
315 char ascii[2] = {'\0', '\0'};
316 bool updated = false;
317 short idx = n->idx, idx_max = n->idx_max;
318 short dir = STRCUR_DIR_NEXT, mode = STRCUR_JUMP_NONE;
319 int cur;
320
321#ifdef USE_FAKE_EDIT
323#endif
324 {
325 if (((event->modifier & (KM_CTRL | KM_ALT)) == 0) && (event_ascii != '\0') &&
326 strchr("01234567890@%^&*-+/{}()[]<>.|", event_ascii))
327 {
328 if (!(n->flag & NUM_EDIT_FULL)) {
329 n->flag |= NUM_EDITED;
330 n->flag |= NUM_EDIT_FULL;
331 n->val_flag[idx] |= NUM_EDITED;
332 }
333 }
334 }
335
336#ifdef USE_FAKE_EDIT
337 /* XXX Hack around keyboards without direct access to '=' nor '*'... */
338 if (ELEM(event_ascii, '=', '*')) {
339 if (!(n->flag & NUM_EDIT_FULL)) {
340 n->flag |= NUM_EDIT_FULL;
341 n->val_flag[idx] |= NUM_EDITED;
342 return true;
343 }
344 if (event->modifier & KM_CTRL) {
345 n->flag &= ~NUM_EDIT_FULL;
346 return true;
347 }
348 }
349#endif
350
351 switch (event->type) {
352 case EVT_MODAL_MAP:
354 n->val[idx] += (event->val == NUM_MODAL_INCREMENT_UP) ? n->val_inc[idx] : -n->val_inc[idx];
355 value_to_editstr(n, idx);
356 n->val_flag[idx] |= NUM_EDITED;
357 updated = true;
358 }
359 else {
360 /* might be a char too... */
361 utf8_buf = event->utf8_buf;
362 ascii[0] = event_ascii;
363 }
364 break;
365 case EVT_BACKSPACEKEY:
366 /* Part specific to backspace... */
367 if (!(n->val_flag[idx] & NUM_EDITED)) {
368 copy_v3_v3(n->val, n->val_org);
369 n->val_flag[0] &= ~NUM_EDITED;
370 n->val_flag[1] &= ~NUM_EDITED;
371 n->val_flag[2] &= ~NUM_EDITED;
372#ifdef USE_FAKE_EDIT
373 n->flag |= NUM_FAKE_EDITED;
374#else
375 n->flag |= NUM_EDIT_FULL;
376#endif
377 updated = true;
378 break;
379 }
380 else if ((event->modifier & KM_SHIFT) || !n->str[0]) {
381 n->val[idx] = n->val_org[idx];
382 n->val_flag[idx] &= ~NUM_EDITED;
383 n->str[0] = '\0';
384 n->str_cur = 0;
385 updated = true;
386 break;
387 }
388 /* Else, common behavior with DELKEY,
389 * only difference is remove char(s) before/after the cursor. */
390 dir = STRCUR_DIR_PREV;
392 case EVT_DELKEY:
393 if ((n->val_flag[idx] & NUM_EDITED) && n->str[0]) {
394 int t_cur = cur = n->str_cur;
395 if (event->modifier & KM_CTRL) {
396 mode = STRCUR_JUMP_DELIM;
397 }
399 strlen(n->str),
400 &t_cur,
402 eStrCursorJumpType(mode),
403 true);
404 if (t_cur != cur) {
405 if (t_cur < cur) {
406 std::swap(t_cur, cur);
407 n->str_cur = cur;
408 }
409 /* +1 for trailing '\0'. */
410 memmove(&n->str[cur], &n->str[t_cur], strlen(&n->str[t_cur]) + 1);
411 updated = true;
412 }
413 if (!n->str[0]) {
414 n->val[idx] = n->val_org[idx];
415 }
416 }
417 else {
418 return false;
419 }
420 break;
421 case EVT_LEFTARROWKEY:
422 dir = STRCUR_DIR_PREV;
425 cur = n->str_cur;
426 if (event->modifier & KM_CTRL) {
427 mode = STRCUR_JUMP_DELIM;
428 }
430 strlen(n->str),
431 &cur,
433 eStrCursorJumpType(mode),
434 true);
435 if (cur != n->str_cur) {
436 n->str_cur = cur;
437 return true;
438 }
439 return false;
440 case EVT_HOMEKEY:
441 if (n->str[0]) {
442 n->str_cur = 0;
443 return true;
444 }
445 return false;
446 case EVT_ENDKEY:
447 if (n->str[0]) {
448 n->str_cur = strlen(n->str);
449 return true;
450 }
451 return false;
452 case EVT_TABKEY:
453#ifdef USE_FAKE_EDIT
454 n->val_flag[idx] &= ~(NUM_NEGATE | NUM_INVERSE);
455#endif
456
457 idx = (idx + idx_max + ((event->modifier & KM_CTRL) ? 0 : 2)) % (idx_max + 1);
458 n->idx = idx;
459 if (n->val_flag[idx] & NUM_EDITED) {
460 value_to_editstr(n, idx);
461 }
462 else {
463 n->str[0] = '\0';
464 n->str_cur = 0;
465 }
466 return true;
467 case EVT_PADPERIOD:
468 case EVT_PERIODKEY:
469 /* Force number-pad "." since some OS's/countries generate a comma char, see: #37992 */
470 ascii[0] = '.';
471 utf8_buf = ascii;
472 break;
473#if 0
474 /* Those keys are not directly accessible in all layouts,
475 * preventing to generate matching events.
476 * So we use a hack (ASCII value) instead, see below. */
477 case EQUALKEY:
478 case PADASTERKEY:
479 if (!(n->flag & NUM_EDIT_FULL)) {
480 n->flag |= NUM_EDIT_FULL;
481 n->val_flag[idx] |= NUM_EDITED;
482 return true;
483 }
484 else if (event->modifier & KM_CTRL) {
485 n->flag &= ~NUM_EDIT_FULL;
486 return true;
487 }
488 break;
489#endif
490
491#ifdef USE_FAKE_EDIT
492 case EVT_PADMINUS:
493 case EVT_MINUSKEY:
494 if ((event->modifier & KM_CTRL) || !(n->flag & NUM_EDIT_FULL)) {
495 n->val_flag[idx] ^= NUM_NEGATE;
496 updated = true;
497 }
498 break;
499 case EVT_PADSLASHKEY:
500 case EVT_SLASHKEY:
501 if ((event->modifier & KM_CTRL) || !(n->flag & NUM_EDIT_FULL)) {
502 n->val_flag[idx] ^= NUM_INVERSE;
503 updated = true;
504 }
505 break;
506#endif
507 case EVT_CKEY:
508 if (event->modifier & KM_CTRL) {
509 /* Copy current `str` to the copy/paste buffer. */
510 WM_clipboard_text_set(n->str, false);
511 updated = true;
512 }
513 break;
514 case EVT_VKEY:
515 if (event->modifier & KM_CTRL) {
516 /* extract the first line from the clipboard */
517 int pbuf_len;
518 char *pbuf = WM_clipboard_text_get_firstline(false, true, &pbuf_len);
519
520 if (pbuf) {
521 const bool success = editstr_insert_at_cursor(n, pbuf, pbuf_len);
522
523 MEM_freeN(pbuf);
524 if (!success) {
525 return false;
526 }
527
528 n->val_flag[idx] |= NUM_EDITED;
529 }
530 updated = true;
531 }
532 break;
533 default:
534 break;
535 }
536
537 if (!updated && !utf8_buf && event->utf8_buf[0]) {
538 utf8_buf = event->utf8_buf;
539 ascii[0] = event_ascii;
540 }
541
542 /* Up to this point, if we have a ctrl modifier, skip.
543 * This allows to still access most of modals' shortcuts even in numinput mode.
544 */
545 if (!updated && (event->modifier & KM_CTRL)) {
546 return false;
547 }
548
549 if ((!utf8_buf || !utf8_buf[0]) && ascii[0]) {
550 /* Fall back to ascii. */
551 utf8_buf = ascii;
552 }
553
554 if (utf8_buf && utf8_buf[0]) {
555 if (!(n->flag & NUM_EDIT_FULL)) {
556 /* In simple edit mode, we only keep a few chars as valid! */
557 /* no need to decode unicode, ASCII is first char only. */
558 if (!editstr_is_simple_numinput(utf8_buf[0])) {
559 return false;
560 }
561 }
562
563 const int utf8_buf_len = BLI_str_utf8_size_or_error(utf8_buf);
564 BLI_assert(utf8_buf_len != -1);
565 if (!editstr_insert_at_cursor(n, utf8_buf, utf8_buf_len)) {
566 return false;
567 }
568
569 n->val_flag[idx] |= NUM_EDITED;
570 }
571 else if (!updated) {
572 return false;
573 }
574
575 /* At this point, our value has changed, try to interpret it with python
576 * (if str is not empty!). */
577 if (n->str[0]) {
578 const float val_prev = n->val[idx];
579 Scene *sce = CTX_data_scene(C);
580 char *error = nullptr;
581
582 double val;
583 int success = user_string_to_number(
584 C, n->str, sce->unit, n->unit_type[idx], &val, false, &error);
585
586 if (error) {
588 printf("%s\n", error);
590 BKE_report(reports, RPT_ERROR, "Numeric input evaluation");
592 }
593
594 if (success) {
595 n->val[idx] = float(val);
596 n->val_flag[idx] &= ~NUM_INVALID;
597 }
598 else {
599 n->val_flag[idx] |= NUM_INVALID;
600 }
601
602#ifdef USE_FAKE_EDIT
603 if (n->val_flag[idx] & NUM_NEGATE) {
604 n->val[idx] = -n->val[idx];
605 }
606 if (n->val_flag[idx] & NUM_INVERSE) {
607 val = n->val[idx];
608 /* If we invert on radians when user is in degrees,
609 * you get unexpected results... See #53463. */
610 if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) {
611 val = RAD2DEG(val);
612 }
613 val = 1.0 / val;
614 if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) {
615 val = DEG2RAD(val);
616 }
617 n->val[idx] = float(val);
618 }
619#endif
620
621 if (UNLIKELY(!isfinite(n->val[idx]))) {
622 n->val[idx] = val_prev;
623 n->val_flag[idx] |= NUM_INVALID;
624 }
625 }
626
627 /* REDRAW SINCE NUMBERS HAVE CHANGED */
628 return true;
629}
ReportList * CTX_wm_reports(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
double BKE_unit_value_scale(const UnitSettings &settings, int unit_type, double value)
Definition unit.cc:1901
@ B_UNIT_ROTATION
Definition BKE_unit.hh:128
@ B_UNIT_NONE
Definition BKE_unit.hh:123
bool BKE_unit_replace_string(char *str, int str_maxncpy, const char *str_prev, double scale_pref, int system, int type)
Definition unit.cc:2351
double BKE_unit_apply_preferred_unit(const UnitSettings &settings, int type, double value)
Definition unit.cc:2339
bool BKE_unit_string_contains_unit(const char *str, int type)
Definition unit.cc:2325
size_t BKE_unit_value_as_string_adaptive(char *str, int str_maxncpy, double value, int prec, int system, int type, bool split, bool pad)
Definition unit.cc:1863
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ATTR_FALLTHROUGH
#define DEG2RAD(_deg)
#define RAD2DEG(_rad)
void copy_vn_short(short *array_tar, int size, short val)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void copy_vn_fl(float *array_tar, int size, float val)
void copy_vn_i(int *array_tar, int size, int val)
MINLINE void zero_v3(float r[3])
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
eStrCursorJumpDirection
@ STRCUR_DIR_NEXT
@ STRCUR_DIR_PREV
void BLI_str_cursor_step_utf8(const char *str, int str_maxlen, int *pos, eStrCursorJumpDirection direction, eStrCursorJumpType jump, bool use_init_step)
@ STRCUR_JUMP_NONE
@ STRCUR_JUMP_DELIM
int BLI_str_utf8_invalid_strip(char *str, size_t str_len) ATTR_NONNULL(1)
const char int BLI_str_utf8_size_or_error(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define UNUSED_VARS(...)
#define UNLIKELY(x)
#define ELEM(...)
#define RPT_(msgid)
bool BPY_run_string_as_number(bContext *C, const char *imports[], const char *expr, BPy_RunErrInfo *err_info, double *r_value) ATTR_NONNULL(1
@ USER_UNIT_NONE
@ USER_FLAG_NUMINPUT_ADVANCED
#define NUM_STR_REP_LEN
#define NUM_MODAL_INCREMENT_DOWN
#define NUM_MAX_ELEMENTS
@ NUM_AFFECT_ALL
#define NUM_MODAL_INCREMENT_UP
@ NUM_NO_NEGATIVE
@ NUM_NULL_ONE
@ NUM_NO_ZERO
@ NUM_NO_FRACTION
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
int UI_calc_float_precision(int prec, double value)
@ KM_CTRL
Definition WM_types.hh:276
@ KM_ALT
Definition WM_types.hh:277
@ KM_SHIFT
Definition WM_types.hh:275
ReportList * reports
Definition WM_types.hh:1025
#define U
#define floorf(x)
#define str(s)
#define printf(...)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static void error(const char *str)
bool user_string_to_number(bContext *C, const char *str, const UnitSettings &unit, int type, double *r_value, const bool use_single_line_error, char **r_error)
Definition numinput.cc:265
static void value_to_editstr(NumInput *n, int idx)
Definition numinput.cc:235
void initNumInput(NumInput *n)
Definition numinput.cc:69
static bool editstr_is_simple_numinput(const char ascii)
Definition numinput.cc:300
@ NUM_INVERSE
Definition numinput.cc:61
@ NUM_NEGATE
Definition numinput.cc:60
@ NUM_INVALID
Definition numinput.cc:57
@ NUM_EDITED
Definition numinput.cc:56
@ NUM_FAKE_EDITED
Definition numinput.cc:48
@ NUM_EDIT_FULL
Definition numinput.cc:45
static bool editstr_insert_at_cursor(NumInput *n, const char *buf, const int buf_len)
Definition numinput.cc:248
#define USE_FAKE_EDIT
Definition numinput.cc:37
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
Definition numinput.cc:311
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:189
void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
Definition numinput.cc:87
bool hasNumInput(const NumInput *n)
Definition numinput.cc:170
short idx_max
float val[NUM_MAX_ELEMENTS]
short val_flag[NUM_MAX_ELEMENTS]
float val_inc[NUM_MAX_ELEMENTS]
char str[NUM_STR_REP_LEN]
float val_org[NUM_MAX_ELEMENTS]
int unit_type[NUM_MAX_ELEMENTS]
short flag
bool unit_use_radians
short idx
struct UnitSettings unit
wmEventModifierFlag modifier
Definition WM_types.hh:771
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
char utf8_buf[6]
Definition WM_types.hh:768
i
Definition text_draw.cc:230
uint len
char WM_event_utf8_to_ascii(const wmEvent *event)
@ EVT_PADPERIOD
@ EVT_MODAL_MAP
@ EVT_VKEY
@ EVT_PERIODKEY
@ EVT_PADSLASHKEY
@ EVT_DELKEY
@ EVT_CKEY
@ EVT_TABKEY
@ EVT_MINUSKEY
@ EVT_RIGHTARROWKEY
@ EVT_HOMEKEY
@ EVT_ENDKEY
@ EVT_PADMINUS
@ EVT_SLASHKEY
@ EVT_LEFTARROWKEY
@ EVT_BACKSPACEKEY
void WM_clipboard_text_set(const char *buf, bool selection)
char * WM_clipboard_text_get_firstline(bool selection, bool ensure_utf8, int *r_len)