Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2020-06-01 15:22:27 +0300
committerHans Goudey <h.goudey@me.com>2020-06-01 15:22:27 +0300
commit45dbc38a8b156a6e704575f4935c7f3f9cf96e5d (patch)
treee9987512a5e88c075a2db210b392b287f0a44ec7 /source/blender
parent8d670546f916596977bffbc614c58bddf2f2b707 (diff)
Fix T74552: Distribute negatives in number input
This applies a relatively simple solution for fixing some unintuitive cases in unit handling. Currently entering -1m50cm evaluates to -0.5m, and similarly 1'6" evaulates to just half a foot. So effectively there's an implied + just between the numbers, which is quite confusing. This works by adding parentheses so the negative distributes to the block of values before the next operator. For example: | Before | After | | `-1m50cm + 1m -2m50cm` | `-(1m50cm) + 1m -(2m50cm)` | | `-4m + 0.5 / -1.1` | `-(4m) + 0.5 / -(1.1)` | | `-1'6"` | `-(1'6")` | | `-1e-2cm` | `-(1e-2cm) ` | Reviewed By: campbellbarton Differential Revision: https://developer.blender.org/D7813
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/intern/unit.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 3f44c13ba19..77e51f9d8c0 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -713,6 +713,116 @@ static bool ch_is_op(char op)
}
}
+/**
+ * Helper function for #unit_distribute_negatives to find the next negative to distribute.
+ *
+ * \note This unecessarily skips the next space if it comes right after the "-"
+ * just to make a more predictable output.
+ */
+static char *find_next_negative(const char *str, const char *remaining_str)
+{
+ char *str_found = strstr(remaining_str, "-");
+
+ if (str_found == NULL) {
+ return NULL;
+ }
+
+ /* Don't use the "-" from scientific notation, but make sure we can look backwards first. */
+ if ((str_found != str) && (*(str_found - 1) == 'e' || *(str_found - 1) == 'E')) {
+ return find_next_negative(str, str_found + 1);
+ }
+
+ if (*(str_found + 1) == ' ') {
+ str_found++;
+ }
+
+ return str_found + 1;
+}
+
+/**
+ * Helper function for #unit_distribute_negatives to find the next operation, including "-".
+ *
+ * \note This unecessarily skips the space before the operation character
+ * just to make a more predictable output.
+ */
+static char *find_next_op(const char *str, char *remaining_str, int len_max)
+{
+ int i;
+ bool scientific_notation = false;
+ for (i = 0; i < len_max; i++) {
+ if (remaining_str[i] == '\0') {
+ return remaining_str + i;
+ }
+
+ if (ch_is_op(remaining_str[i])) {
+ if (scientific_notation) {
+ scientific_notation = false;
+ continue;
+ }
+
+ /* Make sure we don't look backwards before the start of the string. */
+ if (remaining_str != str && i != 0) {
+ /* Check for scientific notation. */
+ if (remaining_str[i - 1] == 'e' || remaining_str[i - 1] == 'E') {
+ scientific_notation = true;
+ continue;
+ }
+
+ /* Return position before a space character. */
+ if (remaining_str[i - 1] == ' ') {
+ i--;
+ }
+ }
+
+ return remaining_str + i;
+ }
+ }
+ BLI_assert(!"String should be NULL terminated");
+ return remaining_str + i;
+}
+
+/**
+ * Put parentheses around blocks of values after negative signs to get rid of an implied "+"
+ * between numbers without an operation between them. For example:
+ *
+ * "-1m50cm + 1 - 2m50cm" -> "-(1m50cm) + 1 - (2m50cm)"
+ */
+static bool unit_distribute_negatives(char *str, const int len_max)
+{
+ bool changed = false;
+
+ char *remaining_str = str;
+ int remaining_str_len = len_max;
+ int ofs = 0;
+ while ((remaining_str = find_next_negative(str, remaining_str)) != NULL) {
+ ofs = (int)(remaining_str - str);
+
+ /* Exit early in the unlikely situation that we've run out of length to add the parentheses. */
+ remaining_str_len = len_max - ofs;
+ if (remaining_str_len <= 2) {
+ return changed;
+ }
+
+ changed = true;
+
+ /* Add '(', shift the following characters to the right to make space. */
+ memmove(remaining_str + 1, remaining_str, remaining_str_len - 1);
+ *remaining_str = '(';
+
+ /* Add the ')' before the next operation or at the end. */
+ remaining_str = find_next_op(str, remaining_str + 1, remaining_str_len);
+ memmove(remaining_str + 1, remaining_str, remaining_str_len - 3);
+ *remaining_str = ')';
+
+ /* Only move forward by 1 even though we added two characters. Minus signs need to be able to
+ * apply to the next block of values too. */
+ remaining_str += 1;
+ remaining_str_len -= 1;
+ }
+
+ return changed;
+}
+
static int unit_scale_str(char *str,
int len_max,
char *str_tmp,
@@ -896,6 +1006,9 @@ bool bUnit_ReplaceString(
char str_tmp[TEMP_STR_SIZE];
bool changed = false;
+ /* Fix cases like "-1m50cm" which would evaluate to -0.5m without this. */
+ changed |= unit_distribute_negatives(str, len_max);
+
/* Try to find a default unit from current or previous string. */
default_unit = unit_detect_from_str(usys, str, str_prev);