From: Olaf Wintermann
Date: Sun, 9 Nov 2025 22:41:53 +0000 (+0100)
Subject: update window layout
X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;p=mizunara.git
update window layout
---
diff --git a/libidav/pwdstore.c b/libidav/pwdstore.c
index ba97c09..c2089b9 100644
--- a/libidav/pwdstore.c
+++ b/libidav/pwdstore.c
@@ -263,7 +263,7 @@ static int read_pwdentry(PwdStore *p, CxBuffer *in) {
}
static void remove_list_entries(PwdStore *s, const char *id) {
- CxIterator i = cxListMutIterator(s->locations);
+ CxIterator i = cxListIterator(s->locations);
cx_foreach(PwdIndexEntry*, ie, i) {
if(!strcmp(ie->id, id)) {
cxIteratorFlagRemoval(i);
@@ -271,7 +271,7 @@ static void remove_list_entries(PwdStore *s, const char *id) {
break;
}
}
- i = cxListMutIterator(s->noloc);
+ i = cxListIterator(s->noloc);
cx_foreach(PwdIndexEntry*, ie, i) {
if(!strcmp(ie->id, id)) {
cxIteratorFlagRemoval(i);
diff --git a/libidav/resource.c b/libidav/resource.c
index 19ddffa..fa96581 100644
--- a/libidav/resource.c
+++ b/libidav/resource.c
@@ -1599,7 +1599,7 @@ CxMap* parse_crypto_prop_str(DavSession *sn, DavKey *key, const char *content) {
property->value = n->children ? dav_convert_xml(sn, n->children) : NULL;
cxmutstr propkey = dav_property_key(property->ns->name, property->name);
- cxMapPut(map, cx_hash_key_cxstr(propkey), property);
+ cxMapPut(map, propkey, property);
cx_strfree(&propkey);
}
n = n->next;
diff --git a/mizunara/Makefile b/mizunara/Makefile
index 4fb25c1..0722cf4 100644
--- a/mizunara/Makefile
+++ b/mizunara/Makefile
@@ -47,7 +47,7 @@ OBJ = $(SRC:%.c=$(BUILD_ROOT)/build/mizunara/%.$(OBJ_EXT))
all: $(BUILD_ROOT)/build/bin/mizunara
$(BUILD_ROOT)/build/bin/mizunara: $(OBJ) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/$(LIB_PREFIX)uitk$(LIB_EXT)
- $(CC) -o $(BUILD_ROOT)/build/bin/mizunara$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -lidav $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/libucx.a $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/libuitk.a
+ $(CC) -o $(BUILD_ROOT)/build/bin/mizunara$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -lidav $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/libuitk.a $(BUILD_ROOT)/build/$(BUILD_LIB_DIR)/libucx.a
$(BUILD_ROOT)/build/mizunara/%.$(OBJ_EXT): %.c
$(CC) $(CFLAGS) $(TK_CFLAGS) -o $@ -c $<
diff --git a/mizunara/window.c b/mizunara/window.c
index e004583..d3edb43 100644
--- a/mizunara/window.c
+++ b/mizunara/window.c
@@ -89,7 +89,7 @@ UiObject* window_create(const char *url) {
.fill = TRUE);
}
- ui_hbox(obj, .spacing = 4) {
+ ui_hbox(obj, .spacing = 4, .margin_left = 6, .margin_right = 8) {
ui_button(obj, .style_class = "flat", .icon = UI_ICON_GO_BACK);
ui_button(obj, .style_class = "flat", .icon = UI_ICON_GO_FORWARD);
ui_path_textfield(obj, .varname = "path", .fill = TRUE, .onactivate = action_pathbar_activate);
diff --git a/ucx/Makefile b/ucx/Makefile
index 1005259..4b61a56 100644
--- a/ucx/Makefile
+++ b/ucx/Makefile
@@ -38,6 +38,7 @@ SRC += hash_key.c
SRC += hash_map.c
SRC += iterator.c
SRC += linked_list.c
+SRC += kv_list.c
SRC += list.c
SRC += map.c
SRC += printf.c
diff --git a/ucx/allocator.c b/ucx/allocator.c
index b10096c..323b14b 100644
--- a/ucx/allocator.c
+++ b/ucx/allocator.c
@@ -73,7 +73,7 @@ struct cx_allocator_s cx_stdlib_allocator = {
NULL
};
const CxAllocator * const cxStdlibAllocator = &cx_stdlib_allocator;
-const CxAllocator * cxDefaultAllocator = cxStdlibAllocator;
+const CxAllocator * cxDefaultAllocator = &cx_stdlib_allocator;
int cx_reallocate_(
void **mem,
diff --git a/ucx/array_list.c b/ucx/array_list.c
index a66db51..03c0bfe 100644
--- a/ucx/array_list.c
+++ b/ucx/array_list.c
@@ -50,7 +50,7 @@ static void *cx_array_default_realloc(
}
CxArrayReallocator cx_array_default_reallocator_impl = {
- cx_array_default_realloc, NULL, NULL, 0, 0
+ cx_array_default_realloc, NULL, NULL
};
CxArrayReallocator *cx_array_default_reallocator = &cx_array_default_reallocator_impl;
@@ -72,11 +72,11 @@ static void *cx_array_advanced_realloc(
}
// retrieve the pointer to the actual allocator
- const CxAllocator *al = alloc->ptr1;
+ const CxAllocator *al = alloc->allocator;
// check if the array is still located on the stack
void *newmem;
- if (array == alloc->ptr2) {
+ if (array == alloc->stack_ptr) {
newmem = cxMalloc(al, n);
if (newmem != NULL && array != NULL) {
memcpy(newmem, array, old_capacity*elem_size);
@@ -89,15 +89,14 @@ static void *cx_array_advanced_realloc(
struct cx_array_reallocator_s cx_array_reallocator(
const struct cx_allocator_s *allocator,
- const void *stackmem
+ const void *stack_ptr
) {
if (allocator == NULL) {
allocator = cxDefaultAllocator;
}
return (struct cx_array_reallocator_s) {
cx_array_advanced_realloc,
- (void*) allocator, (void*) stackmem,
- 0, 0
+ allocator, stack_ptr,
};
}
@@ -291,7 +290,7 @@ int cx_array_copy(
*target, oldcap, newcap, elem_size, reallocator
);
if (newmem == NULL) {
- return 1;
+ return 1; // LCOV_EXCL_LINE
}
// repair src pointer, if necessary
@@ -335,7 +334,7 @@ int cx_array_copy(
return 0;
}
-int cx_array_insert_sorted(
+static int cx_array_insert_sorted_impl(
void **target,
size_t *size,
size_t *capacity,
@@ -343,7 +342,8 @@ int cx_array_insert_sorted(
const void *sorted_data,
size_t elem_size,
size_t elem_count,
- CxArrayReallocator *reallocator
+ CxArrayReallocator *reallocator,
+ bool allow_duplicates
) {
// assert pointers
assert(target != NULL);
@@ -369,6 +369,7 @@ int cx_array_insert_sorted(
// store some counts
size_t old_size = *size;
size_t old_capacity = *capacity;
+ // the necessary capacity is the worst case assumption, including duplicates
size_t needed_capacity = old_size + elem_count;
// if we need more than we have, try a reallocation
@@ -418,13 +419,60 @@ int cx_array_insert_sorted(
bptr,
cmp_func
);
+ // binary search gives us the smallest index;
+ // we also want to include equal elements here
+ while (si + copy_len < elem_count
+ && cmp_func(bptr, src+copy_len*elem_size) == 0) {
+ copy_len++;
+ }
// copy the source elements
- bytes_copied = copy_len * elem_size;
- memcpy(dest, src, bytes_copied);
- dest += bytes_copied;
- src += bytes_copied;
- si += copy_len;
+ if (copy_len > 0) {
+ if (allow_duplicates) {
+ // we can copy the entire chunk
+ bytes_copied = copy_len * elem_size;
+ memcpy(dest, src, bytes_copied);
+ dest += bytes_copied;
+ src += bytes_copied;
+ si += copy_len;
+ di += copy_len;
+ } else {
+ // first, check the end of the source chunk
+ // for being a duplicate of the bptr
+ const char *end_of_src = src + (copy_len - 1) * elem_size;
+ size_t skip_len = 0;
+ while (copy_len > 0 && cmp_func(bptr, end_of_src) == 0) {
+ end_of_src -= elem_size;
+ skip_len++;
+ copy_len--;
+ }
+ char *last = dest == *target ? NULL : dest - elem_size;
+ // then iterate through the source chunk
+ // and skip all duplicates with the last element in the array
+ size_t more_skipped = 0;
+ for (unsigned j = 0; j < copy_len; j++) {
+ if (last != NULL && cmp_func(last, src) == 0) {
+ // duplicate - skip
+ src += elem_size;
+ si++;
+ more_skipped++;
+ } else {
+ memcpy(dest, src, elem_size);
+ src += elem_size;
+ last = dest;
+ dest += elem_size;
+ si++;
+ di++;
+ }
+ }
+ // skip the previously identified elements as well
+ src += skip_len * elem_size;
+ si += skip_len;
+ skip_len += more_skipped;
+ // reduce the actual size by the number of skipped elements
+ *size -= skip_len;
+ }
+ }
// when all source elements are in place, we are done
if (si >= elem_count) break;
@@ -443,20 +491,103 @@ int cx_array_insert_sorted(
memmove(dest, bptr, bytes_copied);
dest += bytes_copied;
bptr += bytes_copied;
+ di += copy_len;
bi += copy_len;
}
- // still source elements left? simply append them
+ // still source elements left?
if (si < elem_count) {
- memcpy(dest, src, elem_size * (elem_count - si));
+ if (allow_duplicates) {
+ // duplicates allowed or nothing inserted yet: simply copy everything
+ memcpy(dest, src, elem_size * (elem_count - si));
+ } else {
+ if (dest != *target) {
+ // skip all source elements that equal the last element
+ char *last = dest - elem_size;
+ while (si < elem_count) {
+ if (last != NULL && cmp_func(last, src) == 0) {
+ src += elem_size;
+ si++;
+ (*size)--;
+ } else {
+ break;
+ }
+ }
+ }
+ // we must check the elements in the chunk one by one
+ while (si < elem_count) {
+ // find a chain of elements that can be copied
+ size_t copy_len = 1, skip_len = 0;
+ {
+ const char *left_src = src;
+ while (si + copy_len < elem_count) {
+ const char *right_src = left_src + elem_size;
+ int d = cmp_func(left_src, right_src);
+ if (d < 0) {
+ if (skip_len > 0) {
+ // new larger element found;
+ // handle it in the next cycle
+ break;
+ }
+ left_src += elem_size;
+ copy_len++;
+ } else if (d == 0) {
+ left_src += elem_size;
+ skip_len++;
+ } else {
+ break;
+ }
+ }
+ }
+ size_t bytes_copied = copy_len * elem_size;
+ memcpy(dest, src, bytes_copied);
+ dest += bytes_copied;
+ src += bytes_copied + skip_len * elem_size;
+ si += copy_len + skip_len;
+ di += copy_len;
+ *size -= skip_len;
+ }
+ }
}
- // still buffer elements left?
- // don't worry, we already moved them to the correct place
+ // buffered elements need to be moved when we skipped duplicates
+ size_t total_skipped = new_size - *size;
+ if (bi < new_size && total_skipped > 0) {
+ // move the remaining buffer to the end of the array
+ memmove(dest, bptr, elem_size * (new_size - bi));
+ }
return 0;
}
+int cx_array_insert_sorted(
+ void **target,
+ size_t *size,
+ size_t *capacity,
+ cx_compare_func cmp_func,
+ const void *sorted_data,
+ size_t elem_size,
+ size_t elem_count,
+ CxArrayReallocator *reallocator
+) {
+ return cx_array_insert_sorted_impl(target, size, capacity,
+ cmp_func, sorted_data, elem_size, elem_count, reallocator, true);
+}
+
+int cx_array_insert_unique(
+ void **target,
+ size_t *size,
+ size_t *capacity,
+ cx_compare_func cmp_func,
+ const void *sorted_data,
+ size_t elem_size,
+ size_t elem_count,
+ CxArrayReallocator *reallocator
+) {
+ return cx_array_insert_sorted_impl(target, size, capacity,
+ cmp_func, sorted_data, elem_size, elem_count, reallocator, false);
+}
+
size_t cx_array_binary_search_inf(
const void *arr,
size_t size,
@@ -502,6 +633,13 @@ size_t cx_array_binary_search_inf(
result = cmp_func(elem, arr_elem);
if (result == 0) {
// found it!
+ // check previous elements;
+ // when they are equal, report the smallest index
+ arr_elem -= elem_size;
+ while (pivot_index > 0 && cmp_func(elem, arr_elem) == 0) {
+ pivot_index--;
+ arr_elem -= elem_size;
+ }
return pivot_index;
} else if (result < 0) {
// element is smaller than pivot, continue search left
@@ -700,6 +838,31 @@ static size_t cx_arl_insert_sorted(
}
}
+static size_t cx_arl_insert_unique(
+ struct cx_list_s *list,
+ const void *sorted_data,
+ size_t n
+) {
+ // get a correctly typed pointer to the list
+ cx_array_list *arl = (cx_array_list *) list;
+
+ if (cx_array_insert_unique(
+ &arl->data,
+ &list->collection.size,
+ &arl->capacity,
+ list->collection.cmpfunc,
+ sorted_data,
+ list->collection.elem_size,
+ n,
+ &arl->reallocator
+ )) {
+ // array list implementation is "all or nothing"
+ return 0;
+ } else {
+ return n;
+ }
+}
+
static void *cx_arl_insert_element(
struct cx_list_s *list,
size_t index,
@@ -717,7 +880,7 @@ static int cx_arl_insert_iter(
const void *elem,
int prepend
) {
- struct cx_list_s *list = iter->src_handle.m;
+ struct cx_list_s *list = iter->src_handle;
if (iter->index < list->collection.size) {
if (cx_arl_insert_element(list,
iter->index + 1 - prepend, elem) == NULL) {
@@ -928,7 +1091,7 @@ static void cx_arl_reverse(struct cx_list_s *list) {
static bool cx_arl_iter_valid(const void *it) {
const struct cx_iterator_s *iter = it;
- const struct cx_list_s *list = iter->src_handle.c;
+ const struct cx_list_s *list = iter->src_handle;
return iter->index < list->collection.size;
}
@@ -941,23 +1104,25 @@ static void cx_arl_iter_next(void *it) {
struct cx_iterator_s *iter = it;
if (iter->base.remove) {
iter->base.remove = false;
- cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL);
+ cx_arl_remove(iter->src_handle, iter->index, 1, NULL);
+ iter->elem_count--;
} else {
iter->index++;
iter->elem_handle =
((char *) iter->elem_handle)
- + ((const struct cx_list_s *) iter->src_handle.c)->collection.elem_size;
+ + ((const struct cx_list_s *) iter->src_handle)->collection.elem_size;
}
}
static void cx_arl_iter_prev(void *it) {
struct cx_iterator_s *iter = it;
- const cx_array_list *list = iter->src_handle.c;
if (iter->base.remove) {
iter->base.remove = false;
- cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL);
+ cx_arl_remove(iter->src_handle, iter->index, 1, NULL);
+ iter->elem_count--;
}
iter->index--;
+ cx_array_list *list = iter->src_handle;
if (iter->index < list->base.collection.size) {
iter->elem_handle = ((char *) list->data)
+ iter->index * list->base.collection.elem_size;
@@ -973,7 +1138,7 @@ static struct cx_iterator_s cx_arl_iterator(
struct cx_iterator_s iter;
iter.index = index;
- iter.src_handle.c = list;
+ iter.src_handle = (void*)list;
iter.elem_handle = cx_arl_at(list, index);
iter.elem_size = list->collection.elem_size;
iter.elem_count = list->collection.size;
@@ -981,7 +1146,7 @@ static struct cx_iterator_s cx_arl_iterator(
iter.base.current = cx_arl_iter_current;
iter.base.next = backwards ? cx_arl_iter_prev : cx_arl_iter_next;
iter.base.remove = false;
- iter.base.mutating = false;
+ iter.base.allow_remove = true;
return iter;
}
@@ -991,6 +1156,7 @@ static cx_list_class cx_array_list_class = {
cx_arl_insert_element,
cx_arl_insert_array,
cx_arl_insert_sorted,
+ cx_arl_insert_unique,
cx_arl_insert_iter,
cx_arl_remove,
cx_arl_clear,
diff --git a/ucx/compare.c b/ucx/compare.c
index b260aff..1fc036d 100644
--- a/ucx/compare.c
+++ b/ucx/compare.c
@@ -198,6 +198,20 @@ int cx_cmp_uint64(const void *i1, const void *i2) {
return cx_vcmp_uint64(a, b);
}
+int cx_vcmp_size(size_t a, size_t b) {
+ if (a == b) {
+ return 0;
+ } else {
+ return a < b ? -1 : 1;
+ }
+}
+
+int cx_cmp_size(const void *i1, const void *i2) {
+ size_t a = *((const size_t *) i1);
+ size_t b = *((const size_t *) i2);
+ return cx_vcmp_size(a, b);
+}
+
int cx_vcmp_float(float a, float b) {
if (fabsf(a - b) < 1e-6f) {
return 0;
diff --git a/ucx/cx/allocator.h b/ucx/cx/allocator.h
index c169a92..a69ef07 100644
--- a/ucx/cx/allocator.h
+++ b/ucx/cx/allocator.h
@@ -46,36 +46,22 @@ typedef struct {
/**
* The allocator's malloc() implementation.
*/
- void *(*malloc)(
- void *data,
- size_t n
- );
+ void *(*malloc)(void *data, size_t n);
/**
* The allocator's realloc() implementation.
*/
- void *(*realloc)(
- void *data,
- void *mem,
- size_t n
- );
+ void *(*realloc)(void *data, void *mem, size_t n);
/**
* The allocator's calloc() implementation.
*/
- void *(*calloc)(
- void *data,
- size_t nmemb,
- size_t size
- );
+ void *(*calloc)(void *data, size_t nmemb, size_t size);
/**
* The allocator's free() implementation.
*/
- void (*free)(
- void *data,
- void *mem
- );
+ void (*free)(void *data, void *mem);
} cx_allocator_class;
/**
@@ -100,15 +86,13 @@ typedef struct cx_allocator_s CxAllocator;
/**
* A pre-defined allocator using standard library malloc() etc.
*/
-cx_attr_export
-extern const CxAllocator * const cxStdlibAllocator;
+CX_EXPORT extern const CxAllocator * const cxStdlibAllocator;
/**
* The default allocator that is used by UCX.
* Initialized with cxStdlibAllocator, but you may change it.
*/
-cx_attr_export
-extern const CxAllocator * cxDefaultAllocator;
+CX_EXPORT extern const CxAllocator * cxDefaultAllocator;
/**
* Function pointer type for destructor functions.
@@ -133,10 +117,33 @@ typedef void (*cx_destructor_func)(void *memory);
* @param data an optional pointer to custom data
* @param memory a pointer to the object to destruct
*/
-typedef void (*cx_destructor_func2)(
- void *data,
- void *memory
-);
+typedef void (*cx_destructor_func2)(void *data, void *memory);
+
+
+/**
+ * Function pointer type for clone functions.
+ *
+ * A clone function is supposed to create a deep copy of the memory pointed to
+ * by the @p source pointer.
+ * If the @p target pointer is non-null, the clone function is supposed to store
+ * the copy into that memory region.
+ * Otherwise, the clone function shall use the specified @p allocator to create
+ * a new object.
+ *
+ * The return value of a clone function is always a pointer to the target
+ * memory region, or @c NULL if any allocation failed.
+ * A clone function SHOULD NOT fail for any other reason than an allocation
+ * failure.
+ *
+ * @param target the target memory or @c NULL, if memory shall be allocated
+ * @param source the source memory
+ * @param allocator the allocator that shall be used
+ * @param data optional additional data
+ * @return either the specified @p target, a pointer to the allocated memory,
+ * or @c NULL, if any error occurred
+ */
+typedef void*(cx_clone_func)(void *target, const void *source,
+ const CxAllocator *allocator, void *data);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
@@ -153,13 +160,8 @@ typedef void (*cx_destructor_func2)(
* @retval non-zero failure
* @see cx_reallocatearray()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_reallocate_(
- void **mem,
- size_t n
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_reallocate_(void **mem, size_t n);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
@@ -180,14 +182,8 @@ int cx_reallocate_(
* @retval non-zero failure
* @see cx_reallocate()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_reallocatearray_(
- void **mem,
- size_t nmemb,
- size_t size
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_reallocatearray_(void **mem, size_t nmemb, size_t size);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
@@ -244,11 +240,7 @@ int cx_reallocatearray_(
* @param mem a pointer to the block to free
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cxFree(
- const CxAllocator *allocator,
- void *mem
-);
+CX_EXPORT void cxFree(const CxAllocator *allocator, void *mem);
/**
* Allocate @p n bytes of memory.
@@ -257,21 +249,14 @@ void cxFree(
* @param n the number of bytes
* @return a pointer to the allocated memory
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_malloc
-cx_attr_dealloc_ucx
-cx_attr_allocsize(2)
-cx_attr_export
-void *cxMalloc(
- const CxAllocator *allocator,
- size_t n
-);
+cx_attr_nodiscard cx_attr_nonnull
+cx_attr_malloc cx_attr_dealloc_ucx cx_attr_allocsize(2)
+CX_EXPORT void *cxMalloc(const CxAllocator *allocator, size_t n);
/**
* Reallocate the previously allocated block in @p mem, making the new block
* @p n bytes long.
- * This function may return the same pointer that was passed to it, if moving
+ * This function may return the same pointer passed to it if moving
* the memory was not necessary.
*
* @note Re-allocating a block allocated by a different allocator is undefined.
@@ -281,25 +266,18 @@ void *cxMalloc(
* @param n the new size in bytes
* @return a pointer to the reallocated memory
*/
-cx_attr_nodiscard
-cx_attr_nonnull_arg(1)
-cx_attr_dealloc_ucx
-cx_attr_allocsize(3)
-cx_attr_export
-void *cxRealloc(
- const CxAllocator *allocator,
- void *mem,
- size_t n
-);
+cx_attr_nodiscard cx_attr_nonnull_arg(1)
+cx_attr_dealloc_ucx cx_attr_allocsize(3)
+CX_EXPORT void *cxRealloc(const CxAllocator *allocator, void *mem, size_t n);
/**
* Reallocate the previously allocated block in @p mem, making the new block
* @p n bytes long.
- * This function may return the same pointer that was passed to it, if moving
+ * This function may return the same pointer passed to it if moving
* the memory was not necessary.
*
* The size is calculated by multiplying @p nemb and @p size.
- * If that multiplication overflows, this function returns @c NULL and @c errno
+ * If that multiplication overflows, this function returns @c NULL, and @c errno
* will be set.
*
* @note Re-allocating a block allocated by a different allocator is undefined.
@@ -310,17 +288,10 @@ void *cxRealloc(
* @param size the size of each element
* @return a pointer to the reallocated memory
*/
-cx_attr_nodiscard
-cx_attr_nonnull_arg(1)
-cx_attr_dealloc_ucx
-cx_attr_allocsize(3, 4)
-cx_attr_export
-void *cxReallocArray(
- const CxAllocator *allocator,
- void *mem,
- size_t nmemb,
- size_t size
-);
+cx_attr_nodiscard cx_attr_nonnull_arg(1)
+cx_attr_dealloc_ucx cx_attr_allocsize(3, 4)
+CX_EXPORT void *cxReallocArray(const CxAllocator *allocator,
+ void *mem, size_t nmemb, size_t size);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
@@ -330,7 +301,7 @@ void *cxReallocArray(
* @note Re-allocating a block allocated by a different allocator is undefined.
*
* @par Error handling
- * @c errno will be set, if the underlying realloc function does so.
+ * @c errno will be set if the underlying realloc function does so.
*
* @param allocator the allocator
* @param mem pointer to the pointer to allocated block
@@ -338,14 +309,8 @@ void *cxReallocArray(
* @retval zero success
* @retval non-zero failure
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-int cxReallocate_(
- const CxAllocator *allocator,
- void **mem,
- size_t n
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT int cxReallocate_(const CxAllocator *allocator, void **mem, size_t n);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
@@ -355,7 +320,7 @@ int cxReallocate_(
* @note Re-allocating a block allocated by a different allocator is undefined.
*
* @par Error handling
- * @c errno will be set, if the underlying realloc function does so.
+ * @c errno will be set if the underlying realloc function does so.
*
* @param allocator (@c CxAllocator*) the allocator
* @param mem (@c void**) pointer to the pointer to allocated block
@@ -385,15 +350,9 @@ int cxReallocate_(
* @retval zero success
* @retval non-zero on failure
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-int cxReallocateArray_(
- const CxAllocator *allocator,
- void **mem,
- size_t nmemb,
- size_t size
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT int cxReallocateArray_(const CxAllocator *allocator,
+ void **mem, size_t nmemb, size_t size);
/**
* Reallocate a previously allocated block and changes the pointer in-place,
@@ -425,17 +384,9 @@ int cxReallocateArray_(
* @param size the size of each element in bytes
* @return a pointer to the allocated memory
*/
-cx_attr_nonnull_arg(1)
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc_ucx
-cx_attr_allocsize(2, 3)
-cx_attr_export
-void *cxCalloc(
- const CxAllocator *allocator,
- size_t nmemb,
- size_t size
-);
+cx_attr_nonnull_arg(1) cx_attr_nodiscard
+cx_attr_malloc cx_attr_dealloc_ucx cx_attr_allocsize(2, 3)
+CX_EXPORT void *cxCalloc(const CxAllocator *allocator, size_t nmemb, size_t size);
/**
* Allocate @p n bytes of memory and sets every byte to zero.
@@ -444,16 +395,9 @@ void *cxCalloc(
* @param n the number of bytes
* @return a pointer to the allocated memory
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_malloc
-cx_attr_dealloc_ucx
-cx_attr_allocsize(2)
-cx_attr_export
-void *cxZalloc(
- const CxAllocator *allocator,
- size_t n
-);
+cx_attr_nodiscard cx_attr_nonnull
+cx_attr_malloc cx_attr_dealloc_ucx cx_attr_allocsize(2)
+CX_EXPORT void *cxZalloc(const CxAllocator *allocator, size_t n);
/**
* Convenience macro that invokes cxMalloc() with the cxDefaultAllocator.
diff --git a/ucx/cx/array_list.h b/ucx/cx/array_list.h
index b38710d..97855dd 100644
--- a/ucx/cx/array_list.h
+++ b/ucx/cx/array_list.h
@@ -44,11 +44,10 @@ extern "C" {
#endif
/**
- * The maximum item size in an array list that fits into stack buffer
- * when swapped.
+ * The maximum item size in an array list that fits into
+ * a stack buffer when swapped.
*/
-cx_attr_export
-extern const unsigned cx_array_swap_sbo_size;
+CX_EXPORT extern const unsigned cx_array_swap_sbo_size;
/**
* Declares variables for an array that can be used with the convenience macros.
@@ -84,7 +83,7 @@ extern const unsigned cx_array_swap_sbo_size;
/**
* Declares variables for an array that can be used with the convenience macros.
*
- * The size and capacity variables will have @c size_t type.
+ * The size and capacity variables will have type @c size_t.
* Use #CX_ARRAY_DECLARE_SIZED() to specify a different type.
*
* @par Examples
@@ -147,7 +146,7 @@ extern const unsigned cx_array_swap_sbo_size;
* const CxAllocator *al = // ...
* cx_array_initialize_a(al, myarray, 128);
* // ...
- * cxFree(al, myarray); // don't forget to free with same allocator
+ * cxFree(al, myarray); // remember to free with the same allocator
* @endcode
*
* @param allocator (@c CxAllocator*) the allocator
@@ -172,10 +171,9 @@ struct cx_array_reallocator_s {
* Reallocates space for the given array.
*
* Implementations are not required to free the original array.
- * This allows reallocation of static memory by allocating heap memory
- * and copying the array contents. The information in the custom fields of
- * the referenced allocator can be used to track the state of the memory
- * or to transport other additional data.
+ * This allows reallocation of static or stack memory by allocating heap memory
+ * and copying the array contents; namely when @c stack_ptr in this struct
+ * is not @c NULL and @p array equals @c stack_ptr.
*
* @param array the array to reallocate
* @param old_capacity the old number of elements
@@ -184,33 +182,18 @@ struct cx_array_reallocator_s {
* @param alloc a reference to this allocator
* @return a pointer to the reallocated memory or @c NULL on failure
*/
- cx_attr_nodiscard
- cx_attr_nonnull_arg(5)
- cx_attr_allocsize(3, 4)
- void *(*realloc)(
- void *array,
- size_t old_capacity,
- size_t new_capacity,
- size_t elem_size,
- struct cx_array_reallocator_s *alloc
- );
+ void *(*realloc)( void *array, size_t old_capacity, size_t new_capacity,
+ size_t elem_size, struct cx_array_reallocator_s *alloc);
/**
- * Custom data pointer.
+ * The allocator that shall be used for the reallocations.
*/
- void *ptr1;
+ const CxAllocator *allocator;
/**
- * Custom data pointer.
+ * Optional pointer to stack memory
+ * if the array is originally located on the stack.
*/
- void *ptr2;
- /**
- * Custom data integer.
- */
- size_t int1;
- /**
- * Custom data integer.
- */
- size_t int2;
+ const void *stack_ptr;
};
/**
@@ -221,32 +204,28 @@ typedef struct cx_array_reallocator_s CxArrayReallocator;
/**
* A default array reallocator that is based on the cxDefaultAllocator.
*/
-cx_attr_export
-extern CxArrayReallocator *cx_array_default_reallocator;
+CX_EXPORT extern CxArrayReallocator *cx_array_default_reallocator;
/**
* Creates a new array reallocator.
*
* When @p allocator is @c NULL, the cxDefaultAllocator will be used.
*
- * When @p stackmem is not @c NULL, the reallocator is supposed to be used
- * @em only for the specific array that is initially located at @p stackmem.
- * When reallocation is needed, the reallocator checks, if the array is
- * still located at @p stackmem and copies the contents to the heap.
+ * When @p stack_ptr is not @c NULL, the reallocator is supposed to be used
+ * @em only for the specific array initially located at @p stack_ptr.
+ * When reallocation is needed, the reallocator checks if the array is
+ * still located at @p stack_ptr and copies the contents to the heap.
*
- * @note Invoking this function with both arguments @c NULL will return a
+ * @note Invoking this function with both arguments being @c NULL will return a
* reallocator that behaves like #cx_array_default_reallocator.
*
* @param allocator the allocator this reallocator shall be based on
- * @param stackmem the address of the array when the array is initially located
- * on the stack or shall not reallocated in place
+ * @param stack_ptr the address of the array when the array is initially located
+ * on the stack or shall not reallocate in place
* @return an array reallocator
*/
-cx_attr_export
-CxArrayReallocator cx_array_reallocator(
- const struct cx_allocator_s *allocator,
- const void *stackmem
-);
+CX_EXPORT CxArrayReallocator cx_array_reallocator(
+ const struct cx_allocator_s *allocator, const void *stack_ptr);
/**
* Reserves memory for additional elements.
@@ -263,7 +242,7 @@ CxArrayReallocator cx_array_reallocator(
*
* The @p width in bytes refers to the size and capacity.
* Both must have the same width.
- * Supported are 0, 1, 2, and 4, as well as 8 if running on a 64 bit
+ * Supported are 0, 1, 2, and 4, as well as 8 if running on a 64-bit
* architecture. If set to zero, the native word width is used.
*
* @param array a pointer to the target array
@@ -279,16 +258,9 @@ CxArrayReallocator cx_array_reallocator(
* @see cx_array_reallocator()
*/
cx_attr_nonnull_arg(1, 2, 3)
-cx_attr_export
-int cx_array_reserve(
- void **array,
- void *size,
- void *capacity,
- unsigned width,
- size_t elem_size,
- size_t elem_count,
- CxArrayReallocator *reallocator
-);
+CX_EXPORT int cx_array_reserve(void **array, void *size, void *capacity,
+ unsigned width, size_t elem_size, size_t elem_count,
+ CxArrayReallocator *reallocator);
/**
* Copies elements from one array to another.
@@ -296,7 +268,7 @@ int cx_array_reserve(
* The elements are copied to the @p target array at the specified @p index,
* overwriting possible elements. The @p index does not need to be in range of
* the current array @p size. If the new index plus the number of elements added
- * would extend the array's size, the remaining @p capacity is used.
+ * extends the array's size, the remaining @p capacity is used.
*
* If the @p capacity is also insufficient to hold the new data, a reallocation
* attempt is made with the specified @p reallocator.
@@ -305,7 +277,7 @@ int cx_array_reserve(
*
* The @p width in bytes refers to the size and capacity.
* Both must have the same width.
- * Supported are 0, 1, 2, and 4, as well as 8 if running on a 64 bit
+ * Supported are 0, 1, 2, and 4, as well as 8 if running on a 64-bit
* architecture. If set to zero, the native word width is used.
*
* @param target a pointer to the target array
@@ -323,18 +295,9 @@ int cx_array_reserve(
* @see cx_array_reallocator()
*/
cx_attr_nonnull_arg(1, 2, 3, 6)
-cx_attr_export
-int cx_array_copy(
- void **target,
- void *size,
- void *capacity,
- unsigned width,
- size_t index,
- const void *src,
- size_t elem_size,
- size_t elem_count,
- CxArrayReallocator *reallocator
-);
+CX_EXPORT int cx_array_copy(void **target, void *size, void *capacity, unsigned width,
+ size_t index, const void *src, size_t elem_size, size_t elem_count,
+ CxArrayReallocator *reallocator);
/**
* Convenience macro that uses cx_array_copy() with a default layout and
@@ -482,17 +445,9 @@ int cx_array_copy(
* @retval non-zero failure
*/
cx_attr_nonnull_arg(1, 2, 3, 5)
-cx_attr_export
-int cx_array_insert_sorted(
- void **target,
- size_t *size,
- size_t *capacity,
- cx_compare_func cmp_func,
- const void *src,
- size_t elem_size,
- size_t elem_count,
- CxArrayReallocator *reallocator
-);
+CX_EXPORT int cx_array_insert_sorted(void **target, size_t *size, size_t *capacity,
+ cx_compare_func cmp_func, const void *src, size_t elem_size, size_t elem_count,
+ CxArrayReallocator *reallocator);
/**
* Inserts an element into a sorted array.
@@ -500,7 +455,7 @@ int cx_array_insert_sorted(
* If the target array is not already sorted with respect
* to the specified @p cmp_func, the behavior is undefined.
*
- * If the capacity is insufficient to hold the new data, a reallocation
+ * If the capacity is not enough to hold the new data, a reallocation
* attempt is made.
*
* The \@ SIZE_TYPE is flexible and can be any unsigned integer type.
@@ -586,6 +541,127 @@ int cx_array_insert_sorted(
#define cx_array_simple_insert_sorted(array, src, n, cmp_func) \
cx_array_simple_insert_sorted_a(NULL, array, src, n, cmp_func)
+
+/**
+ * Inserts a sorted array into another sorted array, avoiding duplicates.
+ *
+ * If either the target or the source array is not already sorted with respect
+ * to the specified @p cmp_func, the behavior is undefined.
+ *
+ * If the capacity is insufficient to hold the new data, a reallocation
+ * attempt is made.
+ * You can create your own reallocator by hand, use #cx_array_default_reallocator,
+ * or use the convenience function cx_array_reallocator() to create a custom reallocator.
+ *
+ * @param target a pointer to the target array
+ * @param size a pointer to the size of the target array
+ * @param capacity a pointer to the capacity of the target array
+ * @param cmp_func the compare function for the elements
+ * @param src the source array
+ * @param elem_size the size of one element
+ * @param elem_count the number of elements to insert
+ * @param reallocator the array reallocator to use
+ * (@c NULL defaults to #cx_array_default_reallocator)
+ * @retval zero success
+ * @retval non-zero failure
+ */
+cx_attr_nonnull_arg(1, 2, 3, 5)
+CX_EXPORT int cx_array_insert_unique(void **target, size_t *size, size_t *capacity,
+ cx_compare_func cmp_func, const void *src, size_t elem_size, size_t elem_count,
+ CxArrayReallocator *reallocator);
+
+/**
+ * Inserts an element into a sorted array if it does not exist.
+ *
+ * If the target array is not already sorted with respect
+ * to the specified @p cmp_func, the behavior is undefined.
+ *
+ * If the capacity is insufficient to hold the new data, a reallocation
+ * attempt is made.
+ *
+ * The \@ SIZE_TYPE is flexible and can be any unsigned integer type.
+ * It is important, however, that @p size and @p capacity are pointers to
+ * variables of the same type.
+ *
+ * @param target (@c void**) a pointer to the target array
+ * @param size (@c SIZE_TYPE*) a pointer to the size of the target array
+ * @param capacity (@c SIZE_TYPE*) a pointer to the capacity of the target array
+ * @param elem_size (@c size_t) the size of one element
+ * @param elem (@c void*) a pointer to the element to add
+ * @param cmp_func (@c cx_cmp_func) the compare function for the elements
+ * @param reallocator (@c CxArrayReallocator*) the array reallocator to use
+ * @retval zero success (also when the element was already present)
+ * @retval non-zero failure
+ */
+#define cx_array_add_unique(target, size, capacity, elem_size, elem, cmp_func, reallocator) \
+ cx_array_insert_unique((void**)(target), size, capacity, cmp_func, elem, elem_size, 1, reallocator)
+
+/**
+ * Convenience macro for cx_array_add_unique() with a default
+ * layout and the specified reallocator.
+ *
+ * @param reallocator (@c CxArrayReallocator*) the array reallocator to use
+ * @param array the name of the array (NOT a pointer or alias to the array)
+ * @param elem the element to add (NOT a pointer, address is automatically taken)
+ * @param cmp_func (@c cx_cmp_func) the compare function for the elements
+ * @retval zero success
+ * @retval non-zero failure
+ * @see CX_ARRAY_DECLARE()
+ * @see cx_array_simple_add_unique()
+ */
+#define cx_array_simple_add_unique_a(reallocator, array, elem, cmp_func) \
+ cx_array_add_unique(&array, &(array##_size), &(array##_capacity), \
+ sizeof((array)[0]), &(elem), cmp_func, reallocator)
+
+/**
+ * Convenience macro for cx_array_add_unique() with a default
+ * layout and the default reallocator.
+ *
+ * @param array the name of the array (NOT a pointer or alias to the array)
+ * @param elem the element to add (NOT a pointer, address is automatically taken)
+ * @param cmp_func (@c cx_cmp_func) the compare function for the elements
+ * @retval zero success
+ * @retval non-zero failure
+ * @see CX_ARRAY_DECLARE()
+ * @see cx_array_simple_add_unique_a()
+ */
+#define cx_array_simple_add_unique(array, elem, cmp_func) \
+ cx_array_simple_add_unique_a(NULL, array, elem, cmp_func)
+
+/**
+ * Convenience macro for cx_array_insert_unique() with a default
+ * layout and the specified reallocator.
+ *
+ * @param reallocator (@c CxArrayReallocator*) the array reallocator to use
+ * @param array the name of the array (NOT a pointer or alias to the array)
+ * @param src (@c void*) pointer to the source array
+ * @param n (@c size_t) number of elements in the source array
+ * @param cmp_func (@c cx_cmp_func) the compare function for the elements
+ * @retval zero success
+ * @retval non-zero failure
+ * @see CX_ARRAY_DECLARE()
+ * @see cx_array_simple_insert_unique()
+ */
+#define cx_array_simple_insert_unique_a(reallocator, array, src, n, cmp_func) \
+ cx_array_insert_unique((void**)(&array), &(array##_size), &(array##_capacity), \
+ cmp_func, src, sizeof((array)[0]), n, reallocator)
+
+/**
+ * Convenience macro for cx_array_insert_unique() with a default
+ * layout and the default reallocator.
+ *
+ * @param array the name of the array (NOT a pointer or alias to the array)
+ * @param src (@c void*) pointer to the source array
+ * @param n (@c size_t) number of elements in the source array
+ * @param cmp_func (@c cx_cmp_func) the compare function for the elements
+ * @retval zero success
+ * @retval non-zero failure
+ * @see CX_ARRAY_DECLARE()
+ * @see cx_array_simple_insert_unique_a()
+ */
+#define cx_array_simple_insert_unique(array, src, n, cmp_func) \
+ cx_array_simple_insert_unique_a(NULL, array, src, n, cmp_func)
+
/**
* Searches the largest lower bound in a sorted array.
*
@@ -609,14 +685,8 @@ int cx_array_insert_sorted(
* @see cx_array_binary_search()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_array_binary_search_inf(
- const void *arr,
- size_t size,
- size_t elem_size,
- const void *elem,
- cx_compare_func cmp_func
-);
+CX_EXPORT size_t cx_array_binary_search_inf(const void *arr, size_t size,
+ size_t elem_size, const void *elem, cx_compare_func cmp_func);
/**
* Searches an item in a sorted array.
@@ -635,14 +705,8 @@ size_t cx_array_binary_search_inf(
* @see cx_array_binary_search_sup()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_array_binary_search(
- const void *arr,
- size_t size,
- size_t elem_size,
- const void *elem,
- cx_compare_func cmp_func
-);
+CX_EXPORT size_t cx_array_binary_search(const void *arr, size_t size,
+ size_t elem_size, const void *elem, cx_compare_func cmp_func);
/**
* Searches the smallest upper bound in a sorted array.
@@ -667,37 +731,25 @@ size_t cx_array_binary_search(
* @see cx_array_binary_search()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_array_binary_search_sup(
- const void *arr,
- size_t size,
- size_t elem_size,
- const void *elem,
- cx_compare_func cmp_func
-);
+CX_EXPORT size_t cx_array_binary_search_sup(const void *arr, size_t size,
+ size_t elem_size, const void *elem, cx_compare_func cmp_func);
/**
* Swaps two array elements.
*
* @param arr the array
* @param elem_size the element size
- * @param idx1 index of first element
- * @param idx2 index of second element
+ * @param idx1 index of the first element
+ * @param idx2 index of the second element
*/
cx_attr_nonnull
-cx_attr_export
-void cx_array_swap(
- void *arr,
- size_t elem_size,
- size_t idx1,
- size_t idx2
-);
+CX_EXPORT void cx_array_swap(void *arr, size_t elem_size, size_t idx1, size_t idx2);
/**
* Allocates an array list for storing elements with @p elem_size bytes each.
*
* If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
- * copies of the added elements and the compare function will be automatically set
+ * copies of the added elements, and the compare function will be automatically set
* to cx_cmp_ptr(), if none is given.
*
* @param allocator the allocator for allocating the list memory
@@ -712,13 +764,8 @@ void cx_array_swap(
cx_attr_nodiscard
cx_attr_malloc
cx_attr_dealloc(cxListFree, 1)
-cx_attr_export
-CxList *cxArrayListCreate(
- const CxAllocator *allocator,
- cx_compare_func comparator,
- size_t elem_size,
- size_t initial_capacity
-);
+CX_EXPORT CxList *cxArrayListCreate(const CxAllocator *allocator,
+ cx_compare_func comparator, size_t elem_size, size_t initial_capacity);
/**
* Allocates an array list for storing elements with @p elem_size bytes each.
diff --git a/ucx/cx/buffer.h b/ucx/cx/buffer.h
index 867fb30..6324a0b 100644
--- a/ucx/cx/buffer.h
+++ b/ucx/cx/buffer.h
@@ -62,7 +62,7 @@ extern "C" {
* If this flag is enabled, the buffer will automatically free its contents when destroyed.
*
* Do NOT set this flag together with #CX_BUFFER_COPY_ON_WRITE. It will be automatically
- * set when the copy-on-write operations is performed.
+ * set when the copy-on-write operation is performed.
*/
#define CX_BUFFER_FREE_CONTENTS 0x01
@@ -74,7 +74,7 @@ extern "C" {
/**
* If this flag is enabled, the buffer will allocate new memory when written to.
*
- * The current contents of the buffer will be copied to the new memory and the flag
+ * The current contents of the buffer will be copied to the new memory, and the flag
* will be cleared while the #CX_BUFFER_FREE_CONTENTS flag will be set automatically.
*/
#define CX_BUFFER_COPY_ON_WRITE 0x04
@@ -127,7 +127,7 @@ struct cx_buffer_flush_config_s {
size_t blkmax;
/**
- * The target for write function.
+ * The target for the write function.
*/
void *target;
@@ -202,7 +202,7 @@ typedef struct cx_buffer_s CxBuffer;
* you will need to cast the pointer, and you should set the
* #CX_BUFFER_COPY_ON_WRITE flag.
*
- * You need to set the size manually after initialization, if
+ * You need to set the size manually after initialization if
* you provide @p space which already contains data.
*
* When you specify stack memory as @p space and decide to use
@@ -210,7 +210,7 @@ typedef struct cx_buffer_s CxBuffer;
* #CX_BUFFER_COPY_ON_EXTEND flag, instead of the
* #CX_BUFFER_AUTO_EXTEND flag.
*
- * @note You may provide @c NULL as argument for @p space.
+ * @note You may provide @c NULL as the argument for @p space.
* Then this function will allocate the space and enforce
* the #CX_BUFFER_FREE_CONTENTS flag. In that case, specifying
* copy-on-write should be avoided, because the allocated
@@ -227,14 +227,8 @@ typedef struct cx_buffer_s CxBuffer;
* @return zero on success, non-zero if a required allocation failed
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-int cxBufferInit(
- CxBuffer *buffer,
- void *space,
- size_t capacity,
- const CxAllocator *allocator,
- int flags
-);
+CX_EXPORT int cxBufferInit(CxBuffer *buffer, void *space, size_t capacity,
+ const CxAllocator *allocator, int flags);
/**
* Configures the buffer for flushing.
@@ -251,11 +245,7 @@ int cxBufferInit(
* @see cxBufferWrite()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferEnableFlushing(
- CxBuffer *buffer,
- CxBufferFlushConfig config
-);
+CX_EXPORT int cxBufferEnableFlushing(CxBuffer *buffer, CxBufferFlushConfig config);
/**
* Destroys the buffer contents.
@@ -267,8 +257,7 @@ int cxBufferEnableFlushing(
* @see cxBufferInit()
*/
cx_attr_nonnull
-cx_attr_export
-void cxBufferDestroy(CxBuffer *buffer);
+CX_EXPORT void cxBufferDestroy(CxBuffer *buffer);
/**
* Deallocates the buffer.
@@ -276,14 +265,10 @@ void cxBufferDestroy(CxBuffer *buffer);
* If the #CX_BUFFER_FREE_CONTENTS feature is enabled, this function also destroys
* the contents. If you @em only want to destroy the contents, use cxBufferDestroy().
*
- * @remark As with all free() functions, this accepts @c NULL arguments in which
- * case it does nothing.
- *
* @param buffer the buffer to deallocate
* @see cxBufferCreate()
*/
-cx_attr_export
-void cxBufferFree(CxBuffer *buffer);
+CX_EXPORT void cxBufferFree(CxBuffer *buffer);
/**
* Allocates and initializes a fresh buffer.
@@ -296,7 +281,7 @@ void cxBufferFree(CxBuffer *buffer);
* #CX_BUFFER_COPY_ON_EXTEND flag, instead of the
* #CX_BUFFER_AUTO_EXTEND flag.
*
- * @note You may provide @c NULL as argument for @p space.
+ * @note You may provide @c NULL as the argument for @p space.
* Then this function will allocate the space and enforce
* the #CX_BUFFER_FREE_CONTENTS flag.
*
@@ -309,16 +294,9 @@ void cxBufferFree(CxBuffer *buffer);
* @param flags buffer features (see cx_buffer_s.flags)
* @return a pointer to the buffer on success, @c NULL if a required allocation failed
*/
-cx_attr_malloc
-cx_attr_dealloc(cxBufferFree, 1)
-cx_attr_nodiscard
-cx_attr_export
-CxBuffer *cxBufferCreate(
- void *space,
- size_t capacity,
- const CxAllocator *allocator,
- int flags
-);
+cx_attr_malloc cx_attr_dealloc(cxBufferFree, 1) cx_attr_nodiscard
+CX_EXPORT CxBuffer *cxBufferCreate(void *space, size_t capacity,
+ const CxAllocator *allocator, int flags);
/**
* Shifts the contents of the buffer by the given offset.
@@ -327,8 +305,8 @@ CxBuffer *cxBufferCreate(
* If auto extension is enabled, the buffer grows, if necessary.
* In case the auto extension fails, this function returns a non-zero value and
* no contents are changed.
- * If auto extension is disabled, the contents that do not fit into the buffer
- * are discarded.
+ * When the auto extension is disabled, the contents that do not fit into the
+ * buffer are discarded.
*
* If the offset is negative, the contents are shifted to the left where the
* first @p shift bytes are discarded.
@@ -336,15 +314,15 @@ CxBuffer *cxBufferCreate(
* If this value is larger than the buffer size, the buffer is emptied (but
* not cleared, see the security note below).
*
- * The buffer position gets shifted alongside with the content but is kept
+ * The buffer position gets shifted alongside the content but is kept
* within the boundaries of the buffer.
*
* @note For situations where @c off_t is not large enough, there are specialized cxBufferShiftLeft() and
- * cxBufferShiftRight() functions using a @c size_t as parameter type.
+ * cxBufferShiftRight() functions using a @c size_t as the parameter type.
*
* @attention
* Security Note: The shifting operation does @em not erase the previously occupied memory cells.
- * But you can easily do that manually, e.g. by calling
+ * But you can do that manually by calling
* memset(buffer->bytes, 0, shift) for a right shift or
* memset(buffer->bytes + buffer->size, 0, buffer->capacity - buffer->size)
* for a left shift.
@@ -357,11 +335,7 @@ CxBuffer *cxBufferCreate(
* @see cxBufferShiftRight()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferShift(
- CxBuffer *buffer,
- off_t shift
-);
+CX_EXPORT int cxBufferShift(CxBuffer *buffer, off_t shift);
/**
* Shifts the buffer to the right.
@@ -374,11 +348,7 @@ int cxBufferShift(
* @see cxBufferShift()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferShiftRight(
- CxBuffer *buffer,
- size_t shift
-);
+CX_EXPORT int cxBufferShiftRight(CxBuffer *buffer, size_t shift);
/**
* Shifts the buffer to the left.
@@ -391,11 +361,7 @@ int cxBufferShiftRight(
* @see cxBufferShift()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferShiftLeft(
- CxBuffer *buffer,
- size_t shift
-);
+CX_EXPORT int cxBufferShiftLeft(CxBuffer *buffer, size_t shift);
/**
@@ -419,12 +385,7 @@ int cxBufferShiftLeft(
*
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferSeek(
- CxBuffer *buffer,
- off_t offset,
- int whence
-);
+CX_EXPORT int cxBufferSeek(CxBuffer *buffer, off_t offset, int whence);
/**
* Clears the buffer by resetting the position and deleting the data.
@@ -439,8 +400,7 @@ int cxBufferSeek(
* @see cxBufferReset()
*/
cx_attr_nonnull
-cx_attr_export
-void cxBufferClear(CxBuffer *buffer);
+CX_EXPORT void cxBufferClear(CxBuffer *buffer);
/**
* Resets the buffer by resetting the position and size to zero.
@@ -452,8 +412,7 @@ void cxBufferClear(CxBuffer *buffer);
* @see cxBufferClear()
*/
cx_attr_nonnull
-cx_attr_export
-void cxBufferReset(CxBuffer *buffer);
+CX_EXPORT void cxBufferReset(CxBuffer *buffer);
/**
* Tests, if the buffer position has exceeded the buffer size.
@@ -463,10 +422,8 @@ void cxBufferReset(CxBuffer *buffer);
* byte of the buffer's contents
* @retval false otherwise
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-bool cxBufferEof(const CxBuffer *buffer);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT bool cxBufferEof(const CxBuffer *buffer);
/**
@@ -484,11 +441,7 @@ bool cxBufferEof(const CxBuffer *buffer);
* @see cxBufferShrink()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferMinimumCapacity(
- CxBuffer *buffer,
- size_t capacity
-);
+CX_EXPORT int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity);
/**
* Shrinks the capacity of the buffer to fit its current size.
@@ -507,17 +460,13 @@ int cxBufferMinimumCapacity(
* @see cxBufferMinimumCapacity()
*/
cx_attr_nonnull
-cx_attr_export
-void cxBufferShrink(
- CxBuffer *buffer,
- size_t reserve
-);
+CX_EXPORT void cxBufferShrink(CxBuffer *buffer, size_t reserve);
/**
* Writes data to a CxBuffer.
*
* If automatic flushing is not enabled, the data is simply written into the
- * buffer at the current position and the position of the buffer is increased
+ * buffer at the current position, and the position of the buffer is increased
* by the number of bytes written.
*
* If flushing is enabled and the buffer needs to flush, the data is flushed to
@@ -526,7 +475,7 @@ void cxBufferShrink(
* data in this buffer is shifted to the beginning of this buffer so that the
* newly available space can be used to append as much data as possible.
*
- * This function only stops writing more elements, when the flush target and this
+ * This function only stops writing more elements when the flush target and this
* buffer are both incapable of taking more data or all data has been written.
*
* If, after flushing, the number of items that shall be written still exceeds
@@ -534,14 +483,14 @@ void cxBufferShrink(
* to the flush target, if possible.
*
* The number returned by this function is the number of elements from
- * @c ptr that could be written to either the flush target or the buffer
- * (so it does not include the number of items that had been already in the buffer
- * in were flushed during the process).
+ * @c ptr that could be written to either the flush target or the buffer.
+ * That means it does @em not include the number of items that were already in
+ * the buffer and were also flushed during the process.
*
* @attention
* When @p size is larger than one and the contents of the buffer are not aligned
* with @p size, flushing stops after all complete items have been flushed, leaving
- * the mis-aligned part in the buffer.
+ * the misaligned part in the buffer.
* Afterward, this function only writes as many items as possible to the buffer.
*
* @note The signature is compatible with the fwrite() family of functions.
@@ -555,13 +504,8 @@ void cxBufferShrink(
* @see cxBufferRead()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cxBufferWrite(
- const void *ptr,
- size_t size,
- size_t nitems,
- CxBuffer *buffer
-);
+CX_EXPORT size_t cxBufferWrite(const void *ptr, size_t size,
+ size_t nitems, CxBuffer *buffer);
/**
* Appends data to a CxBuffer.
@@ -583,13 +527,8 @@ size_t cxBufferWrite(
* @see cxBufferRead()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cxBufferAppend(
- const void *ptr,
- size_t size,
- size_t nitems,
- CxBuffer *buffer
-);
+CX_EXPORT size_t cxBufferAppend(const void *ptr, size_t size,
+ size_t nitems, CxBuffer *buffer);
/**
* Performs a single flush-run on the specified buffer.
@@ -614,19 +553,19 @@ size_t cxBufferAppend(
* at position 200. The flush configuration is
* @c blkmax=4 and @c blksize=64 .
* Assume that the entire flush operation is successful.
- * All 200 bytes on the left hand-side from the current
+ * All 200 bytes on the left-hand-side from the current
* position are written.
- * That means, the size of the buffer is now 140 and the
+ * That means the size of the buffer is now 140 and the
* position is zero.
*
* @par Example 2
* Same as Example 1, but now the @c blkmax is 1.
- * The size of the buffer is now 276 and the position is 136.
+ * The size of the buffer is now 276, and the position is 136.
*
* @par Example 3
* Same as Example 1, but now assume the flush target
* only accepts 100 bytes before returning zero.
- * That means, the flush operations manages to flush
+ * That means the flush operation manages to flush
* one complete block and one partial block, ending
* up with a buffer with size 240 and position 100.
*
@@ -636,8 +575,8 @@ size_t cxBufferAppend(
* @remark When the buffer uses copy-on-write, the memory
* is copied first, before attempting any flush.
* This is, however, considered an erroneous use of the
- * buffer, because it does not make much sense to put
- * readonly data into an UCX buffer for flushing, instead
+ * buffer because it makes little sense to put
+ * readonly data into an UCX buffer for flushing instead
* of writing it directly to the target.
*
* @param buffer the buffer
@@ -645,8 +584,7 @@ size_t cxBufferAppend(
* @see cxBufferEnableFlushing()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cxBufferFlush(CxBuffer *buffer);
+CX_EXPORT size_t cxBufferFlush(CxBuffer *buffer);
/**
* Reads data from a CxBuffer.
@@ -664,13 +602,8 @@ size_t cxBufferFlush(CxBuffer *buffer);
* @see cxBufferAppend()
*/
cx_attr_nonnull
-cx_attr_export
-size_t cxBufferRead(
- void *ptr,
- size_t size,
- size_t nitems,
- CxBuffer *buffer
-);
+CX_EXPORT size_t cxBufferRead(void *ptr, size_t size,
+ size_t nitems, CxBuffer *buffer);
/**
* Writes a character to a buffer.
@@ -678,9 +611,9 @@ size_t cxBufferRead(
* The least significant byte of the argument is written to the buffer. If the
* end of the buffer is reached and #CX_BUFFER_AUTO_EXTEND feature is enabled,
* the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature
- * is disabled or buffer extension fails, @c EOF is returned.
+ * is disabled or the buffer extension fails, @c EOF is returned.
*
- * On successful write, the position of the buffer is increased.
+ * On successful writing, the position of the buffer is increased.
*
* If you just want to write a null-terminator at the current position, you
* should use cxBufferTerminate() instead.
@@ -688,15 +621,11 @@ size_t cxBufferRead(
* @param buffer the buffer to write to
* @param c the character to write
* @return the byte that has been written or @c EOF when the end of the stream is
- * reached and automatic extension is not enabled or not possible
+ * reached, and automatic extension is not enabled or not possible
* @see cxBufferTerminate()
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferPut(
- CxBuffer *buffer,
- int c
-);
+CX_EXPORT int cxBufferPut(CxBuffer *buffer, int c);
/**
* Writes a terminating zero to a buffer at the current position.
@@ -710,8 +639,7 @@ int cxBufferPut(
* @return zero, if the terminator could be written, non-zero otherwise
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferTerminate(CxBuffer *buffer);
+CX_EXPORT int cxBufferTerminate(CxBuffer *buffer);
/**
* Writes a string to a buffer.
@@ -722,13 +650,8 @@ int cxBufferTerminate(CxBuffer *buffer);
* @param str the zero-terminated string
* @return the number of bytes written
*/
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-cx_attr_export
-size_t cxBufferPutString(
- CxBuffer *buffer,
- const char *str
-);
+cx_attr_nonnull cx_attr_cstr_arg(2)
+CX_EXPORT size_t cxBufferPutString(CxBuffer *buffer, const char *str);
/**
* Gets a character from a buffer.
@@ -739,8 +662,7 @@ size_t cxBufferPutString(
* @return the character or @c EOF, if the end of the buffer is reached
*/
cx_attr_nonnull
-cx_attr_export
-int cxBufferGet(CxBuffer *buffer);
+CX_EXPORT int cxBufferGet(CxBuffer *buffer);
#ifdef __cplusplus
}
diff --git a/ucx/cx/collection.h b/ucx/cx/collection.h
index ba329dc..8e900d3 100644
--- a/ucx/cx/collection.h
+++ b/ucx/cx/collection.h
@@ -142,14 +142,16 @@ struct cx_collection_s {
/**
* Indicates whether the collection can guarantee that the stored elements are currently sorted.
*
- * This may return false even when the elements are sorted.
- * It is totally up to the implementation of the collection whether it keeps track of the order of its elements.
+ * This may return @c false even when the elements are sorted.
+ * It is totally up to the implementation of the collection when to check if the elements are sorted.
+ * It is usually a good practice to establish this property as an invariant that does not need
+ * to be re-checked on certain operations.
*
* @param c a pointer to a struct that contains #CX_COLLECTION_BASE
* @retval true if the elements are currently sorted wrt. the collection's compare function
* @retval false if the order of elements is unknown
*/
-#define cxCollectionSorted(c) ((c)->collection.sorted)
+#define cxCollectionSorted(c) ((c)->collection.sorted || (c)->collection.size == 0)
/**
* Sets a simple destructor function for this collection.
diff --git a/ucx/cx/common.h b/ucx/cx/common.h
index 0fc9e47..45a61d5 100644
--- a/ucx/cx/common.h
+++ b/ucx/cx/common.h
@@ -49,7 +49,7 @@
* https://uap-core.de/hg/ucx
*
*
- * LICENCE
+ * LICENSE
*
* Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
*
@@ -130,6 +130,11 @@
#define __attribute__(x)
#endif
+/**
+ * Inform the compiler that falling through a switch case is intentional.
+ */
+#define cx_attr_fallthrough __attribute__((__fallthrough__))
+
/**
* All pointer arguments must be non-NULL.
*/
@@ -184,7 +189,7 @@
*/
#define cx_attr_cstr_arg(idx)
/**
- * No support for access attribute in clang.
+ * No support for the access attribute in clang.
*/
#define cx_attr_access(mode, ...)
#else
@@ -260,15 +265,32 @@
#define _Thread_local __declspec(thread)
#endif // _MSC_VER
+// ---------------------------------------------------------------------------
+// Exported and inlined functions
+// ---------------------------------------------------------------------------
+
#if defined(CX_WINDLL_EXPORT)
-#define cx_attr_export __declspec(dllexport)
+#define CX_EXPORT __declspec(dllexport)
#elif defined(CX_WINDLL)
-#define cx_attr_export __declspec(dllimport)
+#define CX_EXPORT __declspec(dllimport)
#else
/** Only used for building Windows DLLs. */
-#define cx_attr_export
+#define CX_EXPORT
#endif // CX_WINDLL / CX_WINDLL_EXPORT
+#ifdef __GNUC__
+/**
+ * Declares a function to be inlined.
+ */
+#define CX_INLINE __attribute__((always_inline)) static inline
+#else
+#define CX_INLINE static inline
+#endif
+/**
+ * Declares a compatibility function for C++ builds.
+ */
+#define CX_CPPDECL static inline
+
// ---------------------------------------------------------------------------
// Useful function pointers
// ---------------------------------------------------------------------------
@@ -276,22 +298,12 @@
/**
* Function pointer compatible with fwrite-like functions.
*/
-typedef size_t (*cx_write_func)(
- const void *,
- size_t,
- size_t,
- void *
-);
+typedef size_t (*cx_write_func)(const void*, size_t, size_t, void*);
/**
* Function pointer compatible with fread-like functions.
*/
-typedef size_t (*cx_read_func)(
- void *,
- size_t,
- size_t,
- void *
-);
+typedef size_t (*cx_read_func)(void*, size_t, size_t, void*);
// ---------------------------------------------------------------------------
// Utility macros
@@ -343,9 +355,7 @@ typedef size_t (*cx_read_func)(
#if __cplusplus
extern "C"
#endif
-cx_attr_export int cx_szmul_impl(size_t a, size_t b, size_t *result);
+CX_EXPORT int cx_szmul_impl(size_t a, size_t b, size_t *result);
#endif // cx_szmul
-
-
#endif // UCX_COMMON_H
diff --git a/ucx/cx/compare.h b/ucx/cx/compare.h
index cb4ddf1..1b66e62 100644
--- a/ucx/cx/compare.h
+++ b/ucx/cx/compare.h
@@ -47,20 +47,14 @@ extern "C" {
*
* All functions from compare.h with the cx_cmp prefix are
* compatible with this signature and can be used as
- * compare function for collections, or other implementations
+ * compare function for collections or other implementations
* that need to be type-agnostic.
*
* For simple comparisons the cx_vcmp family of functions
* can be used, but they are NOT compatible with this function
* pointer.
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-typedef int (*cx_compare_func)(
- const void *left,
- const void *right
-);
+typedef int (*cx_compare_func)(const void *left, const void *right);
/**
* Compares two integers of type int.
@@ -74,10 +68,8 @@ typedef int (*cx_compare_func)(
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_int(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_int(const void *i1, const void *i2);
/**
* Compares two integers of type int.
@@ -89,8 +81,7 @@ int cx_cmp_int(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_int(int i1, int i2);
+CX_EXPORT int cx_vcmp_int(int i1, int i2);
/**
* Compares two integers of type long int.
@@ -104,10 +95,8 @@ int cx_vcmp_int(int i1, int i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_longint(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_longint(const void *i1, const void *i2);
/**
* Compares two integers of type long int.
@@ -119,8 +108,7 @@ int cx_cmp_longint(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_longint(long int i1, long int i2);
+CX_EXPORT int cx_vcmp_longint(long int i1, long int i2);
/**
* Compares two integers of type long long.
@@ -134,10 +122,8 @@ int cx_vcmp_longint(long int i1, long int i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_longlong(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_longlong(const void *i1, const void *i2);
/**
* Compares two integers of type long long.
@@ -149,8 +135,7 @@ int cx_cmp_longlong(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_longlong(long long int i1, long long int i2);
+CX_EXPORT int cx_vcmp_longlong(long long int i1, long long int i2);
/**
* Compares two integers of type int16_t.
@@ -164,10 +149,8 @@ int cx_vcmp_longlong(long long int i1, long long int i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_int16(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_int16(const void *i1, const void *i2);
/**
* Compares two integers of type int16_t.
@@ -179,8 +162,7 @@ int cx_cmp_int16(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_int16(int16_t i1, int16_t i2);
+CX_EXPORT int cx_vcmp_int16(int16_t i1, int16_t i2);
/**
* Compares two integers of type int32_t.
@@ -194,10 +176,8 @@ int cx_vcmp_int16(int16_t i1, int16_t i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_int32(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_int32(const void *i1, const void *i2);
/**
* Compares two integers of type int32_t.
@@ -209,8 +189,7 @@ int cx_cmp_int32(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_int32(int32_t i1, int32_t i2);
+CX_EXPORT int cx_vcmp_int32(int32_t i1, int32_t i2);
/**
* Compares two integers of type int64_t.
@@ -224,10 +203,8 @@ int cx_vcmp_int32(int32_t i1, int32_t i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_int64(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_int64(const void *i1, const void *i2);
/**
* Compares two integers of type int64_t.
@@ -239,8 +216,7 @@ int cx_cmp_int64(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_int64(int64_t i1, int64_t i2);
+CX_EXPORT int cx_vcmp_int64(int64_t i1, int64_t i2);
/**
* Compares two integers of type unsigned int.
@@ -254,10 +230,8 @@ int cx_vcmp_int64(int64_t i1, int64_t i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_uint(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uint(const void *i1, const void *i2);
/**
* Compares two integers of type unsigned int.
@@ -269,8 +243,7 @@ int cx_cmp_uint(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uint(unsigned int i1, unsigned int i2);
+CX_EXPORT int cx_vcmp_uint(unsigned int i1, unsigned int i2);
/**
* Compares two integers of type unsigned long int.
@@ -284,10 +257,8 @@ int cx_vcmp_uint(unsigned int i1, unsigned int i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_ulongint(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_ulongint(const void *i1, const void *i2);
/**
* Compares two integers of type unsigned long int.
@@ -299,8 +270,7 @@ int cx_cmp_ulongint(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_ulongint(unsigned long int i1, unsigned long int i2);
+CX_EXPORT int cx_vcmp_ulongint(unsigned long int i1, unsigned long int i2);
/**
* Compares two integers of type unsigned long long.
@@ -314,10 +284,8 @@ int cx_vcmp_ulongint(unsigned long int i1, unsigned long int i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_ulonglong(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_ulonglong(const void *i1, const void *i2);
/**
* Compares two integers of type unsigned long long.
@@ -329,8 +297,7 @@ int cx_cmp_ulonglong(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_ulonglong(unsigned long long int i1, unsigned long long int i2);
+CX_EXPORT int cx_vcmp_ulonglong(unsigned long long int i1, unsigned long long int i2);
/**
* Compares two integers of type uint16_t.
@@ -344,10 +311,8 @@ int cx_vcmp_ulonglong(unsigned long long int i1, unsigned long long int i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_uint16(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uint16(const void *i1, const void *i2);
/**
* Compares two integers of type uint16_t.
@@ -359,8 +324,7 @@ int cx_cmp_uint16(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uint16(uint16_t i1, uint16_t i2);
+CX_EXPORT int cx_vcmp_uint16(uint16_t i1, uint16_t i2);
/**
* Compares two integers of type uint32_t.
@@ -374,10 +338,8 @@ int cx_vcmp_uint16(uint16_t i1, uint16_t i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_uint32(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uint32(const void *i1, const void *i2);
/**
* Compares two integers of type uint32_t.
@@ -389,8 +351,7 @@ int cx_cmp_uint32(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uint32(uint32_t i1, uint32_t i2);
+CX_EXPORT int cx_vcmp_uint32(uint32_t i1, uint32_t i2);
/**
* Compares two integers of type uint64_t.
@@ -404,10 +365,8 @@ int cx_vcmp_uint32(uint32_t i1, uint32_t i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_uint64(const void *i1, const void *i2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uint64(const void *i1, const void *i2);
/**
* Compares two integers of type uint64_t.
@@ -419,8 +378,34 @@ int cx_cmp_uint64(const void *i1, const void *i2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uint64(uint64_t i1, uint64_t i2);
+CX_EXPORT int cx_vcmp_uint64(uint64_t i1, uint64_t i2);
+
+/**
+ * Compares two integers of type size_t.
+ *
+ * @note the parameters deliberately have type @c void* to be
+ * compatible with #cx_compare_func without the need of a cast.
+ *
+ * @param i1 pointer to size_t one
+ * @param i2 pointer to size_t two
+ * @retval -1 if the left argument is less than the right argument
+ * @retval 0 if both arguments are equal
+ * @retval 1 if the left argument is greater than the right argument
+ */
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_size(const void *i1, const void *i2);
+
+/**
+ * Compares two integers of type size_t.
+ *
+ * @param i1 size_t one
+ * @param i2 size_t two
+ * @retval -1 if the left argument is less than the right argument
+ * @retval 0 if both arguments are equal
+ * @retval 1 if the left argument is greater than the right argument
+ */
+cx_attr_nodiscard
+CX_EXPORT int cx_vcmp_size(size_t i1, size_t i2);
/**
* Compares two real numbers of type float with precision 1e-6f.
@@ -434,10 +419,8 @@ int cx_vcmp_uint64(uint64_t i1, uint64_t i2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_float(const void *f1, const void *f2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_float(const void *f1, const void *f2);
/**
* Compares two real numbers of type float with precision 1e-6f.
@@ -449,8 +432,7 @@ int cx_cmp_float(const void *f1, const void *f2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_float(float f1, float f2);
+CX_EXPORT int cx_vcmp_float(float f1, float f2);
/**
* Compares two real numbers of type double with precision 1e-14.
@@ -464,10 +446,8 @@ int cx_vcmp_float(float f1, float f2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_double(const void *d1, const void *d2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_double(const void *d1, const void *d2);
/**
* Compares two real numbers of type double with precision 1e-14.
@@ -479,8 +459,7 @@ int cx_cmp_double(const void *d1, const void *d2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_double(double d1, double d2);
+CX_EXPORT int cx_vcmp_double(double d1, double d2);
/**
* Compares the integer representation of two pointers.
@@ -494,10 +473,8 @@ int cx_vcmp_double(double d1, double d2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_intptr(const void *ptr1, const void *ptr2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_intptr(const void *ptr1, const void *ptr2);
/**
* Compares the integer representation of two pointers.
@@ -509,8 +486,7 @@ int cx_cmp_intptr(const void *ptr1, const void *ptr2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_intptr(intptr_t ptr1, intptr_t ptr2);
+CX_EXPORT int cx_vcmp_intptr(intptr_t ptr1, intptr_t ptr2);
/**
* Compares the unsigned integer representation of two pointers.
@@ -524,10 +500,8 @@ int cx_vcmp_intptr(intptr_t ptr1, intptr_t ptr2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_uintptr(const void *ptr1, const void *ptr2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_uintptr(const void *ptr1, const void *ptr2);
/**
* Compares the unsigned integer representation of two pointers.
@@ -539,8 +513,7 @@ int cx_cmp_uintptr(const void *ptr1, const void *ptr2);
* @retval 1 if the left argument is greater than the right argument
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_vcmp_uintptr(uintptr_t ptr1, uintptr_t ptr2);
+CX_EXPORT int cx_vcmp_uintptr(uintptr_t ptr1, uintptr_t ptr2);
/**
* Compares the pointers specified in the arguments without dereferencing.
@@ -551,10 +524,8 @@ int cx_vcmp_uintptr(uintptr_t ptr1, uintptr_t ptr2);
* @retval 0 if both arguments are equal
* @retval 1 if the left argument is greater than the right argument
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cx_cmp_ptr(const void *ptr1, const void *ptr2);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cx_cmp_ptr(const void *ptr1, const void *ptr2);
#ifdef __cplusplus
} // extern "C"
diff --git a/ucx/cx/hash_key.h b/ucx/cx/hash_key.h
index cdf8864..c501e9c 100644
--- a/ucx/cx/hash_key.h
+++ b/ucx/cx/hash_key.h
@@ -46,14 +46,17 @@ extern "C" {
/** Internal structure for a key within a hash map. */
struct cx_hash_key_s {
- /** The key data. */
+ /**
+ * The key data.
+ * May be NULL when the hash is collision-free.
+ */
const void *data;
/**
* The key data length.
*/
size_t len;
/** The hash value of the key data. */
- unsigned hash;
+ uint64_t hash;
};
/**
@@ -76,8 +79,45 @@ typedef struct cx_hash_key_s CxHashKey;
* @see cx_hash_key()
*/
cx_attr_nonnull
-cx_attr_export
-void cx_hash_murmur(CxHashKey *key);
+CX_EXPORT void cx_hash_murmur(CxHashKey *key);
+
+/**
+ * Mixes up a 32-bit integer to be used as a hash.
+ *
+ * This function produces no collisions and has a good statistical distribution.
+ *
+ * @param x the integer
+ * @return the hash
+ */
+CX_EXPORT uint32_t cx_hash_u32(uint32_t x);
+
+/**
+ * Mixes up a 64-bit integer to be used as a hash.
+ *
+ * This function produces no collisions and has a good statistical distribution.
+ *
+ * @param x the integer
+ * @return the hash
+ */
+CX_EXPORT uint64_t cx_hash_u64(uint64_t x);
+
+/**
+ * Computes a hash key from a 32-bit integer.
+ *
+ * @param x the integer
+ * @return the hash key
+ */
+cx_attr_nodiscard
+CX_EXPORT CxHashKey cx_hash_key_u32(uint32_t x);
+
+/**
+ * Computes a hash key from a 64-bit integer.
+ *
+ * @param x the integer
+ * @return the hash key
+ */
+cx_attr_nodiscard
+CX_EXPORT CxHashKey cx_hash_key_u64(uint64_t x);
/**
* Computes a hash key from a string.
@@ -87,10 +127,22 @@ void cx_hash_murmur(CxHashKey *key);
* @param str the string
* @return the hash key
*/
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_export
-CxHashKey cx_hash_key_str(const char *str);
+cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT CxHashKey cx_hash_key_str(const char *str);
+
+/**
+ * Computes a hash key from a string.
+ *
+ * Use this function when the string is represented
+ * as an unsigned char array.
+ *
+ * The string needs to be zero-terminated.
+ *
+ * @param str the string
+ * @return the hash key
+ */
+cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT CxHashKey cx_hash_key_ustr(const unsigned char *str);
/**
* Computes a hash key from a byte array.
@@ -99,13 +151,8 @@ CxHashKey cx_hash_key_str(const char *str);
* @param len the length
* @return the hash key
*/
-cx_attr_nodiscard
-cx_attr_access_r(1, 2)
-cx_attr_export
-CxHashKey cx_hash_key_bytes(
- const unsigned char *bytes,
- size_t len
-);
+cx_attr_nodiscard cx_attr_access_r(1, 2)
+CX_EXPORT CxHashKey cx_hash_key_bytes(const unsigned char *bytes, size_t len);
/**
* Computes a hash key for an arbitrary object.
@@ -115,16 +162,12 @@ CxHashKey cx_hash_key_bytes(
* used for data exchange with different machines.
*
* @param obj a pointer to an arbitrary object
- * @param len the length of object in memory
+ * @param len the length of the object in memory
* @return the hash key
*/
cx_attr_nodiscard
cx_attr_access_r(1, 2)
-cx_attr_export
-CxHashKey cx_hash_key(
- const void *obj,
- size_t len
-);
+CX_EXPORT CxHashKey cx_hash_key(const void *obj, size_t len);
/**
* Computes a hash key from a UCX string.
@@ -133,20 +176,98 @@ CxHashKey cx_hash_key(
* @return the hash key
*/
cx_attr_nodiscard
-static inline CxHashKey cx_hash_key_cxstr(cxstring str) {
- return cx_hash_key(str.ptr, str.length);
-}
+CX_EXPORT CxHashKey cx_hash_key_cxstr(cxstring str);
/**
* Computes a hash key from a UCX string.
*
- * @param str (@c cxstring or @c cxmutstr) the string
- * @return (@c CxHashKey) the hash key
+ * @param str the string
+ * @return the hash key
+ */
+cx_attr_nodiscard
+CX_EXPORT CxHashKey cx_hash_key_mutstr(cxmutstr str);
+
+/**
+ * The identity function for the CX_HASH_KEY() macro.
+ * You should never need to use this manually.
+ *
+ * @param key the key
+ * @return a copy of the key
+ */
+cx_attr_nodiscard
+CX_INLINE CxHashKey cx_hash_key_identity(CxHashKey key) {
+ return key;
+}
+
+#ifndef __cplusplus
+/**
+ * Creates a hash key from any of the supported types with implicit length.
+ *
+ * Does nothing when passing a CxHashkey.
+ *
+ * Supported types are UCX strings, zero-terminated C strings,
+ * and 32-bit or 64-bit unsigned integers.
+ *
+ * @param key the key data
+ * @returns the @c CxHashKey
+ */
+#define CX_HASH_KEY(key) _Generic((key), \
+ CxHashKey: cx_hash_key_identity, \
+ cxstring: cx_hash_key_cxstr, \
+ cxmutstr: cx_hash_key_mutstr, \
+ char*: cx_hash_key_str, \
+ const char*: cx_hash_key_str, \
+ unsigned char*: cx_hash_key_ustr, \
+ const unsigned char*: cx_hash_key_ustr, \
+ uint32_t: cx_hash_key_u32, \
+ uint64_t: cx_hash_key_u64) \
+ (key)
+#endif // __cplusplus
+
+/**
+ * Compare function for hash keys.
+ *
+ * @param left the first key
+ * @param right the second key
+ * @return zero when the keys equal, non-zero when they differ
*/
-#define cx_hash_key_cxstr(str) cx_hash_key_cxstr(cx_strcast(str))
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT int cx_hash_key_cmp(const CxHashKey *left, const CxHashKey *right);
#ifdef __cplusplus
} // extern "C"
+
+// ----------------------------------------------------------
+// Overloads of CX_HASH_KEY (the C++ version of a _Generic)
+// ----------------------------------------------------------
+
+CX_CPPDECL CxHashKey CX_HASH_KEY(CxHashKey key) {
+ return key;
+}
+
+CX_CPPDECL CxHashKey CX_HASH_KEY(cxstring str) {
+ return cx_hash_key_cxstr(str);
+}
+
+CX_CPPDECL CxHashKey CX_HASH_KEY(cxmutstr str) {
+ return cx_hash_key_mutstr(str);
+}
+
+CX_CPPDECL CxHashKey CX_HASH_KEY(const char *str) {
+ return cx_hash_key_str(str);
+}
+
+CX_CPPDECL CxHashKey CX_HASH_KEY(const unsigned char *str) {
+ return cx_hash_key_ustr(str);
+}
+
+CX_CPPDECL CxHashKey CX_HASH_KEY(uint32_t key) {
+ return cx_hash_key_u32(key);
+}
+
+CX_CPPDECL CxHashKey CX_HASH_KEY(uint64_t key) {
+ return cx_hash_key_u64(key);
+}
#endif
#endif // UCX_HASH_KEY_H
diff --git a/ucx/cx/hash_map.h b/ucx/cx/hash_map.h
index 6b11e2c..3c9a303 100644
--- a/ucx/cx/hash_map.h
+++ b/ucx/cx/hash_map.h
@@ -73,7 +73,8 @@ struct cx_hash_map_s {
* copies of the added elements.
*
* @note Iterators provided by this hash map implementation provide the remove operation.
- * The index value of an iterator is incremented when the iterator advanced without removal.
+ * The index value of an iterator is incremented when the iterator advanced without
+ * removing an entry.
* In other words, when the iterator is finished, @c index==size .
*
* @param allocator the allocator to use
@@ -82,15 +83,9 @@ struct cx_hash_map_s {
* @param buckets the initial number of buckets in this hash map
* @return a pointer to the new hash map
*/
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc(cxMapFree, 1)
-cx_attr_export
-CxMap *cxHashMapCreate(
- const CxAllocator *allocator,
- size_t itemsize,
- size_t buckets
-);
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMapFree, 1)
+CX_EXPORT CxMap *cxHashMapCreate(const CxAllocator *allocator,
+ size_t itemsize, size_t buckets);
/**
* Creates a new hash map with a default number of buckets.
@@ -99,7 +94,8 @@ CxMap *cxHashMapCreate(
* copies of the added elements.
*
* @note Iterators provided by this hash map implementation provide the remove operation.
- * The index value of an iterator is incremented when the iterator advanced without removal.
+ * The index value of an iterator is incremented when the iterator advanced without
+ * removing an entry.
* In other words, when the iterator is finished, @c index==size .
*
* @param itemsize (@c size_t) the size of one element
@@ -111,10 +107,10 @@ CxMap *cxHashMapCreate(
* Increases the number of buckets, if necessary.
*
* The load threshold is @c 0.75*buckets. If the element count exceeds the load
- * threshold, the map will be rehashed. Otherwise, no action is performed and
+ * threshold, the map will be rehashed. Otherwise, no action is performed, and
* this function simply returns 0.
*
- * The rehashing process ensures, that the number of buckets is at least
+ * The rehashing process ensures that the number of buckets is at least
* 2.5 times the element count. So there is enough room for additional
* elements without the need of another soon rehashing.
*
@@ -127,8 +123,7 @@ CxMap *cxHashMapCreate(
* @retval non-zero if a memory allocation error occurred
*/
cx_attr_nonnull
-cx_attr_export
-int cxMapRehash(CxMap *map);
+CX_EXPORT int cxMapRehash(CxMap *map);
#ifdef __cplusplus
diff --git a/ucx/cx/iterator.h b/ucx/cx/iterator.h
index 204c4df..4fe304a 100644
--- a/ucx/cx/iterator.h
+++ b/ucx/cx/iterator.h
@@ -50,7 +50,10 @@ struct cx_iterator_base_s {
* True if the iterator points to valid data.
*/
bool (*valid)(const void *);
-
+ /**
+ * Original implementation in case the function needs to be wrapped.
+ */
+ bool (*valid_impl)(const void *);
/**
* Returns a pointer to the current element.
*
@@ -62,17 +65,20 @@ struct cx_iterator_base_s {
* Original implementation in case the function needs to be wrapped.
*/
void *(*current_impl)(const void *);
-
/**
* Advances the iterator.
*
* When valid returns false, the behavior of this function is undefined.
*/
void (*next)(void *);
+ /**
+ * Original implementation in case the function needs to be wrapped.
+ */
+ void (*next_impl)(void *);
/**
* Indicates whether this iterator may remove elements.
*/
- bool mutating;
+ bool allow_remove;
/**
* Internal flag for removing the current element when advancing.
*/
@@ -108,16 +114,7 @@ struct cx_iterator_s {
/**
* Handle for the source collection, if any.
*/
- union {
- /**
- * Access for mutating iterators.
- */
- void *m;
- /**
- * Access for normal iterators.
- */
- const void *c;
- } src_handle;
+ void *src_handle;
/**
* If the iterator is position-aware, contains the index of the element in the underlying collection.
@@ -141,11 +138,11 @@ struct cx_iterator_s {
* Iterator type.
*
* An iterator points to a certain element in a (possibly unbounded) chain of elements.
- * Iterators that are based on collections (which have a defined "first" element), are supposed
+ * Iterators that are based on collections (which have a defined "first" element) are supposed
* to be "position-aware", which means that they keep track of the current index within the collection.
*
* @note Objects that are pointed to by an iterator are always mutable through that iterator. However,
- * any concurrent mutation of the collection other than by this iterator makes this iterator invalid,
+ * any concurrent mutation of the collection other than by this iterator makes this iterator obsolete,
* and it must not be used anymore.
*/
typedef struct cx_iterator_s CxIterator;
@@ -178,13 +175,12 @@ typedef struct cx_iterator_s CxIterator;
#define cxIteratorNext(iter) (iter).base.next(&iter)
/**
- * Flags the current element for removal, if this iterator is mutating.
- *
- * Does nothing for non-mutating iterators.
+ * Flags the current element for removal if the iterator allows it.
*
* @param iter the iterator
+ * @return @c true if removal is allowed, @c false otherwise
*/
-#define cxIteratorFlagRemoval(iter) (iter).base.remove |= (iter).base.mutating
+#define cxIteratorFlagRemoval(iter) ((iter).base.remove = (iter).base.allow_remove)
/**
* Obtains a reference to an arbitrary iterator.
@@ -210,7 +206,7 @@ for (type elem; cxIteratorValid(iter) && (elem = (type)cxIteratorCurrent(iter))
/**
* Creates an iterator for the specified plain array.
*
- * The @p array can be @c NULL in which case the iterator will be immediately
+ * The @p array can be @c NULL, in which case the iterator will be immediately
* initialized such that #cxIteratorValid() returns @c false.
*
* This iterator yields the addresses of the array elements.
@@ -218,23 +214,6 @@ for (type elem; cxIteratorValid(iter) && (elem = (type)cxIteratorCurrent(iter))
* use cxIteratorPtr() to create an iterator which directly
* yields the stored pointers.
*
- * @param array a pointer to the array (can be @c NULL)
- * @param elem_size the size of one array element
- * @param elem_count the number of elements in the array
- * @return an iterator for the specified array
- * @see cxIteratorPtr()
- */
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxIterator(
- const void *array,
- size_t elem_size,
- size_t elem_count
-);
-
-/**
- * Creates a mutating iterator for the specified plain array.
- *
* While the iterator is in use, the array may only be altered by removing
* elements through #cxIteratorFlagRemoval(). Every other change to the array
* will bring this iterator to an undefined state.
@@ -244,67 +223,45 @@ CxIterator cxIterator(
* moving all subsequent elements by one. Usually, when the order of elements is
* not important, this parameter should be set to @c false.
*
- * The @p array can be @c NULL in which case the iterator will be immediately
- * initialized such that #cxIteratorValid() returns @c false.
- *
- *
* @param array a pointer to the array (can be @c NULL)
* @param elem_size the size of one array element
* @param elem_count the number of elements in the array
* @param remove_keeps_order @c true if the order of elements must be preserved
* when removing an element
* @return an iterator for the specified array
+ * @see cxIteratorPtr()
*/
cx_attr_nodiscard
-cx_attr_export
-CxIterator cxMutIterator(
- void *array,
- size_t elem_size,
- size_t elem_count,
- bool remove_keeps_order
-);
+CX_EXPORT CxIterator cxIterator(const void *array,
+ size_t elem_size, size_t elem_count, bool remove_keeps_order);
/**
* Creates an iterator for the specified plain pointer array.
*
* This iterator assumes that every element in the array is a pointer
- * and yields exactly those pointers during iteration (while in contrast
- * an iterator created with cxIterator() would return the addresses
- * of those pointers within the array).
+ * and yields exactly those pointers during iteration (on the other
+ * hand, an iterator created with cxIterator() would return the
+ * addresses of those pointers within the array).
*
- * @param array a pointer to the array (can be @c NULL)
- * @param elem_count the number of elements in the array
- * @return an iterator for the specified array
- * @see cxIterator()
- */
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxIteratorPtr(
- const void *array,
- size_t elem_count
-);
-
-/**
- * Creates a mutating iterator for the specified plain pointer array.
+ * While the iterator is in use, the array may only be altered by removing
+ * elements through #cxIteratorFlagRemoval(). Every other change to the array
+ * will bring this iterator to an undefined state.
*
- * This is the mutating variant of cxIteratorPtr(). See also
- * cxMutIterator().
+ * When @p remove_keeps_order is set to @c false, removing an element will only
+ * move the last element to the position of the removed element, instead of
+ * moving all subsequent elements by one. Usually, when the order of elements is
+ * not important, this parameter should be set to @c false.
*
* @param array a pointer to the array (can be @c NULL)
* @param elem_count the number of elements in the array
* @param remove_keeps_order @c true if the order of elements must be preserved
* when removing an element
* @return an iterator for the specified array
- * @see cxMutIterator()
- * @see cxIteratorPtr()
+ * @see cxIterator()
*/
cx_attr_nodiscard
-cx_attr_export
-CxIterator cxMutIteratorPtr(
- void *array,
- size_t elem_count,
- bool remove_keeps_order
-);
+CX_EXPORT CxIterator cxIteratorPtr(const void *array, size_t elem_count,
+ bool remove_keeps_order);
#ifdef __cplusplus
} // extern "C"
diff --git a/ucx/cx/json.h b/ucx/cx/json.h
index ee09ec1..8856ad4 100644
--- a/ucx/cx/json.h
+++ b/ucx/cx/json.h
@@ -90,11 +90,11 @@ enum cx_json_token_type {
*/
CX_JSON_TOKEN_STRING,
/**
- * A number token that can be represented as integer.
+ * A number token that can be represented as an integer.
*/
CX_JSON_TOKEN_INTEGER,
/**
- * A number token that cannot be represented as integer.
+ * A number token that cannot be represented as an integer.
*/
CX_JSON_TOKEN_NUMBER,
/**
@@ -196,11 +196,11 @@ typedef struct cx_json_object_s CxJsonObject;
*/
typedef struct cx_mutstr_s CxJsonString;
/**
- * Type alias for a number that can be represented as 64-bit signed integer.
+ * Type alias for a number that can be represented as a 64-bit signed integer.
*/
typedef int64_t CxJsonInteger;
/**
- * Type alias for number that is not an integer.
+ * Type alias for a number that is not an integer.
*/
typedef double CxJsonNumber;
/**
@@ -272,27 +272,27 @@ struct cx_json_value_s {
*/
union {
/**
- * The array data if type is #CX_JSON_ARRAY.
+ * The array data if the type is #CX_JSON_ARRAY.
*/
CxJsonArray array;
/**
- * The object data if type is #CX_JSON_OBJECT.
+ * The object data if the type is #CX_JSON_OBJECT.
*/
CxJsonObject object;
/**
- * The string data if type is #CX_JSON_STRING.
+ * The string data if the type is #CX_JSON_STRING.
*/
CxJsonString string;
/**
- * The integer if type is #CX_JSON_INTEGER.
+ * The integer if the type is #CX_JSON_INTEGER.
*/
CxJsonInteger integer;
/**
- * The number if type is #CX_JSON_NUMBER.
+ * The number if the type is #CX_JSON_NUMBER.
*/
CxJsonNumber number;
/**
- * The literal type if type is #CX_JSON_LITERAL.
+ * The literal type if the type is #CX_JSON_LITERAL.
*/
CxJsonLiteral literal;
} value;
@@ -377,7 +377,7 @@ struct cx_json_s {
};
/**
- * Status codes for the json interface.
+ * Status codes for the JSON interface.
*/
enum cx_json_status {
/**
@@ -391,7 +391,7 @@ enum cx_json_status {
/**
* The input ends unexpectedly.
*
- * Refill the buffer with cxJsonFill() to complete the json data.
+ * Refill the buffer with cxJsonFill() to complete the JSON data.
*/
CX_JSON_INCOMPLETE_DATA,
/**
@@ -400,7 +400,7 @@ enum cx_json_status {
* You can use this enumerator to check for all "good" status results
* by checking if the status is less than @c CX_JSON_OK.
*
- * A "good" status means, that you can refill data and continue parsing.
+ * A "good" status means that you can refill data and continue parsing.
*/
CX_JSON_OK,
/**
@@ -412,7 +412,7 @@ enum cx_json_status {
*/
CX_JSON_BUFFER_ALLOC_FAILED,
/**
- * Allocating memory for a json value failed.
+ * Allocating memory for a JSON value failed.
*/
CX_JSON_VALUE_ALLOC_FAILED,
/**
@@ -426,7 +426,7 @@ enum cx_json_status {
};
/**
- * Typedef for the json status enum.
+ * Typedef for the JSON status enum.
*/
typedef enum cx_json_status CxJsonStatus;
@@ -445,7 +445,7 @@ struct cx_json_writer_s {
/**
* The maximum number of fractional digits in a number value.
* The default value is 6 and values larger than 15 are reduced to 15.
- * Note, that the actual number of digits may be lower, depending on the concrete number.
+ * Note that the actual number of digits may be lower, depending on the concrete number.
*/
uint8_t frac_max_digits;
/**
@@ -465,7 +465,7 @@ struct cx_json_writer_s {
};
/**
- * Typedef for the json writer.
+ * Typedef for the JSON writer.
*/
typedef struct cx_json_writer_s CxJsonWriter;
@@ -475,8 +475,7 @@ typedef struct cx_json_writer_s CxJsonWriter;
* @return new JSON writer settings
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonWriter cxJsonWriterCompact(void);
+CX_EXPORT CxJsonWriter cxJsonWriterCompact(void);
/**
* Creates a default writer configuration for pretty output.
@@ -485,8 +484,7 @@ CxJsonWriter cxJsonWriterCompact(void);
* @return new JSON writer settings
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonWriter cxJsonWriterPretty(bool use_spaces);
+CX_EXPORT CxJsonWriter cxJsonWriterPretty(bool use_spaces);
/**
* Writes a JSON value to a buffer or stream.
@@ -496,9 +494,8 @@ CxJsonWriter cxJsonWriterPretty(bool use_spaces);
* that the data is only partially written when an error occurs with no
* way to indicate how much data was written.
* To avoid this problem, you can use a CxBuffer as @p target which is
- * unlikely to fail a write operation and either use the buffer's flush
- * feature to relay the data or use the data in the buffer manually to
- * write it to the actual target.
+ * unlikely to fail a write operation. You can, for example, use the buffer's flush
+ * feature to relay the data.
*
* @param target the buffer or stream where to write to
* @param value the value that shall be written
@@ -508,49 +505,38 @@ CxJsonWriter cxJsonWriterPretty(bool use_spaces);
* @retval non-zero when no or not all data could be written
*/
cx_attr_nonnull_arg(1, 2, 3)
-cx_attr_export
-int cxJsonWrite(
- void* target,
- const CxJsonValue* value,
- cx_write_func wfunc,
- const CxJsonWriter* settings
-);
+CX_EXPORT int cxJsonWrite(void* target, const CxJsonValue* value,
+ cx_write_func wfunc, const CxJsonWriter* settings);
/**
- * Initializes the json interface.
+ * Initializes the JSON interface.
*
- * @param json the json interface
+ * @param json the JSON interface
* @param allocator the allocator that shall be used for the produced values
* @see cxJsonDestroy()
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cxJsonInit(CxJson *json, const CxAllocator *allocator);
+CX_EXPORT void cxJsonInit(CxJson *json, const CxAllocator *allocator);
/**
- * Destroys the json interface.
+ * Destroys the JSON interface.
*
- * @param json the json interface
+ * @param json the JSON interface
* @see cxJsonInit()
*/
cx_attr_nonnull
-cx_attr_export
-void cxJsonDestroy(CxJson *json);
+CX_EXPORT void cxJsonDestroy(CxJson *json);
/**
- * Destroys and re-initializes the json interface.
+ * Destroys and re-initializes the JSON interface.
*
- * You might want to use this, to reset the parser after
+ * You might want to use this to reset the parser after
* encountering a syntax error.
*
- * @param json the json interface
+ * @param json the JSON interface
*/
cx_attr_nonnull
-static inline void cxJsonReset(CxJson *json) {
- const CxAllocator *allocator = json->allocator;
- cxJsonDestroy(json);
- cxJsonInit(json, allocator);
-}
+CX_EXPORT void cxJsonReset(CxJson *json);
/**
* Fills the input buffer.
@@ -563,48 +549,30 @@ static inline void cxJsonReset(CxJson *json) {
* the additional data is appended - inevitably leading to
* an allocation of a new buffer and copying the previous contents.
*
- * @param json the json interface
+ * @param json the JSON interface
* @param buf the source buffer
* @param len the length of the source buffer
* @retval zero success
* @retval non-zero internal allocation error
* @see cxJsonFill()
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonFilln(CxJson *json, const char *buf, size_t len);
-
-#ifdef __cplusplus
-} // extern "C"
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxJsonFilln(CxJson *json, const char *buf, size_t len);
-cx_attr_nonnull
-static inline int cxJsonFill(
- CxJson *json,
- cxstring str
-) {
- return cxJsonFilln(json, str.ptr, str.length);
-}
+/**
+ * Internal function, do not use.
+ *
+ * @param json the JSON interface
+ * @param str the string
+ * @retval zero success
+ * @retval non-zero internal allocation error
+ */
cx_attr_nonnull
-static inline int cxJsonFill(
- CxJson *json,
- cxmutstr str
-) {
+CX_INLINE int cx_json_fill(CxJson *json, cxstring str) {
return cxJsonFilln(json, str.ptr, str.length);
}
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-static inline int cxJsonFill(
- CxJson *json,
- const char *str
-) {
- return cxJsonFilln(json, str, strlen(str));
-}
-
-extern "C" {
-#else // __cplusplus
/**
* Fills the input buffer.
*
@@ -616,53 +584,13 @@ extern "C" {
* the additional data is appended - inevitably leading to
* an allocation of a new buffer and copying the previous contents.
*
- * @param json the json interface
+ * @param json the JSON interface
* @param str the source string
* @retval zero success
* @retval non-zero internal allocation error
* @see cxJsonFilln()
*/
-#define cxJsonFill(json, str) _Generic((str), \
- cxstring: cx_json_fill_cxstr, \
- cxmutstr: cx_json_fill_mutstr, \
- char*: cx_json_fill_str, \
- const char*: cx_json_fill_str) \
- (json, str)
-
-/**
- * @copydoc cxJsonFill()
- */
-cx_attr_nonnull
-static inline int cx_json_fill_cxstr(
- CxJson *json,
- cxstring str
-) {
- return cxJsonFilln(json, str.ptr, str.length);
-}
-
-/**
- * @copydoc cxJsonFill()
- */
-cx_attr_nonnull
-static inline int cx_json_fill_mutstr(
- CxJson *json,
- cxmutstr str
-) {
- return cxJsonFilln(json, str.ptr, str.length);
-}
-
-/**
- * @copydoc cxJsonFill()
- */
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-static inline int cx_json_fill_str(
- CxJson *json,
- const char *str
-) {
- return cxJsonFilln(json, str, strlen(str));
-}
-#endif
+#define cxJsonFill(json, str) cx_json_fill(json, cx_strcast(str))
/**
* Creates a new (empty) JSON object.
@@ -673,8 +601,7 @@ static inline int cx_json_fill_str(
* @see cxJsonArrAddValues()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator);
+CX_EXPORT CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator);
/**
* Creates a new (empty) JSON array.
@@ -685,8 +612,7 @@ CxJsonValue* cxJsonCreateObj(const CxAllocator* allocator);
* @see cxJsonArrAddValues()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator);
+CX_EXPORT CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator);
/**
* Creates a new JSON number value.
@@ -698,8 +624,7 @@ CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator);
* @see cxJsonArrAddNumbers()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num);
+CX_EXPORT CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num);
/**
* Creates a new JSON number value based on an integer.
@@ -711,8 +636,7 @@ CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num);
* @see cxJsonArrAddIntegers()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num);
+CX_EXPORT CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num);
/**
* Creates a new JSON string.
@@ -724,11 +648,8 @@ CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num);
* @see cxJsonObjPutString()
* @see cxJsonArrAddStrings()
*/
-cx_attr_nodiscard
-cx_attr_nonnull_arg(2)
-cx_attr_cstr_arg(2)
-cx_attr_export
-CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str);
+cx_attr_nodiscard cx_attr_nonnull_arg(2) cx_attr_cstr_arg(2)
+CX_EXPORT CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str);
/**
* Creates a new JSON string.
@@ -741,8 +662,7 @@ CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char *str);
* @see cxJsonArrAddCxStrings()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str);
+CX_EXPORT CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str);
/**
* Creates a new JSON literal.
@@ -754,8 +674,7 @@ CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str);
* @see cxJsonArrAddLiterals()
*/
cx_attr_nodiscard
-cx_attr_export
-CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit);
+CX_EXPORT CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit);
/**
* Adds number values to a JSON array.
@@ -766,10 +685,8 @@ CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit
* @retval zero success
* @retval non-zero allocation failure
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count);
/**
* Adds number values, of which all are integers, to a JSON array.
@@ -780,10 +697,8 @@ int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count);
* @retval zero success
* @retval non-zero allocation failure
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count);
/**
* Adds strings to a JSON array.
@@ -797,10 +712,8 @@ int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count);
* @retval non-zero allocation failure
* @see cxJsonArrAddCxStrings()
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count);
/**
* Adds strings to a JSON array.
@@ -814,10 +727,8 @@ int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count);
* @retval non-zero allocation failure
* @see cxJsonArrAddStrings()
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count);
/**
* Adds literals to a JSON array.
@@ -828,10 +739,8 @@ int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count);
* @retval zero success
* @retval non-zero allocation failure
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count);
/**
* Add arbitrary values to a JSON array.
@@ -845,10 +754,8 @@ int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t coun
* @retval zero success
* @retval non-zero allocation failure
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count);
/**
* Adds or replaces a value within a JSON object.
@@ -865,8 +772,7 @@ int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count);
* @retval non-zero allocation failure
*/
cx_attr_nonnull
-cx_attr_export
-int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child);
+CX_EXPORT int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child);
/**
* Creates a new JSON object and adds it to an existing object.
@@ -878,8 +784,7 @@ int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child);
* @see cxJsonCreateObj()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name);
+CX_EXPORT CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name);
/**
* Creates a new JSON array and adds it to an object.
@@ -891,8 +796,7 @@ CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name);
* @see cxJsonCreateArr()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name);
+CX_EXPORT CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name);
/**
* Creates a new JSON number and adds it to an object.
@@ -905,8 +809,7 @@ CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name);
* @see cxJsonCreateNumber()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num);
+CX_EXPORT CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num);
/**
* Creates a new JSON number, based on an integer, and adds it to an object.
@@ -919,8 +822,7 @@ CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num);
* @see cxJsonCreateInteger()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num);
+CX_EXPORT CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num);
/**
* Creates a new JSON string and adds it to an object.
@@ -934,10 +836,8 @@ CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num);
* @see cxJsonObjPut()
* @see cxJsonCreateString()
*/
-cx_attr_nonnull
-cx_attr_cstr_arg(3)
-cx_attr_export
-CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str);
+cx_attr_nonnull cx_attr_cstr_arg(3)
+CX_EXPORT CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str);
/**
* Creates a new JSON string and adds it to an object.
@@ -952,8 +852,7 @@ CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str
* @see cxJsonCreateCxString()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str);
+CX_EXPORT CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str);
/**
* Creates a new JSON literal and adds it to an object.
@@ -966,22 +865,20 @@ CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str)
* @see cxJsonCreateLiteral()
*/
cx_attr_nonnull
-cx_attr_export
-CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit);
+CX_EXPORT CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit);
/**
* Recursively deallocates the memory of a JSON value.
*
* @remark The type of each deallocated value will be changed
- * to #CX_JSON_NOTHING and values of such type will be skipped
- * by the de-allocation. That means, this function protects
+ * to #CX_JSON_NOTHING, and values of such a type will be skipped
+ * by the deallocation. That means this function protects
* you from double-frees when you are accidentally freeing
* a nested value and then the parent value (or vice versa).
*
* @param value the value
*/
-cx_attr_export
-void cxJsonValueFree(CxJsonValue *value);
+CX_EXPORT void cxJsonValueFree(CxJsonValue *value);
/**
* Tries to obtain the next JSON value.
@@ -993,7 +890,7 @@ void cxJsonValueFree(CxJsonValue *value);
* add the missing data with another invocation of cxJsonFill()
* and then repeat the call to cxJsonNext().
*
- * @param json the json interface
+ * @param json the JSON interface
* @param value a pointer where the next value shall be stored
* @retval CX_JSON_NO_ERROR successfully retrieve the @p value
* @retval CX_JSON_NO_DATA there is no (more) data in the buffer to read from
@@ -1005,10 +902,8 @@ void cxJsonValueFree(CxJsonValue *value);
* @retval CX_JSON_FORMAT_ERROR_NUMBER the JSON text contains an illegally formatted number
* @retval CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN JSON syntax error
*/
-cx_attr_nonnull
-cx_attr_access_w(2)
-cx_attr_export
-CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value);
+cx_attr_nonnull cx_attr_access_w(2)
+CX_EXPORT CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value);
/**
* Checks if the specified value is a JSON object.
@@ -1018,7 +913,7 @@ CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value);
* @retval false otherwise
*/
cx_attr_nonnull
-static inline bool cxJsonIsObject(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsObject(const CxJsonValue *value) {
return value->type == CX_JSON_OBJECT;
}
@@ -1030,7 +925,7 @@ static inline bool cxJsonIsObject(const CxJsonValue *value) {
* @retval false otherwise
*/
cx_attr_nonnull
-static inline bool cxJsonIsArray(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsArray(const CxJsonValue *value) {
return value->type == CX_JSON_ARRAY;
}
@@ -1042,14 +937,14 @@ static inline bool cxJsonIsArray(const CxJsonValue *value) {
* @retval false otherwise
*/
cx_attr_nonnull
-static inline bool cxJsonIsString(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsString(const CxJsonValue *value) {
return value->type == CX_JSON_STRING;
}
/**
* Checks if the specified value is a JSON number.
*
- * This function will return true for both floating point and
+ * This function will return true for both floating-point and
* integer numbers.
*
* @param value a pointer to the value
@@ -1058,7 +953,7 @@ static inline bool cxJsonIsString(const CxJsonValue *value) {
* @see cxJsonIsInteger()
*/
cx_attr_nonnull
-static inline bool cxJsonIsNumber(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsNumber(const CxJsonValue *value) {
return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER;
}
@@ -1071,7 +966,7 @@ static inline bool cxJsonIsNumber(const CxJsonValue *value) {
* @see cxJsonIsNumber()
*/
cx_attr_nonnull
-static inline bool cxJsonIsInteger(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsInteger(const CxJsonValue *value) {
return value->type == CX_JSON_INTEGER;
}
@@ -1088,7 +983,7 @@ static inline bool cxJsonIsInteger(const CxJsonValue *value) {
* @see cxJsonIsNull()
*/
cx_attr_nonnull
-static inline bool cxJsonIsLiteral(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsLiteral(const CxJsonValue *value) {
return value->type == CX_JSON_LITERAL;
}
@@ -1102,14 +997,14 @@ static inline bool cxJsonIsLiteral(const CxJsonValue *value) {
* @see cxJsonIsFalse()
*/
cx_attr_nonnull
-static inline bool cxJsonIsBool(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsBool(const CxJsonValue *value) {
return cxJsonIsLiteral(value) && value->value.literal != CX_JSON_NULL;
}
/**
* Checks if the specified value is @c true.
*
- * @remark Be advised, that this is not the same as
+ * @remark Be advised that this is different from
* testing @c !cxJsonIsFalse(v).
*
* @param value a pointer to the value
@@ -1119,14 +1014,14 @@ static inline bool cxJsonIsBool(const CxJsonValue *value) {
* @see cxJsonIsFalse()
*/
cx_attr_nonnull
-static inline bool cxJsonIsTrue(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsTrue(const CxJsonValue *value) {
return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_TRUE;
}
/**
* Checks if the specified value is @c false.
*
- * @remark Be advised, that this is not the same as
+ * @remark Be advised that this is different from
* testing @c !cxJsonIsTrue(v).
*
* @param value a pointer to the value
@@ -1136,7 +1031,7 @@ static inline bool cxJsonIsTrue(const CxJsonValue *value) {
* @see cxJsonIsTrue()
*/
cx_attr_nonnull
-static inline bool cxJsonIsFalse(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsFalse(const CxJsonValue *value) {
return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_FALSE;
}
@@ -1149,7 +1044,7 @@ static inline bool cxJsonIsFalse(const CxJsonValue *value) {
* @see cxJsonIsLiteral()
*/
cx_attr_nonnull
-static inline bool cxJsonIsNull(const CxJsonValue *value) {
+CX_INLINE bool cxJsonIsNull(const CxJsonValue *value) {
return cxJsonIsLiteral(value) && value->value.literal == CX_JSON_NULL;
}
@@ -1162,11 +1057,8 @@ static inline bool cxJsonIsNull(const CxJsonValue *value) {
* @return the value represented as C string
* @see cxJsonIsString()
*/
-cx_attr_nonnull
-cx_attr_returns_nonnull
-static inline char *cxJsonAsString(const CxJsonValue *value) {
- return value->value.string.ptr;
-}
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT char *cxJsonAsString(const CxJsonValue *value);
/**
* Obtains a UCX string from the given JSON value.
@@ -1178,9 +1070,7 @@ static inline char *cxJsonAsString(const CxJsonValue *value) {
* @see cxJsonIsString()
*/
cx_attr_nonnull
-static inline cxstring cxJsonAsCxString(const CxJsonValue *value) {
- return cx_strcast(value->value.string);
-}
+CX_EXPORT cxstring cxJsonAsCxString(const CxJsonValue *value);
/**
* Obtains a mutable UCX string from the given JSON value.
@@ -1192,12 +1082,10 @@ static inline cxstring cxJsonAsCxString(const CxJsonValue *value) {
* @see cxJsonIsString()
*/
cx_attr_nonnull
-static inline cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
- return value->value.string;
-}
+CX_EXPORT cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value);
/**
- * Obtains a double-precision floating point value from the given JSON value.
+ * Obtains a double-precision floating-point value from the given JSON value.
*
* If the @p value is not a JSON number, the behavior is undefined.
*
@@ -1206,13 +1094,7 @@ static inline cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
* @see cxJsonIsNumber()
*/
cx_attr_nonnull
-static inline double cxJsonAsDouble(const CxJsonValue *value) {
- if (value->type == CX_JSON_INTEGER) {
- return (double) value->value.integer;
- } else {
- return value->value.number;
- }
-}
+CX_EXPORT double cxJsonAsDouble(const CxJsonValue *value);
/**
* Obtains a 64-bit signed integer from the given JSON value.
@@ -1227,13 +1109,7 @@ static inline double cxJsonAsDouble(const CxJsonValue *value) {
* @see cxJsonIsInteger()
*/
cx_attr_nonnull
-static inline int64_t cxJsonAsInteger(const CxJsonValue *value) {
- if (value->type == CX_JSON_INTEGER) {
- return value->value.integer;
- } else {
- return (int64_t) value->value.number;
- }
-}
+CX_EXPORT int64_t cxJsonAsInteger(const CxJsonValue *value);
/**
* Obtains a Boolean value from the given JSON value.
@@ -1246,7 +1122,7 @@ static inline int64_t cxJsonAsInteger(const CxJsonValue *value) {
* @see cxJsonIsLiteral()
*/
cx_attr_nonnull
-static inline bool cxJsonAsBool(const CxJsonValue *value) {
+CX_INLINE bool cxJsonAsBool(const CxJsonValue *value) {
return value->value.literal == CX_JSON_TRUE;
}
@@ -1260,7 +1136,7 @@ static inline bool cxJsonAsBool(const CxJsonValue *value) {
* @see cxJsonIsArray()
*/
cx_attr_nonnull
-static inline size_t cxJsonArrSize(const CxJsonValue *value) {
+CX_INLINE size_t cxJsonArrSize(const CxJsonValue *value) {
return value->value.array.array_size;
}
@@ -1278,10 +1154,24 @@ static inline size_t cxJsonArrSize(const CxJsonValue *value) {
* @return the value at the specified index
* @see cxJsonIsArray()
*/
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index);
+
+/**
+ * Removes an element from a JSON array.
+ *
+ * If the @p value is not a JSON array, the behavior is undefined.
+ *
+ * This function, in contrast to cxJsonArrayGet(), returns @c NULL
+ * when the index is out of bounds.
+ *
+ * @param value the JSON value
+ * @param index the index in the array
+ * @return the removed value from the specified index or @c NULL when the index was out of bounds
+ * @see cxJsonIsArray()
+ */
cx_attr_nonnull
-cx_attr_returns_nonnull
-cx_attr_export
-CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index);
+CX_EXPORT CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index);
/**
* Returns an iterator over the JSON array elements.
@@ -1294,10 +1184,8 @@ CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index);
* @return an iterator over the array elements
* @see cxJsonIsArray()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxJsonArrIter(const CxJsonValue *value);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxIterator cxJsonArrIter(const CxJsonValue *value);
/**
* Returns an iterator over the JSON object members.
@@ -1311,36 +1199,18 @@ CxIterator cxJsonArrIter(const CxJsonValue *value);
* @return an iterator over the object members
* @see cxJsonIsObject()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxJsonObjIter(const CxJsonValue *value);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxIterator cxJsonObjIter(const CxJsonValue *value);
/**
- * @copydoc cxJsonObjGet()
+ * Internal function, do not use.
+ * @param value the JSON object
+ * @param name the key to look up
+ * @return the value corresponding to the key
*/
-cx_attr_nonnull
-cx_attr_returns_nonnull
-cx_attr_export
-CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name);
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name);
-#ifdef __cplusplus
-} // extern "C"
-
-static inline CxJsonValue *cxJsonObjGet(const CxJsonValue *value, cxstring name) {
- return cx_json_obj_get_cxstr(value, name);
-}
-
-static inline CxJsonValue *cxJsonObjGet(const CxJsonValue *value, cxmutstr name) {
- return cx_json_obj_get_cxstr(value, cx_strcast(name));
-}
-
-static inline CxJsonValue *cxJsonObjGet(const CxJsonValue *value, const char *name) {
- return cx_json_obj_get_cxstr(value, cx_str(name));
-}
-
-extern "C" {
-#else
/**
* Returns a value corresponding to a key in a JSON object.
*
@@ -1355,32 +1225,31 @@ extern "C" {
* @return the value corresponding to the key
* @see cxJsonIsObject()
*/
-#define cxJsonObjGet(value, name) _Generic((name), \
- cxstring: cx_json_obj_get_cxstr, \
- cxmutstr: cx_json_obj_get_mutstr, \
- char*: cx_json_obj_get_str, \
- const char*: cx_json_obj_get_str) \
- (value, name)
+#define cxJsonObjGet(value, name) cx_json_obj_get(value, cx_strcast(name))
/**
- * @copydoc cxJsonObjGet()
+ * Internal function, do not use.
+ * @param value the JSON object
+ * @param name the key to look up
+ * @return the value corresponding to the key or @c NULL when the key is not part of the object
*/
cx_attr_nonnull
-cx_attr_returns_nonnull
-static inline CxJsonValue *cx_json_obj_get_mutstr(const CxJsonValue *value, cxmutstr name) {
- return cx_json_obj_get_cxstr(value, cx_strcast(name));
-}
+CX_EXPORT CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name);
/**
- * @copydoc cxJsonObjGet()
+ * Removes and returns a value corresponding to a key in a JSON object.
+ *
+ * If the @p value is not a JSON object, the behavior is undefined.
+ *
+ * This function, in contrast to cxJsonObjGet() returns @c NULL when the
+ * object does not contain @p name.
+ *
+ * @param value the JSON object
+ * @param name the key to look up
+ * @return the value corresponding to the key or @c NULL when the key is not part of the object
+ * @see cxJsonIsObject()
*/
-cx_attr_nonnull
-cx_attr_returns_nonnull
-cx_attr_cstr_arg(2)
-static inline CxJsonValue *cx_json_obj_get_str(const CxJsonValue *value, const char *name) {
- return cx_json_obj_get_cxstr(value, cx_str(name));
-}
-#endif
+#define cxJsonObjRemove(value, name) cx_json_obj_remove(value, cx_strcast(name))
#ifdef __cplusplus
}
diff --git a/ucx/cx/kv_list.h b/ucx/cx/kv_list.h
new file mode 100644
index 0000000..c66e46c
--- /dev/null
+++ b/ucx/cx/kv_list.h
@@ -0,0 +1,260 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Mike Becker, Olaf Wintermann All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @file kv_list.h
+ * @brief Linked list implementation with key/value-lookup.
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ * @copyright 2-Clause BSD License
+ */
+
+#ifndef UCX_KV_LIST_H
+#define UCX_KV_LIST_H
+
+#include "common.h"
+#include "list.h"
+#include "map.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each.
+ *
+ * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
+ * copies of the added elements, and the compare function will be automatically set
+ * to cx_cmp_ptr() if none is given.
+ *
+ * After creating the list, it can also be used as a map after converting the pointer
+ * to a CxMap pointer with cxKvListAsMap().
+ * When you want to use the list interface again, you can also convert the map pointer back
+ * with cxKvListAsList().
+ *
+ * @param allocator the allocator for allocating the list nodes
+ * (if @c NULL, the cxDefaultAllocator will be used)
+ * @param comparator the comparator for the elements
+ * (if @c NULL, and the list is not storing pointers, sort and find
+ * functions will not work)
+ * @param elem_size the size of each element in bytes
+ * @return the created list
+ * @see cxKvListAsMap()
+ * @see cxKvListAsList()
+ */
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1)
+CX_EXPORT CxList *cxKvListCreate(const CxAllocator *allocator,
+ cx_compare_func comparator, size_t elem_size);
+
+/**
+ * Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each.
+ *
+ * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
+ * copies of the added elements, and the compare function will be automatically set
+ * to cx_cmp_ptr() if none is given.
+ *
+ * This function creates the list with cxKvListCreate() and immediately applies
+ * cxKvListAsMap(). If you want to use the returned object as a list, you can call
+ * cxKvListAsList() later.
+ *
+ * @param allocator the allocator for allocating the list nodes
+ * (if @c NULL, the cxDefaultAllocator will be used)
+ * @param comparator the comparator for the elements
+ * (if @c NULL, and the list is not storing pointers, sort and find
+ * functions will not work)
+ * @param elem_size the size of each element in bytes
+ * @return the created list wrapped into the CxMap interface
+ * @see cxKvListAsMap()
+ * @see cxKvListAsList()
+ */
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMapFree, 1)
+CX_EXPORT CxMap *cxKvListCreateAsMap(const CxAllocator *allocator,
+ cx_compare_func comparator, size_t elem_size);
+
+/**
+ * Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each.
+ *
+ * The list will use cxDefaultAllocator and no comparator function. If you want
+ * to call functions that need a comparator, you must either set one immediately
+ * after list creation or use cxKvListCreate().
+ *
+ * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
+ * copies of the added elements, and the compare function will be automatically set
+ * to cx_cmp_ptr().
+ *
+ * After creating the list, it can also be used as a map after converting the pointer
+ * to a CxMap pointer with cxKvListAsMap().
+ * When you want to use the list interface again, you can also convert the map pointer back
+ * with cxKvListAsList().
+ *
+ * @param elem_size (@c size_t) the size of each element in bytes
+ * @return (@c CxList*) the created list
+ * @see cxKvListAsMap()
+ * @see cxKvListAsList()
+ */
+#define cxKvListCreateSimple(elem_size) cxKvListCreate(NULL, NULL, elem_size)
+
+/**
+ * Allocates a linked list with a lookup-map for storing elements with @p elem_size bytes each.
+ *
+ * The list will use cxDefaultAllocator and no comparator function. If you want
+ * to call functions that need a comparator, you must either set one immediately
+ * after list creation or use cxKvListCreate().
+ *
+ * If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
+ * copies of the added elements, and the compare function will be automatically set
+ * to cx_cmp_ptr().
+ *
+ * This macro behaves as if the list was created with cxKvListCreateSimple() and
+ * immediately followed up by cxKvListAsMap().
+ * If you want to use the returned object as a list, you can call cxKvListAsList() later.
+ *
+ * @param elem_size (@c size_t) the size of each element in bytes
+ * @return (@c CxMap*) the created list wrapped into the CxMap interface
+ * @see cxKvListAsMap()
+ * @see cxKvListAsList()
+ */
+#define cxKvListCreateAsMapSimple(elem_size) cxKvListCreateAsMap(NULL, NULL, elem_size)
+
+/**
+ * Converts a map pointer belonging to a key-value-List back to the original list pointer.
+ *
+ * @param map a map pointer that was returned by a call to cxKvListAsMap()
+ * @return the original list pointer
+ */
+cx_attr_nodiscard cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT CxList *cxKvListAsList(CxMap *map);
+
+/**
+ * Converts a map pointer belonging to a key-value-List back to the original list pointer.
+ *
+ * @param list a list created by cxKvListCreate() or cxKvListCreateSimple()
+ * @return a map pointer that lets you use the list as if it was a map
+ */
+cx_attr_nodiscard cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT CxMap *cxKvListAsMap(CxList *list);
+
+/**
+ * Sets or updates the key of a list item.
+ *
+ * This is, for example, useful when you have inserted an element using the CxList interface,
+ * and now you want to associate this element with a key.
+ *
+ * @param list the list
+ * @param index the index of the element in the list
+ * @param key the key
+ * @retval zero success
+ * @retval non-zero memory allocation failure or the index is out of bounds
+ * @see cxKvListSetKey()
+ */
+cx_attr_nonnull
+CX_EXPORT int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key);
+
+/**
+ * Inserts an item into the list at the specified index and associates it with the specified key.
+ *
+ * @param list the list
+ * @param index the index the inserted element shall have
+ * @param key the key
+ * @param value the value
+ * @retval zero success
+ * @retval non-zero memory allocation failure or the index is out of bounds
+ * @see cxKvListInsert()
+ */
+cx_attr_nonnull
+CX_EXPORT int cx_kv_list_insert(CxList *list, size_t index, CxHashKey key, void *value);
+
+/**
+ * Sets or updates the key of a list item.
+ *
+ * This is, for example, useful when you have inserted an element using the CxList interface,
+ * and now you want to associate this element with a key.
+ *
+ * @param list (@c CxList*) the list
+ * @param index (@c size_t) the index of the element in the list
+ * @param key (any supported key type) the key
+ * @retval zero success
+ * @retval non-zero memory allocation failure or the index is out of bounds
+ * @see CX_HASH_KEY()
+ */
+#define cxKvListSetKey(list, index, key) cx_kv_list_set_key(list, index, CX_HASH_KEY(key))
+
+/**
+ * Inserts an item into the list at the specified index and associates it with the specified key.
+ *
+ * @param list (@c CxList*) the list
+ * @param index (@c size_t) the index the inserted element shall have
+ * @param key (any supported key type) the key
+ * @param value (@c void*) the value
+ * @retval zero success
+ * @retval non-zero memory allocation failure or the index is out of bounds
+ * @see CX_HASH_KEY()
+ */
+#define cxKvListInsert(list, index, key, value) cx_kv_list_insert(list, index, CX_HASH_KEY(key), value)
+
+
+/**
+ * Removes the key of a list item.
+ *
+ * This can be useful if you want to explicitly remove an item from the lookup map.
+ *
+ * If no key is associated with the item, nothing happens, and this function returns zero.
+ *
+ * @param list the list
+ * @param index the index of the element in the list
+ * @retval zero success
+ * @retval non-zero the index is out of bounds
+ */
+cx_attr_nonnull
+CX_EXPORT int cxKvListRemoveKey(CxList *list, size_t index);
+
+/**
+ * Returns the key of a list item.
+ *
+ * @param list the list
+ * @param index the index of the element in the list
+ * @return a pointer to the key or @c NULL when the index is out of bounds or the item does not have a key
+ */
+cx_attr_nonnull
+CX_EXPORT const CxHashKey *cxKvListGetKey(CxList *list, size_t index);
+
+/**
+ * Adds an item into the list and associates it with the specified key.
+ *
+ * @param list (@c CxList*) the list
+ * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key
+ * @param value (@c void*) the value
+ * @retval zero success
+ * @retval non-zero memory allocation failure
+ */
+#define cxKvListAdd(list, key, value) cxKvListInsert(list, (list)->collection.size, key, value)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // UCX_KV_LIST_H
diff --git a/ucx/cx/linked_list.h b/ucx/cx/linked_list.h
index 3da2cae..996dc58 100644
--- a/ucx/cx/linked_list.h
+++ b/ucx/cx/linked_list.h
@@ -43,12 +43,44 @@
extern "C" {
#endif
+/**
+ * Metadata for a linked list.
+ */
+typedef struct cx_linked_list_s {
+ /** Base members. */
+ struct cx_list_s base;
+ /**
+ * Location of the prev pointer (mandatory).
+ */
+ off_t loc_prev;
+ /**
+ * Location of the next pointer (mandatory).
+ */
+ off_t loc_next;
+ /**
+ * Location of the payload (mandatory).
+ */
+ off_t loc_data;
+ /**
+ * Additional bytes to allocate @em behind the payload (e.g. for metadata).
+ */
+ size_t extra_data_len;
+ /**
+ * Pointer to the first node.
+ */
+ void *begin;
+ /**
+ * Pointer to the last node.
+ */
+ void *end;
+} cx_linked_list;
+
/**
* Allocates a linked list for storing elements with @p elem_size bytes each.
*
* If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
- * copies of the added elements and the compare function will be automatically set
- * to cx_cmp_ptr(), if none is given.
+ * copies of the added elements, and the compare function will be automatically set
+ * to cx_cmp_ptr() if none is given.
*
* @param allocator the allocator for allocating the list nodes
* (if @c NULL, the cxDefaultAllocator will be used)
@@ -58,15 +90,9 @@ extern "C" {
* @param elem_size the size of each element in bytes
* @return the created list
*/
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc(cxListFree, 1)
-cx_attr_export
-CxList *cxLinkedListCreate(
- const CxAllocator *allocator,
- cx_compare_func comparator,
- size_t elem_size
-);
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxListFree, 1)
+CX_EXPORT CxList *cxLinkedListCreate(const CxAllocator *allocator,
+ cx_compare_func comparator, size_t elem_size);
/**
* Allocates a linked list for storing elements with @p elem_size bytes each.
@@ -76,25 +102,25 @@ CxList *cxLinkedListCreate(
* after list creation or use cxLinkedListCreate().
*
* If @p elem_size is #CX_STORE_POINTERS, the created list stores pointers instead of
- * copies of the added elements and the compare function will be automatically set
+ * copies of the added elements, and the compare function will be automatically set
* to cx_cmp_ptr().
*
* @param elem_size (@c size_t) the size of each element in bytes
* @return (@c CxList*) the created list
*/
#define cxLinkedListCreateSimple(elem_size) \
- cxLinkedListCreate(NULL, NULL, elem_size)
+ cxLinkedListCreate(NULL, NULL, elem_size)
/**
* Finds the node at a certain index.
*
* This function can be used to start at an arbitrary position within the list.
- * If the search index is large than the start index, @p loc_advance must denote
- * the location of some sort of @c next pointer (i.e. a pointer to the next node).
+ * If the search index is larger than the start index, @p loc_advance must denote
+ * the location of a @c next pointer (i.e., a pointer to the next node).
* But it is also possible that the search index is smaller than the start index
- * (e.g. in cases where traversing a list backwards is faster) in which case
- * @p loc_advance must denote the location of some sort of @c prev pointer
- * (i.e. a pointer to the previous node).
+ * (e.g., in cases where traversing a list backwards is faster).
+ * In that case @p loc_advance must denote the location of a @c prev pointer
+ * (i.e., a pointer to the previous node).
*
* @param start a pointer to the start node
* @param start_index the start index
@@ -102,15 +128,9 @@ CxList *cxLinkedListCreate(
* @param index the search index
* @return the node found at the specified index
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-void *cx_linked_list_at(
- const void *start,
- size_t start_index,
- ptrdiff_t loc_advance,
- size_t index
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT void *cx_linked_list_at(const void *start,size_t start_index,
+ ptrdiff_t loc_advance, size_t index);
/**
* Finds the node containing an element within a linked list.
@@ -122,18 +142,12 @@ void *cx_linked_list_at(
* @param elem a pointer to the element to find
* @param found_index an optional pointer where the index of the found node
* (given that @p start has index 0) is stored
- * @return the index of the element, if found - unspecified if not found
+ * @return a pointer to the found node or @c NULL if no matching node was found
*/
cx_attr_nonnull_arg(1, 4, 5)
-cx_attr_export
-void *cx_linked_list_find(
- const void *start,
- ptrdiff_t loc_advance,
- ptrdiff_t loc_data,
- cx_compare_func cmp_func,
- const void *elem,
- size_t *found_index
-);
+CX_EXPORT void *cx_linked_list_find(const void *start, ptrdiff_t loc_advance,
+ ptrdiff_t loc_data, cx_compare_func cmp_func, const void *elem,
+ size_t *found_index);
/**
* Finds the first node in a linked list.
@@ -146,13 +160,8 @@ void *cx_linked_list_find(
* @param loc_prev the location of the @c prev pointer
* @return a pointer to the first node
*/
-cx_attr_nonnull
-cx_attr_returns_nonnull
-cx_attr_export
-void *cx_linked_list_first(
- const void *node,
- ptrdiff_t loc_prev
-);
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT void *cx_linked_list_first(const void *node, ptrdiff_t loc_prev);
/**
* Finds the last node in a linked list.
@@ -165,13 +174,8 @@ void *cx_linked_list_first(
* @param loc_next the location of the @c next pointer
* @return a pointer to the last node
*/
-cx_attr_nonnull
-cx_attr_returns_nonnull
-cx_attr_export
-void *cx_linked_list_last(
- const void *node,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull cx_attr_returns_nonnull
+CX_EXPORT void *cx_linked_list_last(const void *node, ptrdiff_t loc_next);
/**
* Finds the predecessor of a node in case it is not linked.
@@ -184,16 +188,11 @@ void *cx_linked_list_last(
* @return the node or @c NULL if @p node has no predecessor
*/
cx_attr_nonnull
-cx_attr_export
-void *cx_linked_list_prev(
- const void *begin,
- ptrdiff_t loc_next,
- const void *node
-);
+CX_EXPORT void *cx_linked_list_prev(const void *begin, ptrdiff_t loc_next, const void *node);
/**
* Adds a new node to a linked list.
- * The node must not be part of any list already.
+ * The node must not be part of any list yet.
*
* @remark One of the pointers @p begin or @p end may be @c NULL, but not both.
*
@@ -204,18 +203,11 @@ void *cx_linked_list_prev(
* @param new_node a pointer to the node that shall be appended
*/
cx_attr_nonnull_arg(5)
-cx_attr_export
-void cx_linked_list_add(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *new_node
-);
+CX_EXPORT void cx_linked_list_add(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node);
/**
* Prepends a new node to a linked list.
- * The node must not be part of any list already.
+ * The node must not be part of any list yet.
*
* @remark One of the pointers @p begin or @p end may be @c NULL, but not both.
*
@@ -226,14 +218,7 @@ void cx_linked_list_add(
* @param new_node a pointer to the node that shall be prepended
*/
cx_attr_nonnull_arg(5)
-cx_attr_export
-void cx_linked_list_prepend(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *new_node
-);
+CX_EXPORT void cx_linked_list_prepend(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node);
/**
* Links two nodes.
@@ -244,13 +229,7 @@ void cx_linked_list_prepend(
* @param loc_next the location of a @c next pointer within your node struct (required)
*/
cx_attr_nonnull
-cx_attr_export
-void cx_linked_list_link(
- void *left,
- void *right,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_linked_list_link(void *left, void *right, ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Unlinks two nodes.
@@ -263,17 +242,11 @@ void cx_linked_list_link(
* @param loc_next the location of a @c next pointer within your node struct (required)
*/
cx_attr_nonnull
-cx_attr_export
-void cx_linked_list_unlink(
- void *left,
- void *right,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_linked_list_unlink(void *left, void *right, ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Inserts a new node after a given node of a linked list.
- * The new node must not be part of any list already.
+ * The new node must not be part of any list yet.
*
* @note If you specify @c NULL as the @p node to insert after, this function needs either the @p begin or
* the @p end pointer to determine the start of the list. Then the new node will be prepended to the list.
@@ -286,19 +259,12 @@ void cx_linked_list_unlink(
* @param new_node a pointer to the node that shall be inserted
*/
cx_attr_nonnull_arg(6)
-cx_attr_export
-void cx_linked_list_insert(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *node,
- void *new_node
-);
+CX_EXPORT void cx_linked_list_insert(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node, void *new_node);
/**
* Inserts a chain of nodes after a given node of a linked list.
- * The chain must not be part of any list already.
+ * The chain must not be part of any list yet.
*
* If you do not explicitly specify the end of the chain, it will be determined by traversing
* the @c next pointer.
@@ -317,20 +283,12 @@ void cx_linked_list_insert(
* @param insert_end a pointer to the last node of the chain (or NULL if the last node shall be determined)
*/
cx_attr_nonnull_arg(6)
-cx_attr_export
-void cx_linked_list_insert_chain(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *node,
- void *insert_begin,
- void *insert_end
-);
+CX_EXPORT void cx_linked_list_insert_chain(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node, void *insert_begin, void *insert_end);
/**
* Inserts a node into a sorted linked list.
- * The new node must not be part of any list already.
+ * The new node must not be part of any list yet.
*
* If the list starting with the node pointed to by @p begin is not sorted
* already, the behavior is undefined.
@@ -343,26 +301,19 @@ void cx_linked_list_insert_chain(
* @param cmp_func a compare function that will receive the node pointers
*/
cx_attr_nonnull_arg(1, 5, 6)
-cx_attr_export
-void cx_linked_list_insert_sorted(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *new_node,
- cx_compare_func cmp_func
-);
+CX_EXPORT void cx_linked_list_insert_sorted(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node, cx_compare_func cmp_func);
/**
* Inserts a chain of nodes into a sorted linked list.
- * The chain must not be part of any list already.
+ * The chain must not be part of any list yet.
*
* If either the list starting with the node pointed to by @p begin or the list
* starting with @p insert_begin is not sorted, the behavior is undefined.
*
* @attention In contrast to cx_linked_list_insert_chain(), the source chain
* will be broken and inserted into the target list so that the resulting list
- * will be sorted according to @p cmp_func. That means, each node in the source
+ * will be sorted according to @p cmp_func. That means each node in the source
* chain may be re-linked with nodes from the target list.
*
* @param begin a pointer to the beginning node pointer (required)
@@ -373,20 +324,55 @@ void cx_linked_list_insert_sorted(
* @param cmp_func a compare function that will receive the node pointers
*/
cx_attr_nonnull_arg(1, 5, 6)
-cx_attr_export
-void cx_linked_list_insert_sorted_chain(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *insert_begin,
- cx_compare_func cmp_func
-);
+CX_EXPORT void cx_linked_list_insert_sorted_chain(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *insert_begin, cx_compare_func cmp_func);
+
+/**
+ * Inserts a node into a sorted linked list if no other node with the same value already exists.
+ * The new node must not be part of any list yet.
+ *
+ * If the list starting with the node pointed to by @p begin is not sorted
+ * already, the behavior is undefined.
+ *
+ * @param begin a pointer to the beginning node pointer (required)
+ * @param end a pointer to the end node pointer (if your list has one)
+ * @param loc_prev the location of a @c prev pointer within your node struct (negative if your struct does not have one)
+ * @param loc_next the location of a @c next pointer within your node struct (required)
+ * @param new_node a pointer to the node that shall be inserted
+ * @param cmp_func a compare function that will receive the node pointers
+ * @retval zero when the node was inserted
+ * @retval non-zero when a node with the same value already exists
+ */
+cx_attr_nonnull_arg(1, 5, 6)
+CX_EXPORT int cx_linked_list_insert_unique(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node, cx_compare_func cmp_func);
+
+/**
+ * Inserts a chain of nodes into a sorted linked list, avoiding duplicates.
+ * The chain must not be part of any list yet.
+ *
+ * If either the list starting with the node pointed to by @p begin or the list
+ * starting with @p insert_begin is not sorted, the behavior is undefined.
+ *
+ * @attention In contrast to cx_linked_list_insert_sorted(), not all nodes of the
+ * chain might be added. This function returns a new chain consisting of all the duplicates.
+ *
+ * @param begin a pointer to the beginning node pointer (required)
+ * @param end a pointer to the end node pointer (if your list has one)
+ * @param loc_prev the location of a @c prev pointer within your node struct (negative if your struct does not have one)
+ * @param loc_next the location of a @c next pointer within your node struct (required)
+ * @param insert_begin a pointer to the first node of the chain that shall be inserted
+ * @param cmp_func a compare function that will receive the node pointers
+ * @return a pointer to a new chain with all duplicates that were not inserted (or @c NULL when there were no duplicates)
+ */
+cx_attr_nonnull_arg(1, 5, 6) cx_attr_nodiscard
+CX_EXPORT void *cx_linked_list_insert_unique_chain(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *insert_begin, cx_compare_func cmp_func);
/**
* Removes a chain of nodes from the linked list.
*
- * If one of the nodes to remove is the beginning (resp. end) node of the list and if @p begin (resp. @p end)
+ * If one of the nodes to remove is the beginning (resp. end) node of the list, and if @p begin (resp. @p end)
* addresses are provided, the pointers are adjusted accordingly.
*
* The following combinations of arguments are valid (more arguments are optional):
@@ -405,20 +391,13 @@ void cx_linked_list_insert_sorted_chain(
* @return the actual number of nodes that were removed (can be less when the list did not have enough nodes)
*/
cx_attr_nonnull_arg(5)
-cx_attr_export
-size_t cx_linked_list_remove_chain(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *node,
- size_t num
-);
+CX_EXPORT size_t cx_linked_list_remove_chain(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node, size_t num);
/**
* Removes a node from the linked list.
*
- * If the node to remove is the beginning (resp. end) node of the list and if @p begin (resp. @p end)
+ * If the node to remove is the beginning (resp. end) node of the list, and if @p begin (resp. @p end)
* addresses are provided, the pointers are adjusted accordingly.
*
* The following combinations of arguments are valid (more arguments are optional):
@@ -435,15 +414,8 @@ size_t cx_linked_list_remove_chain(
* @param node the node to remove
*/
cx_attr_nonnull_arg(5)
-static inline void cx_linked_list_remove(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- void *node
-) {
- cx_linked_list_remove_chain(begin, end, loc_prev, loc_next, node, 1);
-}
+CX_EXPORT void cx_linked_list_remove(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, void *node);
/**
* Determines the size of a linked list starting with @p node.
@@ -453,11 +425,7 @@ static inline void cx_linked_list_remove(
* @return the size of the list or zero if @p node is @c NULL
*/
cx_attr_nodiscard
-cx_attr_export
-size_t cx_linked_list_size(
- const void *node,
- ptrdiff_t loc_next
-);
+CX_EXPORT size_t cx_linked_list_size(const void *node, ptrdiff_t loc_next);
/**
* Sorts a linked list based on a comparison function.
@@ -482,21 +450,14 @@ size_t cx_linked_list_size(
* @param cmp_func the compare function defining the sort order
*/
cx_attr_nonnull_arg(1, 6)
-cx_attr_export
-void cx_linked_list_sort(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next,
- ptrdiff_t loc_data,
- cx_compare_func cmp_func
-);
+CX_EXPORT void cx_linked_list_sort(void **begin, void **end,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next, ptrdiff_t loc_data, cx_compare_func cmp_func);
/**
* Compares two lists element wise.
*
- * @attention Both list must have the same structure.
+ * @attention Both lists must have the same structure.
*
* @param begin_left the beginning of the left list (@c NULL denotes an empty list)
* @param begin_right the beginning of the right list (@c NULL denotes an empty list)
@@ -507,14 +468,8 @@ void cx_linked_list_sort(
* right list, positive if the left list is larger than the right list, zero if both lists are equal.
*/
cx_attr_nonnull_arg(5)
-cx_attr_export
-int cx_linked_list_compare(
- const void *begin_left,
- const void *begin_right,
- ptrdiff_t loc_advance,
- ptrdiff_t loc_data,
- cx_compare_func cmp_func
-);
+CX_EXPORT int cx_linked_list_compare(const void *begin_left, const void *begin_right,
+ ptrdiff_t loc_advance, ptrdiff_t loc_data, cx_compare_func cmp_func);
/**
* Reverses the order of the nodes in a linked list.
@@ -525,13 +480,7 @@ int cx_linked_list_compare(
* @param loc_next the location of a @c next pointer within your node struct (required)
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cx_linked_list_reverse(
- void **begin,
- void **end,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_linked_list_reverse(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next);
#ifdef __cplusplus
} // extern "C"
diff --git a/ucx/cx/list.h b/ucx/cx/list.h
index 14ddc04..4722261 100644
--- a/ucx/cx/list.h
+++ b/ucx/cx/list.h
@@ -80,46 +80,41 @@ struct cx_list_class_s {
/**
* Member function for inserting a single element.
- * The data pointer may be @c NULL in which case the function shall only allocate memory.
- * Returns a pointer to the data of the inserted element.
+ * The data pointer may be @c NULL, in which case the function shall only allocate memory.
+ * Returns a pointer to the allocated memory or @c NULL if allocation fails.
*/
- void *(*insert_element)(
- struct cx_list_s *list,
- size_t index,
- const void *data
- );
+ void *(*insert_element)(struct cx_list_s *list, size_t index, const void *data);
/**
* Member function for inserting multiple elements.
*
+ * The data pointer may be @c NULL, in which case the function shall only allocate memory.
+ * Returns the number of successfully inserted or allocated elements.
+ *
* @see cx_list_default_insert_array()
*/
- size_t (*insert_array)(
- struct cx_list_s *list,
- size_t index,
- const void *data,
- size_t n
- );
+ size_t (*insert_array)(struct cx_list_s *list, size_t index, const void *data, size_t n);
/**
* Member function for inserting sorted elements into a sorted list.
+ * Returns the number of successfully inserted elements.
*
* @see cx_list_default_insert_sorted()
*/
- size_t (*insert_sorted)(
- struct cx_list_s *list,
- const void *sorted_data,
- size_t n
- );
+ size_t (*insert_sorted)(struct cx_list_s *list, const void *sorted_data, size_t n);
+
+ /**
+ * Member function for inserting multiple elements if they do not exist.
+ * Implementations shall return the number of successfully processed elements
+ * (including those which were not added because they are already contained).
+ * @see cx_list_default_insert_unique()
+ */
+ size_t (*insert_unique)(struct cx_list_s *list, const void *sorted_data, size_t n);
/**
* Member function for inserting an element relative to an iterator position.
*/
- int (*insert_iter)(
- struct cx_iterator_s *iter,
- const void *elem,
- int prepend
- );
+ int (*insert_iter)(struct cx_iterator_s *iter, const void *elem, int prepend);
/**
* Member function for removing elements.
@@ -131,12 +126,7 @@ struct cx_list_class_s {
* The function SHALL return the actual number of elements removed, which
* might be lower than @p num when going out of bounds.
*/
- size_t (*remove)(
- struct cx_list_s *list,
- size_t index,
- size_t num,
- void *targetbuf
- );
+ size_t (*remove)(struct cx_list_s *list, size_t index, size_t num, void *targetbuf);
/**
* Member function for removing all elements.
@@ -148,28 +138,17 @@ struct cx_list_class_s {
*
* @see cx_list_default_swap()
*/
- int (*swap)(
- struct cx_list_s *list,
- size_t i,
- size_t j
- );
+ int (*swap)(struct cx_list_s *list, size_t i, size_t j);
/**
* Member function for element lookup.
*/
- void *(*at)(
- const struct cx_list_s *list,
- size_t index
- );
+ void *(*at)(const struct cx_list_s *list, size_t index);
/**
* Member function for finding and optionally removing an element.
*/
- size_t (*find_remove)(
- struct cx_list_s *list,
- const void *elem,
- bool remove
- );
+ size_t (*find_remove)(struct cx_list_s *list, const void *elem, bool remove);
/**
* Member function for sorting the list.
@@ -181,13 +160,9 @@ struct cx_list_class_s {
/**
* Optional member function for comparing this list
* to another list of the same type.
- * If set to @c NULL, comparison won't be optimized.
+ * If set to @c NULL, the comparison won't be optimized.
*/
- cx_attr_nonnull
- int (*compare)(
- const struct cx_list_s *list,
- const struct cx_list_s *other
- );
+ int (*compare)(const struct cx_list_s *list, const struct cx_list_s *other);
/**
* Member function for reversing the order of the items.
@@ -197,11 +172,7 @@ struct cx_list_class_s {
/**
* Member function for returning an iterator pointing to the specified index.
*/
- struct cx_iterator_s (*iterator)(
- const struct cx_list_s *list,
- size_t index,
- bool backward
- );
+ struct cx_iterator_s (*iterator)(const struct cx_list_s *list, size_t index, bool backward);
};
/**
@@ -214,11 +185,10 @@ typedef struct cx_list_s CxList;
*
* Writing to that list is not allowed.
*
- * You can use this is a placeholder for initializing CxList pointers
+ * You can use this as a placeholder for initializing CxList pointers
* for which you do not want to reserve memory right from the beginning.
*/
-cx_attr_export
-extern CxList *const cxEmptyList;
+CX_EXPORT extern CxList *const cxEmptyList;
/**
* Default implementation of an array insert.
@@ -235,13 +205,8 @@ extern CxList *const cxEmptyList;
* @return the number of elements actually inserted
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_list_default_insert_array(
- struct cx_list_s *list,
- size_t index,
- const void *data,
- size_t n
-);
+CX_EXPORT size_t cx_list_default_insert_array(struct cx_list_s *list,
+ size_t index, const void *data, size_t n);
/**
* Default implementation of a sorted insert.
@@ -260,12 +225,28 @@ size_t cx_list_default_insert_array(
* @return the number of elements actually inserted
*/
cx_attr_nonnull
-cx_attr_export
-size_t cx_list_default_insert_sorted(
- struct cx_list_s *list,
- const void *sorted_data,
- size_t n
-);
+CX_EXPORT size_t cx_list_default_insert_sorted(struct cx_list_s *list,
+ const void *sorted_data, size_t n);
+
+/**
+ * Default implementation of an array insert where only elements are inserted when they don't exist in the list.
+ *
+ * This function is similar to cx_list_default_insert_sorted(), except it skips elements that are already in the list.
+ *
+ * @note The return value of this function denotes the number of elements from the @p sorted_data that are definitely
+ * contained in the list after completing the call. It is @em not the number of elements that were newly inserted.
+ * That means, when no error occurred, the return value should be @p n.
+ *
+ * Use this in your own list class if you do not want to implement an optimized version for your list.
+ *
+ * @param list the list
+ * @param sorted_data a pointer to the array of pre-sorted data to insert
+ * @param n the number of elements to insert
+ * @return the number of elements from the @p sorted_data that are definitely present in the list after this call
+ */
+cx_attr_nonnull
+CX_EXPORT size_t cx_list_default_insert_unique(struct cx_list_s *list,
+ const void *sorted_data, size_t n);
/**
* Default unoptimized sort implementation.
@@ -279,8 +260,7 @@ size_t cx_list_default_insert_sorted(
* @param list the list that shall be sorted
*/
cx_attr_nonnull
-cx_attr_export
-void cx_list_default_sort(struct cx_list_s *list);
+CX_EXPORT void cx_list_default_sort(struct cx_list_s *list);
/**
* Default unoptimized swap implementation.
@@ -296,20 +276,19 @@ void cx_list_default_sort(struct cx_list_s *list);
* allocation for the temporary buffer fails
*/
cx_attr_nonnull
-cx_attr_export
-int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j);
+CX_EXPORT int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j);
/**
* Initializes a list struct.
*
* Only use this function if you are creating your own list implementation.
* The purpose of this function is to be called in the initialization code
- * of your list, to set certain members correctly.
+ * of your list to set certain members correctly.
*
* This is particularly important when you want your list to support
* #CX_STORE_POINTERS as @p elem_size. This function will wrap the list
* class accordingly and make sure that you can implement your list as if
- * it was only storing objects and the wrapper will automatically enable
+ * it was only storing objects, and the wrapper will automatically enable
* the feature of storing pointers.
*
* @par Example
@@ -344,14 +323,9 @@ int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j);
* @param elem_size the size of one element
*/
cx_attr_nonnull_arg(1, 2, 3)
-cx_attr_export
-void cx_list_init(
- struct cx_list_s *list,
- struct cx_list_class_s *cl,
- const struct cx_allocator_s *allocator,
- cx_compare_func comparator,
- size_t elem_size
-);
+CX_EXPORT void cx_list_init(struct cx_list_s *list,
+ struct cx_list_class_s *cl, const struct cx_allocator_s *allocator,
+ cx_compare_func comparator, size_t elem_size);
/**
* Returns the number of elements currently stored in the list.
@@ -360,9 +334,7 @@ void cx_list_init(
* @return the number of currently stored elements
*/
cx_attr_nonnull
-static inline size_t cxListSize(const CxList *list) {
- return list->collection.size;
-}
+CX_EXPORT size_t cxListSize(const CxList *list);
/**
* Adds an item to the end of the list.
@@ -375,13 +347,7 @@ static inline size_t cxListSize(const CxList *list) {
* @see cxListEmplace()
*/
cx_attr_nonnull
-static inline int cxListAdd(
- CxList *list,
- const void *elem
-) {
- list->collection.sorted = false;
- return list->cl->insert_element(list, list->collection.size, elem) == NULL;
-}
+CX_EXPORT int cxListAdd(CxList *list, const void *elem);
/**
* Adds multiple items to the end of the list.
@@ -391,28 +357,22 @@ static inline int cxListAdd(
* If there is not enough memory to add all elements, the returned value is
* less than @p n.
*
- * If this list is storing pointers instead of objects @p array is expected to
+ * If this list is storing pointers instead of objects, @p array is expected to
* be an array of pointers.
*
* @param list the list
* @param array a pointer to the elements to add
* @param n the number of elements to add
* @return the number of added elements
+ * @see cxListEmplaceArray()
*/
cx_attr_nonnull
-static inline size_t cxListAddArray(
- CxList *list,
- const void *array,
- size_t n
-) {
- list->collection.sorted = false;
- return list->cl->insert_array(list, list->collection.size, array, n);
-}
+CX_EXPORT size_t cxListAddArray(CxList *list, const void *array, size_t n);
/**
* Inserts an item at the specified index.
*
- * If @p index equals the list @c size, this is effectively cxListAdd().
+ * If the @p index equals the list @c size, this is effectively cxListAdd().
*
* @param list the list
* @param index the index the element shall have
@@ -424,14 +384,7 @@ static inline size_t cxListAddArray(
* @see cxListEmplaceAt()
*/
cx_attr_nonnull
-static inline int cxListInsert(
- CxList *list,
- size_t index,
- const void *elem
-) {
- list->collection.sorted = false;
- return list->cl->insert_element(list, index, elem) == NULL;
-}
+CX_EXPORT int cxListInsert(CxList *list, size_t index, const void *elem);
/**
* Allocates memory for an element at the specified index and returns a pointer to that memory.
@@ -442,14 +395,11 @@ static inline int cxListInsert(
* @param index the index where to emplace the element
* @return a pointer to the allocated memory; @c NULL when the operation fails, or the index is out-of-bounds
* @see cxListEmplace()
+ * @see cxListEmplaceArrayAt()
* @see cxListInsert()
*/
cx_attr_nonnull
-static inline void *cxListEmplaceAt(CxList *list, size_t index) {
- list->collection.sorted = false;
- return list->cl->insert_element(list, index, NULL);
-}
-
+CX_EXPORT void *cxListEmplaceAt(CxList *list, size_t index);
/**
* Allocates memory for an element at the end of the list and returns a pointer to that memory.
@@ -462,10 +412,46 @@ static inline void *cxListEmplaceAt(CxList *list, size_t index) {
* @see cxListAdd()
*/
cx_attr_nonnull
-static inline void *cxListEmplace(CxList *list) {
- list->collection.sorted = false;
- return list->cl->insert_element(list, list->collection.size, NULL);
-}
+CX_EXPORT void *cxListEmplace(CxList *list);
+
+/**
+ * Allocates memory for multiple elements and returns an iterator.
+ *
+ * The iterator will only iterate over the successfully allocated elements.
+ * The @c elem_count attribute is set to that number, and the @c index attribute
+ * will range from zero to @c elem_count minus one.
+ *
+ * @remark When the list is storing pointers, the iterator will iterate over
+ * the @c void** elements.
+ *
+ * @param list the list
+ * @param index the index where to insert the new data
+ * @param n the number of elements for which to allocate the memory
+ * @return an iterator, iterating over the new memory
+ * @see cxListEmplaceAt()
+ * @see cxListInsertArray()
+ */
+cx_attr_nonnull
+CX_EXPORT CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n);
+
+/**
+ * Allocates memory for multiple elements and returns an iterator.
+ *
+ * The iterator will only iterate over the successfully allocated elements.
+ * The @c elem_count attribute is set to that number, and the @c index attribute
+ * will range from zero to @c elem_count minus one.
+ *
+ * @remark When the list is storing pointers, the iterator will iterate over
+ * the @c void** elements.
+ *
+ * @param list the list
+ * @param n the number of elements for which to allocate the memory
+ * @return an iterator, iterating over the new memory
+ * @see cxListEmplace()
+ * @see cxListAddArray()
+ */
+cx_attr_nonnull
+CX_EXPORT CxIterator cxListEmplaceArray(CxList *list, size_t n);
/**
* Inserts an item into a sorted list.
@@ -478,18 +464,27 @@ static inline void *cxListEmplace(CxList *list) {
* @retval non-zero memory allocation failure
*/
cx_attr_nonnull
-static inline int cxListInsertSorted(
- CxList *list,
- const void *elem
-) {
- list->collection.sorted = true; // guaranteed by definition
- const void *data = list->collection.store_pointer ? &elem : elem;
- return list->cl->insert_sorted(list, data, 1) == 0;
-}
+CX_EXPORT int cxListInsertSorted(CxList *list, const void *elem);
+
+/**
+ * Inserts an item into a list if it does not exist.
+ *
+ * If the list is not sorted already, this function will check all elements
+ * and append the new element when it was not found.
+ * It is strongly recommended to use this function only on sorted lists, where
+ * the element, if it is not contained, is inserted at the correct position.
+ *
+ * @param list the list
+ * @param elem a pointer to the element to add
+ * @retval zero success (also when the element was already in the list)
+ * @retval non-zero memory allocation failure
+ */
+cx_attr_nonnull
+CX_EXPORT int cxListInsertUnique(CxList *list, const void *elem);
/**
* Inserts multiple items to the list at the specified index.
- * If @p index equals the list size, this is effectively cxListAddArray().
+ * If the @p index equals the list size, this is effectively cxListAddArray().
*
* This method is usually more efficient than invoking cxListInsert()
* multiple times.
@@ -497,7 +492,7 @@ static inline int cxListInsertSorted(
* If there is not enough memory to add all elements, the returned value is
* less than @p n.
*
- * If this list is storing pointers instead of objects @p array is expected to
+ * If this list is storing pointers instead of objects, @p array is expected to
* be an array of pointers.
*
* @param list the list
@@ -505,28 +500,21 @@ static inline int cxListInsertSorted(
* @param array a pointer to the elements to add
* @param n the number of elements to add
* @return the number of added elements
+ * @see cxListEmplaceArrayAt()
*/
cx_attr_nonnull
-static inline size_t cxListInsertArray(
- CxList *list,
- size_t index,
- const void *array,
- size_t n
-) {
- list->collection.sorted = false;
- return list->cl->insert_array(list, index, array, n);
-}
+CX_EXPORT size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n);
/**
* Inserts a sorted array into a sorted list.
*
- * This method is usually more efficient than inserting each element separately,
+ * This method is usually more efficient than inserting each element separately
* because consecutive chunks of sorted data are inserted in one pass.
*
* If there is not enough memory to add all elements, the returned value is
* less than @p n.
*
- * If this list is storing pointers instead of objects @p array is expected to
+ * If this list is storing pointers instead of objects, @p array is expected to
* be an array of pointers.
*
* If the list is not sorted already, the behavior is undefined.
@@ -537,14 +525,42 @@ static inline size_t cxListInsertArray(
* @return the number of added elements
*/
cx_attr_nonnull
-static inline size_t cxListInsertSortedArray(
- CxList *list,
- const void *array,
- size_t n
-) {
- list->collection.sorted = true; // guaranteed by definition
- return list->cl->insert_sorted(list, array, n);
-}
+CX_EXPORT size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n);
+
+/**
+ * Inserts an array into a list, skipping duplicates.
+ *
+ * The @p list does not need to be sorted (in contrast to cxListInsertSortedArray()).
+ * But it is strongly recommended to use this function only on sorted lists,
+ * because otherwise it will fall back to an inefficient algorithm which inserts
+ * all elements one by one.
+ * If the @p list is not sorted, the @p array also does not need to be sorted.
+ * But when the @p list is sorted, the @p array must also be sorted.
+ *
+ * This method is usually more efficient than inserting each element separately
+ * because consecutive chunks of sorted data are inserted in one pass.
+ *
+ * If there is not enough memory to add all elements, the returned value is
+ * less than @p n.
+ *
+ * @note The return value of this function denotes the number of elements
+ * from the @p sorted_data that are definitely contained in the list after
+ * completing the call. It is @em not the number of elements that were newly
+ * inserted. That means, when no error occurred, the return value should
+ * be @p n.
+ *
+ * If this list is storing pointers instead of objects @p array is expected to
+ * be an array of pointers.
+ *
+ * @param list the list
+ * @param array a pointer to the elements to add
+ * @param n the number of elements to add
+ * @return the number of added elements
+ *
+ * @return the number of elements from the @p sorted_data that are definitely present in the list after this call
+ */
+cx_attr_nonnull
+CX_EXPORT size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n);
/**
* Inserts an element after the current location of the specified iterator.
@@ -563,14 +579,7 @@ static inline size_t cxListInsertSortedArray(
* @see cxListInsertBefore()
*/
cx_attr_nonnull
-static inline int cxListInsertAfter(
- CxIterator *iter,
- const void *elem
-) {
- CxList* list = (CxList*)iter->src_handle.m;
- list->collection.sorted = false;
- return list->cl->insert_iter(iter, elem, 0);
-}
+CX_EXPORT int cxListInsertAfter(CxIterator *iter, const void *elem);
/**
* Inserts an element before the current location of the specified iterator.
@@ -589,14 +598,7 @@ static inline int cxListInsertAfter(
* @see cxListInsertAfter()
*/
cx_attr_nonnull
-static inline int cxListInsertBefore(
- CxIterator *iter,
- const void *elem
-) {
- CxList* list = (CxList*)iter->src_handle.m;
- list->collection.sorted = false;
- return list->cl->insert_iter(iter, elem, 1);
-}
+CX_EXPORT int cxListInsertBefore(CxIterator *iter, const void *elem);
/**
* Removes the element at the specified index.
@@ -610,12 +612,7 @@ static inline int cxListInsertBefore(
* @retval non-zero index out of bounds
*/
cx_attr_nonnull
-static inline int cxListRemove(
- CxList *list,
- size_t index
-) {
- return list->cl->remove(list, index, 1, NULL) == 0;
-}
+CX_EXPORT int cxListRemove(CxList *list, size_t index);
/**
* Removes and returns the element at the specified index.
@@ -630,15 +627,8 @@ static inline int cxListRemove(
* @retval zero success
* @retval non-zero index out of bounds
*/
-cx_attr_nonnull
-cx_attr_access_w(3)
-static inline int cxListRemoveAndGet(
- CxList *list,
- size_t index,
- void *targetbuf
-) {
- return list->cl->remove(list, index, 1, targetbuf) == 0;
-}
+cx_attr_nonnull cx_attr_access_w(3)
+CX_EXPORT int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf);
/**
* Removes and returns the first element of the list.
@@ -650,18 +640,12 @@ static inline int cxListRemoveAndGet(
* @param list the list
* @param targetbuf a buffer where to copy the element
* @retval zero success
- * @retval non-zero list is empty
+ * @retval non-zero the list is empty
* @see cxListPopFront()
* @see cxListRemoveAndGetLast()
*/
-cx_attr_nonnull
-cx_attr_access_w(2)
-static inline int cxListRemoveAndGetFirst(
- CxList *list,
- void *targetbuf
-) {
- return list->cl->remove(list, 0, 1, targetbuf) == 0;
-}
+cx_attr_nonnull cx_attr_access_w(2)
+CX_EXPORT int cxListRemoveAndGetFirst(CxList *list, void *targetbuf);
/**
* Removes and returns the first element of the list.
@@ -675,7 +659,7 @@ static inline int cxListRemoveAndGetFirst(
* @param list (@c CxList*) the list
* @param targetbuf (@c void*) a buffer where to copy the element
* @retval zero success
- * @retval non-zero list is empty
+ * @retval non-zero the list is empty
* @see cxListRemoveAndGetFirst()
* @see cxListPop()
*/
@@ -692,17 +676,10 @@ static inline int cxListRemoveAndGetFirst(
* @param list the list
* @param targetbuf a buffer where to copy the element
* @retval zero success
- * @retval non-zero list is empty
+ * @retval non-zero the list is empty
*/
-cx_attr_nonnull
-cx_attr_access_w(2)
-static inline int cxListRemoveAndGetLast(
- CxList *list,
- void *targetbuf
-) {
- // note: index may wrap - member function will catch that
- return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
-}
+cx_attr_nonnull cx_attr_access_w(2)
+CX_EXPORT int cxListRemoveAndGetLast(CxList *list, void *targetbuf);
/**
* Removes and returns the last element of the list.
@@ -716,7 +693,7 @@ static inline int cxListRemoveAndGetLast(
* @param list (@c CxList*) the list
* @param targetbuf (@c void*) a buffer where to copy the element
* @retval zero success
- * @retval non-zero list is empty
+ * @retval non-zero the list is empty
* @see cxListRemoveAndGetLast()
* @see cxListPopFront()
*/
@@ -738,13 +715,7 @@ static inline int cxListRemoveAndGetLast(
* @return the actual number of removed elements
*/
cx_attr_nonnull
-static inline size_t cxListRemoveArray(
- CxList *list,
- size_t index,
- size_t num
-) {
- return list->cl->remove(list, index, num, NULL);
-}
+CX_EXPORT size_t cxListRemoveArray(CxList *list, size_t index, size_t num);
/**
* Removes and returns multiple elements starting at the specified index.
@@ -759,16 +730,8 @@ static inline size_t cxListRemoveArray(
* @param targetbuf a buffer where to copy the elements
* @return the actual number of removed elements
*/
-cx_attr_nonnull
-cx_attr_access_w(4)
-static inline size_t cxListRemoveArrayAndGet(
- CxList *list,
- size_t index,
- size_t num,
- void *targetbuf
-) {
- return list->cl->remove(list, index, num, targetbuf);
-}
+cx_attr_nonnull cx_attr_access_w(4)
+CX_EXPORT size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf);
/**
* Removes all elements from this list.
@@ -779,10 +742,7 @@ static inline size_t cxListRemoveArrayAndGet(
* @param list the list
*/
cx_attr_nonnull
-static inline void cxListClear(CxList *list) {
- list->collection.sorted = true; // empty lists are always sorted
- list->cl->clear(list);
-}
+CX_EXPORT void cxListClear(CxList *list);
/**
* Swaps two items in the list.
@@ -798,14 +758,7 @@ static inline void cxListClear(CxList *list) {
* or the swap needed extra memory, but allocation failed
*/
cx_attr_nonnull
-static inline int cxListSwap(
- CxList *list,
- size_t i,
- size_t j
-) {
- list->collection.sorted = false;
- return list->cl->swap(list, i, j);
-}
+CX_EXPORT int cxListSwap(CxList *list, size_t i, size_t j);
/**
* Returns a pointer to the element at the specified index.
@@ -817,12 +770,7 @@ static inline int cxListSwap(
* @return a pointer to the element or @c NULL if the index is out of bounds
*/
cx_attr_nonnull
-static inline void *cxListAt(
- const CxList *list,
- size_t index
-) {
- return list->cl->at(list, index);
-}
+CX_EXPORT void *cxListAt(const CxList *list, size_t index);
/**
* Returns a pointer to the first element.
@@ -833,9 +781,7 @@ static inline void *cxListAt(
* @return a pointer to the first element or @c NULL if the list is empty
*/
cx_attr_nonnull
-static inline void *cxListFirst(const CxList *list) {
- return list->cl->at(list, 0);
-}
+CX_EXPORT void *cxListFirst(const CxList *list);
/**
* Returns a pointer to the last element.
@@ -846,12 +792,13 @@ static inline void *cxListFirst(const CxList *list) {
* @return a pointer to the last element or @c NULL if the list is empty
*/
cx_attr_nonnull
-static inline void *cxListLast(const CxList *list) {
- return list->cl->at(list, list->collection.size - 1);
-}
+CX_EXPORT void *cxListLast(const CxList *list);
/**
- * Sets the element at the specified index in the list
+ * Sets the element at the specified index in the list.
+ *
+ * This overwrites the element in-place without calling any destructor
+ * on the overwritten element.
*
* @param list the list to set the element in
* @param index the index to set the element at
@@ -860,91 +807,35 @@ static inline void *cxListLast(const CxList *list) {
* @retval non-zero when index is out of bounds
*/
cx_attr_nonnull
-cx_attr_export
-int cxListSet(
- CxList *list,
- size_t index,
- const void *elem
-);
+CX_EXPORT int cxListSet(CxList *list, size_t index, const void *elem);
/**
* Returns an iterator pointing to the item at the specified index.
*
* The returned iterator is position-aware.
*
- * If the index is out of range, a past-the-end iterator will be returned.
+ * If the index is out of range or @p list is @c NULL, a past-the-end iterator will be returned.
*
* @param list the list
* @param index the index where the iterator shall point at
* @return a new iterator
*/
-cx_attr_nonnull
cx_attr_nodiscard
-static inline CxIterator cxListIteratorAt(
- const CxList *list,
- size_t index
-) {
- return list->cl->iterator(list, index, false);
-}
+CX_EXPORT CxIterator cxListIteratorAt(const CxList *list, size_t index);
/**
* Returns a backwards iterator pointing to the item at the specified index.
*
* The returned iterator is position-aware.
*
- * If the index is out of range, a past-the-end iterator will be returned.
- *
- * @param list the list
- * @param index the index where the iterator shall point at
- * @return a new iterator
- */
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline CxIterator cxListBackwardsIteratorAt(
- const CxList *list,
- size_t index
-) {
- return list->cl->iterator(list, index, true);
-}
-
-/**
- * Returns a mutating iterator pointing to the item at the specified index.
- *
- * The returned iterator is position-aware.
- *
- * If the index is out of range, a past-the-end iterator will be returned.
- *
- * @param list the list
- * @param index the index where the iterator shall point at
- * @return a new iterator
- */
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxIterator cxListMutIteratorAt(
- CxList *list,
- size_t index
-);
-
-/**
- * Returns a mutating backwards iterator pointing to the item at the
- * specified index.
- *
- * The returned iterator is position-aware.
- *
- * If the index is out of range, a past-the-end iterator will be returned.
+ * If the index is out of range or @p list is @c NULL, a past-the-end iterator will be returned.
*
* @param list the list
* @param index the index where the iterator shall point at
* @return a new iterator
*/
-cx_attr_nonnull
cx_attr_nodiscard
-cx_attr_export
-CxIterator cxListMutBackwardsIteratorAt(
- CxList *list,
- size_t index
-);
+CX_EXPORT CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index);
/**
* Returns an iterator pointing to the first item of the list.
@@ -957,27 +848,7 @@ CxIterator cxListMutBackwardsIteratorAt(
* @return a new iterator
*/
cx_attr_nodiscard
-static inline CxIterator cxListIterator(const CxList *list) {
- if (list == NULL) list = cxEmptyList;
- return list->cl->iterator(list, 0, false);
-}
-
-/**
- * Returns a mutating iterator pointing to the first item of the list.
- *
- * The returned iterator is position-aware.
- *
- * If the list is empty or @c NULL, a past-the-end iterator will be returned.
- *
- * @param list the list
- * @return a new iterator
- */
-cx_attr_nodiscard
-static inline CxIterator cxListMutIterator(CxList *list) {
- if (list == NULL) list = cxEmptyList;
- return cxListMutIteratorAt(list, 0);
-}
-
+CX_EXPORT CxIterator cxListIterator(const CxList *list);
/**
* Returns a backwards iterator pointing to the last item of the list.
@@ -990,26 +861,7 @@ static inline CxIterator cxListMutIterator(CxList *list) {
* @return a new iterator
*/
cx_attr_nodiscard
-static inline CxIterator cxListBackwardsIterator(const CxList *list) {
- if (list == NULL) list = cxEmptyList;
- return list->cl->iterator(list, list->collection.size - 1, true);
-}
-
-/**
- * Returns a mutating backwards iterator pointing to the last item of the list.
- *
- * The returned iterator is position-aware.
- *
- * If the list is empty or @c NULL, a past-the-end iterator will be returned.
- *
- * @param list the list
- * @return a new iterator
- */
-cx_attr_nodiscard
-static inline CxIterator cxListMutBackwardsIterator(CxList *list) {
- if (list == NULL) list = cxEmptyList;
- return cxListMutBackwardsIteratorAt(list, list->collection.size - 1);
-}
+CX_EXPORT CxIterator cxListBackwardsIterator(const CxList *list);
/**
* Returns the index of the first element that equals @p elem.
@@ -1022,17 +874,11 @@ static inline CxIterator cxListMutBackwardsIterator(CxList *list) {
* @see cxListIndexValid()
* @see cxListContains()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline size_t cxListFind(
- const CxList *list,
- const void *elem
-) {
- return list->cl->find_remove((CxList*)list, elem, false);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT size_t cxListFind(const CxList *list, const void *elem);
/**
- * Checks, if the list contains the specified element.
+ * Checks if the list contains the specified element.
*
* The elements are compared with the list's comparator function.
*
@@ -1042,14 +888,8 @@ static inline size_t cxListFind(
* @retval false if the element is not contained
* @see cxListFind()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline bool cxListContains(
- const CxList* list,
- const void* elem
-) {
- return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size;
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT bool cxListContains(const CxList* list, const void* elem);
/**
* Checks if the specified index is within bounds.
@@ -1059,11 +899,8 @@ static inline bool cxListContains(
* @retval true if the index is within bounds
* @retval false if the index is out of bounds
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline bool cxListIndexValid(const CxList *list, size_t index) {
- return index < list->collection.size;
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT bool cxListIndexValid(const CxList *list, size_t index);
/**
* Removes and returns the index of the first element that equals @p elem.
@@ -1077,12 +914,7 @@ static inline bool cxListIndexValid(const CxList *list, size_t index) {
* @see cxListIndexValid()
*/
cx_attr_nonnull
-static inline size_t cxListFindRemove(
- CxList *list,
- const void *elem
-) {
- return list->cl->find_remove(list, elem, true);
-}
+CX_EXPORT size_t cxListFindRemove(CxList *list, const void *elem);
/**
* Sorts the list.
@@ -1092,11 +924,7 @@ static inline size_t cxListFindRemove(
* @param list the list
*/
cx_attr_nonnull
-static inline void cxListSort(CxList *list) {
- if (list->collection.sorted) return;
- list->cl->sort(list);
- list->collection.sorted = true;
-}
+CX_EXPORT void cxListSort(CxList *list);
/**
* Reverses the order of the items.
@@ -1104,11 +932,7 @@ static inline void cxListSort(CxList *list) {
* @param list the list
*/
cx_attr_nonnull
-static inline void cxListReverse(CxList *list) {
- // still sorted, but not according to the cmp_func
- list->collection.sorted = false;
- list->cl->reverse(list);
-}
+CX_EXPORT void cxListReverse(CxList *list);
/**
* Compares a list to another list of the same type.
@@ -1119,28 +943,22 @@ static inline void cxListReverse(CxList *list) {
* @param list the list
* @param other the list to compare to
* @retval zero both lists are equal element wise
- * @retval negative the first list is smaller
+ * @retval negative the first list is smaller,
* or the first non-equal element in the first list is smaller
* @retval positive the first list is larger
* or the first non-equal element in the first list is larger
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-int cxListCompare(
- const CxList *list,
- const CxList *other
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT int cxListCompare(const CxList *list, const CxList *other);
/**
* Deallocates the memory of the specified list structure.
*
* Also calls the content destructor functions for each element, if specified.
*
- * @param list the list which shall be freed
+ * @param list the list that shall be freed
*/
-cx_attr_export
-void cxListFree(CxList *list);
+CX_EXPORT void cxListFree(CxList *list);
#ifdef __cplusplus
diff --git a/ucx/cx/map.h b/ucx/cx/map.h
index 36067d5..0b3060d 100644
--- a/ucx/cx/map.h
+++ b/ucx/cx/map.h
@@ -111,16 +111,7 @@ struct cx_map_iterator_s {
/**
* Handle for the source map.
*/
- union {
- /**
- * Access for mutating iterators.
- */
- CxMap *m;
- /**
- * Access for normal iterators.
- */
- const CxMap *c;
- } map;
+ CxMap *map;
/**
* Handle for the current element.
@@ -185,20 +176,16 @@ struct cx_map_class_s {
/**
* Add or overwrite an element.
+ * If the @p value is @c NULL, the implementation
+ * shall only allocate memory instead of adding an existing value to the map.
+ * Returns a pointer to the allocated memory or @c NULL if allocation fails.
*/
- int (*put)(
- CxMap *map,
- CxHashKey key,
- void *value
- );
+ void *(*put)(CxMap *map, CxHashKey key, void *value);
/**
* Returns an element.
*/
- void *(*get)(
- const CxMap *map,
- CxHashKey key
- );
+ void *(*get)(const CxMap *map, CxHashKey key);
/**
* Removes an element.
@@ -210,11 +197,7 @@ struct cx_map_class_s {
* The function SHALL return zero when the @p key was found and
* non-zero, otherwise.
*/
- int (*remove)(
- CxMap *map,
- CxHashKey key,
- void *targetbuf
- );
+ int (*remove)(CxMap *map, CxHashKey key, void *targetbuf);
/**
* Creates an iterator for this map.
@@ -227,11 +210,10 @@ struct cx_map_class_s {
*
* Writing to that map is not allowed.
*
- * You can use this is a placeholder for initializing CxMap pointers
+ * You can use this as a placeholder for initializing CxMap pointers
* for which you do not want to reserve memory right from the beginning.
*/
-cx_attr_export
-extern CxMap *const cxEmptyMap;
+CX_EXPORT extern CxMap *const cxEmptyMap;
/**
* Deallocates the memory of the specified map.
@@ -240,8 +222,7 @@ extern CxMap *const cxEmptyMap;
*
* @param map the map to be freed
*/
-cx_attr_export
-void cxMapFree(CxMap *map);
+CX_EXPORT void cxMapFree(CxMap *map);
/**
@@ -252,9 +233,7 @@ void cxMapFree(CxMap *map);
* @param map the map to be cleared
*/
cx_attr_nonnull
-static inline void cxMapClear(CxMap *map) {
- map->cl->clear(map);
-}
+CX_EXPORT void cxMapClear(CxMap *map);
/**
* Returns the number of elements in this map.
@@ -263,9 +242,7 @@ static inline void cxMapClear(CxMap *map) {
* @return the number of stored elements
*/
cx_attr_nonnull
-static inline size_t cxMapSize(const CxMap *map) {
- return map->collection.size;
-}
+CX_EXPORT size_t cxMapSize(const CxMap *map);
/**
* Creates a value iterator for a map.
@@ -277,308 +254,66 @@ static inline size_t cxMapSize(const CxMap *map) {
* @note An iterator iterates over all elements successively. Therefore, the order
* highly depends on the map implementation and may change arbitrarily when the contents change.
*
- * @param map the map to create the iterator for
+ * @param map the map to create the iterator for (can be @c NULL)
* @return an iterator for the currently stored values
*/
-cx_attr_nonnull
cx_attr_nodiscard
-static inline CxMapIterator cxMapIteratorValues(const CxMap *map) {
- return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);
-}
+CX_EXPORT CxMapIterator cxMapIteratorValues(const CxMap *map);
/**
* Creates a key iterator for a map.
*
- * The elements of the iterator are keys of type CxHashKey and the pointer returned
+ * The elements of the iterator are keys of type CxHashKey, and the pointer returned
* during iterator shall be treated as @c const @c CxHashKey* .
*
* @note An iterator iterates over all elements successively. Therefore, the order
* highly depends on the map implementation and may change arbitrarily when the contents change.
*
- * @param map the map to create the iterator for
+ * @param map the map to create the iterator for (can be @c NULL)
* @return an iterator for the currently stored keys
*/
-cx_attr_nonnull
cx_attr_nodiscard
-static inline CxMapIterator cxMapIteratorKeys(const CxMap *map) {
- return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);
-}
+CX_EXPORT CxMapIterator cxMapIteratorKeys(const CxMap *map);
/**
* Creates an iterator for a map.
*
- * The elements of the iterator are key/value pairs of type CxMapEntry and the pointer returned
+ * The elements of the iterator are key/value pairs of type CxMapEntry, and the pointer returned
* during iterator shall be treated as @c const @c CxMapEntry* .
*
* @note An iterator iterates over all elements successively. Therefore, the order
* highly depends on the map implementation and may change arbitrarily when the contents change.
*
- * @param map the map to create the iterator for
+ * @param map the map to create the iterator for (can be @c NULL)
* @return an iterator for the currently stored entries
* @see cxMapIteratorKeys()
* @see cxMapIteratorValues()
*/
-cx_attr_nonnull
cx_attr_nodiscard
-static inline CxMapIterator cxMapIterator(const CxMap *map) {
- return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);
-}
-
+CX_EXPORT CxMapIterator cxMapIterator(const CxMap *map);
/**
- * Creates a mutating iterator over the values of a map.
- *
- * When the map is storing pointers, those pointers are returned.
- * Otherwise, the iterator iterates over pointers to the memory within the map where the
- * respective elements are stored.
- *
- * @note An iterator iterates over all elements successively. Therefore, the order
- * highly depends on the map implementation and may change arbitrarily when the contents change.
- *
- * @param map the map to create the iterator for
- * @return an iterator for the currently stored values
- */
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxMapIterator cxMapMutIteratorValues(CxMap *map);
-
-/**
- * Creates a mutating iterator over the keys of a map.
- *
- * The elements of the iterator are keys of type CxHashKey and the pointer returned
- * during iterator shall be treated as @c const @c CxHashKey* .
- *
- * @note An iterator iterates over all elements successively. Therefore, the order
- * highly depends on the map implementation and may change arbitrarily when the contents change.
+ * Puts a key/value-pair into the map.
*
- * @param map the map to create the iterator for
- * @return an iterator for the currently stored keys
- */
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxMapIterator cxMapMutIteratorKeys(CxMap *map);
-
-/**
- * Creates a mutating iterator for a map.
+ * A possible existing value will be overwritten.
+ * If destructor functions are specified, they are called for
+ * the overwritten element.
*
- * The elements of the iterator are key/value pairs of type CxMapEntry and the pointer returned
- * during iterator shall be treated as @c const @c CxMapEntry* .
+ * If this map is storing pointers, the @p value pointer is written
+ * to the map. Otherwise, the memory is copied from @p value with
+ * memcpy().
*
- * @note An iterator iterates over all elements successively. Therefore, the order
- * highly depends on the map implementation and may change arbitrarily when the contents change.
+ * The @p key is always copied.
*
- * @param map the map to create the iterator for
- * @return an iterator for the currently stored entries
- * @see cxMapMutIteratorKeys()
- * @see cxMapMutIteratorValues()
- */
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxMapIterator cxMapMutIterator(CxMap *map);
-
-#ifdef __cplusplus
-} // end the extern "C" block here, because we want to start overloading
-cx_attr_nonnull
-static inline int cxMapPut(
- CxMap *map,
- CxHashKey const &key,
- void *value
-) {
- return map->cl->put(map, key, value);
-}
-
-cx_attr_nonnull
-static inline int cxMapPut(
- CxMap *map,
- cxstring const &key,
- void *value
-) {
- return map->cl->put(map, cx_hash_key_cxstr(key), value);
-}
-
-cx_attr_nonnull
-static inline int cxMapPut(
- CxMap *map,
- cxmutstr const &key,
- void *value
-) {
- return map->cl->put(map, cx_hash_key_cxstr(key), value);
-}
-
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-static inline int cxMapPut(
- CxMap *map,
- const char *key,
- void *value
-) {
- return map->cl->put(map, cx_hash_key_str(key), value);
-}
-
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cxMapGet(
- const CxMap *map,
- CxHashKey const &key
-) {
- return map->cl->get(map, key);
-}
-
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cxMapGet(
- const CxMap *map,
- cxstring const &key
-) {
- return map->cl->get(map, cx_hash_key_cxstr(key));
-}
-
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cxMapGet(
- const CxMap *map,
- cxmutstr const &key
-) {
- return map->cl->get(map, cx_hash_key_cxstr(key));
-}
-
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_cstr_arg(2)
-static inline void *cxMapGet(
- const CxMap *map,
- const char *key
-) {
- return map->cl->get(map, cx_hash_key_str(key));
-}
-
-cx_attr_nonnull
-static inline int cxMapRemove(
- CxMap *map,
- CxHashKey const &key
-) {
- return map->cl->remove(map, key, nullptr);
-}
-
-cx_attr_nonnull
-static inline int cxMapRemove(
- CxMap *map,
- cxstring const &key
-) {
- return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr);
-}
-
-cx_attr_nonnull
-static inline int cxMapRemove(
- CxMap *map,
- cxmutstr const &key
-) {
- return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr);
-}
-
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-static inline int cxMapRemove(
- CxMap *map,
- const char *key
-) {
- return map->cl->remove(map, cx_hash_key_str(key), nullptr);
-}
-
-cx_attr_nonnull
-cx_attr_access_w(3)
-static inline int cxMapRemoveAndGet(
- CxMap *map,
- CxHashKey key,
- void *targetbuf
-) {
- return map->cl->remove(map, key, targetbuf);
-}
-
-cx_attr_nonnull
-cx_attr_access_w(3)
-static inline int cxMapRemoveAndGet(
- CxMap *map,
- cxstring key,
- void *targetbuf
-) {
- return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
-}
-
-cx_attr_nonnull
-cx_attr_access_w(3)
-static inline int cxMapRemoveAndGet(
- CxMap *map,
- cxmutstr key,
- void *targetbuf
-) {
- return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
-}
-
-cx_attr_nonnull
-cx_attr_access_w(3)
-cx_attr_cstr_arg(2)
-static inline int cxMapRemoveAndGet(
- CxMap *map,
- const char *key,
- void *targetbuf
-) {
- return map->cl->remove(map, cx_hash_key_str(key), targetbuf);
-}
-
-#else // __cplusplus
-
-/**
- * @copydoc cxMapPut()
- */
-cx_attr_nonnull
-static inline int cx_map_put(
- CxMap *map,
- CxHashKey key,
- void *value
-) {
- return map->cl->put(map, key, value);
-}
-
-/**
- * @copydoc cxMapPut()
- */
-cx_attr_nonnull
-static inline int cx_map_put_cxstr(
- CxMap *map,
- cxstring key,
- void *value
-) {
- return map->cl->put(map, cx_hash_key_cxstr(key), value);
-}
-
-/**
- * @copydoc cxMapPut()
- */
-cx_attr_nonnull
-static inline int cx_map_put_mustr(
- CxMap *map,
- cxmutstr key,
- void *value
-) {
- return map->cl->put(map, cx_hash_key_cxstr(key), value);
-}
-
-/**
- * @copydoc cxMapPut()
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @retval zero success
+ * @retval non-zero value on memory allocation failure
+ * @see cxMapPut()
*/
cx_attr_nonnull
-cx_attr_cstr_arg(2)
-static inline int cx_map_put_str(
- CxMap *map,
- const char *key,
- void *value
-) {
- return map->cl->put(map, cx_hash_key_str(key), value);
-}
+CX_EXPORT int cx_map_put(CxMap *map, CxHashKey key, void *value);
/**
* Puts a key/value-pair into the map.
@@ -594,67 +329,71 @@ static inline int cx_map_put_str(
* The @p key is always copied.
*
* @param map (@c CxMap*) the map
- * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key
+ * @param key (any supported key type) the key
* @param value (@c void*) the value
* @retval zero success
* @retval non-zero value on memory allocation failure
+ * @see CX_HASH_KEY()
*/
-#define cxMapPut(map, key, value) _Generic((key), \
- CxHashKey: cx_map_put, \
- cxstring: cx_map_put_cxstr, \
- cxmutstr: cx_map_put_mustr, \
- char*: cx_map_put_str, \
- const char*: cx_map_put_str) \
- (map, key, value)
-
-/**
- * @copydoc cxMapGet()
- */
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cx_map_get(
- const CxMap *map,
- CxHashKey key
-) {
- return map->cl->get(map, key);
-}
+#define cxMapPut(map, key, value) cx_map_put(map, CX_HASH_KEY(key), value)
/**
- * @copydoc cxMapGet()
+ * Allocates memory for a value in the map associated with the specified key.
+ *
+ * A possible existing value will be overwritten.
+ * If destructor functions are specified, they are called for
+ * the overwritten element.
+ *
+ * If the map is storing pointers, this function returns a @c void** pointer,
+ * meaning a pointer to that pointer.
+ *
+ * The @p key is always copied.
+ *
+ * @param map the map
+ * @param key the key
+ * @return the pointer to the allocated memory or @c NULL if allocation fails
+ * @retval zero success
+ * @retval non-zero value on memory allocation failure
+ * @see cxMapEmplace()
*/
cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cx_map_get_cxstr(
- const CxMap *map,
- cxstring key
-) {
- return map->cl->get(map, cx_hash_key_cxstr(key));
-}
+CX_EXPORT void *cx_map_emplace(CxMap *map, CxHashKey key);
/**
- * @copydoc cxMapGet()
+ * Allocates memory for a value in the map associated with the specified key.
+ *
+ * A possible existing value will be overwritten.
+ * If destructor functions are specified, they are called for
+ * the overwritten element.
+ *
+ * If the map is storing pointers, this function returns a @c void** pointer,
+ * meaning a pointer to that pointer.
+ *
+ * The @p key is always copied.
+ *
+ * @param map (@c CxMap*) the map
+ * @param key (any supported key type) the key
+ * @return the pointer to the allocated memory or @c NULL if allocation fails
+ * @retval zero success
+ * @retval non-zero value on memory allocation failure
+ * @see CX_HASH_KEY()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cx_map_get_mustr(
- const CxMap *map,
- cxmutstr key
-) {
- return map->cl->get(map, cx_hash_key_cxstr(key));
-}
+#define cxMapEmplace(map, key) cx_map_emplace(map, CX_HASH_KEY(key))
/**
- * @copydoc cxMapGet()
+ * Retrieves a value by using a key.
+ *
+ * If this map is storing pointers, the stored pointer is returned.
+ * Otherwise, a pointer to the element within the map's memory
+ * is returned (which is valid as long as the element stays in the map).
+ *
+ * @param map the map
+ * @param key the key
+ * @return the value
+ * @see cxMapGet()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_cstr_arg(2)
-static inline void *cx_map_get_str(
- const CxMap *map,
- const char *key
-) {
- return map->cl->get(map, cx_hash_key_str(key));
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT void *cx_map_get(const CxMap *map, CxHashKey key);
/**
* Retrieves a value by using a key.
@@ -664,134 +403,44 @@ static inline void *cx_map_get_str(
* is returned (which is valid as long as the element stays in the map).
*
* @param map (@c CxMap*) the map
- * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key
+ * @param key (any supported key type) the key
* @return (@c void*) the value
+ * @see CX_HASH_KEY()
*/
-#define cxMapGet(map, key) _Generic((key), \
- CxHashKey: cx_map_get, \
- cxstring: cx_map_get_cxstr, \
- cxmutstr: cx_map_get_mustr, \
- char*: cx_map_get_str, \
- const char*: cx_map_get_str) \
- (map, key)
-
-/**
- * @copydoc cxMapRemove()
- */
-cx_attr_nonnull
-static inline int cx_map_remove(
- CxMap *map,
- CxHashKey key
-) {
- return map->cl->remove(map, key, NULL);
-}
-
-/**
- * @copydoc cxMapRemove()
- */
-cx_attr_nonnull
-static inline int cx_map_remove_cxstr(
- CxMap *map,
- cxstring key
-) {
- return map->cl->remove(map, cx_hash_key_cxstr(key), NULL);
-}
-
-/**
- * @copydoc cxMapRemove()
- */
-cx_attr_nonnull
-static inline int cx_map_remove_mustr(
- CxMap *map,
- cxmutstr key
-) {
- return map->cl->remove(map, cx_hash_key_cxstr(key), NULL);
-}
+#define cxMapGet(map, key) cx_map_get(map, CX_HASH_KEY(key))
/**
- * @copydoc cxMapRemove()
+ * Removes a key/value-pair from the map by using the key.
+ *
+ * Invokes the destructor functions, if any, on the removed element if and only if the
+ * @p targetbuf is @c NULL.
+ *
+ * @param map the map
+ * @param key the key
+ * @param targetbuf the optional buffer where the removed element shall be copied to
+ * @retval zero success
+ * @retval non-zero the key was not found
+ *
+ * @see cxMapRemove()
+ * @see cxMapRemoveAndGet()
*/
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-static inline int cx_map_remove_str(
- CxMap *map,
- const char *key
-) {
- return map->cl->remove(map, cx_hash_key_str(key), NULL);
-}
+cx_attr_nonnull_arg(1)
+CX_EXPORT int cx_map_remove(CxMap *map, CxHashKey key, void *targetbuf);
/**
* Removes a key/value-pair from the map by using the key.
*
- * Always invokes the destructors functions, if any, on the removed element.
+ * Always invokes the destructor functions, if any, on the removed element.
*
* @param map (@c CxMap*) the map
- * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key
+ * @param key (any supported key type) the key
* @retval zero success
* @retval non-zero the key was not found
*
* @see cxMapRemoveAndGet()
+ * @see CX_HASH_KEY()
*/
-#define cxMapRemove(map, key) _Generic((key), \
- CxHashKey: cx_map_remove, \
- cxstring: cx_map_remove_cxstr, \
- cxmutstr: cx_map_remove_mustr, \
- char*: cx_map_remove_str, \
- const char*: cx_map_remove_str) \
- (map, key)
-
-/**
- * @copydoc cxMapRemoveAndGet()
- */
-cx_attr_nonnull
-cx_attr_access_w(3)
-static inline int cx_map_remove_and_get(
- CxMap *map,
- CxHashKey key,
- void *targetbuf
-) {
- return map->cl->remove(map, key, targetbuf);
-}
-
-/**
- * @copydoc cxMapRemoveAndGet()
- */
-cx_attr_nonnull
-cx_attr_access_w(3)
-static inline int cx_map_remove_and_get_cxstr(
- CxMap *map,
- cxstring key,
- void *targetbuf
-) {
- return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
-}
-
-/**
- * @copydoc cxMapRemoveAndGet()
- */
-cx_attr_nonnull
-cx_attr_access_w(3)
-static inline int cx_map_remove_and_get_mustr(
- CxMap *map,
- cxmutstr key,
- void *targetbuf
-) {
- return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf);
-}
-
-/**
- * @copydoc cxMapRemoveAndGet()
- */
-cx_attr_nonnull
-cx_attr_access_w(3)
-cx_attr_cstr_arg(2)
-static inline int cx_map_remove_and_get_str(
- CxMap *map,
- const char *key,
- void *targetbuf
-) {
- return map->cl->remove(map, cx_hash_key_str(key), targetbuf);
-}
+#define cxMapRemove(map, key) cx_map_remove(map, CX_HASH_KEY(key), NULL)
/**
* Removes a key/value-pair from the map by using the key.
@@ -805,21 +454,18 @@ static inline int cx_map_remove_and_get_str(
* and not the object it points to.
*
* @param map (@c CxMap*) the map
- * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key
+ * @param key (any supported key type) the key
* @param targetbuf (@c void*) the buffer where the element shall be copied to
* @retval zero success
* @retval non-zero the key was not found
*
* @see cxMapRemove()
+ * @see CX_HASH_KEY()
*/
-#define cxMapRemoveAndGet(map, key, targetbuf) _Generic((key), \
- CxHashKey: cx_map_remove_and_get, \
- cxstring: cx_map_remove_and_get_cxstr, \
- cxmutstr: cx_map_remove_and_get_mustr, \
- char*: cx_map_remove_and_get_str, \
- const char*: cx_map_remove_and_get_str) \
- (map, key, targetbuf)
-
-#endif // __cplusplus
+#define cxMapRemoveAndGet(map, key, targetbuf) cx_map_remove(map, CX_HASH_KEY(key), targetbuf)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
#endif // UCX_MAP_H
diff --git a/ucx/cx/mempool.h b/ucx/cx/mempool.h
index 5d8d284..6530ea7 100644
--- a/ucx/cx/mempool.h
+++ b/ucx/cx/mempool.h
@@ -156,8 +156,7 @@ typedef struct cx_mempool_s CxMempool;
*
* @param pool the memory pool to free
*/
-cx_attr_export
-void cxMempoolFree(CxMempool *pool);
+CX_EXPORT void cxMempoolFree(CxMempool *pool);
/**
* Creates an array-based memory pool.
@@ -169,11 +168,8 @@ void cxMempoolFree(CxMempool *pool);
* @param type the type of memory pool
* @return the created memory pool or @c NULL if allocation failed
*/
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc(cxMempoolFree, 1)
-cx_attr_export
-CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type);
+cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxMempoolFree, 1)
+CX_EXPORT CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type);
/**
* Creates a basic array-based memory pool.
@@ -212,8 +208,7 @@ CxMempool *cxMempoolCreate(size_t capacity, enum cx_mempool_type type);
* @param fnc the destructor that shall be applied to all memory blocks
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc);
+CX_EXPORT void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc);
/**
* Sets the global destructor for all memory blocks within the specified pool.
@@ -223,8 +218,7 @@ void cxMempoolGlobalDestructor(CxMempool *pool, cx_destructor_func fnc);
* @param data additional data for the destructor function
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data);
+CX_EXPORT void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *data);
/**
* Sets the destructor function for a specific allocated memory object.
@@ -237,11 +231,7 @@ void cxMempoolGlobalDestructor2(CxMempool *pool, cx_destructor_func2 fnc, void *
* @param fnc the destructor function
*/
cx_attr_nonnull
-cx_attr_export
-void cxMempoolSetDestructor(
- void *memory,
- cx_destructor_func fnc
-);
+CX_EXPORT void cxMempoolSetDestructor(void *memory, cx_destructor_func fnc);
/**
* Sets the destructor function for a specific allocated memory object.
@@ -255,12 +245,7 @@ void cxMempoolSetDestructor(
* @param data additional data for the destructor function
*/
cx_attr_nonnull
-cx_attr_export
-void cxMempoolSetDestructor2(
- void *memory,
- cx_destructor_func2 fnc,
- void *data
-);
+CX_EXPORT void cxMempoolSetDestructor2(void *memory, cx_destructor_func2 fnc, void *data);
/**
* Removes the destructor function for a specific allocated memory object.
@@ -271,8 +256,7 @@ void cxMempoolSetDestructor2(
* @param memory the object allocated in the pool
*/
cx_attr_nonnull
-cx_attr_export
-void cxMempoolRemoveDestructor(void *memory);
+CX_EXPORT void cxMempoolRemoveDestructor(void *memory);
/**
* Removes the destructor function for a specific allocated memory object.
@@ -283,8 +267,7 @@ void cxMempoolRemoveDestructor(void *memory);
* @param memory the object allocated in the pool
*/
cx_attr_nonnull
-cx_attr_export
-void cxMempoolRemoveDestructor2(void *memory);
+CX_EXPORT void cxMempoolRemoveDestructor2(void *memory);
/**
* Registers foreign memory with this pool.
@@ -302,12 +285,7 @@ void cxMempoolRemoveDestructor2(void *memory);
* @retval non-zero failure
*/
cx_attr_nonnull
-cx_attr_export
-int cxMempoolRegister(
- CxMempool *pool,
- void *memory,
- cx_destructor_func destr
-);
+CX_EXPORT int cxMempoolRegister(CxMempool *pool, void *memory, cx_destructor_func destr);
/**
@@ -330,13 +308,7 @@ int cxMempoolRegister(
* @retval non-zero failure
*/
cx_attr_nonnull
-cx_attr_export
-int cxMempoolRegister2(
- CxMempool *pool,
- void *memory,
- cx_destructor_func2 destr,
- void *data
-);
+CX_EXPORT int cxMempoolRegister2(CxMempool *pool, void *memory, cx_destructor_func2 destr, void *data);
/**
* Transfers all the memory managed by one pool to another.
@@ -354,11 +326,7 @@ int cxMempoolRegister2(
* @retval non-zero allocation failure or incompatible pools
*/
cx_attr_nonnull
-cx_attr_export
-int cxMempoolTransfer(
- CxMempool *source,
- CxMempool *dest
-);
+CX_EXPORT int cxMempoolTransfer(CxMempool *source, CxMempool *dest);
/**
* Transfers an object from one pool to another.
@@ -375,12 +343,7 @@ int cxMempoolTransfer(
* @retval non-zero failure, or the object was not found in the source pool, or the pools are incompatible
*/
cx_attr_nonnull
-cx_attr_export
-int cxMempoolTransferObject(
- CxMempool *source,
- CxMempool *dest,
- const void *obj
-);
+CX_EXPORT int cxMempoolTransferObject(CxMempool *source, CxMempool *dest, const void *obj);
#ifdef __cplusplus
} // extern "C"
diff --git a/ucx/cx/printf.h b/ucx/cx/printf.h
index 4ffd05f..7311ab4 100644
--- a/ucx/cx/printf.h
+++ b/ucx/cx/printf.h
@@ -27,7 +27,7 @@
*/
/**
* @file printf.h
- * @brief Wrapper for write functions with a printf-like interface.
+ * @brief Wrapper for write-functions with a printf-like interface.
* @author Mike Becker
* @author Olaf Wintermann
* @copyright 2-Clause BSD License
@@ -56,8 +56,7 @@ extern "C" {
/**
* The maximum string length that fits into stack memory.
*/
-cx_attr_export
-extern const unsigned cx_printf_sbo_size;
+CX_EXPORT extern const unsigned cx_printf_sbo_size;
/**
* A @c fprintf like function which writes the output to a stream by
@@ -69,16 +68,8 @@ extern const unsigned cx_printf_sbo_size;
* @param ... additional arguments
* @return the total number of bytes written or an error code from stdlib printf implementation
*/
-cx_attr_nonnull_arg(1, 2, 3)
-cx_attr_printf(3, 4)
-cx_attr_cstr_arg(3)
-cx_attr_export
-int cx_fprintf(
- void *stream,
- cx_write_func wfc,
- const char *fmt,
- ...
-);
+cx_attr_nonnull_arg(1, 2, 3) cx_attr_printf(3, 4) cx_attr_cstr_arg(3)
+CX_EXPORT int cx_fprintf(void *stream, cx_write_func wfc, const char *fmt, ...);
/**
* A @c vfprintf like function which writes the output to a stream by
@@ -91,18 +82,11 @@ int cx_fprintf(
* @return the total number of bytes written or an error code from stdlib printf implementation
* @see cx_fprintf()
*/
-cx_attr_nonnull
-cx_attr_cstr_arg(3)
-cx_attr_export
-int cx_vfprintf(
- void *stream,
- cx_write_func wfc,
- const char *fmt,
- va_list ap
-);
+cx_attr_nonnull cx_attr_cstr_arg(3)
+CX_EXPORT int cx_vfprintf(void *stream, cx_write_func wfc, const char *fmt, va_list ap);
/**
- * A @c asprintf like function which allocates space for a string
+ * An @c asprintf like function which allocates space for a string
* the result is written to.
*
* @note The resulting string is guaranteed to be zero-terminated,
@@ -115,18 +99,11 @@ int cx_vfprintf(
* @return the formatted string
* @see cx_strfree_a()
*/
-cx_attr_nonnull_arg(1, 2)
-cx_attr_printf(2, 3)
-cx_attr_cstr_arg(2)
-cx_attr_export
-cxmutstr cx_asprintf_a(
- const CxAllocator *allocator,
- const char *fmt,
- ...
-);
+cx_attr_nonnull_arg(1, 2) cx_attr_printf(2, 3) cx_attr_cstr_arg(2)
+CX_EXPORT cxmutstr cx_asprintf_a(const CxAllocator *allocator, const char *fmt, ...);
/**
- * A @c asprintf like function which allocates space for a string
+ * An @c asprintf like function which allocates space for a string
* the result is written to.
*
* @note The resulting string is guaranteed to be zero-terminated,
@@ -138,8 +115,7 @@ cxmutstr cx_asprintf_a(
* @return (@c cxmutstr) the formatted string
* @see cx_strfree()
*/
-#define cx_asprintf(fmt, ...) \
- cx_asprintf_a(cxDefaultAllocator, fmt, __VA_ARGS__)
+#define cx_asprintf(fmt, ...) cx_asprintf_a(cxDefaultAllocator, fmt, __VA_ARGS__)
/**
* A @c vasprintf like function which allocates space for a string
@@ -155,21 +131,15 @@ cxmutstr cx_asprintf_a(
* @return the formatted string
* @see cx_asprintf_a()
*/
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-cx_attr_export
-cxmutstr cx_vasprintf_a(
- const CxAllocator *allocator,
- const char *fmt,
- va_list ap
-);
+cx_attr_nonnull cx_attr_cstr_arg(2)
+CX_EXPORT cxmutstr cx_vasprintf_a(const CxAllocator *allocator, const char *fmt, va_list ap);
/**
* A @c vasprintf like function which allocates space for a string
* the result is written to.
*
* @note The resulting string is guaranteed to be zero-terminated,
- * unless there was in error, in which case the string's pointer
+ * unless there was an error, in which case the string's pointer
* will be @c NULL.
*
* @param fmt (@c char*) format string
@@ -189,8 +159,7 @@ cxmutstr cx_vasprintf_a(
* @see cx_fprintf()
* @see cxBufferWrite()
*/
-#define cx_bprintf(buffer, fmt, ...) cx_fprintf((void*)buffer, \
- cxBufferWriteFunc, fmt, __VA_ARGS__)
+#define cx_bprintf(buffer, fmt, ...) cx_fprintf((void*)buffer, cxBufferWriteFunc, fmt, __VA_ARGS__)
/**
@@ -204,7 +173,7 @@ cxmutstr cx_vasprintf_a(
* @param len (@c size_t*) a pointer to the length of the buffer
* @param fmt (@c char*) the format string
* @param ... additional arguments
- * @return (@c int) the length of produced string or an error code from stdlib printf implementation
+ * @return (@c int) the length of the produced string or an error code from stdlib printf implementation
*/
#define cx_sprintf(str, len, fmt, ...) cx_sprintf_a(cxDefaultAllocator, str, len, fmt, __VA_ARGS__)
@@ -222,19 +191,10 @@ cxmutstr cx_vasprintf_a(
* @param len a pointer to the length of the buffer
* @param fmt the format string
* @param ... additional arguments
- * @return the length of produced string or an error code from stdlib printf implementation
+ * @return the length of the produced string or an error code from stdlib printf implementation
*/
-cx_attr_nonnull_arg(1, 2, 3, 4)
-cx_attr_printf(4, 5)
-cx_attr_cstr_arg(4)
-cx_attr_export
-int cx_sprintf_a(
- const CxAllocator *alloc,
- char **str,
- size_t *len,
- const char *fmt,
- ...
-);
+cx_attr_nonnull_arg(1, 2, 3, 4) cx_attr_printf(4, 5) cx_attr_cstr_arg(4)
+CX_EXPORT int cx_sprintf_a(const CxAllocator *alloc, char **str, size_t *len, const char *fmt, ...);
/**
@@ -248,7 +208,7 @@ int cx_sprintf_a(
* @param len (@c size_t*) a pointer to the length of the buffer
* @param fmt (@c char*) the format string
* @param ap (@c va_list) argument list
- * @return (@c int) the length of produced string or an error code from stdlib printf implementation
+ * @return (@c int) the length of the produced string or an error code from stdlib printf implementation
*/
#define cx_vsprintf(str, len, fmt, ap) cx_vsprintf_a(cxDefaultAllocator, str, len, fmt, ap)
@@ -266,20 +226,10 @@ int cx_sprintf_a(
* @param len a pointer to the length of the buffer
* @param fmt the format string
* @param ap argument list
- * @return the length of produced string or an error code from stdlib printf implementation
+ * @return the length of the produced string or an error code from stdlib printf implementation
*/
-cx_attr_nonnull
-cx_attr_cstr_arg(4)
-cx_attr_access_rw(2)
-cx_attr_access_rw(3)
-cx_attr_export
-int cx_vsprintf_a(
- const CxAllocator *alloc,
- char **str,
- size_t *len,
- const char *fmt,
- va_list ap
-);
+cx_attr_nonnull cx_attr_cstr_arg(4) cx_attr_access_rw(2) cx_attr_access_rw(3)
+CX_EXPORT int cx_vsprintf_a(const CxAllocator *alloc, char **str, size_t *len, const char *fmt, va_list ap);
/**
@@ -300,7 +250,7 @@ int cx_vsprintf_a(
* @param str (@c char**) a pointer where the location of the result shall be stored
* @param fmt (@c char*) the format string
* @param ... additional arguments
- * @return (@c int) the length of produced string or an error code from stdlib printf implementation
+ * @return (@c int) the length of the produced string or an error code from stdlib printf implementation
*/
#define cx_sprintf_s(buf, len, str, fmt, ...) cx_sprintf_sa(cxDefaultAllocator, buf, len, str, fmt, __VA_ARGS__)
@@ -323,23 +273,11 @@ int cx_vsprintf_a(
* @param str a pointer where the location of the result shall be stored
* @param fmt the format string
* @param ... additional arguments
- * @return the length of produced string or an error code from stdlib printf implementation
+ * @return the length of the produced string or an error code from stdlib printf implementation
*/
-cx_attr_nonnull_arg(1, 2, 4, 5)
-cx_attr_printf(5, 6)
-cx_attr_cstr_arg(5)
-cx_attr_access_rw(2)
-cx_attr_access_rw(3)
-cx_attr_access_rw(4)
-cx_attr_export
-int cx_sprintf_sa(
- const CxAllocator *alloc,
- char *buf,
- size_t *len,
- char **str,
- const char *fmt,
- ...
-);
+cx_attr_nonnull_arg(1, 2, 4, 5) cx_attr_printf(5, 6) cx_attr_cstr_arg(5)
+cx_attr_access_rw(2) cx_attr_access_rw(3) cx_attr_access_rw(4)
+CX_EXPORT int cx_sprintf_sa(const CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, ...);
/**
* An @c sprintf like function which allocates a new string when the buffer is not large enough.
@@ -359,7 +297,7 @@ int cx_sprintf_sa(
* @param str (@c char**) a pointer where the location of the result shall be stored
* @param fmt (@c char*) the format string
* @param ap (@c va_list) argument list
- * @return (@c int) the length of produced string or an error code from stdlib printf implementation
+ * @return (@c int) the length of the produced string or an error code from stdlib printf implementation
*/
#define cx_vsprintf_s(buf, len, str, fmt, ap) cx_vsprintf_sa(cxDefaultAllocator, buf, len, str, fmt, ap)
@@ -382,19 +320,10 @@ int cx_sprintf_sa(
* @param str a pointer where the location of the result shall be stored
* @param fmt the format string
* @param ap argument list
- * @return the length of produced string or an error code from stdlib printf implementation
+ * @return the length of the produced string or an error code from stdlib printf implementation
*/
-cx_attr_nonnull
-cx_attr_cstr_arg(5)
-cx_attr_export
-int cx_vsprintf_sa(
- const CxAllocator *alloc,
- char *buf,
- size_t *len,
- char **str,
- const char *fmt,
- va_list ap
-);
+cx_attr_nonnull cx_attr_cstr_arg(5)
+CX_EXPORT int cx_vsprintf_sa(const CxAllocator *alloc, char *buf, size_t *len, char **str, const char *fmt, va_list ap);
#ifdef __cplusplus
diff --git a/ucx/cx/properties.h b/ucx/cx/properties.h
index d6df8f5..95a4bbe 100644
--- a/ucx/cx/properties.h
+++ b/ucx/cx/properties.h
@@ -94,8 +94,7 @@ typedef struct cx_properties_config_s CxPropertiesConfig;
/**
* Default properties configuration.
*/
-cx_attr_export
-extern const CxPropertiesConfig cx_properties_config_default;
+CX_EXPORT extern const CxPropertiesConfig cx_properties_config_default;
/**
* Status codes for the properties interface.
@@ -122,7 +121,7 @@ enum cx_properties_status {
* You can use this enumerator to check for all "good" status results
* by checking if the status is less than @c CX_PROPERTIES_OK.
*
- * A "good" status means, that you can refill data and continue parsing.
+ * A "good" status means that you can refill data and continue parsing.
*/
CX_PROPERTIES_OK,
/**
@@ -130,11 +129,11 @@ enum cx_properties_status {
*/
CX_PROPERTIES_NULL_INPUT,
/**
- * The line contains a delimiter, but no key.
+ * The line contains a delimiter but no key.
*/
CX_PROPERTIES_INVALID_EMPTY_KEY,
/**
- * The line contains data, but no delimiter.
+ * The line contains data but no delimiter.
*/
CX_PROPERTIES_INVALID_MISSING_DELIMITER,
/**
@@ -200,7 +199,7 @@ typedef struct cx_properties_sink_s CxPropertiesSink;
/**
* A function that consumes a k/v-pair in a sink.
*
- * The sink could be e.g. a map and the sink function would be calling
+ * The sink could be a map, and the sink function would be calling
* a map function to store the k/v-pair.
*
* @param prop the properties interface that wants to sink a k/v-pair
@@ -210,7 +209,6 @@ typedef struct cx_properties_sink_s CxPropertiesSink;
* @retval zero success
* @retval non-zero sinking the k/v-pair failed
*/
-cx_attr_nonnull
typedef int(*cx_properties_sink_func)(
CxProperties *prop,
CxPropertiesSink *sink,
@@ -257,7 +255,6 @@ typedef struct cx_properties_source_s CxPropertiesSource;
* @retval zero success
* @retval non-zero reading the data failed
*/
-cx_attr_nonnull
typedef int(*cx_properties_read_func)(
CxProperties *prop,
CxPropertiesSource *src,
@@ -272,7 +269,6 @@ typedef int(*cx_properties_read_func)(
* @retval zero initialization was successful
* @retval non-zero otherwise
*/
-cx_attr_nonnull
typedef int(*cx_properties_read_init_func)(
CxProperties *prop,
CxPropertiesSource *src
@@ -284,7 +280,6 @@ typedef int(*cx_properties_read_init_func)(
* @param prop the properties interface that wants to read from the source
* @param src the source
*/
-cx_attr_nonnull
typedef void(*cx_properties_read_clean_func)(
CxProperties *prop,
CxPropertiesSource *src
@@ -297,7 +292,7 @@ struct cx_properties_source_s {
/**
* The source object.
*
- * For example a file stream or a string.
+ * For example, a file stream or a string.
*/
void *src;
/**
@@ -331,38 +326,32 @@ struct cx_properties_source_s {
* @see cxPropertiesInitDefault()
*/
cx_attr_nonnull
-cx_attr_export
-void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config);
+CX_EXPORT void cxPropertiesInit(CxProperties *prop, CxPropertiesConfig config);
/**
* Destroys the properties interface.
*
* @note Even when you are certain that you did not use the interface in a
* way that caused a memory allocation, you should call this function anyway.
- * Future versions of the library might add features that need additional memory
- * and you really don't want to search the entire code where you might need
- * add call to this function.
+ * Future versions of the library might add features that need additional memory,
+ * and you really don't want to search the entire code where you might need to
+ * add a call to this function.
*
* @param prop the properties interface
*/
cx_attr_nonnull
-cx_attr_export
-void cxPropertiesDestroy(CxProperties *prop);
+CX_EXPORT void cxPropertiesDestroy(CxProperties *prop);
/**
* Destroys and re-initializes the properties interface.
*
- * You might want to use this, to reset the parser after
+ * You might want to use this to reset the parser after
* encountering a syntax error.
*
* @param prop the properties interface
*/
cx_attr_nonnull
-static inline void cxPropertiesReset(CxProperties *prop) {
- CxPropertiesConfig config = prop->config;
- cxPropertiesDestroy(prop);
- cxPropertiesInit(prop, config);
-}
+CX_EXPORT void cxPropertiesReset(CxProperties *prop);
/**
* Initialize a properties parser with the default configuration.
@@ -371,7 +360,7 @@ static inline void cxPropertiesReset(CxProperties *prop) {
* @see cxPropertiesInit()
*/
#define cxPropertiesInitDefault(prop) \
- cxPropertiesInit(prop, cx_properties_config_default)
+ cxPropertiesInit(prop, cx_properties_config_default)
/**
* Fills the input buffer with data.
@@ -394,44 +383,22 @@ static inline void cxPropertiesReset(CxProperties *prop) {
* @retval non-zero a memory allocation was necessary but failed
* @see cxPropertiesFill()
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-int cxPropertiesFilln(
- CxProperties *prop,
- const char *buf,
- size_t len
-);
-
-#ifdef __cplusplus
-} // extern "C"
-cx_attr_nonnull
-static inline int cxPropertiesFill(
- CxProperties *prop,
- cxstring str
-) {
- return cxPropertiesFilln(prop, str.ptr, str.length);
-}
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT int cxPropertiesFilln(CxProperties *prop, const char *buf, size_t len);
+/**
+ * Internal function, do not use.
+ *
+ * @param prop the properties interface
+ * @param str the text to fill in
+ * @retval zero success
+ * @retval non-zero a memory allocation was necessary but failed
+ */
cx_attr_nonnull
-static inline int cxPropertiesFill(
- CxProperties *prop,
- cxmutstr str
-) {
+CX_INLINE int cx_properties_fill(CxProperties *prop, cxstring str) {
return cxPropertiesFilln(prop, str.ptr, str.length);
}
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-static inline int cxPropertiesFill(
- CxProperties *prop,
- const char *str
-) {
- return cxPropertiesFilln(prop, str, strlen(str));
-}
-
-extern "C" {
-#else // __cplusplus
/**
* Fills the input buffer with data.
*
@@ -452,62 +419,17 @@ extern "C" {
* @retval non-zero a memory allocation was necessary but failed
* @see cxPropertiesFilln()
*/
-#define cxPropertiesFill(prop, str) _Generic((str), \
- cxstring: cx_properties_fill_cxstr, \
- cxmutstr: cx_properties_fill_mutstr, \
- char*: cx_properties_fill_str, \
- const char*: cx_properties_fill_str) \
- (prop, str)
+#define cxPropertiesFill(prop, str) cx_properties_fill(prop, cx_strcast(str))
/**
- * @copydoc cxPropertiesFill()
- */
-cx_attr_nonnull
-static inline int cx_properties_fill_cxstr(
- CxProperties *prop,
- cxstring str
-) {
- return cxPropertiesFilln(prop, str.ptr, str.length);
-}
-
-/**
- * @copydoc cxPropertiesFill()
- */
-cx_attr_nonnull
-static inline int cx_properties_fill_mutstr(
- CxProperties *prop,
- cxmutstr str
-) {
- return cxPropertiesFilln(prop, str.ptr, str.length);
-}
-
-/**
- * @copydoc cxPropertiesFill()
- */
-cx_attr_nonnull
-cx_attr_cstr_arg(2)
-static inline int cx_properties_fill_str(
- CxProperties *prop,
- const char *str
-) {
- return cxPropertiesFilln(prop, str, strlen(str));
-}
-#endif
-
-/**
- * Specifies stack memory that shall be used as internal buffer.
+ * Specifies stack memory that shall be used as an internal buffer.
*
* @param prop the properties interface
* @param buf a pointer to stack memory
* @param capacity the capacity of the stack memory
*/
cx_attr_nonnull
-cx_attr_export
-void cxPropertiesUseStack(
- CxProperties *prop,
- char *buf,
- size_t capacity
-);
+CX_EXPORT void cxPropertiesUseStack(CxProperties *prop, char *buf, size_t capacity);
/**
* Retrieves the next key/value-pair.
@@ -539,14 +461,8 @@ void cxPropertiesUseStack(
* @retval CX_PROPERTIES_INVALID_MISSING_DELIMITER the properties data contains a line without delimiter
* @retval CX_PROPERTIES_BUFFER_ALLOC_FAILED an internal allocation was necessary but failed
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxPropertiesStatus cxPropertiesNext(
- CxProperties *prop,
- cxstring *key,
- cxstring *value
-);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxPropertiesStatus cxPropertiesNext(CxProperties *prop, cxstring *key, cxstring *value);
/**
* Creates a properties sink for an UCX map.
@@ -562,10 +478,8 @@ CxPropertiesStatus cxPropertiesNext(
* @return the sink
* @see cxPropertiesLoad()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-CxPropertiesSink cxPropertiesMapSink(CxMap *map);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxPropertiesSink cxPropertiesMapSink(CxMap *map);
/**
* Creates a properties source based on an UCX string.
@@ -575,8 +489,7 @@ CxPropertiesSink cxPropertiesMapSink(CxMap *map);
* @see cxPropertiesLoad()
*/
cx_attr_nodiscard
-cx_attr_export
-CxPropertiesSource cxPropertiesStringSource(cxstring str);
+CX_EXPORT CxPropertiesSource cxPropertiesStringSource(cxstring str);
/**
* Creates a properties source based on C string with the specified length.
@@ -586,11 +499,8 @@ CxPropertiesSource cxPropertiesStringSource(cxstring str);
* @return the properties source
* @see cxPropertiesLoad()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_access_r(1, 2)
-cx_attr_export
-CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_access_r(1, 2)
+CX_EXPORT CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len);
/**
* Creates a properties source based on a C string.
@@ -602,11 +512,8 @@ CxPropertiesSource cxPropertiesCstrnSource(const char *str, size_t len);
* @return the properties source
* @see cxPropertiesLoad()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_export
-CxPropertiesSource cxPropertiesCstrSource(const char *str);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT CxPropertiesSource cxPropertiesCstrSource(const char *str);
/**
* Creates a properties source based on an FILE.
@@ -617,11 +524,8 @@ CxPropertiesSource cxPropertiesCstrSource(const char *str);
* @return the properties source
* @see cxPropertiesLoad()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_access_r(1)
-cx_attr_export
-CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_access_r(1)
+CX_EXPORT CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size);
/**
@@ -653,12 +557,8 @@ CxPropertiesSource cxPropertiesFileSource(FILE *file, size_t chunk_size);
* @retval CX_PROPERTIES_BUFFER_ALLOC_FAILED an internal allocation was necessary but failed
*/
cx_attr_nonnull
-cx_attr_export
-CxPropertiesStatus cxPropertiesLoad(
- CxProperties *prop,
- CxPropertiesSink sink,
- CxPropertiesSource source
-);
+CX_EXPORT CxPropertiesStatus cxPropertiesLoad(CxProperties *prop,
+ CxPropertiesSink sink, CxPropertiesSource source);
#ifdef __cplusplus
} // extern "C"
diff --git a/ucx/cx/streams.h b/ucx/cx/streams.h
index 3cc35fa..298ca3a 100644
--- a/ucx/cx/streams.h
+++ b/ucx/cx/streams.h
@@ -54,7 +54,7 @@ extern "C" {
* @param wfnc the write function
* @param buf a pointer to the copy buffer or @c NULL if a buffer
* shall be implicitly created on the heap
- * @param bufsize the size of the copy buffer - if @p buf is @c NULL you can
+ * @param bufsize the size of the copy buffer - if @p buf is @c NULL, you can
* set this to zero to let the implementation decide
* @param n the maximum number of bytes that shall be copied.
* If this is larger than @p bufsize, the content is copied over multiple
@@ -62,19 +62,10 @@ extern "C" {
* @return the total number of bytes copied
*/
cx_attr_nonnull_arg(1, 2, 3, 4)
-cx_attr_access_r(1)
-cx_attr_access_w(2)
-cx_attr_access_w(5)
-cx_attr_export
-size_t cx_stream_bncopy(
- void *src,
- void *dest,
- cx_read_func rfnc,
- cx_write_func wfnc,
- char *buf,
- size_t bufsize,
- size_t n
-);
+cx_attr_access_r(1) cx_attr_access_w(2) cx_attr_access_w(5)
+CX_EXPORT size_t cx_stream_bncopy(void *src, void *dest,
+ cx_read_func rfnc, cx_write_func wfnc,
+ char *buf, size_t bufsize, size_t n);
/**
* Reads data from a stream and writes it to another stream.
@@ -86,7 +77,7 @@ size_t cx_stream_bncopy(
* @param buf (@c char*) a pointer to the copy buffer or @c NULL if a buffer
* shall be implicitly created on the heap
* @param bufsize (@c size_t) the size of the copy buffer - if @p buf is
- * @c NULL you can set this to zero to let the implementation decide
+ * @c NULL, you can set this to zero to let the implementation decide
* @return total number of bytes copied
*/
#define cx_stream_bcopy(src, dest, rfnc, wfnc, buf, bufsize) \
@@ -95,7 +86,7 @@ size_t cx_stream_bncopy(
/**
* Reads data from a stream and writes it to another stream.
*
- * The data is temporarily stored in a stack allocated buffer.
+ * The data is temporarily stored in a stack-allocated buffer.
*
* @param src the source stream
* @param dest the destination stream
@@ -104,22 +95,14 @@ size_t cx_stream_bncopy(
* @param n the maximum number of bytes that shall be copied.
* @return total number of bytes copied
*/
-cx_attr_nonnull
-cx_attr_access_r(1)
-cx_attr_access_w(2)
-cx_attr_export
-size_t cx_stream_ncopy(
- void *src,
- void *dest,
- cx_read_func rfnc,
- cx_write_func wfnc,
- size_t n
-);
+cx_attr_nonnull cx_attr_access_r(1) cx_attr_access_w(2)
+CX_EXPORT size_t cx_stream_ncopy(void *src, void *dest,
+ cx_read_func rfnc, cx_write_func wfnc, size_t n);
/**
* Reads data from a stream and writes it to another stream.
*
- * The data is temporarily stored in a stack allocated buffer.
+ * The data is temporarily stored in a stack-allocated buffer.
*
* @param src (@c void*) the source stream
* @param dest (@c void*) the destination stream
diff --git a/ucx/cx/string.h b/ucx/cx/string.h
index 41bf18a..5177ceb 100644
--- a/ucx/cx/string.h
+++ b/ucx/cx/string.h
@@ -48,8 +48,7 @@
/**
* The maximum length of the "needle" in cx_strstr() that can use SBO.
*/
-cx_attr_export
-extern const unsigned cx_strstr_sbo_size;
+CX_EXPORT extern const unsigned cx_strstr_sbo_size;
/**
* The UCX string structure.
@@ -112,10 +111,10 @@ struct cx_strtok_ctx_s {
*/
size_t pos;
/**
- * Position of next delimiter in the source string.
+ * Position of the next delimiter in the source string.
*
* If the tokenizer has not yet returned a token, the content of this field
- * is undefined. If the tokenizer reached the end of the string, this field
+ * is undefined. If the tokenizer reaches the end of the string, this field
* contains the length of the source string.
*/
size_t delim_pos;
@@ -167,21 +166,20 @@ extern "C" {
*
* The length is implicitly inferred by using a call to @c strlen().
*
+ * When @c NULL is passed, the length will be set to zero.
+ *
* @note the wrapped string will share the specified pointer to the string.
* If you do want a copy, use cx_strdup() on the return value of this function.
*
* If you need to wrap a constant string, use cx_str().
*
- * @param cstring the string to wrap, must be zero-terminated
+ * @param cstring the string to wrap (must be zero-terminated)
* @return the wrapped string
*
* @see cx_mutstrn()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_export
-cxmutstr cx_mutstr(char *cstring);
+cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT cxmutstr cx_mutstr(char *cstring);
/**
* Wraps a string that does not need to be zero-terminated.
@@ -199,34 +197,28 @@ cxmutstr cx_mutstr(char *cstring);
*
* @see cx_mutstr()
*/
-cx_attr_nodiscard
-cx_attr_access_rw(1, 2)
-cx_attr_export
-cxmutstr cx_mutstrn(
- char *cstring,
- size_t length
-);
+cx_attr_nodiscard cx_attr_access_rw(1, 2)
+CX_EXPORT cxmutstr cx_mutstrn(char *cstring, size_t length);
/**
* Wraps a string that must be zero-terminated.
*
* The length is implicitly inferred by using a call to @c strlen().
*
+ * When @c NULL is passed, the length will be set to zero.
+ *
* @note the wrapped string will share the specified pointer to the string.
* If you do want a copy, use cx_strdup() on the return value of this function.
*
* If you need to wrap a non-constant string, use cx_mutstr().
*
- * @param cstring the string to wrap, must be zero-terminated
+ * @param cstring the string to wrap (must be zero-terminated)
* @return the wrapped string
*
* @see cx_strn()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_export
-cxstring cx_str(const char *cstring);
+cx_attr_nodiscard cx_attr_cstr_arg(1)
+CX_EXPORT cxstring cx_str(const char *cstring);
/**
@@ -245,28 +237,27 @@ cxstring cx_str(const char *cstring);
*
* @see cx_str()
*/
-cx_attr_nodiscard
-cx_attr_access_r(1, 2)
-cx_attr_export
-cxstring cx_strn(
- const char *cstring,
- size_t length
-);
+cx_attr_nodiscard cx_attr_access_r(1, 2)
+CX_EXPORT cxstring cx_strn(const char *cstring, size_t length);
#ifdef __cplusplus
} // extern "C"
cx_attr_nodiscard
-static inline cxstring cx_strcast(cxmutstr str) {
+CX_CPPDECL cxstring cx_strcast(cxmutstr str) {
return cx_strn(str.ptr, str.length);
}
cx_attr_nodiscard
-static inline cxstring cx_strcast(cxstring str) {
+CX_CPPDECL cxstring cx_strcast(cxstring str) {
return str;
}
cx_attr_nodiscard
-static inline cxstring cx_strcast(const char *str) {
+CX_CPPDECL cxstring cx_strcast(const char *str) {
return cx_str(str);
}
+cx_attr_nodiscard
+CX_CPPDECL cxstring cx_strcast(const unsigned char *str) {
+ return cx_str(static_cast(str));
+}
extern "C" {
#else
/**
@@ -276,7 +267,7 @@ extern "C" {
* @see cx_strcast()
*/
cx_attr_nodiscard
-static inline cxstring cx_strcast_m(cxmutstr str) {
+CX_INLINE cxstring cx_strcast_m(cxmutstr str) {
return (cxstring) {str.ptr, str.length};
}
/**
@@ -286,7 +277,7 @@ static inline cxstring cx_strcast_m(cxmutstr str) {
* @see cx_strcast()
*/
cx_attr_nodiscard
-static inline cxstring cx_strcast_c(cxstring str) {
+CX_INLINE cxstring cx_strcast_c(cxstring str) {
return str;
}
@@ -297,25 +288,32 @@ static inline cxstring cx_strcast_c(cxstring str) {
* @see cx_strcast()
*/
cx_attr_nodiscard
-static inline cxstring cx_strcast_z(const char *str) {
+CX_INLINE cxstring cx_strcast_u(const unsigned char *str) {
+ return cx_str((const char*)str);
+}
+
+/**
+ * Internal function, do not use.
+ * @param str
+ * @return
+ * @see cx_strcast()
+ */
+cx_attr_nodiscard
+CX_INLINE cxstring cx_strcast_z(const char *str) {
return cx_str(str);
}
/**
-* Casts a mutable string to an immutable string.
-*
-* Does nothing for already immutable strings.
-*
-* @note This is not seriously a cast. Instead, you get a copy
-* of the struct with the desired pointer type. Both structs still
-* point to the same location, though!
-*
-* @param str (@c cxstring or @c cxmutstr) the string to cast
-* @return (@c cxstring) an immutable copy of the string pointer
-*/
+ * Wraps any string into an UCX string.
+ *
+ * @param str (any supported string type) the string to cast
+ * @return (@c cxstring) the string wrapped as UCX string
+ */
#define cx_strcast(str) _Generic((str), \
cxmutstr: cx_strcast_m, \
cxstring: cx_strcast_c, \
+ const unsigned char*: cx_strcast_u, \
+ unsigned char *: cx_strcast_u, \
const char*: cx_strcast_z, \
char *: cx_strcast_z) (str)
#endif
@@ -323,37 +321,32 @@ static inline cxstring cx_strcast_z(const char *str) {
/**
* Passes the pointer in this string to the cxDefaultAllocator's @c free() function.
*
- * The pointer in the struct is set to @c NULL and the length is set to zero
+ * The pointer in the struct is set to @c NULL, and the length is set to zero,
* which means that this function protects you against double-free.
*
* @note There is no implementation for cxstring, because it is unlikely that
* you ever have a const char* you are really supposed to free.
- * If you encounter such situation, you should double-check your code.
+ * If you encounter such a situation, you should double-check your code.
*
* @param str the string to free
*/
-cx_attr_export
-void cx_strfree(cxmutstr *str);
+CX_EXPORT void cx_strfree(cxmutstr *str);
/**
- * Passes the pointer in this string to the allocators free function.
+ * Passes the pointer in this string to the allocator's free function.
*
- * The pointer in the struct is set to @c NULL and the length is set to zero
+ * The pointer in the struct is set to @c NULL, and the length is set to zero,
* which means that this function protects you against double-free.
*
* @note There is no implementation for cxstring, because it is unlikely that
* you ever have a const char* you are really supposed to free.
- * If you encounter such situation, you should double-check your code.
+ * If you encounter such a situation, you should double-check your code.
*
* @param alloc the allocator
* @param str the string to free
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-void cx_strfree_a(
- const CxAllocator *alloc,
- cxmutstr *str
-);
+CX_EXPORT void cx_strfree_a(const CxAllocator *alloc, cxmutstr *str);
/**
* Copies a string.
@@ -371,12 +364,7 @@ void cx_strfree_a(
* @retval non-zero if re-allocation failed
*/
cx_attr_nonnull_arg(1)
-cx_attr_export
-int cx_strcpy_a(
- const CxAllocator *alloc,
- cxmutstr *dest,
- cxstring src
-);
+CX_EXPORT int cx_strcpy_a(const CxAllocator *alloc, cxmutstr *dest, cxstring src);
/**
@@ -408,11 +396,7 @@ int cx_strcpy_a(
* @return the accumulated length of all strings
*/
cx_attr_nodiscard
-cx_attr_export
-size_t cx_strlen(
- size_t count,
- ...
-);
+CX_EXPORT size_t cx_strlen(size_t count, ...);
/**
* Concatenates strings.
@@ -436,15 +420,9 @@ size_t cx_strlen(
* @param ... all other UCX strings
* @return the concatenated string
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-cxmutstr cx_strcat_ma(
- const CxAllocator *alloc,
- cxmutstr str,
- size_t count,
- ...
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT cxmutstr cx_strcat_ma(const CxAllocator *alloc,
+ cxmutstr str, size_t count, ...);
/**
* Concatenates strings and returns a new string.
@@ -465,7 +443,7 @@ cxmutstr cx_strcat_ma(
* @return (@c cxmutstr) the concatenated string
*/
#define cx_strcat_a(alloc, count, ...) \
-cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
+ cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
/**
* Concatenates strings and returns a new string.
@@ -485,7 +463,7 @@ cx_strcat_ma(alloc, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
* @return (@c cxmutstr) the concatenated string
*/
#define cx_strcat(count, ...) \
-cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
+ cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
/**
* Concatenates strings.
@@ -509,7 +487,7 @@ cx_strcat_ma(cxDefaultAllocator, cx_mutstrn(NULL, 0), count, __VA_ARGS__)
* @return (@c cxmutstr) the concatenated string
*/
#define cx_strcat_m(str, count, ...) \
-cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__)
+ cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__)
/**
* Returns a substring starting at the specified location.
@@ -527,11 +505,7 @@ cx_strcat_ma(cxDefaultAllocator, str, count, __VA_ARGS__)
* @see cx_strsubsl_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strsubs(
- cxstring string,
- size_t start
-);
+CX_EXPORT cxstring cx_strsubs(cxstring string, size_t start);
/**
* Returns a substring starting at the specified location.
@@ -553,12 +527,7 @@ cxstring cx_strsubs(
* @see cx_strsubsl_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strsubsl(
- cxstring string,
- size_t start,
- size_t length
-);
+CX_EXPORT cxstring cx_strsubsl(cxstring string, size_t start, size_t length);
/**
* Returns a substring starting at the specified location.
@@ -576,11 +545,7 @@ cxstring cx_strsubsl(
* @see cx_strsubsl()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strsubs_m(
- cxmutstr string,
- size_t start
-);
+CX_EXPORT cxmutstr cx_strsubs_m(cxmutstr string, size_t start);
/**
* Returns a substring starting at the specified location.
@@ -602,12 +567,7 @@ cxmutstr cx_strsubs_m(
* @see cx_strsubsl()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strsubsl_m(
- cxmutstr string,
- size_t start,
- size_t length
-);
+CX_EXPORT cxmutstr cx_strsubsl_m(cxmutstr string, size_t start, size_t length);
/**
* Returns a substring starting at the location of the first occurrence of the
@@ -622,11 +582,7 @@ cxmutstr cx_strsubsl_m(
* @see cx_strchr_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strchr(
- cxstring string,
- int chr
-);
+CX_EXPORT cxstring cx_strchr(cxstring string, int chr);
/**
* Returns a substring starting at the location of the first occurrence of the
@@ -641,11 +597,7 @@ cxstring cx_strchr(
* @see cx_strchr()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strchr_m(
- cxmutstr string,
- int chr
-);
+CX_EXPORT cxmutstr cx_strchr_m(cxmutstr string, int chr);
/**
* Returns a substring starting at the location of the last occurrence of the
@@ -660,11 +612,7 @@ cxmutstr cx_strchr_m(
* @see cx_strrchr_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strrchr(
- cxstring string,
- int chr
-);
+CX_EXPORT cxstring cx_strrchr(cxstring string, int chr);
/**
* Returns a substring starting at the location of the last occurrence of the
@@ -679,11 +627,7 @@ cxstring cx_strrchr(
* @see cx_strrchr()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strrchr_m(
- cxmutstr string,
- int chr
-);
+CX_EXPORT cxmutstr cx_strrchr_m(cxmutstr string, int chr);
/**
* Returns a substring starting at the location of the first occurrence of the
@@ -702,11 +646,7 @@ cxmutstr cx_strrchr_m(
* @see cx_strstr_m()
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strstr(
- cxstring haystack,
- cxstring needle
-);
+CX_EXPORT cxstring cx_strstr(cxstring haystack, cxstring needle);
/**
* Returns a substring starting at the location of the first occurrence of the
@@ -725,11 +665,7 @@ cxstring cx_strstr(
* @see cx_strstr()
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strstr_m(
- cxmutstr haystack,
- cxstring needle
-);
+CX_EXPORT cxmutstr cx_strstr_m(cxmutstr haystack, cxstring needle);
/**
* Splits a given string using a delimiter string.
@@ -743,16 +679,9 @@ cxmutstr cx_strstr_m(
* @param output a preallocated array of at least @p limit length
* @return the actual number of split items
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_access_w(4, 3)
-cx_attr_export
-size_t cx_strsplit(
- cxstring string,
- cxstring delim,
- size_t limit,
- cxstring *output
-);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(4, 3)
+CX_EXPORT size_t cx_strsplit(cxstring string, cxstring delim,
+ size_t limit, cxstring *output);
/**
* Splits a given string using a delimiter string.
@@ -773,17 +702,10 @@ size_t cx_strsplit(
* written to
* @return the actual number of split items
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_access_w(5)
-cx_attr_export
-size_t cx_strsplit_a(
- const CxAllocator *allocator,
- cxstring string,
- cxstring delim,
- size_t limit,
- cxstring **output
-);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5)
+CX_EXPORT size_t cx_strsplit_a(const CxAllocator *allocator,
+ cxstring string, cxstring delim,
+ size_t limit, cxstring **output);
/**
@@ -798,16 +720,9 @@ size_t cx_strsplit_a(
* @param output a preallocated array of at least @p limit length
* @return the actual number of split items
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_access_w(4, 3)
-cx_attr_export
-size_t cx_strsplit_m(
- cxmutstr string,
- cxstring delim,
- size_t limit,
- cxmutstr *output
-);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(4, 3)
+CX_EXPORT size_t cx_strsplit_m(cxmutstr string, cxstring delim,
+ size_t limit, cxmutstr *output);
/**
* Splits a given string using a delimiter string.
@@ -828,17 +743,10 @@ size_t cx_strsplit_m(
* written to
* @return the actual number of split items
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_access_w(5)
-cx_attr_export
-size_t cx_strsplit_ma(
- const CxAllocator *allocator,
- cxmutstr string,
- cxstring delim,
- size_t limit,
- cxmutstr **output
-);
+cx_attr_nodiscard cx_attr_nonnull cx_attr_access_w(5)
+CX_EXPORT size_t cx_strsplit_ma(const CxAllocator *allocator,
+ cxmutstr string, cxstring delim, size_t limit,
+ cxmutstr **output);
/**
* Compares two strings.
@@ -849,11 +757,17 @@ size_t cx_strsplit_ma(
* than @p s2, zero if both strings equal
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_strcmp(
- cxstring s1,
- cxstring s2
-);
+CX_EXPORT int cx_strcmp_(cxstring s1, cxstring s2);
+
+/**
+ * Compares two strings.
+ *
+ * @param s1 the first string
+ * @param s2 the second string
+ * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
+ * than @p s2, zero if both strings equal
+ */
+#define cx_strcmp(s1, s2) cx_strcmp_(cx_strcast(s1), cx_strcast(s2))
/**
* Compares two strings ignoring case.
@@ -864,29 +778,33 @@ int cx_strcmp(
* than @p s2, zero if both strings equal ignoring case
*/
cx_attr_nodiscard
-cx_attr_export
-int cx_strcasecmp(
- cxstring s1,
- cxstring s2
-);
+CX_EXPORT int cx_strcasecmp_(cxstring s1, cxstring s2);
+
+/**
+ * Compares two strings ignoring case.
+ *
+ * @param s1 the first string
+ * @param s2 the second string
+ * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
+ * than @p s2, zero if both strings equal ignoring case
+ */
+#define cx_strcasecmp(s1, s2) cx_strcasecmp_(cx_strcast(s1), cx_strcast(s2))
/**
* Compares two strings.
*
* This function has a compatible signature for the use as a cx_compare_func.
*
+ * @attention This function can @em only compare UCX strings. It is unsafe to
+ * pass normal C-strings to this function.
+ *
* @param s1 the first string
* @param s2 the second string
* @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
* than @p s2, zero if both strings equal
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-int cx_strcmp_p(
- const void *s1,
- const void *s2
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT int cx_strcmp_p(const void *s1, const void *s2);
/**
* Compares two strings ignoring case.
@@ -898,13 +816,8 @@ int cx_strcmp_p(
* @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
* than @p s2, zero if both strings equal ignoring case
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-int cx_strcasecmp_p(
- const void *s1,
- const void *s2
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT int cx_strcasecmp_p(const void *s1, const void *s2);
/**
@@ -919,13 +832,8 @@ int cx_strcasecmp_p(
* @return a duplicate of the string
* @see cx_strdup()
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-cxmutstr cx_strdup_a_(
- const CxAllocator *allocator,
- cxstring string
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT cxmutstr cx_strdup_a_(const CxAllocator *allocator, cxstring string);
/**
* Creates a duplicate of the specified string.
@@ -940,8 +848,7 @@ cxmutstr cx_strdup_a_(
* @see cx_strdup()
* @see cx_strfree_a()
*/
-#define cx_strdup_a(allocator, string) \
- cx_strdup_a_((allocator), cx_strcast(string))
+#define cx_strdup_a(allocator, string) cx_strdup_a_((allocator), cx_strcast(string))
/**
* Creates a duplicate of the specified string.
@@ -968,8 +875,7 @@ cxmutstr cx_strdup_a_(
* @return the trimmed string
*/
cx_attr_nodiscard
-cx_attr_export
-cxstring cx_strtrim(cxstring string);
+CX_EXPORT cxstring cx_strtrim(cxstring string);
/**
* Omits leading and trailing spaces.
@@ -981,11 +887,10 @@ cxstring cx_strtrim(cxstring string);
* @return the trimmed string
*/
cx_attr_nodiscard
-cx_attr_export
-cxmutstr cx_strtrim_m(cxmutstr string);
+CX_EXPORT cxmutstr cx_strtrim_m(cxmutstr string);
/**
- * Checks, if a string has a specific prefix.
+ * Checks if a string has a specific prefix.
*
* @param string the string to check
* @param prefix the prefix the string should have
@@ -993,14 +898,20 @@ cxmutstr cx_strtrim_m(cxmutstr string);
* @c false otherwise
*/
cx_attr_nodiscard
-cx_attr_export
-bool cx_strprefix(
- cxstring string,
- cxstring prefix
-);
+CX_EXPORT bool cx_strprefix_(cxstring string, cxstring prefix);
/**
- * Checks, if a string has a specific suffix.
+ * Checks if a string has a specific prefix.
+ *
+ * @param string the string to check
+ * @param prefix the prefix the string should have
+ * @return @c true, if and only if the string has the specified prefix,
+ * @c false otherwise
+ */
+#define cx_strprefix(string, prefix) cx_strprefix_(cx_strcast(string), cx_strcast(prefix))
+
+/**
+ * Checks if a string has a specific suffix.
*
* @param string the string to check
* @param suffix the suffix the string should have
@@ -1008,14 +919,20 @@ bool cx_strprefix(
* @c false otherwise
*/
cx_attr_nodiscard
-cx_attr_export
-bool cx_strsuffix(
- cxstring string,
- cxstring suffix
-);
+CX_EXPORT bool cx_strsuffix_(cxstring string, cxstring suffix);
+
+/**
+ * Checks if a string has a specific suffix.
+ *
+ * @param string the string to check
+ * @param suffix the suffix the string should have
+ * @return @c true, if and only if the string has the specified suffix,
+ * @c false otherwise
+ */
+#define cx_strsuffix(string, suffix) cx_strsuffix_(cx_strcast(string), cx_strcast(suffix))
/**
- * Checks, if a string has a specific prefix, ignoring the case.
+ * Checks if a string has a specific prefix, ignoring the case.
*
* @param string the string to check
* @param prefix the prefix the string should have
@@ -1023,11 +940,17 @@ bool cx_strsuffix(
* @c false otherwise
*/
cx_attr_nodiscard
-cx_attr_export
-bool cx_strcaseprefix(
- cxstring string,
- cxstring prefix
-);
+CX_EXPORT bool cx_strcaseprefix_(cxstring string, cxstring prefix);
+
+/**
+ * Checks if a string has a specific prefix, ignoring the case.
+ *
+ * @param string the string to check
+ * @param prefix the prefix the string should have
+ * @return @c true, if and only if the string has the specified prefix,
+ * @c false otherwise
+ */
+#define cx_strcaseprefix(string, prefix) cx_strcaseprefix_(cx_strcast(string), cx_strcast(prefix))
/**
* Checks, if a string has a specific suffix, ignoring the case.
@@ -1038,16 +961,22 @@ bool cx_strcaseprefix(
* @c false otherwise
*/
cx_attr_nodiscard
-cx_attr_export
-bool cx_strcasesuffix(
- cxstring string,
- cxstring suffix
-);
+CX_EXPORT bool cx_strcasesuffix_(cxstring string, cxstring suffix);
+
+/**
+ * Checks, if a string has a specific suffix, ignoring the case.
+ *
+ * @param string the string to check
+ * @param suffix the suffix the string should have
+ * @return @c true, if and only if the string has the specified suffix,
+ * @c false otherwise
+ */
+#define cx_strcasesuffix(string, suffix) cx_strcasesuffix_(cx_strcast(string), cx_strcast(suffix))
/**
* Replaces a string with another string.
*
- * Replaces at most @p replmax occurrences.
+ * The function replaces at most @p replmax occurrences.
*
* The returned string will be allocated by @p allocator and is guaranteed
* to be zero-terminated.
@@ -1062,21 +991,14 @@ bool cx_strcasesuffix(
* @param replmax maximum number of replacements
* @return the resulting string after applying the replacements
*/
-cx_attr_nodiscard
-cx_attr_nonnull
-cx_attr_export
-cxmutstr cx_strreplacen_a(
- const CxAllocator *allocator,
- cxstring str,
- cxstring search,
- cxstring replacement,
- size_t replmax
-);
+cx_attr_nodiscard cx_attr_nonnull
+CX_EXPORT cxmutstr cx_strreplacen_a(const CxAllocator *allocator,
+ cxstring str, cxstring search, cxstring replacement, size_t replmax);
/**
* Replaces a string with another string.
*
- * Replaces at most @p replmax occurrences.
+ * The function replaces at most @p replmax occurrences.
*
* The returned string will be allocated by the cxDefaultAllocator and is guaranteed
* to be zero-terminated.
@@ -1091,7 +1013,7 @@ cxmutstr cx_strreplacen_a(
* @return (@c cxmutstr) the resulting string after applying the replacements
*/
#define cx_strreplacen(str, search, replacement, replmax) \
-cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, replmax)
+ cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, replmax)
/**
* Replaces a string with another string.
@@ -1109,7 +1031,7 @@ cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, replmax)
* @return (@c cxmutstr) the resulting string after applying the replacements
*/
#define cx_strreplace_a(allocator, str, search, replacement) \
-cx_strreplacen_a(allocator, str, search, replacement, SIZE_MAX)
+ cx_strreplacen_a(allocator, str, search, replacement, SIZE_MAX)
/**
* Replaces a string with another string.
@@ -1126,7 +1048,7 @@ cx_strreplacen_a(allocator, str, search, replacement, SIZE_MAX)
* @return (@c cxmutstr) the resulting string after applying the replacements
*/
#define cx_strreplace(str, search, replacement) \
-cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, SIZE_MAX)
+ cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, SIZE_MAX)
/**
* Creates a string tokenization context.
@@ -1137,12 +1059,7 @@ cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, SIZE_MAX)
* @return a new string tokenization context
*/
cx_attr_nodiscard
-cx_attr_export
-CxStrtokCtx cx_strtok_(
- cxstring str,
- cxstring delim,
- size_t limit
-);
+CX_EXPORT CxStrtokCtx cx_strtok_(cxstring str, cxstring delim, size_t limit);
/**
* Creates a string tokenization context.
@@ -1153,7 +1070,7 @@ CxStrtokCtx cx_strtok_(
* @return (@c CxStrtokCtx) a new string tokenization context
*/
#define cx_strtok(str, delim, limit) \
- cx_strtok_(cx_strcast(str), cx_strcast(delim), (limit))
+ cx_strtok_(cx_strcast(str), cx_strcast(delim), (limit))
/**
* Returns the next token.
@@ -1165,14 +1082,8 @@ CxStrtokCtx cx_strtok_(
* @return true if successful, false if the limit or the end of the string
* has been reached
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_access_w(2)
-cx_attr_export
-bool cx_strtok_next(
- CxStrtokCtx *ctx,
- cxstring *token
-);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2)
+CX_EXPORT bool cx_strtok_next(CxStrtokCtx *ctx, cxstring *token);
/**
* Returns the next token of a mutable string.
@@ -1188,14 +1099,8 @@ bool cx_strtok_next(
* @return true if successful, false if the limit or the end of the string
* has been reached
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_access_w(2)
-cx_attr_export
-bool cx_strtok_next_m(
- CxStrtokCtx *ctx,
- cxmutstr *token
-);
+cx_attr_nonnull cx_attr_nodiscard cx_attr_access_w(2)
+CX_EXPORT bool cx_strtok_next_m(CxStrtokCtx *ctx, cxmutstr *token);
/**
* Defines an array of more delimiters for the specified tokenization context.
@@ -1204,14 +1109,8 @@ bool cx_strtok_next_m(
* @param delim array of more delimiters
* @param count number of elements in the array
*/
-cx_attr_nonnull
-cx_attr_access_r(2, 3)
-cx_attr_export
-void cx_strtok_delim(
- CxStrtokCtx *ctx,
- const cxstring *delim,
- size_t count
-);
+cx_attr_nonnull cx_attr_access_r(2, 3)
+CX_EXPORT void cx_strtok_delim(CxStrtokCtx *ctx, const cxstring *delim, size_t count);
/* ------------------------------------------------------------------------- *
* string to number conversion functions *
@@ -1227,12 +1126,12 @@ void cx_strtok_delim(
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1244,12 +1143,12 @@ int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep);
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1261,12 +1160,12 @@ int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep);
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1278,12 +1177,12 @@ int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep);
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1295,12 +1194,12 @@ int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groups
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1312,12 +1211,12 @@ int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep)
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1329,12 +1228,12 @@ int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1346,12 +1245,12 @@ int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1363,12 +1262,12 @@ int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1380,12 +1279,12 @@ int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *g
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1397,12 +1296,12 @@ int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *grou
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1414,12 +1313,12 @@ int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *gr
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1431,12 +1330,12 @@ int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const ch
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1448,12 +1347,12 @@ int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1465,12 +1364,12 @@ int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groups
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1482,12 +1381,12 @@ int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groups
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep);
/**
* Converts a string to a number.
@@ -1499,15 +1398,15 @@ int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groups
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep);
/**
- * Converts a string to a single precision floating point number.
+ * Converts a string to a single precision floating-point number.
*
* The function returns non-zero when conversion is not possible.
* In that case the function sets errno to EINVAL when the reason is an invalid character.
@@ -1516,15 +1415,15 @@ int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep);
* @param str the string to convert
* @param output a pointer to the float variable where the result shall be stored
* @param decsep the decimal separator
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep);
/**
- * Converts a string to a double precision floating point number.
+ * Converts a string to a double precision floating-point number.
*
* The function returns non-zero when conversion is not possible.
* In that case the function sets errno to EINVAL when the reason is an invalid character.
@@ -1533,12 +1432,12 @@ int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep
* @param str the string to convert
* @param output a pointer to the float variable where the result shall be stored
* @param decsep the decimal separator
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
-cx_attr_access_w(2) cx_attr_nonnull_arg(2) cx_attr_export
-int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep);
+cx_attr_access_w(2) cx_attr_nonnull_arg(2)
+CX_EXPORT int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep);
/**
* Converts a string to a number.
@@ -1550,7 +1449,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1566,7 +1465,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1582,7 +1481,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1598,7 +1497,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1614,7 +1513,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1630,7 +1529,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1646,7 +1545,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1662,7 +1561,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1678,7 +1577,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1694,7 +1593,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1710,7 +1609,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1726,7 +1625,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1742,7 +1641,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1758,7 +1657,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1774,7 +1673,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1790,7 +1689,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1806,7 +1705,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the integer variable where the result shall be stored
* @param base 2, 8, 10, or 16
- * @param groupsep (@c const @c char*) each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
@@ -1819,7 +1718,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1837,7 +1736,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1855,7 +1754,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1873,7 +1772,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1891,7 +1790,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1909,7 +1808,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1927,7 +1826,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1945,7 +1844,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1963,7 +1862,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1981,7 +1880,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -1999,7 +1898,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -2017,7 +1916,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -2035,7 +1934,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -2053,7 +1952,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -2071,7 +1970,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -2089,7 +1988,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -2107,7 +2006,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
* It sets errno to ERANGE when the target datatype is too small.
*
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
*
* @param str the string to convert
@@ -2119,7 +2018,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
#define cx_strtou64(str, output, base) cx_strtou64_lc_(cx_strcast(str), output, base, ",")
/**
- * Converts a string to a single precision floating point number.
+ * Converts a string to a single precision floating-point number.
*
* The function returns non-zero when conversion is not possible.
* In that case the function sets errno to EINVAL when the reason is an invalid character.
@@ -2128,14 +2027,14 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the float variable where the result shall be stored
* @param decsep the decimal separator
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
#define cx_strtof_lc(str, output, decsep, groupsep) cx_strtof_lc_(cx_strcast(str), output, decsep, groupsep)
/**
- * Converts a string to a double precision floating point number.
+ * Converts a string to a double precision floating-point number.
*
* The function returns non-zero when conversion is not possible.
* In that case the function sets errno to EINVAL when the reason is an invalid character.
@@ -2143,21 +2042,21 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
* @param str the string to convert
* @param output a pointer to the double variable where the result shall be stored
* @param decsep the decimal separator
- * @param groupsep each character in this string is treated as group separator and ignored during conversion
+ * @param groupsep each character in this string is treated as a group separator and ignored during conversion
* @retval zero success
* @retval non-zero conversion was not possible
*/
#define cx_strtod_lc(str, output, decsep, groupsep) cx_strtod_lc_(cx_strcast(str), output, decsep, groupsep)
/**
- * Converts a string to a single precision floating point number.
+ * Converts a string to a single precision floating-point number.
*
* The function returns non-zero when conversion is not possible.
* In that case the function sets errno to EINVAL when the reason is an invalid character.
* It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h.
*
* The decimal separator is assumed to be a dot character.
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose a different format, use cx_strtof_lc().
*
* @param str the string to convert
@@ -2168,13 +2067,13 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
#define cx_strtof(str, output) cx_strtof_lc_(cx_strcast(str), output, '.', ",")
/**
- * Converts a string to a double precision floating point number.
+ * Converts a string to a double precision floating-point number.
*
* The function returns non-zero when conversion is not possible.
* In that case the function sets errno to EINVAL when the reason is an invalid character.
*
* The decimal separator is assumed to be a dot character.
- * The comma character is treated as group separator and ignored during parsing.
+ * The comma character is treated as a group separator and ignored during parsing.
* If you want to choose a different format, use cx_strtof_lc().
*
* @param str the string to convert
diff --git a/ucx/cx/test.h b/ucx/cx/test.h
index fdd9269..ff86b33 100644
--- a/ucx/cx/test.h
+++ b/ucx/cx/test.h
@@ -56,7 +56,7 @@
* }
*
*
- * @attention Do not call own functions within a test, that use
+ * @attention Do not call own functions within a test that use
* CX_TEST_ASSERT() macros and are not defined by using CX_TEST_SUBROUTINE().
*
* @author Mike Becker
@@ -136,10 +136,7 @@ struct CxTestSuite {
* @param name optional name of the suite
* @return a new test suite
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_cstr_arg(1)
-cx_attr_malloc
+cx_attr_nonnull cx_attr_nodiscard cx_attr_cstr_arg(1) cx_attr_malloc
static inline CxTestSuite* cx_test_suite_new(const char *name) {
CxTestSuite* suite = (CxTestSuite*) malloc(sizeof(CxTestSuite));
if (suite != NULL) {
@@ -157,7 +154,7 @@ static inline CxTestSuite* cx_test_suite_new(const char *name) {
*
* @param suite the test suite to free
*/
-static inline void cx_test_suite_free(CxTestSuite* suite) {
+CX_INLINE void cx_test_suite_free(CxTestSuite* suite) {
if (suite == NULL) return;
CxTestSet *l = suite->tests;
while (l != NULL) {
@@ -171,13 +168,13 @@ static inline void cx_test_suite_free(CxTestSuite* suite) {
/**
* Registers a test function with the specified test suite.
*
- * @param suite the suite, the test function shall be added to
+ * @param suite the suite the test function shall be added to
* @param test the test function to register
* @retval zero success
* @retval non-zero failure
*/
cx_attr_nonnull
-static inline int cx_test_register(CxTestSuite* suite, CxTest test) {
+CX_INLINE int cx_test_register(CxTestSuite* suite, CxTest test) {
CxTestSet *t = (CxTestSet*) malloc(sizeof(CxTestSet));
if (t) {
t->test = test;
@@ -204,8 +201,7 @@ static inline int cx_test_register(CxTestSuite* suite, CxTest test) {
* @param out_writer the write function writing to @p out_target
*/
cx_attr_nonnull
-static inline void cx_test_run(CxTestSuite *suite,
- void *out_target, cx_write_func out_writer) {
+CX_INLINE void cx_test_run(CxTestSuite *suite, void *out_target, cx_write_func out_writer) {
if (suite->name == NULL) {
out_writer("*** Test Suite ***\n", 1, 19, out_target);
} else {
@@ -263,7 +259,7 @@ static inline void cx_test_run(CxTestSuite *suite,
* }
* @endcode
*
- * @attention Any CX_TEST_ASSERT() calls must be performed in scope of
+ * @attention Any CX_TEST_ASSERT() calls must be performed in the scope of
* #CX_TEST_DO.
*/
#define CX_TEST_DO _writefnc_("Running ", 1, 8, _output_);\
diff --git a/ucx/cx/tree.h b/ucx/cx/tree.h
index 14832db..a1412ca 100644
--- a/ucx/cx/tree.h
+++ b/ucx/cx/tree.h
@@ -49,12 +49,12 @@ extern "C" {
*
* This iterator is not position-aware in a strict sense, as it does not assume
* a particular order of elements in the tree. However, the iterator keeps track
- * of the number of nodes it has passed in a counter variable.
+ * of the number of nodes it has passed in a counter-variable.
* Each node, regardless of the number of passes, is counted only once.
*
* @note Objects that are pointed to by an iterator are mutable through that
* iterator. However, if the
- * underlying data structure is mutated by other means than this iterator (e.g.
+ * underlying data structure is mutated by other means than this iterator (e.g.,
* elements added or removed), the iterator becomes invalid (regardless of what
* cxIteratorValid() returns).
*
@@ -71,7 +71,7 @@ typedef struct cx_tree_iterator_s {
bool skip;
/**
* Set to true, when the iterator shall visit a node again
- * when all it's children have been processed.
+ * when all its children have been processed.
*/
bool visit_on_exit;
/**
@@ -97,7 +97,7 @@ typedef struct cx_tree_iterator_s {
*/
void *node;
/**
- * Stores a copy of the next pointer of the visited node.
+ * Stores a copy of the pointer to the successor of the visited node.
* Allows freeing a node on exit without corrupting the iteration.
*/
void *node_next;
@@ -155,12 +155,12 @@ struct cx_tree_visitor_queue_s {
*
* This iterator is not position-aware in a strict sense, as it does not assume
* a particular order of elements in the tree. However, the iterator keeps track
- * of the number of nodes it has passed in a counter variable.
+ * of the number of nodes it has passed in a counter-variable.
* Each node, regardless of the number of passes, is counted only once.
*
* @note Objects that are pointed to by an iterator are mutable through that
* iterator. However, if the
- * underlying data structure is mutated by other means than this iterator (e.g.
+ * underlying data structure is mutated by other means than this iterator (e.g.,
* elements added or removed), the iterator becomes invalid (regardless of what
* cxIteratorValid() returns).
*
@@ -212,24 +212,14 @@ typedef struct cx_tree_visitor_s {
* @param iter the iterator
*/
cx_attr_nonnull
-static inline void cxTreeIteratorDispose(CxTreeIterator *iter) {
- cxFreeDefault(iter->stack);
- iter->stack = NULL;
-}
+CX_EXPORT void cxTreeIteratorDispose(CxTreeIterator *iter);
/**
* Releases internal memory of the given tree visitor.
* @param visitor the visitor
*/
cx_attr_nonnull
-static inline void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
- struct cx_tree_visitor_queue_s *q = visitor->queue_next;
- while (q != NULL) {
- struct cx_tree_visitor_queue_s *next = q->next;
- cxFreeDefault(q);
- q = next;
- }
-}
+CX_EXPORT void cxTreeVisitorDispose(CxTreeVisitor *visitor);
/**
* Advises the iterator to skip the subtree below the current node and
@@ -250,7 +240,7 @@ static inline void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
/**
* Links a node to a (new) parent.
*
- * If the node has already a parent, it is unlinked, first.
+ * If the node already has a parent, it is unlinked, first.
* If the parent has children already, the node is @em appended to the list
* of all currently existing children.
*
@@ -265,16 +255,9 @@ static inline void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
* @see cx_tree_unlink()
*/
cx_attr_nonnull
-cx_attr_export
-void cx_tree_link(
- void *parent,
- void *node,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_tree_link(void *parent, void *node,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Unlinks a node from its parent.
@@ -291,15 +274,9 @@ void cx_tree_link(
* @see cx_tree_link()
*/
cx_attr_nonnull
-cx_attr_export
-void cx_tree_unlink(
- void *node,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+CX_EXPORT void cx_tree_unlink(void *node,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Macro that can be used instead of the magic value for infinite search depth.
@@ -318,8 +295,8 @@ void cx_tree_unlink(
* Zero means exact match and a positive number is an implementation defined
* measure for the distance to an exact match.
*
- * For example if a tree stores file path information, a node that is
- * describing a parent directory of a filename that is searched, shall
+ * For example, consider a tree that stores file path information.
+ * A node which is describing a parent directory of a searched file shall
* return a positive number to indicate that a child node might contain the
* searched item. On the other hand, if the node denotes a path that is not a
* prefix of the searched filename, the function would return -1 to indicate
@@ -330,9 +307,8 @@ void cx_tree_unlink(
*
* @return 0 if the node contains the data,
* positive if one of the children might contain the data,
- * negative if neither the node, nor the children contains the data
+ * negative if neither the node nor the children contains the data
*/
-cx_attr_nonnull
typedef int (*cx_tree_search_data_func)(const void *node, const void *data);
@@ -348,8 +324,8 @@ typedef int (*cx_tree_search_data_func)(const void *node, const void *data);
* Zero means exact match and a positive number is an implementation defined
* measure for the distance to an exact match.
*
- * For example if a tree stores file path information, a node that is
- * describing a parent directory of a filename that is searched, shall
+ * For example, consider a tree that stores file path information.
+ * A node which is describing a parent directory of a searched file shall
* return a positive number to indicate that a child node might contain the
* searched item. On the other hand, if the node denotes a path that is not a
* prefix of the searched filename, the function would return -1 to indicate
@@ -360,19 +336,18 @@ typedef int (*cx_tree_search_data_func)(const void *node, const void *data);
*
* @return 0 if @p node contains the same data as @p new_node,
* positive if one of the children might contain the data,
- * negative if neither the node, nor the children contains the data
+ * negative if neither the node nor the children contains the data
*/
-cx_attr_nonnull
typedef int (*cx_tree_search_func)(const void *node, const void *new_node);
/**
* Searches for data in a tree.
*
- * When the data cannot be found exactly, the search function might return a
- * closest result which might be a good starting point for adding a new node
+ * When the data cannot be found exactly, the search function might return the
+ * closest result, which might be a good starting point for adding a new node
* to the tree (see also #cx_tree_add()).
*
- * Depending on the tree structure it is not necessarily guaranteed that the
+ * Depending on the tree structure, it is not necessarily guaranteed that the
* "closest" match is uniquely defined. This function will search for a node
* with the best match according to the @p sfunc (meaning: the return value of
* @p sfunc which is closest to zero). If that is also ambiguous, an arbitrary
@@ -389,27 +364,19 @@ typedef int (*cx_tree_search_func)(const void *node, const void *new_node);
* could contain the node (but doesn't right now), negative if the tree does not
* contain any node that might be related to the searched data
*/
-cx_attr_nonnull
-cx_attr_access_w(5)
-cx_attr_export
-int cx_tree_search_data(
- const void *root,
- size_t depth,
- const void *data,
- cx_tree_search_data_func sfunc,
- void **result,
- ptrdiff_t loc_children,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull cx_attr_access_w(5)
+CX_EXPORT int cx_tree_search_data(const void *root, size_t depth,
+ const void *data, cx_tree_search_data_func sfunc,
+ void **result, ptrdiff_t loc_children, ptrdiff_t loc_next);
/**
* Searches for a node in a tree.
*
* When no node with the same data can be found, the search function might
- * return a closest result which might be a good starting point for adding the
+ * return the closest result, which might be a good starting point for adding the
* new node to the tree (see also #cx_tree_add()).
*
- * Depending on the tree structure it is not necessarily guaranteed that the
+ * Depending on the tree structure, it is not necessarily guaranteed that the
* "closest" match is uniquely defined. This function will search for a node
* with the best match according to the @p sfunc (meaning: the return value of
* @p sfunc which is closest to zero). If that is also ambiguous, an arbitrary
@@ -426,18 +393,10 @@ int cx_tree_search_data(
* could contain the node (but doesn't right now), negative if the tree does not
* contain any node that might be related to the searched data
*/
-cx_attr_nonnull
-cx_attr_access_w(5)
-cx_attr_export
-int cx_tree_search(
- const void *root,
- size_t depth,
- const void *node,
- cx_tree_search_func sfunc,
- void **result,
- ptrdiff_t loc_children,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull cx_attr_access_w(5)
+CX_EXPORT int cx_tree_search(const void *root, size_t depth,
+ const void *node, cx_tree_search_func sfunc,
+ void **result, ptrdiff_t loc_children, ptrdiff_t loc_next);
/**
* Creates a depth-first iterator for a tree with the specified root node.
@@ -460,13 +419,8 @@ int cx_tree_search(
* @see cxTreeIteratorDispose()
*/
cx_attr_nodiscard
-cx_attr_export
-CxTreeIterator cx_tree_iterator(
- void *root,
- bool visit_on_exit,
- ptrdiff_t loc_children,
- ptrdiff_t loc_next
-);
+CX_EXPORT CxTreeIterator cx_tree_iterator(void *root, bool visit_on_exit,
+ ptrdiff_t loc_children, ptrdiff_t loc_next);
/**
* Creates a breadth-first iterator for a tree with the specified root node.
@@ -487,24 +441,19 @@ CxTreeIterator cx_tree_iterator(
* @see cxTreeVisitorDispose()
*/
cx_attr_nodiscard
-cx_attr_export
-CxTreeVisitor cx_tree_visitor(
- void *root,
- ptrdiff_t loc_children,
- ptrdiff_t loc_next
-);
+CX_EXPORT CxTreeVisitor cx_tree_visitor(void *root,
+ ptrdiff_t loc_children, ptrdiff_t loc_next);
/**
* Describes a function that creates a tree node from the specified data.
- * The first argument points to the data the node shall contain and
- * the second argument may be used for additional data (e.g. an allocator).
+ * The first argument points to the data the node shall contain, and
+ * the second argument may be used for additional data (e.g., an allocator).
* Functions of this type shall either return a new pointer to a newly
* created node or @c NULL when allocation fails.
*
* @note the function may leave the node pointers in the struct uninitialized.
* The caller is responsible to set them according to the intended use case.
*/
-cx_attr_nonnull_arg(1)
typedef void *(*cx_tree_node_create_func)(const void *, void *);
/**
@@ -513,8 +462,7 @@ typedef void *(*cx_tree_node_create_func)(const void *, void *);
* This variable is used by #cx_tree_add_array() and #cx_tree_add_iter() to
* implement optimized insertion of multiple elements into a tree.
*/
-cx_attr_export
-extern unsigned int cx_tree_add_look_around_depth;
+CX_EXPORT extern unsigned int cx_tree_add_look_around_depth;
/**
* Adds multiple elements efficiently to a tree.
@@ -554,23 +502,12 @@ extern unsigned int cx_tree_add_look_around_depth;
* @return the number of nodes created and added
* @see cx_tree_add()
*/
-cx_attr_nonnull_arg(1, 3, 4, 6, 7)
-cx_attr_access_w(6)
-cx_attr_export
-size_t cx_tree_add_iter(
- struct cx_iterator_base_s *iter,
- size_t num,
- cx_tree_search_func sfunc,
- cx_tree_node_create_func cfunc,
- void *cdata,
- void **failed,
- void *root,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull_arg(1, 3, 4, 6, 7) cx_attr_access_w(6)
+CX_EXPORT size_t cx_tree_add_iter(struct cx_iterator_base_s *iter, size_t num,
+ cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
+ void *cdata, void **failed, void *root,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Adds multiple elements efficiently to a tree.
@@ -609,24 +546,12 @@ size_t cx_tree_add_iter(
* @return the number of array elements successfully processed
* @see cx_tree_add()
*/
-cx_attr_nonnull_arg(1, 4, 5, 7, 8)
-cx_attr_access_w(7)
-cx_attr_export
-size_t cx_tree_add_array(
- const void *src,
- size_t num,
- size_t elem_size,
- cx_tree_search_func sfunc,
- cx_tree_node_create_func cfunc,
- void *cdata,
- void **failed,
- void *root,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull_arg(1, 4, 5, 7, 8) cx_attr_access_w(7)
+CX_EXPORT size_t cx_tree_add_array(const void *src, size_t num, size_t elem_size,
+ cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
+ void *cdata, void **failed, void *root,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Adds data to a tree.
@@ -637,17 +562,17 @@ size_t cx_tree_add_array(
* When a location is found, the @p cfunc will be invoked with @p cdata.
*
* The node returned by @p cfunc will be linked into the tree.
- * When @p sfunc returned a positive integer, the new node will be linked as a
+ * When @p sfunc returns a positive integer, the new node will be linked as a
* child. The other children (now siblings of the new node) are then checked
* with @p sfunc, whether they could be children of the new node and re-linked
* accordingly.
*
- * When @p sfunc returned zero and the found node has a parent, the new
- * node will be added as sibling - otherwise, the new node will be added
+ * When @p sfunc returns zero and the found node has a parent, the new
+ * node will be added as a sibling - otherwise, the new node will be added
* as a child.
*
- * When @p sfunc returned a negative value, the new node will not be added to
- * the tree and this function returns a non-zero value.
+ * When @p sfunc returns a negative value, the new node will not be added to
+ * the tree, and this function returns a non-zero value.
* The caller should check if @p cnode contains a node pointer and deal with the
* node that could not be added.
*
@@ -673,22 +598,12 @@ size_t cx_tree_add_array(
* @return zero when a new node was created and added to the tree,
* non-zero otherwise
*/
-cx_attr_nonnull_arg(1, 2, 3, 5, 6)
-cx_attr_access_w(5)
-cx_attr_export
-int cx_tree_add(
- const void *src,
- cx_tree_search_func sfunc,
- cx_tree_node_create_func cfunc,
- void *cdata,
- void **cnode,
- void *root,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull_arg(1, 2, 3, 5, 6) cx_attr_access_w(5)
+CX_EXPORT int cx_tree_add(const void *src,
+ cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
+ void *cdata, void **cnode, void *root,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
@@ -747,9 +662,9 @@ struct cx_tree_s {
* A function to create new nodes.
*
* Invocations to this function will receive a pointer to this tree
- * structure as second argument.
+ * structure as the second argument.
*
- * Nodes MAY use #cx_tree_node_base_s as base layout, but do not need to.
+ * Nodes MAY use #cx_tree_node_base_s as the base layout, but do not need to.
*/
cx_tree_node_create_func node_create;
@@ -814,7 +729,7 @@ struct cx_tree_s {
* Macro to roll out the #cx_tree_node_base_s structure with a custom
* node type.
*
- * Must be used as first member in your custom tree struct.
+ * Must be used as the first member in your custom tree struct.
*
* @param type the data type for the nodes
*/
@@ -850,32 +765,20 @@ struct cx_tree_class_s {
* Implementations SHALL NOT simply invoke @p insert_many as this comes
* with too much overhead.
*/
- int (*insert_element)(
- struct cx_tree_s *tree,
- const void *data
- );
+ int (*insert_element)(struct cx_tree_s *tree, const void *data);
/**
* Member function for inserting multiple elements.
*
- * Implementations SHALL avoid to perform a full search in the tree for
+ * Implementations SHALL avoid performing a full search in the tree for
* every element even though the source data MAY be unsorted.
*/
- size_t (*insert_many)(
- struct cx_tree_s *tree,
- struct cx_iterator_base_s *iter,
- size_t n
- );
+ size_t (*insert_many)(struct cx_tree_s *tree, struct cx_iterator_base_s *iter, size_t n);
/**
* Member function for finding a node.
*/
- void *(*find)(
- struct cx_tree_s *tree,
- const void *subtree,
- const void *data,
- size_t depth
- );
+ void *(*find)(struct cx_tree_s *tree, const void *subtree, const void *data, size_t depth);
};
/**
@@ -885,7 +788,7 @@ typedef struct cx_tree_s CxTree;
/**
- * Destroys a node and it's subtree.
+ * Destroys a node and its subtree.
*
* It is guaranteed that the simple destructor is invoked before
* the advanced destructor, starting with the leaf nodes of the subtree.
@@ -906,8 +809,7 @@ typedef struct cx_tree_s CxTree;
* @see cxTreeFree()
*/
cx_attr_nonnull
-cx_attr_export
-void cxTreeDestroySubtree(CxTree *tree, void *node);
+CX_EXPORT void cxTreeDestroySubtree(CxTree *tree, void *node);
/**
@@ -921,7 +823,7 @@ void cxTreeDestroySubtree(CxTree *tree, void *node);
*
* @attention Be careful when calling this function when no destructor function
* is registered that actually frees the memory of nodes. In that case you will
- * need a reference to the (former) root node of the tree somewhere or
+ * need a reference to the (former) root node of the tree somewhere, or
* otherwise you will be leaking memory.
*
* @param tree the tree
@@ -945,8 +847,7 @@ void cxTreeDestroySubtree(CxTree *tree, void *node);
*
* @param tree the tree to free
*/
-cx_attr_export
-void cxTreeFree(CxTree *tree);
+CX_EXPORT void cxTreeFree(CxTree *tree);
/**
* Creates a new tree structure based on the specified layout.
@@ -972,29 +873,18 @@ void cxTreeFree(CxTree *tree);
* @see cxTreeCreateSimple()
* @see cxTreeCreateWrapped()
*/
-cx_attr_nonnull_arg(2, 3, 4)
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc(cxTreeFree, 1)
-cx_attr_export
-CxTree *cxTreeCreate(
- const CxAllocator *allocator,
- cx_tree_node_create_func create_func,
- cx_tree_search_func search_func,
- cx_tree_search_data_func search_data_func,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull_arg(2, 3, 4) cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxTreeFree, 1)
+CX_EXPORT CxTree *cxTreeCreate(const CxAllocator *allocator, cx_tree_node_create_func create_func,
+ cx_tree_search_func search_func, cx_tree_search_data_func search_data_func,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Creates a new tree structure based on a default layout.
*
- * Nodes created by @p create_func MUST contain #cx_tree_node_base_s as first
+ * Nodes created by @p create_func MUST contain #cx_tree_node_base_s as the first
* member (or at least respect the default offsets specified in the tree
- * struct) and they MUST be allocated with the specified allocator.
+ * struct), and they MUST be allocated with the specified allocator.
*
* @note This function will also register an advanced destructor which
* will free the nodes with the allocator's free() method.
@@ -1006,10 +896,8 @@ CxTree *cxTreeCreate(
* @return (@c CxTree*) the new tree
* @see cxTreeCreate()
*/
-#define cxTreeCreateSimple(\
- allocator, create_func, search_func, search_data_func \
-) cxTreeCreate(allocator, create_func, search_func, search_data_func, \
-cx_tree_node_base_layout)
+#define cxTreeCreateSimple(allocator, create_func, search_func, search_data_func) \
+ cxTreeCreate(allocator, create_func, search_func, search_data_func, cx_tree_node_base_layout)
/**
* Creates a new tree structure based on an existing tree.
@@ -1019,7 +907,7 @@ cx_tree_node_base_layout)
* @attention This function will create an incompletely defined tree structure
* where neither the create function, the search function, nor a destructor
* will be set. If you wish to use any of this functionality for the wrapped
- * tree, you need to specify those functions afterwards.
+ * tree, you need to specify those functions afterward.
*
* @param allocator the allocator that was used for nodes of the wrapped tree
* (if @c NULL, the cxDefaultAllocator is assumed)
@@ -1033,20 +921,10 @@ cx_tree_node_base_layout)
* @return the new tree
* @see cxTreeCreate()
*/
-cx_attr_nonnull_arg(2)
-cx_attr_nodiscard
-cx_attr_malloc
-cx_attr_dealloc(cxTreeFree, 1)
-cx_attr_export
-CxTree *cxTreeCreateWrapped(
- const CxAllocator *allocator,
- void *root,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-);
+cx_attr_nonnull_arg(2) cx_attr_nodiscard cx_attr_malloc cx_attr_dealloc(cxTreeFree, 1)
+CX_EXPORT CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next);
/**
* Inserts data into the tree.
@@ -1061,12 +939,7 @@ CxTree *cxTreeCreateWrapped(
* @retval non-zero failure
*/
cx_attr_nonnull
-static inline int cxTreeInsert(
- CxTree *tree,
- const void *data
-) {
- return tree->cl->insert_element(tree, data);
-}
+CX_EXPORT int cxTreeInsert(CxTree *tree, const void *data);
/**
* Inserts elements provided by an iterator efficiently into the tree.
@@ -1081,13 +954,7 @@ static inline int cxTreeInsert(
* @return the number of elements that could be successfully inserted
*/
cx_attr_nonnull
-static inline size_t cxTreeInsertIter(
- CxTree *tree,
- CxIteratorBase *iter,
- size_t n
-) {
- return tree->cl->insert_many(tree, iter, n);
-}
+CX_EXPORT size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n);
/**
* Inserts an array of data efficiently into the tree.
@@ -1103,17 +970,7 @@ static inline size_t cxTreeInsertIter(
* @return the number of elements that could be successfully inserted
*/
cx_attr_nonnull
-static inline size_t cxTreeInsertArray(
- CxTree *tree,
- const void *data,
- size_t elem_size,
- size_t n
-) {
- if (n == 0) return 0;
- if (n == 1) return 0 == cxTreeInsert(tree, data) ? 1 : 0;
- CxIterator iter = cxIterator(data, elem_size, n);
- return cxTreeInsertIter(tree, cxIteratorRef(iter), n);
-}
+CX_EXPORT size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n);
/**
* Searches the data in the specified tree.
@@ -1126,14 +983,8 @@ static inline size_t cxTreeInsertArray(
* @param data the data to search for
* @return the first matching node, or @c NULL when the data cannot be found
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cxTreeFind(
- CxTree *tree,
- const void *data
-) {
- return tree->cl->find(tree, tree->root, data, 0);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT void *cxTreeFind(CxTree *tree, const void *data);
/**
* Searches the data in the specified subtree.
@@ -1154,16 +1005,8 @@ static inline void *cxTreeFind(
* @param max_depth the maximum search depth
* @return the first matching node, or @c NULL when the data cannot be found
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline void *cxTreeFindInSubtree(
- CxTree *tree,
- const void *data,
- void *subtree_root,
- size_t max_depth
-) {
- return tree->cl->find(tree, subtree_root, data, max_depth);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth);
/**
* Determines the size of the specified subtree.
@@ -1172,10 +1015,8 @@ static inline void *cxTreeFindInSubtree(
* @param subtree_root the root node of the subtree
* @return the number of nodes in the specified subtree
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root);
/**
* Determines the depth of the specified subtree.
@@ -1184,10 +1025,8 @@ size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root);
* @param subtree_root the root node of the subtree
* @return the tree depth including the @p subtree_root
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root);
/**
* Determines the size of the entire tree.
@@ -1195,11 +1034,8 @@ size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root);
* @param tree the tree
* @return the tree size, counting the root as one
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline size_t cxTreeSize(CxTree *tree) {
- return tree->size;
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT size_t cxTreeSize(CxTree *tree);
/**
* Determines the depth of the entire tree.
@@ -1207,10 +1043,8 @@ static inline size_t cxTreeSize(CxTree *tree) {
* @param tree the tree
* @return the tree depth, counting the root as one
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-cx_attr_export
-size_t cxTreeDepth(CxTree *tree);
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT size_t cxTreeDepth(CxTree *tree);
/**
* Creates a depth-first iterator for the specified tree starting in @p node.
@@ -1224,18 +1058,8 @@ size_t cxTreeDepth(CxTree *tree);
* @return a tree iterator (depth-first)
* @see cxTreeVisit()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline CxTreeIterator cxTreeIterateSubtree(
- CxTree *tree,
- void *node,
- bool visit_on_exit
-) {
- return cx_tree_iterator(
- node, visit_on_exit,
- tree->loc_children, tree->loc_next
- );
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit);
/**
* Creates a breadth-first iterator for the specified tree starting in @p node.
@@ -1247,13 +1071,8 @@ static inline CxTreeIterator cxTreeIterateSubtree(
* @return a tree visitor (a.k.a. breadth-first iterator)
* @see cxTreeIterate()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) {
- return cx_tree_visitor(
- node, tree->loc_children, tree->loc_next
- );
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node);
/**
* Creates a depth-first iterator for the specified tree.
@@ -1264,14 +1083,8 @@ static inline CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) {
* @return a tree iterator (depth-first)
* @see cxTreeVisit()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline CxTreeIterator cxTreeIterate(
- CxTree *tree,
- bool visit_on_exit
-) {
- return cxTreeIterateSubtree(tree, tree->root, visit_on_exit);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CX_EXPORT CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit);
/**
* Creates a breadth-first iterator for the specified tree.
@@ -1280,16 +1093,13 @@ static inline CxTreeIterator cxTreeIterate(
* @return a tree visitor (a.k.a. breadth-first iterator)
* @see cxTreeIterate()
*/
-cx_attr_nonnull
-cx_attr_nodiscard
-static inline CxTreeVisitor cxTreeVisit(CxTree *tree) {
- return cxTreeVisitSubtree(tree, tree->root);
-}
+cx_attr_nonnull cx_attr_nodiscard
+CxTreeVisitor cxTreeVisit(CxTree *tree);
/**
* Sets the (new) parent of the specified child.
*
- * If the @p child is not already member of the tree, this function behaves
+ * If the @p child is not already a member of the tree, this function behaves
* as #cxTreeAddChildNode().
*
* @param tree the tree
@@ -1298,21 +1108,16 @@ static inline CxTreeVisitor cxTreeVisit(CxTree *tree) {
* @see cxTreeAddChildNode()
*/
cx_attr_nonnull
-cx_attr_export
-void cxTreeSetParent(
- CxTree *tree,
- void *parent,
- void *child
-);
+CX_EXPORT void cxTreeSetParent(CxTree *tree, void *parent, void *child);
/**
* Adds a new node to the tree.
*
- * If the @p child is already member of the tree, the behavior is undefined.
+ * If the @p child is already a member of the tree, the behavior is undefined.
* Use #cxTreeSetParent() if you want to move a subtree to another location.
*
* @attention The node may be externally created, but MUST obey the same rules
- * as if it was created by the tree itself with #cxTreeAddChild() (e.g. use
+ * as if it was created by the tree itself with #cxTreeAddChild() (e.g., use
* the same allocator).
*
* @param tree the tree
@@ -1321,12 +1126,7 @@ void cxTreeSetParent(
* @see cxTreeSetParent()
*/
cx_attr_nonnull
-cx_attr_export
-void cxTreeAddChildNode(
- CxTree *tree,
- void *parent,
- void *child
-);
+CX_EXPORT void cxTreeAddChildNode(CxTree *tree, void *parent, void *child);
/**
* Creates a new node and adds it to the tree.
@@ -1336,7 +1136,7 @@ void cxTreeAddChildNode(
* leaving this task to the tree by using #cxTreeInsert().
*
* Be aware that adding nodes at arbitrary locations in the tree might cause
- * wrong or undesired results when subsequently invoking #cxTreeInsert() and
+ * wrong or undesired results when subsequently invoking #cxTreeInsert(), and
* the invariant imposed by the search function does not hold any longer.
*
* @param tree the tree
@@ -1346,12 +1146,7 @@ void cxTreeAddChildNode(
* @see cxTreeInsert()
*/
cx_attr_nonnull
-cx_attr_export
-int cxTreeAddChild(
- CxTree *tree,
- void *parent,
- const void *data
-);
+CX_EXPORT int cxTreeAddChild(CxTree *tree, void *parent, const void *data);
/**
* A function that is invoked when a node needs to be re-linked to a new parent.
@@ -1365,7 +1160,6 @@ int cxTreeAddChild(
* @param old_parent the old parent of the node
* @param new_parent the new parent of the node
*/
-cx_attr_nonnull
typedef void (*cx_tree_relink_func)(
void *node,
const void *old_parent,
@@ -1387,15 +1181,10 @@ typedef void (*cx_tree_relink_func)(
* @return zero on success, non-zero if @p node is the root node of the tree
*/
cx_attr_nonnull_arg(1, 2)
-cx_attr_export
-int cxTreeRemoveNode(
- CxTree *tree,
- void *node,
- cx_tree_relink_func relink_func
-);
+CX_EXPORT int cxTreeRemoveNode(CxTree *tree, void *node, cx_tree_relink_func relink_func);
/**
- * Removes a node and it's subtree from the tree.
+ * Removes a node and its subtree from the tree.
*
* If the node is not part of the tree, the behavior is undefined.
*
@@ -1406,8 +1195,7 @@ int cxTreeRemoveNode(
* @param node the node to remove
*/
cx_attr_nonnull
-cx_attr_export
-void cxTreeRemoveSubtree(CxTree *tree, void *node);
+CX_EXPORT void cxTreeRemoveSubtree(CxTree *tree, void *node);
/**
* Destroys a node and re-links its children to its former parent.
@@ -1428,12 +1216,7 @@ void cxTreeRemoveSubtree(CxTree *tree, void *node);
* @return zero on success, non-zero if @p node is the root node of the tree
*/
cx_attr_nonnull_arg(1, 2)
-cx_attr_export
-int cxTreeDestroyNode(
- CxTree *tree,
- void *node,
- cx_tree_relink_func relink_func
-);
+CX_EXPORT int cxTreeDestroyNode(CxTree *tree, void *node, cx_tree_relink_func relink_func);
#ifdef __cplusplus
} // extern "C"
diff --git a/ucx/hash_key.c b/ucx/hash_key.c
index fac29bb..25f8c4b 100644
--- a/ucx/hash_key.c
+++ b/ucx/hash_key.c
@@ -27,6 +27,7 @@
*/
#include "cx/hash_key.h"
+#include "cx/compare.h"
#include
void cx_hash_murmur(CxHashKey *key) {
@@ -62,14 +63,14 @@ void cx_hash_murmur(CxHashKey *key) {
switch (len) {
case 3:
h ^= (data[i + 2] & 0xFF) << 16;
- __attribute__((__fallthrough__));
+ cx_attr_fallthrough;
case 2:
h ^= (data[i + 1] & 0xFF) << 8;
- __attribute__((__fallthrough__));
+ cx_attr_fallthrough;
case 1:
h ^= (data[i + 0] & 0xFF);
h *= m;
- __attribute__((__fallthrough__));
+ cx_attr_fallthrough;
default: // do nothing
;
}
@@ -81,6 +82,21 @@ void cx_hash_murmur(CxHashKey *key) {
key->hash = h;
}
+
+uint32_t cx_hash_u32(uint32_t x) {
+ x = ((x >> 16) ^ x) * 0x45d9f3bu;
+ x = ((x >> 16) ^ x) * 0x45d9f3bu;
+ x = (x >> 16) ^ x;
+ return x;
+}
+
+uint64_t cx_hash_u64(uint64_t x) {
+ x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
+ x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
+ x = x ^ (x >> 31);
+ return x;
+}
+
CxHashKey cx_hash_key_str(const char *str) {
CxHashKey key;
key.data = str;
@@ -89,6 +105,22 @@ CxHashKey cx_hash_key_str(const char *str) {
return key;
}
+CxHashKey cx_hash_key_ustr(unsigned const char *str) {
+ CxHashKey key;
+ key.data = str;
+ key.len = str == NULL ? 0 : strlen((const char*)str);
+ cx_hash_murmur(&key);
+ return key;
+}
+
+CxHashKey cx_hash_key_cxstr(cxstring str) {
+ return cx_hash_key(str.ptr, str.length);
+}
+
+CxHashKey cx_hash_key_mutstr(cxmutstr str) {
+ return cx_hash_key(str.ptr, str.length);
+}
+
CxHashKey cx_hash_key_bytes(
const unsigned char *bytes,
size_t len
@@ -110,3 +142,29 @@ CxHashKey cx_hash_key(
cx_hash_murmur(&key);
return key;
}
+
+CxHashKey cx_hash_key_u32(uint32_t x) {
+ CxHashKey key;
+ key.data = NULL;
+ key.len = 0;
+ key.hash = cx_hash_u32(x);
+ return key;
+}
+
+CxHashKey cx_hash_key_u64(uint64_t x) {
+ CxHashKey key;
+ key.data = NULL;
+ key.len = 0;
+ key.hash = cx_hash_u64(x);
+ return key;
+}
+
+int cx_hash_key_cmp(const CxHashKey *left, const CxHashKey *right) {
+ int d;
+ d = cx_vcmp_uint64(left->hash, right->hash);
+ if (d != 0) return d;
+ d = cx_vcmp_size(left->len, right->len);
+ if (d != 0) return d;
+ if (left->len == 0) return 0;
+ return memcmp(left->data, right->data, left->len);
+}
diff --git a/ucx/hash_map.c b/ucx/hash_map.c
index 1721e8c..82ae21e 100644
--- a/ucx/hash_map.c
+++ b/ucx/hash_map.c
@@ -78,7 +78,7 @@ static void cx_hash_map_destructor(struct cx_map_s *map) {
cxFree(map->collection.allocator, map);
}
-static int cx_hash_map_put(
+static void *cx_hash_map_put(
CxMap *map,
CxHashKey key,
void *value
@@ -101,11 +101,12 @@ static int cx_hash_map_put(
elm = elm->next;
}
- if (elm != NULL && elm->key.hash == hash && elm->key.len == key.len &&
- memcmp(elm->key.data, key.data, key.len) == 0) {
+ if (elm != NULL && cx_hash_key_cmp(&elm->key, &key) == 0) {
// overwrite existing element, but call destructors first
cx_invoke_destructor(map, elm->data);
- if (map->collection.store_pointer) {
+ if (value == NULL) {
+ memset(elm->data, 0, map->collection.elem_size);
+ } else if (map->collection.store_pointer) {
memcpy(elm->data, &value, sizeof(void *));
} else {
memcpy(elm->data, value, map->collection.elem_size);
@@ -116,10 +117,12 @@ static int cx_hash_map_put(
allocator,
sizeof(struct cx_hash_map_element_s) + map->collection.elem_size
);
- if (e == NULL) return -1;
+ if (e == NULL) return NULL;
// write the value
- if (map->collection.store_pointer) {
+ if (value == NULL) {
+ memset(e->data, 0, map->collection.elem_size);
+ } else if (map->collection.store_pointer) {
memcpy(e->data, &value, sizeof(void *));
} else {
memcpy(e->data, value, map->collection.elem_size);
@@ -127,7 +130,10 @@ static int cx_hash_map_put(
// copy the key
void *kd = cxMalloc(allocator, key.len);
- if (kd == NULL) return -1;
+ if (kd == NULL) {
+ cxFree(allocator, e);
+ return NULL;
+ }
memcpy(kd, key.data, key.len);
e->key.data = kd;
e->key.len = key.len;
@@ -140,12 +146,14 @@ static int cx_hash_map_put(
prev->next = e;
}
e->next = elm;
+ elm = e;
// increase the size
map->collection.size++;
}
- return 0;
+ // return pointer to the element
+ return elm->data;
}
static void cx_hash_map_unlink(
@@ -205,27 +213,25 @@ static int cx_hash_map_get_remove(
struct cx_hash_map_element_s *elm = hash_map->buckets[slot];
struct cx_hash_map_element_s *prev = NULL;
while (elm && elm->key.hash <= hash) {
- if (elm->key.hash == hash && elm->key.len == key.len) {
- if (memcmp(elm->key.data, key.data, key.len) == 0) {
- if (remove) {
- if (targetbuf == NULL) {
- cx_invoke_destructor(map, elm->data);
- } else {
- memcpy(targetbuf, elm->data, map->collection.elem_size);
- }
- cx_hash_map_unlink(hash_map, slot, prev, elm);
+ if (cx_hash_key_cmp(&elm->key, &key) == 0) {
+ if (remove) {
+ if (targetbuf == NULL) {
+ cx_invoke_destructor(map, elm->data);
+ } else {
+ memcpy(targetbuf, elm->data, map->collection.elem_size);
+ }
+ cx_hash_map_unlink(hash_map, slot, prev, elm);
+ } else {
+ assert(targetbuf != NULL);
+ void *data = NULL;
+ if (map->collection.store_pointer) {
+ data = *(void **) elm->data;
} else {
- assert(targetbuf != NULL);
- void *data = NULL;
- if (map->collection.store_pointer) {
- data = *(void **) elm->data;
- } else {
- data = elm->data;
- }
- memcpy(targetbuf, &data, sizeof(void *));
+ data = elm->data;
}
- return 0;
+ memcpy(targetbuf, &data, sizeof(void *));
}
+ return 0;
}
prev = elm;
elm = prev->next;
@@ -260,19 +266,12 @@ static void *cx_hash_map_iter_current_entry(const void *it) {
static void *cx_hash_map_iter_current_key(const void *it) {
const CxMapIterator *iter = it;
- struct cx_hash_map_element_s *elm = iter->elem;
- return &elm->key;
+ return (void*) iter->entry.key;
}
static void *cx_hash_map_iter_current_value(const void *it) {
const CxMapIterator *iter = it;
- const CxMap *map = iter->map.c;
- struct cx_hash_map_element_s *elm = iter->elem;
- if (map->collection.store_pointer) {
- return *(void **) elm->data;
- } else {
- return elm->data;
- }
+ return iter->entry.value;
}
static bool cx_hash_map_iter_valid(const void *it) {
@@ -282,7 +281,7 @@ static bool cx_hash_map_iter_valid(const void *it) {
static void cx_hash_map_iter_next(void *it) {
CxMapIterator *iter = it;
- CxMap *map = iter->map.m;
+ CxMap *map = iter->map;
struct cx_hash_map_s *hmap = (struct cx_hash_map_s *) map;
struct cx_hash_map_element_s *elm = iter->elem;
@@ -309,6 +308,7 @@ static void cx_hash_map_iter_next(void *it) {
// unlink
cx_hash_map_unlink(hmap, iter->slot, prev, elm);
+ iter->elem_count--;
// advance
elm = next;
@@ -329,7 +329,7 @@ static void cx_hash_map_iter_next(void *it) {
// must not modify the iterator (the parameter is const)
if (elm != NULL) {
iter->entry.key = &elm->key;
- if (iter->map.c->collection.store_pointer) {
+ if (map->collection.store_pointer) {
iter->entry.value = *(void **) elm->data;
} else {
iter->entry.value = elm->data;
@@ -343,7 +343,7 @@ static CxMapIterator cx_hash_map_iterator(
) {
CxMapIterator iter;
- iter.map.c = map;
+ iter.map = (CxMap*) map;
iter.elem_count = map->collection.size;
switch (type) {
@@ -366,7 +366,7 @@ static CxMapIterator cx_hash_map_iterator(
iter.base.valid = cx_hash_map_iter_valid;
iter.base.next = cx_hash_map_iter_next;
iter.base.remove = false;
- iter.base.mutating = false;
+ iter.base.allow_remove = true;
iter.slot = 0;
iter.index = 0;
diff --git a/ucx/iterator.c b/ucx/iterator.c
index 6a78a69..292c11e 100644
--- a/ucx/iterator.c
+++ b/ucx/iterator.c
@@ -53,7 +53,7 @@ static void cx_iter_next_fast(void *it) {
// only move the last element when we are not currently aiming
// at the last element already
if (iter->index < iter->elem_count) {
- void *last = ((char *) iter->src_handle.m)
+ void *last = ((char *) iter->src_handle)
+ iter->elem_count * iter->elem_size;
memcpy(iter->elem_handle, last, iter->elem_size);
}
@@ -84,8 +84,8 @@ static void cx_iter_next_slow(void *it) {
}
}
-CxIterator cxMutIterator(
- void *array,
+CxIterator cxIterator(
+ const void *array,
size_t elem_size,
size_t elem_count,
bool remove_keeps_order
@@ -93,44 +93,25 @@ CxIterator cxMutIterator(
CxIterator iter;
iter.index = 0;
- iter.src_handle.m = array;
- iter.elem_handle = array;
+ iter.src_handle = (void*) array;
+ iter.elem_handle = (void*) array;
iter.elem_size = elem_size;
iter.elem_count = array == NULL ? 0 : elem_count;
iter.base.valid = cx_iter_valid;
iter.base.current = cx_iter_current;
iter.base.next = remove_keeps_order ? cx_iter_next_slow : cx_iter_next_fast;
iter.base.remove = false;
- iter.base.mutating = true;
+ iter.base.allow_remove = true;
return iter;
}
-CxIterator cxIterator(
+CxIterator cxIteratorPtr(
const void *array,
- size_t elem_size,
- size_t elem_count
-) {
- CxIterator iter = cxMutIterator((void*)array, elem_size, elem_count, false);
- iter.base.mutating = false;
- return iter;
-}
-
-CxIterator cxMutIteratorPtr(
- void *array,
size_t elem_count,
bool remove_keeps_order
) {
- CxIterator iter = cxMutIterator(array, sizeof(void*), elem_count, remove_keeps_order);
+ CxIterator iter = cxIterator(array, sizeof(void*), elem_count, remove_keeps_order);
iter.base.current = cx_iter_current_ptr;
return iter;
}
-
-CxIterator cxIteratorPtr(
- const void *array,
- size_t elem_count
-) {
- CxIterator iter = cxMutIteratorPtr((void*) array, elem_count, false);
- iter.base.mutating = false;
- return iter;
-}
diff --git a/ucx/json.c b/ucx/json.c
index 484c7d3..caf1c72 100644
--- a/ucx/json.c
+++ b/ucx/json.c
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
/*
* RFC 8259
@@ -46,22 +47,17 @@ static int json_cmp_objvalue(const void *l, const void *r) {
return cx_strcmp(cx_strcast(left->name), cx_strcast(right->name));
}
-static CxJsonObjValue *json_find_objvalue(const CxJsonValue *obj, cxstring name) {
+static size_t json_find_objvalue(const CxJsonValue *obj, cxstring name) {
assert(obj->type == CX_JSON_OBJECT);
CxJsonObjValue kv_dummy;
kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length);
- size_t index = cx_array_binary_search(
+ return cx_array_binary_search(
obj->value.object.values,
obj->value.object.values_size,
sizeof(CxJsonObjValue),
&kv_dummy,
json_cmp_objvalue
);
- if (index == obj->value.object.values_size) {
- return NULL;
- } else {
- return &obj->value.object.values[index];
- }
}
static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) {
@@ -132,16 +128,6 @@ static void token_destroy(CxJsonToken *token) {
}
}
-static bool json_isdigit(char c) {
- // TODO: remove once UCX has public API for this
- return c >= '0' && c <= '9';
-}
-
-static bool json_isspace(char c) {
- // TODO: remove once UCX has public API for this
- return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f';
-}
-
static int num_isexp(const char *content, size_t length, size_t pos) {
if (pos >= length) {
return 0;
@@ -150,7 +136,7 @@ static int num_isexp(const char *content, size_t length, size_t pos) {
int ok = 0;
for (size_t i = pos; i < length; i++) {
char c = content[i];
- if (json_isdigit(c)) {
+ if (isdigit((unsigned char)c)) {
ok = 1;
} else if (i == pos) {
if (!(c == '+' || c == '-')) {
@@ -167,7 +153,7 @@ static int num_isexp(const char *content, size_t length, size_t pos) {
static CxJsonTokenType token_numbertype(const char *content, size_t length) {
if (length == 0) return CX_JSON_TOKEN_ERROR;
- if (content[0] != '-' && !json_isdigit(content[0])) {
+ if (content[0] != '-' && !isdigit((unsigned char)content[0])) {
return CX_JSON_TOKEN_ERROR;
}
@@ -180,7 +166,7 @@ static CxJsonTokenType token_numbertype(const char *content, size_t length) {
type = CX_JSON_TOKEN_NUMBER;
} else if (content[i] == 'e' || content[i] == 'E') {
return num_isexp(content, length, i + 1) ? CX_JSON_TOKEN_NUMBER : CX_JSON_TOKEN_ERROR;
- } else if (!json_isdigit(content[i])) {
+ } else if (!isdigit((unsigned char)content[i])) {
return CX_JSON_TOKEN_ERROR; // char is not a digit, decimal separator or exponent sep
}
}
@@ -244,7 +230,7 @@ static CxJsonTokenType char2ttype(char c) {
return CX_JSON_TOKEN_STRING;
}
default: {
- if (json_isspace(c)) {
+ if (isspace((unsigned char)c)) {
return CX_JSON_TOKEN_SPACE;
}
}
@@ -644,6 +630,12 @@ void cxJsonDestroy(CxJson *json) {
}
}
+void cxJsonReset(CxJson *json) {
+ const CxAllocator *allocator = json->allocator;
+ cxJsonDestroy(json);
+ cxJsonInit(json, allocator);
+}
+
int cxJsonFilln(CxJson *json, const char *buf, size_t size) {
if (cxBufferEof(&json->buffer)) {
// reinitialize the buffer
@@ -1126,10 +1118,53 @@ CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) {
return value->value.array.array[index];
}
+CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
+ if (index >= value->value.array.array_size) {
+ return NULL;
+ }
+ CxJsonValue *ret = value->value.array.array[index];
+ // TODO: replace with a low level cx_array_remove()
+ size_t count = value->value.array.array_size - index - 1;
+ if (count > 0) {
+ memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*));
+ }
+ value->value.array.array_size--;
+ return ret;
+}
+
+char *cxJsonAsString(const CxJsonValue *value) {
+ return value->value.string.ptr;
+}
+
+cxstring cxJsonAsCxString(const CxJsonValue *value) {
+ return cx_strcast(value->value.string);
+}
+
+cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
+ return value->value.string;
+}
+
+double cxJsonAsDouble(const CxJsonValue *value) {
+ if (value->type == CX_JSON_INTEGER) {
+ return (double) value->value.integer;
+ } else {
+ return value->value.number;
+ }
+}
+
+int64_t cxJsonAsInteger(const CxJsonValue *value) {
+ if (value->type == CX_JSON_INTEGER) {
+ return value->value.integer;
+ } else {
+ return (int64_t) value->value.number;
+ }
+}
+
CxIterator cxJsonArrIter(const CxJsonValue *value) {
return cxIteratorPtr(
value->value.array.array,
- value->value.array.array_size
+ value->value.array.array_size,
+ true // arrays need to keep order
);
}
@@ -1137,16 +1172,31 @@ CxIterator cxJsonObjIter(const CxJsonValue *value) {
return cxIterator(
value->value.object.values,
sizeof(CxJsonObjValue),
- value->value.object.values_size
+ value->value.object.values_size,
+ true // TODO: objects do not always need to keep order
);
}
-CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) {
- CxJsonObjValue *member = json_find_objvalue(value, name);
- if (member == NULL) {
+CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) {
+ size_t index = json_find_objvalue(value, name);
+ if (index >= value->value.object.values_size) {
return &cx_json_value_nothing;
} else {
- return member->value;
+ return value->value.object.values[index].value;
+ }
+}
+
+CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) {
+ size_t index = json_find_objvalue(value, name);
+ if (index >= value->value.object.values_size) {
+ return NULL;
+ } else {
+ CxJsonObjValue kv = value->value.object.values[index];
+ cx_strfree_a(value->allocator, &kv.name);
+ // TODO: replace with cx_array_remove() / cx_array_remove_fast()
+ value->value.object.values_size--;
+ memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue));
+ return kv.value;
}
}
diff --git a/ucx/kv_list.c b/ucx/kv_list.c
new file mode 100644
index 0000000..d4e19f2
--- /dev/null
+++ b/ucx/kv_list.c
@@ -0,0 +1,705 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Mike Becker, Olaf Wintermann All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cx/kv_list.h"
+#include "cx/hash_map.h"
+#include "cx/linked_list.h"
+
+#include
+#include
+
+typedef struct cx_kv_list_s cx_kv_list;
+
+struct cx_kv_list_map_s {
+ struct cx_hash_map_s map_base;
+ /** Back-reference to the list. */
+ cx_kv_list *list;
+};
+
+struct cx_kv_list_s {
+ struct cx_linked_list_s list;
+ /** The lookup map - stores pointers to the nodes. */
+ struct cx_kv_list_map_s *map;
+ const cx_list_class *list_methods;
+ const cx_map_class *map_methods;
+ cx_destructor_func list_destr;
+ cx_destructor_func2 list_destr2;
+ void *list_destr_data;
+ cx_destructor_func map_destr;
+ cx_destructor_func2 map_destr2;
+ void *map_destr_data;
+};
+
+static void cx_kv_list_destructor_wrapper(void *list_ptr, void *elem) {
+ const cx_kv_list *kv_list = list_ptr;
+ // list destructor is already called with proper deref of the elem
+ if (kv_list->list_destr) {
+ kv_list->list_destr(elem);
+ }
+ if (kv_list->list_destr2) {
+ kv_list->list_destr2(kv_list->list_destr_data, elem);
+ }
+ if (kv_list->map_destr) {
+ kv_list->map_destr(elem);
+ }
+ if (kv_list->map_destr2) {
+ kv_list->map_destr2(kv_list->map_destr_data, elem);
+ }
+}
+
+static void cx_kv_list_update_destructors(cx_kv_list *list) {
+ // we copy the destructors to our custom fields and register
+ // an own destructor function which invokes all these
+ if (list->list.base.collection.simple_destructor != NULL) {
+ list->list_destr = list->list.base.collection.simple_destructor;
+ list->list.base.collection.simple_destructor = NULL;
+ }
+ if (list->list.base.collection.advanced_destructor != cx_kv_list_destructor_wrapper) {
+ list->list_destr2 = list->list.base.collection.advanced_destructor;
+ list->list_destr_data = list->list.base.collection.destructor_data;
+ list->list.base.collection.advanced_destructor = cx_kv_list_destructor_wrapper;
+ list->list.base.collection.destructor_data = list;
+ }
+ if (list->map->map_base.base.collection.simple_destructor != NULL) {
+ list->map_destr = list->map->map_base.base.collection.simple_destructor;
+ list->map->map_base.base.collection.simple_destructor = NULL;
+ }
+ if (list->map->map_base.base.collection.advanced_destructor != NULL) {
+ list->map_destr2 = list->map->map_base.base.collection.advanced_destructor;
+ list->map_destr_data = list->map->map_base.base.collection.destructor_data;
+ list->map->map_base.base.collection.advanced_destructor = NULL;
+ list->map->map_base.base.collection.destructor_data = NULL;
+ }
+}
+
+static CxHashKey *cx_kv_list_loc_key(cx_kv_list *list, void *node_data) {
+ return (CxHashKey*)((char*)node_data + list->list.base.collection.elem_size);
+}
+
+static void cx_kvl_deallocate(struct cx_list_s *list) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ // patch the destructors
+ cx_kv_list_update_destructors(kv_list);
+ kv_list->map_methods->deallocate(&kv_list->map->map_base.base);
+ // then free the list, now the destructors may be called
+ kv_list->list_methods->deallocate(list);
+}
+
+static void *cx_kvl_insert_element(
+ struct cx_list_s *list,
+ size_t index,
+ const void *data
+) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ return kv_list->list_methods->insert_element(list, index, data);
+}
+
+static size_t cx_kvl_insert_array(
+ struct cx_list_s *list,
+ size_t index,
+ const void *data,
+ size_t n
+) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ return kv_list->list_methods->insert_array(list, index, data, n);
+}
+
+static size_t cx_kvl_insert_sorted(
+ struct cx_list_s *list,
+ const void *sorted_data,
+ size_t n
+) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ return kv_list->list_methods->insert_sorted(list, sorted_data, n);
+}
+
+static size_t cx_kvl_insert_unique(
+ struct cx_list_s *list,
+ const void *sorted_data,
+ size_t n
+) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ return kv_list->list_methods->insert_unique(list, sorted_data, n);
+}
+
+static int cx_kvl_insert_iter(
+ struct cx_iterator_s *iter,
+ const void *elem,
+ int prepend
+) {
+ cx_kv_list *kv_list = iter->src_handle;
+ return kv_list->list_methods->insert_iter(iter, elem, prepend);
+}
+
+static size_t cx_kvl_remove(
+ struct cx_list_s *list,
+ size_t index,
+ size_t num,
+ void *targetbuf
+) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ // patch the destructors
+ // we also have to do that when targetbuf is NULL,
+ // because we do not want wrong destructors to be called when we remove keys from the map
+ cx_kv_list_update_destructors(kv_list);
+ // iterate through the elements first and remove their keys from the map
+ CxIterator iter = kv_list->list_methods->iterator(list, index, false);
+ for (size_t i = 0; i < num && cxIteratorValid(iter); i++) {
+ void *node_data = cxIteratorCurrent(iter);
+ CxHashKey *key = cx_kv_list_loc_key(kv_list, node_data);
+ // when the hash is zero, there is no key assigned to that element
+ if (key->hash != 0) {
+ kv_list->map_methods->remove(&kv_list->map->map_base.base, *key, NULL);
+ }
+ cxIteratorNext(iter);
+ }
+ return kv_list->list_methods->remove(list, index, num, targetbuf);
+}
+
+static void cx_kvl_clear(struct cx_list_s *list) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ // patch the destructors
+ cx_kv_list_update_destructors(kv_list);
+ // clear the list
+ kv_list->list_methods->clear(list);
+ // then clear the map
+ kv_list->map_methods->clear(&kv_list->map->map_base.base);
+}
+
+static int cx_kvl_swap(
+ struct cx_list_s *list,
+ size_t i,
+ size_t j
+) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ return kv_list->list_methods->swap(list, i, j);
+}
+
+static void *cx_kvl_at(
+ const struct cx_list_s *list,
+ size_t index
+) {
+ const cx_kv_list *kv_list = (const cx_kv_list*)list;
+ return kv_list->list_methods->at(list, index);
+}
+
+static size_t cx_kvl_find_remove(
+ struct cx_list_s *list,
+ const void *elem,
+ bool remove
+) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ // we do not use the original list methods,
+ // because that would need two passes for removal
+ // (the first to find the index, the second to get a pointer)
+ if (list->collection.size == 0) return 0;
+
+ size_t index;
+ cx_linked_list *ll = &kv_list->list;
+ char *node = cx_linked_list_find(
+ ll->begin,
+ ll->loc_next, ll->loc_data,
+ list->collection.cmpfunc, elem,
+ &index
+ );
+ if (node == NULL) {
+ return list->collection.size;
+ }
+ if (remove) {
+ cx_kv_list_update_destructors(kv_list);
+ cx_invoke_advanced_destructor(list, node + ll->loc_data);
+ cx_linked_list_remove(&ll->begin, &ll->end,
+ ll->loc_prev, ll->loc_next, node);
+ CxHashKey *key = cx_kv_list_loc_key(kv_list, node + ll->loc_data);
+ if (key->hash != 0) {
+ kv_list->map_methods->remove(&kv_list->map->map_base.base, *key, NULL);
+ }
+ list->collection.size--;
+ cxFree(list->collection.allocator, node);
+ }
+ return index;
+}
+
+static void cx_kvl_sort(struct cx_list_s *list) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ kv_list->list_methods->sort(list);
+}
+
+static void cx_kvl_reverse(struct cx_list_s *list) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ kv_list->list_methods->reverse(list);
+}
+
+static void cx_kvl_list_iter_next(void *it) {
+ struct cx_iterator_s *iter = it;
+ if (iter->base.remove) {
+ // remove the assigned key from the map before calling the actual function
+ cx_kv_list *kv_list = iter->src_handle;
+ cx_kv_list_update_destructors(kv_list);
+ char *node = iter->elem_handle;
+ CxHashKey *key = cx_kv_list_loc_key(kv_list, node + kv_list->list.loc_data);
+ if (key->hash != 0) {
+ kv_list->map_methods->remove(&kv_list->map->map_base.base, *key, NULL);
+ }
+ }
+ // note that we do not clear the remove flag, because the next_impl will do that
+ iter->base.next_impl(it);
+}
+
+static struct cx_iterator_s cx_kvl_iterator(
+ const struct cx_list_s *list,
+ size_t index,
+ bool backward
+) {
+ const cx_kv_list *kv_list = (const cx_kv_list*)list;
+ struct cx_iterator_s iter = kv_list->list_methods->iterator(list, index, backward);
+ iter.base.next_impl = iter.base.next;
+ iter.base.next = cx_kvl_list_iter_next;
+ return iter;
+}
+
+static void cx_kvl_map_deallocate(struct cx_map_s *map) {
+ cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
+ kv_list->map_methods->deallocate(map);
+ kv_list->list_methods->deallocate(&kv_list->list.base);
+}
+
+static void cx_kvl_map_clear(struct cx_map_s *map) {
+ cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
+ cx_kv_list_update_destructors(kv_list);
+ kv_list->list_methods->clear(&kv_list->list.base);
+ kv_list->map_methods->clear(map);
+}
+
+static void *cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) {
+ cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
+ // if the hash has not yet been computed, do it now
+ if (key.hash == 0) {
+ cx_hash_murmur(&key);
+ }
+
+ // reserve memory in the map first
+ void **map_data = kv_list->map_methods->put(map, key, NULL);
+ if (map_data == NULL) return NULL; // LCOV_EXCL_LINE
+
+ // insert the data into the list (which most likely destroys the sorted property)
+ kv_list->list.base.collection.sorted = false;
+ void *node_data = kv_list->list_methods->insert_element(
+ &kv_list->list.base, kv_list->list.base.collection.size,
+ kv_list->list.base.collection.store_pointer ? &value : value);
+ if (node_data == NULL) { // LCOV_EXCL_START
+ // non-destructively remove the key again
+ kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &map_data);
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ // write the node pointer to the map entry
+ *map_data = node_data;
+
+ // copy the key to the node data
+ CxHashKey *key_ptr = cx_kv_list_loc_key(kv_list, node_data);
+ *key_ptr = key;
+
+ // we must return node_data here and not map_data,
+ // because the node_data is the actual element of this collection
+ return node_data;
+}
+
+void *cx_kvl_map_get(const CxMap *map, CxHashKey key) {
+ cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
+ void *node_data = kv_list->map_methods->get(map, key);
+ if (node_data == NULL) return NULL; // LCOV_EXCL_LINE
+ // return the node data
+ return kv_list->list.base.collection.store_pointer ? *(void**)node_data : node_data;
+}
+
+int cx_kvl_map_remove(CxMap *map, CxHashKey key, void *targetbuf) {
+ cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
+
+ void *node_data;
+ if (kv_list->map_methods->remove(map, key, &node_data)) {
+ return 1;
+ }
+ // we cannot just call a list method (because we don't have the index)
+ // and tbh. we also don't want to (because it's not performant when we
+ // can have the node ptr directly instead)
+ // therefore, we re-implement the logic ourselves
+
+ // check if the outside caller want's us to return or to destroy the element
+ if (targetbuf == NULL) {
+ // patch the destructors and invoke them through the wrapper
+ cx_kv_list_update_destructors(kv_list);
+ cx_invoke_advanced_destructor(&kv_list->list.base, node_data);
+ } else {
+ // copy the element to the target buffer
+ memcpy(targetbuf, node_data, kv_list->list.base.collection.elem_size);
+ }
+
+ // calculate the address of the node
+ void *node_ptr = (char*)node_data - kv_list->list.loc_data;
+
+ // unlink the node
+ cx_linked_list_remove(
+ &kv_list->list.begin,
+ &kv_list->list.end,
+ kv_list->list.loc_prev,
+ kv_list->list.loc_next,
+ node_ptr
+ );
+
+ // decrement the list's size
+ kv_list->list.base.collection.size--;
+
+ // deallocate the node
+ cxFree(kv_list->list.base.collection.allocator, node_ptr);
+
+ return 0;
+}
+
+static void *cx_kvl_iter_current_entry(const void *it) {
+ const CxMapIterator *iter = it;
+ return (void*)&iter->entry;
+}
+
+static void *cx_kvl_iter_current_key(const void *it) {
+ const CxMapEntry *entry = cx_kvl_iter_current_entry(it);
+ return (void*)entry->key;
+}
+
+static void *cx_kvl_iter_current_value(const void *it) {
+ const CxMapEntry *entry = cx_kvl_iter_current_entry(it);
+ return entry->value;
+}
+
+static void cx_kvl_iter_next(void *it) {
+ CxMapIterator *iter = it;
+ cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)iter->map)->list;
+
+ // find the next list entry that has a key assigned
+ CxHashKey *key = NULL;
+ char *next = iter->elem;
+ while (true) {
+ next = *(char**)(next + kv_list->list.loc_next);
+ if (next == NULL) break;
+ key = cx_kv_list_loc_key(kv_list, next + kv_list->list.loc_data);
+ if (key->hash != 0) break;
+ }
+
+ // remove previous element if requested
+ if (iter->base.remove) {
+ iter->base.remove = false;
+ cx_kv_list_update_destructors(kv_list);
+ char *elem = iter->elem;
+ char *elem_data = elem + kv_list->list.loc_data;
+ CxHashKey *elem_key = cx_kv_list_loc_key(kv_list, elem_data);
+ // key is guaranteed to exist because iterator only iterates over elems with a key
+ kv_list->map_methods->remove(&kv_list->map->map_base.base, *elem_key, NULL);
+ cx_invoke_advanced_destructor(&kv_list->list.base, elem_data);
+ cx_linked_list_remove(
+ &kv_list->list.begin,
+ &kv_list->list.end,
+ kv_list->list.loc_prev,
+ kv_list->list.loc_next,
+ elem
+ );
+ cxFree(kv_list->list.base.collection.allocator, elem);
+ kv_list->list.base.collection.size--;
+ iter->index--;
+ iter->elem_count--;
+ }
+
+ // advance to the next element, if any
+ if (next == NULL) {
+ iter->index = kv_list->list.base.collection.size;
+ iter->elem = NULL;
+ iter->entry = (CxMapEntry){NULL, NULL};
+ return;
+ }
+ iter->index++;
+ iter->elem = next;
+ iter->entry.key = key;
+ if (kv_list->list.base.collection.store_pointer) {
+ iter->entry.value = *(void**)(next + kv_list->list.loc_data);
+ } else {
+ iter->entry.value = (void*)(next + kv_list->list.loc_data);
+ }
+}
+
+static bool cx_kvl_iter_valid(const void *it) {
+ const CxMapIterator *iter = it;
+ return iter->elem != NULL;
+}
+
+CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_type type) {
+ CxMapIterator iter = {0};
+
+ iter.type = type;
+ iter.map = (CxMap*)map;
+ // although we iterate over the list, we only report that many elements that have a key in the map
+ iter.elem_count = map->collection.size;
+
+ switch (type) {
+ case CX_MAP_ITERATOR_PAIRS:
+ iter.elem_size = sizeof(CxMapEntry);
+ iter.base.current = cx_kvl_iter_current_entry;
+ break;
+ case CX_MAP_ITERATOR_KEYS:
+ iter.elem_size = sizeof(CxHashKey);
+ iter.base.current = cx_kvl_iter_current_key;
+ break;
+ case CX_MAP_ITERATOR_VALUES:
+ iter.elem_size = map->collection.elem_size;
+ iter.base.current = cx_kvl_iter_current_value;
+ break;
+ default:
+ assert(false); // LCOV_EXCL_LINE
+ }
+
+ iter.base.allow_remove = true;
+ iter.base.next = cx_kvl_iter_next;
+ iter.base.valid = cx_kvl_iter_valid;
+
+ // find the first list entry that has a key assigned
+ cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
+ CxHashKey *key = NULL;
+ char *next = kv_list->list.begin;
+ while (next != NULL) {
+ key = cx_kv_list_loc_key(kv_list, next + kv_list->list.loc_data);
+ if (key->hash != 0) break;
+ next = *(char**)(next + kv_list->list.loc_next);
+ }
+ if (next == NULL) {
+ iter.elem = NULL;
+ iter.entry = (CxMapEntry){NULL, NULL};
+ } else {
+ iter.elem = next;
+ iter.entry.key = key;
+ if (kv_list->list.base.collection.store_pointer) {
+ iter.entry.value = *(void**)(next + kv_list->list.loc_data);
+ } else {
+ iter.entry.value = (void*)(next + kv_list->list.loc_data);
+ }
+ }
+
+ return iter;
+}
+
+static cx_list_class cx_kv_list_class = {
+ cx_kvl_deallocate,
+ cx_kvl_insert_element,
+ cx_kvl_insert_array,
+ cx_kvl_insert_sorted,
+ cx_kvl_insert_unique,
+ cx_kvl_insert_iter,
+ cx_kvl_remove,
+ cx_kvl_clear,
+ cx_kvl_swap,
+ cx_kvl_at,
+ cx_kvl_find_remove,
+ cx_kvl_sort,
+ NULL,
+ cx_kvl_reverse,
+ cx_kvl_iterator,
+};
+
+static cx_map_class cx_kv_map_class = {
+ cx_kvl_map_deallocate,
+ cx_kvl_map_clear,
+ cx_kvl_map_put,
+ cx_kvl_map_get,
+ cx_kvl_map_remove,
+ cx_kvl_map_iterator,
+};
+
+CxList *cxKvListCreate(
+ const CxAllocator *allocator,
+ cx_compare_func comparator,
+ size_t elem_size
+) {
+ if (allocator == NULL) {
+ allocator = cxDefaultAllocator;
+ }
+
+ // create a normal linked list and a normal hash map, first
+ CxList *list = cxLinkedListCreate(allocator, comparator, elem_size);
+ if (list == NULL) return NULL; // LCOV_EXCL_LINE
+ cx_linked_list *ll = (cx_linked_list*)list;
+ ll->extra_data_len = sizeof(CxHashKey);
+ CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0);
+ if (map == NULL) { // LCOV_EXCL_START
+ cxListFree(list);
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ // patch the kv-list class with the compare function of the linked list
+ // this allows cxListCompare() to optimize comparisons between linked lists and kv-list
+ cx_kv_list_class.compare = list->cl->compare;
+
+ // reallocate the map to add memory for the list back-reference
+ struct cx_kv_list_map_s *kv_map = cxRealloc(allocator, map, sizeof(struct cx_kv_list_map_s));
+
+ // reallocate the list to add memory for storing the metadata
+ cx_kv_list *kv_list = cxRealloc(allocator, list, sizeof(struct cx_kv_list_s));
+
+ // if any of the reallocations failed, we bail out
+ if (kv_map != NULL && kv_list != NULL) {
+ map = (CxMap*) kv_map;
+ list = (CxList*) kv_list;
+ } else { // LCOV_EXCL_START
+ cxListFree(list);
+ cxMapFree(map);
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ // zero the custom destructor information
+ memset((char*)kv_list + offsetof(cx_kv_list, list_destr), 0, sizeof(void*)*6);
+
+ // combine the list and the map aspect
+ kv_list->map = kv_map;
+ kv_map->list = kv_list;
+
+ // remember the base methods and override them
+ kv_list->map_methods = map->cl;
+ map->cl = &cx_kv_map_class;
+ if (list->climpl == NULL) {
+ kv_list->list_methods = list->cl;
+ list->cl = &cx_kv_list_class;
+ } else {
+ kv_list->list_methods = list->climpl;
+ list->climpl = &cx_kv_list_class;
+ }
+
+ return list;
+}
+
+CxMap *cxKvListCreateAsMap(
+ const CxAllocator *allocator,
+ cx_compare_func comparator,
+ size_t elem_size
+) {
+ CxList *list = cxKvListCreate(allocator, comparator, elem_size);
+ return list == NULL ? NULL : cxKvListAsMap(list);
+}
+
+CxList *cxKvListAsList(CxMap *map) {
+ return &((struct cx_kv_list_map_s*)map)->list->list.base;
+}
+
+CxMap *cxKvListAsMap(CxList *list) {
+ return &((cx_kv_list*)list)->map->map_base.base;
+}
+
+int cx_kv_list_set_key(CxList *list, size_t index, CxHashKey key) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ void *node_data = kv_list->list_methods->at(list, index);
+ if (node_data == NULL) {
+ return 1;
+ }
+ // if the hash has not yet been computed, do it now
+ if (key.hash == 0) {
+ cx_hash_murmur(&key);
+ }
+
+ // check if the key is already assigned
+ void *existing = kv_list->map_methods->get(&kv_list->map->map_base.base, key);
+ if (existing == node_data) {
+ return 0; // nothing to do
+ }
+ if (existing != NULL) {
+ // the key is already assigned to another node, we disallow re-assignment
+ return 1;
+ }
+
+ // add the key to the map;
+ if (NULL == kv_list->map_methods->put(&kv_list->map->map_base.base, key, node_data)) {
+ return 1; // LCOV_EXCL_LINE
+ }
+
+ // write the key to the list's node
+ CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
+ *loc_key = key;
+
+ return 0;
+}
+
+int cxKvListRemoveKey(CxList *list, size_t index) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ void *node_data = kv_list->list_methods->at(list, index);
+ if (node_data == NULL) {
+ return 1;
+ }
+ CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
+ if (loc_key->hash == 0) {
+ return 0;
+ }
+ kv_list->map_methods->remove(&kv_list->map->map_base.base, *loc_key, NULL);
+ // also zero the memory in the list node,
+ // but don't free the key data (that was done by the map remove)
+ memset(loc_key, 0, sizeof(CxHashKey));
+ return 0;
+}
+
+const CxHashKey *cxKvListGetKey(CxList *list, size_t index) {
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+ void *node_data = kv_list->list_methods->at(list, index);
+ if (node_data == NULL) {
+ return NULL;
+ }
+ CxHashKey *key = cx_kv_list_loc_key(kv_list, node_data);
+ if (key->hash == 0) {
+ return NULL;
+ }
+ return key;
+}
+
+int cx_kv_list_insert(CxList *list, size_t index, CxHashKey key, void *value) {
+ // assume we are losing the sorted property
+ list->collection.sorted = false;
+
+ cx_kv_list *kv_list = (cx_kv_list*)list;
+
+ // reserve memory in the map
+ void **map_data = kv_list->map_methods->put(&kv_list->map->map_base.base, key, NULL);
+ if (map_data == NULL) return 1; // LCOV_EXCL_LINE
+
+ // insert the node
+ void *node_data = kv_list->list_methods->insert_element(&kv_list->list.base, index,
+ kv_list->list.base.collection.store_pointer ? &value : value);
+ if (node_data == NULL) { // LCOV_EXCL_START
+ // non-destructively remove the key again
+ kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &map_data);
+ return 1;
+ } // LCOV_EXCL_STOP
+ *map_data = node_data;
+
+ // write the key to the node
+ CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
+ *loc_key = key;
+
+ return 0;
+}
diff --git a/ucx/linked_list.c b/ucx/linked_list.c
index 7cd2ff2..370b349 100644
--- a/ucx/linked_list.c
+++ b/ucx/linked_list.c
@@ -244,80 +244,184 @@ void cx_linked_list_insert_sorted(
begin, end, loc_prev, loc_next, new_node, cmp_func);
}
-void cx_linked_list_insert_sorted_chain(
+static void *cx_linked_list_insert_sorted_chain_impl(
void **begin,
void **end,
ptrdiff_t loc_prev,
ptrdiff_t loc_next,
void *insert_begin,
- cx_compare_func cmp_func
+ cx_compare_func cmp_func,
+ bool allow_duplicates
) {
assert(begin != NULL);
assert(loc_next >= 0);
assert(insert_begin != NULL);
- // track currently observed nodes
- void *dest_prev = NULL;
- void *dest = *begin;
- void *src = insert_begin;
-
- // special case: list is empty
- if (dest == NULL) {
- *begin = src;
- if (end != NULL) {
- *end = cx_linked_list_last(src, loc_next);
+ // strategy: build completely new chains from scratch
+ void *source_original = *begin;
+ void *source_argument = insert_begin;
+ void *new_begin = NULL;
+ void *new_end = NULL;
+ void *dup_begin = NULL;
+ void *dup_end = NULL;
+
+ // determine the new start
+ {
+ int d = source_original == NULL ? 1 : cmp_func(source_original, source_argument);
+ if (d <= 0) {
+ // the new chain starts with the original chain
+ new_begin = new_end = source_original;
+ source_original = ll_next(source_original);
+ if (d == 0) {
+ if (allow_duplicates) {
+ // duplicate allowed, append it to the chain
+ cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
+ new_end = source_argument;
+ } else {
+ // duplicate is not allowed, start a duplicate chain with the argument
+ dup_begin = dup_end = source_argument;
+ }
+ source_argument = ll_next(source_argument);
+ }
+ } else {
+ // input is smaller, or there is no original chain;
+ // start the new chain with the source argument
+ new_begin = new_end = source_argument;
+ source_argument = ll_next(source_argument);
}
- return;
}
- // search the list for insertion points
- while (dest != NULL && src != NULL) {
- // compare current list node with source node
- // if less or equal, skip
- if (cmp_func(dest, src) <= 0) {
- dest_prev = dest;
- dest = ll_next(dest);
- continue;
- }
-
- // determine chain of elements that can be inserted
- void *end_of_chain = src;
- void *next_in_chain = ll_next(src);
- while (next_in_chain != NULL) {
- // once we become larger than the list elem, break
- if (cmp_func(dest, next_in_chain) <= 0) {
- break;
+ // now successively compare the elements and add them to the correct chains
+ while (source_original != NULL && source_argument != NULL) {
+ int d = cmp_func(source_original, source_argument);
+ if (d <= 0) {
+ // the original is not larger, add it to the chain
+ cx_linked_list_link(new_end, source_original, loc_prev, loc_next);
+ new_end = source_original;
+ source_original = ll_next(source_original);
+ if (d == 0) {
+ if (allow_duplicates) {
+ // duplicate allowed, append it to the chain
+ cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
+ new_end = source_argument;
+ } else {
+ // duplicate is not allowed, append it to the duplicate chain
+ if (dup_end == NULL) {
+ dup_begin = dup_end = source_argument;
+ } else {
+ cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next);
+ dup_end = source_argument;
+ }
+ }
+ source_argument = ll_next(source_argument);
+ }
+ } else {
+ // the original is larger, append the source argument to the chain
+ // check if we must discard the source argument as duplicate
+ if (!allow_duplicates && cmp_func(new_end, source_argument) == 0) {
+ if (dup_end == NULL) {
+ dup_begin = dup_end = source_argument;
+ } else {
+ cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next);
+ dup_end = source_argument;
+ }
+ } else {
+ // no duplicate or duplicates allowed
+ cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
+ new_end = source_argument;
}
- // otherwise, we can insert one more
- end_of_chain = next_in_chain;
- next_in_chain = ll_next(next_in_chain);
+ source_argument = ll_next(source_argument);
}
+ }
- // insert the elements
- if (dest_prev == NULL) {
- // new begin
- *begin = src;
+ if (source_original != NULL) {
+ // something is left from the original chain, append it
+ cx_linked_list_link(new_end, source_original, loc_prev, loc_next);
+ new_end = cx_linked_list_last(source_original, loc_next);
+ } else if (source_argument != NULL) {
+ // something is left from the input chain;
+ // when we allow duplicates, append it
+ if (allow_duplicates) {
+ cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
+ new_end = cx_linked_list_last(source_argument, loc_next);
} else {
- cx_linked_list_link(dest_prev, src, loc_prev, loc_next);
+ // otherwise we must check one-by-one
+ while (source_argument != NULL) {
+ if (cmp_func(new_end, source_argument) == 0) {
+ if (dup_end == NULL) {
+ dup_begin = dup_end = source_argument;
+ } else {
+ cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next);
+ dup_end = source_argument;
+ }
+ } else {
+ cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
+ new_end = source_argument;
+ }
+ source_argument = ll_next(source_argument);
+ }
}
- cx_linked_list_link(end_of_chain, dest, loc_prev, loc_next);
+ }
- // continue with next
- src = next_in_chain;
- dest_prev = dest;
- dest = ll_next(dest);
+ // null the next pointers at the end of the chain
+ ll_next(new_end) = NULL;
+ if (dup_end != NULL) {
+ ll_next(dup_end) = NULL;
}
- // insert remaining items
- if (src != NULL) {
- cx_linked_list_link(dest_prev, src, loc_prev, loc_next);
+ // null the optional prev pointers
+ if (loc_prev >= 0) {
+ ll_prev(new_begin) = NULL;
+ if (dup_begin != NULL) {
+ ll_prev(dup_begin) = NULL;
+ }
}
- // determine new end of list, if requested
+ // output
+ *begin = new_begin;
if (end != NULL) {
- *end = cx_linked_list_last(
- dest != NULL ? dest : dest_prev, loc_next);
+ *end = new_end;
}
+ return dup_begin;
+}
+
+void cx_linked_list_insert_sorted_chain(
+ void **begin,
+ void **end,
+ ptrdiff_t loc_prev,
+ ptrdiff_t loc_next,
+ void *insert_begin,
+ cx_compare_func cmp_func
+) {
+ cx_linked_list_insert_sorted_chain_impl(
+ begin, end, loc_prev, loc_next,
+ insert_begin, cmp_func, true);
+}
+
+int cx_linked_list_insert_unique(
+ void **begin,
+ void **end,
+ ptrdiff_t loc_prev,
+ ptrdiff_t loc_next,
+ void *new_node,
+ cx_compare_func cmp_func
+) {
+ assert(ll_next(new_node) == NULL);
+ return NULL != cx_linked_list_insert_unique_chain(
+ begin, end, loc_prev, loc_next, new_node, cmp_func);
+}
+
+void *cx_linked_list_insert_unique_chain(
+ void **begin,
+ void **end,
+ ptrdiff_t loc_prev,
+ ptrdiff_t loc_next,
+ void *insert_begin,
+ cx_compare_func cmp_func
+) {
+ return cx_linked_list_insert_sorted_chain_impl(
+ begin, end, loc_prev, loc_next,
+ insert_begin, cmp_func, false);
}
size_t cx_linked_list_remove_chain(
@@ -370,6 +474,16 @@ size_t cx_linked_list_remove_chain(
return removed;
}
+void cx_linked_list_remove(
+ void **begin,
+ void **end,
+ ptrdiff_t loc_prev,
+ ptrdiff_t loc_next,
+ void *node
+) {
+ cx_linked_list_remove_chain(begin, end, loc_prev, loc_next, node, 1);
+}
+
size_t cx_linked_list_size(
const void *node,
ptrdiff_t loc_next
@@ -564,64 +678,46 @@ void cx_linked_list_reverse(
// HIGH LEVEL LINKED LIST IMPLEMENTATION
-typedef struct cx_linked_list_node cx_linked_list_node;
-struct cx_linked_list_node {
- cx_linked_list_node *prev;
- cx_linked_list_node *next;
- char payload[];
-};
-
-#define CX_LL_LOC_PREV offsetof(cx_linked_list_node, prev)
-#define CX_LL_LOC_NEXT offsetof(cx_linked_list_node, next)
-#define CX_LL_LOC_DATA offsetof(cx_linked_list_node, payload)
-
-typedef struct {
- struct cx_list_s base;
- cx_linked_list_node *begin;
- cx_linked_list_node *end;
-} cx_linked_list;
-
-static cx_linked_list_node *cx_ll_node_at(
+static void *cx_ll_node_at(
const cx_linked_list *list,
size_t index
) {
if (index >= list->base.collection.size) {
return NULL;
} else if (index > list->base.collection.size / 2) {
- return cx_linked_list_at(list->end, list->base.collection.size - 1, CX_LL_LOC_PREV, index);
+ return cx_linked_list_at(list->end, list->base.collection.size - 1, list->loc_prev, index);
} else {
- return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index);
+ return cx_linked_list_at(list->begin, 0, list->loc_next, index);
}
}
-static cx_linked_list_node *cx_ll_malloc_node(const struct cx_list_s *list) {
- return cxMalloc(list->collection.allocator,
- sizeof(cx_linked_list_node) + list->collection.elem_size);
+static void *cx_ll_malloc_node(const cx_linked_list *list) {
+ return cxZalloc(list->base.collection.allocator,
+ list->loc_data + list->base.collection.elem_size + list->extra_data_len);
}
static int cx_ll_insert_at(
struct cx_list_s *list,
- cx_linked_list_node *node,
+ void *node,
const void *elem
) {
+ cx_linked_list *ll = (cx_linked_list *) list;
// create the new new_node
- cx_linked_list_node *new_node = cx_ll_malloc_node(list);
+ void *new_node = cx_ll_malloc_node(ll);
// sortir if failed
if (new_node == NULL) return 1;
- // initialize new new_node
- new_node->prev = new_node->next = NULL;
+ // copy the data
if (elem != NULL) {
- memcpy(new_node->payload, elem, list->collection.elem_size);
+ memcpy((char*)new_node + ll->loc_data, elem, list->collection.elem_size);
}
// insert
- cx_linked_list *ll = (cx_linked_list *) list;
cx_linked_list_insert_chain(
- (void **) &ll->begin, (void **) &ll->end,
- CX_LL_LOC_PREV, CX_LL_LOC_NEXT,
+ &ll->begin, &ll->end,
+ ll->loc_prev, ll->loc_next,
node, new_node, new_node
);
@@ -640,7 +736,7 @@ static size_t cx_ll_insert_array(
if (index > list->collection.size || n == 0) return 0;
// find position efficiently
- cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
+ void *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
// perform first insert
if (0 != cx_ll_insert_at(list, node, array)) return 1;
@@ -649,14 +745,17 @@ static size_t cx_ll_insert_array(
if (n == 1) return 1;
// we now know exactly where we are
- node = node == NULL ? ((cx_linked_list *) list)->begin : node->next;
+ cx_linked_list *ll = (cx_linked_list *) list;
+ node = node == NULL ? ((cx_linked_list *) list)->begin : CX_LL_PTR(node, ll->loc_next);
// we can add the remaining nodes and immediately advance to the inserted node
const char *source = array;
for (size_t i = 1; i < n; i++) {
- source += list->collection.elem_size;
+ if (source != NULL) {
+ source += list->collection.elem_size;
+ }
if (0 != cx_ll_insert_at(list, node, source)) return i;
- node = node->next;
+ node = CX_LL_PTR(node, ll->loc_next);
}
return n;
}
@@ -670,76 +769,113 @@ static void *cx_ll_insert_element(
if (index > list->collection.size) return NULL;
// find position efficiently
- cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
+ void *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
// perform first insert
if (cx_ll_insert_at(list, node, element)) return NULL;
// return a pointer to the data of the inserted node
+ cx_linked_list *ll = (cx_linked_list *) list;
if (node == NULL) {
- return ((cx_linked_list *) list)->begin->payload;
+ return (char*)(ll->begin) + ll->loc_data;
} else {
- return node->next->payload;
+ char *next = CX_LL_PTR(node, ll->loc_next);
+ return next + ll->loc_data;
}
}
static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func;
+static _Thread_local off_t cx_ll_insert_sorted_loc_data;
static int cx_ll_insert_sorted_cmp_helper(const void *l, const void *r) {
- const cx_linked_list_node *left = l;
- const cx_linked_list_node *right = r;
- return cx_ll_insert_sorted_cmp_func(left->payload, right->payload);
+ const char *left = (const char*)l + cx_ll_insert_sorted_loc_data;
+ const char *right = (const char*)r + cx_ll_insert_sorted_loc_data;
+ return cx_ll_insert_sorted_cmp_func(left, right);
}
-static size_t cx_ll_insert_sorted(
+static size_t cx_ll_insert_sorted_impl(
struct cx_list_s *list,
const void *array,
- size_t n
+ size_t n,
+ bool allow_duplicates
) {
+ cx_linked_list *ll = (cx_linked_list *) list;
+
// special case
if (n == 0) return 0;
// create a new chain of nodes
- cx_linked_list_node *chain = cx_ll_malloc_node(list);
+ void *chain = cx_ll_malloc_node(ll);
if (chain == NULL) return 0;
- memcpy(chain->payload, array, list->collection.elem_size);
- chain->prev = NULL;
- chain->next = NULL;
+ memcpy((char*)chain + ll->loc_data, array, list->collection.elem_size);
// add all elements from the array to that chain
- cx_linked_list_node *prev = chain;
+ void *prev = chain;
const char *src = array;
size_t inserted = 1;
for (; inserted < n; inserted++) {
- cx_linked_list_node *next = cx_ll_malloc_node(list);
+ void *next = cx_ll_malloc_node(ll);
if (next == NULL) break;
src += list->collection.elem_size;
- memcpy(next->payload, src, list->collection.elem_size);
- prev->next = next;
- next->prev = prev;
+ memcpy((char*)next + ll->loc_data, src, list->collection.elem_size);
+ CX_LL_PTR(prev, ll->loc_next) = next;
+ CX_LL_PTR(next, ll->loc_prev) = prev;
prev = next;
}
- prev->next = NULL;
+ CX_LL_PTR(prev, ll->loc_next) = NULL;
// invoke the low level function
- cx_linked_list *ll = (cx_linked_list *) list;
cx_ll_insert_sorted_cmp_func = list->collection.cmpfunc;
- cx_linked_list_insert_sorted_chain(
- (void **) &ll->begin,
- (void **) &ll->end,
- CX_LL_LOC_PREV,
- CX_LL_LOC_NEXT,
- chain,
- cx_ll_insert_sorted_cmp_helper
- );
-
- // adjust the list metadata
- list->collection.size += inserted;
+ cx_ll_insert_sorted_loc_data = ll->loc_data;
+ if (allow_duplicates) {
+ cx_linked_list_insert_sorted_chain(
+ &ll->begin,
+ &ll->end,
+ ll->loc_prev,
+ ll->loc_next,
+ chain,
+ cx_ll_insert_sorted_cmp_helper
+ );
+ list->collection.size += inserted;
+ } else {
+ void *duplicates = cx_linked_list_insert_unique_chain(
+ &ll->begin,
+ &ll->end,
+ ll->loc_prev,
+ ll->loc_next,
+ chain,
+ cx_ll_insert_sorted_cmp_helper
+ );
+ list->collection.size += inserted;
+ // free the nodes that did not make it into the list
+ while (duplicates != NULL) {
+ void *next = CX_LL_PTR(duplicates, ll->loc_next);
+ cxFree(list->collection.allocator, duplicates);
+ duplicates = next;
+ list->collection.size--;
+ }
+ }
return inserted;
}
+static size_t cx_ll_insert_sorted(
+ struct cx_list_s *list,
+ const void *array,
+ size_t n
+) {
+ return cx_ll_insert_sorted_impl(list, array, n, true);
+}
+
+static size_t cx_ll_insert_unique(
+ struct cx_list_s *list,
+ const void *array,
+ size_t n
+) {
+ return cx_ll_insert_sorted_impl(list, array, n, false);
+}
+
static size_t cx_ll_remove(
struct cx_list_s *list,
size_t index,
@@ -747,7 +883,7 @@ static size_t cx_ll_remove(
void *targetbuf
) {
cx_linked_list *ll = (cx_linked_list *) list;
- cx_linked_list_node *node = cx_ll_node_at(ll, index);
+ void *node = cx_ll_node_at(ll, index);
// out-of-bounds check
if (node == NULL) return 0;
@@ -756,8 +892,8 @@ static size_t cx_ll_remove(
size_t removed = cx_linked_list_remove_chain(
(void **) &ll->begin,
(void **) &ll->end,
- CX_LL_LOC_PREV,
- CX_LL_LOC_NEXT,
+ ll->loc_prev,
+ ll->loc_next,
node,
num
);
@@ -767,28 +903,28 @@ static size_t cx_ll_remove(
// copy or destroy the removed chain
if (targetbuf == NULL) {
- cx_linked_list_node *n = node;
+ char *n = node;
for (size_t i = 0; i < removed; i++) {
// element destruction
- cx_invoke_destructor(list, n->payload);
+ cx_invoke_destructor(list, n + ll->loc_data);
// free the node and advance
- void *next = n->next;
+ void *next = CX_LL_PTR(n, ll->loc_next);
cxFree(list->collection.allocator, n);
n = next;
}
} else {
char *dest = targetbuf;
- cx_linked_list_node *n = node;
+ char *n = node;
for (size_t i = 0; i < removed; i++) {
// copy payload
- memcpy(dest, n->payload, list->collection.elem_size);
+ memcpy(dest, n + ll->loc_data, list->collection.elem_size);
// advance target buffer
dest += list->collection.elem_size;
// free the node and advance
- void *next = n->next;
+ void *next = CX_LL_PTR(n, ll->loc_next);
cxFree(list->collection.allocator, n);
n = next;
}
@@ -801,10 +937,10 @@ static void cx_ll_clear(struct cx_list_s *list) {
if (list->collection.size == 0) return;
cx_linked_list *ll = (cx_linked_list *) list;
- cx_linked_list_node *node = ll->begin;
+ char *node = ll->begin;
while (node != NULL) {
- cx_invoke_destructor(list, node->payload);
- cx_linked_list_node *next = node->next;
+ cx_invoke_destructor(list, node + ll->loc_data);
+ void *next = CX_LL_PTR(node, ll->loc_next);
cxFree(list->collection.allocator, node);
node = next;
}
@@ -831,14 +967,14 @@ static int cx_ll_swap(
left = j;
right = i;
}
- cx_linked_list_node *nleft = NULL, *nright = NULL;
+ void *nleft = NULL, *nright = NULL;
if (left < mid && right < mid) {
// case 1: both items left from mid
nleft = cx_ll_node_at(ll, left);
assert(nleft != NULL);
nright = nleft;
for (size_t c = left; c < right; c++) {
- nright = nright->next;
+ nright = CX_LL_PTR(nright, ll->loc_next);
}
} else if (left >= mid && right >= mid) {
// case 2: both items right from mid
@@ -846,7 +982,7 @@ static int cx_ll_swap(
assert(nright != NULL);
nleft = nright;
for (size_t c = right; c > left; c--) {
- nleft = nleft->prev;
+ nleft = CX_LL_PTR(nleft, ll->loc_prev);
}
} else {
// case 3: one item left, one item right
@@ -872,12 +1008,12 @@ static int cx_ll_swap(
if (closest == left) {
nright = nleft;
for (size_t c = left; c < right; c++) {
- nright = nright->next;
+ nright = CX_LL_PTR(nright, ll->loc_next);
}
} else {
nleft = nright;
for (size_t c = right; c > left; c--) {
- nleft = nleft->prev;
+ nleft = CX_LL_PTR(nleft, ll->loc_prev);
}
}
} else {
@@ -890,33 +1026,33 @@ static int cx_ll_swap(
}
}
- cx_linked_list_node *prev = nleft->prev;
- cx_linked_list_node *next = nright->next;
- cx_linked_list_node *midstart = nleft->next;
- cx_linked_list_node *midend = nright->prev;
+ void *prev = CX_LL_PTR(nleft, ll->loc_prev);
+ void *next = CX_LL_PTR(nright, ll->loc_next);
+ void *midstart = CX_LL_PTR(nleft, ll->loc_next);
+ void *midend = CX_LL_PTR(nright, ll->loc_prev);
if (prev == NULL) {
ll->begin = nright;
} else {
- prev->next = nright;
+ CX_LL_PTR(prev, ll->loc_next) = nright;
}
- nright->prev = prev;
+ CX_LL_PTR(nright, ll->loc_prev) = prev;
if (midstart == nright) {
// special case: both nodes are adjacent
- nright->next = nleft;
- nleft->prev = nright;
+ CX_LL_PTR(nright, ll->loc_next) = nleft;
+ CX_LL_PTR(nleft, ll->loc_prev) = nright;
} else {
// likely case: a chain is between the two nodes
- nright->next = midstart;
- midstart->prev = nright;
- midend->next = nleft;
- nleft->prev = midend;
+ CX_LL_PTR(nright, ll->loc_next) = midstart;
+ CX_LL_PTR(midstart, ll->loc_prev) = nright;
+ CX_LL_PTR(midend, ll->loc_next) = nleft;
+ CX_LL_PTR(nleft, ll->loc_prev) = midend;
}
- nleft->next = next;
+ CX_LL_PTR(nleft, ll->loc_next) = next;
if (next == NULL) {
ll->end = nleft;
} else {
- next->prev = nleft;
+ CX_LL_PTR(next, ll->loc_prev) = nleft;
}
return 0;
@@ -927,8 +1063,8 @@ static void *cx_ll_at(
size_t index
) {
cx_linked_list *ll = (cx_linked_list *) list;
- cx_linked_list_node *node = cx_ll_node_at(ll, index);
- return node == NULL ? NULL : node->payload;
+ char *node = cx_ll_node_at(ll, index);
+ return node == NULL ? NULL : node + ll->loc_data;
}
static size_t cx_ll_find_remove(
@@ -939,10 +1075,10 @@ static size_t cx_ll_find_remove(
if (list->collection.size == 0) return 0;
size_t index;
- cx_linked_list *ll = ((cx_linked_list *) list);
- cx_linked_list_node *node = cx_linked_list_find(
+ cx_linked_list *ll = (cx_linked_list *) list;
+ char *node = cx_linked_list_find(
ll->begin,
- CX_LL_LOC_NEXT, CX_LL_LOC_DATA,
+ ll->loc_next, ll->loc_data,
list->collection.cmpfunc, elem,
&index
);
@@ -950,9 +1086,9 @@ static size_t cx_ll_find_remove(
return list->collection.size;
}
if (remove) {
- cx_invoke_destructor(list, node->payload);
- cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end,
- CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node);
+ cx_invoke_destructor(list, node + ll->loc_data);
+ cx_linked_list_remove(&ll->begin, &ll->end,
+ ll->loc_prev, ll->loc_next, node);
list->collection.size--;
cxFree(list->collection.allocator, node);
}
@@ -961,14 +1097,14 @@ static size_t cx_ll_find_remove(
static void cx_ll_sort(struct cx_list_s *list) {
cx_linked_list *ll = (cx_linked_list *) list;
- cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end,
- CX_LL_LOC_PREV, CX_LL_LOC_NEXT, CX_LL_LOC_DATA,
+ cx_linked_list_sort(&ll->begin, &ll->end,
+ ll->loc_prev, ll->loc_next, ll->loc_data,
list->collection.cmpfunc);
}
static void cx_ll_reverse(struct cx_list_s *list) {
cx_linked_list *ll = (cx_linked_list *) list;
- cx_linked_list_reverse((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT);
+ cx_linked_list_reverse(&ll->begin, &ll->end, ll->loc_prev, ll->loc_next);
}
static int cx_ll_compare(
@@ -977,8 +1113,10 @@ static int cx_ll_compare(
) {
cx_linked_list *left = (cx_linked_list *) list;
cx_linked_list *right = (cx_linked_list *) other;
+ assert(left->loc_next == right->loc_next);
+ assert(left->loc_data == right->loc_data);
return cx_linked_list_compare(left->begin, right->begin,
- CX_LL_LOC_NEXT, CX_LL_LOC_DATA,
+ left->loc_next, left->loc_data,
list->collection.cmpfunc);
}
@@ -989,49 +1127,52 @@ static bool cx_ll_iter_valid(const void *it) {
static void cx_ll_iter_next(void *it) {
struct cx_iterator_s *iter = it;
+ cx_linked_list *ll = iter->src_handle;
if (iter->base.remove) {
iter->base.remove = false;
- struct cx_list_s *list = iter->src_handle.m;
- cx_linked_list *ll = iter->src_handle.m;
- cx_linked_list_node *node = iter->elem_handle;
- iter->elem_handle = node->next;
- cx_invoke_destructor(list, node->payload);
- cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end,
- CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node);
+ struct cx_list_s *list = iter->src_handle;
+ char *node = iter->elem_handle;
+ iter->elem_handle = CX_LL_PTR(node, ll->loc_next);
+ cx_invoke_destructor(list, node + ll->loc_data);
+ cx_linked_list_remove(&ll->begin, &ll->end,
+ ll->loc_prev, ll->loc_next, node);
list->collection.size--;
+ iter->elem_count--;
cxFree(list->collection.allocator, node);
} else {
iter->index++;
- cx_linked_list_node *node = iter->elem_handle;
- iter->elem_handle = node->next;
+ void *node = iter->elem_handle;
+ iter->elem_handle = CX_LL_PTR(node, ll->loc_next);
}
}
static void cx_ll_iter_prev(void *it) {
struct cx_iterator_s *iter = it;
+ cx_linked_list *ll = iter->src_handle;
if (iter->base.remove) {
iter->base.remove = false;
- struct cx_list_s *list = iter->src_handle.m;
- cx_linked_list *ll = iter->src_handle.m;
- cx_linked_list_node *node = iter->elem_handle;
- iter->elem_handle = node->prev;
+ struct cx_list_s *list = iter->src_handle;
+ char *node = iter->elem_handle;
+ iter->elem_handle = CX_LL_PTR(node, ll->loc_prev);
iter->index--;
- cx_invoke_destructor(list, node->payload);
- cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end,
- CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node);
+ cx_invoke_destructor(list, node + ll->loc_data);
+ cx_linked_list_remove(&ll->begin, &ll->end,
+ ll->loc_prev, ll->loc_next, node);
list->collection.size--;
+ iter->elem_count--;
cxFree(list->collection.allocator, node);
} else {
iter->index--;
- cx_linked_list_node *node = iter->elem_handle;
- iter->elem_handle = node->prev;
+ char *node = iter->elem_handle;
+ iter->elem_handle = CX_LL_PTR(node, ll->loc_prev);
}
}
static void *cx_ll_iter_current(const void *it) {
const struct cx_iterator_s *iter = it;
- cx_linked_list_node *node = iter->elem_handle;
- return node->payload;
+ const cx_linked_list *ll = iter->src_handle;
+ char *node = iter->elem_handle;
+ return node + ll->loc_data;
}
static CxIterator cx_ll_iterator(
@@ -1041,14 +1182,14 @@ static CxIterator cx_ll_iterator(
) {
CxIterator iter;
iter.index = index;
- iter.src_handle.c = list;
+ iter.src_handle = (void*)list;
iter.elem_handle = cx_ll_node_at((const cx_linked_list *) list, index);
iter.elem_size = list->collection.elem_size;
iter.elem_count = list->collection.size;
iter.base.valid = cx_ll_iter_valid;
iter.base.current = cx_ll_iter_current;
iter.base.next = backwards ? cx_ll_iter_prev : cx_ll_iter_next;
- iter.base.mutating = false;
+ iter.base.allow_remove = true;
iter.base.remove = false;
return iter;
}
@@ -1058,11 +1199,12 @@ static int cx_ll_insert_iter(
const void *elem,
int prepend
) {
- struct cx_list_s *list = iter->src_handle.m;
- cx_linked_list_node *node = iter->elem_handle;
+ struct cx_list_s *list = iter->src_handle;
+ cx_linked_list *ll = iter->src_handle;
+ void *node = iter->elem_handle;
if (node != NULL) {
assert(prepend >= 0 && prepend <= 1);
- cx_linked_list_node *choice[2] = {node, node->prev};
+ void *choice[2] = {node, CX_LL_PTR(node, ll->loc_prev)};
int result = cx_ll_insert_at(list, choice[prepend], elem);
if (result == 0) {
iter->elem_count++;
@@ -1084,10 +1226,10 @@ static int cx_ll_insert_iter(
static void cx_ll_destructor(CxList *list) {
cx_linked_list *ll = (cx_linked_list *) list;
- cx_linked_list_node *node = ll->begin;
+ char *node = ll->begin;
while (node) {
- cx_invoke_destructor(list, node->payload);
- void *next = node->next;
+ cx_invoke_destructor(list, node + ll->loc_data);
+ void *next = CX_LL_PTR(node, ll->loc_next);
cxFree(list->collection.allocator, node);
node = next;
}
@@ -1100,6 +1242,7 @@ static cx_list_class cx_linked_list_class = {
cx_ll_insert_element,
cx_ll_insert_array,
cx_ll_insert_sorted,
+ cx_ll_insert_unique,
cx_ll_insert_iter,
cx_ll_remove,
cx_ll_clear,
@@ -1123,6 +1266,10 @@ CxList *cxLinkedListCreate(
cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list));
if (list == NULL) return NULL;
+ list->extra_data_len = 0;
+ list->loc_prev = 0;
+ list->loc_next = sizeof(void*);
+ list->loc_data = sizeof(void*)*2;
cx_list_init((CxList*)list, &cx_linked_list_class,
allocator, comparator, elem_size);
diff --git a/ucx/list.c b/ucx/list.c
index 7fbbb8b..d4a8b22 100644
--- a/ucx/list.c
+++ b/ucx/list.c
@@ -29,6 +29,7 @@
#include "cx/list.h"
#include
+#include
//
@@ -38,10 +39,18 @@ static int cx_pl_cmpfunc(
const void *l,
const void *r
) {
+ // l and r are guaranteed to be non-NULL pointing to the list's memory
void *const *lptr = l;
void *const *rptr = r;
- const void *left = lptr == NULL ? NULL : *lptr;
- const void *right = rptr == NULL ? NULL : *rptr;
+ const void *left = *lptr;
+ const void *right = *rptr;
+ if (left == NULL) {
+ // NULL is smaller than any value except NULL
+ return right == NULL ? 0 : -1;
+ } else if (right == NULL) {
+ // any value is larger than NULL
+ return 1;
+ }
return cx_pl_cmpfunc_impl(left, right);
}
@@ -90,12 +99,23 @@ static size_t cx_pl_insert_sorted(
return result;
}
+static size_t cx_pl_insert_unique(
+ struct cx_list_s *list,
+ const void *array,
+ size_t n
+) {
+ cx_pl_hack_cmpfunc(list);
+ size_t result = list->climpl->insert_unique(list, array, n);
+ cx_pl_unhack_cmpfunc(list);
+ return result;
+}
+
static int cx_pl_insert_iter(
struct cx_iterator_s *iter,
const void *elem,
int prepend
) {
- struct cx_list_s *list = iter->src_handle.m;
+ struct cx_list_s *list = iter->src_handle;
return list->climpl->insert_iter(iter, &elem, prepend);
}
@@ -181,6 +201,7 @@ static cx_list_class cx_pointer_list_class = {
cx_pl_insert_element,
cx_pl_insert_array,
cx_pl_insert_sorted,
+ cx_pl_insert_unique,
cx_pl_insert_iter,
cx_pl_remove,
cx_pl_clear,
@@ -225,7 +246,7 @@ static CxIterator cx_emptyl_iterator(
cx_attr_unused bool backwards
) {
CxIterator iter = {0};
- iter.src_handle.c = list;
+ iter.src_handle = (void*) list;
iter.index = index;
iter.base.valid = cx_emptyl_iter_valid;
return iter;
@@ -238,6 +259,7 @@ static cx_list_class cx_empty_list_class = {
NULL,
NULL,
NULL,
+ NULL,
cx_emptyl_noop,
NULL,
cx_emptyl_at,
@@ -278,21 +300,26 @@ size_t cx_list_default_insert_array(
const void *data,
size_t n
) {
- size_t elem_size = list->collection.elem_size;
const char *src = data;
size_t i = 0;
for (; i < n; i++) {
if (NULL == invoke_list_func(
- insert_element, list, index + i,
- src + (i * elem_size))) return i;
+ insert_element, list, index + i, src)
+ ) {
+ return i; // LCOV_EXCL_LINE
+ }
+ if (src != NULL) {
+ src += list->collection.elem_size;
+ }
}
return i;
}
-size_t cx_list_default_insert_sorted(
+static size_t cx_list_default_insert_sorted_impl(
struct cx_list_s *list,
const void *sorted_data,
- size_t n
+ size_t n,
+ bool allow_duplicates
) {
// corner case
if (n == 0) return 0;
@@ -302,22 +329,54 @@ size_t cx_list_default_insert_sorted(
const char *src = sorted_data;
// track indices and number of inserted items
- size_t di = 0, si = 0, inserted = 0;
+ size_t di = 0, si = 0, processed = 0;
// search the list for insertion points
- for (; di < list->collection.size; di++) {
+ while (di < list->collection.size) {
const void *list_elm = invoke_list_func(at, list, di);
- // compare current list element with first source element
- // if less or equal, skip
- if (cmp(list_elm, src) <= 0) {
- continue;
+ // compare the current list element with the first source element
+ // if less, skip the list elements
+ // if equal, skip the list elements and optionally the source elements
+ {
+ int d = cmp(list_elm, src);
+ if (d <= 0) {
+ if (!allow_duplicates && d == 0) {
+ src += elem_size;
+ si++;
+ processed++; // we also count duplicates for the return value
+ while (si < n && cmp(list_elm, src) == 0) {
+ src += elem_size;
+ si++;
+ processed++;
+ }
+ if (processed == n) {
+ return processed;
+ }
+ }
+ di++;
+ continue;
+ }
}
- // determine number of consecutive elements that can be inserted
- size_t ins = 1;
+ // determine the number of consecutive elements that can be inserted
+ size_t ins = 1, skip = 0;
const char *next = src;
while (++si < n) {
+ if (!allow_duplicates) {
+ // skip duplicates within the source
+ if (cmp(next, next + elem_size) == 0) {
+ next += elem_size;
+ skip++;
+ continue;
+ } else {
+ if (skip > 0) {
+ // if we had to skip something, we must wait for the next run
+ next += elem_size;
+ break;
+ }
+ }
+ }
next += elem_size;
// once we become larger than the list elem, break
if (cmp(list_elm, next) <= 0) {
@@ -329,33 +388,70 @@ size_t cx_list_default_insert_sorted(
// insert the elements at location si
if (ins == 1) {
- if (NULL == invoke_list_func(
- insert_element, list, di, src)) return inserted;
+ if (NULL == invoke_list_func(insert_element, list, di, src)) {
+ return processed; // LCOV_EXCL_LINE
+ }
} else {
size_t r = invoke_list_func(insert_array, list, di, src, ins);
- if (r < ins) return inserted + r;
+ if (r < ins) {
+ return processed + r; // LCOV_EXCL_LINE
+ }
}
- inserted += ins;
+ processed += ins + skip;
di += ins;
// everything inserted?
- if (inserted == n) return inserted;
+ if (processed == n) {
+ return processed;
+ }
src = next;
}
// insert remaining items
if (si < n) {
- inserted += invoke_list_func(insert_array, list, di, src, n - si);
+ if (allow_duplicates) {
+ processed += invoke_list_func(insert_array, list, di, src, n - si);
+ } else {
+ const void *last = di == 0 ? NULL : invoke_list_func(at, list, di - 1);
+ for (; si < n; si++) {
+ // skip duplicates within the source
+ if (last == NULL || cmp(last, src) != 0) {
+ if (NULL == invoke_list_func(insert_element, list, di, src)) {
+ return processed; // LCOV_EXCL_LINE
+ }
+ last = src;
+ di++;
+ }
+ processed++;
+ src += elem_size;
+ }
+ }
}
- return inserted;
+ return processed;
+}
+
+size_t cx_list_default_insert_sorted(
+ struct cx_list_s *list,
+ const void *sorted_data,
+ size_t n
+) {
+ return cx_list_default_insert_sorted_impl(list, sorted_data, n, true);
+}
+
+size_t cx_list_default_insert_unique(
+ struct cx_list_s *list,
+ const void *sorted_data,
+ size_t n
+) {
+ return cx_list_default_insert_sorted_impl(list, sorted_data, n, false);
}
void cx_list_default_sort(struct cx_list_s *list) {
size_t elem_size = list->collection.elem_size;
size_t list_size = list->collection.size;
void *tmp = cxMallocDefault(elem_size * list_size);
- if (tmp == NULL) abort();
+ if (tmp == NULL) abort(); // LCOV_EXCL_LINE
// copy elements from source array
char *loc = tmp;
@@ -388,7 +484,7 @@ int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) {
size_t elem_size = list->collection.elem_size;
void *tmp = cxMallocDefault(elem_size);
- if (tmp == NULL) return 1;
+ if (tmp == NULL) return 1; // LCOV_EXCL_LINE
void *ip = invoke_list_func(at, list, i);
void *jp = invoke_list_func(at, list, j);
@@ -472,34 +568,174 @@ int cxListCompare(
}
}
-CxIterator cxListMutIteratorAt(
- CxList *list,
- size_t index
-) {
- CxIterator it = list->cl->iterator(list, index, false);
- it.base.mutating = true;
- return it;
+size_t cxListSize(const CxList *list) {
+ return list->collection.size;
}
-CxIterator cxListMutBackwardsIteratorAt(
- CxList *list,
- size_t index
-) {
- CxIterator it = list->cl->iterator(list, index, true);
- it.base.mutating = true;
- return it;
+int cxListAdd(CxList *list, const void *elem) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, list->collection.size, elem) == NULL;
}
-void cxListFree(CxList *list) {
- if (list == NULL) return;
- list->cl->deallocate(list);
+size_t cxListAddArray(CxList *list, const void *array, size_t n) {
+ list->collection.sorted = false;
+ return list->cl->insert_array(list, list->collection.size, array, n);
}
-int cxListSet(
- CxList *list,
- size_t index,
- const void *elem
-) {
+int cxListInsert(CxList *list, size_t index, const void *elem) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, index, elem) == NULL;
+}
+
+void *cxListEmplaceAt(CxList *list, size_t index) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, index, NULL);
+}
+
+void *cxListEmplace(CxList *list) {
+ list->collection.sorted = false;
+ return list->cl->insert_element(list, list->collection.size, NULL);
+}
+
+static bool cx_list_emplace_iterator_valid(const void *it) {
+ const CxIterator *iter = it;
+ return iter->index < iter->elem_count;
+}
+
+CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n) {
+ list->collection.sorted = false;
+ size_t c = list->cl->insert_array(list, index, NULL, n);
+ CxIterator iter = list->cl->iterator(list, index, false);
+ // tweak the fields of this iterator
+ iter.elem_count = c;
+ iter.index = 0;
+ // replace the valid function to abort iteration when c is reached
+ iter.base.valid = cx_list_emplace_iterator_valid;
+ // if we are storing pointers, we want to return the pure pointers.
+ // therefore, we must unwrap the "current" method
+ if (list->collection.store_pointer) {
+ iter.base.current = iter.base.current_impl;
+ }
+ return iter;
+}
+
+CxIterator cxListEmplaceArray(CxList *list, size_t n) {
+ return cxListEmplaceArrayAt(list, list->collection.size, n);
+}
+
+int cxListInsertSorted(CxList *list, const void *elem) {
+ assert(cxCollectionSorted(list));
+ list->collection.sorted = true;
+ const void *data = list->collection.store_pointer ? &elem : elem;
+ return list->cl->insert_sorted(list, data, 1) == 0;
+}
+
+int cxListInsertUnique(CxList *list, const void *elem) {
+ if (cxCollectionSorted(list)) {
+ list->collection.sorted = true;
+ const void *data = list->collection.store_pointer ? &elem : elem;
+ return list->cl->insert_unique(list, data, 1) == 0;
+ } else {
+ if (cxListContains(list, elem)) {
+ return 0;
+ } else {
+ return cxListAdd(list, elem);
+ }
+ }
+}
+
+size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n) {
+ list->collection.sorted = false;
+ return list->cl->insert_array(list, index, array, n);
+}
+
+size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n) {
+ assert(cxCollectionSorted(list));
+ list->collection.sorted = true;
+ return list->cl->insert_sorted(list, array, n);
+}
+
+size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n) {
+ if (cxCollectionSorted(list)) {
+ list->collection.sorted = true;
+ return list->cl->insert_unique(list, array, n);
+ } else {
+ const char *source = array;
+ for (size_t i = 0 ; i < n; i++) {
+ // note: this also checks elements added in a previous iteration
+ const void *data = list->collection.store_pointer ?
+ *((const void**)source) : source;
+ if (!cxListContains(list, data)) {
+ if (cxListAdd(list, data)) {
+ return i; // LCOV_EXCL_LINE
+ }
+ }
+ source += list->collection.elem_size;
+ }
+ return n;
+ }
+}
+
+int cxListInsertAfter(CxIterator *iter, const void *elem) {
+ CxList* list = (CxList*)iter->src_handle;
+ list->collection.sorted = false;
+ return list->cl->insert_iter(iter, elem, 0);
+}
+
+int cxListInsertBefore(CxIterator *iter, const void *elem) {
+ CxList* list = (CxList*)iter->src_handle;
+ list->collection.sorted = false;
+ return list->cl->insert_iter(iter, elem, 1);
+}
+
+int cxListRemove(CxList *list, size_t index) {
+ return list->cl->remove(list, index, 1, NULL) == 0;
+}
+
+int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf) {
+ return list->cl->remove(list, index, 1, targetbuf) == 0;
+}
+
+int cxListRemoveAndGetFirst(CxList *list, void *targetbuf) {
+ return list->cl->remove(list, 0, 1, targetbuf) == 0;
+}
+
+int cxListRemoveAndGetLast(CxList *list, void *targetbuf) {
+ // note: index may wrap - member function will catch that
+ return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0;
+}
+
+size_t cxListRemoveArray(CxList *list, size_t index, size_t num) {
+ return list->cl->remove(list, index, num, NULL);
+}
+
+size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf) {
+ return list->cl->remove(list, index, num, targetbuf);
+}
+
+void cxListClear(CxList *list) {
+ list->cl->clear(list);
+ list->collection.sorted = true; // empty lists are always sorted
+}
+
+int cxListSwap(CxList *list, size_t i, size_t j) {
+ list->collection.sorted = false;
+ return list->cl->swap(list, i, j);
+}
+
+void *cxListAt(const CxList *list, size_t index) {
+ return list->cl->at(list, index);
+}
+
+void *cxListFirst(const CxList *list) {
+ return list->cl->at(list, 0);
+}
+
+void *cxListLast(const CxList *list) {
+ return list->cl->at(list, list->collection.size - 1);
+}
+
+int cxListSet(CxList *list, size_t index, const void *elem) {
if (index >= list->collection.size) {
return 1;
}
@@ -515,3 +751,56 @@ int cxListSet(
return 0;
}
+
+CxIterator cxListIteratorAt(const CxList *list, size_t index) {
+ if (list == NULL) list = cxEmptyList;
+ return list->cl->iterator(list, index, false);
+}
+
+CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) {
+ if (list == NULL) list = cxEmptyList;
+ return list->cl->iterator(list, index, true);
+}
+
+CxIterator cxListIterator(const CxList *list) {
+ if (list == NULL) list = cxEmptyList;
+ return list->cl->iterator(list, 0, false);
+}
+
+CxIterator cxListBackwardsIterator(const CxList *list) {
+ if (list == NULL) list = cxEmptyList;
+ return list->cl->iterator(list, list->collection.size - 1, true);
+}
+
+size_t cxListFind(const CxList *list, const void *elem) {
+ return list->cl->find_remove((CxList*)list, elem, false);
+}
+
+bool cxListContains(const CxList* list, const void* elem) {
+ return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size;
+}
+
+bool cxListIndexValid(const CxList *list, size_t index) {
+ return index < list->collection.size;
+}
+
+size_t cxListFindRemove(CxList *list, const void *elem) {
+ return list->cl->find_remove(list, elem, true);
+}
+
+void cxListSort(CxList *list) {
+ if (list->collection.sorted) return;
+ list->cl->sort(list);
+ list->collection.sorted = true;
+}
+
+void cxListReverse(CxList *list) {
+ // still sorted, but not according to the cmp_func
+ list->collection.sorted = false;
+ list->cl->reverse(list);
+}
+
+void cxListFree(CxList *list) {
+ if (list == NULL) return;
+ list->cl->deallocate(list);
+}
diff --git a/ucx/map.c b/ucx/map.c
index 49223f5..d0c41f4 100644
--- a/ucx/map.c
+++ b/ucx/map.c
@@ -51,7 +51,7 @@ static CxMapIterator cx_empty_map_iterator(
cx_attr_unused enum cx_map_iterator_type type
) {
CxMapIterator iter = {0};
- iter.map.c = map;
+ iter.map = (CxMap*) map;
iter.base.valid = cx_empty_map_iter_valid;
return iter;
}
@@ -84,22 +84,43 @@ CxMap *const cxEmptyMap = &cx_empty_map;
//
-CxMapIterator cxMapMutIteratorValues(CxMap *map) {
- CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);
- it.base.mutating = true;
- return it;
+void cxMapClear(CxMap *map) {
+ map->cl->clear(map);
}
-CxMapIterator cxMapMutIteratorKeys(CxMap *map) {
- CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);
- it.base.mutating = true;
- return it;
+size_t cxMapSize(const CxMap *map) {
+ return map->collection.size;
}
-CxMapIterator cxMapMutIterator(CxMap *map) {
- CxMapIterator it = map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);
- it.base.mutating = true;
- return it;
+CxMapIterator cxMapIteratorValues(const CxMap *map) {
+ if (map == NULL) map = cxEmptyMap;
+ return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES);
+}
+
+CxMapIterator cxMapIteratorKeys(const CxMap *map) {
+ if (map == NULL) map = cxEmptyMap;
+ return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS);
+}
+
+CxMapIterator cxMapIterator(const CxMap *map) {
+ if (map == NULL) map = cxEmptyMap;
+ return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS);
+}
+
+int cx_map_put(CxMap *map, CxHashKey key, void *value) {
+ return map->cl->put(map, key, value) == NULL;
+}
+
+void *cx_map_emplace(CxMap *map, CxHashKey key) {
+ return map->cl->put(map, key, NULL);
+}
+
+void *cx_map_get(const CxMap *map, CxHashKey key) {
+ return map->cl->get(map, key);
+}
+
+int cx_map_remove(CxMap *map, CxHashKey key, void *targetbuf) {
+ return map->cl->remove(map, key, targetbuf);
}
void cxMapFree(CxMap *map) {
diff --git a/ucx/mempool.c b/ucx/mempool.c
index 8711439..fab6427 100644
--- a/ucx/mempool.c
+++ b/ucx/mempool.c
@@ -633,13 +633,19 @@ int cxMempoolTransfer(
new_source_allocator->data = source;
// transfer all the data
- memcpy(&dest->data[dest->size], source->data, sizeof(void*)*source->size);
- dest->size += source->size;
+ if (source->size > 0) {
+ memcpy(&dest->data[dest->size], source->data,
+ sizeof(void*)*source->size);
+ dest->size += source->size;
+ }
// transfer all registered memory
- memcpy(&dest->registered[dest->registered_size], source->registered,
- sizeof(struct cx_mempool_foreign_memory_s) * source->size);
- dest->registered_size += source->registered_size;
+ if (source->registered_size > 0) {
+ memcpy(&dest->registered[dest->registered_size], source->registered,
+ sizeof(struct cx_mempool_foreign_memory_s)
+ * source->registered_size);
+ dest->registered_size += source->registered_size;
+ }
// register the old allocator with the new pool
// we have to remove const-ness for this, but that's okay here
diff --git a/ucx/properties.c b/ucx/properties.c
index 4593602..3583532 100644
--- a/ucx/properties.c
+++ b/ucx/properties.c
@@ -51,6 +51,12 @@ void cxPropertiesDestroy(CxProperties *prop) {
cxBufferDestroy(&prop->buffer);
}
+void cxPropertiesReset(CxProperties *prop) {
+ CxPropertiesConfig config = prop->config;
+ cxPropertiesDestroy(prop);
+ cxPropertiesInit(prop, config);
+}
+
int cxPropertiesFilln(
CxProperties *prop,
const char *buf,
@@ -244,7 +250,7 @@ static int cx_properties_sink_map(
CxMap *map = sink->sink;
CxAllocator *alloc = sink->data;
cxmutstr v = cx_strdup_a(alloc, value);
- int r = cx_map_put_cxstr(map, key, v.ptr);
+ int r = cxMapPut(map, key, v.ptr);
if (r != 0) cx_strfree_a(alloc, &v);
return r;
}
diff --git a/ucx/string.c b/ucx/string.c
index 61d88f3..52ce290 100644
--- a/ucx/string.c
+++ b/ucx/string.c
@@ -25,6 +25,10 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef MEMRCHR_NEED_GNU
+#define _GNU_SOURCE
+#endif
+
#include "cx/string.h"
#include
@@ -33,6 +37,7 @@
#include
#include
#include
+#include
#ifdef _WIN32
#define cx_strcasecmp_impl _strnicmp
@@ -42,7 +47,7 @@
#endif
cxmutstr cx_mutstr(char *cstring) {
- return (cxmutstr) {cstring, strlen(cstring)};
+ return (cxmutstr) {cstring, cstring == NULL ? 0 : strlen(cstring)};
}
cxmutstr cx_mutstrn(
@@ -53,7 +58,7 @@ cxmutstr cx_mutstrn(
}
cxstring cx_str(const char *cstring) {
- return (cxstring) {cstring, strlen(cstring)};
+ return (cxstring) {cstring, cstring == NULL ? 0 : strlen(cstring)};
}
cxstring cx_strn(
@@ -231,19 +236,24 @@ cxmutstr cx_strchr_m(
}
cxstring cx_strrchr(
- cxstring string,
- int chr
+ cxstring string,
+ int chr
) {
+#ifdef WITH_MEMRCHR
+ char *ret = memrchr(string.ptr, 0xFF & chr, string.length);
+ if (ret == NULL) return (cxstring) {NULL, 0};
+ return (cxstring) {ret, string.length - (ret - string.ptr)};
+#else
chr = 0xFF & chr;
size_t i = string.length;
while (i > 0) {
i--;
- // TODO: improve by comparing multiple bytes at once
if (string.ptr[i] == chr) {
return cx_strsubs(string, i);
}
}
return (cxstring) {NULL, 0};
+#endif
}
cxmutstr cx_strrchr_m(
@@ -451,7 +461,7 @@ size_t cx_strsplit_ma(
delim, limit, (cxstring **) output);
}
-int cx_strcmp(
+int cx_strcmp_(
cxstring s1,
cxstring s2
) {
@@ -468,7 +478,7 @@ int cx_strcmp(
}
}
-int cx_strcasecmp(
+int cx_strcasecmp_(
cxstring s1,
cxstring s2
) {
@@ -520,19 +530,13 @@ cxmutstr cx_strdup_a_(
return result;
}
-static bool str_isspace(char c) {
- // TODO: remove once UCX has public API for this
- return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f';
-}
-
cxstring cx_strtrim(cxstring string) {
cxstring result = string;
- // TODO: optimize by comparing multiple bytes at once
- while (result.length > 0 && str_isspace(*result.ptr)) {
+ while (result.length > 0 && isspace((unsigned char)(result.ptr[0]))) {
result.ptr++;
result.length--;
}
- while (result.length > 0 && str_isspace(result.ptr[result.length - 1])) {
+ while (result.length > 0 && isspace((unsigned char)result.ptr[result.length - 1])) {
result.length--;
}
return result;
@@ -543,7 +547,7 @@ cxmutstr cx_strtrim_m(cxmutstr string) {
return (cxmutstr) {(char *) result.ptr, result.length};
}
-bool cx_strprefix(
+bool cx_strprefix_(
cxstring string,
cxstring prefix
) {
@@ -551,7 +555,7 @@ bool cx_strprefix(
return memcmp(string.ptr, prefix.ptr, prefix.length) == 0;
}
-bool cx_strsuffix(
+bool cx_strsuffix_(
cxstring string,
cxstring suffix
) {
@@ -560,7 +564,7 @@ bool cx_strsuffix(
suffix.ptr, suffix.length) == 0;
}
-bool cx_strcaseprefix(
+bool cx_strcaseprefix_(
cxstring string,
cxstring prefix
) {
@@ -572,7 +576,7 @@ bool cx_strcaseprefix(
#endif
}
-bool cx_strcasesuffix(
+bool cx_strcasesuffix_(
cxstring string,
cxstring suffix
) {
@@ -957,11 +961,6 @@ int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep
return 0;
}
-static bool str_isdigit(char c) {
- // TODO: remove once UCX has public API for this
- return c >= '0' && c <= '9';
-}
-
int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep) {
// TODO: overflow check
// TODO: increase precision
@@ -994,7 +993,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
// parse all digits until we find the decsep
size_t pos = 0;
do {
- if (str_isdigit(str.ptr[pos])) {
+ if (isdigit((unsigned char)str.ptr[pos])) {
result = result * 10 + (str.ptr[pos] - '0');
} else if (strchr(groupsep, str.ptr[pos]) == NULL) {
break;
@@ -1023,7 +1022,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
// parse everything until exponent or end
double factor = 1.;
do {
- if (str_isdigit(str.ptr[pos])) {
+ if (isdigit((unsigned char)str.ptr[pos])) {
factor *= 0.1;
result = result + factor * (str.ptr[pos] - '0');
} else if (strchr(groupsep, str.ptr[pos]) == NULL) {
@@ -1064,7 +1063,7 @@ int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupse
// parse the exponent
unsigned int exp = 0;
do {
- if (str_isdigit(str.ptr[pos])) {
+ if (isdigit((unsigned char)str.ptr[pos])) {
exp = 10 * exp + (str.ptr[pos] - '0');
} else if (strchr(groupsep, str.ptr[pos]) == NULL) {
errno = EINVAL;
diff --git a/ucx/tree.c b/ucx/tree.c
index 1b2b38e..d948a4c 100644
--- a/ucx/tree.c
+++ b/ucx/tree.c
@@ -375,7 +375,7 @@ CxTreeIterator cx_tree_iterator(
iter.skip = false;
// assign base iterator functions
- iter.base.mutating = false;
+ iter.base.allow_remove = false;
iter.base.remove = false;
iter.base.current_impl = NULL;
iter.base.valid = cx_tree_iter_valid;
@@ -496,7 +496,7 @@ CxTreeVisitor cx_tree_visitor(
iter.queue_last = NULL;
// assign base iterator functions
- iter.base.mutating = false;
+ iter.base.allow_remove = false;
iter.base.remove = false;
iter.base.current_impl = NULL;
iter.base.valid = cx_tree_visitor_valid;
@@ -717,7 +717,7 @@ size_t cx_tree_add_array(
}
// otherwise, create iterator and hand over to other function
- CxIterator iter = cxIterator(src, elem_size, num);
+ CxIterator iter = cxIterator(src, elem_size, num, false);
return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc,
cfunc, cdata, failed, root,
loc_parent, loc_children, loc_last_child,
@@ -804,16 +804,12 @@ static cx_tree_class cx_tree_default_class = {
cx_tree_default_find
};
-CxTree *cxTreeCreate(
- const CxAllocator *allocator,
+CxTree *cxTreeCreate(const CxAllocator *allocator,
cx_tree_node_create_func create_func,
cx_tree_search_func search_func,
cx_tree_search_data_func search_data_func,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next
) {
if (allocator == NULL) {
allocator = cxDefaultAllocator;
@@ -852,15 +848,9 @@ void cxTreeFree(CxTree *tree) {
cxFree(tree->allocator, tree);
}
-CxTree *cxTreeCreateWrapped(
- const CxAllocator *allocator,
- void *root,
- ptrdiff_t loc_parent,
- ptrdiff_t loc_children,
- ptrdiff_t loc_last_child,
- ptrdiff_t loc_prev,
- ptrdiff_t loc_next
-) {
+CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root,
+ ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+ ptrdiff_t loc_prev, ptrdiff_t loc_next) {
if (allocator == NULL) {
allocator = cxDefaultAllocator;
}
@@ -888,11 +878,7 @@ CxTree *cxTreeCreateWrapped(
return tree;
}
-void cxTreeSetParent(
- CxTree *tree,
- void *parent,
- void *child
-) {
+void cxTreeSetParent(CxTree *tree, void *parent, void *child) {
size_t loc_parent = tree->loc_parent;
if (tree_parent(child) == NULL) {
tree->size++;
@@ -900,19 +886,12 @@ void cxTreeSetParent(
cx_tree_link(parent, child, cx_tree_node_layout(tree));
}
-void cxTreeAddChildNode(
- CxTree *tree,
- void *parent,
- void *child
-) {
+void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) {
cx_tree_link(parent, child, cx_tree_node_layout(tree));
tree->size++;
}
-int cxTreeAddChild(
- CxTree *tree,
- void *parent,
- const void *data) {
+int cxTreeAddChild(CxTree *tree, void *parent, const void *data) {
void *node = tree->node_create(data, tree);
if (node == NULL) return 1;
cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
@@ -921,6 +900,29 @@ int cxTreeAddChild(
return 0;
}
+int cxTreeInsert(CxTree *tree, const void *data) {
+ return tree->cl->insert_element(tree, data);
+}
+
+size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n) {
+ return tree->cl->insert_many(tree, iter, n);
+}
+
+size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n) {
+ if (n == 0) return 0;
+ if (n == 1) return 0 == cxTreeInsert(tree, data) ? 1 : 0;
+ CxIterator iter = cxIterator(data, elem_size, n, false);
+ return cxTreeInsertIter(tree, cxIteratorRef(iter), n);
+}
+
+void *cxTreeFind( CxTree *tree, const void *data) {
+ return tree->cl->find(tree, tree->root, data, 0);
+}
+
+void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth) {
+ return tree->cl->find(tree, subtree_root, data, max_depth);
+}
+
size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root) {
CxTreeVisitor visitor = cx_tree_visitor(
subtree_root,
@@ -945,6 +947,10 @@ size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root) {
return visitor.depth;
}
+size_t cxTreeSize(CxTree *tree) {
+ return tree->size;
+}
+
size_t cxTreeDepth(CxTree *tree) {
CxTreeVisitor visitor = cx_tree_visitor(
tree->root, tree->loc_children, tree->loc_next
@@ -1052,3 +1058,38 @@ void cxTreeDestroySubtree(CxTree *tree, void *node) {
tree->root = NULL;
}
}
+
+void cxTreeIteratorDispose(CxTreeIterator *iter) {
+ cxFreeDefault(iter->stack);
+ iter->stack = NULL;
+}
+
+void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
+ struct cx_tree_visitor_queue_s *q = visitor->queue_next;
+ while (q != NULL) {
+ struct cx_tree_visitor_queue_s *next = q->next;
+ cxFreeDefault(q);
+ q = next;
+ }
+}
+
+CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) {
+ return cx_tree_iterator(
+ node, visit_on_exit,
+ tree->loc_children, tree->loc_next
+ );
+}
+
+CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) {
+ return cx_tree_visitor(
+ node, tree->loc_children, tree->loc_next
+ );
+}
+
+CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit) {
+ return cxTreeIterateSubtree(tree, tree->root, visit_on_exit);
+}
+
+CxTreeVisitor cxTreeVisit(CxTree *tree) {
+ return cxTreeVisitSubtree(tree, tree->root);
+}
diff --git a/ui/common/args.c b/ui/common/args.c
index e799889..796919b 100644
--- a/ui/common/args.c
+++ b/ui/common/args.c
@@ -33,6 +33,156 @@
#include "../ui/container.h"
+
+/* ---------------------------- UiDialogArgs ---------------------------- */
+
+UiDialogArgs* ui_dialog_args_new(void) {
+ UiDialogArgs *args = malloc(sizeof(UiDialogArgs));
+ memset(args, 0, sizeof(UiDialogArgs));
+ return args;
+}
+
+void ui_dialog_args_set_title(UiDialogArgs *args, const char *title) {
+ args->title = strdup(title);
+}
+
+void ui_dialog_args_set_content(UiDialogArgs *args, const char *str) {
+ args->content = strdup(str);
+}
+
+void ui_dialog_args_set_button1_label(UiDialogArgs *args, const char *label) {
+ args->button1_label = strdup(label);
+}
+
+void ui_dialog_args_set_button2_label(UiDialogArgs *args, const char *label) {
+ args->button2_label = strdup(label);
+}
+
+void ui_dialog_args_set_closebutton_label(UiDialogArgs *args, const char *label) {
+ args->closebutton_label = strdup(label);
+}
+
+void ui_dialog_args_set_input_value(UiDialogArgs *args, const char *value) {
+ args->input_value = strdup(value);
+}
+
+void ui_dialog_args_set_input(UiDialogArgs *args, UiBool input) {
+ args->input = input;
+}
+
+void ui_dialog_args_set_password(UiDialogArgs *args, UiBool password) {
+ args->password = password;
+}
+
+void ui_dialog_args_set_result(UiDialogArgs *args, ui_callback cb) {
+ args->result = cb;
+}
+
+void ui_dialog_args_set_resultdata(UiDialogArgs *args, void *userdata) {
+ args->resultdata = userdata;
+}
+
+void ui_dialog_args_free(UiDialogArgs *args) {
+ free((void*)args->title);
+ free((void*)args->button1_label);
+ free((void*)args->button2_label);
+ free((void*)args->content);
+ free((void*)args->closebutton_label);
+ free((void*)args->input_value);
+ free(args);
+}
+
+
+/* -------------------------- UiDialogWindowArgs -------------------------- */
+
+UiDialogWindowArgs* ui_dialogwindow_args_new(void) {
+ UiDialogWindowArgs *args = malloc(sizeof(UiDialogWindowArgs));
+ memset(args, 0, sizeof(UiDialogWindowArgs));
+ return args;
+}
+
+void ui_dialogwindow_args_set_modal(UiDialogWindowArgs *args, UiTri value) {
+ args->modal = value;
+}
+
+void ui_dialogwindow_args_set_titlebar_buttons(UiDialogWindowArgs *args, UiTri value) {
+ args->titlebar_buttons = value;
+}
+
+void ui_dialogwindow_args_set_show_closebutton(UiDialogWindowArgs *args, UiTri value) {
+ args->show_closebutton = value;
+}
+
+void ui_dialogwindow_args_set_title(UiDialogWindowArgs *args, const char *title) {
+ args->title = strdup(title);
+}
+
+void ui_dialogwindow_args_set_lbutton1(UiDialogWindowArgs *args, const char *label) {
+ args->lbutton1 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_lbutton2(UiDialogWindowArgs *args, const char *label) {
+ args->lbutton2 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_rbutton3(UiDialogWindowArgs *args, const char *label) {
+ args->rbutton3 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_rbutton4(UiDialogWindowArgs *args, const char *label) {
+ args->rbutton4 = strdup(label);
+}
+
+void ui_dialogwindow_args_set_lbutton1_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_lbutton2_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_rbutton3_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_rbutton4_states(UiDialogWindowArgs *args, const int *states) {
+ // TODO
+}
+
+void ui_dialogwindow_args_set_default_button(UiDialogWindowArgs *args, int button) {
+ args->default_button = button;
+}
+
+void ui_dialogwindow_args_set_width(UiDialogWindowArgs *args, int width) {
+ args->width = width;
+}
+
+void ui_dialogwindow_args_set_height(UiDialogWindowArgs *args, int height) {
+ args->height = height;
+}
+
+void ui_dialogwindow_args_set_onclick(UiDialogWindowArgs *args, ui_callback cb) {
+ args->onclick = cb;
+}
+
+void ui_dialogwindow_args_set_onclickdata(UiDialogWindowArgs *args, void *userdata) {
+ args->onclickdata = userdata;
+}
+
+void ui_dialogwindow_args_free(UiDialogWindowArgs *args) {
+ free((void*)args->title);
+ free((void*)args->lbutton1);
+ free((void*)args->lbutton2);
+ free((void*)args->rbutton3);
+ free((void*)args->rbutton4);
+ free((void*)args->lbutton1_groups);
+ free((void*)args->lbutton2_groups);
+ free((void*)args->rbutton3_groups);
+ free((void*)args->rbutton4_groups);
+ free(args);
+}
+
+
/* ---------------------------- UiMenuItemArgs ---------------------------- */
UiMenuItemArgs* ui_menuitem_args_new(void) {
@@ -45,10 +195,6 @@ void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label) {
args->label = strdup(label);
}
-void ui_menuitem_args_set_stockid(UiMenuItemArgs *args, const char *stockid) {
- args->stockid = strdup(stockid);
-}
-
void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon) {
args->icon = strdup(icon);
}
@@ -63,7 +209,6 @@ void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata) {
void ui_menuitem_args_free(UiMenuItemArgs *args) {
free((void*)args->label);
- free((void*)args->stockid);
free((void*)args->icon);
free(args);
}
@@ -81,10 +226,6 @@ void ui_menutoggleitem_args_set_label(UiMenuToggleItemArgs *args, const char *la
args->label = strdup(label);
}
-void ui_menutoggleitem_args_set_stockid(UiMenuToggleItemArgs *args, const char *stockid) {
- args->stockid = strdup(stockid);
-}
-
void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const char *icon) {
args->icon = strdup(icon);
}
@@ -103,7 +244,6 @@ void ui_menutoggleitem_args_set_onchangedata(UiMenuToggleItemArgs *args, void *o
void ui_menutoggleitem_args_free(UiMenuToggleItemArgs *args) {
free((void*)args->label);
- free((void*)args->stockid);
free((void*)args->icon);
free((void*)args->varname);
free(args);
@@ -154,14 +294,14 @@ void ui_toolbar_item_args_set_label(UiToolbarItemArgs *args, const char *label)
args->label = strdup(label);
}
-void ui_toolbar_item_args_set_stockid(UiToolbarItemArgs *args, const char *stockid) {
- args->stockid = strdup(stockid);
-}
-
void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char *icon) {
args->icon = strdup(icon);
}
+void ui_toolbar_item_args_set_tooltip(UiToolbarItemArgs *args, const char *tooltip) {
+ args->tooltip = strdup(tooltip);
+}
+
void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback) {
args->onclick = callback;
}
@@ -170,13 +310,16 @@ void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclick
args->onclickdata = onclickdata;
}
-void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *groups) {
- // TODO
+void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
}
void ui_toolbar_item_args_free(UiToolbarItemArgs *args) {
free((void*)args->label);
- free((void*)args->stockid);
free((void*)args->icon);
+ free((void*)args->tooltip);
+ free((void*)args->groups);
free(args);
}
@@ -188,47 +331,42 @@ UiToolbarToggleItemArgs* ui_toolbar_toggleitem_args_new(void) {
return args;
}
-
void ui_toolbar_toggleitem_args_set_label(UiToolbarToggleItemArgs *args, const char *label) {
args->label = strdup(label);
}
-
-void ui_toolbar_toggleitem_args_set_stockid(UiToolbarToggleItemArgs *args, const char *stockid) {
- args->stockid = strdup(stockid);
-}
-
-
void ui_toolbar_toggleitem_args_set_icon(UiToolbarToggleItemArgs *args, const char *icon) {
args->icon = strdup(icon);
}
+void ui_toolbar_toggleitem_args_set_tooltip(UiToolbarToggleItemArgs *args, const char *tooltip) {
+ args->tooltip = strdup(tooltip);
+}
void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname) {
args->varname = strdup(varname);
}
-
void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback) {
args->onchange = callback;
}
-
void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args, void *onchangedata) {
args->onchangedata = onchangedata;
}
-
-void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args, int *groups) {
- // TODO
+void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args,int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
}
-
void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args) {
free((void*)args->label);
- free((void*)args->stockid);
free((void*)args->icon);
+ free((void*)args->tooltip);
free((void*)args->varname);
+ free((void*)args->groups);
free(args);
}
@@ -241,26 +379,22 @@ UiToolbarMenuArgs* ui_toolbar_menu_args_new(void) {
return args;
}
-
void ui_toolbar_menu_args_set_label(UiToolbarMenuArgs *args, const char *label) {
args->label = strdup(label);
}
-
-void ui_toolbar_menu_args_set_stockid(UiToolbarMenuArgs *args, const char *stockid) {
- args->stockid = strdup(stockid);
-}
-
-
void ui_toolbar_menu_args_set_icon(UiToolbarMenuArgs *args, const char *icon) {
args->icon = strdup(icon);
}
+void ui_toolbar_menu_args_set_tooltip(UiToolbarMenuArgs *args, const char *tooltip) {
+ args->tooltip = strdup(tooltip);
+}
void ui_toolbar_menu_args_free(UiToolbarMenuArgs *args) {
free((void*)args->label);
- free((void*)args->stockid);
free((void*)args->icon);
+ free((void*)args->tooltip);
free(args);
}
@@ -274,7 +408,7 @@ UiContainerArgs* ui_container_args_new(void) {
}
void ui_container_args_set_fill(UiContainerArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
void ui_container_args_set_hexpand(UiContainerArgs *args, UiBool value) {
@@ -346,6 +480,22 @@ void ui_container_args_set_margin(UiContainerArgs *args, int value) {
args->margin = value;
}
+void ui_container_args_set_margin_left(UiContainerArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_container_args_set_margin_right(UiContainerArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_container_args_set_margin_top(UiContainerArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_container_args_set_margin_bottom(UiContainerArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
void ui_container_args_set_spacing(UiContainerArgs *args, int value) {
args->spacing = value;
@@ -379,7 +529,7 @@ UiFrameArgs* ui_frame_args_new(void) {
void ui_frame_args_set_fill(UiFrameArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
@@ -407,6 +557,26 @@ void ui_frame_args_set_override_defaults(UiFrameArgs *args, UiBool value) {
args->override_defaults = value;
}
+void ui_frame_args_set_margin(UiFrameArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_frame_args_set_margin_left(UiFrameArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_frame_args_set_margin_right(UiFrameArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_frame_args_set_margin_top(UiFrameArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_frame_args_set_margin_bottom(UiFrameArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
void ui_frame_args_set_colspan(UiFrameArgs *args, int colspan) {
args->colspan = colspan;
@@ -427,11 +597,13 @@ void ui_frame_args_set_style_class(UiFrameArgs *args, const char *classname) {
args->style_class = strdup(classname);
}
-
-void ui_frame_args_set_margin(UiFrameArgs *args, int value) {
- args->margin = value;
+void ui_frame_args_set_subcontainer(UiFrameArgs *args, UiSubContainerType subcontainer) {
+ args->subcontainer = subcontainer;
}
+void ui_frame_args_set_padding(UiFrameArgs *args, int value) {
+ args->padding = value;
+}
void ui_frame_args_set_spacing(UiFrameArgs *args, int value) {
args->spacing = value;
@@ -457,7 +629,6 @@ void ui_frame_args_set_label(UiFrameArgs *args, const char *label) {
args->label = strdup(label);
}
-
void ui_frame_args_free(UiFrameArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
@@ -474,27 +645,38 @@ UiSidebarArgs* ui_sidebar_args_new(void) {
return args;
}
-
void ui_sidebar_args_set_name(UiSidebarArgs *args, const char *name) {
args->name = strdup(name);
}
-
void ui_sidebar_args_set_style_class(UiSidebarArgs *args, const char *classname) {
args->style_class = strdup(classname);
}
-
void ui_sidebar_args_set_margin(UiSidebarArgs *args, int value) {
args->margin = value;
}
+void ui_sidebar_args_set_margin_left(UiSidebarArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_sidebar_args_set_margin_right(UiSidebarArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_sidebar_args_set_margin_top(UiSidebarArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_sidebar_args_set_margin_bottom(UiSidebarArgs *args, int value) {
+ args->margin_bottom = value;
+}
void ui_sidebar_args_set_spacing(UiSidebarArgs *args, int value) {
args->spacing = value;
}
-
void ui_sidebar_args_free(UiSidebarArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
@@ -510,61 +692,66 @@ UiSplitPaneArgs* ui_splitpane_args_new(void) {
return args;
}
-
void ui_splitpane_args_set_fill(UiSplitPaneArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
-
void ui_splitpane_args_set_hexpand(UiSplitPaneArgs *args, UiBool value) {
args->hexpand = value;
}
-
void ui_splitpane_args_set_vexpand(UiSplitPaneArgs *args, UiBool value) {
args->vexpand = value;
}
-
void ui_splitpane_args_set_hfill(UiSplitPaneArgs *args, UiBool value) {
args->hfill = value;
}
-
void ui_splitpane_args_set_vfill(UiSplitPaneArgs *args, UiBool value) {
args->vfill = value;
}
-
void ui_splitpane_args_set_override_defaults(UiSplitPaneArgs *args, UiBool value) {
args->override_defaults = value;
}
-
void ui_splitpane_args_set_colspan(UiSplitPaneArgs *args, int colspan) {
args->colspan = colspan;
}
-
void ui_splitpane_args_set_rowspan(UiSplitPaneArgs *args, int rowspan) {
args->rowspan = rowspan;
}
-
void ui_splitpane_args_set_name(UiSplitPaneArgs *args, const char *name) {
args->name = strdup(name);
}
-
void ui_splitpane_args_set_style_class(UiSplitPaneArgs *args, const char *classname) {
args->style_class = strdup(classname);
}
-
void ui_splitpane_args_set_margin(UiSplitPaneArgs *args, int value) {
args->margin = value;
}
+void ui_splitpane_args_set_margin_left(UiSplitPaneArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_splitpane_args_set_margin_right(UiSplitPaneArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_splitpane_args_set_margin_top(UiSplitPaneArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_splitpane_args_set_margin_bottom(UiSplitPaneArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
void ui_splitpane_args_set_spacing(UiSplitPaneArgs *args, int value) {
args->spacing = value;
@@ -585,6 +772,9 @@ void ui_splitpane_args_set_initial_position(UiSplitPaneArgs *args, int pos) {
args->initial_position = pos;
}
+void ui_splitpane_args_set_position_property(UiSplitPaneArgs *args, const char *propname) {
+ args->position_property = strdup(propname);
+}
void ui_splitpane_args_set_varname(UiSplitPaneArgs *args, const char *varname) {
args->varname = strdup(varname);
@@ -599,8 +789,125 @@ void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max) {
args->max_panes = max;
}
-
void ui_splitpane_args_free(UiSplitPaneArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->varname);
+ free((void*)args->position_property);
+ free(args);
+}
+
+
+/* ---------------------------- UiTabViewArgs ---------------------------- */
+
+UiTabViewArgs* ui_tabview_args_new(void) {
+ UiTabViewArgs *args = malloc(sizeof(UiTabViewArgs));
+ memset(args, 0, sizeof(UiTabViewArgs));
+ return args;
+}
+
+void ui_tabview_args_set_fill(UiTabViewArgs *args, UiBool fill) {
+ args->fill = fill;
+}
+
+void ui_tabview_args_set_hexpand(UiTabViewArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+void ui_tabview_args_set_vexpand(UiTabViewArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+void ui_tabview_args_set_hfill(UiTabViewArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+void ui_tabview_args_set_vfill(UiTabViewArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+void ui_tabview_args_set_override_defaults(UiTabViewArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+void ui_tabview_args_set_colspan(UiTabViewArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+void ui_tabview_args_set_rowspan(UiTabViewArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+void ui_tabview_args_set_name(UiTabViewArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+void ui_tabview_args_set_style_class(UiTabViewArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_tabview_args_set_margin(UiTabViewArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_tabview_args_set_margin_left(UiTabViewArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_tabview_args_set_margin_right(UiTabViewArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_tabview_args_set_margin_top(UiTabViewArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_tabview_args_set_margin_bottom(UiTabViewArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
+void ui_tabview_args_set_padding(UiTabViewArgs *args, int value) {
+ args->padding = value;
+}
+
+void ui_tabview_args_set_spacing(UiTabViewArgs *args, int value) {
+ args->spacing = value;
+}
+
+void ui_tabview_args_set_columnspacing(UiTabViewArgs *args, int value) {
+ args->columnspacing = value;
+}
+
+
+void ui_tabview_args_set_rowspacing(UiTabViewArgs *args, int value) {
+ args->rowspacing = value;
+}
+
+void ui_tabview_args_set_type(UiTabViewArgs *args, UiTabViewType tabview) {
+ args->tabview = tabview;
+}
+
+void ui_tabview_args_set_onchange(UiTabViewArgs *args, ui_callback cb) {
+ args->onchange = cb;
+}
+
+void ui_tabview_args_set_onchangedata(UiTabViewArgs *args, void *userdata) {
+ args->onchangedata = userdata;
+}
+
+void ui_tabview_args_set_varname(UiTabViewArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_tabview_args_set_value(UiTabViewArgs *args, UiInteger *value) {
+ args->value = value;
+}
+
+void ui_tabview_args_set_subcontainer(UiTabViewArgs *args, UiSubContainerType subcontainer) {
+ args->subcontainer = subcontainer;
+}
+
+void ui_tabview_args_free(UiTabViewArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
free((void*)args->varname);
@@ -608,6 +915,90 @@ void ui_splitpane_args_free(UiSplitPaneArgs *args) {
}
+/* ------------------------- UiWidgetArgs ----------------------------*/
+
+UiWidgetArgs* ui_widget_args_new(void) {
+ UiWidgetArgs *args = malloc(sizeof(UiWidgetArgs));
+ memset(args, 0, sizeof(UiWidgetArgs));
+ return args;
+}
+
+
+void ui_widget_args_set_fill(UiWidgetArgs *args, UiBool fill) {
+ args->fill = fill;
+}
+
+
+void ui_widget_args_set_hexpand(UiWidgetArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+
+void ui_widget_args_set_vexpand(UiWidgetArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+
+void ui_widget_args_set_hfill(UiWidgetArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_widget_args_set_vfill(UiWidgetArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_widget_args_set_override_defaults(UiWidgetArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+void ui_widget_args_set_margin(UiWidgetArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_widget_args_set_margin_left(UiWidgetArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_widget_args_set_margin_right(UiWidgetArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_widget_args_set_margin_top(UiWidgetArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_widget_args_set_margin_bottom(UiWidgetArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
+void ui_widget_args_set_colspan(UiWidgetArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_widget_args_set_rowspan(UiWidgetArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+
+void ui_widget_args_set_name(UiWidgetArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+
+void ui_widget_args_set_style_class(UiWidgetArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_widget_args_free(UiWidgetArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free(args);
+}
+
+
/* ------------------------- UiLabelArgs ----------------------------*/
@@ -617,36 +1008,49 @@ UiLabelArgs* ui_label_args_new(void) {
return args;
}
-
void ui_label_args_set_fill(UiLabelArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
-
void ui_label_args_set_hexpand(UiLabelArgs *args, UiBool value) {
args->hexpand = value;
}
-
void ui_label_args_set_vexpand(UiLabelArgs *args, UiBool value) {
args->vexpand = value;
}
-
void ui_label_args_set_hfill(UiLabelArgs *args, UiBool value) {
args->hfill = value;
}
-
void ui_label_args_set_vfill(UiLabelArgs *args, UiBool value) {
args->vfill = value;
}
-
void ui_label_args_set_override_defaults(UiLabelArgs *args, UiBool value) {
args->override_defaults = value;
}
+void ui_label_args_set_margin(UiLabelArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_label_args_set_margin_left(UiLabelArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_label_args_set_margin_right(UiLabelArgs *args, int value){
+ args->margin_right = value;
+}
+
+void ui_label_args_set_margin_top(UiLabelArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_label_args_set_margin_bottom(UiLabelArgs *args, int value) {
+ args->margin_bottom = value;
+}
void ui_label_args_set_colspan(UiLabelArgs *args, int colspan) {
args->colspan = colspan;
@@ -657,12 +1061,10 @@ void ui_label_args_set_rowspan(UiLabelArgs *args, int rowspan) {
args->rowspan = rowspan;
}
-
void ui_label_args_set_name(UiLabelArgs *args, const char *name) {
args->name = strdup(name);
}
-
void ui_label_args_set_style_class(UiLabelArgs *args, const char *classname) {
args->style_class = strdup(classname);
}
@@ -671,7 +1073,6 @@ void ui_label_args_set_label(UiLabelArgs *args, const char *label){
args->label = strdup(label);
}
-
void ui_label_args_set_align(UiLabelArgs *args, UiAlignment align) {
args->align = align;
}
@@ -708,7 +1109,7 @@ UiProgressbarArgs* ui_progressbar_args_new(void) {
void ui_progressbar_args_set_fill(UiProgressbarArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
@@ -736,6 +1137,25 @@ void ui_progressbar_args_set_override_defaults(UiProgressbarArgs *args, UiBool v
args->override_defaults = value;
}
+void ui_progressbar_args_set_margin(UiProgressbarArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_progressbar_args_set_margin_left(UiProgressbarArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_progressbar_args_set_margin_right(UiProgressbarArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_progressbar_args_set_margin_top(UiProgressbarArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_progressbar_args_set_margin_bottom(UiProgressbarArgs *args, int value) {
+ args->margin_bottom = value;
+}
void ui_progressbar_args_set_colspan(UiProgressbarArgs *args, int colspan) {
args->colspan = colspan;
@@ -789,7 +1209,7 @@ UiProgressbarSpinnerArgs* ui_progress_spinner_args_new(void) {
}
void ui_progress_spinner_args_set_fill(UiProgressbarSpinnerArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
void ui_progress_spinner_args_set_hexpand(UiProgressbarSpinnerArgs *args, UiBool value) {
@@ -812,6 +1232,26 @@ void ui_progress_spinner_args_set_override_defaults(UiProgressbarSpinnerArgs *ar
args->override_defaults = value;
}
+void ui_progress_spinner_args_set_margin(UiProgressbarSpinnerArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_progress_spinner_args_set_margin_left(UiProgressbarSpinnerArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_progress_spinner_args_set_margin_right(UiProgressbarSpinnerArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_progress_spinner_args_set_margin_top(UiProgressbarSpinnerArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_progress_spinner_args_set_margin_bottom(UiProgressbarSpinnerArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
void ui_progress_spinner_args_set_colspan(UiProgressbarSpinnerArgs *args, int colspan) {
args->colspan = colspan;
}
@@ -854,7 +1294,7 @@ UiButtonArgs* ui_button_args_new(void) {
void ui_button_args_set_fill(UiButtonArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
@@ -868,192 +1308,342 @@ void ui_button_args_set_vexpand(UiButtonArgs *args, UiBool value) {
}
-void ui_button_args_set_hfill(UiButtonArgs *args, UiBool value) {
- args->hfill = value;
+void ui_button_args_set_hfill(UiButtonArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+
+void ui_button_args_set_vfill(UiButtonArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+
+void ui_button_args_set_override_defaults(UiButtonArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+void ui_button_args_set_margin(UiButtonArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_button_args_set_margin_left(UiButtonArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_button_args_set_margin_right(UiButtonArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_button_args_set_margin_top(UiButtonArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_button_args_set_margin_bottom(UiButtonArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
+void ui_button_args_set_colspan(UiButtonArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+
+void ui_button_args_set_rowspan(UiButtonArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+void ui_button_args_set_name(UiButtonArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+void ui_button_args_set_style_class(UiButtonArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_button_args_set_label(UiButtonArgs *args, const char *label){
+ args->label = strdup(label);
+}
+
+void ui_button_args_set_icon(UiButtonArgs *args, const char *icon){
+ args->icon = strdup(icon);
+}
+
+void ui_button_args_set_tooltip(UiButtonArgs *args, const char *tooltip) {
+ args->tooltip = strdup(tooltip);
+}
+
+void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype){
+ args->labeltype = labeltype;
+}
+
+void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback){
+ args->onclick = callback;
+}
+
+void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata){
+ args->onclickdata = onclickdata;
+}
+
+void ui_button_args_set_groups(UiButtonArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
+}
+
+void ui_button_args_free(UiButtonArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->label);
+ free((void*)args->icon);
+ free((void*)args->tooltip);
+ free((void*)args->groups);
+ free(args);
+}
+
+
+/* ------------------------- UiToggleArgs ----------------------------*/
+
+
+UiToggleArgs* ui_toggle_args_new(void) {
+ UiToggleArgs *args = malloc(sizeof(UiToggleArgs));
+ memset(args, 0, sizeof(UiToggleArgs));
+ return args;
+}
+
+void ui_toggle_args_set_fill(UiToggleArgs *args, UiBool fill) {
+ args->fill = fill;
+}
+
+void ui_toggle_args_set_hexpand(UiToggleArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+void ui_toggle_args_set_vexpand(UiToggleArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+void ui_toggle_args_set_hfill(UiToggleArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+void ui_toggle_args_set_vfill(UiToggleArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+void ui_toggle_args_set_override_defaults(UiToggleArgs *args, UiBool value) {
+ args->override_defaults = value;
}
+void ui_toggle_args_set_margin(UiToggleArgs *args, int value) {
+ args->margin = value;
+}
-void ui_button_args_set_vfill(UiButtonArgs *args, UiBool value) {
- args->vfill = value;
+void ui_toggle_args_set_margin_left(UiToggleArgs *args, int value) {
+ args->margin_left = value;
}
+void ui_toggle_args_set_margin_right(UiToggleArgs *args, int value) {
+ args->margin_right = value;
+}
-void ui_button_args_set_override_defaults(UiButtonArgs *args, UiBool value) {
- args->override_defaults = value;
+void ui_toggle_args_set_margin_top(UiToggleArgs *args, int value) {
+ args->margin_top = value;
}
+void ui_toggle_args_set_margin_bottom(UiToggleArgs *args, int value) {
+ args->margin_bottom = value;
+}
-void ui_button_args_set_colspan(UiButtonArgs *args, int colspan) {
+void ui_toggle_args_set_colspan(UiToggleArgs *args, int colspan) {
args->colspan = colspan;
}
-
-void ui_button_args_set_rowspan(UiButtonArgs *args, int rowspan) {
+void ui_toggle_args_set_rowspan(UiToggleArgs *args, int rowspan) {
args->rowspan = rowspan;
}
-void ui_button_args_set_name(UiButtonArgs *args, const char *name) {
+void ui_toggle_args_set_name(UiToggleArgs *args, const char *name) {
args->name = strdup(name);
}
-
-void ui_button_args_set_style_class(UiButtonArgs *args, const char *classname) {
+void ui_toggle_args_set_style_class(UiToggleArgs *args, const char *classname) {
args->style_class = strdup(classname);
}
-void ui_button_args_set_label(UiButtonArgs *args, const char *label){
+void ui_toggle_args_set_label(UiToggleArgs *args, const char *label){
args->label = strdup(label);
}
-
-void ui_button_args_set_stockid(UiButtonArgs *args, const char *stockid){
- args->stockid = strdup(stockid);
+void ui_toggle_args_set_icon(UiToggleArgs *args, const char *icon){
+ args->icon = strdup(icon);
}
+void ui_toggle_args_set_tooltip(UiToggleArgs *args, const char *tooltip) {
+ args->tooltip = strdup(tooltip);
+}
-void ui_button_args_set_icon(UiButtonArgs *args, const char *icon){
- args->icon = strdup(icon);
+void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype){
+ args->labeltype = labeltype;
}
+void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback){
+ args->onchange = callback;
+}
-void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype){
- args->labeltype = labeltype;
+void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata){
+ args->onchangedata = onchangedata;
}
-void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback){
- args->onclick = callback;
+void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname) {
+ args->varname = strdup(varname);
}
+void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value) {
+ args->value = value;
+}
-void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata){
- args->onclickdata = onclickdata;
+void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group) {
+ args->enable_group = group;
}
-void ui_button_args_set_groups(UiButtonArgs *args, int *groups){
- // TODO
+void ui_toggle_args_set_groups(UiToggleArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
}
-void ui_button_args_free(UiButtonArgs *args) {
+void ui_toggle_args_free(UiToggleArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
free((void*)args->label);
- free((void*)args->stockid);
free((void*)args->icon);
+ free((void*)args->tooltip);
+ free((void*)args->varname);
free((void*)args->groups);
free(args);
}
-
-/* ------------------------- UiToggleArgs ----------------------------*/
+/* ------------------------- UiLinkButtonArgs ----------------------------*/
-UiToggleArgs* ui_toggle_args_new(void) {
- UiToggleArgs *args = malloc(sizeof(UiToggleArgs));
- memset(args, 0, sizeof(UiToggleArgs));
+UiLinkButtonArgs* ui_linkbutton_args_new(void) {
+ UiLinkButtonArgs *args = malloc(sizeof(UiLinkButtonArgs));
+ memset(args, 0, sizeof(UiLinkButtonArgs));
return args;
}
-void ui_toggle_args_set_fill(UiToggleArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+void ui_linkbutton_args_set_fill(UiLinkButtonArgs *args, UiBool fill) {
+ args->fill = fill;
}
-void ui_toggle_args_set_hexpand(UiToggleArgs *args, UiBool value) {
+void ui_linkbutton_args_set_hexpand(UiLinkButtonArgs *args, UiBool value) {
args->hexpand = value;
}
-void ui_toggle_args_set_vexpand(UiToggleArgs *args, UiBool value) {
+void ui_linkbutton_args_set_vexpand(UiLinkButtonArgs *args, UiBool value) {
args->vexpand = value;
}
-void ui_toggle_args_set_hfill(UiToggleArgs *args, UiBool value) {
+void ui_linkbutton_args_set_hfill(UiLinkButtonArgs *args, UiBool value) {
args->hfill = value;
}
-void ui_toggle_args_set_vfill(UiToggleArgs *args, UiBool value) {
+void ui_linkbutton_args_set_vfill(UiLinkButtonArgs *args, UiBool value) {
args->vfill = value;
}
-void ui_toggle_args_set_override_defaults(UiToggleArgs *args, UiBool value) {
+void ui_linkbutton_args_set_override_defaults(UiLinkButtonArgs *args, UiBool value) {
args->override_defaults = value;
}
+void ui_linkbutton_args_set_margin(UiLinkButtonArgs *args, int value) {
+ args->margin = value;
+}
-void ui_toggle_args_set_colspan(UiToggleArgs *args, int colspan) {
+void ui_linkbutton_args_set_margin_left(UiLinkButtonArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_linkbutton_args_set_margin_right(UiLinkButtonArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_linkbutton_args_set_margin_top(UiLinkButtonArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_linkbutton_args_set_margin_bottom(UiLinkButtonArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
+void ui_linkbutton_args_set_colspan(UiLinkButtonArgs *args, int colspan) {
args->colspan = colspan;
}
-void ui_toggle_args_set_rowspan(UiToggleArgs *args, int rowspan) {
+void ui_linkbutton_args_set_rowspan(UiLinkButtonArgs *args, int rowspan) {
args->rowspan = rowspan;
}
-void ui_toggle_args_set_name(UiToggleArgs *args, const char *name) {
+void ui_linkbutton_args_set_name(UiLinkButtonArgs *args, const char *name) {
args->name = strdup(name);
}
-void ui_toggle_args_set_style_class(UiToggleArgs *args, const char *classname) {
+void ui_linkbutton_args_set_style_class(UiLinkButtonArgs *args, const char *classname) {
args->style_class = strdup(classname);
}
-void ui_toggle_args_set_label(UiToggleArgs *args, const char *label){
+void ui_linkbutton_args_set_label(UiLinkButtonArgs *args, const char *label){
args->label = strdup(label);
}
-
-void ui_toggle_args_set_stockid(UiToggleArgs *args, const char *stockid){
- args->stockid = strdup(stockid);
+void ui_linkbutton_args_set_uri(UiLinkButtonArgs *args, const char *uri) {
+ args->uri = strdup(uri);
}
-
-void ui_toggle_args_set_icon(UiToggleArgs *args, const char *icon){
- args->icon = strdup(icon);
+void ui_linkbutton_args_set_onclick(UiLinkButtonArgs *args, ui_callback callback) {
+ args->onclick = callback;
}
-
-void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype){
- args->labeltype = labeltype;
+void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata) {
+ args->onclickdata = userdata;
}
-void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback){
- args->onchange = callback;
+void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value) {
+ args->nofollow = value;
}
-
-void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata){
- args->onchangedata = onchangedata;
+void ui_linkbutton_args_set_type(UiLinkButtonArgs *args, UiLinkType type) {
+ args->type = type;
}
-void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname) {
+void ui_linkbutton_args_set_varname(UiLinkButtonArgs *args, const char *varname) {
args->varname = strdup(varname);
}
-void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value) {
+void ui_linkbutton_args_set_value(UiLinkButtonArgs *args, UiString *value) {
args->value = value;
}
-void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group) {
- args->enable_group = group;
-}
-
-void ui_toggle_args_set_groups(UiToggleArgs *args, int *groups){
- // TODO
+void ui_linkbutton_args_set_groups(UiLinkButtonArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
}
-void ui_toggle_args_free(UiToggleArgs *args) {
+void ui_linkbutton_args_free(UiLinkButtonArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
free((void*)args->label);
- free((void*)args->stockid);
- free((void*)args->icon);
+ free((void*)args->uri);
free((void*)args->varname);
free((void*)args->groups);
free(args);
@@ -1069,7 +1659,7 @@ UiListArgs* ui_list_args_new(void) {
}
void ui_list_args_set_fill(UiListArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
void ui_list_args_set_hexpand(UiListArgs *args, UiBool value) {
@@ -1092,6 +1682,26 @@ void ui_list_args_set_override_defaults(UiListArgs *args, UiBool value) {
args->override_defaults = value;
}
+void ui_list_args_set_margin(UiListArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_list_args_set_margin_left(UiListArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_list_args_set_margin_right(UiListArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_list_args_set_margin_top(UiListArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_list_args_set_margin_bottom(UiListArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
void ui_list_args_set_colspan(UiListArgs *args, int colspan) {
args->colspan = colspan;
}
@@ -1141,6 +1751,14 @@ void ui_list_args_set_getvalue_data(UiListArgs *args, void *userdata) {
args->getvalue2data = userdata;
}
+void ui_list_args_set_getstyle_func(UiListArgs *args, ui_getstylefunc getstyle) {
+ args->getstyle = getstyle;
+}
+
+void ui_list_args_set_getstyle_data(UiListArgs *args, void *userdata) {
+ args->getstyledata = userdata;
+}
+
void ui_list_args_set_onactivate(UiListArgs *args, ui_callback callback) {
args->onactivate = callback;
}
@@ -1181,6 +1799,14 @@ void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata) {
args->ondropdata = userdata;
}
+void ui_list_args_set_onsave(UiListArgs *args, ui_list_savefunc onsave) {
+ args->onsave = onsave;
+}
+
+void ui_list_args_set_onsavedata(UiListArgs *args, void *userdata) {
+ args->onsavedata = userdata;
+}
+
void ui_list_args_set_multiselection(UiListArgs *args, UiBool multiselection) {
args->multiselection = multiselection;
}
@@ -1189,8 +1815,10 @@ void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder)
args->contextmenu = menubuilder;
}
-void ui_list_args_set_groups(UiListArgs *args, int *groups) {
- // TODO
+void ui_list_args_set_groups(UiListArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
}
void ui_list_args_free(UiListArgs *args) {
@@ -1203,6 +1831,7 @@ void ui_list_args_free(UiListArgs *args) {
}
free(args->static_elements);
}
+ free((void*)args->groups);
free(args);
}
@@ -1218,7 +1847,7 @@ UiSourceListArgs* ui_sourcelist_args_new(void) {
void ui_sourcelist_args_set_fill(UiSourceListArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
@@ -1246,6 +1875,25 @@ void ui_sourcelist_args_set_override_defaults(UiSourceListArgs *args, UiBool val
args->override_defaults = value;
}
+void ui_sourcelist_args_set_margin(UiSourceListArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_sourcelist_args_set_margin_left(UiSourceListArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_sourcelist_args_set_margin_right(UiSourceListArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_sourcelist_args_set_margin_top(UiSourceListArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_sourcelist_args_set_margin_bottom(UiSourceListArgs *args, int value) {
+ args->margin_bottom = value;
+}
void ui_sourcelist_args_set_colspan(UiSourceListArgs *args, int colspan) {
args->colspan = colspan;
@@ -1310,12 +1958,20 @@ void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *user
args->onbuttonclickdata = userdata;
}
+void ui_sourcelist_args_set_contextmenu(UiSourceListArgs *args, UiMenuBuilder *menubuilder) {
+ args->contextmenu = menubuilder;
+}
+
+void ui_sourcelist_args_set_header_is_item(UiSourceListArgs *args, UiBool value) {
+ args->header_is_item = value;
+}
void ui_sourcelist_args_free(UiSourceListArgs *args) {
free((void*)args->name);
free((void*)args->style_class);
free((void*)args->varname);
free((void*)args->sublists);
+ free((void*)args->groups);
free(args);
}
@@ -1330,7 +1986,7 @@ UiTextAreaArgs* ui_textarea_args_new(void) {
void ui_textarea_args_set_fill(UiTextAreaArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
@@ -1358,6 +2014,26 @@ void ui_textarea_args_set_override_defaults(UiTextAreaArgs *args, UiBool value)
args->override_defaults = value;
}
+void ui_textarea_args_set_margin(UiTextAreaArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_textarea_args_set_margin_left(UiTextAreaArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_textarea_args_set_margin_right(UiTextAreaArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_textarea_args_set_margin_top(UiTextAreaArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_textarea_args_set_margin_bottom(UiTextAreaArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
void ui_textarea_args_set_colspan(UiTextAreaArgs *args, int colspan) {
args->colspan = colspan;
@@ -1395,8 +2071,10 @@ void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value) {
args->value = value;
}
-void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *groups){
- // TODO
+void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
}
void ui_textarea_args_free(UiTextAreaArgs *args) {
@@ -1419,7 +2097,7 @@ UiTextFieldArgs* ui_textfield_args_new(void) {
void ui_textfield_args_set_fill(UiTextFieldArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
@@ -1447,6 +2125,26 @@ void ui_textfield_args_set_override_defaults(UiTextFieldArgs *args, UiBool value
args->override_defaults = value;
}
+void ui_textfield_args_set_margin(UiTextFieldArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_textfield_args_set_margin_left(UiTextFieldArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_textfield_args_set_margin_right(UiTextFieldArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_textfield_args_set_margin_top(UiTextFieldArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_textfield_args_set_margin_bottom(UiTextFieldArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
void ui_textfield_args_set_colspan(UiTextFieldArgs *args, int colspan) {
args->colspan = colspan;
@@ -1493,8 +2191,10 @@ void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value) {
args->value = value;
}
-void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *groups){
- // TODO
+void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
}
void ui_textfield_args_free(UiTextFieldArgs *args) {
@@ -1506,6 +2206,129 @@ void ui_textfield_args_free(UiTextFieldArgs *args) {
}
+/* ------------------------- UiSpinBoxArgs ----------------------------*/
+
+UiSpinBoxArgs* ui_spinbox_args_new(void) {
+ UiSpinBoxArgs *args = malloc(sizeof(UiSpinBoxArgs));
+ memset(args, 0, sizeof(UiSpinBoxArgs));
+ return args;
+}
+
+void ui_spinbox_args_set_fill(UiSpinBoxArgs *args, UiBool fill) {
+ args->fill = fill;
+}
+
+void ui_spinbox_args_set_hexpand(UiSpinBoxArgs *args, UiBool value) {
+ args->hexpand = value;
+}
+
+void ui_spinbox_args_set_vexpand(UiSpinBoxArgs *args, UiBool value) {
+ args->vexpand = value;
+}
+
+void ui_spinbox_args_set_hfill(UiSpinBoxArgs *args, UiBool value) {
+ args->hfill = value;
+}
+
+void ui_spinbox_args_set_vfill(UiSpinBoxArgs *args, UiBool value) {
+ args->vfill = value;
+}
+
+void ui_spinbox_args_set_override_defaults(UiSpinBoxArgs *args, UiBool value) {
+ args->override_defaults = value;
+}
+
+void ui_spinbox_args_set_colspan(UiSpinBoxArgs *args, int colspan) {
+ args->colspan = colspan;
+}
+
+void ui_spinbox_args_set_rowspan(UiSpinBoxArgs *args, int rowspan) {
+ args->rowspan = rowspan;
+}
+
+void ui_spinbox_args_set_name(UiSpinBoxArgs *args, const char *name) {
+ args->name = strdup(name);
+}
+
+void ui_spinbox_args_set_style_class(UiSpinBoxArgs *args, const char *classname) {
+ args->style_class = strdup(classname);
+}
+
+void ui_spinbox_args_set_onchange(UiSpinBoxArgs *args, ui_callback callback) {
+ args->onchange = callback;
+}
+
+void ui_spinbox_args_set_onchangedata(UiSpinBoxArgs *args, void *onchangedata) {
+ args->onchangedata = onchangedata;
+}
+
+void ui_spinbox_args_set_margin(UiSpinBoxArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_spinbox_args_set_margin_left(UiSpinBoxArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_spinbox_args_set_margin_right(UiSpinBoxArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_spinbox_args_set_margin_top(UiSpinBoxArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_spinbox_args_set_margin_bottom(UiSpinBoxArgs *args, int value) {
+ args->margin_bottom = value;
+}
+
+void ui_spinbox_args_set_min(UiSpinBoxArgs *args, double min) {
+ args->min = min;
+}
+
+void ui_spinbox_args_set_max(UiSpinBoxArgs *args, double max) {
+ args->max = max;
+}
+
+void ui_spinbox_args_set_step(UiSpinBoxArgs *args, double step) {
+ args->step = step;
+}
+
+void ui_spinbox_args_set_digits(UiSpinBoxArgs *args, int digits) {
+ args->digits = digits;
+}
+
+void ui_spinbox_args_set_varname(UiSpinBoxArgs *args, const char *varname) {
+ args->varname = strdup(varname);
+}
+
+void ui_spinbox_args_set_intvalue(UiSpinBoxArgs *args, UiInteger *value) {
+ args->intvalue = value;
+}
+
+void ui_spinbox_args_set_doublevalue(UiSpinBoxArgs *args, UiDouble *value) {
+ args->doublevalue = value;
+}
+
+void ui_spinbox_args_set_rangevalue(UiSpinBoxArgs *args, UiRange *value) {
+ args->rangevalue = value;
+}
+
+void ui_spinbox_args_set_groups(UiSpinBoxArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
+}
+
+void ui_spinbox_args_free(UiSpinBoxArgs *args) {
+ free((void*)args->name);
+ free((void*)args->style_class);
+ free((void*)args->varname);
+ free((void*)args->groups);
+ free(args);
+}
+
+
/* ------------------------- UiWebviewArgs ----------------------------*/
UiWebviewArgs* ui_webview_args_new(void) {
@@ -1516,7 +2339,7 @@ UiWebviewArgs* ui_webview_args_new(void) {
void ui_webview_args_set_fill(UiWebviewArgs *args, UiBool fill) {
- args->fill = fill ? UI_ON : UI_OFF;
+ args->fill = fill;
}
@@ -1544,6 +2367,25 @@ void ui_webview_args_set_override_defaults(UiWebviewArgs *args, UiBool value) {
args->override_defaults = value;
}
+void ui_webview_args_set_margin(UiWebviewArgs *args, int value) {
+ args->margin = value;
+}
+
+void ui_webview_args_set_margin_left(UiWebviewArgs *args, int value) {
+ args->margin_left = value;
+}
+
+void ui_webview_args_set_margin_right(UiWebviewArgs *args, int value) {
+ args->margin_right = value;
+}
+
+void ui_webview_args_set_margin_top(UiWebviewArgs *args, int value) {
+ args->margin_top = value;
+}
+
+void ui_webview_args_set_margin_bottom(UiWebviewArgs *args, int value) {
+ args->margin_bottom = value;
+}
void ui_webview_args_set_colspan(UiWebviewArgs *args, int colspan) {
args->colspan = colspan;
@@ -1572,8 +2414,10 @@ void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value) {
args->value = value;
}
-void ui_webview_args_set_groups(UiWebviewArgs *args, int *groups){
- // TODO
+void ui_webview_args_set_groups(UiWebviewArgs *args, int *states, int numstates) {
+ args->groups = calloc(numstates+1, sizeof(int));
+ memcpy((void*)args->groups, states, numstates * sizeof(int));
+ ((int*)args->groups)[numstates] = -1;
}
void ui_webview_args_free(UiWebviewArgs *args) {
diff --git a/ui/common/args.h b/ui/common/args.h
index 04e7063..e533193 100644
--- a/ui/common/args.h
+++ b/ui/common/args.h
@@ -29,23 +29,57 @@
#ifndef UIC_ARGS_H
#define UIC_ARGS_H
+#include "../ui/window.h"
#include "../ui/container.h"
#include "../ui/display.h"
#include "../ui/button.h"
+#include "../ui/entry.h"
#include "../ui/menu.h"
#include "../ui/toolbar.h"
#include "../ui/tree.h"
#include "../ui/text.h"
#include "../ui/webview.h"
+#include "../ui/widget.h"
#ifdef __cplusplus
extern "C" {
#endif
+UIEXPORT UiDialogArgs* ui_dialog_args_new(void);
+UIEXPORT void ui_dialog_args_set_title(UiDialogArgs *args, const char *title);
+UIEXPORT void ui_dialog_args_set_content(UiDialogArgs *args, const char *str);
+UIEXPORT void ui_dialog_args_set_button1_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_button2_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_closebutton_label(UiDialogArgs *args, const char *label);
+UIEXPORT void ui_dialog_args_set_input_value(UiDialogArgs *args, const char *value);
+UIEXPORT void ui_dialog_args_set_input(UiDialogArgs *args, UiBool input);
+UIEXPORT void ui_dialog_args_set_password(UiDialogArgs *args, UiBool password);
+UIEXPORT void ui_dialog_args_set_result(UiDialogArgs *args, ui_callback cb);
+UIEXPORT void ui_dialog_args_set_resultdata(UiDialogArgs *args, void *userdata);
+UIEXPORT void ui_dialog_args_free(UiDialogArgs *args);
+
+UIEXPORT UiDialogWindowArgs* ui_dialogwindow_args_new(void);
+UIEXPORT void ui_dialogwindow_args_set_modal(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_titlebar_buttons(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_show_closebutton(UiDialogWindowArgs *args, UiTri value);
+UIEXPORT void ui_dialogwindow_args_set_title(UiDialogWindowArgs *args, const char *title);
+UIEXPORT void ui_dialogwindow_args_set_lbutton1(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_lbutton2(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_rbutton3(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_rbutton4(UiDialogWindowArgs *args, const char *label);
+UIEXPORT void ui_dialogwindow_args_set_lbutton1_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_lbutton2_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_rbutton3_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_rbutton4_states(UiDialogWindowArgs *args, const int *states);
+UIEXPORT void ui_dialogwindow_args_set_default_button(UiDialogWindowArgs *args, int button);
+UIEXPORT void ui_dialogwindow_args_set_width(UiDialogWindowArgs *args, int width);
+UIEXPORT void ui_dialogwindow_args_set_height(UiDialogWindowArgs *args, int height);
+UIEXPORT void ui_dialogwindow_args_set_onclick(UiDialogWindowArgs *args, ui_callback cb);
+UIEXPORT void ui_dialogwindow_args_set_onclickdata(UiDialogWindowArgs *args, void *userdata);
+UIEXPORT void ui_dialogwindow_args_free(UiDialogWindowArgs *args);
UIEXPORT UiMenuItemArgs* ui_menuitem_args_new(void);
UIEXPORT void ui_menuitem_args_set_label(UiMenuItemArgs *args, const char *label);
-UIEXPORT void ui_menuitem_args_set_stockid(UiMenuItemArgs *args, const char *stockid);
UIEXPORT void ui_menuitem_args_set_icon(UiMenuItemArgs *args, const char *icon);
UIEXPORT void ui_menuitem_args_set_onclick(UiMenuItemArgs *args, ui_callback callback);
UIEXPORT void ui_menuitem_args_set_onclickdata(UiMenuItemArgs *args, void *onclickdata);
@@ -53,7 +87,6 @@ UIEXPORT void ui_menuitem_args_free(UiMenuItemArgs *args);
UIEXPORT UiMenuToggleItemArgs* ui_menutoggleitem_args_new(void);
UIEXPORT void ui_menutoggleitem_args_set_label(UiMenuToggleItemArgs *args, const char *label);
-UIEXPORT void ui_menutoggleitem_args_set_stockid(UiMenuToggleItemArgs *args, const char *stockid);
UIEXPORT void ui_menutoggleitem_args_set_icon(UiMenuToggleItemArgs *args, const char *icon);
UIEXPORT void ui_menutoggleitem_args_set_varname(UiMenuToggleItemArgs *args, const char *varname);
UIEXPORT void ui_menutoggleitem_args_set_onchange(UiMenuToggleItemArgs *args, ui_callback callback);
@@ -70,27 +103,27 @@ UIEXPORT void ui_menuitemlist_args_free(UiMenuItemListArgs *args);
UIEXPORT UiToolbarItemArgs* ui_toolbar_item_args_new(void);
UIEXPORT void ui_toolbar_item_args_set_label(UiToolbarItemArgs *args, const char *label);
-UIEXPORT void ui_toolbar_item_args_set_stockid(UiToolbarItemArgs *args, const char *stockid);
UIEXPORT void ui_toolbar_item_args_set_icon(UiToolbarItemArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_item_args_set_tooltip(UiToolbarItemArgs *args, const char *tooltip);
UIEXPORT void ui_toolbar_item_args_set_onclick(UiToolbarItemArgs *args, ui_callback callback);
UIEXPORT void ui_toolbar_item_args_set_onclickdata(UiToolbarItemArgs *args, void *onclickdata);
-UIEXPORT void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *groups);
+UIEXPORT void ui_toolbar_item_args_set_groups(UiToolbarItemArgs *args, int *states, int numstates);
UIEXPORT void ui_toolbar_item_args_free(UiToolbarItemArgs *args);
UIEXPORT UiToolbarToggleItemArgs* ui_toolbar_toggleitem_args_new(void);
UIEXPORT void ui_toolbar_toggleitem_args_set_label(UiToolbarToggleItemArgs *args, const char *label);
-UIEXPORT void ui_toolbar_toggleitem_args_set_stockid(UiToolbarToggleItemArgs *args, const char *stockid);
UIEXPORT void ui_toolbar_toggleitem_args_set_icon(UiToolbarToggleItemArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_toggleitem_args_set_tooltip(UiToolbarToggleItemArgs *args, const char *tooltip);
UIEXPORT void ui_toolbar_toggleitem_args_set_varname(UiToolbarToggleItemArgs *args, const char *varname);
UIEXPORT void ui_toolbar_toggleitem_args_set_onchange(UiToolbarToggleItemArgs *args, ui_callback callback);
UIEXPORT void ui_toolbar_toggleitem_args_set_onchangedata(UiToolbarToggleItemArgs *args, void *onchangedata);
-UIEXPORT void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args, int *groups);
+UIEXPORT void ui_toolbar_toggleitem_args_set_groups(UiToolbarToggleItemArgs *args, int *states, int numstates);
UIEXPORT void ui_toolbar_toggleitem_args_free(UiToolbarToggleItemArgs *args);
UIEXPORT UiToolbarMenuArgs* ui_toolbar_menu_args_new(void);
UIEXPORT void ui_toolbar_menu_args_set_label(UiToolbarMenuArgs *args, const char *label);
-UIEXPORT void ui_toolbar_menu_args_set_stockid(UiToolbarMenuArgs *args, const char *stockid);
UIEXPORT void ui_toolbar_menu_args_set_icon(UiToolbarMenuArgs *args, const char *icon);
+UIEXPORT void ui_toolbar_menu_args_set_tooltip(UiToolbarMenuArgs *args, const char *tooltip);
UIEXPORT void ui_toolbar_menu_args_free(UiToolbarMenuArgs *args);
UIEXPORT UiContainerArgs* ui_container_args_new(void);
@@ -100,6 +133,11 @@ UIEXPORT void ui_container_args_set_vexpand(UiContainerArgs *args, UiBool value)
UIEXPORT void ui_container_args_set_hfill(UiContainerArgs *args, UiBool value);
UIEXPORT void ui_container_args_set_vfill(UiContainerArgs *args, UiBool value);
UIEXPORT void ui_container_args_set_override_defaults(UiContainerArgs *args, UiBool value);
+UIEXPORT void ui_container_args_set_margin(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_margin_left(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_margin_top(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_colspan(UiContainerArgs *args, int colspan);
UIEXPORT void ui_container_args_set_rowspan(UiContainerArgs *args, int rowspan);
UIEXPORT void ui_container_args_set_def_hexpand(UiContainerArgs *args, UiBool value);
@@ -108,13 +146,11 @@ UIEXPORT void ui_container_args_set_def_hfill(UiContainerArgs *args, UiBool valu
UIEXPORT void ui_container_args_set_def_vfill(UiContainerArgs *args, UiBool value);
UIEXPORT void ui_container_args_set_name(UiContainerArgs *args, const char *name);
UIEXPORT void ui_container_args_set_style_class(UiContainerArgs *args, const char *classname);
-UIEXPORT void ui_container_args_set_margin(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_spacing(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_columnspacing(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_rowspacing(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_free(UiContainerArgs *args);
-
UIEXPORT UiFrameArgs* ui_frame_args_new(void);
UIEXPORT void ui_frame_args_set_fill(UiFrameArgs *args, UiBool fill);
UIEXPORT void ui_frame_args_set_hexpand(UiFrameArgs *args, UiBool value);
@@ -122,11 +158,17 @@ UIEXPORT void ui_frame_args_set_vexpand(UiFrameArgs *args, UiBool value);
UIEXPORT void ui_frame_args_set_hfill(UiFrameArgs *args, UiBool value);
UIEXPORT void ui_frame_args_set_vfill(UiFrameArgs *args, UiBool value);
UIEXPORT void ui_frame_args_set_override_defaults(UiFrameArgs *args, UiBool value);
+UIEXPORT void ui_frame_args_set_margin(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_margin_left(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_margin_right(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_margin_top(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_margin_bottom(UiFrameArgs *args, int value);
UIEXPORT void ui_frame_args_set_colspan(UiFrameArgs *args, int colspan);
UIEXPORT void ui_frame_args_set_rowspan(UiFrameArgs *args, int rowspan);
UIEXPORT void ui_frame_args_set_name(UiFrameArgs *args, const char *name);
UIEXPORT void ui_frame_args_set_style_class(UiFrameArgs *args, const char *classname);
-UIEXPORT void ui_frame_args_set_margin(UiFrameArgs *args, int value);
+UIEXPORT void ui_frame_args_set_subcontainer(UiFrameArgs *args, UiSubContainerType subcontainer);
+UIEXPORT void ui_frame_args_set_padding(UiFrameArgs *args, int value);
UIEXPORT void ui_frame_args_set_spacing(UiFrameArgs *args, int value);
UIEXPORT void ui_frame_args_set_columnspacing(UiFrameArgs *args, int value);
UIEXPORT void ui_frame_args_set_rowspacing(UiFrameArgs *args, int value);
@@ -138,6 +180,10 @@ UIEXPORT UiSidebarArgs* ui_sidebar_args_new(void);
UIEXPORT void ui_sidebar_args_set_name(UiSidebarArgs *args, const char *name);
UIEXPORT void ui_sidebar_args_set_style_class(UiSidebarArgs *args, const char *classname);
UIEXPORT void ui_sidebar_args_set_margin(UiSidebarArgs *args, int value);
+UIEXPORT void ui_sidebar_args_set_margin_left(UiSidebarArgs *args, int value);
+UIEXPORT void ui_sidebar_args_set_margin_right(UiSidebarArgs *args, int value);
+UIEXPORT void ui_sidebar_args_set_margin_top(UiSidebarArgs *args, int value);
+UIEXPORT void ui_sidebar_args_set_margin_bottom(UiSidebarArgs *args, int value);
UIEXPORT void ui_sidebar_args_set_spacing(UiSidebarArgs *args, int value);
UIEXPORT void ui_sidebar_args_free(UiSidebarArgs *args);
@@ -148,20 +194,71 @@ UIEXPORT void ui_splitpane_args_set_vexpand(UiSplitPaneArgs *args, UiBool value)
UIEXPORT void ui_splitpane_args_set_hfill(UiSplitPaneArgs *args, UiBool value);
UIEXPORT void ui_splitpane_args_set_vfill(UiSplitPaneArgs *args, UiBool value);
UIEXPORT void ui_splitpane_args_set_override_defaults(UiSplitPaneArgs *args, UiBool value);
+UIEXPORT void ui_splitpane_args_set_margin(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_margin_left(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_margin_right(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_margin_top(UiSplitPaneArgs *args, int value);
+UIEXPORT void ui_splitpane_args_set_margin_bottom(UiSplitPaneArgs *args, int value);
UIEXPORT void ui_splitpane_args_set_colspan(UiSplitPaneArgs *args, int colspan);
UIEXPORT void ui_splitpane_args_set_rowspan(UiSplitPaneArgs *args, int rowspan);
UIEXPORT void ui_splitpane_args_set_name(UiSplitPaneArgs *args, const char *name);
UIEXPORT void ui_splitpane_args_set_style_class(UiSplitPaneArgs *args, const char *classname);
-UIEXPORT void ui_splitpane_args_set_margin(UiSplitPaneArgs *args, int value);
UIEXPORT void ui_splitpane_args_set_spacing(UiSplitPaneArgs *args, int value);
UIEXPORT void ui_splitpane_args_set_columnspacing(UiSplitPaneArgs *args, int value);
UIEXPORT void ui_splitpane_args_set_rowspacing(UiSplitPaneArgs *args, int value);
UIEXPORT void ui_splitpane_args_set_initial_position(UiSplitPaneArgs *args, int pos);
+UIEXPORT void ui_splitpane_args_set_position_property(UiSplitPaneArgs *args, const char *propname);
UIEXPORT void ui_splitpane_args_set_varname(UiSplitPaneArgs *args, const char *varname);
UIEXPORT void ui_splitpane_args_set_value(UiSplitPaneArgs *args, UiInteger *value);
UIEXPORT void ui_splitpane_args_set_max_panes(UiSplitPaneArgs *args, int max);
UIEXPORT void ui_splitpane_args_free(UiSplitPaneArgs *args);
+UIEXPORT UiTabViewArgs* ui_tabview_args_new(void);
+UIEXPORT void ui_tabview_args_set_fill(UiTabViewArgs *args, UiBool fill);
+UIEXPORT void ui_tabview_args_set_hexpand(UiTabViewArgs *args, UiBool value);
+UIEXPORT void ui_tabview_args_set_vexpand(UiTabViewArgs *args, UiBool value);
+UIEXPORT void ui_tabview_args_set_hfill(UiTabViewArgs *args, UiBool value);
+UIEXPORT void ui_tabview_args_set_vfill(UiTabViewArgs *args, UiBool value);
+UIEXPORT void ui_tabview_args_set_override_defaults(UiTabViewArgs *args, UiBool value);
+UIEXPORT void ui_tabview_args_set_margin(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_margin_left(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_margin_right(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_margin_top(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_margin_bottom(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_colspan(UiTabViewArgs *args, int colspan);
+UIEXPORT void ui_tabview_args_set_rowspan(UiTabViewArgs *args, int rowspan);
+UIEXPORT void ui_tabview_args_set_name(UiTabViewArgs *args, const char *name);
+UIEXPORT void ui_tabview_args_set_style_class(UiTabViewArgs *args, const char *classname);
+UIEXPORT void ui_tabview_args_set_padding(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_spacing(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_columnspacing(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_rowspacing(UiTabViewArgs *args, int value);
+UIEXPORT void ui_tabview_args_set_type(UiTabViewArgs *args, UiTabViewType tabview);
+UIEXPORT void ui_tabview_args_set_onchange(UiTabViewArgs *args, ui_callback cb);
+UIEXPORT void ui_tabview_args_set_onchangedata(UiTabViewArgs *args, void *userdata);
+UIEXPORT void ui_tabview_args_set_varname(UiTabViewArgs *args, const char *varname);
+UIEXPORT void ui_tabview_args_set_value(UiTabViewArgs *args, UiInteger *value);
+UIEXPORT void ui_tabview_args_set_subcontainer(UiTabViewArgs *args, UiSubContainerType subcontainer);
+UIEXPORT void ui_tabview_args_free(UiTabViewArgs *args);
+
+UIEXPORT UiWidgetArgs* ui_widget_args_new(void);
+UIEXPORT void ui_widget_args_set_fill(UiWidgetArgs *args, UiBool fill);
+UIEXPORT void ui_widget_args_set_hexpand(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_vexpand(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_hfill(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_vfill(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_override_defaults(UiWidgetArgs *args, UiBool value);
+UIEXPORT void ui_widget_args_set_margin(UiWidgetArgs *args, int value);
+UIEXPORT void ui_widget_args_set_margin_left(UiWidgetArgs *args, int value);
+UIEXPORT void ui_widget_args_set_margin_right(UiWidgetArgs *args, int value);
+UIEXPORT void ui_widget_args_set_margin_top(UiWidgetArgs *args, int value);
+UIEXPORT void ui_widget_args_set_margin_bottom(UiWidgetArgs *args, int value);
+UIEXPORT void ui_widget_args_set_colspan(UiWidgetArgs *args, int colspan);
+UIEXPORT void ui_widget_args_set_rowspan(UiWidgetArgs *args, int rowspan);
+UIEXPORT void ui_widget_args_set_name(UiWidgetArgs *args, const char *name);
+UIEXPORT void ui_widget_args_set_style_class(UiWidgetArgs *args, const char *classname);
+UIEXPORT void ui_widget_args_free(UiWidgetArgs *args);
+
UIEXPORT UiLabelArgs* ui_label_args_new(void);
UIEXPORT void ui_label_args_set_fill(UiLabelArgs *args, UiBool fill);
UIEXPORT void ui_label_args_set_hexpand(UiLabelArgs *args, UiBool value);
@@ -169,6 +266,11 @@ UIEXPORT void ui_label_args_set_vexpand(UiLabelArgs *args, UiBool value);
UIEXPORT void ui_label_args_set_hfill(UiLabelArgs *args, UiBool value);
UIEXPORT void ui_label_args_set_vfill(UiLabelArgs *args, UiBool value);
UIEXPORT void ui_label_args_set_override_defaults(UiLabelArgs *args, UiBool value);
+UIEXPORT void ui_label_args_set_margin(UiLabelArgs *args, int value);
+UIEXPORT void ui_label_args_set_margin_left(UiLabelArgs *args, int value);
+UIEXPORT void ui_label_args_set_margin_right(UiLabelArgs *args, int value);
+UIEXPORT void ui_label_args_set_margin_top(UiLabelArgs *args, int value);
+UIEXPORT void ui_label_args_set_margin_bottom(UiLabelArgs *args, int value);
UIEXPORT void ui_label_args_set_colspan(UiLabelArgs *args, int colspan);
UIEXPORT void ui_label_args_set_rowspan(UiLabelArgs *args, int rowspan);
UIEXPORT void ui_label_args_set_name(UiLabelArgs *args, const char *name);
@@ -187,6 +289,11 @@ UIEXPORT void ui_progressbar_args_set_vexpand(UiProgressbarArgs *args, UiBool va
UIEXPORT void ui_progressbar_args_set_hfill(UiProgressbarArgs *args, UiBool value);
UIEXPORT void ui_progressbar_args_set_vfill(UiProgressbarArgs *args, UiBool value);
UIEXPORT void ui_progressbar_args_set_override_defaults(UiProgressbarArgs *args, UiBool value);
+UIEXPORT void ui_progressbar_args_set_margin(UiProgressbarArgs *args, int value);
+UIEXPORT void ui_progressbar_args_set_margin_left(UiProgressbarArgs *args, int value);
+UIEXPORT void ui_progressbar_args_set_margin_right(UiProgressbarArgs *args, int value);
+UIEXPORT void ui_progressbar_args_set_margin_top(UiProgressbarArgs *args, int value);
+UIEXPORT void ui_progressbar_args_set_margin_bottom(UiProgressbarArgs *args, int value);
UIEXPORT void ui_progressbar_args_set_colspan(UiProgressbarArgs *args, int colspan);
UIEXPORT void ui_progressbar_args_set_rowspan(UiProgressbarArgs *args, int rowspan);
UIEXPORT void ui_progressbar_args_set_name(UiProgressbarArgs *args, const char *name);
@@ -204,6 +311,11 @@ UIEXPORT void ui_progress_spinner_args_set_vexpand(UiProgressbarSpinnerArgs *arg
UIEXPORT void ui_progress_spinner_args_set_hfill(UiProgressbarSpinnerArgs *args, UiBool value);
UIEXPORT void ui_progress_spinner_args_set_vfill(UiProgressbarSpinnerArgs *args, UiBool value);
UIEXPORT void ui_progress_spinner_args_set_override_defaults(UiProgressbarSpinnerArgs *args, UiBool value);
+UIEXPORT void ui_progress_spinner_args_set_margin(UiProgressbarSpinnerArgs *args, int value);
+UIEXPORT void ui_progress_spinner_args_set_margin_left(UiProgressbarSpinnerArgs *args, int value);
+UIEXPORT void ui_progress_spinner_args_set_margin_right(UiProgressbarSpinnerArgs *args, int value);
+UIEXPORT void ui_progress_spinner_args_set_margin_top(UiProgressbarSpinnerArgs *args, int value);
+UIEXPORT void ui_progress_spinner_args_set_margin_bottom(UiProgressbarSpinnerArgs *args, int value);
UIEXPORT void ui_progress_spinner_args_set_colspan(UiProgressbarSpinnerArgs *args, int colspan);
UIEXPORT void ui_progress_spinner_args_set_rowspan(UiProgressbarSpinnerArgs *args, int rowspan);
UIEXPORT void ui_progress_spinner_args_set_name(UiProgressbarSpinnerArgs *args, const char *name);
@@ -219,17 +331,22 @@ UIEXPORT void ui_button_args_set_vexpand(UiButtonArgs *args, UiBool value);
UIEXPORT void ui_button_args_set_hfill(UiButtonArgs *args, UiBool value);
UIEXPORT void ui_button_args_set_vfill(UiButtonArgs *args, UiBool value);
UIEXPORT void ui_button_args_set_override_defaults(UiButtonArgs *args, UiBool value);
+UIEXPORT void ui_button_args_set_margin(UiButtonArgs *args, int value);
+UIEXPORT void ui_button_args_set_margin_left(UiButtonArgs *args, int value);
+UIEXPORT void ui_button_args_set_margin_right(UiButtonArgs *args, int value);
+UIEXPORT void ui_button_args_set_margin_top(UiButtonArgs *args, int value);
+UIEXPORT void ui_button_args_set_margin_bottom(UiButtonArgs *args, int value);
UIEXPORT void ui_button_args_set_colspan(UiButtonArgs *args, int colspan);
UIEXPORT void ui_button_args_set_rowspan(UiButtonArgs *args, int rowspan);
UIEXPORT void ui_button_args_set_name(UiButtonArgs *args, const char *name);
UIEXPORT void ui_button_args_set_style_class(UiButtonArgs *args, const char *classname);
UIEXPORT void ui_button_args_set_label(UiButtonArgs *args, const char *label);
-UIEXPORT void ui_button_args_set_stockid(UiButtonArgs *args, const char *stockid);
UIEXPORT void ui_button_args_set_icon(UiButtonArgs *args, const char *icon);
+UIEXPORT void ui_button_args_set_tooltip(UiButtonArgs *args, const char *tooltip);
UIEXPORT void ui_button_args_set_labeltype(UiButtonArgs *args, int labeltype);
UIEXPORT void ui_button_args_set_onclick(UiButtonArgs *args, ui_callback callback);
UIEXPORT void ui_button_args_set_onclickdata(UiButtonArgs *args, void *onclickdata);
-UIEXPORT void ui_button_args_set_groups(UiButtonArgs *args, int *groups);
+UIEXPORT void ui_button_args_set_groups(UiButtonArgs *args, int *states, int numstates);
UIEXPORT void ui_button_args_free(UiButtonArgs *args);
UIEXPORT UiToggleArgs* ui_toggle_args_new(void);
@@ -239,22 +356,54 @@ UIEXPORT void ui_toggle_args_set_vexpand(UiToggleArgs *args, UiBool value);
UIEXPORT void ui_toggle_args_set_hfill(UiToggleArgs *args, UiBool value);
UIEXPORT void ui_toggle_args_set_vfill(UiToggleArgs *args, UiBool value);
UIEXPORT void ui_toggle_args_set_override_defaults(UiToggleArgs *args, UiBool value);
+UIEXPORT void ui_toggle_args_set_margin(UiToggleArgs *args, int value);
+UIEXPORT void ui_toggle_args_set_margin_left(UiToggleArgs *args, int value);
+UIEXPORT void ui_toggle_args_set_margin_right(UiToggleArgs *args, int value);
+UIEXPORT void ui_toggle_args_set_margin_top(UiToggleArgs *args, int value);
+UIEXPORT void ui_toggle_args_set_margin_bottom(UiToggleArgs *args, int value);
UIEXPORT void ui_toggle_args_set_colspan(UiToggleArgs *args, int colspan);
UIEXPORT void ui_toggle_args_set_rowspan(UiToggleArgs *args, int rowspan);
UIEXPORT void ui_toggle_args_set_name(UiToggleArgs *args, const char *name);
UIEXPORT void ui_toggle_args_set_style_class(UiToggleArgs *args, const char *classname);
UIEXPORT void ui_toggle_args_set_label(UiToggleArgs *args, const char *label);
-UIEXPORT void ui_toggle_args_set_stockid(UiToggleArgs *args, const char *stockid);
UIEXPORT void ui_toggle_args_set_icon(UiToggleArgs *args, const char *icon);
+UIEXPORT void ui_toggle_args_set_tooltip(UiToggleArgs *args, const char *tooltip);
UIEXPORT void ui_toggle_args_set_labeltype(UiToggleArgs *args, int labeltype);
UIEXPORT void ui_toggle_args_set_onchange(UiToggleArgs *args, ui_callback callback);
UIEXPORT void ui_toggle_args_set_onchangedata(UiToggleArgs *args, void *onchangedata);
UIEXPORT void ui_toggle_args_set_varname(UiToggleArgs *args, const char *varname);
UIEXPORT void ui_toggle_args_set_value(UiToggleArgs *args, UiInteger *value);
UIEXPORT void ui_toggle_args_set_enablegroup(UiToggleArgs *args, int group);
-UIEXPORT void ui_toggle_args_set_groups(UiToggleArgs *args, int *groups);
+UIEXPORT void ui_toggle_args_set_groups(UiToggleArgs *args, int *states, int numstates);
UIEXPORT void ui_toggle_args_free(UiToggleArgs *args);
+UIEXPORT UiLinkButtonArgs* ui_linkbutton_args_new(void);
+UIEXPORT void ui_linkbutton_args_set_fill(UiLinkButtonArgs *args, UiBool fill);
+UIEXPORT void ui_linkbutton_args_set_hexpand(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_vexpand(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_hfill(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_vfill(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_override_defaults(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_margin(UiLinkButtonArgs *args, int value);
+UIEXPORT void ui_linkbutton_args_set_margin_left(UiLinkButtonArgs *args, int value);
+UIEXPORT void ui_linkbutton_args_set_margin_right(UiLinkButtonArgs *args, int value);
+UIEXPORT void ui_linkbutton_args_set_margin_top(UiLinkButtonArgs *args, int value);
+UIEXPORT void ui_linkbutton_args_set_margin_bottom(UiLinkButtonArgs *args, int value);
+UIEXPORT void ui_linkbutton_args_set_colspan(UiLinkButtonArgs *args, int colspan);
+UIEXPORT void ui_linkbutton_args_set_rowspan(UiLinkButtonArgs *args, int rowspan);
+UIEXPORT void ui_linkbutton_args_set_name(UiLinkButtonArgs *args, const char *name);
+UIEXPORT void ui_linkbutton_args_set_style_class(UiLinkButtonArgs *args, const char *classname);
+UIEXPORT void ui_linkbutton_args_set_varname(UiLinkButtonArgs *args, const char *varname);
+UIEXPORT void ui_linkbutton_args_set_value(UiLinkButtonArgs *args, UiString *value);
+UIEXPORT void ui_linkbutton_args_set_label(UiLinkButtonArgs *args, const char *label);
+UIEXPORT void ui_linkbutton_args_set_uri(UiLinkButtonArgs *args, const char *uri);
+UIEXPORT void ui_linkbutton_args_set_onclick(UiLinkButtonArgs *args, ui_callback callback);
+UIEXPORT void ui_linkbutton_args_set_onclickdata(UiLinkButtonArgs *args, void *userdata);
+UIEXPORT void ui_linkbutton_args_set_nofollow(UiLinkButtonArgs *args, UiBool value);
+UIEXPORT void ui_linkbutton_args_set_type(UiLinkButtonArgs *args, UiLinkType type);
+UIEXPORT void ui_linkbutton_args_set_groups(UiLinkButtonArgs *args, int *states, int numstates);
+UIEXPORT void ui_linkbutton_args_free(UiLinkButtonArgs *args);
+
UIEXPORT UiListArgs* ui_list_args_new(void);
UIEXPORT void ui_list_args_set_fill(UiListArgs *args, UiBool fill);
UIEXPORT void ui_list_args_set_hexpand(UiListArgs *args, UiBool value);
@@ -262,6 +411,11 @@ UIEXPORT void ui_list_args_set_vexpand(UiListArgs *args, UiBool value);
UIEXPORT void ui_list_args_set_hfill(UiListArgs *args, UiBool value);
UIEXPORT void ui_list_args_set_vfill(UiListArgs *args, UiBool value);
UIEXPORT void ui_list_args_set_override_defaults(UiListArgs *args, UiBool value);
+UIEXPORT void ui_list_args_set_margin(UiListArgs *args, int value);
+UIEXPORT void ui_list_args_set_margin_left(UiListArgs *args, int value);
+UIEXPORT void ui_list_args_set_margin_right(UiListArgs *args, int value);
+UIEXPORT void ui_list_args_set_margin_top(UiListArgs *args, int value);
+UIEXPORT void ui_list_args_set_margin_bottom(UiListArgs *args, int value);
UIEXPORT void ui_list_args_set_colspan(UiListArgs *args, int colspan);
UIEXPORT void ui_list_args_set_rowspan(UiListArgs *args, int rowspan);
UIEXPORT void ui_list_args_set_name(UiListArgs *args, const char *name);
@@ -273,6 +427,8 @@ UIEXPORT void ui_list_args_set_static_elements(UiListArgs *args, char **strarray
UIEXPORT void ui_list_args_set_getvalue_func(UiListArgs *args, ui_getvaluefunc getvalue);
UIEXPORT void ui_list_args_set_getvalue_func2(UiListArgs *args, ui_getvaluefunc2 getvalue);
UIEXPORT void ui_list_args_set_getvalue_data(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_getstyle_func(UiListArgs *args, ui_getstylefunc getstyle);
+UIEXPORT void ui_list_args_set_getstyle_data(UiListArgs *args, void *userdata);
UIEXPORT void ui_list_args_set_onactivate(UiListArgs *args, ui_callback callback);
UIEXPORT void ui_list_args_set_onactivatedata(UiListArgs *args, void *userdata);
UIEXPORT void ui_list_args_set_onselection(UiListArgs *args, ui_callback callback);
@@ -283,9 +439,11 @@ UIEXPORT void ui_list_args_set_ondragcomplete(UiListArgs *args, ui_callback call
UIEXPORT void ui_list_args_set_ondragcompletedata(UiListArgs *args, void *userdata);
UIEXPORT void ui_list_args_set_ondrop(UiListArgs *args, ui_callback callback);
UIEXPORT void ui_list_args_set_ondropdata(UiListArgs *args, void *userdata);
+UIEXPORT void ui_list_args_set_onsave(UiListArgs *args, ui_list_savefunc onsave);
+UIEXPORT void ui_list_args_set_onsavedata(UiListArgs *args, void *userdata);
UIEXPORT void ui_list_args_set_multiselection(UiListArgs *args, UiBool multiselection);
UIEXPORT void ui_list_args_set_contextmenu(UiListArgs *args, UiMenuBuilder *menubuilder);
-UIEXPORT void ui_list_args_set_groups(UiListArgs *args, int *groups);
+UIEXPORT void ui_list_args_set_groups(UiListArgs *args, int *states, int numstates);
UIEXPORT void ui_list_args_free(UiListArgs *args);
UIEXPORT UiSourceListArgs* ui_sourcelist_args_new(void);
@@ -295,6 +453,11 @@ UIEXPORT void ui_sourcelist_args_set_vexpand(UiSourceListArgs *args, UiBool valu
UIEXPORT void ui_sourcelist_args_set_hfill(UiSourceListArgs *args, UiBool value);
UIEXPORT void ui_sourcelist_args_set_vfill(UiSourceListArgs *args, UiBool value);
UIEXPORT void ui_sourcelist_args_set_override_defaults(UiSourceListArgs *args, UiBool value);
+UIEXPORT void ui_sourcelist_args_set_margin(UiSourceListArgs *args, int value);
+UIEXPORT void ui_sourcelist_args_set_margin_left(UiSourceListArgs *args, int value);
+UIEXPORT void ui_sourcelist_args_set_margin_right(UiSourceListArgs *args, int value);
+UIEXPORT void ui_sourcelist_args_set_margin_top(UiSourceListArgs *args, int value);
+UIEXPORT void ui_sourcelist_args_set_margin_bottom(UiSourceListArgs *args, int value);
UIEXPORT void ui_sourcelist_args_set_colspan(UiSourceListArgs *args, int colspan);
UIEXPORT void ui_sourcelist_args_set_rowspan(UiSourceListArgs *args, int rowspan);
UIEXPORT void ui_sourcelist_args_set_name(UiSourceListArgs *args, const char *name);
@@ -308,6 +471,8 @@ UIEXPORT void ui_sourcelist_args_set_onactivate(UiSourceListArgs *args, ui_callb
UIEXPORT void ui_sourcelist_args_set_onactivatedata(UiSourceListArgs *args, void *userdata);
UIEXPORT void ui_sourcelist_args_set_onbuttonclick(UiSourceListArgs *args, ui_callback callback);
UIEXPORT void ui_sourcelist_args_set_onbuttonclickdata(UiSourceListArgs *args, void *userdata);
+UIEXPORT void ui_sourcelist_args_set_contextmenu(UiSourceListArgs *args, UiMenuBuilder *menubuilder);
+UIEXPORT void ui_sourcelist_args_set_header_is_item(UiSourceListArgs *args, UiBool value);
UIEXPORT void ui_sourcelist_args_free(UiSourceListArgs *args);
UIEXPORT UiTextAreaArgs* ui_textarea_args_new(void);
@@ -317,6 +482,11 @@ UIEXPORT void ui_textarea_args_set_vexpand(UiTextAreaArgs *args, UiBool value);
UIEXPORT void ui_textarea_args_set_hfill(UiTextAreaArgs *args, UiBool value);
UIEXPORT void ui_textarea_args_set_vfill(UiTextAreaArgs *args, UiBool value);
UIEXPORT void ui_textarea_args_set_override_defaults(UiTextAreaArgs *args, UiBool value);
+UIEXPORT void ui_textarea_args_set_margin(UiTextAreaArgs *args, int value);
+UIEXPORT void ui_textarea_args_set_margin_left(UiTextAreaArgs *args, int value);
+UIEXPORT void ui_textarea_args_set_margin_right(UiTextAreaArgs *args, int value);
+UIEXPORT void ui_textarea_args_set_margin_top(UiTextAreaArgs *args, int value);
+UIEXPORT void ui_textarea_args_set_margin_bottom(UiTextAreaArgs *args, int value);
UIEXPORT void ui_textarea_args_set_colspan(UiTextAreaArgs *args, int colspan);
UIEXPORT void ui_textarea_args_set_rowspan(UiTextAreaArgs *args, int rowspan);
UIEXPORT void ui_textarea_args_set_name(UiTextAreaArgs *args, const char *name);
@@ -325,7 +495,7 @@ UIEXPORT void ui_textarea_args_set_onchange(UiTextAreaArgs *args, ui_callback ca
UIEXPORT void ui_textarea_args_set_onchangedata(UiTextAreaArgs *args, void *onchangedata);
UIEXPORT void ui_textarea_args_set_varname(UiTextAreaArgs *args, const char *varname);
UIEXPORT void ui_textarea_args_set_value(UiTextAreaArgs *args, UiText *value);
-UIEXPORT void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *groups);
+UIEXPORT void ui_textarea_args_set_groups(UiTextAreaArgs *args, int *states, int numstates);
UIEXPORT void ui_textarea_args_free(UiTextAreaArgs *args);
UIEXPORT UiTextFieldArgs* ui_textfield_args_new(void);
@@ -335,6 +505,11 @@ UIEXPORT void ui_textfield_args_set_vexpand(UiTextFieldArgs *args, UiBool value)
UIEXPORT void ui_textfield_args_set_hfill(UiTextFieldArgs *args, UiBool value);
UIEXPORT void ui_textfield_args_set_vfill(UiTextFieldArgs *args, UiBool value);
UIEXPORT void ui_textfield_args_set_override_defaults(UiTextFieldArgs *args, UiBool value);
+UIEXPORT void ui_textfield_args_set_margin(UiTextFieldArgs *args, int value);
+UIEXPORT void ui_textfield_args_set_margin_left(UiTextFieldArgs *args, int value);
+UIEXPORT void ui_textfield_args_set_margin_right(UiTextFieldArgs *args, int value);
+UIEXPORT void ui_textfield_args_set_margin_top(UiTextFieldArgs *args, int value);
+UIEXPORT void ui_textfield_args_set_margin_bottom(UiTextFieldArgs *args, int value);
UIEXPORT void ui_textfield_args_set_colspan(UiTextFieldArgs *args, int colspan);
UIEXPORT void ui_textfield_args_set_rowspan(UiTextFieldArgs *args, int rowspan);
UIEXPORT void ui_textfield_args_set_name(UiTextFieldArgs *args, const char *name);
@@ -345,9 +520,38 @@ UIEXPORT void ui_textfield_args_set_onactivate(UiTextFieldArgs *args, ui_callbac
UIEXPORT void ui_textfield_args_set_onactivatedata(UiTextFieldArgs *args, void *onactivatedata);
UIEXPORT void ui_textfield_args_set_varname(UiTextFieldArgs *args, const char *varname);
UIEXPORT void ui_textfield_args_set_value(UiTextFieldArgs *args, UiString *value);
-UIEXPORT void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *groups);
+UIEXPORT void ui_textfield_args_set_groups(UiTextFieldArgs *args, int *states, int numstates);
UIEXPORT void ui_textfield_args_free(UiTextFieldArgs *args);
+UIEXPORT UiSpinBoxArgs* ui_spinbox_args_new(void);
+UIEXPORT void ui_spinbox_args_set_fill(UiSpinBoxArgs *args, UiBool fill);
+UIEXPORT void ui_spinbox_args_set_hexpand(UiSpinBoxArgs *args, UiBool value);
+UIEXPORT void ui_spinbox_args_set_vexpand(UiSpinBoxArgs *args, UiBool value);
+UIEXPORT void ui_spinbox_args_set_hfill(UiSpinBoxArgs *args, UiBool value);
+UIEXPORT void ui_spinbox_args_set_vfill(UiSpinBoxArgs *args, UiBool value);
+UIEXPORT void ui_spinbox_args_set_override_defaults(UiSpinBoxArgs *args, UiBool value);
+UIEXPORT void ui_spinbox_args_set_margin(UiSpinBoxArgs *args, int value);
+UIEXPORT void ui_spinbox_args_set_margin_left(UiSpinBoxArgs *args, int value);
+UIEXPORT void ui_spinbox_args_set_margin_right(UiSpinBoxArgs *args, int value);
+UIEXPORT void ui_spinbox_args_set_margin_top(UiSpinBoxArgs *args, int value);
+UIEXPORT void ui_spinbox_args_set_margin_bottom(UiSpinBoxArgs *args, int value);
+UIEXPORT void ui_spinbox_args_set_colspan(UiSpinBoxArgs *args, int colspan);
+UIEXPORT void ui_spinbox_args_set_rowspan(UiSpinBoxArgs *args, int rowspan);
+UIEXPORT void ui_spinbox_args_set_name(UiSpinBoxArgs *args, const char *name);
+UIEXPORT void ui_spinbox_args_set_style_class(UiSpinBoxArgs *args, const char *classname);
+UIEXPORT void ui_spinbox_args_set_onchange(UiSpinBoxArgs *args, ui_callback callback);
+UIEXPORT void ui_spinbox_args_set_onchangedata(UiSpinBoxArgs *args, void *onchangedata);
+UIEXPORT void ui_spinbox_args_set_min(UiSpinBoxArgs *args, double min);
+UIEXPORT void ui_spinbox_args_set_max(UiSpinBoxArgs *args, double max);
+UIEXPORT void ui_spinbox_args_set_step(UiSpinBoxArgs *args, double step);
+UIEXPORT void ui_spinbox_args_set_digits(UiSpinBoxArgs *args, int digits);
+UIEXPORT void ui_spinbox_args_set_varname(UiSpinBoxArgs *args, const char *varname);
+UIEXPORT void ui_spinbox_args_set_intvalue(UiSpinBoxArgs *args, UiInteger *value);
+UIEXPORT void ui_spinbox_args_set_doublevalue(UiSpinBoxArgs *args, UiDouble *value);
+UIEXPORT void ui_spinbox_args_set_rangevalue(UiSpinBoxArgs *args, UiRange *value);
+UIEXPORT void ui_spinbox_args_set_groups(UiSpinBoxArgs *args, int *states, int numstates);
+UIEXPORT void ui_spinbox_args_free(UiSpinBoxArgs *args);
+
UIEXPORT UiWebviewArgs* ui_webview_args_new(void);
UIEXPORT void ui_webview_args_set_fill(UiWebviewArgs *args, UiBool fill);
UIEXPORT void ui_webview_args_set_hexpand(UiWebviewArgs *args, UiBool value);
@@ -355,13 +559,18 @@ UIEXPORT void ui_webview_args_set_vexpand(UiWebviewArgs *args, UiBool value);
UIEXPORT void ui_webview_args_set_hfill(UiWebviewArgs *args, UiBool value);
UIEXPORT void ui_webview_args_set_vfill(UiWebviewArgs *args, UiBool value);
UIEXPORT void ui_webview_args_set_override_defaults(UiWebviewArgs *args, UiBool value);
+UIEXPORT void ui_webview_args_set_margin(UiWebviewArgs *args, int value);
+UIEXPORT void ui_webview_args_set_margin_left(UiWebviewArgs *args, int value);
+UIEXPORT void ui_webview_args_set_margin_right(UiWebviewArgs *args, int value);
+UIEXPORT void ui_webview_args_set_margin_top(UiWebviewArgs *args, int value);
+UIEXPORT void ui_webview_args_set_margin_bottom(UiWebviewArgs *args, int value);
UIEXPORT void ui_webview_args_set_colspan(UiWebviewArgs *args, int colspan);
UIEXPORT void ui_webview_args_set_rowspan(UiWebviewArgs *args, int rowspan);
UIEXPORT void ui_webview_args_set_name(UiWebviewArgs *args, const char *name);
UIEXPORT void ui_webview_args_set_style_class(UiWebviewArgs *args, const char *classname);
UIEXPORT void ui_webview_args_set_varname(UiWebviewArgs *args, const char *varname);
UIEXPORT void ui_webview_args_set_value(UiWebviewArgs *args, UiGeneric *value);
-UIEXPORT void ui_webview_args_set_groups(UiWebviewArgs *args, int *groups);
+UIEXPORT void ui_webview_args_set_groups(UiWebviewArgs *args, int *states, int numstates);
UIEXPORT void ui_webview_args_free(UiWebviewArgs *args);
#ifdef __cplusplus
diff --git a/ui/common/container.c b/ui/common/container.c
new file mode 100644
index 0000000..6f0dde9
--- /dev/null
+++ b/ui/common/container.c
@@ -0,0 +1,87 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "container.h"
+#include "object.h"
+
+void ui_end_new(UiObject *obj) {
+ if(!obj->container_end) {
+ return;
+ }
+ UiContainerX *rm = obj->container_end;
+ uic_object_pop_container(obj);
+ ui_free(obj->ctx, rm);
+}
+
+void ui_newline(UiObject *obj) {
+ UiContainerX *container = obj->container_end;
+ if(container) {
+ container->newline = TRUE;
+ }
+}
+
+void uic_layout_setup_expand_fill(
+ UiLayout *layout,
+ UiBool def_hexpand,
+ UiBool def_vexpand,
+ UiBool def_hfill,
+ UiBool def_vfill)
+{
+ if(layout->fill) {
+ layout->hfill = TRUE;
+ layout->vfill = TRUE;
+ layout->hexpand = TRUE;
+ layout->vexpand = TRUE;
+ return;
+ }
+
+ if(!layout->override_defaults) {
+ if(def_hexpand) {
+ layout->hexpand = TRUE;
+ }
+ if(def_hfill) {
+ layout->hfill = TRUE;
+ }
+ if(def_vexpand) {
+ layout->vexpand = TRUE;
+ }
+ if(def_vfill) {
+ layout->vfill = TRUE;
+ }
+ }
+}
+
+void uic_layout_setup_margin(UiLayout *layout) {
+ int margin = layout->margin;
+ if(margin > 0) {
+ layout->margin_left = margin;
+ layout->margin_right = margin;
+ layout->margin_top = margin;
+ layout->margin_bottom = margin;
+ }
+}
diff --git a/ui/common/container.h b/ui/common/container.h
new file mode 100644
index 0000000..6f102ed
--- /dev/null
+++ b/ui/common/container.h
@@ -0,0 +1,59 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UIC_CONTAINER_H
+#define UIC_CONTAINER_H
+
+#include "../ui/container.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * prepares the layout horizontal and vertical fill/expand settings
+ * based on fill and defaults
+ */
+void uic_layout_setup_expand_fill(
+ UiLayout *layout,
+ UiBool def_hexpand,
+ UiBool def_vexpand,
+ UiBool def_hfill,
+ UiBool def_vfill);
+
+/*
+ * adjusts margin_* if margin > 0
+ */
+void uic_layout_setup_margin(UiLayout *layout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_CONTAINER_H */
+
diff --git a/ui/common/context.c b/ui/common/context.c
index d0cd53d..73911a5 100644
--- a/ui/common/context.c
+++ b/ui/common/context.c
@@ -38,6 +38,7 @@
#include "context.h"
#include "../ui/window.h"
+#include "../ui/widget.h"
#include "document.h"
#include "types.h"
@@ -102,21 +103,19 @@ void uic_context_attach_document(UiContext *ctx, void *document) {
UiContext *doc_ctx = ui_document_context(document);
doc_ctx->parent = ctx;
- // check if any parent context has an unbound variable with the same name
- // as any document variable
+ // if a document variable has the same name as a parent variable,
+ // move the bindings to the document
UiContext *var_ctx = ctx;
while(var_ctx) {
- if(var_ctx->vars_unbound && cxMapSize(var_ctx->vars_unbound) > 0) {
- CxMapIterator i = cxMapIterator(var_ctx->vars_unbound);
- cx_foreach(CxMapEntry*, entry, i) {
- printf("attach %s\n", entry->key->data);
- UiVar *var = entry->value;
- UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key);
- if(docvar) {
- // bind var to document var
- uic_copy_binding(var, docvar, TRUE);
- cxIteratorFlagRemoval(i);
- }
+ CxMapIterator i = cxMapIterator(var_ctx->vars);
+ cx_foreach(CxMapEntry*, entry, i) {
+ printf("attach %.*s\n", (int)entry->key->len, (char*)entry->key->data);
+ UiVar *var = entry->value;
+ UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key);
+ if(docvar) {
+ // bind var to document var
+ uic_copy_binding(var, docvar, TRUE);
+ cxIteratorFlagRemoval(i);
}
}
@@ -129,10 +128,10 @@ static void uic_context_unbind_vars(UiContext *ctx) {
cx_foreach(CxMapEntry*, entry, mi) {
UiVar *var = entry->value;
// var->from && var->from_ctx && var->from_ctx != ctx
+ uic_save_var(var);
if(var->from) {
- uic_save_var2(var);
uic_copy_binding(var, var->from, FALSE);
- cxMapPut(var->from->from_ctx->vars_unbound, *entry->key, var->from);
+ cxMapPut(var->from->from_ctx->vars, *entry->key, var->from);
var->from = NULL;
}
}
@@ -199,13 +198,6 @@ UiVar* uic_get_var(UiContext *ctx, const char *name) {
}
UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) {
- if(ctx->vars_unbound) {
- UiVar *unbound = cxMapGet(ctx->vars_unbound, name);
- if(unbound) {
- return unbound;
- }
- }
-
UiVar *var = uic_get_var(ctx, name);
if(var) {
if(var->type == type) {
@@ -224,10 +216,7 @@ UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) {
cxMempoolSetDestructor(var, (cx_destructor_func)uic_unbind_var);
- if(!ctx->vars_unbound) {
- ctx->vars_unbound = cxHashMapCreate(ctx->allocator, CX_STORE_POINTERS, 16);
- }
- cxMapPut(ctx->vars_unbound, name, var);
+ cxMapPut(ctx->vars, name, var);
return var;
}
@@ -278,7 +267,7 @@ void* uic_create_value(UiContext *ctx, UiVarType type) {
}
-UiVar* uic_widget_var(UiContext* toplevel, UiContext* current, void* value, const char* varname, UiVarType type) {
+UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type) {
if (value) {
return uic_create_value_var(current, value);
}
@@ -383,7 +372,7 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
ui_setop_enable(FALSE);
}
-void uic_save_var2(UiVar *var) {
+void uic_save_var(UiVar *var) {
switch(var->type) {
case UI_VAR_SPECIAL: break;
case UI_VAR_INTEGER: uic_int_save(var->value); break;
@@ -542,6 +531,9 @@ void uic_check_group_widgets(UiContext *ctx) {
}
void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...) {
+ if(enable == NULL) {
+ enable = (ui_enablefunc)ui_set_enabled;
+ }
// get groups
CxList *groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16);
va_list ap;
@@ -557,6 +549,22 @@ void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable,
cxListFree(groups);
}
+void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *groups, int ngroups) {
+ if(enable == NULL) {
+ enable = (ui_enablefunc)ui_set_enabled;
+ }
+ CxList *ls = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), ngroups);
+ for(int i=0;i= 0;i++) { }
@@ -614,7 +622,7 @@ void* ui_realloc(UiContext *ctx, void *ptr, size_t size) {
return ctx ? cxRealloc(ctx->allocator, ptr, size) : NULL;
}
-UIEXPORT char* ui_strdup(UiContext *ctx, const char *str) {
+char* ui_strdup(UiContext *ctx, const char *str) {
if(!ctx) {
return NULL;
}
@@ -622,3 +630,11 @@ UIEXPORT char* ui_strdup(UiContext *ctx, const char *str) {
cxmutstr d = cx_strdup_a(ctx->allocator, s);
return d.ptr;
}
+
+void ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr) {
+ cxMempoolRegister(ctx->mp, data, (cx_destructor_func)destr);
+}
+
+void ui_set_destructor(void *mem, ui_destructor_func destr) {
+ cxMempoolSetDestructor(mem, (cx_destructor_func)destr);
+}
diff --git a/ui/common/context.h b/ui/common/context.h
index 4fdcfe6..f517090 100644
--- a/ui/common/context.h
+++ b/ui/common/context.h
@@ -67,8 +67,7 @@ struct UiContext {
void *document;
CxList *documents;
- CxMap *vars; // manually created context vars
- CxMap *vars_unbound; // unbound vars created by widgets
+ CxMap *vars;
CxList *groups; // int list
CxList *group_widgets; // UiGroupWidget list
@@ -92,7 +91,6 @@ struct UiContext {
void *close_data;
};
-// UiVar replacement, rename it to UiVar when finished
struct UiVar {
void *value;
void *original_value;
@@ -133,10 +131,10 @@ UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type);
UiVar* uic_create_value_var(UiContext *ctx, void *value);
void* uic_create_value(UiContext *ctx, UiVarType type);
-UiVar* uic_widget_var(UiContext* toplevel, UiContext* current, void* value, const char* varname, UiVarType type);
+UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type);
void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc);
-void uic_save_var2(UiVar *var);
+void uic_save_var(UiVar *var);
void uic_unbind_var(UiVar *var);
void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value);
diff --git a/ui/common/document.c b/ui/common/document.c
index bd69073..3eb5874 100644
--- a/ui/common/document.c
+++ b/ui/common/document.c
@@ -36,22 +36,16 @@
#include
-static CxMap *documents;
-void uic_docmgr_init() {
- if (!documents) {
- documents = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 32);
- }
-}
void* ui_document_new(size_t size) {
CxMempool *mp = cxMempoolCreateSimple(256);
const CxAllocator *a = mp->allocator;
UiContext *ctx = uic_context(NULL, mp);
- void *document = cxCalloc(a, size, 1);
- cxMapPut(documents, cx_hash_key(&document, sizeof(void*)), ctx);
- return document;
+ UiDoc *document = cxCalloc(a, sizeof(UiDoc) + size, 1);
+ document->ctx = ctx;
+ return &document->doc;
}
void ui_document_destroy(void *doc) {
@@ -74,7 +68,9 @@ void ui_document_destroy(void *doc) {
UiContext* ui_document_context(void *doc) {
if(doc) {
- return cxMapGet(documents, cx_hash_key(&doc, sizeof(void*)));
+ char *docPtr = doc;
+ UiDoc *document = (UiDoc*)(docPtr - sizeof(void*));
+ return document->ctx;
} else {
return NULL;
}
diff --git a/ui/common/document.h b/ui/common/document.h
index 0f439d5..b98c810 100644
--- a/ui/common/document.h
+++ b/ui/common/document.h
@@ -36,7 +36,11 @@
extern "C" {
#endif
-void uic_docmgr_init();
+typedef struct UiDoc {
+ UiContext *ctx;
+ char doc[];
+} UiDoc;
+
void uic_document_addvar(void *doc, char *name, int type, size_t vs);
diff --git a/ui/common/menu.c b/ui/common/menu.c
index 31f8171..b0cfc46 100644
--- a/ui/common/menu.c
+++ b/ui/common/menu.c
@@ -41,6 +41,22 @@ static UiMenuBuilder global_builder;
static int menu_item_counter = 0;
+static void *tmp_eventdata;
+static int tmp_eventdata_type;
+
+void uic_set_tmp_eventdata(void *eventdata, int type) {
+ tmp_eventdata = eventdata;
+ tmp_eventdata_type = type;
+}
+
+void* uic_get_tmp_eventdata(void) {
+ return tmp_eventdata;
+}
+
+int uic_get_tmp_eventdata_type(void) {
+ return tmp_eventdata_type;
+}
+
void uic_menu_init(void) {
global_builder.current = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS);
current_builder = &global_builder;
@@ -100,7 +116,7 @@ void ui_menu_create(const char *label) {
menu->item.next = NULL;
menu->item.type = UI_MENU;
- menu->label = label;
+ menu->label = nl_strdup(label);
menu->items_begin = NULL;
menu->items_end = NULL;
menu->parent = NULL;
@@ -133,7 +149,6 @@ void ui_menuitem_create(UiMenuItemArgs *args) {
item->item.type = UI_MENU_ITEM;
item->label = nl_strdup(args->label);
- item->stockid = nl_strdup(args->stockid);
item->icon = nl_strdup(args->icon);
item->userdata = args->onclickdata;
item->callback = args->onclick;
@@ -160,7 +175,6 @@ void ui_menu_toggleitem_create(UiMenuToggleItemArgs *args) {
item->item.type = UI_MENU_CHECK_ITEM;
item->label = nl_strdup(args->label);
- item->stockid = nl_strdup(args->stockid);
item->icon = nl_strdup(args->icon);
item->varname = nl_strdup(args->varname);
item->userdata = args->onchangedata;
@@ -178,7 +192,6 @@ void ui_menu_radioitem_create(UiMenuToggleItemArgs *args) {
item->item.type = UI_MENU_RADIO_ITEM;
item->label = nl_strdup(args->label);
- item->stockid = nl_strdup(args->stockid);
item->icon = nl_strdup(args->icon);
item->varname = nl_strdup(args->varname);
item->userdata = args->onchangedata;
@@ -258,6 +271,7 @@ void ui_contextmenu_builder(UiMenuBuilder **out_builder) {
builder->menus_begin = NULL;
builder->menus_end = NULL;
builder->current = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS);
+ builder->ref = 1;
current_builder = builder;
*out_builder = builder;
@@ -271,6 +285,7 @@ static void free_menuitem(UiMenuItemI *item) {
default: break;
case UI_MENU: {
UiMenu *menu = (UiMenu*)item;
+ free(menu->label);
UiMenuItemI *m = menu->items_begin;
while(m) {
UiMenuItemI *next = m->next;
@@ -283,7 +298,6 @@ static void free_menuitem(UiMenuItemI *item) {
UiMenuItem *i = (UiMenuItem*)item;
free(i->groups);
free(i->label);
- free(i->stockid);
free(i->icon);
break;
}
@@ -291,7 +305,6 @@ static void free_menuitem(UiMenuItemI *item) {
UiMenuCheckItem *i = (UiMenuCheckItem*)item;
free(i->groups);
free(i->label);
- free(i->stockid);
free(i->icon);
free(i->varname);
break;
@@ -300,9 +313,8 @@ static void free_menuitem(UiMenuItemI *item) {
UiMenuRadioItem *i = (UiMenuRadioItem*)item;
free(i->groups);
free(i->label);
- free(i->stockid);
free(i->icon);
- //free(i->varname);
+ free(i->varname);
break;
}
case UI_MENU_ITEM_LIST: {
@@ -329,3 +341,13 @@ void ui_menubuilder_free(UiMenuBuilder *builder) {
cxListFree(builder->current);
free(builder);
}
+
+void ui_menubuilder_ref(UiMenuBuilder *builder) {
+ builder->ref++;
+}
+
+void ui_menubuilder_unref(UiMenuBuilder *builder) {
+ if(--builder->ref <= 0) {
+ ui_menubuilder_free(builder);
+ }
+}
diff --git a/ui/common/menu.h b/ui/common/menu.h
index 1ed01b0..f44f6b4 100644
--- a/ui/common/menu.h
+++ b/ui/common/menu.h
@@ -66,7 +66,7 @@ struct UiMenuItemI {
struct UiMenu {
UiMenuItemI item;
- const char *label;
+ char *label;
UiMenuItemI *items_begin;
UiMenuItemI *items_end;
UiMenu *parent;
@@ -77,7 +77,6 @@ struct UiMenuItem {
UiMenuItemI item;
ui_callback callback;
char *label;
- char *stockid;
char *icon;
void *userdata;
int *groups;
@@ -87,7 +86,6 @@ struct UiMenuItem {
struct UiMenuCheckItem {
UiMenuItemI item;
char *label;
- char *stockid;
char *icon;
char *varname;
ui_callback callback;
@@ -99,7 +97,6 @@ struct UiMenuCheckItem {
struct UiMenuRadioItem {
UiMenuItemI item;
char *label;
- char *stockid;
char *icon;
char *varname;
ui_callback callback;
@@ -123,6 +120,7 @@ struct UiMenuBuilder {
UiMenu *menus_begin;
UiMenu *menus_end;
CxList *current;
+ int ref;
};
void uic_menu_init(void);
@@ -133,6 +131,10 @@ void uic_add_menu_to_stack(UiMenu* menu);
int* uic_copy_groups(const int* groups, size_t *ngroups);
+void uic_set_tmp_eventdata(void *eventdata, int type);
+void* uic_get_tmp_eventdata(void);
+int uic_get_tmp_eventdata_type(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/ui/common/object.c b/ui/common/object.c
index e7981c4..b041bc9 100644
--- a/ui/common/object.c
+++ b/ui/common/object.c
@@ -28,7 +28,6 @@
#include
#include
-
#include "object.h"
#include "context.h"
@@ -74,32 +73,6 @@ void uic_object_destroyed(UiObject *obj) {
}
}
-void ui_end(UiObject *obj) {
- if(!obj->next) {
- return;
- }
-
- UiObject *prev = NULL;
- while(obj->next) {
- prev = obj;
- obj = obj->next;
- }
-
- if(prev) {
- // TODO: free last obj
- prev->next = NULL;
- }
-}
-
-void ui_end_new(UiObject *obj) {
- if(!obj->container_end) {
- return;
- }
- UiContainerX *rm = obj->container_end;
- uic_object_pop_container(obj);
- ui_free(obj->ctx, rm);
-}
-
void ui_object_ref(UiObject *obj) {
obj->ref++;
}
@@ -133,17 +106,18 @@ void uic_object_destroy(UiObject *obj) {
}
UiObject* uic_object_new_toplevel(void) {
+ fflush(stdout);
CxMempool *mp = cxMempoolCreateSimple(256);
UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
+ fflush(stdout);
obj->ctx = uic_context(obj, mp);
+ obj->ctx->parent = ui_global_context();
+ fflush(stdout);
uic_object_created(obj);
+ fflush(stdout);
return obj;
}
-UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget) {
- return uic_ctx_object_new(toplevel->ctx, widget);
-}
-
UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) {
UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObject));
newobj->ctx = ctx;
@@ -152,26 +126,6 @@ UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) {
return newobj;
}
-void uic_obj_add(UiObject *toplevel, UiObject *ctobj) {
- UiObject *current = uic_current_obj(toplevel);
- current->next = ctobj;
-}
-
-UiObject* uic_current_obj(UiObject *toplevel) {
- if(!toplevel) {
- return NULL;
- }
- UiObject *obj = toplevel;
- while(obj->next) {
- obj = obj->next;
- }
- return obj;
-}
-
-UiContainer* uic_get_current_container(UiObject *obj) {
- return uic_current_obj(obj)->container;
-}
-
void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer) {
newcontainer->prev = toplevel->container_end;
if(toplevel->container_end) {
@@ -190,4 +144,29 @@ void uic_object_pop_container(UiObject *toplevel) {
} else {
toplevel->container_begin = NULL;
}
+
+ // TODO: free container?
+}
+
+/*
+ * This might look like a weird function, but in case a container creates a
+ * sub-container, 2 container objects are added to the list, however we want
+ * only one container, otherwise ui_container_finish() would not work
+ */
+void uic_object_remove_second_last_container(UiObject *toplevel) {
+ if(toplevel->container_end && toplevel->container_end->prev) {
+ UiContainerX *end = toplevel->container_end;
+ UiContainerX *rm = toplevel->container_end->prev;
+
+ end->prev = rm->prev;
+ if(rm->prev) {
+ rm->prev->next = end;
+ } else {
+ toplevel->container_begin = end;
+ }
+
+ // TODO: free container?
+ } else {
+ fprintf(stderr, "Error: uic_object_remove_second_last_container expected at least 2 containers\n");
+ }
}
diff --git a/ui/common/object.h b/ui/common/object.h
index 45cf683..e6dd3c3 100644
--- a/ui/common/object.h
+++ b/ui/common/object.h
@@ -48,13 +48,10 @@ void uic_object_destroy(UiObject *obj);
UiObject* uic_object_new_toplevel(void);
UiObject* uic_object_new(UiObject *toplevel, UIWIDGET widget);
UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget);
-void uic_obj_add(UiObject *toplevel, UiObject *ctobj);
-UiObject* uic_current_obj(UiObject *toplevel);
-
-UiContainer* uic_get_current_container(UiObject *obj); // deprecated
void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer);
void uic_object_pop_container(UiObject *toplevel);
+void uic_object_remove_second_last_container(UiObject *toplevel);
diff --git a/ui/common/objs.mk b/ui/common/objs.mk
index a126b56..4d401b5 100644
--- a/ui/common/objs.mk
+++ b/ui/common/objs.mk
@@ -32,6 +32,7 @@ COMMON_OBJPRE = $(OBJ_DIR)$(COMMON_SRC_DIR)
COMMON_OBJ = context$(OBJ_EXT)
COMMON_OBJ += document$(OBJ_EXT)
COMMON_OBJ += object$(OBJ_EXT)
+COMMON_OBJ += container$(OBJ_EXT)
COMMON_OBJ += types$(OBJ_EXT)
COMMON_OBJ += properties$(OBJ_EXT)
COMMON_OBJ += menu$(OBJ_EXT)
diff --git a/ui/common/properties.c b/ui/common/properties.c
index 629112f..28676fb 100644
--- a/ui/common/properties.c
+++ b/ui/common/properties.c
@@ -73,7 +73,7 @@ char* ui_getappdir(void) {
#define UI_ENV_HOME "USERPROFILE"
#endif
-char* ui_configfile(char *name) {
+char* ui_configfile(const char *name) {
const char *appname = ui_appname();
if(!appname) {
return NULL;
@@ -128,6 +128,7 @@ static int ui_mkdir(char *path) {
void uic_load_app_properties() {
application_properties = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 128);
+ application_properties->collection.simple_destructor = free;
if(!ui_appname()) {
// applications without name cannot load app properties
@@ -191,13 +192,22 @@ int uic_store_app_properties() {
return ret;
}
+// public
+int ui_app_save_settings(void) {
+ return uic_store_app_properties();
+}
+
const char* ui_get_property(const char *name) {
return cxMapGet(application_properties, name);
}
void ui_set_property(const char *name, const char *value) {
- cxMapPut(application_properties, name, (char*)value);
+ if(value) {
+ cxMapPut(application_properties, name, strdup(value));
+ } else {
+ cxMapRemove(application_properties, name);
+ }
}
const char* ui_set_default_property(const char *name, const char *value) {
@@ -236,12 +246,14 @@ static char* uic_concat_path(const char *base, const char *p, const char *ext) {
#ifndef UI_COCOA
-void ui_locales_dir(char *path) {
- locales_dir = path;
+void ui_locales_dir(const char *path) {
+ free(locales_dir);
+ locales_dir = path ? strdup(path) : NULL;
}
-void ui_pixmaps_dir(char *path) {
- pixmaps_dir = path;
+void ui_pixmaps_dir(const char *path) {
+ free(pixmaps_dir);
+ pixmaps_dir = path ? strdup(path) : NULL;
}
char* uic_get_image_path(const char *imgfilename) {
@@ -252,7 +264,7 @@ char* uic_get_image_path(const char *imgfilename) {
}
}
-void ui_load_lang(char *locale) {
+void ui_load_lang(const char *locale) {
if(!locale) {
locale = "en_EN";
}
@@ -314,12 +326,12 @@ int uic_load_language_file(const char *path) {
return 0;
}
-char* uistr(char *name) {
+char* uistr(const char *name) {
char *value = uistr_n(name);
return value ? value : "missing string";
}
-char* uistr_n(char *name) {
+char* uistr_n(const char *name) {
if(!language) {
return NULL;
}
diff --git a/ui/common/toolbar.c b/ui/common/toolbar.c
index 199dc41..f237290 100644
--- a/ui/common/toolbar.c
+++ b/ui/common/toolbar.c
@@ -29,69 +29,73 @@
#include "toolbar.h"
#include "menu.h"
+#include
#include
static CxMap* toolbar_items;
-static CxList* toolbar_defaults[3]; // 0: left 1: center 2: right
+static CxList* toolbar_defaults[8]; // 0: left 1: center 2: right
static UiToolbarMenuItem* ui_appmenu;
void uic_toolbar_init(void) {
toolbar_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16);
- toolbar_defaults[0] = cxLinkedListCreateSimple(CX_STORE_POINTERS);
- toolbar_defaults[1] = cxLinkedListCreateSimple(CX_STORE_POINTERS);
- toolbar_defaults[2] = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+ for(int i=0;i<8;i++) {
+ toolbar_defaults[i] = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+ }
}
static char* nl_strdup(const char* str) {
return str ? strdup(str) : NULL;
}
-static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs *args, size_t *ngroups) {
+static UiToolbarItemArgs itemargs_copy(UiToolbarItemArgs *args, size_t *ngroups, size_t *nvstates) {
UiToolbarItemArgs newargs;
newargs.label = nl_strdup(args->label);
- newargs.stockid = nl_strdup(args->stockid);
newargs.icon = nl_strdup(args->icon);
+ newargs.tooltip = nl_strdup(args->tooltip);
newargs.onclick = args->onclick;
newargs.onclickdata = args->onclickdata;
newargs.groups = uic_copy_groups(args->groups, ngroups);
+ newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);
return newargs;
}
void ui_toolbar_item_create(const char* name, UiToolbarItemArgs *args) {
UiToolbarItem* item = malloc(sizeof(UiToolbarItem));
item->item.type = UI_TOOLBAR_ITEM;
- item->args = itemargs_copy(args, &item->ngroups);
+ item->args = itemargs_copy(args, &item->ngroups, &item->nvstates);
cxMapPut(toolbar_items, name, item);
}
-static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs *args, size_t *ngroups) {
+static UiToolbarToggleItemArgs toggleitemargs_copy(UiToolbarToggleItemArgs *args, size_t *ngroups, size_t *nvstates) {
UiToolbarToggleItemArgs newargs;
newargs.label = nl_strdup(args->label);
- newargs.stockid = nl_strdup(args->stockid);
newargs.icon = nl_strdup(args->icon);
+ newargs.tooltip = nl_strdup(args->tooltip);
newargs.varname = nl_strdup(args->varname);
newargs.onchange = args->onchange;
newargs.onchangedata = args->onchangedata;
newargs.groups = uic_copy_groups(args->groups, ngroups);
+ newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);
return newargs;
}
void ui_toolbar_toggleitem_create(const char* name, UiToolbarToggleItemArgs *args) {
UiToolbarToggleItem* item = malloc(sizeof(UiToolbarToggleItem));
item->item.type = UI_TOOLBAR_TOGGLEITEM;
- item->args = toggleitemargs_copy(args, &item->ngroups);
+ item->args = toggleitemargs_copy(args, &item->ngroups, &item->nvstates);
cxMapPut(toolbar_items, name, item);
}
-static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs *args) {
+static UiToolbarMenuArgs menuargs_copy(UiToolbarMenuArgs *args, size_t *nvstates) {
UiToolbarMenuArgs newargs;
newargs.label = nl_strdup(args->label);
- newargs.stockid = nl_strdup(args->stockid);
newargs.icon = nl_strdup(args->icon);
+ newargs.tooltip = nl_strdup(args->tooltip);
+ newargs.visibility_states = uic_copy_groups(args->visibility_states, nvstates);
return newargs;
}
@@ -99,7 +103,7 @@ UIEXPORT void ui_toolbar_menu_create(const char* name, UiToolbarMenuArgs *args)
UiToolbarMenuItem* item = malloc(sizeof(UiToolbarMenuItem));
item->item.type = UI_TOOLBAR_MENU;
memset(&item->menu, 0, sizeof(UiMenu));
- item->args = menuargs_copy(args);
+ item->args = menuargs_copy(args, &item->nvstates);
item->end = 0;
@@ -120,7 +124,7 @@ CxMap* uic_get_toolbar_items(void) {
}
CxList* uic_get_toolbar_defaults(enum UiToolbarPos pos) {
- if (pos >= 0 && pos < 3) {
+ if (pos >= 0 && pos < 8) {
return toolbar_defaults[pos];
}
return NULL;
@@ -128,15 +132,19 @@ CxList* uic_get_toolbar_defaults(enum UiToolbarPos pos) {
void ui_toolbar_add_default(const char* name, enum UiToolbarPos pos) {
char* cp = strdup(name);
- if (pos >= 0 && pos < 3) {
+ if (pos >= 0 && pos < 8) {
cxListAdd(toolbar_defaults[pos], cp);
} else {
- // TODO: error
+ fprintf(stderr, "Error: illegal toolbar position: %d\n", (int)pos);
}
}
UiBool uic_toolbar_isenabled(void) {
- return cxListSize(toolbar_defaults[0]) + cxListSize(toolbar_defaults[1]) + cxListSize(toolbar_defaults[2]) > 0;
+ size_t size = 0;
+ for(int i=0;i<8;i++) {
+ size += cxListSize(toolbar_defaults[i]);
+ }
+ return size > 0;
}
UiToolbarItemI* uic_toolbar_get_item(const char* name) {
diff --git a/ui/common/toolbar.h b/ui/common/toolbar.h
index a13828e..1ac1d55 100644
--- a/ui/common/toolbar.h
+++ b/ui/common/toolbar.h
@@ -63,18 +63,21 @@ struct UiToolbarItem {
UiToolbarItemI item;
UiToolbarItemArgs args;
size_t ngroups;
+ size_t nvstates;
};
struct UiToolbarToggleItem {
UiToolbarItemI item;
UiToolbarToggleItemArgs args;
size_t ngroups;
+ size_t nvstates;
};
struct UiToolbarMenuItem {
UiToolbarItemI item;
UiMenu menu;
UiToolbarMenuArgs args;
+ size_t nvstates;
int end;
};
diff --git a/ui/common/types.c b/ui/common/types.c
index b3f55d1..57ad68e 100644
--- a/ui/common/types.c
+++ b/ui/common/types.c
@@ -165,12 +165,26 @@ void ui_list_clear(UiList *list) {
cxListClear(list->data);
}
-UIEXPORT void ui_list_update(UiList *list) {
+void ui_list_update(UiList *list) {
if(list->update) {
list->update(list, -1);
}
}
+void ui_list_update_row(UiList *list, int row) {
+ if(list->update) {
+ list->update(list, row);
+ }
+}
+
+UiListSelection ui_list_get_selection(UiList *list) {
+ if(list->getselection) {
+ return list->getselection(list);
+ } else {
+ return (UiListSelection){0, NULL};
+ }
+}
+
void ui_list_addobsv(UiList *list, ui_callback f, void *data) {
list->observers = ui_add_observer(list->observers, f, data);
}
@@ -206,6 +220,7 @@ UiModel* ui_model(UiContext *ctx, ...) {
va_end(ap);
size_t len = cxListSize(cols);
+ info->alloc = len;
info->columns = len;
info->types = ui_calloc(ctx, len, sizeof(UiModelType));
info->titles = ui_calloc(ctx, len, sizeof(char*));
@@ -215,7 +230,7 @@ UiModel* ui_model(UiContext *ctx, ...) {
CxIterator iter = cxListIterator(cols);
cx_foreach(UiColumn*, c, iter) {
info->types[i] = c->type;
- info->titles[i] = c->name;
+ info->titles[i] = ui_strdup(ctx, c->name);
i++;
}
cxListFree(cols);
@@ -223,6 +238,30 @@ UiModel* ui_model(UiContext *ctx, ...) {
return info;
}
+#define UI_MODEL_DEFAULT_ALLOC_SIZE 16
+
+UiModel* ui_model_new(UiContext *ctx) {
+ UiModel *info = ui_calloc(ctx, 1, sizeof(UiModel));
+ info->alloc = UI_MODEL_DEFAULT_ALLOC_SIZE;
+ info->types = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(UiModelType));
+ info->titles = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(char*));
+ info->columnsize = ui_calloc(ctx, UI_MODEL_DEFAULT_ALLOC_SIZE, sizeof(int));
+ return info;
+}
+
+void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width) {
+ if(model->columns >= model->alloc) {
+ model->alloc += UI_MODEL_DEFAULT_ALLOC_SIZE;
+ model->types = ui_realloc(ctx, model->types, model->alloc * sizeof(UiModelType));
+ model->titles = ui_realloc(ctx, model->titles, model->alloc * sizeof(char*));
+ model->columnsize = ui_realloc(ctx, model->columnsize, model->alloc * sizeof(int));
+ }
+ model->types[model->columns] = type;
+ model->titles[model->columns] = ui_strdup(ctx, title);
+ model->columnsize[model->columns] = width;
+ model->columns++;
+}
+
UiModel* ui_model_copy(UiContext *ctx, UiModel* model) {
const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
@@ -244,6 +283,9 @@ UiModel* ui_model_copy(UiContext *ctx, UiModel* model) {
void ui_model_free(UiContext *ctx, UiModel *mi) {
const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
+ for(int i=0;icolumns;i++) {
+ ui_free(ctx, mi->titles[i]);
+ }
cxFree(a, mi->types);
cxFree(a, mi->titles);
cxFree(a, mi->columnsize);
@@ -271,18 +313,32 @@ UiDouble* ui_double_new(UiContext *ctx, const char *name) {
return d;
}
+static void string_destroy(UiString *s) {
+ if(s->value.free && s->value.ptr) {
+ s->value.free(s->value.ptr);
+ }
+}
+
UiString* ui_string_new(UiContext *ctx, const char *name) {
UiString *s = ui_malloc(ctx, sizeof(UiString));
memset(s, 0, sizeof(UiString));
+ ui_set_destructor(s, (ui_destructor_func)string_destroy);
if(name) {
uic_reg_var(ctx, name, UI_VAR_STRING, s);
}
return s;
}
+static void text_destroy(UiText *t) {
+ if(t->destroy) {
+ t->destroy(t);
+ }
+}
+
UiText* ui_text_new(UiContext *ctx, const char *name) {
UiText *t = ui_malloc(ctx, sizeof(UiText));
memset(t, 0, sizeof(UiText));
+ ui_set_destructor(t, (ui_destructor_func)text_destroy);
if(name) {
uic_reg_var(ctx, name, UI_VAR_TEXT, t);
}
@@ -298,9 +354,16 @@ UiRange* ui_range_new(UiContext *ctx, const char *name) {
return r;
}
-UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
+static void generic_destroy(UiGeneric *g) {
+ if(g->destroy) {
+ g->destroy(g);
+ }
+}
+
+UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric));
memset(g, 0, sizeof(UiGeneric));
+ ui_set_destructor(g, (ui_destructor_func)generic_destroy);
if(name) {
uic_reg_var(ctx, name, UI_VAR_GENERIC, g);
}
@@ -375,7 +438,7 @@ char* ui_string_get(UiString* s) {
return s->get ? s->get(s) : s->value.ptr;
}
else {
- return 0;
+ return NULL;
}
}
@@ -405,6 +468,69 @@ char* ui_text_get(UiText* s) {
return s->get ? s->get(s) : s->value.ptr;
}
else {
+ return NULL;
+ }
+}
+
+void ui_range_set(UiRange *r, double value) {
+ if (r) {
+ if (r->set) {
+ r->set(r, value);
+ } else {
+ r->value = value;
+ }
+ }
+}
+
+void ui_range_set_range(UiRange *r, double min, double max) {
+ if (r) {
+ if (r->setrange) {
+ r->setrange(r, min, max);
+ } else {
+ r->min = min;
+ r->max = max;
+ }
+ }
+}
+
+void ui_range_set_extent(UiRange *r, double extent) {
+ if (r) {
+ if (r->setextent) {
+ r->setextent(r, extent);
+ } else {
+ r->extent = extent;
+ }
+ }
+}
+
+double ui_range_get(UiRange *r) {
+ if (r) {
+ return r->get ? r->get(r) : r->value;
+ } else {
+ return 0;
+ }
+}
+
+double ui_range_get_min(UiRange *r) {
+ if (r) {
+ return r->min;
+ } else {
+ return 0;
+ }
+}
+
+double ui_range_get_max(UiRange *r) {
+ if (r) {
+ return r->max;
+ } else {
+ return 0;
+ }
+}
+
+double ui_range_get_extent(UiRange *r) {
+ if (r) {
+ return r->extent;
+ } else {
return 0;
}
}
@@ -566,6 +692,8 @@ void uic_range_unbind(UiRange *r) {
void uic_list_unbind(UiList *l) {
l->update = NULL;
+ l->getselection = NULL;
+ l->setselection = NULL;
l->obj = NULL;
}
@@ -585,10 +713,12 @@ UIEXPORT UiListSelection ui_list_getselection(UiList *list) {
}
UIEXPORT void ui_list_setselection(UiList *list, int index) {
- if (list->setselection && index >= 0) {
- UiListSelection sel;
- sel.count = 1;
- sel.rows = &index;
+ if (list->setselection) {
+ UiListSelection sel = { 0, NULL };
+ if(index >= 0) {
+ sel.count = 1;
+ sel.rows = &index;
+ }
list->setselection(list, sel);
}
}
diff --git a/ui/common/wrapper.c b/ui/common/wrapper.c
index ea88553..50ecf40 100644
--- a/ui/common/wrapper.c
+++ b/ui/common/wrapper.c
@@ -134,6 +134,17 @@ int ui_srclist_size(UiList *list) {
return ui_list_count(list);
}
+/*
+ * numerates all sublists and sets the sublist index as userdata
+ */
+void ui_srclist_generate_sublist_num_data(UiList *list) {
+ CxList *cxlist = list->data;
+ CxIterator i = cxListIterator(cxlist);
+ cx_foreach(UiSubList *, sublist, i) {
+ sublist->userdata = (void*)i.index;
+ }
+}
+
/* ---------------------------- UiSubListEventData ---------------------------- */
@@ -211,6 +222,10 @@ void ui_sublist_item_set_button_label(UiSubListItem *item, const char *button_la
item->button_label = button_label ? strdup(button_label) : NULL;
}
+void ui_sublist_item_set_button_menu(UiSubListItem *item, UiMenuBuilder *menu) {
+ item->button_menu = menu;
+}
+
void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge) {
item->badge = badge ? strdup(badge) : NULL;
}
@@ -218,3 +233,103 @@ void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge) {
void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata) {
item->eventdata = NULL;
}
+
+/* ---------------------------- UiListSelection ---------------------------- */
+
+UiListSelection* ui_list_get_selection_allocated(UiList *list) {
+ UiListSelection *sel = malloc(sizeof(UiListSelection));
+ *sel = ui_list_get_selection(list);
+ return sel;
+
+}
+
+int ui_list_selection_get_count(UiListSelection *sel) {
+ return sel->count;
+}
+
+int* ui_list_selection_get_rows(UiListSelection *sel) {
+ return sel->rows;
+}
+
+UIEXPORT void ui_list_set_selected_indices(UiList *list, int *indices, int num) {
+ UiListSelection sel;
+ sel.rows = indices;
+ sel.count = num;
+ if(list->setselection) {
+ list->setselection(list, sel);
+ }
+}
+
+void ui_list_selection_free(UiListSelection *sel) {
+ ui_listselection_free(*sel);
+ free(sel);
+}
+
+/* ---------------------------- UiFileList ---------------------------- */
+
+int ui_filelist_count(UiFileList *flist) {
+ return flist->nfiles;
+}
+
+char* ui_filelist_get(UiFileList *flist, int index) {
+ if(index >= 0 && index < flist->nfiles) {
+ return flist->files[index];
+ }
+ return NULL;
+}
+
+/* ---------------------------- UiTextStyle ---------------------------- */
+
+void ui_textstyle_set_bold(UiTextStyle *style, UiBool set) {
+ if(set) {
+ style->text_style |= UI_TEXT_STYLE_BOLD;
+ } else {
+ style->text_style &= ~UI_TEXT_STYLE_BOLD;
+ }
+}
+
+void ui_textstyle_set_underline(UiTextStyle *style, UiBool set) {
+ if(set) {
+ style->text_style |= UI_TEXT_STYLE_UNDERLINE;
+ } else {
+ style->text_style &= ~UI_TEXT_STYLE_UNDERLINE;
+ }
+}
+
+void ui_textstyle_set_italic(UiTextStyle *style, UiBool set) {
+ if(set) {
+ style->text_style |= UI_TEXT_STYLE_ITALIC;
+ } else {
+ style->text_style &= ~UI_TEXT_STYLE_ITALIC;
+ }
+}
+
+void ui_textstyle_set_color(UiTextStyle *style, int r, int g, int b) {
+ style->fg_set = TRUE;
+ style->fg.red = r;
+ style->fg.green = g;
+ style->fg.blue = b;
+}
+
+void ui_textstyle_enable_color(UiTextStyle *style, UiBool enable) {
+ style->fg_set = enable;
+}
+
+
+/* ---------------------------- UiCellValue ---------------------------- */
+
+UiBool ui_cell_value_is_string(UiCellValue *value) {
+ return value->type == UI_STRING_EDITABLE;
+}
+
+UiBool ui_cell_value_is_int(UiCellValue *value) {
+ return FALSE; // TODO
+}
+
+const char* ui_cell_value_get_string(UiCellValue *value) {
+ return value->string;
+}
+
+int64_t ui_cell_value_get_int(UiCellValue *value) {
+ return value->i;
+}
diff --git a/ui/common/wrapper.h b/ui/common/wrapper.h
index d190fc8..88fd8c8 100644
--- a/ui/common/wrapper.h
+++ b/ui/common/wrapper.h
@@ -58,6 +58,7 @@ UIEXPORT void ui_srclist_insert(UiList *list, int index, UiSubList *item);
UIEXPORT void ui_srclist_remove(UiList *list, int index);
UIEXPORT void ui_srclist_clear(UiList *list);
UIEXPORT int ui_srclist_size(UiList *list);
+UIEXPORT void ui_srclist_generate_sublist_num_data(UiList *list);
UIEXPORT UiList* ui_sublist_event_get_list(UiSubListEventData *event);
UIEXPORT int ui_sublist_event_get_sublist_index(UiSubListEventData *event);
@@ -74,6 +75,25 @@ UIEXPORT int ui_event_get_eventdatatype(UiEvent *event);
UIEXPORT int ui_event_get_int(UiEvent *event);
UIEXPORT int ui_event_get_set(UiEvent *event);
+UIEXPORT UiListSelection* ui_list_get_selection_allocated(UiList *list);
+UIEXPORT int ui_list_selection_get_count(UiListSelection *sel);
+UIEXPORT int* ui_list_selection_get_rows(UiListSelection *sel);
+UIEXPORT void ui_list_set_selected_indices(UiList *list, int *indices, int num);
+UIEXPORT void ui_list_selection_free(UiListSelection *sel);
+
+UIEXPORT int ui_filelist_count(UiFileList *flist);
+UIEXPORT char* ui_filelist_get(UiFileList *flist, int index);
+
+UIEXPORT void ui_textstyle_set_bold(UiTextStyle *style, UiBool set);
+UIEXPORT void ui_textstyle_set_underline(UiTextStyle *style, UiBool set);
+UIEXPORT void ui_textstyle_set_italic(UiTextStyle *style, UiBool set);
+UIEXPORT void ui_textstyle_set_color(UiTextStyle *style, int r, int g, int b);
+UIEXPORT void ui_textstyle_enable_color(UiTextStyle *style, UiBool enable);
+
+UIEXPORT UiBool ui_cell_value_is_string(UiCellValue *value);
+UIEXPORT UiBool ui_cell_value_is_int(UiCellValue *value);
+UIEXPORT const char* ui_cell_value_get_string(UiCellValue *value);
+UIEXPORT int64_t ui_cell_value_get_int(UiCellValue *value);
#ifdef __cplusplus
diff --git a/ui/gtk/button.c b/ui/gtk/button.c
index 6f6ad0b..6db5141 100644
--- a/ui/gtk/button.c
+++ b/ui/gtk/button.c
@@ -32,6 +32,8 @@
#include "button.h"
#include "container.h"
#include
+#include
+#include
#include "../common/context.h"
#include "../common/object.h"
@@ -58,6 +60,7 @@ GtkWidget* ui_create_button(
UiObject *obj,
const char *label,
const char *icon,
+ const char *tooltip,
ui_callback onclick,
void *userdata,
int event_value,
@@ -65,6 +68,9 @@ GtkWidget* ui_create_button(
{
GtkWidget *button = gtk_button_new_with_label(label);
ui_button_set_icon_name(button, icon);
+ if(tooltip) {
+ gtk_widget_set_tooltip_text(button, tooltip);
+ }
if(onclick) {
UiEventData *event = malloc(sizeof(UiEventData));
@@ -98,12 +104,12 @@ GtkWidget* ui_create_button(
}
UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {
- UiObject* current = uic_current_obj(obj);
- GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->onclick, args->onclickdata, 0, FALSE);
+ GtkWidget *button = ui_create_button(obj, args->label, args->icon, args->tooltip, args->onclick, args->onclickdata, 0, FALSE);
ui_set_name_and_style(button, args->name, args->style_class);
ui_set_widget_groups(obj->ctx, button, args->groups);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, button);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, button, &layout);
return button;
}
@@ -120,6 +126,14 @@ void ui_button_clicked(GtkWidget *widget, UiEventData *event) {
event->callback(&e, event->userdata);
}
+void ui_button_set_label(UIWIDGET button, const char *label) {
+ gtk_button_set_label(GTK_BUTTON(button), label);
+}
+
+void ui_button_set_icon(UIWIDGET button, const char *icon) {
+ ui_button_set_icon_name(button, icon);
+}
+
int64_t ui_toggle_button_get(UiInteger *integer) {
GtkToggleButton *button = integer->obj;
integer->value = (int)gtk_toggle_button_get_active(button);
@@ -171,6 +185,7 @@ void ui_setup_togglebutton(
GtkWidget *togglebutton,
const char *label,
const char *icon,
+ const char *tooltip,
const char *varname,
UiInteger *value,
ui_callback onchange,
@@ -181,6 +196,9 @@ void ui_setup_togglebutton(
gtk_button_set_label(GTK_BUTTON(togglebutton), label);
}
ui_button_set_icon_name(togglebutton, icon);
+ if(tooltip) {
+ gtk_widget_set_tooltip_text(togglebutton, tooltip);
+ }
ui_bind_togglebutton(
obj,
@@ -210,8 +228,7 @@ void ui_bind_togglebutton(
void (*enable_state_func)(void*, void*),
int enable_state)
{
- UiObject* current = uic_current_obj(obj);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, value, varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER);
if (var) {
UiInteger* value = (UiInteger*)var->value;
value->obj = widget;
@@ -281,13 +298,12 @@ void ui_bind_togglebutton(
}
static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
ui_setup_togglebutton(
obj,
widget,
args->label,
args->icon,
+ args->tooltip,
args->varname,
args->value,
args->onchange,
@@ -296,8 +312,9 @@ static UIWIDGET togglebutton_create(UiObject *obj, GtkWidget *widget, UiToggleAr
ui_set_name_and_style(widget, args->name, args->style_class);
ui_set_widget_groups(obj->ctx, widget, args->groups);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
return widget;
}
@@ -340,9 +357,7 @@ static void ui_checkbox_enable_state(GtkCheckButton *widget, UiEventData *event)
}
}
-UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
+UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
GtkWidget *widget = gtk_check_button_new_with_label(args->label);
ui_bind_togglebutton(
obj,
@@ -360,8 +375,9 @@ UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
ui_set_name_and_style(widget, args->name, args->style_class);
ui_set_widget_groups(obj->ctx, widget, args->groups);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
return widget;
}
@@ -372,14 +388,99 @@ UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args) {
}
#endif
+
+#if GTK_MAJOR_VERSION >= 3
+
+static void switch_changed(
+ GObject *gobject,
+ GParamSpec *pspec,
+ UiVarEventData *event)
+{
+ GtkSwitch *sw = GTK_SWITCH (gobject);
+ gboolean active = gtk_switch_get_active (sw);
+
+ UiEvent e;
+ e.obj = event->obj;
+ e.document = e.obj->ctx->document;
+ e.window = e.obj->window;
+ e.eventdata = NULL;
+ e.eventdatatype = 0;
+ e.set = ui_get_setop();
+
+ if(event->callback) {
+ event->callback(&e, event->userdata);
+ }
+ if(event->var) {
+ UiInteger *i = event->var->value;
+ ui_notify_evt(i->observers, &e);
+ }
+}
+
UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
-#ifdef UI_GTK3
- return NULL; // TODO
+ GtkWidget *widget = gtk_switch_new();
+ ui_set_name_and_style(widget, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, widget, args->groups);
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
+ if(var) {
+ UiInteger *value = var->value;
+ value->obj = widget;
+ value->get = ui_switch_get;
+ value->set = ui_switch_set;
+
+ if(value->value) {
+ gtk_switch_set_active(GTK_SWITCH(widget), TRUE);
+ }
+
+
+ }
+
+ UiVarEventData *event = malloc(sizeof(UiVarEventData));
+ event->obj = obj;
+ event->callback = args->onchange;
+ event->userdata = args->onchangedata;
+ event->var = var;
+ event->observers = NULL;
+
+ g_signal_connect(
+ widget,
+ "notify::active",
+ G_CALLBACK(switch_changed),
+ event);
+
+ g_signal_connect(
+ widget,
+ "destroy",
+ G_CALLBACK(ui_destroy_vardata),
+ event);
+
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
+
+ return widget;
+}
+
+int64_t ui_switch_get(UiInteger *value) {
+ GtkSwitch *sw = GTK_SWITCH((GtkWidget*)value->obj);
+ value->value = gtk_switch_get_active(sw);
+ return value->value;
+}
+
+void ui_switch_set(UiInteger *value, int64_t i) {
+ GtkSwitch *sw = GTK_SWITCH((GtkWidget*)value->obj);
+ value->value = i;
+ gtk_switch_set_active(sw, i);
+}
+
#else
+
+UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args) {
return ui_checkbox_create(obj, args);
-#endif
}
+#endif
+
#if GTK_MAJOR_VERSION >= 4
#define RADIOBUTTON_NEW(group, label) gtk_check_button_new_with_label(label)
#define RADIOBUTTON_SET_GROUP(button, group)
@@ -424,12 +525,10 @@ static void destroy_radiobutton(GtkWidget *w, UiRadioButtonData *data) {
}
UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
GSList *rg = NULL;
UiInteger *rgroup;
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
UiBool first = FALSE;
if(var) {
@@ -505,8 +604,9 @@ UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) {
event);
}
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, rbutton);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, rbutton, &layout);
return rbutton;
}
@@ -594,3 +694,307 @@ void ui_radiobutton_set(UiInteger *value, int64_t i) {
value->value = i;
}
#endif
+
+
+static void ui_destroy_linkbutton(GtkWidget *widget, UiLinkButton *data) {
+ free(data->link);
+ free(data);
+}
+
+static const char* linkbutton_get_uri(UiLinkButton *link) {
+ if(link->type == UI_LINK_BUTTON) {
+ return link->link;
+ } else {
+ return gtk_link_button_get_uri(GTK_LINK_BUTTON(link->widget));
+ }
+}
+
+static void linkbutton_set_uri(UiLinkButton *link, const char *uri) {
+ if(link->type == UI_LINK_BUTTON) {
+ free(link->link);
+ link->link = uri ? strdup(uri) : NULL;
+ } else {
+ gtk_link_button_set_uri(GTK_LINK_BUTTON(link->widget), uri);
+ }
+}
+
+static gboolean linkbutton_get_visited(UiLinkButton *link) {
+ if(link->type == UI_LINK_BUTTON) {
+ return FALSE;
+ } else {
+ gtk_link_button_get_visited(GTK_LINK_BUTTON(link->widget));
+ }
+}
+
+static void linkbutton_set_visited(UiLinkButton *link, gboolean visited) {
+ if(link->type != UI_LINK_BUTTON) {
+ gtk_link_button_set_visited(GTK_LINK_BUTTON(link->widget), visited);
+ }
+}
+
+/*
+ * Apply linkbutton settings from json. Expects jsonvalue to be a valid
+ * json object.
+ *
+ * {
+ * "label": "label text",
+ * "uri": "http://example.com",
+ * "visited": true
+ * }
+ *
+ */
+static void linkbutton_apply_value(UiLinkButton *link, const char *jsonvalue) {
+ CxJson json;
+ cxJsonInit(&json, NULL);
+ cxJsonFill(&json, jsonvalue);
+
+ CxJsonValue *value;
+ if(cxJsonNext(&json, &value) == CX_JSON_NO_ERROR) {
+ if(cxJsonIsObject(value)) {
+ CxJsonValue *label = cxJsonObjGet(value, "label");
+ CxJsonValue *uri = cxJsonObjGet(value, "uri");
+ CxJsonValue *visited = cxJsonObjGet(value, "visited");
+ if(label) {
+ gtk_button_set_label(GTK_BUTTON(link->widget), cxJsonIsString(label) ? cxJsonAsString(label) : NULL);
+ }
+ if(uri) {
+ linkbutton_set_uri(link, cxJsonIsString(uri) ? cxJsonAsString(uri) : NULL);
+
+ }
+ if(visited) {
+ linkbutton_set_visited(link, cxJsonIsBool(visited) ? cxJsonAsBool(visited) : FALSE);
+ }
+ }
+ cxJsonValueFree(value);
+ }
+ cxJsonDestroy(&json);
+}
+
+static char* create_linkbutton_jsonvalue(const char *label, const char *uri, gboolean include_null, gboolean visited, gboolean set_visited) {
+ CxJsonValue *obj = cxJsonCreateObj(NULL);
+ if(label) {
+ cxJsonObjPutString(obj, CX_STR("label"), label);
+ } else if(include_null) {
+ cxJsonObjPutLiteral(obj, CX_STR("label"), CX_JSON_NULL);
+ }
+
+ if(uri) {
+ cxJsonObjPutString(obj, CX_STR("uri"), uri);
+ } else if(include_null) {
+ cxJsonObjPutLiteral(obj, CX_STR("uri"), CX_JSON_NULL);
+ }
+
+ if(set_visited) {
+ cxJsonObjPutLiteral(obj, CX_STR("visited"), visited ? CX_JSON_TRUE : CX_JSON_FALSE);
+ }
+
+ CxJsonWriter writer = cxJsonWriterCompact();
+ CxBuffer buf;
+ cxBufferInit(&buf, NULL, 128, NULL, CX_BUFFER_AUTO_EXTEND);
+ cxJsonWrite(&buf, obj, (cx_write_func)cxBufferWrite, &writer);
+ cxJsonValueFree(obj);
+ cxBufferTerminate(&buf);
+
+ return buf.space;
+}
+
+static char* linkbutton_get_value(UiLinkButton *link) {
+ const char *label = gtk_button_get_label(GTK_BUTTON(link->widget));
+ const char *uri = linkbutton_get_uri(link);
+ gboolean visited = linkbutton_get_visited(link);
+ return create_linkbutton_jsonvalue(label, uri, TRUE, visited, TRUE);
+}
+
+static void linkbutton_callback(GtkWidget *widget, UiLinkButton *data) {
+ if(data->onclick) {
+ UiEvent e;
+ e.obj = data->obj;
+ e.document = e.obj->ctx->document;
+ e.window = e.obj->window;
+ e.eventdata = (char*)linkbutton_get_uri(data);
+ e.eventdatatype = UI_EVENT_DATA_STRING;
+ e.intval = 0;
+ e.set = ui_get_setop();
+ data->onclick(&e, data->onclickdata);
+ }
+}
+
+static void linkbutton_clicked(GtkWidget *widget, UiLinkButton *data) {
+ linkbutton_callback(widget, data);
+ if(data->link) {
+#if GTK_CHECK_VERSION(4, 0, 0)
+ GtkUriLauncher *launcher = gtk_uri_launcher_new (data->link);
+ gtk_uri_launcher_launch (launcher, NULL, NULL, NULL, NULL);
+ g_object_unref (launcher);
+#elif GTK_CHECK_VERSION(3, 22, 0)
+ GError *error = NULL;
+ gtk_show_uri_on_window(NULL, data->link, GDK_CURRENT_TIME, &error);
+#elif
+ // TODO: call xdg-open
+#endif
+ }
+}
+
+static gboolean linkbutton_activate_link(GtkLinkButton *self, UiLinkButton *data) {
+ linkbutton_callback(data->widget, data);
+ return data->nofollow;
+}
+
+UIWIDGET ui_linkbutton_create(UiObject *obj, UiLinkButtonArgs *args) {
+ UiLinkButton *data = malloc(sizeof(UiLinkButton));
+ memset(data, 0, sizeof(UiLinkButton));
+ data->obj = obj;
+ data->type = args->type;
+ data->nofollow = args->nofollow;
+ data->onclick = args->onclick;
+ data->onclickdata = args->onclickdata;
+
+ GtkWidget *button;
+ if(args->type == UI_LINK_BUTTON) {
+ button = gtk_button_new();
+ g_signal_connect(
+ button,
+ "clicked",
+ G_CALLBACK(linkbutton_clicked),
+ data);
+ } else {
+ button = gtk_link_button_new("file:///");
+ g_signal_connect(
+ button,
+ "activate-link",
+ G_CALLBACK(linkbutton_activate_link),
+ data);
+ }
+ gtk_button_set_label(GTK_BUTTON(button), args->label);
+#if GTK_CHECK_VERSION(4, 0, 0)
+ gtk_button_set_can_shrink(GTK_BUTTON(button), TRUE);
+#elif GTK_MAJOR_VERSION == 3
+ GtkWidget *child = gtk_bin_get_child(GTK_BIN(button));
+ gtk_label_set_ellipsize(GTK_LABEL(child), PANGO_ELLIPSIZE_END);
+#endif
+ g_object_set_data(G_OBJECT(button), "ui_linkbutton", data);
+ g_signal_connect(
+ button,
+ "destroy",
+ G_CALLBACK(ui_destroy_linkbutton),
+ data);
+
+ data->widget = button;
+
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
+ if(var) {
+ UiString *str = var->value;
+ char *current_value = ui_get(str);
+ if(current_value) {
+ linkbutton_apply_value(data, current_value);
+ }
+
+ str->obj = data;
+ str->get = ui_linkbutton_get;
+ str->set = ui_linkbutton_set;
+ }
+
+ ui_set_name_and_style(button, args->name, args->style_class);
+ ui_set_widget_groups(obj->ctx, button, args->groups);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, button, &layout);
+
+ return button;
+}
+
+char* ui_linkbutton_get(UiString *s) {
+ UiLinkButton *link = s->obj;
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ s->value.ptr = linkbutton_get_value(link);
+ s->value.free = free;
+ return s->value.ptr;
+}
+
+void ui_linkbutton_set(UiString *s, const char *str) {
+ linkbutton_apply_value(s->obj, str);
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+#if GTK_MAJOR_VERSION == 3
+ UiLinkButton *data = s->obj;
+ GtkWidget *child = gtk_bin_get_child(GTK_BIN(data->widget));
+ gtk_label_set_ellipsize(GTK_LABEL(child), PANGO_ELLIPSIZE_END);
+#endif
+}
+
+
+void ui_linkbutton_value_set(UiString *str, const char *label, const char *uri) {
+ char *value = create_linkbutton_jsonvalue(label, uri, TRUE, FALSE, TRUE);
+ ui_set(str, value);
+ free(value);
+}
+
+void ui_linkbutton_value_set_label(UiString *str, const char *label) {
+ char *value = create_linkbutton_jsonvalue(label, NULL, FALSE, FALSE, TRUE);
+ ui_set(str, value);
+ free(value);
+}
+
+void ui_linkbutton_value_set_uri(UiString *str, const char *uri) {
+ char *value = create_linkbutton_jsonvalue(NULL, uri, FALSE, FALSE, TRUE);
+ ui_set(str, value);
+ free(value);
+}
+
+void ui_linkbutton_value_set_visited(UiString *str, UiBool visited) {
+ char *value = create_linkbutton_jsonvalue(NULL, NULL, FALSE, visited, TRUE);
+ ui_set(str, value);
+ free(value);
+}
+
+
+void ui_linkbutton_set_label(UIWIDGET button, const char *label) {
+ gtk_button_set_label(GTK_BUTTON(button), label);
+}
+
+void ui_linkbutton_set_uri(UIWIDGET button, const char *label) {
+ UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+ if(link) {
+ linkbutton_set_uri(link, label);
+ } else {
+ fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+ }
+}
+
+void ui_linkbutton_set_visited(UIWIDGET button, UiBool visited) {
+ UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+ if(link) {
+ linkbutton_set_visited(link, visited);
+ } else {
+ fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+ }
+}
+
+char* ui_linkbutton_get_label(UIWIDGET button) {
+ const char *label = gtk_button_get_label(GTK_BUTTON(button));
+ return label ? strdup(label) : NULL;
+}
+
+char* ui_linkbutton_get_uri(UIWIDGET button) {
+ UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+ if(link) {
+ const char *uri = linkbutton_get_uri(link);
+ return uri ? strdup(uri) : NULL;
+ } else {
+ fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+ }
+ return NULL;
+}
+
+UiBool ui_linkbutton_get_visited(UIWIDGET button) {
+ UiLinkButton *link = g_object_get_data(G_OBJECT(button), "ui_linkbutton");
+ if(link) {
+ return linkbutton_get_visited(link);
+ } else {
+ fprintf(stderr, "Error: ui_linkbutton_set_label: widget is not a linkbutton\n");
+ }
+ return FALSE;
+}
diff --git a/ui/gtk/button.h b/ui/gtk/button.h
index c855b35..ce94b90 100644
--- a/ui/gtk/button.h
+++ b/ui/gtk/button.h
@@ -37,6 +37,16 @@
extern "C" {
#endif
+typedef struct UiLinkButton {
+ UiObject *obj;
+ GtkWidget *widget;
+ UiLinkType type;
+ UiBool nofollow;
+ char *link;
+ ui_callback onclick;
+ void *onclickdata;
+} UiLinkButton;
+
void ui_button_set_icon_name(GtkWidget *button, const char *icon_name);
typedef void (*ui_toggled_func)(void*, void*);
@@ -45,6 +55,7 @@ GtkWidget* ui_create_button(
UiObject *obj,
const char *label,
const char *icon,
+ const char *tooltip,
ui_callback onclick,
void *userdata,
int event_value,
@@ -55,6 +66,7 @@ void ui_setup_togglebutton(
GtkWidget *togglebutton,
const char *label,
const char *icon,
+ const char *tooltip,
const char *varname,
UiInteger *value,
ui_callback onchange,
@@ -86,9 +98,15 @@ UIWIDGET ui_radiobutton_var(UiObject *obj, char *label, UiVar *var);
void ui_radio_obs(GtkToggleButton *widget, UiVarEventData *event);
+int64_t ui_switch_get(UiInteger *value);
+void ui_switch_set(UiInteger *value, int64_t i);
+
int64_t ui_radiobutton_get(UiInteger *value);
void ui_radiobutton_set(UiInteger *value, int64_t i);
+char* ui_linkbutton_get(UiString *s);
+void ui_linkbutton_set(UiString *s, const char *str);
+
#ifdef __cplusplus
}
#endif
diff --git a/ui/gtk/container.c b/ui/gtk/container.c
index 7a98bf4..9ca07f9 100644
--- a/ui/gtk/container.c
+++ b/ui/gtk/container.c
@@ -28,6 +28,7 @@
#include
#include
+#include
#include
#include "container.h"
@@ -36,17 +37,20 @@
#include "../common/context.h"
#include "../common/object.h"
+#include "../common/container.h"
+
+#include "../ui/properties.h"
void ui_container_begin_close(UiObject *obj) {
- UiContainer *ct = uic_get_current_container(obj);
+ UiContainerX *ct = obj->container_end;
ct->close = 1;
}
int ui_container_finish(UiObject *obj) {
- UiContainer *ct = uic_get_current_container(obj);
+ UiContainerX *ct = obj->container_end;
if(ct->close) {
- ui_end(obj);
+ ui_end_new(obj);
return 0;
}
return 1;
@@ -70,7 +74,7 @@ GtkWidget* ui_gtk_hbox_new(int spacing) {
GtkWidget* ui_subcontainer_create(
UiSubContainerType type,
- UiObject *newobj,
+ UiObject *obj,
int spacing,
int columnspacing,
int rowspacing,
@@ -78,38 +82,39 @@ GtkWidget* ui_subcontainer_create(
{
GtkWidget *sub = NULL;
GtkWidget *add = NULL;
+ UiContainerX *container = NULL;
switch(type) {
default: {
sub = ui_gtk_vbox_new(spacing);
- add = ui_box_set_margin(sub, margin);
- newobj->container = ui_box_container(newobj, sub, type);
- newobj->widget = sub;
+ add = ui_gtk_set_margin(sub, margin, 0, 0, 0, 0);
+ container = ui_box_container(obj, sub, type);
break;
}
case UI_CONTAINER_HBOX: {
sub = ui_gtk_hbox_new(spacing);
- add = ui_box_set_margin(sub, margin);
- newobj->container = ui_box_container(newobj, sub, type);
- newobj->widget = sub;
+ add = ui_gtk_set_margin(sub, margin, 0, 0, 0, 0);
+ container = ui_box_container(obj, sub, type);
break;
}
case UI_CONTAINER_GRID: {
sub = ui_create_grid_widget(columnspacing, rowspacing);
- add = ui_box_set_margin(sub, margin);
- newobj->container = ui_grid_container(newobj, sub, FALSE, FALSE, FALSE, FALSE);
- newobj->widget = sub;
+ add = ui_gtk_set_margin(sub, margin, 0, 0, 0, 0);
+ container = ui_grid_container(obj, sub, FALSE, FALSE, FALSE, FALSE);
break;
}
case UI_CONTAINER_NO_SUB: {
break;
}
}
+ if(container) {
+ uic_object_push_container(obj, container);
+ }
return add;
}
/* -------------------- Box Container -------------------- */
-UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
+UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
UiBoxContainer *ct = cxCalloc(
obj->ctx->allocator,
1,
@@ -117,12 +122,14 @@ UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType
ct->container.widget = box;
ct->container.add = ui_box_container_add;
ct->type = type;
- return (UiContainer*)ct;
+ return (UiContainerX*)ct;
}
-void ui_box_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
UiBoxContainer *bc = (UiBoxContainer*)ct;
- UiBool fill = ct->layout.fill;
+ widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
+
+ UiBool fill = layout->fill;
if(bc->has_fill && fill) {
fprintf(stderr, "UiError: container has 2 filled widgets");
fill = FALSE;
@@ -149,11 +156,10 @@ void ui_box_container_add(UiContainer *ct, GtkWidget *widget) {
gtk_box_pack_start(GTK_BOX(ct->widget), widget, expand, fill, 0);
#endif
- ui_reset_layout(ct->layout);
ct->current = widget;
}
-UiContainer* ui_grid_container(
+UiContainerX* ui_grid_container(
UiObject *obj,
GtkWidget *grid,
UiBool def_hexpand,
@@ -173,140 +179,72 @@ UiContainer* ui_grid_container(
ct->container.add = ui_grid_container_add;
UI_GTK_V2(ct->width = 0);
UI_GTK_V2(ct->height = 1);
- return (UiContainer*)ct;
+ return (UiContainerX*)ct;
}
+
#if GTK_MAJOR_VERSION >= 3
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
UiGridContainer *grid = (UiGridContainer*)ct;
+ widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
- if(ct->layout.newline) {
+ if(ct->container.newline) {
grid->x = 0;
grid->y++;
- ct->layout.newline = FALSE;
+ ct->container.newline = FALSE;
}
- int hexpand = FALSE;
- int vexpand = FALSE;
- int hfill = FALSE;
- int vfill = FALSE;
- if(!ct->layout.override_defaults) {
- if(grid->def_hexpand) {
- hexpand = TRUE;
- hfill = TRUE;
- } else if(grid->def_hfill) {
- hfill = TRUE;
- }
- if(grid->def_vexpand) {
- vexpand = TRUE;
- vfill = TRUE;
- } else if(grid->def_vfill) {
- vfill = TRUE;
- }
- }
-
- UiBool fill = ct->layout.fill;
- if(ct->layout.hexpand) {
- hexpand = TRUE;
- hfill = TRUE;
- } else if(ct->layout.hfill) {
- hfill = TRUE;
- }
- if(ct->layout.vexpand) {
- vexpand = TRUE;
- vfill = TRUE;
- } else if(ct->layout.vfill) {
- vfill = TRUE;
- }
- if(fill) {
- hfill = TRUE;
- vfill = TRUE;
- }
+ uic_layout_setup_expand_fill(layout, grid->def_hexpand, grid->def_vexpand, grid->def_hfill, grid->def_vfill);
- if(!hfill) {
+ if(!layout->hfill) {
gtk_widget_set_halign(widget, GTK_ALIGN_START);
}
- if(!vfill) {
+ if(!layout->vfill) {
gtk_widget_set_valign(widget, GTK_ALIGN_START);
}
- gtk_widget_set_hexpand(widget, hexpand);
- gtk_widget_set_vexpand(widget, vexpand);
+ gtk_widget_set_hexpand(widget, layout->hexpand);
+ gtk_widget_set_vexpand(widget, layout->vexpand);
- int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1;
- int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1;
+ int colspan = layout->colspan > 0 ? layout->colspan : 1;
+ int rowspan = layout->rowspan > 0 ? layout->rowspan : 1;
gtk_grid_attach(GTK_GRID(ct->widget), widget, grid->x, grid->y, colspan, rowspan);
grid->x += colspan;
- ui_reset_layout(ct->layout);
- ct->current = widget;
+ grid->container.current = widget;
}
#endif
#ifdef UI_GTK2
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget) {
UiGridContainer *grid = (UiGridContainer*)ct;
+ widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
- if(ct->layout.newline) {
+ if(ct->container.newline) {
grid->x = 0;
grid->y++;
- ct->layout.newline = FALSE;
+ ct->container.newline = FALSE;
}
- int hexpand = FALSE;
- int vexpand = FALSE;
- int hfill = FALSE;
- int vfill = FALSE;
- if(!ct->layout.override_defaults) {
- if(grid->def_hexpand) {
- hexpand = TRUE;
- hfill = TRUE;
- } else if(grid->def_hfill) {
- hfill = TRUE;
- }
- if(grid->def_vexpand) {
- vexpand = TRUE;
- vfill = TRUE;
- } else if(grid->def_vfill) {
- vfill = TRUE;
- }
- }
-
- UiBool fill = ct->layout.fill;
- if(ct->layout.hexpand) {
- hexpand = TRUE;
- hfill = TRUE;
- } else if(ct->layout.hfill) {
- hfill = TRUE;
- }
- if(ct->layout.vexpand) {
- vexpand = TRUE;
- vfill = TRUE;
- } else if(ct->layout.vfill) {
- vfill = TRUE;
- }
- if(fill) {
- hfill = TRUE;
- vfill = TRUE;
- }
+ uic_layout_setup_expand_fill(layout, grid->def_hexpand, grid->def_vexpand, grid->def_hfill, grid->def_vfill);
GtkAttachOptions xoptions = 0;
GtkAttachOptions yoptions = 0;
- if(hexpand) {
+ if(layout->hexpand) {
xoptions = GTK_EXPAND;
}
- if(hfill) {
+ if(layout->hfill) {
xoptions |= GTK_FILL;
}
- if(vexpand) {
+ if(layout->vexpand) {
yoptions = GTK_EXPAND;
}
- if(vfill) {
+ if(layout->vfill) {
yoptions |= GTK_FILL;
}
- int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1;
- int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1;
+ int colspan = layout->colspan > 0 ? layout->colspan : 1;
+ int rowspan = layout->rowspan > 0 ? layout->rowspan : 1;
// TODO: use colspan/rowspan
gtk_table_attach(GTK_TABLE(ct->widget), widget, grid->x, grid->x+1, grid->y, grid->y+1, xoptions, yoptions, 0, 0);
@@ -318,116 +256,138 @@ void ui_grid_container_add(UiContainer *ct, GtkWidget *widget) {
gtk_table_resize(GTK_TABLE(ct->widget), grid->width, grid->height);
}
- ui_reset_layout(ct->layout);
ct->current = widget;
}
#endif
-UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) {
- UiContainer *ct = cxCalloc(
+UiContainerX* ui_frame_container(UiObject *obj, GtkWidget *frame) {
+ UiContainerPrivate *ct = cxCalloc(
obj->ctx->allocator,
1,
- sizeof(UiContainer));
+ sizeof(UiContainerPrivate));
ct->widget = frame;
ct->add = ui_frame_container_add;
- return ct;
+ return (UiContainerX*)ct;
}
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+ widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
FRAME_SET_CHILD(ct->widget, widget);
+ ct->current = widget;
}
-UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander) {
- UiContainer *ct = cxCalloc(
+UiContainerX* ui_expander_container(UiObject *obj, GtkWidget *expander) {
+ UiContainerPrivate *ct = cxCalloc(
obj->ctx->allocator,
1,
- sizeof(UiContainer));
+ sizeof(UiContainerPrivate));
ct->widget = expander;
ct->add = ui_expander_container_add;
- return ct;
+ return (UiContainerX*)ct;
}
-void ui_expander_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_expander_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+ widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
EXPANDER_SET_CHILD(ct->widget, widget);
+ ct->current = widget;
}
-void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+ widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
// TODO: check if the widget implements GtkScrollable
SCROLLEDWINDOW_SET_CHILD(ct->widget, widget);
- ui_reset_layout(ct->layout);
ct->current = widget;
}
-UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) {
- UiContainer *ct = cxCalloc(
+UiContainerX* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) {
+ UiContainerPrivate *ct = cxCalloc(
obj->ctx->allocator,
1,
- sizeof(UiContainer));
+ sizeof(UiContainerPrivate));
ct->widget = scrolledwindow;
ct->add = ui_scrolledwindow_container_add;
- return ct;
+ return (UiContainerX*)ct;
}
-UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
+UiContainerX* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
UiTabViewContainer *ct = cxCalloc(
obj->ctx->allocator,
1,
sizeof(UiTabViewContainer));
ct->container.widget = tabview;
ct->container.add = ui_tabview_container_add;
- return (UiContainer*)ct;
+ return (UiContainerX*)ct;
}
-void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_tabview_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
UiGtkTabView *data = ui_widget_get_tabview_data(ct->widget);
if(!data) {
fprintf(stderr, "UI Error: widget is not a tabview");
return;
}
- data->add_tab(ct->widget, -1, ct->layout.label, widget);
+ widget = ui_gtk_set_margin(widget, layout->margin, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
+ data->add_tab(ct->widget, -1, layout->label, widget);
- ui_reset_layout(ct->layout);
ct->current = widget;
}
+#ifdef UI_GTK2
+static void alignment_child_visibility_changed(GtkWidget *widget, gpointer user_data) {
+ gtk_widget_set_visible(gtk_widget_get_parent(widget), gtk_widget_get_visible(widget));
+}
-GtkWidget* ui_box_set_margin(GtkWidget *box, int margin) {
- GtkWidget *ret = box;
+#endif
+
+GtkWidget* ui_gtk_set_margin(GtkWidget *widget, int margin, int margin_left, int margin_right, int margin_top, int margin_bottom) {
+ if(margin > 0) {
+ margin_left = margin;
+ margin_right = margin;
+ margin_top = margin;
+ margin_bottom = margin;
+ }
+ GtkWidget *ret = widget;
#if GTK_MAJOR_VERSION >= 3
-#if GTK_MAJOR_VERSION * 1000 + GTK_MINOR_VERSION >= 3012
- gtk_widget_set_margin_start(box, margin);
- gtk_widget_set_margin_end(box, margin);
+#if GTK_CHECK_VERSION(3, 12, 0)
+ gtk_widget_set_margin_start(widget, margin_left);
+ gtk_widget_set_margin_end(widget, margin_right);
#else
- gtk_widget_set_margin_left(box, margin);
- gtk_widget_set_margin_right(box, margin);
+ gtk_widget_set_margin_left(widget, margin_left);
+ gtk_widget_set_margin_right(widget, margin_right);
#endif
- gtk_widget_set_margin_top(box, margin);
- gtk_widget_set_margin_bottom(box, margin);
+ gtk_widget_set_margin_top(widget, margin_top);
+ gtk_widget_set_margin_bottom(widget, margin_bottom);
#elif defined(UI_GTK2)
GtkWidget *a = gtk_alignment_new(0.5, 0.5, 1, 1);
- gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin, margin, margin, margin);
- gtk_container_add(GTK_CONTAINER(a), box);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin_top, margin_bottom, margin_left, margin_right);
+ gtk_container_add(GTK_CONTAINER(a), widget);
+ g_signal_connect(
+ widget,
+ "show",
+ G_CALLBACK(alignment_child_visibility_changed),
+ NULL);
+ g_signal_connect(
+ widget,
+ "hide",
+ G_CALLBACK(alignment_child_visibility_changed),
+ NULL);
ret = a;
#endif
return ret;
}
UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type) {
- UiObject *current = uic_current_obj(obj);
- UiContainer *ct = current->container;
- UI_APPLY_LAYOUT2(current, args);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args->spacing) : ui_gtk_hbox_new(args->spacing);
ui_set_name_and_style(box, args->name, args->style_class);
- GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box;
- ct->add(ct, widget);
+ ct->add(ct, box, &layout);
- UiObject *newobj = uic_object_new(obj, box);
- newobj->container = ui_box_container(obj, box, type);
- uic_obj_add(obj, newobj);
+ UiContainerX *container = ui_box_container(obj, box, type);
+ uic_object_push_container(obj, container);
- return widget;
+ return box;
}
UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) {
@@ -452,82 +412,113 @@ GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing) {
}
UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
- UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT2(current, args);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
GtkWidget *widget;
GtkWidget *grid = ui_create_grid_widget(args->columnspacing, args->rowspacing);
ui_set_name_and_style(grid, args->name, args->style_class);
- widget = ui_box_set_margin(grid, args->margin);
- current->container->add(current->container, widget);
+ ct->add(ct, grid, &layout);
- UiObject *newobj = uic_object_new(obj, grid);
- newobj->container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
- uic_obj_add(obj, newobj);
+ UiContainerX *container = ui_grid_container(obj, grid, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill);
+ uic_object_push_container(obj, container);
- return widget;
+ return grid;
+}
+
+static void frame_create_subcontainer(UiObject *obj, UiFrameArgs *args) {
+ switch(args->subcontainer) {
+ default:
+ case UI_CONTAINER_VBOX: {
+ UiContainerArgs sub_args = { .spacing = args->spacing, .margin = args->padding };
+ ui_vbox_create(obj, &sub_args);
+ break;
+ }
+ case UI_CONTAINER_HBOX: {
+ UiContainerArgs sub_args = { .spacing = args->spacing, .margin = args->padding };
+ ui_hbox_create(obj, &sub_args);
+ break;
+ }
+ case UI_CONTAINER_GRID: {
+ UiContainerArgs sub_args = { .columnspacing = args->columnspacing, .rowspacing = args->rowspacing, .margin = args->padding };
+ ui_grid_create(obj, &sub_args);
+ break;
+ }
+ case UI_CONTAINER_NO_SUB: {
+ break; // NOOP
+ }
+ }
}
UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) {
- UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT2(current, args);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
GtkWidget *frame = gtk_frame_new(args->label);
- UiObject *newobj = uic_object_new(obj, frame);
- GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
+ ct->add(ct, frame, &layout);
+
+ GtkWidget *sub = ui_subcontainer_create(
+ args->subcontainer,
+ obj, args->spacing,
+ args->columnspacing,
+ args->rowspacing,
+ args->padding);
if(sub) {
FRAME_SET_CHILD(frame, sub);
} else {
- newobj->widget = frame;
- newobj->container = ui_frame_container(obj, frame);
+ UiContainerX *container = ui_frame_container(obj, frame);
+ uic_object_push_container(obj, container);
}
- current->container->add(current->container, frame);
- uic_obj_add(obj, newobj);
return frame;
}
UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) {
- UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT2(current, args);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
GtkWidget *expander = gtk_expander_new(args->label);
gtk_expander_set_expanded(GTK_EXPANDER(expander), args->isexpanded);
- UiObject *newobj = uic_object_new(obj, expander);
- GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
+ ct->add(ct, expander, &layout);
+
+ GtkWidget *sub = ui_subcontainer_create(
+ args->subcontainer,
+ obj, args->spacing,
+ args->columnspacing,
+ args->rowspacing,
+ args->padding);
if(sub) {
EXPANDER_SET_CHILD(expander, sub);
} else {
- newobj->widget = expander;
- newobj->container = ui_expander_container(obj, expander);
+ UiContainerX *container = ui_expander_container(obj, expander);
+ uic_object_push_container(obj, container);
}
- current->container->add(current->container, expander);
- uic_obj_add(obj, newobj);
return expander;
}
UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) {
- UiObject* current = uic_current_obj(obj);
- UI_APPLY_LAYOUT2(current, args);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
GtkWidget *sw = SCROLLEDWINDOW_NEW();
ui_set_name_and_style(sw, args->name, args->style_class);
- GtkWidget *widget = ui_box_set_margin(sw, args->margin);
- current->container->add(current->container, widget);
-
- UiObject *newobj = uic_object_new(obj, sw);
- GtkWidget *sub = ui_subcontainer_create(args->subcontainer, newobj, args->spacing, args->columnspacing, args->rowspacing, args->margin);
+ ct->add(ct, sw, &layout);
+
+ GtkWidget *sub = ui_subcontainer_create(
+ args->subcontainer,
+ obj, args->spacing,
+ args->columnspacing,
+ args->rowspacing,
+ args->padding);
if(sub) {
SCROLLEDWINDOW_SET_CHILD(sw, sub);
} else {
- newobj->widget = sw;
- newobj->container = ui_scrolledwindow_container(obj, sw);
+ UiContainerX *container = ui_scrolledwindow_container(obj, sw);
+ uic_object_push_container(obj, container);
}
- uic_obj_add(obj, newobj);
-
return sw;
}
@@ -736,7 +727,7 @@ typedef void (*ui_tabview_set_func)(UiInteger*, int64_t);
UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
UiGtkTabView *data = malloc(sizeof(UiGtkTabView));
memset(data, 0, sizeof(UiGtkTabView));
- data->margin = args->margin;
+ data->padding = args->padding;
data->spacing = args->spacing;
data->columnspacing = args->columnspacing;
data->rowspacing = args->rowspacing;
@@ -796,9 +787,8 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
}
}
- UiObject* current = uic_current_obj(obj);
if(args->value || args->varname) {
- UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
UiInteger *i = var->value;
i->get = getfunc;
i->set = setfunc;
@@ -807,29 +797,56 @@ UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs *args) {
g_object_set_data(G_OBJECT(widget), "ui_tabview", data);
data->widget = data_widget;
- data->subcontainer = args->subcontainer;
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
- UiObject *newobj = uic_object_new(obj, widget);
- newobj->container = ui_tabview_container(obj, widget);
- uic_obj_add(obj, newobj);
- data->obj = newobj;
+ UiContainerX *container = ui_tabview_container(obj, widget);
+ uic_object_push_container(obj, container);
return widget;
}
+static GtkWidget* create_tab(UiObject *obj, UiGtkTabView *tabview, const char *title, int tab) {
+ UiContainerX *container;
+ GtkWidget *sub;
+ switch(tabview->subcontainer) {
+ default: {
+ sub = ui_gtk_vbox_new(tabview->spacing);
+ container = ui_box_container(obj, sub, tabview->subcontainer);
+ break;
+ }
+ case UI_CONTAINER_HBOX: {
+ sub = ui_gtk_hbox_new(tabview->spacing);
+ container = ui_box_container(obj, sub, tabview->subcontainer);
+ break;
+ }
+ case UI_CONTAINER_GRID: {
+ sub = ui_create_grid_widget(tabview->columnspacing, tabview->rowspacing);
+ container = ui_grid_container(obj, sub, FALSE, FALSE, FALSE, FALSE);
+ break;
+ }
+ }
+
+ uic_object_push_container(obj, container);
+
+ GtkWidget *widget = ui_gtk_set_margin(sub, tabview->padding, 0, 0, 0, 0);
+ tabview->add_tab(tabview->widget, tab, title, widget);
+
+ return sub;
+}
+
void ui_tab_create(UiObject* obj, const char* title) {
- UiObject* current = uic_current_obj(obj);
- UiGtkTabView *data = ui_widget_get_tabview_data(current->widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ GtkWidget *tabview = ct->widget;
+ UiGtkTabView *data = ui_widget_get_tabview_data(tabview);
if(!data) {
fprintf(stderr, "UI Error: widget is not a tabview\n");
return;
}
- UiObject *newobj = ui_tabview_add(current->widget, title, -1);
- current->next = newobj;
+ create_tab(obj, data, title, -1);
}
@@ -859,31 +876,8 @@ UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) {
return NULL;
}
- UiObject *newobj = cxCalloc(data->obj->ctx->allocator, 1, sizeof(UiObject));
- newobj->ctx = data->obj->ctx;
-
- GtkWidget *sub;
- switch(data->subcontainer) {
- default: {
- sub = ui_gtk_vbox_new(data->spacing);
- newobj->container = ui_box_container(newobj, sub, data->subcontainer);
- break;
- }
- case UI_CONTAINER_HBOX: {
- sub = ui_gtk_hbox_new(data->spacing);
- newobj->container = ui_box_container(newobj, sub, data->subcontainer);
- break;
- }
- case UI_CONTAINER_GRID: {
- sub = ui_create_grid_widget(data->columnspacing, data->rowspacing);
- newobj->container = ui_grid_container(newobj, sub, FALSE, FALSE, FALSE, FALSE);
- break;
- }
- }
- newobj->widget = sub;
- GtkWidget *widget = ui_box_set_margin(sub, data->margin);
-
- data->add_tab(data->widget, tab_index, name, widget);
+ UiObject *newobj = uic_object_new_toplevel();
+ newobj->widget = create_tab(newobj, data, name, tab_index);
return newobj;
}
@@ -892,20 +886,16 @@ UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) {
/* -------------------- Headerbar -------------------- */
static void hb_set_part(UiObject *obj, int part) {
- UiObject* current = uic_current_obj(obj);
- GtkWidget *headerbar = current->widget;
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ GtkWidget *headerbar = ct->widget;
UiHeaderbarContainer *hb = cxCalloc(
obj->ctx->allocator,
1,
sizeof(UiHeaderbarContainer));
- memcpy(hb, current->container, sizeof(UiHeaderbarContainer));
-
- UiObject *newobj = uic_object_new(obj, headerbar);
- newobj->container = (UiContainer*)hb;
- uic_obj_add(obj, newobj);
-
+ memcpy(hb, ct, sizeof(UiHeaderbarContainer));
hb->part = part;
+ uic_object_push_container(obj, (UiContainerX*)hb);
}
void ui_headerbar_start_create(UiObject *obj) {
@@ -921,74 +911,70 @@ void ui_headerbar_end_create(UiObject *obj) {
}
UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs *args) {
- UiObject *current = uic_current_obj(obj);
- UiContainer *ct = current->container;
- UI_APPLY_LAYOUT2(current, args);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
GtkWidget *box = ui_gtk_hbox_new(args->alt_spacing);
ui_set_name_and_style(box, args->name, args->style_class);
- ct->add(ct, box);
+ ct->add(ct, box, &layout);
- UiObject *newobj = uic_object_new(obj, box);
- newobj->container = ui_headerbar_fallback_container(obj, box);
- uic_obj_add(obj, newobj);
+ UiContainerX *container = ui_headerbar_fallback_container(obj, box);
+ uic_object_push_container(obj, container);
return box;
}
static void hb_fallback_set_part(UiObject *obj, int part) {
- UiObject* current = uic_current_obj(obj);
- GtkWidget *headerbar = current->widget;
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ GtkWidget *headerbar = ct->widget;
- UiObject *newobj = uic_object_new(obj, headerbar);
- newobj->container = ui_headerbar_container(obj, headerbar);
- uic_obj_add(obj, newobj);
+ UiContainerX *container = ui_headerbar_container(obj, headerbar);
+ uic_object_push_container(obj, container);
- UiHeaderbarContainer *hb = (UiHeaderbarContainer*)newobj->container;
+ UiHeaderbarContainer *hb = (UiHeaderbarContainer*)container;
hb->part = part;
}
-UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) {
+UiContainerX* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) {
UiHeaderbarContainer *ct = cxCalloc(
obj->ctx->allocator,
1,
sizeof(UiHeaderbarContainer));
ct->container.widget = headerbar;
ct->container.add = ui_headerbar_fallback_container_add;
- return (UiContainer*)ct;
+ return (UiContainerX*)ct;
}
-void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_headerbar_fallback_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
BOX_ADD(ct->widget, widget);
}
#if GTK_CHECK_VERSION(3, 10, 0)
-UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
+UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs *args) {
GtkWidget *headerbar = g_object_get_data(G_OBJECT(obj->widget), "ui_headerbar");
if(!headerbar) {
return ui_headerbar_fallback_create(obj, args);
}
- UiObject *newobj = uic_object_new(obj, headerbar);
- newobj->container = ui_headerbar_container(obj, headerbar);
- uic_obj_add(obj, newobj);
+ UiContainerX *container = ui_headerbar_container(obj, headerbar);
+ uic_object_push_container(obj, container);
return headerbar;
}
-UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) {
+UiContainerX* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) {
UiHeaderbarContainer *ct = cxCalloc(
obj->ctx->allocator,
1,
sizeof(UiHeaderbarContainer));
ct->container.widget = headerbar;
ct->container.add = ui_headerbar_container_add;
- return (UiContainer*)ct;
+ return (UiContainerX*)ct;
}
-void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget) {
+void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
if(hb->part == 0) {
UI_HEADERBAR_PACK_START(ct->widget, widget);
@@ -1023,12 +1009,11 @@ UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
}
GtkWidget *box = ui_gtk_vbox_new(args->spacing);
- ui_box_set_margin(box, args->margin);
+ ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom);
adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box);
- UiObject *newobj = uic_object_new(obj, box);
- newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
- uic_obj_add(obj, newobj);
+ UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+ uic_object_push_container(obj, container);
return box;
}
@@ -1037,17 +1022,44 @@ UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) {
GtkWidget *sidebar_vbox = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar");
GtkWidget *box = ui_gtk_vbox_new(args->spacing);
- ui_box_set_margin(box, args->margin);
+ ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom);
BOX_ADD_EXPAND(sidebar_vbox, box);
- UiObject *newobj = uic_object_new(obj, box);
- newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
- uic_obj_add(obj, newobj);
+ UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+ uic_object_push_container(obj, container);
return box;
}
#endif
+/* ------------------------ Split Window Panels ------------------------ */
+
+static UIWIDGET splitwindow_panel(UiObject *obj, GtkWidget *pbox, UiSidebarArgs *args) {
+ if(!pbox) {
+ fprintf(stderr, "Error: window is not a splitview window\n");
+ return NULL;
+ }
+
+ GtkWidget *box = ui_gtk_vbox_new(args->spacing);
+ ui_set_name_and_style(box, args->name, args->style_class);
+ ui_gtk_set_margin(box, args->margin, args->margin_left, args->margin_right, args->margin_top, args->margin_bottom);
+ BOX_ADD_EXPAND(pbox, box);
+
+ UiContainerX *container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
+ uic_object_push_container(obj, container);
+
+ return box;
+}
+
+UIWIDGET ui_left_panel_create(UiObject *obj, UiSidebarArgs *args) {
+ return splitwindow_panel(obj, g_object_get_data(G_OBJECT(obj->widget), "ui_left_panel"), args);
+}
+
+UIWIDGET ui_right_panel_create(UiObject *obj, UiSidebarArgs *args) {
+ return splitwindow_panel(obj, g_object_get_data(G_OBJECT(obj->widget), "ui_right_panel"), args);
+}
+
+
/* -------------------- Splitpane -------------------- */
static GtkWidget* create_paned(UiOrientation orientation) {
@@ -1065,23 +1077,55 @@ static GtkWidget* create_paned(UiOrientation orientation) {
return NULL;
}
-
+static void save_pane_pos(GtkWidget *widget, char *property_name) {
+ int pos = gtk_paned_get_position(GTK_PANED(widget));
+ char buf[32];
+ snprintf(buf, 32, "%d", pos);
+ ui_set_property(property_name, buf);
+ free(property_name);
+}
static UIWIDGET splitpane_create(UiObject *obj, UiOrientation orientation, UiSplitPaneArgs *args) {
- UiObject* current = uic_current_obj(obj);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
GtkWidget *pane0 = create_paned(orientation);
-
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, pane0);
+ ct->add(ct, pane0, &layout);
int max = args->max_panes == 0 ? 2 : args->max_panes;
- UiObject *newobj = uic_object_new(obj, pane0);
- newobj->container = ui_splitpane_container(obj, pane0, orientation, max, args->initial_position);
- uic_obj_add(obj, newobj);
+ if(args->position_property) {
+ const char *pos_str = ui_get_property(args->position_property);
+ if(pos_str) {
+ char *end;
+ long pos = strtol(pos_str, &end, 10);
+ if(*end == '\0') {
+ args->initial_position = (int)pos;
+ }
+ }
+
+ g_signal_connect(
+ pane0,
+ "destroy",
+ G_CALLBACK(save_pane_pos),
+ strdup(args->position_property));
+ }
+
+ UiSplitPane *splitpane = ui_create_splitpane_data(pane0, orientation, max, args->initial_position);
+ UiContainerX *container = ui_splitpane_container(obj, pane0, splitpane);
+ uic_object_push_container(obj, container);
- g_object_set_data(G_OBJECT(pane0), "ui_splitpane", newobj->container);
+ g_object_set_data(G_OBJECT(pane0), "ui_splitpane", splitpane);
+
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
+ if(var) {
+ UiInteger *i = var->value;
+ splitpane->initial_position = i->value;
+
+ i->obj = splitpane;
+ i->get = ui_splitpane_get;
+ i->set = ui_splitpane_set;
+ }
return pane0;
}
@@ -1094,20 +1138,27 @@ UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
return splitpane_create(obj, UI_VERTICAL, args);
}
-UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init) {
- UiSplitPaneContainer *ct = ui_calloc(obj->ctx, 1, sizeof(UiSplitPaneContainer));
- ct->container.widget = pane;
- ct->container.add = ui_splitpane_container_add;
+UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation, int max, int init) {
+ UiSplitPane *ct = malloc(sizeof(UiSplitPane));
ct->current_pane = pane;
ct->orientation = orientation;
ct->max = max;
ct->initial_position = init;
ct->children = cxArrayListCreateSimple(CX_STORE_POINTERS, 4);
- return (UiContainer*)ct;
+ return ct;
+}
+
+UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data) {
+ UiSplitPaneContainer *ct = ui_calloc(obj->ctx, 1, sizeof(UiSplitPaneContainer));
+ ct->container.widget = pane;
+ ct->container.add = ui_splitpane_container_add;
+ ct->splitpane = data;
+ return (UiContainerX*)ct;
}
-void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget) {
- UiSplitPaneContainer *s = (UiSplitPaneContainer*)ct;
+void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout) {
+ UiSplitPaneContainer *sct = (UiSplitPaneContainer*)ct;
+ UiSplitPane *s = sct->splitpane;
if(s->nchildren >= s->max) {
fprintf(stderr, "splitpane: maximum number of children reached\n");
@@ -1138,14 +1189,26 @@ void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget) {
}
}
+int64_t ui_splitpane_get(UiInteger *i) {
+ UiSplitPane *s = i->obj;
+ i->value = gtk_paned_get_position(GTK_PANED(s->current_pane));
+ return i->value;
+}
+
+void ui_splitpane_set(UiInteger *i, int64_t value) {
+ UiSplitPane *s = i->obj;
+ i->value = value;
+ gtk_paned_set_position(GTK_PANED(s->current_pane), (int)value);
+}
+
UIEXPORT void ui_splitpane_set_visible(UIWIDGET splitpane, int child_index, UiBool visible) {
- UiSplitPaneContainer *ct = g_object_get_data(G_OBJECT(splitpane), "ui_splitpane");
- if(!ct) {
+ UiSplitPane *s = g_object_get_data(G_OBJECT(splitpane), "ui_splitpane");
+ if(!s) {
fprintf(stderr, "UI Error: not a splitpane\n");
return;
}
- GtkWidget *w = cxListAt(ct->children, child_index);
+ GtkWidget *w = cxListAt(s->children, child_index);
if(w) {
gtk_widget_set_visible(w, visible);
}
@@ -1199,13 +1262,12 @@ static void update_itemlist(UiList *list, int c) {
UiObject *item_obj = cxMapGet(ct->current_items, key);
if(item_obj) {
// re-add previously created widget
- ui_box_container_add(ct->container, item_obj->widget);
+ UiLayout layout = {0};
+ ui_box_container_add(ct->container, item_obj->widget, &layout);
} else {
// create new widget and object for this list element
- CxMempool *mp = cxMempoolCreateSimple(256);
- const CxAllocator *a = mp->allocator;
- UiObject *obj = cxCalloc(a, 1, sizeof(UiObject));
- obj->ctx = uic_context(obj, mp);
+ UiObject *obj = uic_object_new_toplevel();
+ obj->ctx->parent = ct->parent->ctx;
obj->window = NULL;
obj->widget = ui_subcontainer_create(
ct->subcontainer,
@@ -1214,7 +1276,8 @@ static void update_itemlist(UiList *list, int c) {
ct->columnspacing,
ct->rowspacing,
ct->margin);
- ui_box_container_add(ct->container, obj->widget);
+ UiLayout layout = {0};
+ ui_box_container_add(ct->container, obj->widget, &layout);
if(ct->create_ui) {
ct->create_ui(obj, index, elm, ct->userdata);
}
@@ -1236,19 +1299,17 @@ static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *con
}
UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args) {
- UiObject *current = uic_current_obj(obj);
- UiContainer *ct = current->container;
- UI_APPLY_LAYOUT2(current, args);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
GtkWidget *box = args->container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args->spacing) : ui_gtk_hbox_new(args->spacing);
ui_set_name_and_style(box, args->name, args->style_class);
- GtkWidget *widget = args->margin > 0 ? ui_box_set_margin(box, args->margin) : box;
- ct->add(ct, widget);
+ ct->add(ct, box, &layout);
UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer));
container->parent = obj;
container->widget = box;
- container->container = ui_box_container(current, box, args->container);
+ container->container = (UiContainerPrivate*)ui_box_container(obj, box, args->container);
container->create_ui = args->create_ui;
container->userdata = args->userdata;
container->subcontainer = args->subcontainer;
@@ -1261,7 +1322,7 @@ UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args) {
container->rowspacing = args->sub_rowspacing;
container->remove_items = TRUE;
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_LIST);
if(var) {
UiList *list = var->value;
list->obj = container;
@@ -1278,56 +1339,3 @@ UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args) {
}
-
-/*
- * -------------------- Layout Functions --------------------
- *
- * functions for setting layout attributes for the current container
- *
- */
-
-void ui_layout_fill(UiObject *obj, UiBool fill) {
- UiContainer *ct = uic_get_current_container(obj);
- ct->layout.fill = fill;
-}
-
-void ui_layout_hexpand(UiObject *obj, UiBool expand) {
- UiContainer *ct = uic_get_current_container(obj);
- ct->layout.hexpand = expand;
-}
-
-void ui_layout_vexpand(UiObject *obj, UiBool expand) {
- UiContainer *ct = uic_get_current_container(obj);
- ct->layout.vexpand = expand;
-}
-
-void ui_layout_hfill(UiObject *obj, UiBool fill) {
- UiContainer *ct = uic_get_current_container(obj);
- ct->layout.hfill = fill;
-}
-
-void ui_layout_vfill(UiObject *obj, UiBool fill) {
- UiContainer *ct = uic_get_current_container(obj);
- ct->layout.vfill = fill;
-}
-
-UIEXPORT void ui_layout_override_defaults(UiObject *obj, UiBool d) {
- UiContainer *ct = uic_get_current_container(obj);
- ct->layout.override_defaults = d;
-}
-
-void ui_layout_colspan(UiObject* obj, int cols) {
- UiContainer* ct = uic_get_current_container(obj);
- ct->layout.colspan = cols;
-}
-
-void ui_layout_rowspan(UiObject* obj, int rows) {
- UiContainer* ct = uic_get_current_container(obj);
- ct->layout.rowspan = rows;
-}
-
-void ui_newline(UiObject *obj) {
- UiContainer *ct = uic_get_current_container(obj);
- ct->layout.newline = TRUE;
-}
-
diff --git a/ui/gtk/container.h b/ui/gtk/container.h
index 5f44766..2f2510c 100644
--- a/ui/gtk/container.h
+++ b/ui/gtk/container.h
@@ -45,45 +45,30 @@ extern "C" {
#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout))
-typedef void (*ui_container_add_f)(UiContainer*, GtkWidget*);
typedef struct UiDocumentView UiDocumentView;
-
-typedef struct UiLayout UiLayout;
-struct UiLayout {
- UiBool fill;
- UiBool newline;
- char *label;
- UiBool hexpand;
- UiBool vexpand;
- UiBool hfill;
- UiBool vfill;
- UiBool override_defaults;
- int width;
- int colspan;
- int rowspan;
-};
-
-struct UiContainer {
+typedef struct UiContainerPrivate UiContainerPrivate;
+struct UiContainerPrivate {
+ UiContainerX container;
GtkWidget *widget;
UIMENU menu;
- GtkWidget *current;
+ GtkWidget *current; // TODO: remove
- void (*add)(UiContainer*, GtkWidget*);
+ void (*add)(UiContainerPrivate*, GtkWidget*, UiLayout *layout);
UiLayout layout;
int close;
};
typedef struct UiBoxContainer {
- UiContainer container;
+ UiContainerPrivate container;
UiSubContainerType type;
UiBool has_fill;
} UiBoxContainer;
typedef struct UiGridContainer {
- UiContainer container;
+ UiContainerPrivate container;
UiBool def_hexpand;
UiBool def_vexpand;
UiBool def_hfill;
@@ -97,7 +82,7 @@ typedef struct UiGridContainer {
} UiGridContainer;
typedef struct UiTabViewContainer {
- UiContainer container;
+ UiContainerPrivate container;
} UiTabViewContainer;
typedef void (*ui_select_tab_func)(UIWIDGET widget, int tab);
@@ -110,7 +95,7 @@ typedef struct UiGtkTabView {
ui_select_tab_func remove_tab;
ui_add_tab_func add_tab;
UiSubContainerType subcontainer;
- int margin;
+ int padding;
int spacing;
int columnspacing;
int rowspacing;
@@ -118,9 +103,7 @@ typedef struct UiGtkTabView {
void *onchangedata;
} UiGtkTabView;
-
-typedef struct UiSplitPaneContainer {
- UiContainer container;
+typedef struct UiSplitPane {
GtkWidget *current_pane;
CxList *children;
UiOrientation orientation;
@@ -128,10 +111,15 @@ typedef struct UiSplitPaneContainer {
int max;
int nchildren;
int initial_position;
+} UiSplitPane;
+
+typedef struct UiSplitPaneContainer {
+ UiContainerPrivate container;
+ UiSplitPane *splitpane;
} UiSplitPaneContainer;
typedef struct UiHeaderbarContainer {
- UiContainer container;
+ UiContainerPrivate container;
GtkWidget *centerbox;
int part;
UiHeaderbarAlternative alternative; /* only used by fallback headerbar */
@@ -140,7 +128,7 @@ typedef struct UiHeaderbarContainer {
typedef struct UiGtkItemListContainer {
UiObject *parent;
GtkWidget *widget;
- UiContainer *container;
+ UiContainerPrivate *container;
void (*create_ui)(UiObject *, int, void *, void *);
void *userdata;
UiSubContainerType subcontainer;
@@ -163,52 +151,52 @@ GtkWidget* ui_subcontainer_create(
int rowspacing,
int margin);
-UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget);
-
-GtkWidget* ui_box_set_margin(GtkWidget *box, int margin);
+GtkWidget* ui_gtk_set_margin(GtkWidget *widget, int margin, int margin_left, int margin_right, int margin_top, int margin_bottom);
UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, UiSubContainerType type);
-UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type);
-void ui_box_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type);
+void ui_box_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing);
-UiContainer* ui_grid_container(
+UiContainerX* ui_grid_container(
UiObject *obj,
GtkWidget *grid,
UiBool def_hexpand,
UiBool def_vexpand,
UiBool def_hfill,
UiBool def_vfill);
-void ui_grid_container_add(UiContainer *ct, GtkWidget *widget);
+void ui_grid_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
-UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame);
-void ui_frame_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_frame_container(UiObject *obj, GtkWidget *frame);
+void ui_frame_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
-UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander);
-void ui_expander_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_expander_container(UiObject *obj, GtkWidget *expander);
+void ui_expander_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
-UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow);
-void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow);
+void ui_scrolledwindow_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
-UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
-void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
+void ui_tabview_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
-UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init);
-void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget);
+UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation, int max, int init);
+UiContainerX* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiSplitPane *data);
+void ui_splitpane_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
+int64_t ui_splitpane_get(UiInteger *i);
+void ui_splitpane_set(UiInteger *i, int64_t value);
UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview);
void ui_gtk_notebook_select_tab(GtkWidget *widget, int tab);
#if GTK_CHECK_VERSION(3, 10, 0)
-UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar);
-void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar);
+void ui_headerbar_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
#endif
-UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar);
-void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget);
+UiContainerX* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar);
+void ui_headerbar_fallback_container_add(UiContainerPrivate *ct, GtkWidget *widget, UiLayout *layout);
#ifdef __cplusplus
}
diff --git a/ui/gtk/display.c b/ui/gtk/display.c
index 40fcde1..1f8c39e 100644
--- a/ui/gtk/display.c
+++ b/ui/gtk/display.c
@@ -47,8 +47,6 @@ static void set_alignment(GtkWidget *widget, float xalign, float yalign) {
}
UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
const char *css_class = NULL;
char *markup = NULL;
if(args->label) {
@@ -101,11 +99,11 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs *args) {
case UI_ALIGN_DEFAULT: break;
case UI_ALIGN_LEFT: set_alignment(widget, 0, .5); break;
case UI_ALIGN_RIGHT: set_alignment(widget, 1, .5); break;
- case UI_ALIGN_CENTER: break; // TODO
+ case UI_ALIGN_CENTER: set_alignment(widget, .5, .5); break;
}
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if(var) {
UiString* value = (UiString*)var->value;
value->obj = widget;
@@ -113,8 +111,9 @@ UIWIDGET ui_label_create(UiObject *obj, UiLabelArgs *args) {
value->set = ui_label_set;
}
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
return widget;
}
@@ -147,10 +146,12 @@ void ui_label_set(UiString *s, const char *value) {
}
}
+/*
UIWIDGET ui_space_deprecated(UiObject *obj) {
GtkWidget *widget = gtk_label_new("");
- UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
return widget;
}
@@ -161,12 +162,14 @@ UIWIDGET ui_separator_deprecated(UiObject *obj) {
#else
GtkWidget *widget = gtk_hseparator_new();
#endif
- UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
return widget;
}
-
+*/
+
/* ------------------------- progress bar ------------------------- */
typedef struct UiProgressBarRange {
@@ -175,8 +178,6 @@ typedef struct UiProgressBarRange {
} UiProgressBarRange;
UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
GtkWidget *progressbar = gtk_progress_bar_new();
if(args->max > args->min) {
UiProgressBarRange *range = malloc(sizeof(UiProgressBarRange));
@@ -191,7 +192,7 @@ UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) {
}
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_DOUBLE);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_DOUBLE);
if(var && var->value) {
UiDouble *value = var->value;
value->get = ui_progressbar_get;
@@ -200,8 +201,9 @@ UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs *args) {
ui_progressbar_set(value, value->value);
}
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, progressbar);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, progressbar, &layout);
return progressbar;
}
@@ -229,11 +231,9 @@ void ui_progressbar_set(UiDouble *d, double value) {
/* ------------------------- progress spinner ------------------------- */
UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
GtkWidget *spinner = gtk_spinner_new();
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_INTEGER);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var && var->value) {
UiInteger *value = var->value;
value->get = ui_spinner_get;
@@ -242,8 +242,9 @@ UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs *args
ui_spinner_set(value, value->value);
}
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, spinner);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, spinner, &layout);
return spinner;
}
diff --git a/ui/gtk/draw_cairo.c b/ui/gtk/draw_cairo.c
index fc85c32..c067bc0 100644
--- a/ui/gtk/draw_cairo.c
+++ b/ui/gtk/draw_cairo.c
@@ -35,29 +35,29 @@
#if GTK_MAJOR_VERSION >= 3
-static void ui_drawingarea_draw(
- GtkDrawingArea *area,
- cairo_t *cr,
- int width,
- int height,
- gpointer data)
-{
+void ui_drawingarea_draw(UiDrawingArea *drawingarea, cairo_t *cr, int width, int height) {
UiCairoGraphics g;
g.g.width = width;
g.g.height = height;
- g.widget = GTK_WIDGET(area);
+ g.widget = drawingarea->widget;;
g.cr = cr;
- UiDrawEvent *event = data;
- UiEvent ev;
- ev.obj = event->obj;
- ev.window = event->obj->window;
- ev.document = event->obj->ctx->document;
+ UiEvent event;
+ event.obj = drawingarea->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = NULL;
+ event.eventdatatype = 0;
+ event.intval = 0;
+ event.set = 0;
- event->callback(&ev, &g.g, event->userdata);
+ if(drawingarea->draw) {
+ drawingarea->draw(&event, &g.g, drawingarea->drawdata);
+ }
}
#endif
+/*
#if UI_GTK3
gboolean ui_drawingarea_expose(GtkWidget *w, cairo_t *cr, void *data) {
int width = gtk_widget_get_allocated_width(w);
@@ -85,9 +85,11 @@ gboolean ui_canvas_expose(GtkWidget *w, GdkEventExpose *e, void *data) {
return FALSE;
}
#endif
+*/
// function from graphics.h
+/*
void ui_connect_draw_handler(GtkWidget *widget, UiDrawEvent *event) {
#if GTK_MAJOR_VERSION >= 4
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(widget), ui_drawingarea_draw, event, NULL);
@@ -103,7 +105,7 @@ void ui_connect_draw_handler(GtkWidget *widget, UiDrawEvent *event) {
event);
#endif
}
-
+*/
PangoContext *ui_get_pango_context(UiGraphics *g) {
UiCairoGraphics *gr = (UiCairoGraphics*)g;
@@ -130,7 +132,7 @@ void ui_draw_line(UiGraphics *g, int x1, int y1, int x2, int y2) {
cairo_stroke(gr->cr);
}
-void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, int fill) {
+void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, UiBool fill) {
UiCairoGraphics *gr = (UiCairoGraphics*)g;
cairo_set_line_width(gr->cr, 1);
cairo_rectangle(gr->cr, x + 0.5, y + 0.5 , w, h);
diff --git a/ui/gtk/draw_cairo.h b/ui/gtk/draw_cairo.h
index 6be96a7..a1ae8d7 100644
--- a/ui/gtk/draw_cairo.h
+++ b/ui/gtk/draw_cairo.h
@@ -41,7 +41,7 @@ typedef struct UiCairoGraphics {
cairo_t *cr;
} UiCairoGraphics;
-// ui_canvas_expose
+void ui_drawingarea_draw(UiDrawingArea *drawingarea, cairo_t *cr, int width, int height);
#ifdef __cplusplus
}
diff --git a/ui/gtk/entry.c b/ui/gtk/entry.c
index 3c83f11..b411191 100644
--- a/ui/gtk/entry.c
+++ b/ui/gtk/entry.c
@@ -35,28 +35,36 @@
#include "entry.h"
-UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args) {
- double min = 0;
- double max = 1000;
-
- UiObject* current = uic_current_obj(obj);
+UIWIDGET ui_spinbox_create(UiObject *obj, UiSpinBoxArgs *args) {
+ double min = args->min;
+ double max = args->max != 0 ? args->max : 1000;
UiVar *var = NULL;
+ UiVarType vartype = 0;
if(args->varname) {
var = uic_get_var(obj->ctx, args->varname);
+ if(var) {
+ vartype = var->type;
+ } else {
+ var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, args->varname, UI_VAR_RANGE);
+ vartype = UI_VAR_RANGE;
+ }
}
if(!var) {
if(args->intvalue) {
- var = uic_widget_var(obj->ctx, current->ctx, args->intvalue, NULL, UI_VAR_INTEGER);
+ var = uic_widget_var(obj->ctx, obj->ctx, args->intvalue, NULL, UI_VAR_INTEGER);
+ vartype = UI_VAR_INTEGER;
} else if(args->doublevalue) {
- var = uic_widget_var(obj->ctx, current->ctx, args->doublevalue, NULL, UI_VAR_DOUBLE);
+ var = uic_widget_var(obj->ctx, obj->ctx, args->doublevalue, NULL, UI_VAR_DOUBLE);
+ vartype = UI_VAR_DOUBLE;
} else if(args->rangevalue) {
- var = uic_widget_var(obj->ctx, current->ctx, args->rangevalue, NULL, UI_VAR_RANGE);
+ var = uic_widget_var(obj->ctx, obj->ctx, args->rangevalue, NULL, UI_VAR_RANGE);
+ vartype = UI_VAR_RANGE;
}
}
- if(var && var->type == UI_VAR_RANGE) {
+ if(vartype == UI_VAR_RANGE) {
UiRange *r = var->value;
min = r->min;
max = r->max;
@@ -72,11 +80,16 @@ UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args) {
GtkWidget *spin = gtk_spin_button_new_with_range(min, max, args->step);
ui_set_name_and_style(spin, args->name, args->style_class);
ui_set_widget_groups(obj->ctx, spin, args->groups);
+
+ if(args->width > 0) {
+ gtk_widget_set_size_request(spin, args->width, -1);
+ }
+
gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), args->digits);
UiObserver **obs = NULL;
if(var) {
double value = 0;
- switch(var->type) {
+ switch(vartype) {
default: break;
case UI_VAR_INTEGER: {
UiInteger *i = var->value;
@@ -129,8 +142,9 @@ UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args) {
G_CALLBACK(ui_destroy_vardata),
event);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, spin);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, spin, &layout);
return spin;
}
diff --git a/ui/gtk/graphics.c b/ui/gtk/graphics.c
index 6883575..33fd186 100644
--- a/ui/gtk/graphics.c
+++ b/ui/gtk/graphics.c
@@ -33,19 +33,88 @@
#include "container.h"
#include "../common/object.h"
-UIWIDGET ui_drawingarea(UiObject *obj, ui_drawfunc f, void *userdata) {
+#if GTK_CHECK_VERSION(3, 0, 0)
+#include "draw_cairo.h"
+#endif
+
+static void destroy_drawingarea(GtkWidget *widget, UiDrawingArea *drawingarea) {
+ free(drawingarea);
+}
+
+static void drawingarea_draw(UiDrawingArea *drawingarea, cairo_t *cr, int width, int height) {
+ UiEvent event;
+ event.obj = drawingarea->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = NULL;
+ event.eventdatatype = 0;
+ event.intval = 0;
+ event.set = 0;
+
+
+}
+
+#if GTK_CHECK_VERSION(4, 0, 0)
+static void drawfunc(
+ GtkDrawingArea *area,
+ cairo_t *cr,
+ int width,
+ int height,
+ gpointer userdata)
+{
+ ui_drawingarea_draw(userdata, cr, width, height);
+}
+#elif GTK_CHECK_VERSION(3, 0, 0)
+gboolean draw_callback(GtkWidget *widget, cairo_t *cr, UiDrawingArea *drawingarea) {
+ int width = gtk_widget_get_allocated_width(widget);
+ int height = gtk_widget_get_allocated_height(widget);
+ ui_drawingarea_draw(drawingarea, cr, width, height);
+ return FALSE;
+}
+#endif
+
+UIWIDGET ui_drawingarea_create(UiObject *obj, UiDrawingAreaArgs *args) {
GtkWidget *widget = gtk_drawing_area_new();
+ ui_set_name_and_style(widget, args->name, args->style_class);
- if(f) {
- UiDrawEvent *event = malloc(sizeof(UiDrawEvent));
- event->obj = obj;
- event->callback = f;
- event->userdata = userdata;
- ui_connect_draw_handler(widget, event);
- }
+#if GTK_CHECK_VERSION(4, 0, 0)
+ gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(widget), args->width > 0 ? args->width : 100);
+ gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(widget), args->height > 0 ? args->height : 100);
+#else
+ int w = args->width > 0 ? args->width : 100;
+ int h = args->height > 0 ? args->height : 100;
+ gtk_widget_set_size_request(widget, w, h);
+#endif
+
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
+
+ UiDrawingArea *drawingarea = malloc(sizeof(UiDrawingArea));
+ drawingarea->obj = obj;
+ drawingarea->widget = widget;
+ drawingarea->draw = args->draw;
+ drawingarea->drawdata = args->drawdata;
+ drawingarea->onclick = args->onclick;
+ drawingarea->onclickdata = args->onclickdata;
+ drawingarea->onmotion = args->onmotion;
+ drawingarea->onmotiondata = args->onmotiondata;
+
+#if GTK_CHECK_VERSION(4, 0, 0)
+ gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(widget), drawfunc, drawingarea, NULL);
+#elif GTK_CHECK_VERSION(3, 0, 0)
+ g_signal_connect(
+ widget,
+ "draw",
+ G_CALLBACK(draw_callback),
+ NULL);
+#endif
- UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, widget);
+ g_signal_connect(
+ widget,
+ "destroy",
+ G_CALLBACK(destroy_drawingarea),
+ drawingarea);
return widget;
}
@@ -142,7 +211,7 @@ void ui_text_setstringl(UiTextLayout *layout, char *str, int len) {
pango_layout_set_text(layout->layout, str, len);
}
-void ui_text_setfont(UiTextLayout *layout, char *font, int size) {
+void ui_text_setfont(UiTextLayout *layout, const char *font, int size) {
PangoFontDescription *fontDesc;
fontDesc = pango_font_description_from_string(font);
pango_font_description_set_size(fontDesc, size * PANGO_SCALE);
diff --git a/ui/gtk/graphics.h b/ui/gtk/graphics.h
index 67616bd..fb89539 100644
--- a/ui/gtk/graphics.h
+++ b/ui/gtk/graphics.h
@@ -36,18 +36,24 @@
extern "C" {
#endif
-typedef struct UiDrawEvent {
- ui_drawfunc callback;
- UiObject *obj;
- void *userdata;
-} UiDrawEvent;
+
+typedef struct UiDrawingArea {
+ UiObject *obj;
+ GtkWidget *widget;
+ ui_drawfunc draw;
+ void *drawdata;
+ ui_callback onclick;
+ void *onclickdata;
+ ui_callback onmotion;
+ void *onmotiondata;
+} UiDrawingArea;
struct UiTextLayout {
PangoLayout *layout;
};
// implemented in draw_*.h
-void ui_connect_draw_handler(GtkWidget *widget, UiDrawEvent *event);
+//void ui_connect_draw_handler(GtkWidget *widget, UiDrawEvent *event);
PangoContext *ui_get_pango_context(UiGraphics *g);
#ifdef __cplusplus
diff --git a/ui/gtk/headerbar.c b/ui/gtk/headerbar.c
index e1b80b5..0a9bd3e 100644
--- a/ui/gtk/headerbar.c
+++ b/ui/gtk/headerbar.c
@@ -31,21 +31,70 @@
#include "button.h"
#include "menu.h"
+#include "../ui/properties.h"
+
#if GTK_CHECK_VERSION(3, 10, 0)
-void ui_fill_headerbar(UiObject *obj, GtkWidget *headerbar) {
+void ui_fill_headerbar(UiObject *obj, GtkWidget *sidebar_headerbar, GtkWidget *main_headerbar, GtkWidget *right_headerbar) {
+ CxList *sidebar_left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_SIDEBAR_LEFT);
+ CxList *sidebar_right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_SIDEBAR_RIGHT);
+
CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT);
CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER);
CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT);
- ui_headerbar_add_items(obj, headerbar, left_defaults, UI_TOOLBAR_LEFT);
- ui_headerbar_add_items(obj, headerbar, center_defaults, UI_TOOLBAR_CENTER);
-
+ CxList *rightpanel_left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_LEFT);
+ CxList *rightpanel_center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_CENTER);
+ CxList *rightpanel_right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHTPANEL_RIGHT);
+
UiToolbarMenuItem *appmenu = uic_get_appmenu();
- if(appmenu) {
- ui_add_headerbar_menu(headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT);
+ const char *appmenu_pos_str = ui_get_property("ui.gtk.window.appmenu.position");
+ int appmenu_pos = UI_TOOLBAR_RIGHT;
+ if(sidebar_headerbar) {
+ appmenu_pos = UI_TOOLBAR_SIDEBAR_RIGHT;
+ } else if(right_headerbar) {
+ appmenu_pos = UI_TOOLBAR_RIGHTPANEL_RIGHT;
+ }
+ if(appmenu_pos_str) {
+ if(!strcmp(appmenu_pos_str, "sidebar") && sidebar_headerbar) {
+ appmenu_pos = UI_TOOLBAR_SIDEBAR_RIGHT;
+ } else if(!strcmp(appmenu_pos_str, "main")) {
+ appmenu_pos = UI_TOOLBAR_RIGHT;
+ } else if(!strcmp(appmenu_pos_str, "rightpanel") && right_headerbar) {
+ appmenu_pos = UI_TOOLBAR_RIGHTPANEL_RIGHT;
+ }
+ }
+
+ // main toolbar
+ ui_headerbar_add_items(obj, main_headerbar, left_defaults, UI_TOOLBAR_LEFT);
+ ui_headerbar_add_items(obj, main_headerbar, center_defaults, UI_TOOLBAR_CENTER);
+
+ if(appmenu && appmenu_pos == UI_TOOLBAR_RIGHT) {
+ ui_add_headerbar_menu(main_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT);
+ }
+ ui_headerbar_add_items(obj, main_headerbar, right_defaults, UI_TOOLBAR_RIGHT);
+
+ // sidebar
+ if(sidebar_headerbar) {
+ // ui_headerbar_add_items pos parameter uses only UI_TOOLBAR_LEFT, UI_TOOLBAR_CENTER, UI_TOOLBAR_RIGHT
+ ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_left_defaults, UI_TOOLBAR_LEFT);
+
+ if(appmenu && appmenu_pos == UI_TOOLBAR_SIDEBAR_RIGHT) {
+ ui_add_headerbar_menu(sidebar_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT);
+ }
+ ui_headerbar_add_items(obj, sidebar_headerbar, sidebar_right_defaults, UI_TOOLBAR_RIGHT);
+ }
+
+ // right panel
+ if(right_headerbar) {
+ ui_headerbar_add_items(obj, right_headerbar, rightpanel_left_defaults, UI_TOOLBAR_LEFT);
+ ui_headerbar_add_items(obj, right_headerbar, rightpanel_center_defaults, UI_TOOLBAR_CENTER);
+
+ if(appmenu && appmenu_pos == UI_TOOLBAR_RIGHTPANEL_RIGHT) {
+ ui_add_headerbar_menu(right_headerbar, NULL, appmenu, obj, UI_TOOLBAR_RIGHT);
+ }
+ ui_headerbar_add_items(obj, right_headerbar, rightpanel_right_defaults, UI_TOOLBAR_RIGHT);
}
- ui_headerbar_add_items(obj, headerbar, right_defaults, UI_TOOLBAR_RIGHT);
}
static void create_item(UiObject *obj, GtkWidget *headerbar, GtkWidget *box, UiToolbarItemI *i, enum UiToolbarPos pos) {
@@ -114,8 +163,9 @@ void ui_add_headerbar_item(
UiObject *obj,
enum UiToolbarPos pos)
{
- GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.onclick, item->args.onclickdata, 0, FALSE);
+ GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.tooltip, item->args.onclick, item->args.onclickdata, 0, FALSE);
ui_set_widget_groups(obj->ctx, button, item->args.groups);
+ ui_set_widget_visibility_states(obj->ctx, button, item->args.visibility_states);
WIDGET_ADD_CSS_CLASS(button, "flat");
headerbar_add(headerbar, box, button, pos);
}
@@ -129,8 +179,9 @@ void ui_add_headerbar_toggleitem(
{
GtkWidget *button = gtk_toggle_button_new();
ui_set_widget_groups(obj->ctx, button, item->args.groups);
+ ui_set_widget_visibility_states(obj->ctx, button, item->args.visibility_states);
WIDGET_ADD_CSS_CLASS(button, "flat");
- ui_setup_togglebutton(obj, button, item->args.label, item->args.icon, item->args.varname, NULL, item->args.onchange, item->args.onchangedata, 0);
+ ui_setup_togglebutton(obj, button, item->args.label, item->args.icon, item->args.tooltip, item->args.varname, NULL, item->args.onchange, item->args.onchangedata, 0);
headerbar_add(headerbar, box, button, pos);
}
@@ -145,6 +196,7 @@ void ui_add_headerbar_menu(
#if GTK_MAJOR_VERSION >= 4
GtkWidget *menubutton = gtk_menu_button_new();
+ ui_set_widget_visibility_states(obj->ctx, menubutton, item->args.visibility_states);
if(item->args.label) {
gtk_menu_button_set_label(GTK_MENU_BUTTON(menubutton), item->args.label);
}
@@ -162,9 +214,10 @@ void ui_add_headerbar_menu(
gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(menubutton), G_MENU_MODEL(menu));
#else
GtkWidget *menubutton = gtk_menu_button_new();
-
- // TODO
-
+ GtkWidget *menu = gtk_menu_new();
+ ui_add_menu_items(menu, 0, &item->menu, obj);
+ gtk_widget_show_all(menu);
+ gtk_menu_button_set_popup(GTK_MENU_BUTTON(menubutton), menu);
#endif
diff --git a/ui/gtk/headerbar.h b/ui/gtk/headerbar.h
index acea9fe..93028ea 100644
--- a/ui/gtk/headerbar.h
+++ b/ui/gtk/headerbar.h
@@ -58,7 +58,7 @@ extern "C" {
#endif
#endif
-void ui_fill_headerbar(UiObject *obj, GtkWidget *headerbar);
+void ui_fill_headerbar(UiObject *obj, GtkWidget *sidebar_headerbar, GtkWidget *main_headerbar, GtkWidget *right_headerbar);
void ui_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxList *items, enum UiToolbarPos pos);
diff --git a/ui/gtk/image.c b/ui/gtk/image.c
index 425af82..e60dbdd 100644
--- a/ui/gtk/image.c
+++ b/ui/gtk/image.c
@@ -64,8 +64,6 @@ static gboolean imageviewer_draw(GtkWidget *widget, cairo_t *cr, gpointer userda
#endif
UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args) {
- UiObject *current = uic_current_obj(obj);
-
GtkWidget *drawingarea = gtk_drawing_area_new();
GtkWidget *toplevel;
GtkWidget *widget = drawingarea;
@@ -111,7 +109,7 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args) {
g_object_set_data_full(G_OBJECT(drawingarea), "uiimageviewer", imgviewer, (GDestroyNotify)imageviewer_destroy);
- UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_GENERIC);
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_GENERIC);
imgviewer->var = var;
imgviewer->widget = drawingarea;
@@ -187,8 +185,9 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs *args) {
ui_widget_set_contextmenu(widget, menu);
}
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, toplevel);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, toplevel, &layout);
return toplevel;
}
diff --git a/ui/gtk/list.c b/ui/gtk/list.c
index be9c00a..f793b2c 100644
--- a/ui/gtk/list.c
+++ b/ui/gtk/list.c
@@ -39,21 +39,22 @@
#include
#include "list.h"
+#include "button.h"
#include "icon.h"
#include "menu.h"
#include "dnd.h"
-void* ui_strmodel_getvalue(void *elm, int column) {
- return column == 0 ? elm : NULL;
+static void* getvalue_wrapper(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+ ui_getvaluefunc getvalue = (ui_getvaluefunc)userdata;
+ return getvalue(elm, col);
}
-static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
- if(model->getvalue2) {
- return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
- } else if(model->getvalue) {
- return model->getvalue(elm, col);
- }
+static void* str_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
+ return elm;
+}
+
+static void* null_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) {
return NULL;
}
@@ -74,6 +75,42 @@ static void listview_copy_static_elements(UiListView *listview, char **elm, size
}
}
+static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
+ UiListView *tableview = malloc(sizeof(UiListView));
+ memset(tableview, 0, sizeof(UiListView));
+ tableview->obj = obj;
+ tableview->model = args->model;
+ tableview->onactivate = args->onactivate;
+ tableview->onactivatedata = args->onactivatedata;
+ tableview->onselection = args->onselection;
+ tableview->onselectiondata = args->onselectiondata;
+ tableview->ondragstart = args->ondragstart;
+ tableview->ondragstartdata = args->ondragstartdata;
+ tableview->ondragcomplete = args->ondragcomplete;
+ tableview->ondragcompletedata = args->ondragcompletedata;
+ tableview->ondrop = args->ondrop;
+ tableview->ondropdata = args->ondropdata;
+ tableview->selection.count = 0;
+ tableview->selection.rows = NULL;
+ tableview->current_row = -1;
+ tableview->getstyle = args->getstyle;
+ tableview->getstyledata = args->getstyledata;
+ tableview->onsave = args->onsave;
+ tableview->onsavedata = args->onsavedata;
+
+ if(args->getvalue2) {
+ tableview->getvalue = args->getvalue2;
+ tableview->getvaluedata = args->getvalue2data;
+ } else if(args->getvalue) {
+ tableview->getvalue = getvalue_wrapper;
+ tableview->getvaluedata = (void*)args->getvalue;
+ } else {
+ tableview->getvalue = null_getvalue;
+ }
+
+ return tableview;
+}
+
#if GTK_CHECK_VERSION(4, 10, 0)
@@ -108,6 +145,58 @@ ObjWrapper* obj_wrapper_new(void* data, int i) {
/* END GObject wrapper for generic pointers */
+typedef struct UiCellEntry {
+ GtkEntry *entry;
+ UiListView *listview;
+ char *previous_value;
+ int row;
+ int col;
+} UiCellEntry;
+
+static void cell_save_value(UiCellEntry *data, int restore) {
+ if(data->listview && data->listview->onsave) {
+ UiVar *var = data->listview->var;
+ UiList *list = var ? var->value : NULL;
+ const char *str = ENTRY_GET_TEXT(data->entry);
+ UiCellValue value;
+ value.string = str;
+ value.type = UI_STRING_EDITABLE;
+ if(data->listview->onsave(list, data->row, data->col, &value, data->listview->onsavedata)) {
+ free(data->previous_value);
+ data->previous_value = strdup(str);
+ } else if(restore) {
+ ENTRY_SET_TEXT(data->entry, data->previous_value);
+ }
+ }
+}
+
+static void cell_entry_leave_focus(
+ GtkEventControllerFocus *self,
+ UiCellEntry *data)
+{
+ // TODO: use a different singal to track focus
+ // we only want to call cell_save_value, when another entry is selected,
+ // not when the window loses focus or something like that
+ cell_save_value(data, TRUE);
+}
+
+static void cell_entry_destroy(GtkWidget *object, UiCellEntry *data) {
+ free(data->previous_value);
+ free(data);
+}
+
+static void cell_entry_unmap(GtkWidget *w, UiCellEntry *data) {
+ const char *text = ENTRY_GET_TEXT(w);
+ cell_save_value(data, FALSE);
+}
+
+static void cell_entry_activate(
+ GtkEntry *self,
+ UiCellEntry *data)
+{
+ cell_save_value(data, TRUE);
+}
+
static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
UiColData *col = userdata;
UiModel *model = col->listview->model;
@@ -124,25 +213,125 @@ static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item,
} else if(type == UI_ICON) {
GtkWidget *image = gtk_image_new();
gtk_list_item_set_child(item, image);
- } else {
+ } else if(type == UI_STRING_EDITABLE) {
+ GtkWidget *textfield = gtk_entry_new();
+ gtk_widget_add_css_class(textfield, "ui-table-entry");
+ gtk_list_item_set_child(item, textfield);
+
+ UiCellEntry *entry_data = malloc(sizeof(UiCellEntry));
+ entry_data->entry = GTK_ENTRY(textfield);
+ entry_data->listview = NULL;
+ entry_data->previous_value = NULL;
+ entry_data->col = 0;
+ entry_data->row = 0;
+ g_object_set_data(G_OBJECT(textfield), "ui_entry_data", entry_data);
+
+ g_signal_connect(
+ textfield,
+ "destroy",
+ G_CALLBACK(cell_entry_destroy),
+ entry_data);
+ g_signal_connect(
+ textfield,
+ "activate",
+ G_CALLBACK(cell_entry_activate),
+ entry_data);
+ g_signal_connect(
+ textfield,
+ "unmap",
+ G_CALLBACK(cell_entry_unmap),
+ entry_data);
+
+ GtkEventController *focus_controller = gtk_event_controller_focus_new();
+ g_signal_connect(focus_controller, "leave", G_CALLBACK(cell_entry_leave_focus), entry_data);
+ gtk_widget_add_controller(textfield, focus_controller);
+ } else if(type == UI_BOOL_EDITABLE) {
+ GtkWidget *checkbox = gtk_check_button_new();
+ gtk_list_item_set_child(item, checkbox);
+ }else {
GtkWidget *label = gtk_label_new(NULL);
gtk_label_set_xalign(GTK_LABEL(label), 0);
gtk_list_item_set_child(item, label);
}
}
-static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
+PangoAttrList* textstyle2pangoattributes(UiTextStyle style) {
+ PangoAttrList *attr = pango_attr_list_new();
+
+ if(style.text_style & UI_TEXT_STYLE_BOLD) {
+ pango_attr_list_insert(attr, pango_attr_weight_new(PANGO_WEIGHT_BOLD));
+ }
+ if(style.text_style & UI_TEXT_STYLE_ITALIC) {
+ pango_attr_list_insert(attr, pango_attr_style_new(PANGO_STYLE_ITALIC));
+ }
+ if(style.text_style & UI_TEXT_STYLE_UNDERLINE) {
+ pango_attr_list_insert(attr, pango_attr_underline_new(PANGO_UNDERLINE_SINGLE));
+ }
+
+ // foreground color, convert from 8bit to 16bit
+ guint16 r = (guint16)style.fg.red * 257;
+ guint16 g = (guint16)style.fg.green * 257;
+ guint16 b = (guint16)style.fg.blue * 257;
+ pango_attr_list_insert(attr, pango_attr_foreground_new(r, g, b));
+
+ return attr;
+}
+
+static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, gpointer userdata) {
UiColData *col = userdata;
UiList *list = col->listview->var ? col->listview->var->value : NULL;
-
+ UiListView *listview = col->listview;
+
ObjWrapper *obj = gtk_list_item_get_item(item);
UiModel *model = col->listview->model;
UiModelType type = model->types[col->model_column];
+ // cache the GtkListItem
+ CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
+ UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
+ if(row) {
+ if(row->items[col->model_column] == NULL) {
+ row->bound++;
+ }
+ } else {
+ row = calloc(1, sizeof(UiRowItems) + listview->numcolumns * sizeof(GtkListItem*));
+ cxMapPut(listview->bound_rows, row_key, row);
+ row->bound = 1;
+ }
+ row->items[col->model_column] = item;
+
UiBool freevalue = FALSE;
- void *data = model_getvalue(model, list, obj->data, obj->i, col->data_column, &freevalue);
+ void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue);
GtkWidget *child = gtk_list_item_get_child(item);
+ PangoAttrList *attributes = NULL;
+ UiTextStyle style = { 0, 0 };
+ if(listview->getstyle) {
+ // query current row style, if it wasn't already queried
+ if(obj->i != listview->current_row) {
+ listview->current_row = obj->i;
+ listview->row_style = (UiTextStyle){ 0, 0 };
+ listview->apply_row_style = listview->getstyle(list, obj->data, obj->i, -1, listview->getstyledata, &listview->row_style);
+ style = listview->row_style;
+ if(listview->apply_row_style) {
+ pango_attr_list_unref(listview->current_row_attributes);
+ listview->current_row_attributes = textstyle2pangoattributes(style);
+ }
+ }
+
+ int style_col = col->data_column;
+ if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
+ style_col++; // col->data_column is the icon, we need the next col for the label
+ }
+
+ // get the column style
+ if(listview->getstyle(list, obj->data, obj->i, style_col, listview->getstyledata, &style)) {
+ attributes = textstyle2pangoattributes(style);
+ } else if(listview->apply_row_style) {
+ attributes = listview->current_row_attributes;
+ }
+ }
+
switch(type) {
case UI_STRING_FREE: {
freevalue = TRUE;
@@ -152,6 +341,7 @@ static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item,
if(freevalue) {
free(data);
}
+ gtk_label_set_attributes(GTK_LABEL(child), attributes);
break;
}
case UI_INTEGER: {
@@ -159,6 +349,7 @@ static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item,
char buf[32];
snprintf(buf, 32, "%d", (int)intvalue);
gtk_label_set_label(GTK_LABEL(child), buf);
+ gtk_label_set_attributes(GTK_LABEL(child), attributes);
break;
}
case UI_ICON: {
@@ -172,7 +363,7 @@ static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item,
}
case UI_ICON_TEXT_FREE: {
- void *data2 = model_getvalue(model, list, obj->data, obj->i, col->data_column+1, &freevalue);
+ void *data2 = listview->getvalue(list, obj->data, obj->i, col->data_column+1, listview->getvaluedata, &freevalue);
if(type == UI_ICON_TEXT_FREE) {
freevalue = TRUE;
}
@@ -184,70 +375,96 @@ static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item,
}
if(data2 && label) {
gtk_label_set_label(GTK_LABEL(label), data2);
+ gtk_label_set_attributes(GTK_LABEL(label), attributes);
}
if(freevalue) {
free(data2);
}
break;
}
+ case UI_STRING_EDITABLE: {
+ UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data");
+ if(entry) {
+ entry->listview = col->listview;
+ entry->row = obj->i;
+ entry->col = col->data_column;
+ entry->previous_value = strdup(data);
+ }
+ ENTRY_SET_TEXT(child, data);
+ break;
+ }
+ case UI_BOOL_EDITABLE: {
+ intptr_t i = (intptr_t)data;
+ gtk_check_button_set_active(GTK_CHECK_BUTTON(child), (gboolean)i);
+ break;
+ }
+ }
+
+ if(attributes != listview->current_row_attributes) {
+ pango_attr_list_unref(attributes);
}
}
+static void column_factory_unbind(GtkSignalListItemFactory *self, GtkListItem *item, UiColData *col) {
+ ObjWrapper *obj = gtk_list_item_get_item(item);
+ UiListView *listview = col->listview;
+ CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
+ UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
+ if(row) {
+ row->items[col->model_column] = NULL;
+ row->bound--;
+ if(row->bound == 0) {
+ cxMapRemove(listview->bound_rows, row_key);
+ }
+ } // else: should not happen
+
+ GtkWidget *child = gtk_list_item_get_child(item);
+ UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data");
+ if(entry) {
+ cell_save_value(entry, FALSE);
+ entry->listview = NULL;
+ free(entry->previous_value);
+ entry->previous_value = NULL;
+ } else if(GTK_IS_CHECK_BUTTON(child)) {
+
+ }
+}
+
+
static GtkSelectionModel* create_selection_model(UiListView *listview, GListStore *liststore, bool multiselection) {
GtkSelectionModel *selection_model;
if(multiselection) {
selection_model = GTK_SELECTION_MODEL(gtk_multi_selection_new(G_LIST_MODEL(liststore)));
} else {
selection_model = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(liststore)));
+ gtk_single_selection_set_can_unselect(GTK_SINGLE_SELECTION(selection_model), TRUE);
+ gtk_single_selection_set_autoselect(GTK_SINGLE_SELECTION(selection_model), FALSE);
}
g_signal_connect(selection_model, "selection-changed", G_CALLBACK(ui_listview_selection_changed), listview);
return selection_model;
}
-static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
- UiListView *tableview = malloc(sizeof(UiListView));
- memset(tableview, 0, sizeof(UiListView));
- tableview->obj = obj;
- tableview->model = args->model;
- tableview->onactivate = args->onactivate;
- tableview->onactivatedata = args->onactivatedata;
- tableview->onselection = args->onselection;
- tableview->onselectiondata = args->onselectiondata;
- tableview->ondragstart = args->ondragstart;
- tableview->ondragstartdata = args->ondragstartdata;
- tableview->ondragcomplete = args->ondragcomplete;
- tableview->ondragcompletedata = args->ondragcompletedata;
- tableview->ondrop = args->ondrop;
- tableview->ondropdata = args->ondropdata;
- tableview->selection.count = 0;
- tableview->selection.rows = NULL;
- return tableview;
-}
-
UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
// to simplify things and share code with ui_table_create, we also
// use a UiModel for the listview
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- if(args->getvalue2) {
- model->getvalue2 = args->getvalue2;
- model->getvalue2data = args->getvalue2data;
- } else if(args->getvalue) {
- model->getvalue = args->getvalue;
- } else {
- model->getvalue = ui_strmodel_getvalue;
- }
args->model = model;
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
UiListView *listview = create_listview(obj, args);
+ if(!args->getvalue && !args->getvalue2) {
+ listview->getvalue = str_getvalue;
+ }
+ listview->numcolumns = 1;
listview->columns = malloc(sizeof(UiColData));
listview->columns->listview = listview;
listview->columns->data_column = 0;
listview->columns->model_column = 0;
+ listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
+ listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
+
GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
@@ -255,7 +472,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection);
GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
// init listview
listview->widget = view;
@@ -280,7 +497,7 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
ui_update_liststore(ls, list);
} else if (args->static_elements && args->static_nelm > 0) {
listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
- listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
+ listview->getvalue = str_getvalue; // force string values
ui_update_liststore_static(ls, listview->elements, listview->nelm);
}
@@ -304,48 +521,58 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, scroll_area);
+ if(args->width > 0 || args->height > 0) {
+ int width = args->width;
+ int height = args->height;
+ if(width == 0) {
+ width = -1;
+ }
+ if(height == 0) {
+ height = -1;
+ }
+ gtk_widget_set_size_request(scroll_area, width, height);
+ }
- // ct->current should point to view, not scroll_area, to make it possible
- // to add a context menu
- current->container->current = view;
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, scroll_area, &layout);
return scroll_area;
}
UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
// to simplify things and share code with ui_tableview_create, we also
// use a UiModel for the listview
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- if(args->getvalue2) {
- model->getvalue2 = args->getvalue2;
- model->getvalue2data = args->getvalue2data;
- } else if(args->getvalue) {
- model->getvalue = args->getvalue;
- } else {
- model->getvalue = ui_strmodel_getvalue;
- }
args->model = model;
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
UiListView *listview = create_listview(obj, args);
+ if(!args->getvalue && !args->getvalue2) {
+ listview->getvalue = str_getvalue;
+ }
+
+ listview->numcolumns = 1;
listview->columns = malloc(sizeof(UiColData));
listview->columns->listview = listview;
listview->columns->data_column = 0;
listview->columns->model_column = 0;
+ listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
+ listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
+
GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
+ if(args->width > 0) {
+ gtk_widget_set_size_request(view, args->width, -1);
+ }
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
// init listview
listview->widget = view;
@@ -370,7 +597,7 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
ui_update_liststore(ls, list);
} else if (args->static_elements && args->static_nelm > 0) {
listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
- listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
+ listview->getvalue = str_getvalue; // force string values
ui_update_liststore_static(ls, listview->elements, listview->nelm);
}
@@ -380,8 +607,10 @@ UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
}
// add widget to parent
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, view);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, view, &layout);
+
return view;
}
@@ -395,8 +624,6 @@ void ui_combobox_select(UIWIDGET dropdown, int index) {
}
UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
//g_list_store_append(ls, v1);
@@ -407,7 +634,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args->multiselection);
GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model));
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
// init tableview
tableview->widget = view;
@@ -426,6 +653,10 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
int columns = model ? model->columns : 0;
tableview->columns = calloc(columns, sizeof(UiColData));
+ tableview->numcolumns = columns;
+
+ tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
+ tableview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
int addi = 0;
for(int i=0;icontainer->add(current->container, scroll_area);
+ if(args->width > 0 || args->height > 0) {
+ int width = args->width;
+ int height = args->height;
+ if(width == 0) {
+ width = -1;
+ }
+ if(height == 0) {
+ height = -1;
+ }
+ gtk_widget_set_size_request(scroll_area, width, height);
+ }
- // ct->current should point to view, not scroll_area, to make it possible
- // to add a context menu
- current->container->current = view;
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, scroll_area, &layout);
return scroll_area;
}
@@ -625,14 +865,19 @@ void ui_listview_update2(UiList *list, int i) {
} else {
void *value = list->get(list, i);
if(value) {
- ObjWrapper *obj = obj_wrapper_new(value, i);
- // TODO: if index i is selected, the selection is lost
- // is it possible to update the item without removing it?
- int count = g_list_model_get_n_items(G_LIST_MODEL(view->liststore));
- if(count <= i) {
- g_list_store_splice(view->liststore, i, 0, (void **)&obj, 1);
- } else {
- g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1);
+ ObjWrapper *obj = g_list_model_get_item(G_LIST_MODEL(view->liststore), i);
+ if(obj) {
+ obj->data = value;
+ }
+
+ CxHashKey row_key = cx_hash_key(&i, sizeof(int));
+ UiRowItems *row = cxMapGet(view->bound_rows, row_key);
+ if(row) {
+ for(int c=0;cnumcolumns;c++) {
+ if(row->items[c] != NULL) {
+ column_factory_bind(NULL, row->items[c], &view->columns[c]);
+ }
+ }
}
}
}
@@ -695,15 +940,42 @@ void ui_combobox_setselection(UiList *list, UiListSelection selection) {
#else
-static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, UiList *list, void *elm, int row) {
+static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIter *iter, UiList *list, void *elm, int row) {
+ UiModel *model = listview->model;
+ ui_getstylefunc getstyle = listview->getstyle;
+
+ // get the row style
+ UiBool style_set = FALSE;
+ UiTextStyle style = { 0, 0 };
+ if(getstyle) {
+ style_set = getstyle(list, elm, row, -1, listview->getstyledata, &style);
+ }
+
// set column values
int c = 0;
for(int i=0;icolumns;i++,c++) {
UiBool freevalue = FALSE;
- void *data = model_getvalue(model, list, elm, row, c, &freevalue);
+ void *data = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue);
+
+ UiModelType type = model->types[i];
+
+ if(getstyle) {
+ // in case the column is icon+text, only get a style for the text column
+ int style_col = c;
+ if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
+ style_col++;
+ }
+
+ // Get the individual column style
+ // The column style overrides the row style, however if no column style
+ // is provided, we stick with the row style
+ if(getstyle(list, elm, row, style_col, listview->getstyledata, &style)) {
+ style_set = TRUE;
+ }
+ }
GValue value = G_VALUE_INIT;
- switch(model->types[i]) {
+ switch(type) {
case UI_STRING_FREE: {
freevalue = TRUE;
}
@@ -765,7 +1037,7 @@ static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *mod
c++;
freevalue = FALSE;
- char *str = model_getvalue(model, list, elm, row, c, &freevalue);
+ char *str = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue);
g_value_init(&value, G_TYPE_STRING);
g_value_set_string(&value, str);
if(model->types[i] == UI_ICON_TEXT_FREE || freevalue) {
@@ -776,12 +1048,64 @@ static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *mod
}
gtk_list_store_set_value(store, iter, c, &value);
+
+ if(style_set) {
+ int soff = listview->style_offset + i*6;
+
+ GValue style_set_value = G_VALUE_INIT;
+ g_value_init(&style_set_value, G_TYPE_BOOLEAN);
+ g_value_set_boolean(&style_set_value, TRUE);
+ gtk_list_store_set_value(store, iter, soff, &style_set_value);
+
+ GValue style_weight_value = G_VALUE_INIT;
+ g_value_init(&style_weight_value, G_TYPE_INT);
+ if(style.text_style & UI_TEXT_STYLE_BOLD) {
+ g_value_set_int(&style_weight_value, 600);
+ } else {
+ g_value_set_int(&style_weight_value, 400);
+ }
+ gtk_list_store_set_value(store, iter, soff + 1, &style_weight_value);
+
+ GValue style_underline_value = G_VALUE_INIT;
+ g_value_init(&style_underline_value, G_TYPE_INT);
+ if(style.text_style & UI_TEXT_STYLE_UNDERLINE) {
+ g_value_set_int(&style_underline_value, PANGO_UNDERLINE_SINGLE);
+ } else {
+ g_value_set_int(&style_underline_value, PANGO_UNDERLINE_NONE);
+ }
+ gtk_list_store_set_value(store, iter, soff + 2, &style_underline_value);
+
+ GValue style_italic_value = G_VALUE_INIT;
+ g_value_init(&style_italic_value, G_TYPE_INT);
+ if(style.text_style & UI_TEXT_STYLE_ITALIC) {
+ g_value_set_int(&style_italic_value, PANGO_STYLE_ITALIC);
+ } else {
+ g_value_set_int(&style_italic_value, PANGO_STYLE_NORMAL);
+ }
+ gtk_list_store_set_value(store, iter, soff + 3, &style_italic_value);
+
+ GValue style_fgset_value = G_VALUE_INIT;
+ g_value_init(&style_fgset_value, G_TYPE_BOOLEAN);
+ g_value_set_boolean(&style_fgset_value, style.fg_set);
+ gtk_list_store_set_value(store, iter, soff + 4, &style_fgset_value);
+
+ if(style.fg_set) {
+ char buf[8];
+ snprintf(buf, 8, "#%02X%02X%02X", (int)style.fg.red, (int)style.fg.green, (int)style.fg.blue);
+
+ GValue style_fg_value = G_VALUE_INIT;
+ g_value_init(&style_fg_value, G_TYPE_STRING);
+ g_value_set_string(&style_fg_value, buf);
+ gtk_list_store_set_value(store, iter, soff + 5, &style_fg_value);
+ }
+ }
}
}
-static GtkListStore* create_list_store(UiList *list, UiModel *model) {
+static GtkListStore* create_list_store(UiListView *listview, UiList *list) {
+ UiModel *model = listview->model;
int columns = model->columns;
- GType types[2*columns];
+ GType *types = calloc(columns*8, sizeof(GType));
int c = 0;
for(int i=0;itypes[i]) {
@@ -796,8 +1120,18 @@ static GtkListStore* create_list_store(UiList *list, UiModel *model) {
}
}
}
+ int s = 0;
+ for(int i=0;istyle_offset+s] = G_TYPE_BOOLEAN; s++; // *-set
+ types[listview->style_offset+s] = G_TYPE_INT; s++; // weight
+ types[listview->style_offset+s] = G_TYPE_INT; s++; // underline
+ types[listview->style_offset+s] = G_TYPE_INT; s++; // style
+ types[listview->style_offset+s] = G_TYPE_BOOLEAN; s++; // foreground-set
+ types[listview->style_offset+s] = G_TYPE_STRING; s++; // foreground
+ }
- GtkListStore *store = gtk_list_store_newv(c, types);
+ GtkListStore *store = gtk_list_store_newv(c+s, types);
+ free(types);
if(list) {
void *elm = list->first(list);
@@ -807,7 +1141,7 @@ static GtkListStore* create_list_store(UiList *list, UiModel *model) {
GtkTreeIter iter;
gtk_list_store_insert (store, &iter, -1);
- update_list_row(store, &iter, model, list, elm, i++);
+ update_list_row(listview, store, &iter, list, elm, i++);
// next row
elm = list->next(list);
@@ -819,8 +1153,6 @@ static GtkListStore* create_list_store(UiList *list, UiModel *model) {
UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
// create treeview
GtkWidget *view = gtk_tree_view_new();
ui_set_name_and_style(view, args->name, args->style_class);
@@ -841,36 +1173,30 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
#endif
UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- if(args->getvalue2) {
- model->getvalue2 = args->getvalue2;
- model->getvalue2data = args->getvalue2data;
- } else if(args->getvalue) {
- model->getvalue = args->getvalue;
- } else {
- model->getvalue = ui_strmodel_getvalue;
- }
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
-
- UiList *list = var ? var->value : NULL;
- GtkListStore *listmodel = create_list_store(list, model);
- gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
- g_object_unref(listmodel);
-
- UiListView *listview = malloc(sizeof(UiListView));
- memset(listview, 0, sizeof(UiListView));
- listview->obj = obj;
- listview->widget = view;
- listview->var = var;
+ UiListView *listview = create_listview(obj, args);
+ listview->style_offset = 1;
+ if(!args->getvalue && !args->getvalue2) {
+ listview->getvalue = str_getvalue;
+ }
listview->model = model;
- listview->selection.count = 0;
- listview->selection.rows = NULL;
g_signal_connect(
view,
"destroy",
G_CALLBACK(ui_listview_destroy),
listview);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
+
+ // init listview
+ listview->widget = view;
+ listview->var = var;
+
+ UiList *list = var ? var->value : NULL;
+ GtkListStore *listmodel = create_list_store(listview, list);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
+ g_object_unref(listmodel);
+
// bind var
list->update = ui_listview_update;
list->getselection = ui_listview_getselection;
@@ -920,12 +1246,21 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, scroll_area, FALSE);
+ if(args->width > 0 || args->height > 0) {
+ int width = args->width;
+ int height = args->height;
+ if(width == 0) {
+ width = -1;
+ }
+ if(height == 0) {
+ height = -1;
+ }
+ gtk_widget_set_size_request(scroll_area, width, height);
+ }
- // ct->current should point to view, not scroll_area, to make it possible
- // to add a context menu
- current->container->current = view;
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, scroll_area, &layout);
return scroll_area;
}
@@ -942,18 +1277,28 @@ void ui_combobox_select(UIWIDGET dropdown, int index) {
}
UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
// create treeview
GtkWidget *view = gtk_tree_view_new();
UiModel *model = args->model;
int columns = model ? model->columns : 0;
+ // find the last data column index
int addi = 0;
- for(int i=0;itypes[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
+ addi++;
+ }
+ }
+ style_offset = i+addi;
+
+ // create columns and init cell renderers
+ addi = 0;
+ for(i=0;itypes[i] == UI_ICON_TEXT) {
+ if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, model->titles[i]);
@@ -964,8 +1309,21 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
gtk_tree_view_column_pack_start(column, iconrenderer, FALSE);
- gtk_tree_view_column_add_attribute(column, iconrenderer, "pixbuf", i);
- gtk_tree_view_column_add_attribute(column, textrenderer, "text", i+1);
+ gtk_tree_view_column_add_attribute(column, iconrenderer, "pixbuf", addi + i);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "text", addi + i+1);
+
+ if(args->getstyle) {
+ int soff = style_offset + i*6;
+ gtk_tree_view_column_add_attribute(column, textrenderer, "weight-set", soff);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "underline-set", soff);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "style-set", soff);
+
+ gtk_tree_view_column_add_attribute(column, textrenderer, "weight", soff + 1);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "underline", soff + 2);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "style", soff + 3);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "foreground-set", soff + 4);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "foreground", soff + 5);
+ }
addi++;
} else if (model->types[i] == UI_ICON) {
@@ -977,13 +1335,26 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
i + addi,
NULL);
} else {
- GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+ GtkCellRenderer *textrenderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
model->titles[i],
- renderer,
+ textrenderer,
"text",
i + addi,
NULL);
+
+ if(args->getstyle) {
+ int soff = style_offset + i*6;
+ gtk_tree_view_column_add_attribute(column, textrenderer, "weight-set", soff);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "underline-set", soff);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "style-set", soff);
+
+ gtk_tree_view_column_add_attribute(column, textrenderer, "weight", soff + 1);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "underline", soff + 2);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "style", soff + 3);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "foreground-set", soff + 4);
+ gtk_tree_view_column_add_attribute(column, textrenderer, "foreground", soff + 5);
+ }
}
int colsz = model->columnsize[i];
@@ -1004,38 +1375,27 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
#endif
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
-
- UiList *list = var ? var->value : NULL;
- GtkListStore *listmodel = create_list_store(list, model);
- gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
- g_object_unref(listmodel);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
//g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL);
//g_signal_connect(view, "drag-end", G_CALLBACK(drag_end), NULL);
// add TreeView as observer to the UiList to update the TreeView if the
// data changes
- UiListView *tableview = malloc(sizeof(UiListView));
- memset(tableview, 0, sizeof(UiListView));
- tableview->obj = obj;
+ UiListView *tableview = create_listview(obj, args);
tableview->widget = view;
- tableview->var = var;
- tableview->model = model;
- tableview->ondragstart = args->ondragstart;
- tableview->ondragstartdata = args->ondragstartdata;
- tableview->ondragcomplete = args->ondragcomplete;
- tableview->ondragcompletedata = args->ondragcompletedata;
- tableview->ondrop = args->ondrop;
- tableview->ondropdata = args->ondropdata;
- tableview->selection.count = 0;
- tableview->selection.rows = NULL;
+ tableview->style_offset = style_offset;
g_signal_connect(
view,
"destroy",
G_CALLBACK(ui_listview_destroy),
tableview);
+ UiList *list = var ? var->value : NULL;
+ GtkListStore *listmodel = create_list_store(tableview, list);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
+ g_object_unref(listmodel);
+
// bind var
list->update = ui_listview_update;
list->getselection = ui_listview_getselection;
@@ -1088,6 +1448,18 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
+ if(args->width > 0 || args->height > 0) {
+ int width = args->width;
+ int height = args->height;
+ if(width == 0) {
+ width = -1;
+ }
+ if(height == 0) {
+ height = -1;
+ }
+ gtk_widget_set_size_request(scroll_area, width, height);
+ }
+
if(args->contextmenu) {
UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, scroll_area);
#if GTK_MAJOR_VERSION >= 4
@@ -1097,12 +1469,9 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
#endif
}
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, scroll_area, FALSE);
-
- // ct->current should point to view, not scroll_area, to make it possible
- // to add a context menu
- current->container->current = view;
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, scroll_area, &layout);
return scroll_area;
}
@@ -1112,7 +1481,7 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
void ui_listview_update(UiList *list, int i) {
UiListView *view = list->obj;
if(i < 0) {
- GtkListStore *store = create_list_store(list, view->model);
+ GtkListStore *store = create_list_store(view, list);
gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store));
g_object_unref(G_OBJECT(store));
} else {
@@ -1120,7 +1489,7 @@ void ui_listview_update(UiList *list, int i) {
GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget));
GtkTreeIter iter;
if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) {
- update_list_row(GTK_LIST_STORE(store), &iter, view->model, list, elm, i);
+ update_list_row(view, GTK_LIST_STORE(store), &iter, list, elm, i);
}
}
}
@@ -1148,48 +1517,45 @@ void ui_listview_setselection(UiList *list, UiListSelection selection) {
/* --------------------------- ComboBox --------------------------- */
UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
- UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- if(args->getvalue2) {
- model->getvalue2 = args->getvalue2;
- model->getvalue2data = args->getvalue2data;
- } else if(args->getvalue) {
- model->getvalue = args->getvalue;
- } else {
- model->getvalue = ui_strmodel_getvalue;
+ GtkWidget *combobox = gtk_combo_box_new();
+ if(args->width > 0) {
+ gtk_widget_set_size_request(combobox, args->width, -1);
}
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
-
- GtkWidget *combobox = ui_create_combobox(obj, model, var, args->static_elements, args->static_nelm, args->onactivate, args->onactivatedata);
ui_set_name_and_style(combobox, args->name, args->style_class);
ui_set_widget_groups(obj->ctx, combobox, args->groups);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, combobox, FALSE);
- current->container->current = combobox;
- return combobox;
-}
-
-GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **elm, size_t nelm, ui_callback f, void *udata) {
- GtkWidget *combobox = gtk_combo_box_new();
-
- UiListView *uicbox = malloc(sizeof(UiListView));
- memset(uicbox, 0, sizeof(UiListView));
- uicbox->obj = obj;
- uicbox->widget = combobox;
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, combobox, &layout);
- UiList *list = var ? var->value : NULL;
- GtkListStore *listmodel = create_list_store(list, model);
+ UiListView *listview = create_listview(obj, args);
+ listview->widget = combobox;
+ listview->style_offset = 1;
+ listview->model = ui_model(obj->ctx, UI_STRING, "", -1);
+ g_signal_connect(
+ combobox,
+ "destroy",
+ G_CALLBACK(ui_listview_destroy),
+ listview);
- if(!list && elm && nelm > 0) {
- listview_copy_static_elements(uicbox, elm, nelm);
- for(int i=0;ictx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
+ UiList *list = var ? var->value : NULL;
+ GtkListStore *listmodel = create_list_store(listview, list);
+ if(var) {
+ listview->var = var;
+ list->update = ui_combobox_modelupdate;
+ list->getselection = ui_combobox_getselection;
+ list->setselection = ui_combobox_setselection;
+ list->obj = listview;
+ list->update(list, -1);
+ } else if(args->static_nelm > 0) {
+ listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
+ for(int i=0;istatic_nelm;i++) {
GtkTreeIter iter;
GValue value = G_VALUE_INIT;
gtk_list_store_insert(listmodel, &iter, -1);
g_value_init(&value, G_TYPE_STRING);
- g_value_set_string(&value, uicbox->elements[i]);
+ g_value_set_string(&value, listview->elements[i]);
gtk_list_store_set_value(listmodel, &iter, 0, &value);
}
}
@@ -1199,23 +1565,6 @@ GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **
g_object_unref(listmodel);
}
- uicbox->var = var;
- uicbox->model = model;
-
- g_signal_connect(
- combobox,
- "destroy",
- G_CALLBACK(ui_combobox_destroy),
- uicbox);
-
- // bind var
- if(list) {
- list->update = ui_combobox_modelupdate;
- list->getselection = ui_combobox_getselection;
- list->setselection = ui_combobox_setselection;
- list->obj = uicbox;
- }
-
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
gtk_cell_layout_set_attributes(
@@ -1227,13 +1576,13 @@ GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **
gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
// add callback
- if(f) {
+ if(args->onactivate) {
UiEventData *event = ui_malloc(obj->ctx, sizeof(UiEventData));
event->obj = obj;
- event->userdata = udata;
- event->callback = f;
+ event->userdata = args->onactivatedata;
+ event->callback = args->onactivate;
event->value = 0;
- event->customdata = uicbox;
+ event->customdata = listview;
g_signal_connect(
combobox,
@@ -1268,7 +1617,7 @@ void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e) {
void ui_combobox_modelupdate(UiList *list, int i) {
UiListView *view = list->obj;
- GtkListStore *store = create_list_store(view->var->value, view->model);
+ GtkListStore *store = create_list_store(view, list);
gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store));
g_object_unref(store);
}
@@ -1704,27 +2053,28 @@ void ui_listview_destroy(GtkWidget *w, UiListView *v) {
}
#if GTK_CHECK_VERSION(4, 10, 0)
free(v->columns);
+ pango_attr_list_unref(v->current_row_attributes);
+ cxMapFree(v->bound_rows);
#endif
free(v->selection.rows);
free(v);
}
-void ui_combobox_destroy(GtkWidget *w, UiListView *v) {
- if(v->var) {
- ui_destroy_boundvar(v->obj->ctx, v->var);
- }
- if(v->elements) {
- for(int i=0;inelm;i++) {
- free(v->elements[i]);
- }
- free(v->elements);
- }
- free(v);
-}
-
/* ------------------------------ Source List ------------------------------ */
+static ui_sourcelist_update_func sourcelist_update_finished_callback;
+
+void ui_sourcelist_set_update_callback(ui_sourcelist_update_func cb) {
+ sourcelist_update_finished_callback = cb;
+}
+
+static void ui_sourcelist_update_finished(void) {
+ if(sourcelist_update_finished_callback) {
+ sourcelist_update_finished_callback();
+ }
+}
+
static void ui_destroy_sourcelist(GtkWidget *w, UiListBox *v) {
cxListFree(v->sublists);
free(v);
@@ -1751,7 +2101,7 @@ static void listbox_create_header(GtkListBoxRow* row, GtkListBoxRow* before, gpo
if(sublist->separator) {
GtkWidget *separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
gtk_list_box_row_set_header(row, separator);
- } else if(sublist->header) {
+ } else if(sublist->header && !listbox->header_is_item) {
GtkWidget *header = gtk_label_new(sublist->header);
gtk_widget_set_halign(header, GTK_ALIGN_START);
if(row == listbox->first_row) {
@@ -1801,21 +2151,19 @@ static void add_sublist(UiListBox *uilistbox, CxList *sublists, UiSubList *subli
uisublist.listbox = uilistbox;
uisublist.userdata = sublist->userdata;
uisublist.index = cxListSize(sublists);
-
+ uisublist.startpos = 0;
+ cxListAdd(sublists, &uisublist);
+
// bind UiList
UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(sublists)-1);
- UiList *list = uisublist.var->value;
- if(list) {
+ if(uisublist.var && uisublist.var->value) {
+ UiList *list = uisublist.var->value;
list->obj = sublist_ptr;
list->update = ui_listbox_list_update;
}
-
- cxListAdd(sublists, &uisublist);
}
UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
#ifdef UI_GTK3
GtkWidget *listbox = g_object_new(ui_sidebar_list_box_get_type(), NULL);
#else
@@ -1834,12 +2182,14 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
ui_set_name_and_style(listbox, args->name, args->style_class);
ui_set_widget_groups(obj->ctx, listbox, args->groups);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, scroll_area);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, scroll_area, &layout);
UiListBox *uilistbox = malloc(sizeof(UiListBox));
uilistbox->obj = obj;
uilistbox->listbox = GTK_LIST_BOX(listbox);
+ uilistbox->header_is_item = args->header_is_item;
uilistbox->getvalue = args->getvalue;
uilistbox->getvaluedata = args->getvaluedata;
uilistbox->onactivate = args->onactivate;
@@ -1868,7 +2218,7 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
// fill items
ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
} else {
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST);
if(var) {
UiList *list = var->value;
list->obj = uilistbox;
@@ -1883,6 +2233,11 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
g_object_set_data(G_OBJECT(scroll_area), "ui_listbox", uilistbox);
g_object_set_data(G_OBJECT(listbox), "ui_listbox", uilistbox);
+ if(args->contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, listbox);
+ ui_widget_set_contextmenu(listbox, menu);
+ }
+
// signals
g_signal_connect(
listbox,
@@ -1952,22 +2307,82 @@ void ui_listbox_update(UiListBox *listbox, int from, int to) {
}
// reload sublist
+ sublist->startpos = pos;
ui_listbox_update_sublist(listbox, sublist, pos);
pos += sublist->numitems;
}
+
+ ui_sourcelist_update_finished();
+}
+
+static void listbox_button_clicked(GtkWidget *button, UiEventDataExt *data) {
+ UiListBoxSubList *sublist = data->customdata0;
+
+ UiSubListEventData *eventdata = &sublist->listbox->current_eventdata;
+ eventdata->list = sublist->var->value;
+ eventdata->sublist_index = sublist->index;
+ eventdata->row_index = data->value0;
+ eventdata->sublist_userdata = sublist->userdata;
+ eventdata->row_data = eventdata->list->get(eventdata->list, eventdata->row_index);
+ eventdata->event_data = data->customdata2;
+
+ UiEvent event;
+ event.obj = data->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = eventdata;
+ event.eventdatatype = UI_EVENT_DATA_SUBLIST;
+ event.intval = data->value0;
+ event.set = ui_get_setop();
+
+ if(data->callback2) {
+ data->callback2(&event, data->userdata2);
+ }
+
+ if(data->customdata3) {
+ uic_set_tmp_eventdata(eventdata, UI_EVENT_DATA_SUBLIST);
+
+ UIMENU menu = data->customdata3;
+ g_object_set_data(G_OBJECT(button), "ui-button-popup", menu);
+ gtk_popover_popup(GTK_POPOVER(menu));
+ }
}
-static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *sublist, UiSubListItem *item, int index) {
+#if GTK_CHECK_VERSION(4, 0, 0)
+static void button_popover_closed(GtkPopover *popover, GtkWidget *button) {
+ g_object_set_data(G_OBJECT(button), "ui-button-popup", NULL);
+ if(g_object_get_data(G_OBJECT(button), "ui-button-invisible")) {
+ g_object_set_data(G_OBJECT(button), "ui-button-invisible", NULL);
+ gtk_widget_set_visible(button, FALSE);
+ }
+}
+#else
+static void popup_hide(GtkWidget *self, GtkWidget *button) {
+ g_object_set_data(G_OBJECT(button), "ui-button-popup", NULL);
+ if(g_object_get_data(G_OBJECT(button), "ui-button-invisible")) {
+ g_object_set_data(G_OBJECT(button), "ui-button-invisible", NULL);
+ gtk_widget_set_visible(button, FALSE);
+ }
+}
+#endif
+
+static void listbox_fill_row(UiListBox *listbox, GtkWidget *row, UiListBoxSubList *sublist, UiSubListItem *item, int index) {
+ UiBool is_header = index < 0;
+
GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
if(item->icon) {
GtkWidget *icon = ICON_IMAGE(item->icon);
BOX_ADD(hbox, icon);
}
GtkWidget *label = gtk_label_new(item->label);
+ if(is_header) {
+ WIDGET_ADD_CSS_CLASS(label, "ui-listbox-header-row");
+ }
gtk_widget_set_halign(label, GTK_ALIGN_START);
BOX_ADD_EXPAND(hbox, label);
- // TODO: badge, button
- GtkWidget *row = gtk_list_box_row_new();
+ if(item->badge) {
+
+ }
LISTBOX_ROW_SET_CHILD(row, hbox);
// signals
@@ -1983,6 +2398,9 @@ static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *subli
event->userdata2 = listbox->onbuttonclickdata;
event->value0 = index;
+ // TODO: semi-memory leak when listbox_fill_row is called again for the same row
+ // each row update will create a new UiEventDataExt object and a separate destroy handler
+
g_signal_connect(
row,
"destroy",
@@ -1991,9 +2409,137 @@ static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *subli
g_object_set_data(G_OBJECT(row), "ui-listbox-row-eventdata", event);
- return row;
+ // badge
+ if(item->badge) {
+ GtkWidget *badge = gtk_label_new(item->badge);
+ WIDGET_ADD_CSS_CLASS(badge, "ui-badge");
+#if GTK_CHECK_VERSION(3, 14, 0)
+ gtk_widget_set_valign(badge, GTK_ALIGN_CENTER);
+ BOX_ADD(hbox, badge);
+#else
+ GtkWidget *align = gtk_alignment_new(0.5, 0.5, 0, 0);
+ gtk_container_add(GTK_CONTAINER(align), badge);
+ BOX_ADD(hbox, align);
+#endif
+ }
+ // button
+ if(item->button_icon || item->button_label) {
+ GtkWidget *button = gtk_button_new();
+ gtk_button_set_label(GTK_BUTTON(button), item->button_label);
+ ui_button_set_icon_name(button, item->button_icon);
+ WIDGET_ADD_CSS_CLASS(button, "flat");
+ BOX_ADD(hbox, button);
+ g_signal_connect(
+ button,
+ "clicked",
+ G_CALLBACK(listbox_button_clicked),
+ event
+ );
+ gtk_widget_set_visible(button, FALSE);
+
+ g_object_set_data(G_OBJECT(row), "ui-listbox-row-button", button);
+
+ // menu
+ if(item->button_menu) {
+ UIMENU menu = ui_contextmenu_create(item->button_menu, listbox->obj, button);
+ event->customdata3 = menu;
+#if GTK_CHECK_VERSION(4, 0, 0)
+ g_signal_connect(menu, "closed", G_CALLBACK(button_popover_closed), button);
+#else
+ g_signal_connect(menu, "hide", G_CALLBACK(popup_hide), button);
+#endif
+ ui_menubuilder_unref(item->button_menu);
+ }
+ }
}
+static void update_sublist_item(UiListBox *listbox, UiListBoxSubList *sublist, int index) {
+ int header_row = listbox->header_is_item && sublist->header ? 1 : 0;
+ GtkListBoxRow *row = gtk_list_box_get_row_at_index(listbox->listbox, sublist->startpos + index + header_row);
+ if(!row) {
+ return;
+ }
+ UiList *list = sublist->var->value;
+ if(!list) {
+ return;
+ }
+
+ void *elm = list->get(list, index);
+ UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
+ if(listbox->getvalue) {
+ listbox->getvalue(list, sublist->userdata, elm, index, &item, listbox->getvaluedata);
+ } else {
+ item.label = strdup(elm);
+ }
+
+ LISTBOX_ROW_REMOVE_CHILD(row);
+
+ listbox_fill_row(listbox, GTK_WIDGET(row), sublist, &item, index);
+
+ // cleanup
+ free(item.label);
+ free(item.icon);
+ free(item.button_label);
+ free(item.button_icon);
+ free(item.badge);
+}
+
+static void listbox_row_on_enter(GtkWidget *row) {
+ GtkWidget *button = g_object_get_data(G_OBJECT(row), "ui-listbox-row-button");
+ if(button) {
+ gtk_widget_set_visible(button, TRUE);
+ }
+}
+
+static void listbox_row_on_leave(GtkWidget *row) {
+ GtkWidget *button = g_object_get_data(G_OBJECT(row), "ui-listbox-row-button");
+ if(button) {
+ if(!g_object_get_data(G_OBJECT(button), "ui-button-popup")) {
+ gtk_widget_set_visible(button, FALSE);
+ } else {
+ g_object_set_data(G_OBJECT(button), "ui-button-invisible", (void*)1);
+ }
+ }
+}
+
+#if GTK_CHECK_VERSION(4, 0, 0)
+static void listbox_row_enter(
+ GtkEventControllerMotion* self,
+ gdouble x,
+ gdouble y,
+ GtkWidget *row)
+{
+ listbox_row_on_enter(row);
+}
+
+static void listbox_row_leave(
+ GtkEventControllerMotion* self,
+ GtkWidget *row)
+{
+ listbox_row_on_leave(row);
+}
+#else
+static gboolean listbox_row_enter(
+ GtkWidget *row,
+ GdkEventCrossing event,
+ gpointer user_data)
+{
+ listbox_row_on_enter(row);
+ return FALSE;
+}
+
+
+static gboolean listbox_row_leave(
+ GtkWidget *row,
+ GdkEventCrossing *event,
+ gpointer user_data)
+{
+ listbox_row_on_leave(row);
+ return FALSE;
+}
+
+#endif
+
void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index) {
// clear sublist
CxIterator r = cxListIterator(sublist->widgets);
@@ -2005,13 +2551,40 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
sublist->numitems = 0;
// create items for each UiList element
+ if(!sublist->var) {
+ return;
+ }
UiList *list = sublist->var->value;
if(!list) {
return;
}
- size_t index = 0;
+ int index = 0;
void *elm = list->first(list);
+ void *first = elm;
+
+ if(sublist->header && !listbox->header_is_item && !elm) {
+ // empty row for header
+ GtkWidget *row = gtk_list_box_row_new();
+ cxListAdd(sublist->widgets, row);
+ g_object_set_data(G_OBJECT(row), "ui_listbox", listbox);
+ g_object_set_data(G_OBJECT(row), "ui_listbox_sublist", sublist);
+ //intptr_t rowindex = listbox_insert_index + index;
+ //g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex);
+ gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index);
+ sublist->numitems = 1;
+ return;
+ }
+
+ int first_index = 0;
+ int header_row = 0;
+ if(listbox->header_is_item && sublist->header) {
+ index = -1;
+ first_index = -1;
+ header_row = 1;
+ elm = sublist->header;
+ }
+
while(elm) {
UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
if(listbox->getvalue) {
@@ -2020,9 +2593,25 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
item.label = strdup(elm);
}
+ if(item.label == NULL && index == -1 && sublist->header) {
+ item.label = strdup(sublist->header);
+ }
+
// create listbox item
- GtkWidget *row = create_listbox_row(listbox, sublist, &item, (int)index);
- if(index == 0) {
+ GtkWidget *row = gtk_list_box_row_new();
+#if GTK_CHECK_VERSION(4, 0, 0)
+ GtkEventController *motion_controller = gtk_event_controller_motion_new();
+ gtk_widget_add_controller(GTK_WIDGET(row), motion_controller);
+ g_signal_connect(motion_controller, "enter", G_CALLBACK(listbox_row_enter), row);
+ g_signal_connect(motion_controller, "leave", G_CALLBACK(listbox_row_leave), row);
+#else
+ gtk_widget_set_events(GTK_WIDGET(row), GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+ g_signal_connect(row, "enter-notify-event", G_CALLBACK(listbox_row_enter), NULL);
+ g_signal_connect(row, "leave-notify-event", G_CALLBACK(listbox_row_leave), NULL);
+#endif
+
+ listbox_fill_row(listbox, row, sublist, &item, index);
+ if(index == first_index) {
// first row in the sublist, set ui_listbox data to the row
// which is then used by the headerfunc
g_object_set_data(G_OBJECT(row), "ui_listbox", listbox);
@@ -2033,9 +2622,9 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
listbox->first_row = GTK_LIST_BOX_ROW(row);
}
}
- intptr_t rowindex = listbox_insert_index + index;
- g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex);
- gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index);
+ //intptr_t rowindex = listbox_insert_index + index;
+ //g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex);
+ gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index + header_row);
cxListAdd(sublist->widgets, row);
// cleanup
@@ -2046,7 +2635,7 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
free(item.badge);
// next row
- elm = list->next(list);
+ elm = index >= 0 ? list->next(list) : first;
index++;
}
@@ -2055,6 +2644,19 @@ void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, si
void ui_listbox_list_update(UiList *list, int i) {
UiListBoxSubList *sublist = list->obj;
+ if(i < 0) {
+ ui_listbox_update_sublist(sublist->listbox, sublist, sublist->startpos);
+ size_t pos = 0;
+ CxIterator it = cxListIterator(sublist->listbox->sublists);
+ cx_foreach(UiListBoxSubList *, ls, it) {
+ ls->startpos = pos;
+ pos += ls->numitems;
+ }
+ } else {
+ update_sublist_item(sublist->listbox, sublist, i);
+ }
+
+ ui_sourcelist_update_finished();
}
void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) {
@@ -2069,7 +2671,7 @@ void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user
eventdata.sublist_index = sublist->index;
eventdata.row_index = data->value0;
eventdata.sublist_userdata = sublist->userdata;
- eventdata.row_data = eventdata.list->get(eventdata.list, eventdata.row_index);
+ eventdata.row_data = eventdata.row_index >= 0 ? eventdata.list->get(eventdata.list, eventdata.row_index) : NULL;
eventdata.event_data = data->customdata2;
UiEvent event;
diff --git a/ui/gtk/list.h b/ui/gtk/list.h
index bd490ab..1aaf89b 100644
--- a/ui/gtk/list.h
+++ b/ui/gtk/list.h
@@ -40,17 +40,36 @@ extern "C" {
typedef struct UiColData UiColData;
+#if GTK_CHECK_VERSION(4, 10, 0)
+typedef struct UiRowItems {
+ int bound;
+ GtkListItem *items[];
+} UiRowItems;
+#endif
+
typedef struct UiListView {
UiObject *obj;
GtkWidget *widget;
UiVar *var;
UiModel *model;
+ ui_getvaluefunc2 getvalue;
+ void *getvaluedata;
+ ui_getstylefunc getstyle;
+ void *getstyledata;
char **elements;
size_t nelm;
+ int current_row;
+ UiTextStyle row_style;
+ UiBool apply_row_style;
#if GTK_CHECK_VERSION(4, 10, 0)
+ CxMap *bound_rows;
GListStore *liststore;
GtkSelectionModel *selectionmodel;
UiColData *columns;
+ int numcolumns;
+ PangoAttrList *current_row_attributes;
+#else
+ int style_offset;
#endif
ui_callback onactivate;
void *onactivatedata;
@@ -62,6 +81,8 @@ typedef struct UiListView {
void *ondragcompletedata;
ui_callback ondrop;
void *ondropdata;
+ ui_list_savefunc onsave;
+ void *onsavedata;
UiListSelection selection;
} UiListView;
@@ -91,6 +112,7 @@ typedef struct UiListBoxSubList {
UiListBox *listbox;
void *userdata;
size_t index;
+ size_t startpos;
} UiListBoxSubList;
struct UiListBox {
@@ -104,6 +126,8 @@ struct UiListBox {
ui_callback onbuttonclick;
void *onbuttonclickdata;
GtkListBoxRow *first_row;
+ UiBool header_is_item;
+ UiSubListEventData current_eventdata;
};
diff --git a/ui/gtk/menu.c b/ui/gtk/menu.c
index 521bf91..74597ae 100644
--- a/ui/gtk/menu.c
+++ b/ui/gtk/menu.c
@@ -33,6 +33,7 @@
#include "menu.h"
#include "toolkit.h"
+#include "widget.h"
#include "../common/context.h"
#include "../common/menu.h"
#include "../common/types.h"
@@ -42,6 +43,7 @@
#include
#include
+#include
#if GTK_MAJOR_VERSION <= 3
@@ -135,44 +137,6 @@ void add_menuitem_widget(GtkWidget *parent, int index, UiMenuItemI *item, UiObje
}
}
-/*
-void add_menuitem_st_widget(
- GtkWidget *parent,
- int index,
- UiMenuItemI *item,
- UiObject *obj)
-{
- UiStMenuItem *i = (UiStMenuItem*)item;
-
- GtkWidget *widget = gtk_image_menu_item_new_from_stock(i->stockid, obj->ctx->accel_group);
-
- if(i->callback != NULL) {
- UiEventData *event = malloc(sizeof(UiEventData));
- event->obj = obj;
- event->userdata = i->userdata;
- event->callback = i->callback;
- event->value = 0;
-
- g_signal_connect(
- widget,
- "activate",
- G_CALLBACK(ui_menu_event_wrapper),
- event);
- g_signal_connect(
- widget,
- "destroy",
- G_CALLBACK(ui_destroy_userdata),
- event);
- }
-
- gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget);
-
- if(i->groups) {
- uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups);
- }
-}
-*/
-
void add_menuseparator_widget(
GtkWidget *parent,
int index,
@@ -214,25 +178,6 @@ void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *
// TODO
}
-/*
-void add_checkitemnv_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
- UiCheckItemNV *ci = (UiCheckItemNV*)item;
- GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label);
- gtk_menu_shell_append(GTK_MENU_SHELL(p), widget);
-
- UiVar *var = uic_create_var(obj->ctx, ci->varname, UI_VAR_INTEGER);
- if(var) {
- UiInteger *value = var->value;
- value->obj = widget;
- value->get = ui_checkitem_get;
- value->set = ui_checkitem_set;
- value = 0;
- } else {
- // TODO: error
- }
-}
-*/
-
static void menuitem_list_remove_binding(void *obj) {
UiActiveMenuItemList *ls = obj;
UiList *list = ls->var->value;
@@ -261,8 +206,8 @@ void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObje
ls->oldcount = 0;
ls->getvalue = il->getvalue;
- //UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
- UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
+ UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
+ //UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
ls->var = var;
if(var) {
UiList *list = var->value;
@@ -339,6 +284,7 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) {
event->callback = list->callback;
event->value = i - 1;
event->customdata = elm;
+ event->customint = UI_EVENT_DATA_LIST_ELM;
g_signal_connect(
widget,
@@ -364,9 +310,17 @@ void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) {
evt.obj = event->obj;
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
+ if(event->customdata) {
+ evt.eventdata = event->customdata;
+ evt.eventdatatype = event->customint;
+ } else {
+ evt.eventdata = uic_get_tmp_eventdata();
+ evt.eventdatatype = uic_get_tmp_eventdata_type();
+ }
evt.eventdata = event->customdata;
evt.intval = event->value;
- event->callback(&evt, event->userdata);
+ event->callback(&evt, event->userdata);
+ uic_set_tmp_eventdata(NULL, 0);
}
void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) {
@@ -468,6 +422,9 @@ void ui_gmenu_add_menu_items(GMenu *parent, int i, UiMenu *menu, UiObject *obj)
GMenu *section = NULL;
while(it) {
if(it->type == UI_MENU_SEPARATOR) {
+ if(section) {
+ g_object_unref(section);
+ }
section = g_menu_new();
g_menu_append_section(parent, NULL, G_MENU_MODEL(section));
index++;
@@ -481,6 +438,9 @@ void ui_gmenu_add_menu_items(GMenu *parent, int i, UiMenu *menu, UiObject *obj)
}
it = it->next;
}
+ if(section) {
+ g_object_unref(section);
+ }
}
void ui_gmenu_add_menu(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) {
@@ -488,6 +448,7 @@ void ui_gmenu_add_menu(GMenu *parent, int index, UiMenuItemI *item, UiObject *ob
GMenu *menu = g_menu_new();
ui_gmenu_add_menu_items(menu, 0, mi, obj);
g_menu_append_submenu(parent, mi->label, G_MENU_MODEL(menu));
+ g_object_unref(menu);
}
static void action_enable(GSimpleAction *action, int enabled) {
@@ -499,6 +460,7 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
GSimpleAction *action = g_simple_action_new(item->id, NULL);
g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
+ g_object_unref(action);
if(i->groups) {
CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups);
@@ -529,7 +491,8 @@ void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject
}
char action_name[32];
- snprintf(action_name, 32, "win.%s", item->id);
+ snprintf(action_name, 32, "win.%s", item->id);
+
g_menu_append(parent, i->label, action_name);
}
@@ -543,8 +506,161 @@ void ui_gmenu_add_checkitem(GMenu *p, int index, UiMenuItemI *item, UiObject *ob
// TODO
}
-void ui_gmenu_add_radioitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) {
+
+
+typedef struct UiCallbackData {
+ ui_callback callback;
+ void *userdata;
+} UiCallbackData;
+
+static void radiogroup_remove_binding(void *obj) {
+ UiMenuRadioGroup *group = obj;
+ if(group->var) {
+ UiInteger *i = group->var->value;
+ CxList *bindings = i->obj;
+ if(bindings) {
+ (void)cxListFindRemove(bindings, obj);
+ }
+ }
+}
+
+static void stateful_action_notify_group(UiMenuRadioGroup *group, UiInteger *i) {
+ UiEvent event;
+ event.obj = group->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = NULL;
+ event.eventdatatype = 0;
+ event.intval = (int)i->value;
+ event.set = ui_get_setop();
+
+ CxIterator iter = cxListIterator(group->callbacks);
+ cx_foreach(UiCallbackData *, cb, iter) {
+ if(cb->callback) {
+ cb->callback(&event, cb->userdata);
+ }
+ }
+
+ UiObserver *obs = i->observers;
+ while(obs) {
+ if(obs->callback) {
+ obs->callback(&event, obs->data);
+ }
+ obs = obs->next;
+ }
+}
+
+static void ui_action_set_state(UiInteger *i, int64_t value) {
+ i->value = value;
+ CxList *bindings = i->obj;
+ CxIterator iter = cxListIterator(bindings);
+ cx_foreach(UiMenuRadioGroup *, group, iter) {
+ char buf[32];
+ snprintf(buf, 32, "%d", (int)value);
+ GVariant *state = g_variant_new_string(buf);
+ g_action_change_state(G_ACTION(group->action), state);
+ stateful_action_notify_group(group, i);
+ }
+}
+
+static int64_t ui_action_get_state(UiInteger *i) {
+ return i->value;
+}
+
+static UiMenuRadioGroup* create_radio_group(UiObject *obj, UiMenuRadioItem *item, GSimpleAction *action) {
+ UiMenuRadioGroup *group = cxZalloc(obj->ctx->allocator, sizeof(UiMenuRadioGroup));
+ group->callbacks = cxArrayListCreate(obj->ctx->allocator, NULL, sizeof(UiCallbackData), 8);
+ group->var = uic_create_var(ui_global_context(), item->varname, UI_VAR_INTEGER);
+ group->obj = obj;
+ group->action = action;
+ if(group->var) {
+ UiInteger *i = group->var->value;
+ CxList *bindings = i->obj;
+ if(!bindings) {
+ bindings = cxLinkedListCreate(group->var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS);
+ i->obj = bindings;
+ i->set = ui_action_set_state;
+ i->get = ui_action_get_state;
+ }
+ cxListAdd(bindings, group);
+ // the destruction of the toplevel obj must remove the binding
+ uic_context_add_destructor(obj->ctx, radiogroup_remove_binding, group);
+ }
+ return group;
+}
+
+static void stateful_action_activate(
+ GSimpleAction *action,
+ GVariant *state,
+ UiMenuRadioGroup *group)
+{
+ g_simple_action_set_state(action, state);
+
+ UiVar *var = group->var;
+ if(!var) {
+ return;
+ }
+ UiInteger *i = var->value;
+
+ gsize len;
+ const char *s = g_variant_get_string(state, &len);
+ cxstring value = cx_strn(s, len);
+ int v;
+ if(!cx_strtoi(value, &v, 10)) {
+ i->value = v;
+ }
+
+ CxList *bindings = i->obj;
+ CxIterator iter = cxListIterator(bindings);
+ cx_foreach(UiMenuRadioGroup *, gr, iter) {
+ stateful_action_notify_group(gr, i);
+ }
+}
+
+
+void ui_gmenu_add_radioitem(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) {
+ UiMenuRadioItem *i = (UiMenuRadioItem*)item;
+
+ if(!i->varname) {
+ return;
+ }
+
+ // All radio buttons with the name varname use the same GAction
+ UiMenuRadioGroup *group = NULL;
+ GAction *action = g_action_map_lookup_action(obj->ctx->action_map, i->varname);
+ if(!action) {
+ GVariant *state = g_variant_new_string("0");
+ GSimpleAction *newAction = g_simple_action_new_stateful(i->varname, G_VARIANT_TYPE_STRING, state);
+ g_action_map_add_action(obj->ctx->action_map, G_ACTION(newAction));
+ g_object_unref(newAction);
+
+ group = create_radio_group(obj, i, newAction);
+ g_object_set_data(G_OBJECT(newAction), "ui_radiogroup", group);
+
+ g_signal_connect(
+ newAction,
+ "change-state",
+ G_CALLBACK(stateful_action_activate),
+ group);
+ } else {
+ group = g_object_get_data(G_OBJECT(action), "ui_radiogroup");
+ if(!group) {
+ fprintf(stderr, "Error: missing ui_radiogroup property for action %s\n", i->varname);
+ return; // error, should not happen
+ }
+ }
+
+ size_t item_index = cxListSize(group->callbacks);
+ UiCallbackData cb;
+ cb.callback = i->callback;
+ cb.userdata = i->userdata;
+ cxListAdd(group->callbacks, &cb);
+
+
+ cxmutstr action_name = cx_asprintf("win.%s::%d", i->varname, (int)item_index);
+ g_menu_append(parent, i->label, action_name.ptr);
+ free(action_name.ptr);
}
static void menuitem_list_remove_binding(void *obj) {
@@ -576,8 +692,13 @@ void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject
ls->oldcount = 0;
ls->getvalue = il->getvalue;
- //UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
- UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
+ GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i"));
+ g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
+ g_object_unref(action);
+ snprintf(ls->action, 32, "win.%s", item->id);
+
+ UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
+ //UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
ls->var = var;
if(var) {
UiList *list = var->value;
@@ -604,10 +725,6 @@ void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject
ls->callback = il->callback;
ls->userdata = il->userdata;
- GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i"));
- g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));
- snprintf(ls->action, 32, "win.%s", item->id);
-
UiEventData *event = malloc(sizeof(UiEventData));
event->obj = obj;
@@ -639,10 +756,16 @@ void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEvent
evt.obj = event->obj;
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
- evt.eventdata = event->customdata;
- evt.eventdatatype = event->customint;
+ if(event->customdata) {
+ evt.eventdata = event->customdata;
+ evt.eventdatatype = event->customint;
+ } else {
+ evt.eventdata = uic_get_tmp_eventdata();
+ evt.eventdatatype = uic_get_tmp_eventdata_type();
+ }
evt.intval = intval;
- event->callback(&evt, event->userdata);
+ event->callback(&evt, event->userdata);
+ uic_set_tmp_eventdata(NULL, 0);
}
void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) {
@@ -650,6 +773,10 @@ void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* par
UiVar *var = event->customdata;
UiList *list = var->value;
+ if(!event->callback) {
+ return;
+ }
+
UiEvent evt;
evt.obj = event->obj;
evt.window = event->obj->window;
@@ -687,6 +814,7 @@ void ui_update_gmenu_item_list(UiActiveGMenuItemList *list) {
GVariant *v = g_variant_new("i", i);
g_menu_item_set_action_and_target_value(item, list->action, v);
g_menu_insert_item(list->menu, list->index+i, item);
+ g_object_unref(item);
elm = ui_list_next(ls);
i++;
@@ -706,6 +834,7 @@ UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, GtkWidget *w
GMenu *menu = g_menu_new();
ui_gmenu_add_menu_items(menu, 0, builder->menus_begin, obj);
GtkWidget *contextmenu = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
+ g_object_unref(menu);
gtk_popover_set_has_arrow(GTK_POPOVER(contextmenu), FALSE);
gtk_widget_set_halign(contextmenu, GTK_ALIGN_START);
gtk_widget_set_parent(GTK_WIDGET(contextmenu), widget);
diff --git a/ui/gtk/menu.h b/ui/gtk/menu.h
index dc6240c..a7f65e7 100644
--- a/ui/gtk/menu.h
+++ b/ui/gtk/menu.h
@@ -98,6 +98,14 @@ struct UiActiveGMenuItemList {
void *userdata;
};
+typedef struct UiMenuRadioGroup {
+ UiObject *obj;
+ CxList *callbacks;
+ UiVar *var;
+ GSimpleAction *action;
+} UiMenuRadioGroup;
+
+
void ui_gmenu_add_menu_items(GMenu *parent, int i, UiMenu *menu, UiObject *obj);
void ui_gmenu_add_menu(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj);
diff --git a/ui/gtk/range.c b/ui/gtk/range.c
index 45c5bfc..e33b24a 100644
--- a/ui/gtk/range.c
+++ b/ui/gtk/range.c
@@ -76,8 +76,10 @@ static UIWIDGET ui_scrollbar(UiObject *obj, UiOrientation orientation, UiRange *
event);
}
- UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, scrollbar);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ //UiLayout layout = UI_ARGS2LAYOUT(args);
+ UiLayout layout = {0};
+ ct->add(ct, scrollbar, &layout);
return scrollbar;
}
@@ -126,7 +128,7 @@ void ui_scrollbar_setextent(UiRange *range, double extent) {
#else
gtk_adjustment_set_page_size(a, extent);
#endif
-#if GTK_MAJOR_VERSION * 100 + GTK_MIMOR_VERSION < 318
+#if !GTK_CHECK_VERSION(3, 18, 0)
gtk_adjustment_changed(a);
#endif
range->extent = extent;
diff --git a/ui/gtk/text.c b/ui/gtk/text.c
index 9ea0c4c..0859642 100644
--- a/ui/gtk/text.c
+++ b/ui/gtk/text.c
@@ -108,8 +108,7 @@ static GtkTextBuffer* create_textbuffer(UiTextArea *textarea) {
}
UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
- UiObject* current = uic_current_obj(obj);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_TEXT);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_TEXT);
GtkWidget *text_area = gtk_text_view_new();
ui_set_name_and_style(text_area, args->name, args->style_class);
@@ -145,6 +144,18 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
SCROLLEDWINDOW_SET_CHILD(scroll_area, text_area);
+ if(args->width > 0 || args->height > 0) {
+ int width = args->width;
+ int height = args->height;
+ if(width == 0) {
+ width = -1;
+ }
+ if(height == 0) {
+ height = -1;
+ }
+ gtk_widget_set_size_request(scroll_area, width, height);
+ }
+
// font and padding
//PangoFontDescription *font;
//font = pango_font_description_from_string("Monospace");
@@ -155,8 +166,9 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs *args) {
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text_area), 2);
// add
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, scroll_area);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, scroll_area, &layout);
// bind value
if(var) {
@@ -598,8 +610,7 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
ui_set_name_and_style(textfield, args->name, args->style_class);
ui_set_widget_groups(obj->ctx, textfield, args->groups);
- UiObject* current = uic_current_obj(obj);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
UiTextField *uitext = malloc(sizeof(UiTextField));
uitext->obj = obj;
@@ -616,10 +627,11 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
uitext);
if(args->width > 0) {
- // TODO: gtk4
-#if GTK_MAJOR_VERSION <= 3
- gtk_entry_set_width_chars(GTK_ENTRY(textfield), args->width);
-#endif
+ // An early implementation used gtk_entry_set_width_chars,
+ // but that is not available on gtk4 and other toolkits
+ // also don't have this. Setting the width in pixels can
+ // be implemented on all platforms
+ gtk_widget_set_size_request(textfield, args->width, -1);
}
if(frameless) {
// TODO: gtk2legacy workaroud
@@ -629,8 +641,9 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor
gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE);
}
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, textfield);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, textfield, &layout);
if(var) {
UiString *value = var->value;
@@ -921,8 +934,6 @@ static gboolean ui_path_textfield_key_controller(
}
UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
UiPathTextField *pathtf = malloc(sizeof(UiPathTextField));
memset(pathtf, 0, sizeof(UiPathTextField));
pathtf->obj = obj;
@@ -945,8 +956,9 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
pathtf->stack = gtk_stack_new();
gtk_widget_set_name(pathtf->stack, "path-textfield-box");
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, pathtf->stack);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, pathtf->stack, &layout);
pathtf->entry_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
pathtf->entry = gtk_entry_new();
@@ -978,7 +990,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
gtk_stack_set_visible_child(GTK_STACK(pathtf->stack), pathtf->entry_box);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if (var) {
UiString* value = (UiString*)var->value;
value->obj = pathtf;
@@ -1082,8 +1094,6 @@ static GtkWidget* create_path_button_box() {
}
UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
UiPathTextField *pathtf = malloc(sizeof(UiPathTextField));
memset(pathtf, 0, sizeof(UiPathTextField));
pathtf->obj = obj;
@@ -1117,8 +1127,9 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
G_CALLBACK(ui_path_textfield_destroy),
pathtf);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, eventbox, FALSE);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, eventbox, &layout);
// hbox as parent for the GtkEntry and GtkButtonBox
GtkWidget *hbox = ui_gtk_hbox_new(0);
@@ -1142,7 +1153,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
G_CALLBACK(ui_path_textfield_key_press),
pathtf);
- UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_STRING);
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if (var) {
UiString* value = (UiString*)var->value;
value->obj = pathtf;
diff --git a/ui/gtk/toolbar.c b/ui/gtk/toolbar.c
index 0409be9..64b221a 100644
--- a/ui/gtk/toolbar.c
+++ b/ui/gtk/toolbar.c
@@ -128,15 +128,9 @@ static void set_toolbutton_icon(GtkToolItem *item, const char *icon_name) {
void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) {
GtkToolItem *button;
- if(item->args.stockid) {
-#ifdef UI_GTK2
- button = gtk_tool_button_new_from_stock(item->args.stockid);
-#else
- // TODO: gtk3 stock
- button = gtk_tool_button_new(NULL, item->args.label);
-#endif
- } else {
- button = gtk_tool_button_new(NULL, item->args.label);
+ button = gtk_tool_button_new(NULL, item->args.label);
+ if(item->args.tooltip) {
+ gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), item->args.tooltip);
}
gtk_tool_item_set_homogeneous(button, FALSE);
@@ -176,21 +170,16 @@ void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) {
void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObject *obj) {
GtkToolItem *button;
- if(item->args.stockid) {
-#ifdef UI_GTK2
- button = gtk_toggle_tool_button_new_from_stock(item->args.stockid);
-#else
- button = gtk_toggle_tool_button_new_from_stock(item->args.stockid); // TODO: gtk3 stock
-#endif
- } else {
- button = gtk_toggle_tool_button_new();
- gtk_tool_item_set_homogeneous(button, FALSE);
- if(item->args.label) {
- gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->args.label);
- }
- if(item->args.icon) {
- set_toolbutton_icon(button, item->args.icon);
- }
+ button = gtk_toggle_tool_button_new();
+ gtk_tool_item_set_homogeneous(button, FALSE);
+ if(item->args.label) {
+ gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->args.label);
+ }
+ if(item->args.icon) {
+ set_toolbutton_icon(button, item->args.icon);
+ }
+ if(item->args.tooltip) {
+ gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), item->args.tooltip);
}
ui_set_widget_ngroups(obj->ctx, GTK_WIDGET(button), item->args.groups, item->ngroups);
@@ -282,21 +271,15 @@ static void ui_toolbar_menubutton_destroy(GtkWidget *widget, UiToolbarMenuWidget
void add_toolitem_menu_widget(GtkToolbar *tb, UiToolbarMenuItem *item, UiObject *obj) {
GtkToolItem *button;
- if(item->args.stockid) {
-#ifdef UI_GTK2
- button = gtk_tool_button_new_from_stock(item->args.stockid);
-#else
- // TODO: gtk3 stock
- button = gtk_tool_button_new(NULL, item->args.label);
-#endif
- } else {
- button = gtk_tool_button_new(NULL, item->args.label);
- }
+ button = gtk_tool_button_new(NULL, item->args.label);
gtk_tool_item_set_homogeneous(button, FALSE);
if(item->args.icon) {
set_toolbutton_icon(button, item->args.icon);
}
+ if(item->args.tooltip) {
+ gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), item->args.tooltip);
+ }
gtk_tool_item_set_is_important(button, TRUE);
gtk_toolbar_insert(tb, button, -1);
diff --git a/ui/gtk/toolkit.c b/ui/gtk/toolkit.c
index 7a26a70..87d1ef1 100644
--- a/ui/gtk/toolkit.c
+++ b/ui/gtk/toolkit.c
@@ -40,7 +40,6 @@
#include "../common/toolbar.h"
#include "../common/threadpool.h"
-#include
#include
#include
@@ -66,6 +65,8 @@ static UiObject *active_window;
static int scale_factor = 1;
+static UiBool exit_on_shutdown;
+
UIEXPORT void ui_init(const char *appname, int argc, char **argv) {
application_name = appname;
uic_init_global_context();
@@ -77,7 +78,6 @@ UIEXPORT void ui_init(const char *appname, int argc, char **argv) {
#endif
ui_css_init();
- uic_docmgr_init();
uic_menu_init();
uic_toolbar_init();
ui_image_init();
@@ -110,8 +110,11 @@ void ui_onexit(ui_callback f, void *userdata) {
exit_data = userdata;
}
+void ui_app_exit_on_shutdown(UiBool exitapp) {
+ exit_on_shutdown = exitapp;
+}
-#ifndef UI_GTK2
+#ifdef UI_APPLICATION
static void app_startup(GtkApplication* app, gpointer userdata) {
if(startup_func) {
startup_func(NULL, startup_data);
@@ -119,8 +122,16 @@ static void app_startup(GtkApplication* app, gpointer userdata) {
}
static void app_activate(GtkApplication* app, gpointer userdata) {
- printf("activate\n");
+ //printf("activate\n");
+}
+
+static void app_shutdown(GtkApplication *app, gpointer userdata) {
+ if(exit_func) {
+ exit_func(NULL, exit_data);
+ }
+ ui_app_save_settings();
}
+
#endif
void ui_main() {
@@ -130,6 +141,7 @@ void ui_main() {
application_name ? application_name : "application1");
app = UI_APPLICATION_NEW(appid.ptr);
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
+ g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), NULL);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
g_application_run(G_APPLICATION (app), 0, NULL);
g_object_unref (app);
@@ -140,11 +152,14 @@ void ui_main() {
startup_func(NULL, startup_data);
}
gtk_main();
-#endif
if(exit_func) {
exit_func(NULL, exit_data);
}
- uic_store_app_properties();
+ ui_app_save_settings();
+#endif
+ if(exit_on_shutdown) {
+ exit(0);
+ }
}
#ifndef UI_GTK2
@@ -306,15 +321,15 @@ void ui_destroy_widget_var(GtkWidget *object, UiVar *var) {
ui_destroy_boundvar(NULL, var);
}
+// TODO: move to common
void ui_destroy_boundvar(UiContext *ctx, UiVar *var) {
+ uic_save_var(var);
uic_unbind_var(var);
+ // UI_VAR_SPECIAL: anonymous value variable, that is not registered
+ // in ctx->vars
if(var->type == UI_VAR_SPECIAL) {
ui_free(var->from_ctx, var);
- } else {
- ui_free(var->from_ctx, var);
- // TODO: free or unbound
- //uic_remove_bound_var(ctx, var);
}
}
@@ -378,6 +393,26 @@ static const char *ui_gtk_css =
" margin-top: 4px;\n"
" margin-bottom: 10px;\n"
"}\n"
+".ui-listbox-header-row {\n"
+" font-weight: bold;\n"
+"}\n"
+".ui-badge {\n"
+" background-color: #e53935;\n"
+" color: white;\n"
+" border-radius: 9999px;\n"
+" padding: 0px 10px 0px 10px;\n"
+" font-weight: bold;\n"
+" margin-left: 4px;"
+" margin-right: 4px;"
+"}\n"
+".ui-nopadding {"
+" padding: 0;"
+"}\n"
+".ui-table-entry {"
+" border: none;"
+" box-shadow: none;"
+" background: transparent;"
+"}\n"
;
#elif GTK_MAJOR_VERSION == 3
@@ -411,6 +446,21 @@ static const char *ui_gtk_css =
" margin-top: 4px;\n"
" margin-bottom: 10px;\n"
"}\n"
+".ui-listbox-header-row {\n"
+" font-weight: bold;\n"
+"}\n"
+".ui-badge {\n"
+" background-color: #e53935;\n"
+" color: white;\n"
+" border-radius: 9999px;\n"
+" padding: 0px 10px 0px 10px;\n"
+" font-weight: bold;\n"
+" margin-left: 4px;"
+" margin-right: 4px;"
+"}\n"
+".ui-nopadding {"
+" padding: 0;"
+"}\n"
;
#endif
@@ -493,3 +543,19 @@ void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups,
ui_set_enabled(widget, FALSE);
}
}
+
+void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const int *states) {
+ if(!states) {
+ return;
+ }
+ size_t nstates = uic_group_array_size(states);
+ ui_set_widget_nvisibility_states(ctx, widget, states, nstates);
+}
+
+
+void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups) {
+ if(ngroups > 0) {
+ uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_visible, states, ngroups);
+ ui_set_visible(widget, FALSE);
+ }
+}
diff --git a/ui/gtk/toolkit.h b/ui/gtk/toolkit.h
index b66c695..cfa25bb 100644
--- a/ui/gtk/toolkit.h
+++ b/ui/gtk/toolkit.h
@@ -74,6 +74,7 @@ extern "C" {
#define ICON_IMAGE(icon) gtk_image_new_from_icon_name(icon)
#define LISTBOX_REMOVE(listbox, row) gtk_list_box_remove(GTK_LIST_BOX(listbox), row)
#define LISTBOX_ROW_SET_CHILD(row, child) gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), child)
+#define LISTBOX_ROW_REMOVE_CHILD(row) gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), NULL)
#define PANED_SET_CHILD1(paned, child) gtk_paned_set_start_child(GTK_PANED(paned), child)
#define PANED_SET_CHILD2(paned, child) gtk_paned_set_end_child(GTK_PANED(paned), child)
#else
@@ -96,6 +97,7 @@ extern "C" {
#define ICON_IMAGE(icon) gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_BUTTON)
#define LISTBOX_REMOVE(listbox, row) gtk_container_remove(GTK_CONTAINER(listbox), row)
#define LISTBOX_ROW_SET_CHILD(row, child) gtk_container_add(GTK_CONTAINER(row), child)
+#define LISTBOX_ROW_REMOVE_CHILD(row) gtk_container_remove(GTK_CONTAINER(row), gtk_bin_get_child(GTK_BIN(row)))
#define PANED_SET_CHILD1(paned, child) gtk_paned_pack1(GTK_PANED(paned), child, TRUE, TRUE)
#define PANED_SET_CHILD2(paned, child) gtk_paned_pack2(GTK_PANED(paned), child, TRUE, TRUE)
#endif
@@ -178,6 +180,8 @@ int ui_get_scalefactor();
void ui_set_name_and_style(GtkWidget *widget, const char *name, const char *style);
void ui_set_widget_groups(UiContext *ctx, GtkWidget *widget, const int *groups);
void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, size_t ngroups);
+void ui_set_widget_visibility_states(UiContext *ctx, GtkWidget *widget, const int *states);
+void ui_set_widget_nvisibility_states(UiContext *ctx, GtkWidget *widget, const int *states, size_t ngroups);
void ui_destroy_userdata(GtkWidget *object, void *userdata);
void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data);
diff --git a/ui/gtk/webview.c b/ui/gtk/webview.c
index 3b9a946..f8f5718 100644
--- a/ui/gtk/webview.c
+++ b/ui/gtk/webview.c
@@ -34,13 +34,11 @@
#ifdef UI_WEBVIEW
UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
GtkWidget *webview = webkit_web_view_new();
ui_set_name_and_style(webview, args->name, args->style_class);
- UiVar *var = uic_widget_var(obj->ctx, current->ctx, args->value, args->varname, UI_VAR_GENERIC);
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_GENERIC);
if(var) {
WebViewData *data = malloc(sizeof(WebViewData));
memset(data, 0, sizeof(WebViewData));
@@ -55,13 +53,14 @@ UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args) {
value->set = ui_webview_set;
value->obj = data;
if(value->value && value->type && !strcmp(value->type, UI_WEBVIEW_OBJECT_TYPE)) {
- // TODO
+ ui_webview_set(value, value->value, UI_WEBVIEW_OBJECT_TYPE);
}
}
ui_set_widget_groups(obj->ctx, webview, args->groups);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, webview);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, webview, &layout);
return webview;
}
@@ -97,13 +96,13 @@ int ui_webview_set(UiGeneric *g, void *value, const char *type) {
}
ui_webview_enable_javascript(g, data->javascript);
- webkit_web_view_set_zoom_level(data->webview, data->zoom);
+ ui_webview_set_zoom(g, data->zoom);
return 0;
}
void ui_webview_load_url(UiGeneric *g, const char *url) {
- WebViewData data = { .uri = (char*)url, .type = WEBVIEW_CONTENT_URL };
+ WebViewData data = { .uri = (char*)url, .type = WEBVIEW_CONTENT_URL, .javascript = TRUE, .zoom = 1 };
g->set(g, &data, UI_WEBVIEW_OBJECT_TYPE);
}
@@ -129,6 +128,8 @@ void ui_webview_load_content(
data.mimetype = (char*)mimetype;
data.encoding = (char*)encoding;
data.type = WEBVIEW_CONTENT_CONTENT;
+ data.javascript = FALSE;
+ data.zoom = 1;
g->set(g, &data, UI_WEBVIEW_OBJECT_TYPE);
}
diff --git a/ui/gtk/widget.c b/ui/gtk/widget.c
index 36f4465..06ef1b2 100644
--- a/ui/gtk/widget.c
+++ b/ui/gtk/widget.c
@@ -32,22 +32,21 @@
#include "../common/object.h"
UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs *args) {
- UiObject* current = uic_current_obj(obj);
-
UIWIDGET widget = create_widget(obj, args, userdata);
- UI_APPLY_LAYOUT2(current, args);
- current->container->add(current->container, widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
return widget;
}
UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) {
- UiObject* current = uic_current_obj(obj);
GtkWidget *widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
ui_set_name_and_style(widget, args->name, args->style_class);
- UI_APPLY_LAYOUT1(current, (*args));
- current->container->add(current->container, widget);
+ UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+ ct->add(ct, widget, &layout);
return widget;
}
diff --git a/ui/gtk/window.c b/ui/gtk/window.c
index cdafae3..f90997f 100644
--- a/ui/gtk/window.c
+++ b/ui/gtk/window.c
@@ -49,6 +49,9 @@ static int nwindows = 0;
static int window_default_width = 650;
static int window_default_height = 550;
+static int splitview_window_default_pos = -1;
+static UiBool splitview_window_use_prop = TRUE;
+
static gboolean ui_window_destroy(void *data) {
UiObject *obj = data;
uic_object_destroy(obj);
@@ -77,6 +80,36 @@ void ui_exit_event(GtkWidget *widget, gpointer data) {
}
static gboolean ui_window_close_request(UiObject *obj) {
+ if(obj->widget) {
+ void *appwindow = g_object_get_data(G_OBJECT(obj->widget), "ui.appwindow");
+ if(appwindow) {
+ int width = 0;
+ int height = 0;
+#if GTK_CHECK_VERSION(4, 10, 0)
+ graphene_rect_t bounds;
+ if(gtk_widget_compute_bounds(obj->widget, obj->widget, &bounds)) {
+ width = bounds.size.width;
+ height = bounds.size.height;
+ }
+#elif GTK_CHECK_VERSION(4, 0, 0)
+ GtkAllocation alloc;
+ gtk_widget_get_allocation(GTK_WIDGET(obj->widget), &alloc);
+ width = alloc.width;
+ height = alloc.height;
+#else
+ gtk_window_get_size(GTK_WINDOW(obj->widget), &width, &height);
+#endif
+ if(width > 0 && height > 0) {
+ char width_str[32];
+ char height_str[32];
+ snprintf(width_str, 32, "%d", width);
+ snprintf(height_str, 32, "%d", height);
+ ui_set_property("ui.window.width", width_str);
+ ui_set_property("ui.window.height", height_str);
+ }
+ }
+ }
+
uic_context_prepare_close(obj->ctx);
obj->ref--;
if(obj->ref > 0) {
@@ -101,7 +134,14 @@ static gboolean close_request(GtkWidget* self, GdkEvent* event, UiObject *obj) {
}
#endif
-static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool simple) {
+static void save_window_splitview_pos(GtkWidget *widget, void *unused) {
+ int pos = gtk_paned_get_position(GTK_PANED(widget));
+ char buf[32];
+ snprintf(buf, 32, "%d", pos);
+ ui_set_property("ui.window.splitview.pos", buf);
+}
+
+static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool splitview, UiBool simple) {
UiObject *obj = uic_object_new_toplevel();
#ifdef UI_LIBADWAITA
@@ -122,19 +162,28 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
gtk_window_set_title(GTK_WINDOW(obj->widget), title);
}
- const char *width = ui_get_property("ui.window.width");
- const char *height = ui_get_property("ui.window.height");
- if(width && height) {
- gtk_window_set_default_size(
- GTK_WINDOW(obj->widget),
- atoi(width),
- atoi(height));
- } else {
- gtk_window_set_default_size(
- GTK_WINDOW(obj->widget),
- window_default_width + sidebar*250,
- window_default_height);
+ if(!simple) {
+ g_object_set_data(G_OBJECT(obj->widget), "ui.appwindow", obj);
+ }
+
+ int window_width = window_default_width;
+ int window_height = window_default_height;
+ if(!simple) {
+ const char *width = ui_get_property("ui.window.width");
+ const char *height = ui_get_property("ui.window.height");
+ if(width && height) {
+ int w = atoi(width);
+ int h = atoi(height);
+ if(w > 0 && h > 0) {
+ window_width = w;
+ window_height = h;
+ }
+ }
}
+ gtk_window_set_default_size(
+ GTK_WINDOW(obj->widget),
+ window_width,
+ window_height);
obj->destroy = ui_window_widget_destroy;
g_signal_connect(
@@ -161,50 +210,95 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
GtkWidget *toolbar_view = adw_toolbar_view_new();
adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(toolbar_view), vbox);
- GtkWidget *content_box = ui_gtk_vbox_new(0);
- BOX_ADD_EXPAND(GTK_BOX(vbox), content_box);
+ GtkWidget *headerbar_sidebar = NULL;
+ GtkWidget *headerbar_main = adw_header_bar_new();
+ GtkWidget *headerbar_right = NULL;
+
+ GtkWidget *content = toolbar_view;
+ if(splitview) {
+ content = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
+ g_signal_connect(
+ content,
+ "destroy",
+ G_CALLBACK(save_window_splitview_pos),
+ NULL);
+
+ const char *splitview_pos_str = ui_get_property("ui.window.splitview.pos");
+ int pos = splitview_window_default_pos;
+ if(pos < 0) {
+ pos = window_width / 2;
+ }
+ if(splitview_pos_str && splitview_window_use_prop) {
+ int splitview_pos = atoi(splitview_pos_str);
+ if(splitview_pos > 0) {
+ pos = splitview_pos;
+ }
+ }
+ gtk_paned_set_position(GTK_PANED(content), pos);
+
+ GtkWidget *right_panel = adw_toolbar_view_new();
+ GtkWidget *right_vbox = ui_gtk_vbox_new(0);
+ adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(right_panel), right_vbox);
+
+ headerbar_right = adw_header_bar_new();
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_right), FALSE);
+ adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(right_panel), headerbar_right);
+
+ adw_header_bar_set_show_end_title_buttons(ADW_HEADER_BAR(headerbar_main), FALSE);
+
+ gtk_paned_set_start_child(GTK_PANED(content), toolbar_view);
+ gtk_paned_set_end_child(GTK_PANED(content), right_panel);
+
+ g_object_set_data(G_OBJECT(obj->widget), "ui_window_splitview", content);
+ g_object_set_data(G_OBJECT(obj->widget), "ui_left_panel", vbox);
+ g_object_set_data(G_OBJECT(obj->widget), "ui_right_panel", right_vbox);
+ }
+
+ GtkWidget *content_box = vbox;
- GtkWidget *sidebar_headerbar = NULL;
if(sidebar) {
GtkWidget *splitview = adw_overlay_split_view_new();
adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), splitview);
GtkWidget *sidebar_toolbar_view = adw_toolbar_view_new();
adw_overlay_split_view_set_sidebar(ADW_OVERLAY_SPLIT_VIEW(splitview), sidebar_toolbar_view);
- sidebar_headerbar = adw_header_bar_new();
- adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), sidebar_headerbar);
+ headerbar_sidebar = adw_header_bar_new();
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
+ adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), headerbar_sidebar);
- adw_overlay_split_view_set_content(ADW_OVERLAY_SPLIT_VIEW(splitview), toolbar_view);
+ adw_overlay_split_view_set_content(ADW_OVERLAY_SPLIT_VIEW(splitview), content);
g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_toolbar_view);
} else {
- adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), toolbar_view);
+ adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), content);
}
- GtkWidget *headerbar = adw_header_bar_new();
-
const char *show_title = ui_get_property("ui.gtk.window.showtitle");
if(show_title) {
if(!strcmp(show_title, "main") && sidebar) {
- adw_header_bar_set_show_title(ADW_HEADER_BAR(sidebar_headerbar), FALSE);
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
} else if(!strcmp(show_title, "sidebar")) {
- adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar), FALSE);
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE);
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE);
} else if(!strcmp(show_title, "false")) {
- adw_header_bar_set_show_title(ADW_HEADER_BAR(sidebar_headerbar), FALSE);
- adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar), FALSE);
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE);
} else {
fprintf(stderr, "Unknown value '%s' for property ui.gtk.window.showtitle\n", show_title);
- adw_header_bar_set_show_title(ADW_HEADER_BAR(sidebar_headerbar), FALSE);
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), FALSE);
}
} else {
- adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar), FALSE);
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_main), FALSE);
+ if(sidebar) {
+ adw_header_bar_set_show_title(ADW_HEADER_BAR(headerbar_sidebar), TRUE);
+ }
}
- adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar_view), headerbar);
- g_object_set_data(G_OBJECT(obj->widget), "ui_headerbar", headerbar);
+ adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar_view), headerbar_main);
+ g_object_set_data(G_OBJECT(obj->widget), "ui_headerbar", headerbar_main);
if(!simple) {
- ui_fill_headerbar(obj, headerbar);
+ ui_fill_headerbar(obj, headerbar_sidebar, headerbar_main, headerbar_right);
}
#elif GTK_MAJOR_VERSION >= 4
GtkWidget *content_box = ui_gtk_vbox_new(0);
@@ -278,7 +372,8 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
gtk_container_add(GTK_CONTAINER(frame), content_box);
obj->container = ui_box_container(obj, content_box);
*/
- obj->container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX);
+ UiContainerX *container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX);
+ uic_object_push_container(obj, container);
nwindows++;
return obj;
@@ -286,15 +381,19 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
UiObject* ui_window(const char *title, void *window_data) {
- return create_window(title, window_data, FALSE, FALSE);
+ return create_window(title, window_data, FALSE, FALSE, FALSE);
}
UiObject *ui_sidebar_window(const char *title, void *window_data) {
- return create_window(title, window_data, TRUE, FALSE);
+ return create_window(title, window_data, TRUE, FALSE, FALSE);
+}
+
+UIEXPORT UiObject *ui_splitview_window(const char *title, UiBool sidebar) {
+ return create_window(title, NULL, sidebar, TRUE, FALSE);
}
UiObject* ui_simple_window(const char *title, void *window_data) {
- return create_window(title, window_data, FALSE, TRUE);
+ return create_window(title, window_data, FALSE, FALSE, TRUE);
}
void ui_window_size(UiObject *obj, int width, int height) {
@@ -304,6 +403,54 @@ void ui_window_size(UiObject *obj, int width, int height) {
height);
}
+void ui_window_default_size(int width, int height) {
+ window_default_width = width;
+ window_default_height = height;
+}
+
+void ui_splitview_window_set_pos(UiObject *obj, int pos) {
+ GtkWidget *splitview = g_object_get_data(G_OBJECT(obj->widget), "ui_window_splitview");
+ if(splitview) {
+ gtk_paned_set_position(GTK_PANED(splitview), pos);
+ } else {
+ fprintf(stderr, "Error: window has no splitview\n");
+ }
+}
+
+int ui_splitview_window_get_pos(UiObject *obj) {
+ GtkWidget *splitview = g_object_get_data(G_OBJECT(obj->widget), "ui_window_splitview");
+ if(splitview) {
+ return gtk_paned_get_position(GTK_PANED(splitview));
+ } else {
+ fprintf(stderr, "Error: window has no splitview\n");
+ }
+ return 0;
+}
+
+void ui_splitview_window_set_default_pos(int pos) {
+ splitview_window_default_pos = pos;
+}
+
+void ui_splitview_window_use_property(UiBool enable) {
+ splitview_window_use_prop = enable;
+}
+
+UIEXPORT void ui_splitview_window_set_visible(UiObject *obj, int pane, UiBool visible) {
+ GtkWidget *panel = NULL;
+ if(pane == 0) {
+ panel = g_object_get_data(G_OBJECT(obj->widget), "ui_left_panel");
+ } else if(pane == 1) {
+ panel = g_object_get_data(G_OBJECT(obj->widget), "ui_right_panel");
+ }
+
+ if(panel == NULL) {
+ fprintf(stderr, "Error: obj is not a splitview window or invalid pane %d specified\n", pane);
+ return;
+ }
+
+ gtk_widget_set_visible(panel, visible);
+}
+
#ifdef UI_LIBADWAITA
static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *data) {
@@ -313,7 +460,6 @@ static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *
evt.window = evt.obj->window;
evt.eventdata = NULL;
evt.eventdatatype = 0;
- evt.eventdatatype = 0;
evt.intval = 0;
if(!strcmp(response, "btn1")) {
@@ -333,35 +479,35 @@ static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *
}
}
-void ui_dialog_create(UiObject *parent, UiDialogArgs args) {
- AdwDialog *dialog = adw_alert_dialog_new(args.title, args.content);
+void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
+ AdwDialog *dialog = adw_alert_dialog_new(args->title, args->content);
UiEventData *event = malloc(sizeof(UiEventData));
- event->callback = args.result;
- event->userdata = args.resultdata;
+ event->callback = args->result;
+ event->userdata = args->resultdata;
event->customdata = NULL;
event->customint = 0;
event->value = 0;
event->obj = parent;
- if(args.button1_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn1", args.button1_label);
+ if(args->button1_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn1", args->button1_label);
}
- if(args.button2_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn2", args.button2_label);
+ if(args->button2_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "btn2", args->button2_label);
}
- if(args.closebutton_label) {
- adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "close", args.closebutton_label);
+ if(args->closebutton_label) {
+ adw_alert_dialog_add_response(ADW_ALERT_DIALOG(dialog), "close", args->closebutton_label);
adw_alert_dialog_set_close_response(ADW_ALERT_DIALOG(dialog), "close");
}
GtkWidget *entry = NULL;
- if(args.input || args.password) {
+ if(args->input || args->password) {
entry = gtk_entry_new();
- if(args.password) {
+ if(args->password) {
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
}
- if(args.input_value) {
- ENTRY_SET_TEXT(entry, args.input_value);
+ if(args->input_value) {
+ ENTRY_SET_TEXT(entry, args->input_value);
}
adw_alert_dialog_set_extra_child(ADW_ALERT_DIALOG(dialog), entry);
event->customdata = entry;
@@ -410,47 +556,47 @@ static void ui_dialog_response (GtkDialog* self, gint response_id, gpointer user
WINDOW_DESTROY(GTK_WIDGET(self));
}
-void ui_dialog_create(UiObject *parent, UiDialogArgs args) {
+void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
GtkDialog *dialog = GTK_DIALOG(gtk_dialog_new());
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent->widget));
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
GtkWidget *dialog_w = GTK_WIDGET(dialog);
- if(args.title) {
- gtk_window_set_title(GTK_WINDOW(dialog), args.title);
+ if(args->title) {
+ gtk_window_set_title(GTK_WINDOW(dialog), args->title);
}
- if(args.button1_label) {
- gtk_dialog_add_button(dialog, args.button1_label, 1);
+ if(args->button1_label) {
+ gtk_dialog_add_button(dialog, args->button1_label, 1);
}
- if(args.button2_label) {
- gtk_dialog_add_button(dialog, args.button2_label, 2);
+ if(args->button2_label) {
+ gtk_dialog_add_button(dialog, args->button2_label, 2);
}
- if(args.closebutton_label) {
- gtk_dialog_add_button(dialog, args.closebutton_label, 0);
+ if(args->closebutton_label) {
+ gtk_dialog_add_button(dialog, args->closebutton_label, 0);
}
GtkWidget *content_area = gtk_dialog_get_content_area(dialog);
- if(args.content) {
- GtkWidget *label = gtk_label_new(args.content);
+ if(args->content) {
+ GtkWidget *label = gtk_label_new(args->content);
BOX_ADD(content_area, label);
}
GtkWidget *textfield = NULL;
- if(args.input || args.password) {
+ if(args->input || args->password) {
textfield = gtk_entry_new();
- if(args.password) {
+ if(args->password) {
gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE);
}
- if(args.input_value) {
- ENTRY_SET_TEXT(textfield, args.input_value);
+ if(args->input_value) {
+ ENTRY_SET_TEXT(textfield, args->input_value);
}
BOX_ADD(content_area, textfield);
}
UiEventData *event = malloc(sizeof(UiEventData));
event->obj = parent;
- event->callback = args.result;
- event->userdata = args.resultdata;
+ event->callback = args->result;
+ event->userdata = args->resultdata;
event->value = 0;
event->customdata = textfield;
@@ -694,18 +840,6 @@ static void ui_gtkfilechooser(UiObject *obj, GtkFileChooserAction action, unsign
G_CALLBACK(ui_destroy_userdata),
event);
-
- UiEvent evt;
- evt.obj = obj;
- evt.document = evt.obj->ctx->document;
- evt.window = evt.obj->window;
- evt.intval = 0;
-
- UiFileList flist;
- flist.files = NULL;
- flist.nfiles = 0;
- evt.eventdata = &flist;
-
gtk_widget_show(dialog);
}
#endif
@@ -749,18 +883,18 @@ static void ui_dialogwindow_response(GtkDialog* self, gint response_id, gpointer
-UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
+UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
GtkWidget *dialog = DIALOG_NEW();
- if(args.width > 0 || args.height > 0) {
+ if(args->width > 0 || args->height > 0) {
gtk_window_set_default_size(
GTK_WINDOW(dialog),
- args.width,
- args.height);
+ args->width,
+ args->height);
}
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent->widget));
- if(args.modal != UI_OFF) {
+ if(args->modal != UI_OFF) {
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
}
@@ -770,15 +904,15 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
obj->destroy = ui_window_widget_destroy;
nwindows++;
- if(args.title != NULL) {
- gtk_window_set_title(GTK_WINDOW(dialog), args.title);
+ if(args->title != NULL) {
+ gtk_window_set_title(GTK_WINDOW(dialog), args->title);
}
#if ! GTK_CHECK_VERSION(4, 10, 0)
UiEventData *event = malloc(sizeof(UiEventData));
event->obj = obj;
- event->userdata = args.onclickdata;
- event->callback = args.onclick;
+ event->userdata = args->onclickdata;
+ event->callback = args->onclick;
event->value = 0;
event->customdata = NULL;
@@ -815,45 +949,46 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
#endif
GtkWidget *content_vbox = ui_gtk_vbox_new(0);
- obj->container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX);
- if(args.lbutton1 || args.lbutton2 || args.rbutton3 || args.rbutton4) {
+ UiContainerX *container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX);
+ uic_object_push_container(obj, container);
+ if(args->lbutton1 || args->lbutton2 || args->rbutton3 || args->rbutton4) {
#if GTK_CHECK_VERSION(3, 10, 0)
- if(args.titlebar_buttons != UI_OFF) {
+ if(args->titlebar_buttons != UI_OFF) {
GtkWidget *headerbar = gtk_header_bar_new();
gtk_window_set_titlebar(GTK_WINDOW(dialog), headerbar);
- if(args.show_closebutton == UI_OFF) {
+ if(args->show_closebutton == UI_OFF) {
HEADERBAR_SHOW_CLOSEBUTTON(headerbar, FALSE);
}
- if(args.lbutton1) {
- GtkWidget *button = ui_create_button(obj, args.lbutton1, NULL, args.onclick, args.onclickdata, 1, args.default_button == 1);
+ if(args->lbutton1) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 1, args->default_button == 1);
gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 1) {
+ if(args->default_button == 1) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.lbutton2) {
- GtkWidget *button = ui_create_button(obj, args.lbutton2, NULL, args.onclick, args.onclickdata, 2, args.default_button == 2);
+ if(args->lbutton2) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 2, args->default_button == 2);
gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 2) {
+ if(args->default_button == 2) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton4) {
- GtkWidget *button = ui_create_button(obj, args.rbutton4, NULL, args.onclick, args.onclickdata, 4, args.default_button == 4);
+ if(args->rbutton4) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 4, args->default_button == 4);
gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 4) {
+ if(args->default_button == 4) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton3) {
- GtkWidget *button = ui_create_button(obj, args.rbutton3, NULL, args.onclick, args.onclickdata, 3, args.default_button == 3);
+ if(args->rbutton3) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 3, args->default_button == 3);
gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button);
- if(args.default_button == 3) {
+ if(args->default_button == 3) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
@@ -868,21 +1003,21 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
GtkWidget *separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
GtkWidget *grid = ui_create_grid_widget(10, 10);
- GtkWidget *widget = ui_box_set_margin(grid, 16);
+ GtkWidget *widget = ui_gtk_set_margin(grid, 16, 0, 0, 0, 0);
gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
- if(args.lbutton1) {
- GtkWidget *button = ui_create_button(obj, args.lbutton1, NULL, args.onclick, args.onclickdata, 1, args.default_button == 1);
+ if(args->lbutton1) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton1, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 1, args->default_button == 1);
gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1);
- if(args.default_button == 1) {
+ if(args->default_button == 1) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.lbutton2) {
- GtkWidget *button = ui_create_button(obj, args.lbutton2, NULL, args.onclick, args.onclickdata, 2, args.default_button == 2);
+ if(args->lbutton2) {
+ GtkWidget *button = ui_create_button(obj, args->lbutton2, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 2, args->default_button == 2);
gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1);
- if(args.default_button == 2) {
+ if(args->default_button == 2) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
@@ -890,18 +1025,18 @@ UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) {
GtkWidget *space = gtk_label_new(NULL);
gtk_widget_set_hexpand(space, TRUE);
gtk_grid_attach(GTK_GRID(grid), space, 2, 0, 1, 1);
- if(args.rbutton3) {
- GtkWidget *button = ui_create_button(obj, args.rbutton3, NULL, args.onclick, args.onclickdata, 3, args.default_button == 3);
+ if(args->rbutton3) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton3, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 3, args->default_button == 3);
gtk_grid_attach(GTK_GRID(grid), button, 3, 0, 1, 1);
- if(args.default_button == 3) {
+ if(args->default_button == 3) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
}
- if(args.rbutton4) {
- GtkWidget *button = ui_create_button(obj, args.rbutton4, NULL, args.onclick, args.onclickdata, 4, args.default_button == 4);
+ if(args->rbutton4) {
+ GtkWidget *button = ui_create_button(obj, args->rbutton4, NULL, NULL/*tooltip*/, args->onclick, args->onclickdata, 4, args->default_button == 4);
gtk_grid_attach(GTK_GRID(grid), button, 4, 0, 1, 1);
- if(args.default_button == 4) {
+ if(args->default_button == 4) {
WIDGET_ADD_CSS_CLASS(button, "suggested-action");
DEFAULT_BUTTON(dialog, button);
}
diff --git a/ui/ui/button.h b/ui/ui/button.h
index fb578f7..693f730 100644
--- a/ui/ui/button.h
+++ b/ui/ui/button.h
@@ -35,6 +35,12 @@
extern "C" {
#endif
+enum UiLinkType {
+ UI_LINK_TEXT = 0,
+ UI_LINK_BUTTON
+};
+typedef enum UiLinkType UiLinkType;
+
typedef struct UiButtonArgs {
UiBool fill;
UiBool hexpand;
@@ -42,19 +48,24 @@ typedef struct UiButtonArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
const char *style_class;
- const char* label;
- const char* stockid;
- const char* icon;
+ const char *label;
+ const char *icon;
+ const char *tooltip;
UiLabelType labeltype;
ui_callback onclick;
- void* onclickdata;
+ void *onclickdata;
- const int* groups;
+ const int *groups;
} UiButtonArgs;
typedef struct UiToggleArgs {
@@ -64,38 +75,86 @@ typedef struct UiToggleArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
const char *style_class;
- const char* label;
- const char* stockid;
- const char* icon;
+ const char *label;
+ const char *icon;
+ const char *tooltip;
UiLabelType labeltype;
- UiInteger* value;
- const char* varname;
+ UiInteger *value;
+ const char *varname;
ui_callback onchange;
- void* onchangedata;
+ void *onchangedata;
int enable_group;
- const int* groups;
+ const int *groups;
} UiToggleArgs;
+
+typedef struct UiLinkButtonArgs {
+ UiBool fill;
+ UiBool hexpand;
+ UiBool vexpand;
+ UiBool hfill;
+ UiBool vfill;
+ UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
+ int colspan;
+ int rowspan;
+ const char *name;
+ const char *style_class;
+
+ const char *label;
+ const char *uri;
+ UiString *value;
+ const char *varname;
+ ui_callback onclick;
+ void *onclickdata;
+ UiBool nofollow;
+ UiLinkType type;
+
+ const int *groups;
+} UiLinkButtonArgs;
#define ui_button(obj, ...) ui_button_create(obj, &(UiButtonArgs){ __VA_ARGS__ } )
#define ui_togglebutton(obj, ...) ui_togglebutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
#define ui_checkbox(obj, ...) ui_checkbox_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
#define ui_switch(obj, ...) ui_switch_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
#define ui_radiobutton(obj, ...) ui_radiobutton_create(obj, &(UiToggleArgs){ __VA_ARGS__ } )
+#define ui_linkbutton(obj, ...) ui_linkbutton_create(obj, &(UiLinkButtonArgs){ __VA_ARGS__ })
-UIEXPORT UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args);
-UIEXPORT UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs *args);
-UIEXPORT UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs *args);
-UIEXPORT UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs *args);
-UIEXPORT UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args);
+UIEXPORT UIWIDGET ui_togglebutton_create(UiObject *obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_checkbox_create(UiObject *obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_switch_create(UiObject *obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args);
+UIEXPORT UIWIDGET ui_linkbutton_create(UiObject *obj, UiLinkButtonArgs *args);
+UIEXPORT void ui_button_set_label(UIWIDGET button, const char *label);
+UIEXPORT void ui_button_set_icon(UIWIDGET button, const char *icon);
+UIEXPORT void ui_linkbutton_value_set(UiString *str, const char *label, const char *uri);
+UIEXPORT void ui_linkbutton_value_set_label(UiString *str, const char *label);
+UIEXPORT void ui_linkbutton_value_set_uri(UiString *str, const char *uri);
+UIEXPORT void ui_linkbutton_value_set_visited(UiString *str, UiBool visited);
+UIEXPORT void ui_linkbutton_set_label(UIWIDGET button, const char *label);
+UIEXPORT void ui_linkbutton_set_uri(UIWIDGET button, const char *label);
+UIEXPORT void ui_linkbutton_set_visited(UIWIDGET button, UiBool visited);
+UIEXPORT char* ui_linkbutton_get_label(UIWIDGET button);
+UIEXPORT char* ui_linkbutton_get_uri(UIWIDGET button);
+UIEXPORT UiBool ui_linkbutton_get_visited(UIWIDGET button);
#ifdef __cplusplus
}
diff --git a/ui/ui/container.h b/ui/ui/container.h
index 75c78b0..3355850 100644
--- a/ui/ui/container.h
+++ b/ui/ui/container.h
@@ -65,12 +65,16 @@ typedef struct UiContainerArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
const char *style_class;
- int margin;
int spacing;
int columnspacing;
int rowspacing;
@@ -87,14 +91,19 @@ typedef struct UiFrameArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
const char *style_class;
UiSubContainerType subcontainer;
-
- int margin;
+
+ int padding;
int spacing;
int columnspacing;
int rowspacing;
@@ -110,6 +119,11 @@ typedef struct UiTabViewArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
@@ -124,13 +138,10 @@ typedef struct UiTabViewArgs {
UiInteger *value;
const char* varname;
- int margin;
+ int padding;
int spacing;
int columnspacing;
int rowspacing;
-
- const char* label;
- UiBool isexpanded;
} UiTabViewArgs;
typedef struct UiHeaderbarArgs {
@@ -140,6 +151,11 @@ typedef struct UiHeaderbarArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
@@ -156,6 +172,10 @@ typedef struct UiSidebarArgs {
const char *name;
const char *style_class;
int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int spacing;
} UiSidebarArgs;
@@ -166,17 +186,22 @@ typedef struct UiSplitPaneArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
const char *style_class;
- int margin;
int spacing;
int columnspacing;
int rowspacing;
int initial_position;
+ const char *position_property;
UiInteger *value;
const char* varname;
int max_panes;
@@ -189,12 +214,16 @@ typedef struct UiItemListContainerArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
const char *style_class;
- int margin;
int spacing;
int sub_margin;
@@ -227,9 +256,29 @@ typedef struct UiItemListContainerArgs {
UiSubContainerType subcontainer;
} UiItemListContainerArgs;
+
+typedef struct UiLayout UiLayout;
+struct UiLayout {
+ UiBool fill;
+ char *label;
+ UiBool hexpand;
+ UiBool vexpand;
+ UiBool hfill;
+ UiBool vfill;
+ UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
+ int colspan;
+ int rowspan;
+};
+
struct UiContainerX {
void *container;
- int close;
+ UiBool close;
+ UiBool newline;
UiContainerX *prev;
UiContainerX *next;
};
@@ -246,6 +295,8 @@ struct UiContainerX {
#define ui_tabview(obj, ...) for(ui_tabview_create(obj, &(UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_headerbar(obj, ...) for(ui_headerbar_create(obj, &(UiHeaderbarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_sidebar(obj, ...) for(ui_sidebar_create(obj, &(UiSidebarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_left_panel(obj, ...) for(ui_left_panel_create(obj, &(UiSidebarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_right_panel(ob, ...) for(ui_right_panel_create(obj, &(UiSidebarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_vbox0(obj) for(ui_vbox_create(obj, &(UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_hbox0(obj) for(ui_hbox_create(obj, &(UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
@@ -256,6 +307,9 @@ struct UiContainerX {
#define ui_tabview0(obj) for(ui_tabview_create(obj, &(UiTabViewArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_headerbar0(obj) for(ui_headerbar_create(obj, &(UiHeaderbarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_sidebar0(obj) for(ui_sidebar_create(obj, &(UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_left_panel0(obj) for(ui_left_panel_create(obj, &(UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_right_panel0(obj) for(ui_right_panel_create(obj, &(UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+
#define ui_vbox_w(obj, w, ...) for(w = ui_vbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_hbox_w(obj, w, ...) for(w = ui_hbox_create(obj, &(UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
@@ -301,6 +355,8 @@ UIEXPORT void ui_headerbar_center_create(UiObject *obj);
UIEXPORT void ui_headerbar_end_create(UiObject *obj);
UIEXPORT UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args);
+UIEXPORT UIWIDGET ui_left_panel_create(UiObject *obj, UiSidebarArgs *args);
+UIEXPORT UIWIDGET ui_right_panel_create(UiObject *obj, UiSidebarArgs *args);
UIEXPORT UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs *args);
@@ -309,18 +365,6 @@ UIEXPORT UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args);
UIEXPORT void ui_splitpane_set_visible(UIWIDGET splitpane, int child_index, UiBool visible);
-// box container layout functions
-UIEXPORT void ui_layout_fill(UiObject *obj, UiBool fill);
-// grid container layout functions
-UIEXPORT void ui_layout_hexpand(UiObject *obj, UiBool expand);
-UIEXPORT void ui_layout_vexpand(UiObject *obj, UiBool expand);
-UIEXPORT void ui_layout_hfill(UiObject *obj, UiBool fill);
-UIEXPORT void ui_layout_vfill(UiObject *obj, UiBool fill);
-UIEXPORT void ui_layout_override_defaults(UiObject *obj, UiBool d);
-UIEXPORT void ui_layout_width(UiObject *obj, int width);
-UIEXPORT void ui_layout_height(UiObject* obj, int width);
-UIEXPORT void ui_layout_colspan(UiObject *obj, int cols);
-UIEXPORT void ui_layout_rowspan(UiObject* obj, int rows);
UIEXPORT void ui_newline(UiObject *obj);
// TODO
@@ -334,7 +378,7 @@ UIEXPORT void ui_container_begin_close(UiObject *obj);
UIEXPORT int ui_container_finish(UiObject *obj);
#define UI_APPLY_LAYOUT1(obj, args) \
- if(args.fill != UI_DEFAULT) ui_layout_fill(obj, args.fill == UI_ON ? 1 : 0 ); \
+ if(args.fill) ui_layout_fill(obj, 1); \
if(args.hexpand) ui_layout_hexpand(obj, 1); \
if(args.vexpand) ui_layout_vexpand(obj, 1); \
if(args.hfill) ui_layout_hfill(obj, 1); \
@@ -345,7 +389,7 @@ UIEXPORT int ui_container_finish(UiObject *obj);
/*force caller to add ';'*/(void)0
#define UI_APPLY_LAYOUT2(obj, args) \
- if(args->fill != UI_DEFAULT) ui_layout_fill(obj, args->fill == UI_ON ? 1 : 0 ); \
+ if(args->fill) ui_layout_fill(obj, 1); \
if(args->hexpand) ui_layout_hexpand(obj, 1); \
if(args->vexpand) ui_layout_vexpand(obj, 1); \
if(args->hfill) ui_layout_hfill(obj, 1); \
@@ -355,7 +399,21 @@ UIEXPORT int ui_container_finish(UiObject *obj);
if(args->rowspan > 0) ui_layout_rowspan(obj, args->rowspan); \
/*force caller to add ';'*/(void)0
-
+#define UI_ARGS2LAYOUT(args) { \
+ .fill = args->fill, \
+ .hexpand = args->hexpand, \
+ .vexpand = args->vexpand, \
+ .hfill = args->hfill, \
+ .vfill = args->vfill, \
+ .override_defaults = args->override_defaults, \
+ .margin = args->margin, \
+ .margin_left = args->margin_left, \
+ .margin_right = args->margin_right, \
+ .margin_top = args->margin_top, \
+ .margin_bottom = args->margin_bottom, \
+ .colspan = args->colspan, \
+ .rowspan = args->rowspan }
+
#ifdef __cplusplus
}
#endif
diff --git a/ui/ui/display.h b/ui/ui/display.h
index 3cb3d65..1ed1235 100644
--- a/ui/ui/display.h
+++ b/ui/ui/display.h
@@ -38,15 +38,7 @@
#ifdef __cplusplus
extern "C" {
#endif
-
-enum UiAlignment {
- UI_ALIGN_DEFAULT = 0,
- UI_ALIGN_LEFT,
- UI_ALIGN_RIGHT,
- UI_ALIGN_CENTER
-};
-
-typedef enum UiAlignment UiAlignment;
+
enum UiLabelStyle {
UI_LABEL_STYLE_DEFAULT = 0,
@@ -64,6 +56,11 @@ typedef struct UiLabelArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
@@ -83,6 +80,11 @@ typedef struct UiProgressbarArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
int width;
@@ -102,6 +104,11 @@ typedef struct UiProgressbarSpinnerArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
diff --git a/ui/ui/entry.h b/ui/ui/entry.h
index cb1b7f7..6dd6a0a 100644
--- a/ui/ui/entry.h
+++ b/ui/ui/entry.h
@@ -36,20 +36,28 @@ extern "C" {
#endif
-typedef struct UiSpinnerArgs {
+typedef struct UiSpinBoxArgs {
UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
+ int width;
const char *name;
const char *style_class;
double step;
int digits;
+ double min;
+ double max;
UiInteger *intvalue;
UiDouble* doublevalue;
UiRange *rangevalue;
@@ -58,13 +66,13 @@ typedef struct UiSpinnerArgs {
void* onchangedata;
const int *groups;
-} UiSpinnerArgs;
+} UiSpinBoxArgs;
-UIWIDGET ui_spinner_create(UiObject *obj, UiSpinnerArgs *args);
+UIWIDGET ui_spinbox_create(UiObject *obj, UiSpinBoxArgs *args);
-#define ui_spinner(obj, ...) ui_spinner_create(obj, &(UiSpinnerArgs){ __VA_ARGS__ } )
+#define ui_spinbox(obj, ...) ui_spinbox_create(obj, &(UiSpinBoxArgs){ __VA_ARGS__ } )
void ui_spinner_setrange(UIWIDGET spinner, double min, double max);
void ui_spinner_setdigits(UIWIDGET spinner, int digits);
diff --git a/ui/ui/graphics.h b/ui/ui/graphics.h
index 6eb0daf..e0063b9 100644
--- a/ui/ui/graphics.h
+++ b/ui/ui/graphics.h
@@ -45,25 +45,53 @@ struct UiGraphics {
int height;
};
-UIWIDGET ui_drawingarea(UiObject *obj, ui_drawfunc f, void *userdata);
-void ui_drawingarea_mousehandler(UiObject *obj, UIWIDGET widget, ui_callback f, void *u);
-void ui_drawingarea_getsize(UIWIDGET drawingarea, int *width, int *height);
-void ui_drawingarea_redraw(UIWIDGET drawingarea);
+typedef struct UiDrawingAreaArgs {
+ UiBool fill;
+ UiBool hexpand;
+ UiBool vexpand;
+ UiBool hfill;
+ UiBool vfill;
+ UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
+ int colspan;
+ int rowspan;
+ const char *name;
+ const char *style_class;
+
+ int width;
+ int height;
+ ui_drawfunc draw;
+ void *drawdata;
+ ui_callback onclick;
+ void *onclickdata;
+ ui_callback onmotion;
+ void *onmotiondata;
+} UiDrawingAreaArgs;
+
+#define ui_drawingarea(obj, ...) ui_drawingarea_create(obj, &(UiDrawingAreaArgs) { __VA_ARGS__ } )
+
+UIEXPORT UIWIDGET ui_drawingarea_create(UiObject *obj, UiDrawingAreaArgs *args);
+UIEXPORT void ui_drawingarea_getsize(UIWIDGET drawingarea, int *width, int *height);
+UIEXPORT void ui_drawingarea_redraw(UIWIDGET drawingarea);
// text layout
-UiTextLayout* ui_text(UiGraphics *g);
-void ui_text_free(UiTextLayout *text);
-void ui_text_setstring(UiTextLayout *layout, char *str);
-void ui_text_setstringl(UiTextLayout *layout, char *str, int len);
-void ui_text_setfont(UiTextLayout *layout, char *font, int size);
-void ui_text_getsize(UiTextLayout *layout, int *width, int *height);
-void ui_text_setwidth(UiTextLayout *layout, int width);
+UIEXPORT UiTextLayout* ui_text(UiGraphics *g);
+UIEXPORT void ui_text_free(UiTextLayout *text);
+UIEXPORT void ui_text_setstring(UiTextLayout *layout, char *str);
+UIEXPORT void ui_text_setstringl(UiTextLayout *layout, char *str, int len);
+UIEXPORT void ui_text_setfont(UiTextLayout *layout, const char *font, int size);
+UIEXPORT void ui_text_getsize(UiTextLayout *layout, int *width, int *height);
+UIEXPORT void ui_text_setwidth(UiTextLayout *layout, int width);
// drawing functions
-void ui_graphics_color(UiGraphics *g, int red, int green, int blue);
-void ui_draw_line(UiGraphics *g, int x1, int y1, int x2, int y2);
-void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, int fill);
-void ui_draw_text(UiGraphics *g, int x, int y, UiTextLayout *text);
+UIEXPORT void ui_graphics_color(UiGraphics *g, int red, int green, int blue);
+UIEXPORT void ui_draw_line(UiGraphics *g, int x1, int y1, int x2, int y2);
+UIEXPORT void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, UiBool fill);
+UIEXPORT void ui_draw_text(UiGraphics *g, int x, int y, UiTextLayout *text);
#ifdef __cplusplus
}
diff --git a/ui/ui/image.h b/ui/ui/image.h
index 405b509..77d923f 100644
--- a/ui/ui/image.h
+++ b/ui/ui/image.h
@@ -51,6 +51,11 @@ typedef struct UiImageViewerArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
diff --git a/ui/ui/menu.h b/ui/ui/menu.h
index 3f805b8..9dde9b4 100644
--- a/ui/ui/menu.h
+++ b/ui/ui/menu.h
@@ -38,7 +38,6 @@ extern "C" {
typedef struct UiMenuItemArgs {
const char* label;
- const char* stockid;
const char* icon;
ui_callback onclick;
@@ -49,7 +48,6 @@ typedef struct UiMenuItemArgs {
typedef struct UiMenuToggleItemArgs {
const char* label;
- const char* stockid;
const char* icon;
const char* varname;
@@ -96,7 +94,8 @@ UIEXPORT void ui_menu_end(void); // TODO: private
#define ui_contextmenu(builder) for(ui_contextmenu_builder(builder);ui_menu_is_open();ui_menu_close())
UIEXPORT void ui_contextmenu_builder(UiMenuBuilder **out_builder);
-UIEXPORT void ui_menubuilder_free(UiMenuBuilder *builder);
+UIEXPORT void ui_menubuilder_ref(UiMenuBuilder *builder);
+UIEXPORT void ui_menubuilder_unref(UiMenuBuilder *builder);
UIEXPORT UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, UIWIDGET widget);
UIEXPORT void ui_contextmenu_popup(UIMENU menu, UIWIDGET widget, int x, int y);
diff --git a/ui/ui/properties.h b/ui/ui/properties.h
index 5c985d9..ffb10dd 100644
--- a/ui/ui/properties.h
+++ b/ui/ui/properties.h
@@ -41,14 +41,14 @@ const char* ui_set_default_property(const char *name, const char *value);
int ui_properties_store(void);
-void ui_locales_dir(char *path);
-void ui_pixmaps_dir(char *path);
+void ui_locales_dir(const char *path);
+void ui_pixmaps_dir(const char *path);
-void ui_load_lang(char *locale);
+void ui_load_lang(const char *locale);
void ui_load_lang_def(char *locale, char *default_locale);
-char* uistr(char *name);
-char* uistr_n(char *name);
+char* uistr(const char *name);
+char* uistr_n(const char *name);
#ifdef __cplusplus
}
diff --git a/ui/ui/text.h b/ui/ui/text.h
index 0daf925..ac5a2c1 100644
--- a/ui/ui/text.h
+++ b/ui/ui/text.h
@@ -42,9 +42,15 @@ typedef struct UiTextAreaArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
int width;
+ int height;
const char *name;
const char *style_class;
@@ -63,6 +69,11 @@ typedef struct UiTextFieldArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
int width;
@@ -97,6 +108,11 @@ typedef struct UiPathTextFieldArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
diff --git a/ui/ui/toolbar.h b/ui/ui/toolbar.h
index 4b42af2..26a79e6 100644
--- a/ui/ui/toolbar.h
+++ b/ui/ui/toolbar.h
@@ -37,38 +37,46 @@ extern "C" {
#endif
typedef struct UiToolbarItemArgs {
- const char* label;
- const char* stockid;
- const char* icon;
-
- ui_callback onclick;
- void* onclickdata;
-
- const int *groups;
+ const char *label;
+ const char *icon;
+ const char *tooltip;
+
+ ui_callback onclick;
+ void* onclickdata;
+
+ const int *groups;
+ const int *visibility_states;
} UiToolbarItemArgs;
typedef struct UiToolbarToggleItemArgs {
- const char* label;
- const char* stockid;
- const char* icon;
-
- const char* varname;
- ui_callback onchange;
- void* onchangedata;
-
- const int *groups;
+ const char *label;
+ const char *icon;
+ const char *tooltip;
+
+ const char *varname;
+ ui_callback onchange;
+ void *onchangedata;
+
+ const int *groups;
+ const int *visibility_states;
} UiToolbarToggleItemArgs;
typedef struct UiToolbarMenuArgs {
- const char* label;
- const char* stockid;
- const char* icon;
+ const char *label;
+ const char *icon;
+ const char *tooltip;
+ const int *visibility_states;
} UiToolbarMenuArgs;
enum UiToolbarPos {
- UI_TOOLBAR_LEFT = 0,
- UI_TOOLBAR_CENTER,
- UI_TOOLBAR_RIGHT
+ UI_TOOLBAR_LEFT = 0,
+ UI_TOOLBAR_CENTER,
+ UI_TOOLBAR_RIGHT,
+ UI_TOOLBAR_SIDEBAR_LEFT,
+ UI_TOOLBAR_SIDEBAR_RIGHT,
+ UI_TOOLBAR_RIGHTPANEL_LEFT,
+ UI_TOOLBAR_RIGHTPANEL_CENTER,
+ UI_TOOLBAR_RIGHTPANEL_RIGHT
};
#define ui_toolbar_item(name, ...) ui_toolbar_item_create(name, &(UiToolbarItemArgs){ __VA_ARGS__ } )
diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h
index 7b54742..83cd78a 100644
--- a/ui/ui/toolkit.h
+++ b/ui/ui/toolkit.h
@@ -88,13 +88,7 @@ typedef void* UIMENU; // NSMenu*
#elif UI_WIN32
-#include
-
-#define UIEXPORT __declspec(dllexport)
-
-typedef struct W32Widget {
- HWND hwnd;
-} W32Widget;
+#include "win32.h"
#define UIWIDGET W32Widget*
#define UIWINDOW void*
@@ -200,6 +194,9 @@ typedef struct UiFileList UiFileList;
typedef struct UiListSelection UiListSelection;
+typedef struct UiTextStyle UiTextStyle;
+typedef struct UiColor UiColor;
+
/* begin opaque types */
typedef struct UiContext UiContext;
typedef struct UiContainer UiContainer;
@@ -237,11 +234,21 @@ typedef enum UiDnDAction {
UI_DND_ACTION_LINK,
UI_DND_ACTION_CUSTOM
} UiDnDAction;
-
+
+enum UiAlignment {
+ UI_ALIGN_DEFAULT = 0,
+ UI_ALIGN_LEFT,
+ UI_ALIGN_RIGHT,
+ UI_ALIGN_CENTER
+};
+
+typedef enum UiAlignment UiAlignment;
+
typedef void(*ui_callback)(UiEvent*, void*); /* event, user data */
typedef void*(*ui_getvaluefunc)(void *elm, int col);
typedef void*(*ui_getvaluefunc2)(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult);
+typedef UiBool(*ui_getstylefunc)(UiList *list, void *elm, int row, int col, void *userdata, UiTextStyle *style);
typedef int(*ui_threadfunc)(void*);
@@ -249,6 +256,9 @@ typedef void(*ui_freefunc)(void*);
typedef void(*ui_enablefunc)(void*, int);
+typedef void (*ui_destructor_func)(void *memory);
+
+
struct UiObject {
/*
* native widget
@@ -272,11 +282,6 @@ struct UiObject {
*/
UiContext *ctx;
- /*
- * container interface (deprecated)
- */
- UiContainer *container;
-
/*
* container list
* TODO: remove old UiContainer and rename UiContainerX to UiContainer
@@ -403,6 +408,7 @@ struct UiGeneric {
void* (*get)(UiGeneric*);
const char* (*get_type)(UiGeneric*);
int (*set)(UiGeneric*, void *, const char *type);
+ void (*destroy)(UiGeneric*);
void *obj;
void *value;
@@ -493,6 +499,23 @@ enum UiEventType {
UI_EVENT_DATA_FILE_LIST
};
+#define UI_COLOR(r, g, b) (UiColor){r, g, b}
+struct UiColor {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+};
+
+#define UI_TEXT_STYLE_BOLD 1
+#define UI_TEXT_STYLE_ITALIC 2
+#define UI_TEXT_STYLE_UNDERLINE 4
+
+struct UiTextStyle {
+ uint32_t text_style;
+ UiColor fg;
+ UiBool fg_set;
+};
+
UIEXPORT void ui_init(const char *appname, int argc, char **argv);
UIEXPORT const char* ui_appname();
@@ -514,6 +537,9 @@ UIEXPORT void ui_onstartup(ui_callback f, void *userdata);
UIEXPORT void ui_onopen(ui_callback f, void *userdata);
UIEXPORT void ui_onexit(ui_callback f, void *userdata);
+UIEXPORT int ui_app_save_settings(void);
+UIEXPORT void ui_app_exit_on_shutdown(UiBool exitapp);
+
UIEXPORT void ui_main(void);
UIEXPORT void ui_show(UiObject *obj);
UIEXPORT void ui_close(UiObject *obj);
@@ -535,6 +561,8 @@ UIEXPORT void ui_attach_document(UiContext *ctx, void *document);
UIEXPORT void ui_detach_document(UiContext *ctx, void *document);
UIEXPORT void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...);
+UIEXPORT void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *groups, int ngroups);
+UIEXPORT void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates);
UIEXPORT void ui_set_group(UiContext *ctx, int group);
UIEXPORT void ui_unset_group(UiContext *ctx, int group);
@@ -548,6 +576,8 @@ UIEXPORT void* ui_calloc(UiContext *ctx, size_t nelem, size_t elsize);
UIEXPORT void ui_free(UiContext *ctx, void *ptr);
UIEXPORT void* ui_realloc(UiContext *ctx, void *ptr, size_t size);
UIEXPORT char* ui_strdup(UiContext *ctx, const char *str);
+UIEXPORT void ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr);
+UIEXPORT void ui_set_destructor(void *mem, ui_destructor_func destr);
// types
@@ -578,6 +608,13 @@ UIEXPORT void ui_string_set(UiString *s, const char *value);
UIEXPORT char* ui_string_get(UiString *s);
UIEXPORT void ui_text_set(UiText *s, const char* value);
UIEXPORT char* ui_text_get(UiText *s);
+UIEXPORT void ui_range_set(UiRange *r, double value);
+UIEXPORT void ui_range_set_range(UiRange *r, double min, double max);
+UIEXPORT void ui_range_set_extent(UiRange *r, double extent);
+UIEXPORT double ui_range_get(UiRange *r);
+UIEXPORT double ui_range_get_min(UiRange *r);
+UIEXPORT double ui_range_get_max(UiRange *r);
+UIEXPORT double ui_range_get_extent(UiRange *r);
UIEXPORT void ui_generic_set_image(UiGeneric *g, void *img);
UIEXPORT void* ui_generic_get_image(UiGeneric *g);
@@ -608,6 +645,8 @@ UIEXPORT void ui_list_prepend(UiList *list, void *data);
UIEXPORT void ui_list_remove(UiList *list, int i);
UIEXPORT void ui_list_clear(UiList *list);
UIEXPORT void ui_list_update(UiList *list);
+UIEXPORT void ui_list_update_row(UiList *list, int row);
+UIEXPORT UiListSelection ui_list_get_selection(UiList *list);
UIEXPORT void ui_list_addobsv(UiList *list, ui_callback f, void *data);
UIEXPORT void ui_list_notify(UiList *list);
@@ -622,11 +661,6 @@ UIEXPORT char* ui_clipboard_get();
UIEXPORT void ui_add_image(char *imgname, char *filename); // TODO: remove?
-// general widget functions
-UIEXPORT void ui_set_enabled(UIWIDGET widget, int enabled);
-UIEXPORT void ui_set_show_all(UIWIDGET widget, int value);
-UIEXPORT void ui_set_visible(UIWIDGET widget, int visible);
-
UIEXPORT void ui_listselection_free(UiListSelection selection);
@@ -637,7 +671,7 @@ UIEXPORT UiStr ui_str_free(char *str, void (*free)(void *v));
UIEXPORT char* ui_getappdir(void);
-UIEXPORT char* ui_configfile(char *name);
+UIEXPORT char* ui_configfile(const char *name);
UIEXPORT UiCondVar* ui_condvar_create(void);
UIEXPORT void ui_condvar_wait(UiCondVar *var);
diff --git a/ui/ui/tree.h b/ui/ui/tree.h
index af51d08..33a903c 100644
--- a/ui/ui/tree.h
+++ b/ui/ui/tree.h
@@ -51,15 +51,33 @@ typedef enum UiModelType {
UI_INTEGER,
UI_ICON,
UI_ICON_TEXT,
- UI_ICON_TEXT_FREE
+ UI_ICON_TEXT_FREE,
+ UI_STRING_EDITABLE,
+ UI_BOOL_EDITABLE
} UiModelType;
+typedef struct UiCellValue {
+ union {
+ const char *string;
+ int64_t i;
+ UiBool b;
+ };
+ UiModelType type;
+} UiCellValue;
+
+typedef UiBool (*ui_list_savefunc)(UiList *list, int row, int col, UiCellValue *value, void *userdata);
+
struct UiModel {
/*
* number of columns
*/
int columns;
+ /*
+ * current allocation size (internal)
+ */
+ int alloc;
+
/*
* array of column types
* array length is the number of columns
@@ -76,25 +94,6 @@ struct UiModel {
* array of column size hints
*/
int *columnsize;
-
- /*
- * void*(*ui_getvaluefunc)(void *elm, int col);
- *
- * function for translating model data to view data
- * first argument is the pointer returned by UiList first|next|get
- * second argument is the column index
- * TODO: return
- */
- ui_getvaluefunc getvalue;
-
- /*
- * void*(*ui_getvaluefunc2)(UiList *list, void *elm, int row, int col, void *userdata)
- *
- * alternative for getvalue
- */
- ui_getvaluefunc2 getvalue2;
-
- void *getvalue2data;
};
struct UiListCallbacks {
@@ -121,11 +120,18 @@ struct UiListArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
+ int width;
+ int height;
+
const char *name;
const char *style_class;
-
UiList* list;
const char* varname;
UiModel* model;
@@ -134,6 +140,8 @@ struct UiListArgs {
ui_getvaluefunc getvalue;
ui_getvaluefunc2 getvalue2;
void *getvalue2data;
+ ui_getstylefunc getstyle;
+ void *getstyledata;
ui_callback onactivate;
void* onactivatedata;
ui_callback onselection;
@@ -146,6 +154,8 @@ struct UiListArgs {
void* ondropdata;
UiBool multiselection;
UiMenuBuilder *contextmenu;
+ ui_list_savefunc onsave;
+ void *onsavedata;
const int *groups;
};
@@ -175,12 +185,13 @@ typedef struct UiSubListEventData {
* will be passed to free
*/
struct UiSubListItem {
- char *icon;
- char *label;
- char *button_icon;
- char *button_label;
- char *badge;
- void *eventdata;
+ char *icon;
+ char *label;
+ char *button_icon;
+ char *button_label;
+ UiMenuBuilder *button_menu;
+ char *badge;
+ void *eventdata;
};
struct UiSourceListArgs {
@@ -190,8 +201,15 @@ struct UiSourceListArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
+ int width;
+ int height;
const char *name;
const char *style_class;
@@ -237,6 +255,11 @@ struct UiSourceListArgs {
*/
void *getvaluedata;
+ /*
+ * is a sublist header a selectable item
+ */
+ UiBool header_is_item;
+
/*
* activated when a list item is selected
*/
@@ -248,13 +271,26 @@ struct UiSourceListArgs {
*/
ui_callback onbuttonclick;
void *onbuttonclickdata;
+
+ UiMenuBuilder *contextmenu;
};
#define UI_SUBLIST(...) (UiSubList){ __VA_ARGS__ }
#define UI_SUBLISTS(...) (UiSubList[]){ __VA_ARGS__, (UiSubList){NULL,NULL,NULL,0} }
+/*
+ * Creates an UiModel, that specifies columns for a table widget.
+ *
+ * For each column a column type (UiModelType) and a title string
+ * (char*) must be specified. The column list must be terminated
+ * with -1.
+ *
+ * UiModel *model = ui_model(ctx, UI_STRING, "Column 1", UI_STRING, "Column 2", -1);
+ */
UIEXPORT UiModel* ui_model(UiContext *ctx, ...);
+UIEXPORT UiModel* ui_model_new(UiContext *ctx);
+UIEXPORT void ui_model_add_column(UiContext *ctx, UiModel *model, UiModelType type, const char *title, int width);
UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model);
UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi);
@@ -278,10 +314,23 @@ UIEXPORT void ui_sublist_item_set_icon(UiSubListItem *item, const char *icon);
UIEXPORT void ui_sublist_item_set_label(UiSubListItem *item, const char *label);
UIEXPORT void ui_sublist_item_set_button_icon(UiSubListItem *item, const char *button_icon);
UIEXPORT void ui_sublist_item_set_button_label(UiSubListItem *item, const char *button_label);
+UIEXPORT void ui_sublist_item_set_button_menu(UiSubListItem *item, UiMenuBuilder *menu);
UIEXPORT void ui_sublist_item_set_badge(UiSubListItem *item, const char *badge);
UIEXPORT void ui_sublist_item_set_eventdata(UiSubListItem *item, void *eventdata);
+
+/*
+ * Only relevant for some language bindings
+ */
+typedef void(*ui_sourcelist_update_func)(void);
+
+/*
+ * The sourcelist update callback is called after any source list
+ * sublist update is completed
+ */
+UIEXPORT void ui_sourcelist_set_update_callback(ui_sourcelist_update_func cb);
+
#ifdef __cplusplus
}
#endif
diff --git a/ui/ui/webview.h b/ui/ui/webview.h
index 36f77f9..9636165 100644
--- a/ui/ui/webview.h
+++ b/ui/ui/webview.h
@@ -36,15 +36,28 @@
extern "C" {
#endif
+/*
+ * WebView type string used by UiGeneric
+ */
#define UI_WEBVIEW_OBJECT_TYPE "webview"
-
+
+/*
+ * UiWebViewData* is returned by a webviews UiGeneric->get function
+ */
+typedef struct UiWebViewData UiWebViewData;
+
typedef struct UiWebviewArgs {
- UiTri fill;
+ UiBool fill;
UiBool hexpand;
UiBool vexpand;
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
@@ -58,11 +71,11 @@ typedef struct UiWebviewArgs {
#define ui_webview(obj, ...) ui_webview_create(obj, &(UiWebviewArgs){ __VA_ARGS__ } )
-UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args);
+UIEXPORT UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args);
-void ui_webview_load_url(UiGeneric *g, const char *url);
+UIEXPORT void ui_webview_load_url(UiGeneric *g, const char *url);
-void ui_webview_load_content(
+UIEXPORT void ui_webview_load_content(
UiGeneric *g,
const char *uri,
const char *content,
@@ -70,16 +83,20 @@ void ui_webview_load_content(
const char *mimetype,
const char *encoding);
+/*
+ * Frees a UiWebViewData object returned by a webviews UiGeneric->get function
+ */
+UIEXPORT void ui_webview_data_free(UiWebViewData *data);
-void ui_webview_reload(UiGeneric *g);
-UiBool ui_webview_can_go_back(UiGeneric *g);
-UiBool ui_webview_can_go_forward(UiGeneric *g);
-void ui_webview_go_back(UiGeneric *g);
-void ui_webview_go_forward(UiGeneric *g);
-const char * ui_webview_get_uri(UiGeneric *g);
-void ui_webview_enable_javascript(UiGeneric *g, UiBool enable);
-void ui_webview_set_zoom(UiGeneric *g, double zoom);
-double ui_webview_get_zoom(UiGeneric *g);
+UIEXPORT void ui_webview_reload(UiGeneric *g);
+UIEXPORT UiBool ui_webview_can_go_back(UiGeneric *g);
+UIEXPORT UiBool ui_webview_can_go_forward(UiGeneric *g);
+UIEXPORT void ui_webview_go_back(UiGeneric *g);
+UIEXPORT void ui_webview_go_forward(UiGeneric *g);
+UIEXPORT const char * ui_webview_get_uri(UiGeneric *g);
+UIEXPORT void ui_webview_enable_javascript(UiGeneric *g, UiBool enable);
+UIEXPORT void ui_webview_set_zoom(UiGeneric *g, double zoom);
+UIEXPORT double ui_webview_get_zoom(UiGeneric *g);
#ifdef __cplusplus
diff --git a/ui/ui/widget.h b/ui/ui/widget.h
index fee08d9..aea5b8e 100644
--- a/ui/ui/widget.h
+++ b/ui/ui/widget.h
@@ -41,6 +41,11 @@ typedef struct UiWidgetArgs {
UiBool hfill;
UiBool vfill;
UiBool override_defaults;
+ int margin;
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
int colspan;
int rowspan;
const char *name;
@@ -69,6 +74,9 @@ UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args);
#define ui_separator(obj, ...) ui_separator_create(obj, &(UiWidgetArgs){ __VA_ARGS__ } )
+UIEXPORT void ui_set_enabled(UIWIDGET widget, int enabled);
+UIEXPORT void ui_set_visible(UIWIDGET widget, int visible);
+
UIEXPORT void ui_widget_set_size(UIWIDGET w, int width, int height);
UIEXPORT void ui_widget_redraw(UIWIDGET w);
diff --git a/ui/ui/win32.h b/ui/ui/win32.h
new file mode 100644
index 0000000..54d0543
--- /dev/null
+++ b/ui/ui/win32.h
@@ -0,0 +1,71 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UI_WIN32_H
+#define UI_WIN32_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UIEXPORT __declspec(dllexport)
+
+typedef struct W32WidgetClass W32WidgetClass;
+typedef struct W32Widget W32Widget;
+typedef struct W32Size W32Size;
+
+typedef void (*W32LayoutFunc)(void *, int, int);
+
+struct W32Size {
+ int width;
+ int height;
+};
+
+struct W32WidgetClass {
+ void (*eventproc)(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void (*show)(W32Widget *widget, BOOLEAN show);
+ void (*enable)(W32Widget *widget, BOOLEAN enable);
+ W32Size (*get_preferred_size)(W32Widget *widget);
+ void (*destroy)(W32Widget *widget);
+};
+
+struct W32Widget {
+ W32WidgetClass *wclass;
+ HWND hwnd;
+ void *userdata;
+ void (*layout)(void *layout, int width, int height);
+ void *layoutmanager;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UI_WIN32_H */
diff --git a/ui/ui/window.h b/ui/ui/window.h
index 352abb7..83e85a3 100644
--- a/ui/ui/window.h
+++ b/ui/ui/window.h
@@ -74,17 +74,25 @@ typedef struct UiDialogWindowArgs {
UIEXPORT UiObject *ui_window(const char *title, void *window_data);
UIEXPORT UiObject *ui_sidebar_window(const char *title, void *window_data);
+UIEXPORT UiObject *ui_splitview_window(const char *title, UiBool sidebar);
UIEXPORT UiObject *ui_simple_window(const char *title, void *window_data);
-UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args);
+UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args);
-#define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, (UiDialogWindowArgs){ __VA_ARGS__ });
-#define ui_dialog_window0(parent) ui_dialog_window_create(parent, (UiDialogWindowArgs){ 0 });
+#define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, &(UiDialogWindowArgs){ __VA_ARGS__ });
+#define ui_dialog_window0(parent) ui_dialog_window_create(parent, &(UiDialogWindowArgs){ 0 });
UIEXPORT void ui_window_size(UiObject *obj, int width, int height);
+UIEXPORT void ui_window_default_size(int width, int height);
-#define ui_dialog(parent, ...) ui_dialog_create(parent, (UiDialogArgs){ __VA_ARGS__ } )
+UIEXPORT void ui_splitview_window_set_pos(UiObject *obj, int pos);
+UIEXPORT int ui_splitview_window_get_pos(UiObject *obj);
+UIEXPORT void ui_splitview_window_set_default_pos(int pos);
+UIEXPORT void ui_splitview_window_use_property(UiBool enable);
+UIEXPORT void ui_splitview_window_set_visible(UiObject *obj, int pane, UiBool visible);
-UIEXPORT void ui_dialog_create(UiObject *parent, UiDialogArgs args);
+#define ui_dialog(parent, ...) ui_dialog_create(parent, &(UiDialogArgs){ __VA_ARGS__ } )
+
+UIEXPORT void ui_dialog_create(UiObject *parent, UiDialogArgs *args);
UIEXPORT void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata);
UIEXPORT void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata);