Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / util / numinput.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Jonathan Smith
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/util/numinput.c
24  *  \ingroup edutil
25  */
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_utildefines.h"
30 #include "BLI_math.h"
31 #include "BLI_string.h"
32 #include "BLI_string_utf8.h"
33 #include "BLI_string_cursor_utf8.h"
34
35 #include "BKE_context.h"
36 #include "BKE_scene.h"
37 #include "BKE_unit.h"
38
39 #include "DNA_scene_types.h"
40
41 #include "WM_api.h"
42 #include "WM_types.h"
43
44 #ifdef WITH_PYTHON
45 #include "BPY_extern.h"
46 #endif
47
48 #include "ED_numinput.h"
49 #include "UI_interface.h"
50
51 /* Numeric input which isn't allowing full numeric editing. */
52 #define USE_FAKE_EDIT
53
54 /* NumInput.flag */
55 enum {
56         /* (1 << 8) and below are reserved for public flags! */
57         NUM_EDIT_FULL       = (1 << 9),   /* Enable full editing, with units and math operators support. */
58 #ifdef USE_FAKE_EDIT
59         NUM_FAKE_EDITED     = (1 << 10),  /* Fake edited state (temp, avoids issue with backspace). */
60 #endif
61 };
62
63 /* NumInput.val_flag[] */
64 enum {
65         /* (1 << 8) and below are reserved for public flags! */
66         NUM_EDITED          = (1 << 9),    /* User has edited this value somehow. */
67         NUM_INVALID         = (1 << 10),   /* Current expression for this value is invalid. */
68 #ifdef USE_FAKE_EDIT
69         NUM_NEGATE          = (1 << 11),   /* Current expression's result has to be negated. */
70         NUM_INVERSE         = (1 << 12),   /* Current expression's result has to be inverted. */
71 #endif
72 };
73
74 /* ************************** Functions *************************** */
75
76 /* ************************** NUMINPUT **************************** */
77
78 void initNumInput(NumInput *n)
79 {
80         n->idx_max = 0;
81         n->unit_sys = USER_UNIT_NONE;
82         copy_vn_i(n->unit_type, NUM_MAX_ELEMENTS, B_UNIT_NONE);
83         n->unit_use_radians = false;
84
85         n->flag = 0;
86         copy_vn_short(n->val_flag, NUM_MAX_ELEMENTS, 0);
87         zero_v3(n->val);
88         copy_vn_fl(n->val_org, NUM_MAX_ELEMENTS, 0.0f);
89         copy_vn_fl(n->val_inc, NUM_MAX_ELEMENTS, 1.0f);
90
91         n->idx = 0;
92         n->str[0] = '\0';
93         n->str_cur = 0;
94 }
95
96 /* str must be NUM_STR_REP_LEN * (idx_max + 1) length. */
97 void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
98 {
99         short j;
100         const int ln = NUM_STR_REP_LEN;
101         int prec = 2; /* draw-only, and avoids too much issues with radian->degrees conversion. */
102
103         for (j = 0; j <= n->idx_max; j++) {
104                 /* if AFFECTALL and no number typed and cursor not on number, use first number */
105                 const short i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j;
106
107                 /* Use scale_length if needed! */
108                 const float fac = (float)BKE_scene_unit_scale(unit_settings, n->unit_type[j], 1.0);
109
110                 if (n->val_flag[i] & NUM_EDITED) {
111                         /* Get the best precision, allows us to draw '10.0001' as '10' instead! */
112                         prec = UI_calc_float_precision(prec, (double)n->val[i]);
113                         if (i == n->idx) {
114                                 const char *heading_exp = "", *trailing_exp = "";
115                                 char before_cursor[NUM_STR_REP_LEN];
116                                 char val[16];
117
118 #ifdef USE_FAKE_EDIT
119                                 if (n->val_flag[i] & NUM_NEGATE) {
120                                         heading_exp = (n->val_flag[i] & NUM_INVERSE) ? "-1/(" : "-(";
121                                         trailing_exp = ")";
122                                 }
123                                 else if (n->val_flag[i] & NUM_INVERSE) {
124                                         heading_exp = "1/(";
125                                         trailing_exp = ")";
126                                 }
127 #endif
128
129                                 if (n->val_flag[i] & NUM_INVALID) {
130                                         BLI_strncpy(val, "Invalid", sizeof(val));
131                                 }
132                                 else {
133                                         bUnit_AsString(val, sizeof(val), (double)(n->val[i] * fac), prec,
134                                                        n->unit_sys, n->unit_type[i], true, false);
135                                 }
136
137                                 BLI_strncpy(before_cursor, n->str, n->str_cur + 1);  /* +1 because of trailing '\0' */
138                                 BLI_snprintf(&str[j * ln], ln, "[%s%s|%s%s] = %s",
139                                              heading_exp, before_cursor, &n->str[n->str_cur], trailing_exp, val);
140                         }
141                         else {
142                                 const char *cur = (i == n->idx) ? "|" : "";
143                                 if (n->unit_use_radians && n->unit_type[i] == B_UNIT_ROTATION) {
144                                         /* Radian exception... */
145                                         BLI_snprintf(&str[j * ln], ln, "%s%.6gr%s", cur, n->val[i], cur);
146                                 }
147                                 else {
148                                         char tstr[NUM_STR_REP_LEN];
149                                         bUnit_AsString(tstr, ln, (double)n->val[i], prec, n->unit_sys, n->unit_type[i], true, false);
150                                         BLI_snprintf(&str[j * ln], ln, "%s%s%s", cur, tstr, cur);
151                                 }
152                         }
153                 }
154                 else {
155                         const char *cur = (i == n->idx) ? "|" : "";
156                         BLI_snprintf(&str[j * ln], ln, "%sNONE%s", cur, cur);
157                 }
158                 /* We might have cut some multi-bytes utf8 chars (e.g. trailing '°' of degrees values can become only 'A')... */
159                 BLI_utf8_invalid_strip(&str[j * ln], strlen(&str[j * ln]));
160         }
161 }
162
163 bool hasNumInput(const NumInput *n)
164 {
165         short i;
166
167 #ifdef USE_FAKE_EDIT
168         if (n->flag & NUM_FAKE_EDITED) {
169                 return true;
170         }
171 #endif
172
173         for (i = 0; i <= n->idx_max; i++) {
174                 if (n->val_flag[i] & NUM_EDITED) {
175                         return true;
176                 }
177         }
178
179         return false;
180 }
181
182 /**
183  * \warning \a vec must be set beforehand otherwise we risk uninitialized vars.
184  */
185 bool applyNumInput(NumInput *n, float *vec)
186 {
187         short i, j;
188         float val;
189
190         if (hasNumInput(n)) {
191                 for (j = 0; j <= n->idx_max; j++) {
192 #ifdef USE_FAKE_EDIT
193                         if (n->flag & NUM_FAKE_EDITED) {
194                                 val = n->val[j];
195                         }
196                         else
197 #endif
198                         {
199                                 /* if AFFECTALL and no number typed and cursor not on number, use first number */
200                                 i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j;
201                                 val = (!(n->val_flag[i] & NUM_EDITED) && n->val_flag[i] & NUM_NULL_ONE) ? 1.0f : n->val[i];
202
203                                 if (n->val_flag[i] & NUM_NO_NEGATIVE && val < 0.0f) {
204                                         val = 0.0f;
205                                 }
206                                 if (n->val_flag[i] & NUM_NO_FRACTION && val != floorf(val)) {
207                                         val = floorf(val + 0.5f);
208                                         if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
209                                                 val = 1.0f;
210                                         }
211                                 }
212                                 else if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
213                                         val = 0.0001f;
214                                 }
215                         }
216                         vec[j] = val;
217                 }
218 #ifdef USE_FAKE_EDIT
219                 n->flag &= ~NUM_FAKE_EDITED;
220 #endif
221                 return true;
222         }
223         else {
224                 /* Else, we set the 'org' values for numinput! */
225                 for (j = 0; j <= n->idx_max; j++) {
226                         n->val[j] = n->val_org[j] = vec[j];
227                 }
228                 return false;
229         }
230 }
231
232
233 static void value_to_editstr(NumInput *n, int idx)
234 {
235         const int prec = 6; /* editing, higher precision needed. */
236         n->str_cur = bUnit_AsString(n->str, NUM_STR_REP_LEN, (double)n->val[idx], prec,
237                                     n->unit_sys, n->unit_type[idx], true, false);
238 }
239
240 static bool editstr_insert_at_cursor(NumInput *n, const char *buf, const int buf_len)
241 {
242         int cur = n->str_cur;
243         int len = strlen(&n->str[cur]) + 1;  /* +1 for the trailing '\0'. */
244         int n_cur = cur + buf_len;
245
246         if (n_cur + len >= NUM_STR_REP_LEN) {
247                 return false;
248         }
249
250         memmove(&n->str[n_cur], &n->str[cur], len);
251         memcpy(&n->str[cur], buf, sizeof(char) * buf_len);
252
253         n->str_cur = n_cur;
254         return true;
255 }
256
257 bool user_string_to_number(bContext *C, const char *str, const UnitSettings *unit, int type, double *r_value)
258 {
259 #ifdef WITH_PYTHON
260         double unit_scale = BKE_scene_unit_scale(unit, type, 1.0);
261         if (!bUnit_ContainsUnit(str, unit->system, type)) {
262                 int success = BPY_execute_string_as_number(C, NULL, str, true, r_value);
263                 *r_value *= bUnit_PreferredUnitScalar(unit, type);
264                 *r_value /= unit_scale;
265                 return success;
266         }
267         else {
268                 char str_unit_convert[256];
269                 BLI_strncpy(str_unit_convert, str, sizeof(str_unit_convert));
270                 bUnit_ReplaceString(
271                         str_unit_convert, sizeof(str_unit_convert), str,
272                         unit_scale, unit->system, type);
273
274                 return BPY_execute_string_as_number(C, NULL, str_unit_convert, true, r_value);
275         }
276 #else
277         *r_value = atof(str);
278         return true;
279 #endif
280 }
281
282
283 static bool editstr_is_simple_numinput(const char ascii)
284 {
285         if (ascii >= '0' && ascii <= '9') {
286                 return true;
287         }
288         else if (ascii == '.') {
289                 return true;
290         }
291         else {
292                 return false;
293         }
294 }
295
296 bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
297 {
298         const char *utf8_buf = NULL;
299         char ascii[2] = {'\0', '\0'};
300         bool updated = false;
301         short idx = n->idx, idx_max = n->idx_max;
302         short dir = STRCUR_DIR_NEXT, mode = STRCUR_JUMP_NONE;
303         int cur;
304
305 #ifdef USE_FAKE_EDIT
306         if (U.flag & USER_FLAG_NUMINPUT_ADVANCED)
307 #endif
308         {
309                 if ((event->ctrl == 0) && (event->alt == 0) && (event->ascii != '\0') &&
310                     strchr("01234567890@%^&*-+/{}()[]<>.|", event->ascii))
311                 {
312                         if (!(n->flag & NUM_EDIT_FULL)) {
313                                 n->flag |= NUM_EDITED;
314                                 n->flag |= NUM_EDIT_FULL;
315                                 n->val_flag[idx] |= NUM_EDITED;
316                         }
317                 }
318         }
319
320         switch (event->type) {
321                 case EVT_MODAL_MAP:
322                         if (ELEM(event->val, NUM_MODAL_INCREMENT_UP, NUM_MODAL_INCREMENT_DOWN)) {
323                                 n->val[idx] += (event->val == NUM_MODAL_INCREMENT_UP) ? n->val_inc[idx] : -n->val_inc[idx];
324                                 value_to_editstr(n, idx);
325                                 n->val_flag[idx] |= NUM_EDITED;
326                                 updated = true;
327                         }
328                         else {
329                                 /* might be a char too... */
330                                 utf8_buf = event->utf8_buf;
331                                 ascii[0] = event->ascii;
332                         }
333                         break;
334                 case BACKSPACEKEY:
335                         /* Part specific to backspace... */
336                         if (!(n->val_flag[idx] & NUM_EDITED)) {
337                                 copy_v3_v3(n->val, n->val_org);
338                                 n->val_flag[0] &= ~NUM_EDITED;
339                                 n->val_flag[1] &= ~NUM_EDITED;
340                                 n->val_flag[2] &= ~NUM_EDITED;
341 #ifdef USE_FAKE_EDIT
342                                 n->flag |= NUM_FAKE_EDITED;
343 #else
344                                 n->flag |= NUM_EDIT_FULL;
345 #endif
346                                 updated = true;
347                                 break;
348                         }
349                         else if (event->shift || !n->str[0]) {
350                                 n->val[idx] = n->val_org[idx];
351                                 n->val_flag[idx] &= ~NUM_EDITED;
352                                 n->str[0] = '\0';
353                                 n->str_cur = 0;
354                                 updated = true;
355                                 break;
356                         }
357                         /* Else, common behavior with DELKEY, only difference is remove char(s) before/after the cursor. */
358                         dir = STRCUR_DIR_PREV;
359                         ATTR_FALLTHROUGH;
360                 case DELKEY:
361                         if ((n->val_flag[idx] & NUM_EDITED) && n->str[0]) {
362                                 int t_cur = cur = n->str_cur;
363                                 if (event->ctrl) {
364                                         mode = STRCUR_JUMP_DELIM;
365                                 }
366                                 BLI_str_cursor_step_utf8(n->str, strlen(n->str), &t_cur, dir, mode, true);
367                                 if (t_cur != cur) {
368                                         if (t_cur < cur) {
369                                                 SWAP(int, t_cur, cur);
370                                                 n->str_cur = cur;
371                                         }
372                                         memmove(&n->str[cur], &n->str[t_cur], strlen(&n->str[t_cur]) + 1);  /* +1 for trailing '\0'. */
373                                         updated = true;
374                                 }
375                                 if (!n->str[0]) {
376                                         n->val[idx] = n->val_org[idx];
377                                 }
378                         }
379                         else {
380                                 return false;
381                         }
382                         break;
383                 case LEFTARROWKEY:
384                         dir = STRCUR_DIR_PREV;
385                         ATTR_FALLTHROUGH;
386                 case RIGHTARROWKEY:
387                         cur = n->str_cur;
388                         if (event->ctrl) {
389                                 mode = STRCUR_JUMP_DELIM;
390                         }
391                         BLI_str_cursor_step_utf8(n->str, strlen(n->str), &cur, dir, mode, true);
392                         if (cur != n->str_cur) {
393                                 n->str_cur = cur;
394                                 return true;
395                         }
396                         return false;
397                 case HOMEKEY:
398                         if (n->str[0]) {
399                                 n->str_cur = 0;
400                                 return true;
401                         }
402                         return false;
403                 case ENDKEY:
404                         if (n->str[0]) {
405                                 n->str_cur = strlen(n->str);
406                                 return true;
407                         }
408                         return false;
409                 case TABKEY:
410 #ifdef USE_FAKE_EDIT
411                         n->val_flag[idx] &= ~(NUM_NEGATE | NUM_INVERSE);
412 #endif
413
414                         idx = (idx + idx_max + (event->ctrl ? 0 : 2)) % (idx_max + 1);
415                         n->idx = idx;
416                         if (n->val_flag[idx] & NUM_EDITED) {
417                                 value_to_editstr(n, idx);
418                         }
419                         else {
420                                 n->str[0] = '\0';
421                                 n->str_cur = 0;
422                         }
423                         return true;
424                 case PADPERIOD:
425                 case PERIODKEY:
426                         /* Force numdot, some OSs/countries generate a comma char in this case, sic...  (T37992) */
427                         ascii[0] = '.';
428                         utf8_buf = ascii;
429                         break;
430 #if 0
431                 /* Those keys are not directly accessible in all layouts, preventing to generate matching events.
432                  * So we use a hack (ascii value) instead, see below.
433                  */
434                 case EQUALKEY:
435                 case PADASTERKEY:
436                         if (!(n->flag & NUM_EDIT_FULL)) {
437                                 n->flag |= NUM_EDIT_FULL;
438                                 n->val_flag[idx] |= NUM_EDITED;
439                                 return true;
440                         }
441                         else if (event->ctrl) {
442                                 n->flag &= ~NUM_EDIT_FULL;
443                                 return true;
444                         }
445                         break;
446 #endif
447
448 #ifdef USE_FAKE_EDIT
449                 case PADMINUS:
450                 case MINUSKEY:
451                         if (event->ctrl || !(n->flag & NUM_EDIT_FULL)) {
452                                 n->val_flag[idx] ^= NUM_NEGATE;
453                                 updated = true;
454                         }
455                         break;
456                 case PADSLASHKEY:
457                 case SLASHKEY:
458                         if (event->ctrl || !(n->flag & NUM_EDIT_FULL)) {
459                                 n->val_flag[idx] ^= NUM_INVERSE;
460                                 updated = true;
461                         }
462                         break;
463 #endif
464                 case CKEY:
465                         if (event->ctrl) {
466                                 /* Copy current str to the copypaste buffer. */
467                                 WM_clipboard_text_set(n->str, 0);
468                                 updated = true;
469                         }
470                         break;
471                 case VKEY:
472                         if (event->ctrl) {
473                                 /* extract the first line from the clipboard */
474                                 int pbuf_len;
475                                 char *pbuf = WM_clipboard_text_get_firstline(false, &pbuf_len);
476
477                                 if (pbuf) {
478                                         const bool success = editstr_insert_at_cursor(n, pbuf, pbuf_len);
479
480                                         MEM_freeN(pbuf);
481                                         if (!success) {
482                                                 return false;
483                                         }
484
485                                         n->val_flag[idx] |= NUM_EDITED;
486                                 }
487                                 updated = true;
488                         }
489                         break;
490                 default:
491                         break;
492         }
493
494         if (!updated && !utf8_buf && (event->utf8_buf[0] || event->ascii)) {
495                 utf8_buf = event->utf8_buf;
496                 ascii[0] = event->ascii;
497         }
498
499 #ifdef USE_FAKE_EDIT
500         /* XXX Hack around keyboards without direct access to '=' nor '*'... */
501         if (ELEM(ascii[0], '=', '*')) {
502                 if (!(n->flag & NUM_EDIT_FULL)) {
503                         n->flag |= NUM_EDIT_FULL;
504                         n->val_flag[idx] |= NUM_EDITED;
505                         return true;
506                 }
507                 else if (event->ctrl) {
508                         n->flag &= ~NUM_EDIT_FULL;
509                         return true;
510                 }
511         }
512 #endif
513
514         /* Up to this point, if we have a ctrl modifier, skip.
515          * This allows to still access most of modals' shortcuts even in numinput mode.
516          */
517         if (!updated && event->ctrl) {
518                 return false;
519         }
520
521         if ((!utf8_buf || !utf8_buf[0]) && ascii[0]) {
522                 /* Fallback to ascii. */
523                 utf8_buf = ascii;
524         }
525
526         if (utf8_buf && utf8_buf[0]) {
527                 if (!(n->flag & NUM_EDIT_FULL)) {
528                         /* In simple edit mode, we only keep a few chars as valid! */
529                         /* no need to decode unicode, ascii is first char only */
530                         if (!editstr_is_simple_numinput(utf8_buf[0])) {
531                                 return false;
532                         }
533                 }
534
535                 if (!editstr_insert_at_cursor(n, utf8_buf, BLI_str_utf8_size(utf8_buf))) {
536                         return false;
537                 }
538
539                 n->val_flag[idx] |= NUM_EDITED;
540         }
541         else if (!updated) {
542                 return false;
543         }
544
545         /* At this point, our value has changed, try to interpret it with python (if str is not empty!). */
546         if (n->str[0]) {
547                 const float val_prev = n->val[idx];
548                 Scene *sce = CTX_data_scene(C);
549
550                 double val;
551                 int success = user_string_to_number(C, n->str, &sce->unit, n->unit_type[idx], &val);
552
553                 if (success) {
554                         n->val[idx] = (float)val;
555                         n->val_flag[idx] &= ~NUM_INVALID;
556                 }
557                 else {
558                         n->val_flag[idx] |= NUM_INVALID;
559                 }
560
561
562 #ifdef USE_FAKE_EDIT
563                 if (n->val_flag[idx] & NUM_NEGATE) {
564                         n->val[idx] = -n->val[idx];
565                 }
566                 if (n->val_flag[idx] & NUM_INVERSE) {
567                         val = n->val[idx];
568                         /* If we invert on radians when user is in degrees, you get unexpected results... See T53463. */
569                         if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) {
570                                 val = RAD2DEG(val);
571                         }
572                         val = 1.0 / val;
573                         if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) {
574                                 val = DEG2RAD(val);
575                         }
576                         n->val[idx] = (float)val;
577                 }
578 #endif
579
580                 if (UNLIKELY(!isfinite(n->val[idx]))) {
581                         n->val[idx] = val_prev;
582                         n->val_flag[idx] |= NUM_INVALID;
583                 }
584         }
585
586         /* REDRAW SINCE NUMBERS HAVE CHANGED */
587         return true;
588 }