patch [#23758] Better handling of UTF chars in UNITS fields (lengths, angles, etc.)
authorCampbell Barton <ideasman42@gmail.com>
Wed, 15 Sep 2010 17:37:00 +0000 (17:37 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 15 Sep 2010 17:37:00 +0000 (17:37 +0000)
from Lorenzo Tozzi (oni_niubbo) with minor edits.

--- from the tracker
The present situation is this: due to bug#22274, during editing, UTF chars are stripped from buttons with a unit associated
(length, angles, etc.).
Example: if the button displays '90°' and you click on it with LMB, the editing string will become '90'.

The problem arises if you use microns: '34µm' becomes '34' that blender interprets as 34 meters. So clicking on a button
and hitting enter won't confirm the previous value, but will change it (very badly also).

Of course nobody is using microns in blender, but the problem will arise when we will implement areas and option 'Separate
Units' will be enabled. The value '2m² 3cm²' will become '2m' during editing.

This patch solves the problem rewriting the string in a smarter way than just stripping the UTF chars: the unit is translated
from unit->name_short ('µm') to unit->name_alt ('um'). So clicking on '34µm' the editing string will become
'34um'.
--- end

note: rather then allowing empty strings in name_alt field I made it so if the unit system was the default one a NULL name_alt will just strip the string, since its the default its not needed.

source/blender/blenkernel/BKE_unit.h
source/blender/blenkernel/intern/unit.c
source/blender/editors/interface/interface.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_intern.h

index 36ccc1f149707d16af954fe6c57fcc56549ac8d8..65bdea8095a2c4bc56a34a4723e6a979c828a261 100644 (file)
@@ -36,6 +36,9 @@ void  bUnit_AsString(char *str, int len_max, double value, int prec, int system,
 /* replace units with values, used before python button evaluation */
 int            bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pref, int system, int type);
 
+/* make string keyboard-friendly: 10µm --> 10um */
+void bUnit_ToUnitAltName(char *str, int len_max, char *orig_str, int system, int type);
+
 /* the size of the unit used for this value (used for calculating the ckickstep) */
 double bUnit_ClosestScalar(double value, int system, int type);
 
index 133f858e9eab6c648b6fdd292033a5981e769bbe..963cfdbea1b549c4f72bfe6506f1f0c38a7b7216 100644 (file)
@@ -44,7 +44,8 @@ typedef struct bUnitDef {
        char *name;
        char *name_plural;      /* abused a bit for the display name */
        char *name_short;       /* this is used for display*/
-       char *name_alt;         /* can be NULL */
+       char *name_alt;         /* keyboard-friendly ASCII-only version of name_short, can be NULL */
+                                               /* if name_short has non-ASCII chars, name_alt should be present */
        
        char *name_display;             /* can be NULL */
 
@@ -76,7 +77,7 @@ static struct bUnitCollection buDummyCollecton = {buDummyDef, 0, 0, sizeof(buDum
 static struct bUnitDef buMetricLenDef[] = {
        {"kilometer", "kilometers",             "km", NULL,     "Kilometers", 1000.0, 0.0,              B_UNIT_DEF_NONE},
        {"hectometer", "hectometers",   "hm", NULL,     "100 Meters", 100.0, 0.0,                       B_UNIT_DEF_SUPPRESS},
-       {"dekameter", "dekameters",             "dkm",NULL,     "10 Meters", 10.0, 0.0,                 B_UNIT_DEF_SUPPRESS},
+       {"dekameter", "dekameters",             "dam",NULL,     "10 Meters", 10.0, 0.0,                 B_UNIT_DEF_SUPPRESS},
        {"meter", "meters",                             "m",  NULL,     "Meters", 1.0, 0.0,                     B_UNIT_DEF_NONE}, /* base unit */
        {"decimetre", "decimetres",             "dm", NULL,     "10 Centimeters", 0.1, 0.0,                     B_UNIT_DEF_SUPPRESS},
        {"centimeter", "centimeters",   "cm", NULL,     "Centimeters", 0.01, 0.0,                       B_UNIT_DEF_NONE},
@@ -543,6 +544,49 @@ int bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pre
        return change;
 }
 
+/* 45µm --> 45um */
+void bUnit_ToUnitAltName(char *str, int len_max, char *orig_str, int system, int type)
+{
+       bUnitCollection *usys = unit_get_system(system, type);
+
+       bUnitDef *unit;
+       bUnitDef *unit_def= unit_default(usys);
+
+       /* find and substitute all units */
+       for(unit= usys->units; unit->name; unit++) {
+               if(len_max > 0 && (unit->name_alt || unit == unit_def))
+               {
+                       char *found= NULL;
+
+                       found= unit_find_str(orig_str, unit->name_short);
+                       if(found) {
+                               int offset= found - orig_str;
+                               int len_name= 0;
+
+                               /* copy everything before the unit */
+                               offset= (offset<len_max? offset: len_max);
+                               strncpy(str, orig_str, offset);
+
+                               str+= offset;
+                               orig_str+= offset + strlen(unit->name_short);
+                               len_max-= offset;
+
+                               /* print the alt_name */
+                               if(unit->name_alt)
+                                       len_name= snprintf(str, len_max, "%s", unit->name_alt);
+                               else
+                                       len_name= 0;
+
+                               len_name= (len_name<len_max? len_name: len_max);
+                               str+= len_name;
+                               len_max-= len_name;
+                       }
+               }
+       }
+
+       /* finally copy the rest of the string */
+       strncpy(str, orig_str, len_max);
+}
 
 double bUnit_ClosestScalar(double value, int system, int type)
 {
index 021dcc940e6ebc885d8e846abef4dfc4aed345f8..59e0af634b8e9b3571a3f50f2b931563187b9a46 100644 (file)
@@ -1443,6 +1443,23 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
        }
 }
 
+/* str will be overwritten */
+void ui_convert_to_unit_alt_name(uiBut *but, char *str, int maxlen)
+{
+       if(ui_is_but_unit(but)) {
+               int unit_type= RNA_SUBTYPE_UNIT_VALUE(RNA_property_subtype(but->rnaprop));
+               char *orig_str;
+               Scene *scene= CTX_data_scene((bContext *)but->block->evil_C);
+               
+               orig_str= MEM_callocN(sizeof(char)*maxlen + 1, "textedit sub str");
+               memcpy(orig_str, str, maxlen);
+               
+               bUnit_ToUnitAltName(str, maxlen, orig_str, scene->unit.system, unit_type);
+               
+               MEM_freeN(orig_str);
+       }
+}
+
 static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, int pad)
 {
        Scene *scene= CTX_data_scene((bContext *)but->block->evil_C);
index 484c78cd8319843777f143a73b1cc43983c734cc..b4ac56a6f0f8b74514e70df85ade4c571cf9d212 100644 (file)
@@ -1555,7 +1555,8 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
                int i;
                for(i=0; data->str[i]; i++) {
                        if(!isascii(data->str[i])) {
-                               data->str[i]= '\0';
+                               /* no stripping actually: just convert to alt name */
+                               ui_convert_to_unit_alt_name(but, data->str, data->maxlen);
                                break;
                        }
                }
index 02ce6a4f93b026c495d3d23ba9de892e30d1abeb..d5f6b089544028a5aae2c359178e1c0da9c6dddc 100644 (file)
@@ -356,6 +356,7 @@ extern void ui_set_but_vectorf(uiBut *but, float *vec);
 extern void ui_hsvcircle_vals_from_pos(float *valrad, float *valdist, rcti *rect, float mx, float my);
 
 extern void ui_get_but_string(uiBut *but, char *str, int maxlen);
+extern void ui_convert_to_unit_alt_name(uiBut *but, char *str, int maxlen);
 extern int ui_set_but_string(struct bContext *C, uiBut *but, const char *str);
 extern int ui_get_but_string_max_length(uiBut *but);