a8ef3db45d4e9036ed21c9c0608d14c6ce17c725 — octaspire 11 months ago 1bab7a7 v0.471.0
Nuklear plugin: add 'nuklear-edit-string', fix two layout functions

* Add function 'nuklear-edit-string' for showing
  text input widgets.

* Fix two layout functions: 'nuklear-layout-row-dynamic'
  and 'nuklear-layout-row-static'. Some of the arguments
  were assigned incorrectly in those functions.

* Add internal helper function for setting the contents of
  a Dern value as text (string or symbol) type.

* Add internal helper function for getting an element from
  a Dern vector as a string value or (unpushed) error,
  if the index is not valid or the value has
  incorrect type.

* Fix naming of one internal helper function to have
  '_const' in the end. Add also a non-const version
  of that same function.
M dev/include/octaspire/dern/octaspire_dern_config.h => dev/include/octaspire/dern/octaspire_dern_config.h +1 -1
@@ 18,7 18,7 @@ limitations under the License.
 #define OCTASPIRE_DERN_CONFIG_H
 
 #define OCTASPIRE_DERN_CONFIG_VERSION_MAJOR "0"
-#define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "470"
+#define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "471"
 #define OCTASPIRE_DERN_CONFIG_VERSION_PATCH "0"
 
 #define OCTASPIRE_DERN_CONFIG_VERSION_STR "Octaspire Dern version " \

