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