M dev/include/octaspire/dern/octaspire_dern_value.h => dev/include/octaspire/dern/octaspire_dern_value.h +22 -1
@@ 563,7 563,14 @@ bool octaspire_dern_value_as_text_is_equal_to_c_string(
 char const *octaspire_dern_value_as_text_get_c_string(
     octaspire_dern_value_t const * const self);
 
-octaspire_string_t const *octaspire_dern_value_as_text_get_string(
+bool octaspire_dern_value_as_text_set_c_string(
+    octaspire_dern_value_t * const self,
+    char const * const str);
+
+octaspire_string_t *octaspire_dern_value_as_text_get_string(
+    octaspire_dern_value_t * const self);
+
+octaspire_string_t const *octaspire_dern_value_as_text_get_string_const(
     octaspire_dern_value_t const * const self);
 
 size_t octaspire_dern_value_as_text_get_length_in_octets(


@@ 671,6 678,14 @@ typedef struct octaspire_dern_text_or_unpushed_error_const_t
 }
 octaspire_dern_text_or_unpushed_error_const_t;
 
+typedef struct octaspire_dern_string_or_unpushed_error_t
+{
+    octaspire_string_t     * str;
+    octaspire_dern_value_t * value;
+    octaspire_dern_value_t * unpushedError;
+}
+octaspire_dern_string_or_unpushed_error_t;
+
 typedef struct octaspire_dern_symbol_or_unpushed_error_t
 {
     octaspire_string_t     const * symbol;


@@ 743,6 758,12 @@ octaspire_dern_value_as_vector_get_element_at_as_text_or_unpushed_error_const(
     ptrdiff_t const possiblyNegativeIndex,
     char const * const dernFuncName);
 
+octaspire_dern_string_or_unpushed_error_t
+octaspire_dern_value_as_vector_get_element_at_as_string_or_unpushed_error(
+    octaspire_dern_value_t * const self,
+    ptrdiff_t const possiblyNegativeIndex,
+    char const * const dernFuncName);
+
 octaspire_dern_symbol_or_unpushed_error_t
 octaspire_dern_value_as_vector_get_element_at_as_symbol_or_unpushed_error(
     octaspire_dern_value_t * const self,

M dev/src/octaspire_dern_stdlib.c => dev/src/octaspire_dern_stdlib.c +2 -2
@@ 5891,8 5891,8 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_distance(
     return octaspire_dern_vm_create_new_value_integer(
         vm,
         octaspire_string_levenshtein_distance(
-            octaspire_dern_value_as_text_get_string(firstArgVal),
-            octaspire_dern_value_as_text_get_string(secondArgVal)));
+            octaspire_dern_value_as_text_get_string_const(firstArgVal),
+            octaspire_dern_value_as_text_get_string_const(secondArgVal)));
 }
 
 octaspire_dern_value_t *octaspire_dern_vm_builtin_max(

M dev/src/octaspire_dern_value.c => dev/src/octaspire_dern_value.c +100 -3
@@ 3192,7 3192,56 @@ char const *octaspire_dern_value_as_text_get_c_string(
     return 0;
 }
 
-octaspire_string_t const *octaspire_dern_value_as_text_get_string(
+bool octaspire_dern_value_as_text_set_c_string(
+    octaspire_dern_value_t * const self,
+    char const * const str)
+{
+    switch (self->typeTag)
+    {
+        case OCTASPIRE_DERN_VALUE_TAG_ILLEGAL:
+        {
+            abort();
+        }
+
+        case OCTASPIRE_DERN_VALUE_TAG_STRING:
+        {
+            return octaspire_string_set_from_c_string(self->value.string, str);
+        }
+
+        case OCTASPIRE_DERN_VALUE_TAG_SYMBOL:
+        {
+            // TODO handle whitespace (and other
+            // characters not allowed in symbols)
+            return octaspire_string_set_from_c_string(self->value.symbol, str);
+        }
+
+        case OCTASPIRE_DERN_VALUE_TAG_CHARACTER:
+        case OCTASPIRE_DERN_VALUE_TAG_NIL:
+        case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
+        case OCTASPIRE_DERN_VALUE_TAG_INTEGER:
+        case OCTASPIRE_DERN_VALUE_TAG_REAL:
+        case OCTASPIRE_DERN_VALUE_TAG_ERROR:
+        case OCTASPIRE_DERN_VALUE_TAG_VECTOR:
+        case OCTASPIRE_DERN_VALUE_TAG_HASH_MAP:
+        case OCTASPIRE_DERN_VALUE_TAG_QUEUE:
+        case OCTASPIRE_DERN_VALUE_TAG_LIST:
+        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
+        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
+        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
+        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
+        case OCTASPIRE_DERN_VALUE_TAG_PORT:
+        case OCTASPIRE_DERN_VALUE_TAG_C_DATA:
+        case OCTASPIRE_DERN_VALUE_TAG_SEMVER:
+        {
+            octaspire_helpers_verify_true(false);
+        }
+        break;
+    }
+
+    return 0;
+}
+
+octaspire_string_t const *octaspire_dern_value_as_text_get_string_const(
     octaspire_dern_value_t const * const self)
 {
     switch (self->typeTag)


@@ 3242,6 3291,13 @@ octaspire_string_t const *octaspire_dern_value_as_text_get_string(
     return 0;
 }
 
+octaspire_string_t *octaspire_dern_value_as_text_get_string(
+    octaspire_dern_value_t * const self)
+{
+    return (octaspire_string_t*)
+        octaspire_dern_value_as_text_get_string_const(self);
+}
+
 size_t octaspire_dern_value_as_text_get_length_in_octets(
     octaspire_dern_value_t const * const self)
 {


@@ 3651,7 3707,48 @@ octaspire_dern_value_as_vector_get_element_at_as_text_or_unpushed_error_const(
     }
 
     result.value = arg;
-    result.text = octaspire_dern_value_as_text_get_string(arg);
+    result.text = octaspire_dern_value_as_text_get_string_const(arg);
+    return result;
+}
+
+octaspire_dern_string_or_unpushed_error_t
+octaspire_dern_value_as_vector_get_element_at_as_string_or_unpushed_error(
+    octaspire_dern_value_t * const self,
+    ptrdiff_t const possiblyNegativeIndex,
+    char const * const dernFuncName)
+{
+    octaspire_helpers_verify_not_null(self);
+
+    octaspire_dern_vm_t * const vm = self->vm;
+
+    octaspire_helpers_verify_not_null(vm);
+
+    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);
+    octaspire_dern_string_or_unpushed_error_t result = {0, 0, 0};
+
+    octaspire_dern_value_t * const arg =
+        octaspire_dern_value_as_vector_get_element_at(self, possiblyNegativeIndex);
+
+    octaspire_helpers_verify_not_null(arg);
+
+    if (!octaspire_dern_value_is_string(arg))
+    {
+        result.unpushedError = octaspire_dern_vm_create_new_value_error_format(
+            vm,
+            "Builtin '%s' expects string as "
+            "%d. argument. Type '%s' was given.",
+            dernFuncName,
+            possiblyNegativeIndex,
+            octaspire_dern_value_helper_get_type_as_c_string(arg->typeTag));
+
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return result;
+    }
+
+    result.value = arg;
+    result.str   = octaspire_dern_value_as_text_get_string(arg);
     return result;
 }
 


@@ 3692,7 3789,7 @@ octaspire_dern_value_as_vector_get_element_at_as_symbol_or_unpushed_error(
     }
 
     result.value  = arg;
-    result.symbol = octaspire_dern_value_as_text_get_string(arg);
+    result.symbol = octaspire_dern_value_as_text_get_string_const(arg);
     return result;
 }
 

M release/examples/dern-nuklear-example.dern => release/examples/dern-nuklear-example.dern +14 -6
@@ 37,6 37,7 @@
 (define dern-nuklear-example-slider-int-value      as {D+15}   [current value of the integer slider])
 (define dern-nuklear-example-slider-float-value    as {D+1.75} [current value of the floating point slider])
 (define dern-nuklear-example-radio-option          as 'EASY    [currently selected option])
+(define dern-nuklear-example-text-value            as []       [text input])
 
 (define dern-nuklear-example-render as (fn ()
   (if (nuklear-begin dern-nuklear-example-nuklear-ctx [] {D+10} {D+10} {D+780} {D+580})


@@ 85,20 86,27 @@
           (println [float to {}] dern-nuklear-example-slider-float-value))
 
       ; Radio buttons
-      (nuklear-layout-row-static dern-nuklear-example-nuklear-ctx {D+90} {D+150} {D+2})
-      (if (nuklear-option-label
+      (nuklear-layout-row-dynamic dern-nuklear-example-nuklear-ctx {D+35} {D+2})
+      (nuklear-option-label
             dern-nuklear-example-nuklear-ctx
             [Easy]
             'EASY
             dern-nuklear-example-radio-option)
-          (println [EASY selected]))
-      (if (nuklear-option-label
+      (nuklear-option-label
             dern-nuklear-example-nuklear-ctx
             [Hard]
             'HARD
             dern-nuklear-example-radio-option)
-          (println [HARD selected]))
-      (println [Radio option {} is active] dern-nuklear-example-radio-option)))
+      ;(println [Radio option {} is active] dern-nuklear-example-radio-option)
+
+      ; Text input (simple)
+      (nuklear-layout-row-static dern-nuklear-example-nuklear-ctx {D+35} {D+150} {D+1})
+      (nuklear-edit-string
+        dern-nuklear-example-nuklear-ctx
+        'SIMPLE
+        dern-nuklear-example-text-value
+        {D+256}
+        'DEFAULT)))
   (nuklear-end dern-nuklear-example-nuklear-ctx)
   (nuklear-sdl-render)
   (sdl2-GL-SwapWindow dern-nuklear-example-window))

M release/octaspire-dern-amalgamated.c => release/octaspire-dern-amalgamated.c +125 -7
@@ 26223,7 26223,7 @@ limitations under the License.
 #define OCTASPIRE_DERN_CONFIG_H
 
 #define OCTASPIRE_DERN_CONFIG_VERSION_MAJOR "0"
-#define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "470"
+#define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "471"
 #define OCTASPIRE_DERN_CONFIG_VERSION_PATCH "0"
 
 #define OCTASPIRE_DERN_CONFIG_VERSION_STR "Octaspire Dern version " \


@@ 27149,7 27149,14 @@ bool octaspire_dern_value_as_text_is_equal_to_c_string(
 char const *octaspire_dern_value_as_text_get_c_string(
     octaspire_dern_value_t const * const self);
 
-octaspire_string_t const *octaspire_dern_value_as_text_get_string(
+bool octaspire_dern_value_as_text_set_c_string(
+    octaspire_dern_value_t * const self,
+    char const * const str);
+
+octaspire_string_t *octaspire_dern_value_as_text_get_string(
+    octaspire_dern_value_t * const self);
+
+octaspire_string_t const *octaspire_dern_value_as_text_get_string_const(
     octaspire_dern_value_t const * const self);
 
 size_t octaspire_dern_value_as_text_get_length_in_octets(


@@ 27257,6 27264,14 @@ typedef struct octaspire_dern_text_or_unpushed_error_const_t
 }
 octaspire_dern_text_or_unpushed_error_const_t;
 
+typedef struct octaspire_dern_string_or_unpushed_error_t
+{
+    octaspire_string_t     * str;
+    octaspire_dern_value_t * value;
+    octaspire_dern_value_t * unpushedError;
+}
+octaspire_dern_string_or_unpushed_error_t;
+
 typedef struct octaspire_dern_symbol_or_unpushed_error_t
 {
     octaspire_string_t     const * symbol;


@@ 27329,6 27344,12 @@ octaspire_dern_value_as_vector_get_element_at_as_text_or_unpushed_error_const(
     ptrdiff_t const possiblyNegativeIndex,
     char const * const dernFuncName);
 
+octaspire_dern_string_or_unpushed_error_t
+octaspire_dern_value_as_vector_get_element_at_as_string_or_unpushed_error(
+    octaspire_dern_value_t * const self,
+    ptrdiff_t const possiblyNegativeIndex,
+    char const * const dernFuncName);
+
 octaspire_dern_symbol_or_unpushed_error_t
 octaspire_dern_value_as_vector_get_element_at_as_symbol_or_unpushed_error(
     octaspire_dern_value_t * const self,


@@ 39781,8 39802,8 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_distance(
     return octaspire_dern_vm_create_new_value_integer(
         vm,
         octaspire_string_levenshtein_distance(
-            octaspire_dern_value_as_text_get_string(firstArgVal),
-            octaspire_dern_value_as_text_get_string(secondArgVal)));
+            octaspire_dern_value_as_text_get_string_const(firstArgVal),
+            octaspire_dern_value_as_text_get_string_const(secondArgVal)));
 }
 
 octaspire_dern_value_t *octaspire_dern_vm_builtin_max(


@@ 47839,7 47860,56 @@ char const *octaspire_dern_value_as_text_get_c_string(
     return 0;
 }
 
-octaspire_string_t const *octaspire_dern_value_as_text_get_string(
+bool octaspire_dern_value_as_text_set_c_string(
+    octaspire_dern_value_t * const self,
+    char const * const str)
+{
+    switch (self->typeTag)
+    {
+        case OCTASPIRE_DERN_VALUE_TAG_ILLEGAL:
+        {
+            abort();
+        }
+
+        case OCTASPIRE_DERN_VALUE_TAG_STRING:
+        {
+            return octaspire_string_set_from_c_string(self->value.string, str);
+        }
+
+        case OCTASPIRE_DERN_VALUE_TAG_SYMBOL:
+        {
+            // TODO handle whitespace (and other
+            // characters not allowed in symbols)
+            return octaspire_string_set_from_c_string(self->value.symbol, str);
+        }
+
+        case OCTASPIRE_DERN_VALUE_TAG_CHARACTER:
+        case OCTASPIRE_DERN_VALUE_TAG_NIL:
+        case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
+        case OCTASPIRE_DERN_VALUE_TAG_INTEGER:
+        case OCTASPIRE_DERN_VALUE_TAG_REAL:
+        case OCTASPIRE_DERN_VALUE_TAG_ERROR:
+        case OCTASPIRE_DERN_VALUE_TAG_VECTOR:
+        case OCTASPIRE_DERN_VALUE_TAG_HASH_MAP:
+        case OCTASPIRE_DERN_VALUE_TAG_QUEUE:
+        case OCTASPIRE_DERN_VALUE_TAG_LIST:
+        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
+        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
+        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
+        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
+        case OCTASPIRE_DERN_VALUE_TAG_PORT:
+        case OCTASPIRE_DERN_VALUE_TAG_C_DATA:
+        case OCTASPIRE_DERN_VALUE_TAG_SEMVER:
+        {
+            octaspire_helpers_verify_true(false);
+        }
+        break;
+    }
+
+    return 0;
+}
+
+octaspire_string_t const *octaspire_dern_value_as_text_get_string_const(
     octaspire_dern_value_t const * const self)
 {
     switch (self->typeTag)


@@ 47889,6 47959,13 @@ octaspire_string_t const *octaspire_dern_value_as_text_get_string(
     return 0;
 }
 
+octaspire_string_t *octaspire_dern_value_as_text_get_string(
+    octaspire_dern_value_t * const self)
+{
+    return (octaspire_string_t*)
+        octaspire_dern_value_as_text_get_string_const(self);
+}
+
 size_t octaspire_dern_value_as_text_get_length_in_octets(
     octaspire_dern_value_t const * const self)
 {


@@ 48298,7 48375,48 @@ octaspire_dern_value_as_vector_get_element_at_as_text_or_unpushed_error_const(
     }
 
     result.value = arg;
-    result.text = octaspire_dern_value_as_text_get_string(arg);
+    result.text = octaspire_dern_value_as_text_get_string_const(arg);
+    return result;
+}
+
+octaspire_dern_string_or_unpushed_error_t
+octaspire_dern_value_as_vector_get_element_at_as_string_or_unpushed_error(
+    octaspire_dern_value_t * const self,
+    ptrdiff_t const possiblyNegativeIndex,
+    char const * const dernFuncName)
+{
+    octaspire_helpers_verify_not_null(self);
+
+    octaspire_dern_vm_t * const vm = self->vm;
+
+    octaspire_helpers_verify_not_null(vm);
+
+    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);
+    octaspire_dern_string_or_unpushed_error_t result = {0, 0, 0};
+
+    octaspire_dern_value_t * const arg =
+        octaspire_dern_value_as_vector_get_element_at(self, possiblyNegativeIndex);
+
+    octaspire_helpers_verify_not_null(arg);
+
+    if (!octaspire_dern_value_is_string(arg))
+    {
+        result.unpushedError = octaspire_dern_vm_create_new_value_error_format(
+            vm,
+            "Builtin '%s' expects string as "
+            "%d. argument. Type '%s' was given.",
+            dernFuncName,
+            possiblyNegativeIndex,
+            octaspire_dern_value_helper_get_type_as_c_string(arg->typeTag));
+
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return result;
+    }
+
+    result.value = arg;
+    result.str   = octaspire_dern_value_as_text_get_string(arg);
     return result;
 }
 


@@ 48339,7 48457,7 @@ octaspire_dern_value_as_vector_get_element_at_as_symbol_or_unpushed_error(
     }
 
     result.value  = arg;
-    result.symbol = octaspire_dern_value_as_text_get_string(arg);
+    result.symbol = octaspire_dern_value_as_text_get_string_const(arg);
     return result;
 }
 

M release/plugins/dern_nuklear.c => release/plugins/dern_nuklear.c +311 -6
@@ 361,7 361,7 @@ octaspire_dern_value_t *dern_nuklear_label(
             octaspire_dern_value_helper_get_type_as_c_string(thirdArg->typeTag));
     }
 
-    octaspire_string_t const * const alignment = octaspire_dern_value_as_text_get_string(thirdArg);
+    octaspire_string_t const * const alignment = octaspire_dern_value_as_text_get_string_const(thirdArg);
 
     nk_flags flags = 0;
 


@@ 986,6 986,275 @@ octaspire_dern_value_t *dern_nuklear_option_label(
     return octaspire_dern_vm_create_new_value_boolean(vm, result);
 }
 
+octaspire_dern_value_t *dern_nuklear_edit_string(
+    octaspire_dern_vm_t * const vm,
+    octaspire_dern_value_t * const arguments,
+    octaspire_dern_value_t * const environment)
+{
+    OCTASPIRE_HELPERS_UNUSED_PARAMETER(environment);
+
+    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);
+    char   const * const dernFuncName    = "nuklear-edit-string";
+    char   const * const ctxName         = "ctx";
+    size_t const         numExpectedArgs = 5;
+
+    size_t const numArgs =
+        octaspire_dern_value_as_vector_get_length(arguments);
+
+    if (numArgs != numExpectedArgs)
+    {
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return octaspire_dern_vm_create_new_value_error_format(
+            vm,
+            "Builtin '%s' expects %zu arguments. "
+            "%zu arguments were given.",
+            dernFuncName,
+            numExpectedArgs,
+            numArgs);
+    }
+
+    // ctx
+
+    octaspire_dern_c_data_or_unpushed_error_t cDataOrError =
+        octaspire_dern_value_as_vector_get_element_at_as_c_data_or_unpushed_error(
+            arguments,
+            0,
+            dernFuncName,
+            ctxName,
+            DERN_NUKLEAR_PLUGIN_NAME);
+
+    if (cDataOrError.unpushedError)
+    {
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return cDataOrError.unpushedError;
+    }
+
+    struct nk_context * const ctx = cDataOrError.cData;
+
+    octaspire_helpers_verify_not_null(ctx);
+
+    // edit-type
+
+    char const * const altEditType[] =
+    {
+        "SIMPLE",
+        "FIELD",
+        "BOX",
+        "EDITOR",
+        0
+    };
+
+    octaspire_dern_one_of_texts_or_unpushed_error_const_t textOrErrorEditType =
+        octaspire_dern_value_as_vector_get_element_at_as_one_of_texts_or_unpushed_error_const(
+            arguments,
+            1,
+            dernFuncName,
+            altEditType);
+
+    if (textOrErrorEditType.unpushedError)
+    {
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return textOrErrorEditType.unpushedError;
+    }
+
+    octaspire_helpers_verify_true(
+        textOrErrorEditType.index >= 0 && textOrErrorEditType.index <= 3);
+
+    nk_flags editType = NK_EDIT_SIMPLE;
+
+    switch (textOrErrorEditType.index)
+    {
+        case 0: { editType = NK_EDIT_SIMPLE; } break;
+        case 1: { editType = NK_EDIT_FIELD;  } break;
+        case 2: { editType = NK_EDIT_BOX;    } break;
+        case 3: { editType = NK_EDIT_EDITOR; } break;
+    }
+
+    // str
+
+    octaspire_dern_string_or_unpushed_error_t stringOrError =
+        octaspire_dern_value_as_vector_get_element_at_as_string_or_unpushed_error(
+            arguments,
+            2,
+            dernFuncName);
+
+    if (stringOrError.unpushedError)
+    {
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return stringOrError.unpushedError;
+    }
+
+    // len
+
+    octaspire_dern_number_or_unpushed_error_const_t numberOrError =
+        octaspire_dern_value_as_vector_get_element_at_as_number_or_unpushed_error_const(
+            arguments,
+            3,
+            dernFuncName);
+
+    if (numberOrError.unpushedError)
+    {
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return numberOrError.unpushedError;
+    }
+
+    int const len = numberOrError.number;
+
+    if (len < 2)
+    {
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return octaspire_dern_vm_create_new_value_error_format(
+            vm,
+            "Builtin '%s' expects input length larger than 1. %zu was given."
+            "%zu arguments were given.",
+            dernFuncName,
+            len);
+    }
+
+    // Remove characters until the string fits into the buffer.
+    while (octaspire_dern_value_as_string_get_length_in_octets(
+               stringOrError.value) >= (size_t)(len - 1))
+    {
+        octaspire_helpers_verify_true(
+            octaspire_dern_value_as_string_pop_back_ucs_character(
+                stringOrError.value));
+    }
+
+    // filter
+
+    char const * const altFilter[] =
+    {
+        "DEFAULT",
+        "ASCII",
+        "FLOAT",
+        "DECIMAL",
+        "HEX",
+        "OCT",
+        "BINARY",
+        0
+    };
+
+    octaspire_dern_one_of_texts_or_unpushed_error_const_t textOrErrorFilter =
+        octaspire_dern_value_as_vector_get_element_at_as_one_of_texts_or_unpushed_error_const(
+            arguments,
+            4,
+            dernFuncName,
+            altFilter);
+
+    if (textOrErrorFilter.unpushedError)
+    {
+        octaspire_helpers_verify_true(
+            stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+        return textOrErrorFilter.unpushedError;
+    }
+
+    octaspire_helpers_verify_true(
+        textOrErrorFilter.index >= 0 && textOrErrorFilter.index <= 6);
+
+    nk_plugin_filter filter = nk_filter_default;
+
+    switch (textOrErrorFilter.index)
+    {
+        case 0: { filter = nk_filter_default; } break;
+        case 1: { filter = nk_filter_ascii;   } break;
+        case 2: { filter = nk_filter_float;   } break;
+        case 3: { filter = nk_filter_decimal; } break;
+        case 4: { filter = nk_filter_hex;     } break;
+        case 5: { filter = nk_filter_oct;     } break;
+        case 6: { filter = nk_filter_binary;  } break;
+    }
+
+    char * memory = octaspire_allocator_malloc(
+        octaspire_dern_vm_get_allocator(vm),
+        len);
+
+    octaspire_helpers_verify_not_null(memory);
+
+    strncpy(
+        memory,
+        octaspire_dern_value_as_string_get_c_string(stringOrError.value),
+        len);
+
+    int memused = octaspire_dern_value_as_string_get_length_in_octets(
+        stringOrError.value);
+
+    // Show the widget.
+
+    nk_flags const resultFlags = nk_edit_string(
+        ctx,
+        NK_EDIT_SIMPLE,
+        memory,
+        &memused,
+        len,
+        filter);
+
+    if (memused < len)
+    {
+        memory[memused] = '\0';
+    }
+
+    octaspire_helpers_verify_true(
+        octaspire_dern_value_as_text_set_c_string(
+            stringOrError.value,
+            memory));
+
+    octaspire_allocator_free(octaspire_dern_vm_get_allocator(vm), memory);
+
+    memory = 0;
+
+    octaspire_string_t * const result = octaspire_string_new(
+        "",
+        octaspire_dern_vm_get_allocator(vm));
+
+    octaspire_helpers_verify_not_null(result);
+
+    if (resultFlags)
+    {
+        if (resultFlags & NK_EDIT_ACTIVE)
+        {
+            octaspire_string_concatenate_c_string(result, "ACTIVE ");
+        }
+
+        if (resultFlags & NK_EDIT_INACTIVE)
+        {
+            octaspire_string_concatenate_c_string(result, "INACTIVE ");
+        }
+
+        if (resultFlags & NK_EDIT_ACTIVATED)
+        {
+            octaspire_string_concatenate_c_string(result, "ACTIVATED ");
+        }
+
+        if (resultFlags & NK_EDIT_DEACTIVATED)
+        {
+            octaspire_string_concatenate_c_string(result, "DEACTIVATED ");
+        }
+
+        if (resultFlags & NK_EDIT_COMMITED)
+        {
+            octaspire_string_concatenate_c_string(result, "COMMITED ");
+        }
+    }
+
+    octaspire_helpers_verify_true(
+        stackLength == octaspire_dern_vm_get_stack_length(vm));
+
+    return octaspire_dern_vm_create_new_value_string(vm, result);
+}
+
 octaspire_dern_value_t *dern_nuklear_progress(
     octaspire_dern_vm_t * const vm,
     octaspire_dern_value_t * const arguments,


@@ 1182,7 1451,7 @@ octaspire_dern_value_t *dern_nuklear_layout_row_dynamic(
     octaspire_dern_number_or_unpushed_error_const_t numberOrErrorNumColumns =
         octaspire_dern_value_as_vector_get_element_at_as_number_or_unpushed_error_const(
             arguments,
-            1,
+            2,
             dernFuncName);
 
     if (numberOrErrorNumColumns.unpushedError)


@@ 1278,7 1547,7 @@ octaspire_dern_value_t *dern_nuklear_layout_row_static(
     octaspire_dern_number_or_unpushed_error_const_t numberOrErrorItemWidth =
         octaspire_dern_value_as_vector_get_element_at_as_number_or_unpushed_error_const(
             arguments,
-            1,
+            2,
             dernFuncName);
 
     if (numberOrErrorItemWidth.unpushedError)


@@ 1296,7 1565,7 @@ octaspire_dern_value_t *dern_nuklear_layout_row_static(
     octaspire_dern_number_or_unpushed_error_const_t numberOrErrorColumns =
         octaspire_dern_value_as_vector_get_element_at_as_number_or_unpushed_error_const(
             arguments,
-            2,
+            3,
             dernFuncName);
 
     if (numberOrErrorColumns.unpushedError)


@@ 1487,8 1756,6 @@ octaspire_dern_value_t *dern_nuklear_layout_row(
         ratios[numRatiosAdded + i] = ratio;
     }
 
-    printf("--->%d | %f | %d | %f | %f\n", textOrError.index, height, columns, ratios[0], ratios[1]);
-
     nk_layout_row(
         ctx,
         textOrError.index == 0 ? NK_DYNAMIC : NK_STATIC,


@@ 2128,6 2395,44 @@ bool dern_nuklear_init(
 
     if (!octaspire_dern_vm_create_and_register_new_builtin(
             vm,
+            "nuklear-edit-string",
+            dern_nuklear_edit_string,
+            5,
+            "NAME\n"
+            "\tnuklear-edit-string\n"
+            "\n"
+            "SYNOPSIS\n"
+            "\t(require 'dern_nuklear)\n"
+            "\n"
+            "\t(nuklear-edit-string ctx edit-type str len filter) -> string or error\n"
+            "\n"
+            "DESCRIPTION\n"
+            "\tDisplay a simple text input with the given maximum length.\n"
+            "\n"
+            "ARGUMENTS\n"
+            "\tctx           nuklear context.\n"
+            "\tedit-type     One of symbols: SIMPLE, FIELD, BOX or EDITOR."
+            "\tstr           edit result.\n"
+            "\tlen           max allowed input length.\n"
+            "\tfilter        text (string or symbol) describing allowed input.\n"
+            "\t              Must be one of: DEFAULT, ASCII, FLOAT, DECIMAL,\n"
+            "\t              HEX, OCT or BINARY.\n"
+            "\n"
+            "RETURN VALUE\n"
+            "\tString that is empty or contains status information.\n"
+            "\tPossible values are: ACTIVE, INACTIVE, ACTIVATED, DEACTIVATED\n"
+            "\tand COMMITED. Error is returned if something went wrong.\n"
+            "\n"
+            "SEE ALSO\n"
+            "\tnuklear-begin\n",
+            false,
+            targetEnv))
+    {
+        return false;
+    }
+
+    if (!octaspire_dern_vm_create_and_register_new_builtin(
+            vm,
             "nuklear-layout-row-dynamic",
             dern_nuklear_layout_row_dynamic,
             3,