cat >> "$TEMP_DIR/make.mk" << __EOF__
OBJ_EXT = .o
LIB_EXT = .a
+LIB_PREFIX = lib
PACKAGE_SCRIPT = package_osx.sh
__EOF__
break
cat >> "$TEMP_DIR/make.mk" << __EOF__
OBJ_EXT = .o
LIB_EXT = .a
+LIB_PREFIX = lib
PACKAGE_SCRIPT = package_unix.sh
__EOF__
break
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://unixwork.de/uwproj">
+<project version="0.3" xmlns="http://unixwork.de/uwproj">
<dependency>
<lang>c</lang>
</dependency>
<dependency platform="macos">
<make>OBJ_EXT = .o</make>
<make>LIB_EXT = .a</make>
+ <make>LIB_PREFIX = lib</make>
<make>PACKAGE_SCRIPT = package_osx.sh</make>
</dependency>
<dependency platform="unix" not="macos">
<make>OBJ_EXT = .o</make>
<make>LIB_EXT = .a</make>
+ <make>LIB_PREFIX = lib</make>
<make>PACKAGE_SCRIPT = package_unix.sh</make>
</dependency>
+++ /dev/null
-UCX is a library for common data structures, algorithms and string functions.
-
-More informations at: https://develop.uap-core.de/ucx/
-
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2019 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.
- */
-
-#define _GNU_SOURCE /* we want to use qsort_r(), if available */
-#define __STDC_WANT_LIB_EXT1__ 1 /* use qsort_s, if available */
-
-
-#include "ucx/array.h"
-#include "ucx/utils.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#ifndef UCX_ARRAY_DISABLE_QSORT
-#ifdef __GLIBC__
-#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
-#define ucx_array_sort_impl qsort_r
-#endif /* glibc version >= 2.8 */
-#elif /* not __GLIBC__ */ defined(__APPLE__) || defined(__FreeBSD__)
-#define ucx_array_sort_impl ucx_qsort_r
-#define USE_UCX_QSORT_R
-#elif /* not (__APPLE || __FreeBSD__) */ defined(__sun)
-#if __STDC_VERSION__ >= 201112L
-#define ucx_array_sort_impl qsort_s
-#endif
-#endif /* __GLIBC__, __APLE__, __FreeBSD__, __sun */
-#endif /* UCX_ARRAY_DISABLE_QSORT */
-
-#ifndef ucx_array_sort_impl
-#define ucx_array_sort_impl ucx_mergesort
-#endif
-
-static int ucx_array_ensurecap(UcxArray *array, size_t reqcap) {
- size_t required_capacity = array->capacity;
- while (reqcap > required_capacity) {
- if (required_capacity * 2 < required_capacity)
- return 1;
- required_capacity <<= 1;
- }
- if (ucx_array_reserve(array, required_capacity)) {
- return 1;
- }
- return 0;
-}
-
-int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity,
- size_t elmsize, size_t index, void* data) {
-
- if(!alloc || !capacity || !array) {
- errno = EINVAL;
- return 1;
- }
-
- size_t newcapacity = *capacity;
- while(index >= newcapacity) {
- if(ucx_szmul(newcapacity, 2, &newcapacity)) {
- errno = EOVERFLOW;
- return 1;
- }
- }
-
- size_t memlen, offset;
- if(ucx_szmul(newcapacity, elmsize, &memlen)) {
- errno = EOVERFLOW;
- return 1;
- }
- /* we don't need to check index*elmsize - it is smaller than memlen */
-
-
- void* newptr = alrealloc(alloc, *array, memlen);
- if(newptr == NULL) {
- errno = ENOMEM; /* we cannot assume that every allocator sets this */
- return 1;
- }
- *array = newptr;
- *capacity = newcapacity;
-
-
- char* dest = *array;
- dest += elmsize*index;
- memcpy(dest, data, elmsize);
-
- return 0;
-}
-
-int ucx_array_util_setptr_a(UcxAllocator* alloc, void** array, size_t* capacity,
- size_t index, void* data) {
-
- return ucx_array_util_set_a(alloc, array, capacity, sizeof(void*),
- index, &data);
-}
-
-UcxArray* ucx_array_new(size_t capacity, size_t elemsize) {
- return ucx_array_new_a(capacity, elemsize, ucx_default_allocator());
-}
-
-UcxArray* ucx_array_new_a(size_t capacity, size_t elemsize,
- UcxAllocator* allocator) {
- UcxArray* array = almalloc(allocator, sizeof(UcxArray));
- if(array) {
- ucx_array_init_a(array, capacity, elemsize, allocator);
- }
- return array;
-}
-
-void ucx_array_init(UcxArray* array, size_t capacity, size_t elemsize) {
- ucx_array_init_a(array, capacity, elemsize, ucx_default_allocator());
-}
-
-void ucx_array_init_a(UcxArray* array, size_t capacity, size_t elemsize,
- UcxAllocator* allocator) {
-
- array->allocator = allocator;
- array->elemsize = elemsize;
- array->size = 0;
- array->data = alcalloc(allocator, capacity, elemsize);
-
- if (array->data) {
- array->capacity = capacity;
- } else {
- array->capacity = 0;
- }
-}
-
-int ucx_array_clone(UcxArray* dest, UcxArray const* src) {
- if (ucx_array_ensurecap(dest, src->capacity)) {
- return 1;
- }
-
- dest->elemsize = src->elemsize;
- dest->size = src->size;
-
- if (dest->data) {
- memcpy(dest->data, src->data, src->size*src->elemsize);
- }
-
- return 0;
-}
-
-int ucx_array_equals(UcxArray const *array1, UcxArray const *array2,
- cmp_func cmpfnc, void* data) {
-
- if (array1->size != array2->size || array1->elemsize != array2->elemsize) {
- return 0;
- } else {
- if (array1->size == 0)
- return 1;
-
- size_t elemsize;
- if (cmpfnc == NULL) {
- cmpfnc = ucx_cmp_mem;
- elemsize = array1->elemsize;
- data = &elemsize;
- }
-
- for (size_t i = 0 ; i < array1->size ; i++) {
- int r = cmpfnc(
- ucx_array_at(array1, i),
- ucx_array_at(array2, i),
- data);
- if (r != 0)
- return 0;
- }
- return 1;
- }
-}
-
-void ucx_array_destroy(UcxArray *array) {
- if(array->data)
- alfree(array->allocator, array->data);
- array->data = NULL;
- array->capacity = array->size = 0;
-}
-
-void ucx_array_free(UcxArray *array) {
- ucx_array_destroy(array);
- alfree(array->allocator, array);
-}
-
-int ucx_array_append_from(UcxArray *array, void *data, size_t count) {
- if (ucx_array_ensurecap(array, array->size + count))
- return 1;
-
- void* dest = ucx_array_at(array, array->size);
- if (data) {
- memcpy(dest, data, array->elemsize*count);
- } else {
- memset(dest, 0, array->elemsize*count);
- }
- array->size += count;
-
- return 0;
-}
-
-int ucx_array_prepend_from(UcxArray *array, void *data, size_t count) {
- if (ucx_array_ensurecap(array, array->size + count))
- return 1;
-
- if (array->size > 0) {
- void *dest = ucx_array_at(array, count);
- memmove(dest, array->data, array->elemsize*array->size);
- }
-
- if (data) {
- memcpy(array->data, data, array->elemsize*count);
- } else {
- memset(array->data, 0, array->elemsize*count);
- }
- array->size += count;
-
- return 0;
-}
-
-int ucx_array_set_from(UcxArray *array, size_t index,
- void *data, size_t count) {
- if (ucx_array_ensurecap(array, index + count))
- return 1;
-
- if (index+count > array->size) {
- array->size = index+count;
- }
-
- void *dest = ucx_array_at(array, index);
- if (data) {
- memcpy(dest, data, array->elemsize*count);
- } else {
- memset(dest, 0, array->elemsize*count);
- }
-
- return 0;
-}
-
-int ucx_array_concat(UcxArray *array1, const UcxArray *array2) {
-
- if (array1->elemsize != array2->elemsize)
- return 1;
-
- size_t capacity = array1->capacity+array2->capacity;
-
- if (array1->capacity < capacity) {
- if (ucx_array_reserve(array1, capacity)) {
- return 1;
- }
- }
-
- void* dest = ucx_array_at(array1, array1->size);
- memcpy(dest, array2->data, array2->size*array2->elemsize);
-
- array1->size += array2->size;
-
- return 0;
-}
-
-void *ucx_array_at(UcxArray const *array, size_t index) {
- char* memory = array->data;
- char* loc = memory + index*array->elemsize;
- return loc;
-}
-
-size_t ucx_array_find(UcxArray const *array, void *elem,
- cmp_func cmpfnc, void *data) {
-
- size_t elemsize;
- if (cmpfnc == NULL) {
- cmpfnc = ucx_cmp_mem;
- elemsize = array->elemsize;
- data = &elemsize;
- }
-
- if (array->size > 0) {
- for (size_t i = 0 ; i < array->size ; i++) {
- void* ptr = ucx_array_at(array, i);
- if (cmpfnc(ptr, elem, data) == 0) {
- return i;
- }
- }
- return array->size;
- } else {
- return 0;
- }
-}
-
-int ucx_array_contains(UcxArray const *array, void *elem,
- cmp_func cmpfnc, void *data) {
- return ucx_array_find(array, elem, cmpfnc, data) != array->size;
-}
-
-static void ucx_mergesort_merge(void *arrdata,size_t elemsize,
- cmp_func cmpfnc, void *data,
- size_t start, size_t mid, size_t end) {
-
- char* array = arrdata;
-
- size_t rightstart = mid + 1;
-
- if (cmpfnc(array + mid*elemsize,
- array + rightstart*elemsize, data) <= 0) {
- /* already sorted */
- return;
- }
-
- /* we need memory for one element */
- void *value = malloc(elemsize);
-
- while (start <= mid && rightstart <= end) {
- if (cmpfnc(array + start*elemsize,
- array + rightstart*elemsize, data) <= 0) {
- start++;
- } else {
- /* save the value from the right */
- memcpy(value, array + rightstart*elemsize, elemsize);
-
- /* shift all left elements one element to the right */
- size_t shiftcount = rightstart-start;
- void *startptr = array + start*elemsize;
- void *dest = array + (start+1)*elemsize;
- memmove(dest, startptr, shiftcount*elemsize);
-
- /* bring the first value from the right to the left */
- memcpy(startptr, value, elemsize);
-
- start++;
- mid++;
- rightstart++;
- }
- }
-
- /* free the temporary memory */
- free(value);
-}
-
-static void ucx_mergesort_impl(void *arrdata, size_t elemsize,
- cmp_func cmpfnc, void *data, size_t l, size_t r) {
- if (l < r) {
- size_t m = l + (r - l) / 2;
-
- ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, l, m);
- ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, m + 1, r);
- ucx_mergesort_merge(arrdata, elemsize, cmpfnc, data, l, m, r);
- }
-}
-
-static void ucx_mergesort(void *arrdata, size_t count, size_t elemsize,
- cmp_func cmpfnc, void *data) {
-
- ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, 0, count-1);
-}
-
-#ifdef USE_UCX_QSORT_R
-struct cmpfnc_swapargs_info {
- cmp_func func;
- void *data;
-};
-
-static int cmp_func_swap_args(void *data, const void *x, const void *y) {
- struct cmpfnc_swapargs_info* info = data;
- return info->func(x, y, info->data);
-}
-
-static void ucx_qsort_r(void *array, size_t count, size_t elemsize,
- cmp_func cmpfnc, void *data) {
- struct cmpfnc_swapargs_info info;
- info.func = cmpfnc;
- info.data = data;
- qsort_r(array, count, elemsize, &info, cmp_func_swap_args);
-}
-#endif /* USE_UCX_QSORT_R */
-
-void ucx_array_sort(UcxArray* array, cmp_func cmpfnc, void *data) {
- ucx_array_sort_impl(array->data, array->size, array->elemsize,
- cmpfnc, data);
-}
-
-void ucx_array_remove(UcxArray *array, size_t index) {
- array->size--;
- if (index < array->size) {
- void* dest = ucx_array_at(array, index);
- void* src = ucx_array_at(array, index+1);
- memmove(dest, src, (array->size - index)*array->elemsize);
- }
-}
-
-void ucx_array_remove_fast(UcxArray *array, size_t index) {
- array->size--;
- if (index < array->size) {
- void* dest = ucx_array_at(array, index);
- void* src = ucx_array_at(array, array->size);
- memcpy(dest, src, array->elemsize);
- }
-}
-
-int ucx_array_shrink(UcxArray* array) {
- void* newptr = alrealloc(array->allocator, array->data,
- array->size*array->elemsize);
- if (newptr) {
- array->data = newptr;
- array->capacity = array->size;
- return 0;
- } else {
- return 1;
- }
-}
-
-int ucx_array_resize(UcxArray* array, size_t capacity) {
- if (array->capacity >= capacity) {
- void* newptr = alrealloc(array->allocator, array->data,
- capacity*array->elemsize);
- if (newptr) {
- array->data = newptr;
- array->capacity = capacity;
- if (array->size > array->capacity) {
- array->size = array->capacity;
- }
- return 0;
- } else {
- return 1;
- }
- } else {
- return ucx_array_reserve(array, capacity);
- }
-}
-
-int ucx_array_reserve(UcxArray* array, size_t capacity) {
- if (array->capacity > capacity) {
- return 0;
- } else {
- void* newptr = alrealloc(array->allocator, array->data,
- capacity*array->elemsize);
- if (newptr) {
- array->data = newptr;
- array->capacity = capacity;
- return 0;
- } else {
- return 1;
- }
- }
-}
-
-int ucx_array_grow(UcxArray* array, size_t count) {
- return ucx_array_reserve(array, array->size+count);
-}
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 "ucx/avl.h"
-
-#include <limits.h>
-
-#define ptrcast(ptr) ((void*)(ptr))
-#define alloc_tree(al) (UcxAVLTree*) almalloc((al), sizeof(UcxAVLTree))
-#define alloc_node(al) (UcxAVLNode*) almalloc((al), sizeof(UcxAVLNode))
-
-static void ucx_avl_connect(UcxAVLTree *tree,
- UcxAVLNode *node, UcxAVLNode *child, intptr_t nullkey) {
- if (child) {
- child->parent = node;
- }
- // if child is NULL, nullkey decides if left or right pointer is cleared
- if (tree->cmpfunc(
- ptrcast(child ? child->key : nullkey),
- ptrcast(node->key), tree->userdata) > 0) {
- node->right = child;
- } else {
- node->left = child;
- }
- size_t lh = node->left ? node->left->height : 0;
- size_t rh = node->right ? node->right->height : 0;
- node->height = 1 + (lh > rh ? lh : rh);
-}
-
-#define avlheight(node) ((node) ? (node)->height : 0)
-
-static UcxAVLNode* avl_rotright(UcxAVLTree *tree, UcxAVLNode *l0) {
- UcxAVLNode *p = l0->parent;
- UcxAVLNode *l1 = l0->left;
- if (p) {
- ucx_avl_connect(tree, p, l1, 0);
- } else {
- l1->parent = NULL;
- }
- ucx_avl_connect(tree, l0, l1->right, l1->key);
- ucx_avl_connect(tree, l1, l0, 0);
- return l1;
-}
-
-static UcxAVLNode* avl_rotleft(UcxAVLTree *tree, UcxAVLNode *l0) {
- UcxAVLNode *p = l0->parent;
- UcxAVLNode *l1 = l0->right;
- if (p) {
- ucx_avl_connect(tree, p, l1, 0);
- } else {
- l1->parent = NULL;
- }
- ucx_avl_connect(tree, l0, l1->left, l1->key);
- ucx_avl_connect(tree, l1, l0, 0);
- return l1;
-}
-
-static void ucx_avl_balance(UcxAVLTree *tree, UcxAVLNode *n) {
- int lh = avlheight(n->left);
- int rh = avlheight(n->right);
- n->height = 1 + (lh > rh ? lh : rh);
-
- if (lh - rh == 2) {
- UcxAVLNode *c = n->left;
- if (avlheight(c->right) - avlheight(c->left) == 1) {
- avl_rotleft(tree, c);
- }
- n = avl_rotright(tree, n);
- } else if (rh - lh == 2) {
- UcxAVLNode *c = n->right;
- if (avlheight(c->left) - avlheight(c->right) == 1) {
- avl_rotright(tree, c);
- }
- n = avl_rotleft(tree, n);
- }
-
- if (n->parent) {
- ucx_avl_balance(tree, n->parent);
- } else {
- tree->root = n;
- }
-}
-
-UcxAVLTree *ucx_avl_new(cmp_func cmpfunc) {
- return ucx_avl_new_a(cmpfunc, ucx_default_allocator());
-}
-
-UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator) {
- UcxAVLTree* tree = alloc_tree(allocator);
- if (tree) {
- tree->allocator = allocator;
- tree->cmpfunc = cmpfunc;
- tree->root = NULL;
- tree->userdata = NULL;
- }
-
- return tree;
-}
-
-static void ucx_avl_free_node(UcxAllocator *al, UcxAVLNode *node) {
- if (node) {
- ucx_avl_free_node(al, node->left);
- ucx_avl_free_node(al, node->right);
- alfree(al, node);
- }
-}
-
-void ucx_avl_free(UcxAVLTree *tree) {
- UcxAllocator *al = tree->allocator;
- ucx_avl_free_node(al, tree->root);
- alfree(al, tree);
-}
-
-static void ucx_avl_free_content_node(UcxAllocator *al, UcxAVLNode *node,
- ucx_destructor destr) {
- if (node) {
- ucx_avl_free_content_node(al, node->left, destr);
- ucx_avl_free_content_node(al, node->right, destr);
- if (destr) {
- destr(node->value);
- } else {
- alfree(al, node->value);
- }
- }
-}
-
-void ucx_avl_free_content(UcxAVLTree *tree, ucx_destructor destr) {
- ucx_avl_free_content_node(tree->allocator, tree->root, destr);
-}
-
-UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key) {
- UcxAVLNode *n = tree->root;
- int cmpresult;
- while (n && (cmpresult = tree->cmpfunc(
- ptrcast(key), ptrcast(n->key), tree->userdata))) {
- n = cmpresult > 0 ? n->right : n->left;
- }
- return n;
-}
-
-void *ucx_avl_get(UcxAVLTree *tree, intptr_t key) {
- UcxAVLNode *n = ucx_avl_get_node(tree, key);
- return n ? n->value : NULL;
-}
-
-UcxAVLNode *ucx_avl_find_node(UcxAVLTree *tree, intptr_t key,
- distance_func dfnc, int mode) {
- UcxAVLNode *n = tree->root;
- UcxAVLNode *closest = NULL;
-
- intmax_t cmpresult;
- intmax_t closest_dist;
- closest_dist = mode == UCX_AVL_FIND_LOWER_BOUNDED ? INTMAX_MIN : INTMAX_MAX;
-
- while (n && (cmpresult = dfnc(
- ptrcast(key), ptrcast(n->key), tree->userdata))) {
- if (mode == UCX_AVL_FIND_CLOSEST) {
- intmax_t dist = cmpresult;
- if (dist < 0) dist *= -1;
- if (dist < closest_dist) {
- closest_dist = dist;
- closest = n;
- }
- } else if (mode == UCX_AVL_FIND_LOWER_BOUNDED && cmpresult <= 0) {
- if (cmpresult > closest_dist) {
- closest_dist = cmpresult;
- closest = n;
- }
- } else if (mode == UCX_AVL_FIND_UPPER_BOUNDED && cmpresult >= 0) {
- if (cmpresult < closest_dist) {
- closest_dist = cmpresult;
- closest = n;
- }
- }
- n = cmpresult > 0 ? n->right : n->left;
- }
- return n ? n : closest;
-}
-
-void *ucx_avl_find(UcxAVLTree *tree, intptr_t key,
- distance_func dfnc, int mode) {
- UcxAVLNode *n = ucx_avl_find_node(tree, key, dfnc, mode);
- return n ? n->value : NULL;
-}
-
-int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value) {
- return ucx_avl_put_s(tree, key, value, NULL);
-}
-
-int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value,
- void **oldvalue) {
- if (tree->root) {
- UcxAVLNode *n = tree->root;
- int cmpresult;
- while ((cmpresult = tree->cmpfunc(
- ptrcast(key), ptrcast(n->key), tree->userdata))) {
- UcxAVLNode *m = cmpresult > 0 ? n->right : n->left;
- if (m) {
- n = m;
- } else {
- break;
- }
- }
-
- if (cmpresult) {
- UcxAVLNode* e = alloc_node(tree->allocator);
- if (e) {
- e->key = key; e->value = value; e->height = 1;
- e->parent = e->left = e->right = NULL;
- ucx_avl_connect(tree, n, e, 0);
- ucx_avl_balance(tree, n);
- return 0;
- } else {
- return 1;
- }
- } else {
- if (oldvalue) {
- *oldvalue = n->value;
- }
- n->value = value;
- return 0;
- }
- } else {
- tree->root = alloc_node(tree->allocator);
- if (tree->root) {
- tree->root->key = key; tree->root->value = value;
- tree->root->height = 1;
- tree->root->parent = tree->root->left = tree->root->right = NULL;
-
- if (oldvalue) {
- *oldvalue = NULL;
- }
-
- return 0;
- } else {
- return 1;
- }
- }
-}
-
-int ucx_avl_remove(UcxAVLTree *tree, intptr_t key) {
- return ucx_avl_remove_s(tree, key, NULL, NULL);
-}
-
-int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node) {
- return ucx_avl_remove_s(tree, node->key, NULL, NULL);
-}
-
-int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key,
- intptr_t *oldkey, void **oldvalue) {
-
- UcxAVLNode *n = tree->root;
- int cmpresult;
- while (n && (cmpresult = tree->cmpfunc(
- ptrcast(key), ptrcast(n->key), tree->userdata))) {
- n = cmpresult > 0 ? n->right : n->left;
- }
- if (n) {
- if (oldkey) {
- *oldkey = n->key;
- }
- if (oldvalue) {
- *oldvalue = n->value;
- }
-
- UcxAVLNode *p = n->parent;
- if (n->left && n->right) {
- UcxAVLNode *s = n->right;
- while (s->left) {
- s = s->left;
- }
- ucx_avl_connect(tree, s->parent, s->right, s->key);
- n->key = s->key; n->value = s->value;
- p = s->parent;
- alfree(tree->allocator, s);
- } else {
- if (p) {
- ucx_avl_connect(tree, p, n->right ? n->right:n->left, n->key);
- } else {
- tree->root = n->right ? n->right : n->left;
- if (tree->root) {
- tree->root->parent = NULL;
- }
- }
- alfree(tree->allocator, n);
- }
-
- if (p) {
- ucx_avl_balance(tree, p);
- }
-
- return 0;
- } else {
- return 1;
- }
-}
-
-static size_t ucx_avl_countn(UcxAVLNode *node) {
- if (node) {
- return 1 + ucx_avl_countn(node->left) + ucx_avl_countn(node->right);
- } else {
- return 0;
- }
-}
-
-size_t ucx_avl_count(UcxAVLTree *tree) {
- return ucx_avl_countn(tree->root);
-}
-
-UcxAVLNode* ucx_avl_pred(UcxAVLNode* node) {
- if (node->left) {
- UcxAVLNode* n = node->left;
- while (n->right) {
- n = n->right;
- }
- return n;
- } else {
- UcxAVLNode* n = node;
- while (n->parent) {
- if (n->parent->right == n) {
- return n->parent;
- } else {
- n = n->parent;
- }
- }
- return NULL;
- }
-}
-
-UcxAVLNode* ucx_avl_succ(UcxAVLNode* node) {
- if (node->right) {
- UcxAVLNode* n = node->right;
- while (n->left) {
- n = n->left;
- }
- return n;
- } else {
- UcxAVLNode* n = node;
- while (n->parent) {
- if (n->parent->left == n) {
- return n->parent;
- } else {
- n = n->parent;
- }
- }
- return NULL;
- }
-}
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 "ucx/logging.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <time.h>
-
-UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask) {
- UcxLogger *logger = (UcxLogger*) malloc(sizeof(UcxLogger));
- if (logger != NULL) {
- logger->stream = stream;
- logger->writer = (write_func)fwrite;
- logger->dateformat = (char*) "%F %T %z ";
- logger->level = level;
- logger->mask = mask;
- logger->levels = ucx_map_new(8);
-
- unsigned int l;
- l = UCX_LOGGER_ERROR;
- ucx_map_int_put(logger->levels, l, (void*) "[ERROR]");
- l = UCX_LOGGER_WARN;
- ucx_map_int_put(logger->levels, l, (void*) "[WARNING]");
- l = UCX_LOGGER_INFO;
- ucx_map_int_put(logger->levels, l, (void*) "[INFO]");
- l = UCX_LOGGER_DEBUG;
- ucx_map_int_put(logger->levels, l, (void*) "[DEBUG]");
- l = UCX_LOGGER_TRACE;
- ucx_map_int_put(logger->levels, l, (void*) "[TRACE]");
- }
-
- return logger;
-}
-
-void ucx_logger_free(UcxLogger *logger) {
- ucx_map_free(logger->levels);
- free(logger);
-}
-
-// estimated max. message length (documented)
-#define UCX_LOGGER_MSGMAX 4096
-
-void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file,
- const unsigned int line, const char *format, ...) {
- if (level <= logger->level) {
- char msg[UCX_LOGGER_MSGMAX];
- const char *text;
- size_t k = 0;
- size_t n;
-
- if ((logger->mask & UCX_LOGGER_LEVEL) > 0) {
- text = (const char*) ucx_map_int_get(logger->levels, level);
- if (!text) {
- text = "[UNKNOWN]";
- }
- n = strlen(text);
- n = n > 256 ? 256 : n;
- memcpy(msg+k, text, n);
- k += n;
- msg[k++] = ' ';
- }
- if ((logger->mask & UCX_LOGGER_TIMESTAMP) > 0) {
- time_t now = time(NULL);
- k += strftime(msg+k, 128, logger->dateformat, localtime(&now));
- }
- if ((logger->mask & UCX_LOGGER_SOURCE) > 0) {
- char *fpart = strrchr(file, '/');
- if (fpart) file = fpart+1;
- fpart = strrchr(file, '\\');
- if (fpart) file = fpart+1;
- n = strlen(file);
- memcpy(msg+k, file, n);
- k += n;
- k += sprintf(msg+k, ":%u ", line);
- }
-
- if (k > 0) {
- msg[k++] = '-'; msg[k++] = ' ';
- }
-
- va_list args;
- va_start (args, format);
- k += vsnprintf(msg+k, UCX_LOGGER_MSGMAX-k-1, format, args);
- va_end (args);
-
- msg[k++] = '\n';
-
- logger->writer(msg, 1, k, logger->stream);
- }
-}
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 "ucx/stack.h"
-
-#include <string.h>
-
-static size_t ucx_stack_align(size_t n) {
- int align = n % sizeof(void*);
- if (align) {
- n += sizeof(void*) - align;
- }
- return n;
-}
-
-void ucx_stack_init(UcxStack *stack, char* space, size_t size) {
- stack->size = size - size % sizeof(void*);
- stack->space = space;
- stack->top = NULL;
-
- stack->allocator.pool = stack;
- stack->allocator.malloc = (ucx_allocator_malloc) ucx_stack_malloc;
- stack->allocator.calloc = (ucx_allocator_calloc) ucx_stack_calloc;
- stack->allocator.realloc = (ucx_allocator_realloc) ucx_stack_realloc;
- stack->allocator.free = (ucx_allocator_free) ucx_stack_free;
-}
-
-void *ucx_stack_malloc(UcxStack *stack, size_t n) {
-
- if (ucx_stack_avail(stack) < ucx_stack_align(n)) {
- return NULL;
- } else {
- char *prev = stack->top;
- if (stack->top) {
- stack->top += ucx_stack_align(ucx_stack_topsize(stack));
- } else {
- stack->top = stack->space;
- }
-
- ((struct ucx_stack_metadata*)stack->top)->prev = prev;
- ((struct ucx_stack_metadata*)stack->top)->size = n;
- stack->top += sizeof(struct ucx_stack_metadata);
-
- return stack->top;
- }
-}
-
-void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize) {
- void *mem = ucx_stack_malloc(stack, nelem*elsize);
- memset(mem, 0, nelem*elsize);
- return mem;
-}
-
-void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n) {
- if (ptr == stack->top) {
- if (stack->size - (stack->top - stack->space) < ucx_stack_align(n)) {
- return NULL;
- } else {
- ((struct ucx_stack_metadata*)stack->top - 1)->size = n;
- return ptr;
- }
- } else {
- if (ucx_stack_align(((struct ucx_stack_metadata*)ptr - 1)->size) <
- ucx_stack_align(n)) {
- void *nptr = ucx_stack_malloc(stack, n);
- if (nptr) {
- memcpy(nptr, ptr, n);
- ucx_stack_free(stack, ptr);
-
- return nptr;
- } else {
- return NULL;
- }
- } else {
- ((struct ucx_stack_metadata*)ptr - 1)->size = n;
- return ptr;
- }
- }
-}
-
-void ucx_stack_free(UcxStack *stack, void *ptr) {
- if (ptr == stack->top) {
- stack->top = ((struct ucx_stack_metadata*) stack->top - 1)->prev;
- } else {
- struct ucx_stack_metadata *next = (struct ucx_stack_metadata*)(
- (char*)ptr +
- ucx_stack_align(((struct ucx_stack_metadata*) ptr - 1)->size)
- );
- next->prev = ((struct ucx_stack_metadata*) ptr - 1)->prev;
- }
-}
-
-void ucx_stack_popn(UcxStack *stack, void *dest, size_t n) {
- if (ucx_stack_empty(stack)) {
- return;
- }
-
- if (dest) {
- size_t len = ucx_stack_topsize(stack);
- if (len > n) {
- len = n;
- }
-
- memcpy(dest, stack->top, len);
- }
-
- ucx_stack_free(stack, stack->top);
-}
-
-size_t ucx_stack_avail(UcxStack *stack) {
- size_t avail = ((stack->top ? (stack->size
- - (stack->top - stack->space)
- - ucx_stack_align(ucx_stack_topsize(stack)))
- : stack->size));
-
- if (avail > sizeof(struct ucx_stack_metadata)) {
- return avail - sizeof(struct ucx_stack_metadata);
- } else {
- return 0;
- }
-}
-
-void *ucx_stack_push(UcxStack *stack, size_t n, const void *data) {
- void *space = ucx_stack_malloc(stack, n);
- if (space) {
- memcpy(space, data, n);
- }
- return space;
-}
-
-void *ucx_stack_pusharr(UcxStack *stack,
- size_t nelem, size_t elsize, const void *data) {
-
- // skip the memset by using malloc
- void *space = ucx_stack_malloc(stack, nelem*elsize);
- if (space) {
- memcpy(space, data, nelem*elsize);
- }
- return space;
-}
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 "ucx/test.h"
-
-UcxTestSuite* ucx_test_suite_new() {
- UcxTestSuite* suite = (UcxTestSuite*) malloc(sizeof(UcxTestSuite));
- if (suite != NULL) {
- suite->success = 0;
- suite->failure = 0;
- suite->tests = NULL;
- }
-
- return suite;
-}
-
-void ucx_test_suite_free(UcxTestSuite* suite) {
- UcxTestList *l = suite->tests;
- while (l != NULL) {
- UcxTestList *e = l;
- l = l->next;
- free(e);
- }
- free(suite);
-}
-
-int ucx_test_register(UcxTestSuite* suite, UcxTest test) {
- if (suite->tests) {
- UcxTestList *newelem = (UcxTestList*) malloc(sizeof(UcxTestList));
- if (newelem) {
- newelem->test = test;
- newelem->next = NULL;
-
- UcxTestList *last = suite->tests;
- while (last->next) {
- last = last->next;
- }
- last->next = newelem;
-
- return EXIT_SUCCESS;
- } else {
- return EXIT_FAILURE;
- }
- } else {
- suite->tests = (UcxTestList*) malloc(sizeof(UcxTestList));
- if (suite->tests) {
- suite->tests->test = test;
- suite->tests->next = NULL;
-
- return EXIT_SUCCESS;
- } else {
- return EXIT_FAILURE;
- }
- }
-}
-
-void ucx_test_run(UcxTestSuite* suite, FILE* output) {
- suite->success = 0;
- suite->failure = 0;
- for (UcxTestList* elem = suite->tests ; elem ; elem = elem->next) {
- elem->test(suite, output);
- }
- fwrite("\nAll test completed.\n", 1, 21, output);
- fprintf(output, " Total: %u\n Success: %u\n Failure: %u\n",
- suite->success+suite->failure, suite->success, suite->failure);
-}
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 "ucx/utils.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <limits.h>
-#include <errno.h>
-
-/* COPY FUCNTIONS */
-void* ucx_strcpy(const void* s, void* data) {
- const char *str = (const char*) s;
- size_t n = 1+strlen(str);
- char *cpy = (char*) malloc(n);
- memcpy(cpy, str, n);
- return cpy;
-}
-
-void* ucx_memcpy(const void* m, void* n) {
- size_t k = *((size_t*)n);
- void *cpy = malloc(k);
- memcpy(cpy, m, k);
- return cpy;
-}
-
-size_t ucx_stream_bncopy(void *src, void *dest, read_func readfnc,
- write_func writefnc, char* buf, size_t bufsize, size_t n) {
- if(n == 0 || bufsize == 0) {
- return 0;
- }
-
- char *lbuf;
- size_t ncp = 0;
-
- if(buf) {
- lbuf = buf;
- } else {
- lbuf = (char*)malloc(bufsize);
- if(lbuf == NULL) {
- return 0;
- }
- }
-
- size_t r;
- size_t rn = bufsize > n ? n : bufsize;
- while((r = readfnc(lbuf, 1, rn, src)) != 0) {
- r = writefnc(lbuf, 1, r, dest);
- ncp += r;
- n -= r;
- rn = bufsize > n ? n : bufsize;
- if(r == 0 || n == 0) {
- break;
- }
- }
-
- if (lbuf != buf) {
- free(lbuf);
- }
-
- return ncp;
-}
-
-/* COMPARE FUNCTIONS */
-
-int ucx_cmp_str(const void *s1, const void *s2, void *data) {
- return strcmp((const char*)s1, (const char*)s2);
-}
-
-int ucx_cmp_strn(const void *s1, const void *s2, void *n) {
- return strncmp((const char*)s1, (const char*)s2, *((size_t*) n));
-}
-
-int ucx_cmp_sstr(const void *s1, const void *s2, void *data) {
- sstr_t a = *(const sstr_t*) s1;
- sstr_t b = *(const sstr_t*) s2;
- return sstrcmp(a, b);
-}
-
-int ucx_cmp_int(const void *i1, const void *i2, void *data) {
- int a = *((const int*) i1);
- int b = *((const int*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_longint(const void *i1, const void *i2, void *data) {
- long int a = *((const long int*) i1);
- long int b = *((const long int*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_longlong(const void *i1, const void *i2, void *data) {
- long long a = *((const long long*) i1);
- long long b = *((const long long*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_int16(const void *i1, const void *i2, void *data) {
- int16_t a = *((const int16_t*) i1);
- int16_t b = *((const int16_t*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_int32(const void *i1, const void *i2, void *data) {
- int32_t a = *((const int32_t*) i1);
- int32_t b = *((const int32_t*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_int64(const void *i1, const void *i2, void *data) {
- int64_t a = *((const int64_t*) i1);
- int64_t b = *((const int64_t*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_uint(const void *i1, const void *i2, void *data) {
- unsigned int a = *((const unsigned int*) i1);
- unsigned int b = *((const unsigned int*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_ulongint(const void *i1, const void *i2, void *data) {
- unsigned long int a = *((const unsigned long int*) i1);
- unsigned long int b = *((const unsigned long int*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_ulonglong(const void *i1, const void *i2, void *data) {
- unsigned long long a = *((const unsigned long long*) i1);
- unsigned long long b = *((const unsigned long long*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_uint16(const void *i1, const void *i2, void *data) {
- uint16_t a = *((const uint16_t*) i1);
- uint16_t b = *((const uint16_t*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_uint32(const void *i1, const void *i2, void *data) {
- uint32_t a = *((const uint32_t*) i1);
- uint32_t b = *((const uint32_t*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_uint64(const void *i1, const void *i2, void *data) {
- uint64_t a = *((const uint64_t*) i1);
- uint64_t b = *((const uint64_t*) i2);
- if (a == b) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-intmax_t ucx_dist_int(const void *i1, const void *i2, void *data) {
- intmax_t a = *((const int*) i1);
- intmax_t b = *((const int*) i2);
- return a - b;
-}
-
-intmax_t ucx_dist_longint(const void *i1, const void *i2, void *data) {
- intmax_t a = *((const long int*) i1);
- intmax_t b = *((const long int*) i2);
- return a - b;
-}
-
-intmax_t ucx_dist_longlong(const void *i1, const void *i2, void *data) {
- intmax_t a = *((const long long*) i1);
- intmax_t b = *((const long long*) i2);
- return a - b;
-}
-
-intmax_t ucx_dist_int16(const void *i1, const void *i2, void *data) {
- intmax_t a = *((const int16_t*) i1);
- intmax_t b = *((const int16_t*) i2);
- return a - b;
-}
-
-intmax_t ucx_dist_int32(const void *i1, const void *i2, void *data) {
- intmax_t a = *((const int32_t*) i1);
- intmax_t b = *((const int32_t*) i2);
- return a - b;
-}
-
-intmax_t ucx_dist_int64(const void *i1, const void *i2, void *data) {
- intmax_t a = *((const int64_t*) i1);
- intmax_t b = *((const int64_t*) i2);
- return a - b;
-}
-
-intmax_t ucx_dist_uint(const void *i1, const void *i2, void *data) {
- uintmax_t a = *((const unsigned int*) i1);
- uintmax_t b = *((const unsigned int*) i2);
- return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a);
-}
-
-intmax_t ucx_dist_ulongint(const void *i1, const void *i2, void *data) {
- uintmax_t a = *((const unsigned long int*) i1);
- uintmax_t b = *((const unsigned long int*) i2);
- return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a);
-}
-
-intmax_t ucx_dist_ulonglong(const void *i1, const void *i2, void *data) {
- uintmax_t a = *((const unsigned long long*) i1);
- uintmax_t b = *((const unsigned long long*) i2);
- return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a);
-}
-
-intmax_t ucx_dist_uint16(const void *i1, const void *i2, void *data) {
- uintmax_t a = *((const uint16_t*) i1);
- uintmax_t b = *((const uint16_t*) i2);
- return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a);
-}
-
-intmax_t ucx_dist_uint32(const void *i1, const void *i2, void *data) {
- uintmax_t a = *((const uint32_t*) i1);
- uintmax_t b = *((const uint32_t*) i2);
- return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a);
-}
-
-intmax_t ucx_dist_uint64(const void *i1, const void *i2, void *data) {
- uintmax_t a = *((const uint64_t*) i1);
- uintmax_t b = *((const uint64_t*) i2);
- return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a);
-}
-
-int ucx_cmp_float(const void *f1, const void *f2, void *epsilon) {
- float a = *((const float*) f1);
- float b = *((const float*) f2);
- float e = !epsilon ? 1e-6f : *((float*)epsilon);
- if (fabsf(a - b) < e) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_double(const void *d1, const void *d2, void *epsilon) {
- double a = *((const double*) d1);
- double b = *((const double*) d2);
- double e = !epsilon ? 1e-14 : *((double*)epsilon);
- if (fabs(a - b) < e) {
- return 0;
- } else {
- return a < b ? -1 : 1;
- }
-}
-
-int ucx_cmp_ptr(const void *ptr1, const void *ptr2, void *data) {
- const intptr_t p1 = (const intptr_t) ptr1;
- const intptr_t p2 = (const intptr_t) ptr2;
- if (p1 == p2) {
- return 0;
- } else {
- return p1 < p2 ? -1 : 1;
- }
-}
-
-int ucx_cmp_mem(const void *ptr1, const void *ptr2, void *n) {
- return memcmp(ptr1, ptr2, *((size_t*)n));
-}
-
-/* PRINTF FUNCTIONS */
-
-#ifdef va_copy
-#define UCX_PRINTF_BUFSIZE 256
-#else
-#pragma message("WARNING: C99 va_copy macro not supported by this platform" \
- " - limiting ucx_*printf to 2 KiB")
-#define UCX_PRINTF_BUFSIZE 0x800
-#endif
-
-int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...) {
- int ret;
- va_list ap;
- va_start(ap, fmt);
- ret = ucx_vfprintf(stream, wfc, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap) {
- char buf[UCX_PRINTF_BUFSIZE];
-#ifdef va_copy
- va_list ap2;
- va_copy(ap2, ap);
- int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
- if (ret < 0) {
- return ret;
- } else if (ret < UCX_PRINTF_BUFSIZE) {
- return (int)wfc(buf, 1, ret, stream);
- } else {
- if (ret == INT_MAX) {
- errno = ENOMEM;
- return -1;
- }
-
- int len = ret + 1;
- char *newbuf = (char*)malloc(len);
- if (!newbuf) {
- return -1;
- }
-
- ret = vsnprintf(newbuf, len, fmt, ap2);
- if (ret > 0) {
- ret = (int)wfc(newbuf, 1, ret, stream);
- }
- free(newbuf);
- }
- return ret;
-#else
- int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
- if (ret < 0) {
- return ret;
- } else if (ret < UCX_PRINTF_BUFSIZE) {
- return (int)wfc(buf, 1, ret, stream);
- } else {
- errno = ENOMEM;
- return -1;
- }
-#endif
-}
-
-sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...) {
- va_list ap;
- sstr_t ret;
- va_start(ap, fmt);
- ret = ucx_vasprintf(allocator, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-sstr_t ucx_vasprintf(UcxAllocator *a, const char *fmt, va_list ap) {
- sstr_t s;
- s.ptr = NULL;
- s.length = 0;
- char buf[UCX_PRINTF_BUFSIZE];
-#ifdef va_copy
- va_list ap2;
- va_copy(ap2, ap);
- int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
- if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) {
- s.ptr = (char*)almalloc(a, ret + 1);
- if (s.ptr) {
- s.length = (size_t)ret;
- memcpy(s.ptr, buf, ret);
- s.ptr[s.length] = '\0';
- }
- } else if (ret == INT_MAX) {
- errno = ENOMEM;
- } else {
- int len = ret + 1;
- s.ptr = (char*)almalloc(a, len);
- if (s.ptr) {
- ret = vsnprintf(s.ptr, len, fmt, ap2);
- if (ret < 0) {
- free(s.ptr);
- s.ptr = NULL;
- } else {
- s.length = (size_t)ret;
- }
- }
- }
-#else
- int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
- if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) {
- s.ptr = (char*)almalloc(a, ret + 1);
- if (s.ptr) {
- s.length = (size_t)ret;
- memcpy(s.ptr, buf, ret);
- s.ptr[s.length] = '\0';
- }
- } else {
- errno = ENOMEM;
- }
-#endif
- return s;
-}
include common/objs.mk
-UI_LIB = ../build/lib/libuitk$(LIB_EXT)
+UI_LIB = ../build/lib/$(LIB_PREFIX)uitk$(LIB_EXT)
include $(TOOLKIT)/objs.mk
OBJ = $(TOOLKITOBJS) $(COMMONOBJS)
include $(TOOLKIT)/Makefile
-$(COMMON_OBJPRE)%.o: common/%.c
+$(COMMON_OBJPRE)uic_%$(OBJ_EXT): common/%.c
$(CC) -o $@ -c -I../ucx/ $(CFLAGS) $(TK_CFLAGS) $<
* POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef _WIN32
+
#include "condvar.h"
#include <stdlib.h>
free(p);
}
+
+#endif
\ No newline at end of file
memset(ctx, 0, sizeof(UiContext));
ctx->mp = mp;
ctx->allocator = mp->allocator;
+ ctx->destroy_handler = cxArrayListCreate(ctx->allocator, NULL, sizeof(UiDestroyHandler), 16);
ctx->obj = toplevel;
ctx->vars = cxHashMapCreate(mp->allocator, CX_STORE_POINTERS, 16);
return ctx->parent ? uic_root_context(ctx->parent) : ctx;
}
+void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data) {
+ UiDestroyHandler handler;
+ handler.destructor = func;
+ handler.data = data;
+ cxListAdd(ctx->destroy_handler, &handler);
+}
+
void uic_context_prepare_close(UiContext *ctx) {
cxListClear(ctx->groups);
cxListClear(ctx->group_widgets);
ctx->document = 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
}
}
- var_ctx = ctx->parent;
+ var_ctx = var_ctx->parent;
}
}
CxMapIterator mi = cxMapIterator(ctx->vars);
cx_foreach(CxMapEntry*, entry, mi) {
UiVar *var = entry->value;
- if(var->from && var->from_ctx) {
+ // var->from && var->from_ctx && var->from_ctx != ctx
+ if(var->from) {
uic_save_var2(var);
uic_copy_binding(var, var->from, FALSE);
- cxMapPut(var->from_ctx->vars_unbound, *entry->key, var->from);
- var->from_ctx = ctx;
+ cxMapPut(var->from->from_ctx->vars_unbound, *entry->key, var->from);
+ var->from = NULL;
}
}
void uic_context_detach_document2(UiContext *ctx, void *document) {
// find the document in the documents list
- ssize_t docIndex = cxListFind(ctx->documents, document);
- if(docIndex < 0) {
+ size_t docIndex = cxListFind(ctx->documents, document);
+ if(!cxListIndexValid(ctx->documents, docIndex)) {
return;
}
UiContext *docctx = ui_document_context(document);
uic_context_unbind_vars(docctx); // unbind all doc/subdoc vars from the parent
+ docctx->parent = NULL;
}
void uic_context_detach_all(UiContext *ctx) {
var = ui_malloc(ctx, sizeof(UiVar));
var->type = type;
var->value = uic_create_value(ctx, type);
+ var->original_value = NULL;
var->from = NULL;
var->from_ctx = ctx;
var->from = NULL;
var->from_ctx = ctx;
var->value = value;
+ var->original_value = NULL;
var->type = UI_VAR_SPECIAL;
return var;
}
}
void *fromvalue = from->value;
+ void *tovalue = to->value;
// update var
if(copytodoc) {
- to->from = from;
- to->from_ctx = from->from_ctx;
+ to->from = from; // from which UiVar are the bindings copied
+ from->original_value = fromvalue; // save original value otherwise it would be lost
+ // widgets store a reference to the UiVar with their value
+ // the UiVar object must be updated to contain the current value object
+ from->value = tovalue;
+ } else {
+ if(to->original_value) {
+ to->value = to->original_value;
+ tovalue = to->value;
+ }
}
+ ui_setop_enable(TRUE);
+
// copy binding
// we don't copy the observer, because the from var has never one
switch(from->type) {
case UI_VAR_SPECIAL: break;
case UI_VAR_INTEGER: {
UiInteger *f = fromvalue;
- UiInteger *t = to->value;
+ UiInteger *t = tovalue;
if(!f->obj) break;
uic_int_copy(f, t);
t->set(t, t->value);
}
case UI_VAR_DOUBLE: {
UiDouble *f = fromvalue;
- UiDouble *t = to->value;
+ UiDouble *t = tovalue;
if(!f->obj) break;
uic_double_copy(f, t);
t->set(t, t->value);
}
case UI_VAR_STRING: {
UiString *f = fromvalue;
- UiString *t = to->value;
+ UiString *t = tovalue;
if(!f->obj) break;
uic_string_copy(f, t);
char *tvalue = t->value.ptr ? t->value.ptr : "";
+ char *fvalue = f->value.ptr ? f->value.ptr : "";
t->set(t, tvalue);
break;
}
case UI_VAR_TEXT: {
UiText *f = fromvalue;
- UiText *t = to->value;
+ UiText *t = tovalue;
if(!f->obj) break;
uic_text_copy(f, t);
- char *tvalue = t->value.ptr ? t->value.ptr : "";
- t->set(t, tvalue);
- t->setposition(t, t->pos);
+ t->restore(t);
break;
}
- case UI_VAR_LIST: {
- // TODO: not sure how correct this is
-
- UiList *f = from->value;
- UiList *t = to->value;
- if (f->obj) {
- t->obj = f->obj;
- t->update = f->update;
- t->getselection = f->getselection;
- t->setselection = f->setselection;
- }
-
- UiVar tmp = *from;
- *from = *to;
- *to = tmp;
-
- UiList* t2 = to->value;
- ui_notify(t2->observers, NULL);
-
+ case UI_VAR_LIST: {
+ UiList *f = fromvalue;
+ UiList *t = tovalue;
+ uic_list_copy(f, t);
+ ui_list_update(t);
break;
}
case UI_VAR_RANGE: {
UiRange *f = fromvalue;
- UiRange *t = to->value;
+ UiRange *t = tovalue;
if(!f->obj) break;
uic_range_copy(f, t);
t->setextent(t, t->extent);
}
case UI_VAR_GENERIC: {
UiGeneric *f = fromvalue;
- UiGeneric *t = to->value;
+ UiGeneric *t = tovalue;
if(!f->obj) break;
uic_generic_copy(f, t);
t->set(t, t->value, t->type);
break;
}
}
+
+ ui_setop_enable(FALSE);
}
void uic_save_var2(UiVar *var) {
}
UIEXPORT void ui_context_destroy(UiContext *ctx) {
+ CxIterator i = cxListIterator(ctx->destroy_handler);
+ cx_foreach(UiDestroyHandler *, h, i) {
+ h->destructor(h->data);
+ }
cxMempoolFree(ctx->mp);
}
extern "C" {
#endif
-typedef struct UiVar UiVar;
-typedef struct UiListPtr UiListPtr;
-typedef struct UiListVar UiListVar;
-typedef struct UiGroupWidget UiGroupWidget;
+typedef struct UiVar UiVar;
+typedef struct UiListPtr UiListPtr;
+typedef struct UiListVar UiListVar;
+typedef struct UiGroupWidget UiGroupWidget;
+typedef struct UiDestroyHandler UiDestroyHandler;
-typedef enum UiVarType UiVarType;
-
-enum UiVarType {
+typedef enum UiVarType {
UI_VAR_SPECIAL = 0,
UI_VAR_INTEGER,
UI_VAR_DOUBLE,
UI_VAR_LIST,
UI_VAR_RANGE,
UI_VAR_GENERIC
-};
+} UiVarType;
struct UiContext {
UiContext *parent;
UiObject *obj;
CxMempool *mp;
const CxAllocator *allocator;
+ CxList *destroy_handler;
void *document;
CxList *documents;
// UiVar replacement, rename it to UiVar when finished
struct UiVar {
void *value;
+ void *original_value;
UiVarType type;
- UiVar *from;
+ UiVar *from;
UiContext *from_ctx;
};
int numgroups;
};
+struct UiDestroyHandler {
+ cx_destructor_func destructor;
+ void *data;
+};
+
void uic_init_global_context(void);
UiContext* uic_context(UiObject *toplevel, CxMempool *mp);
UiContext* uic_root_context(UiContext *ctx);
+void uic_context_add_destructor(UiContext *ctx, cx_destructor_func func, void *data);
void uic_context_set_document(UiContext *ctx, void *document); // deprecated
void uic_context_detach_document(UiContext *ctx); // deprecated
void uic_context_attach_document(UiContext *ctx, void *document);
void uic_context_detach_document2(UiContext *ctx, void *document);
+void uic_context_attach_context(UiContext *ctx, UiContext *doc_ctx);
+void uic_context_detach_context(UiContext *ctx, UiContext *doc_ctx);
void uic_context_detach_all(UiContext *ctx);
UiVar* uic_get_var(UiContext *ctx, const char *name);
}
void* ui_document_new(size_t size) {
- CxMempool *mp = cxMempoolCreate(256, NULL);
+ CxMempool *mp = cxMempoolCreateSimple(256);
const CxAllocator *a = mp->allocator;
UiContext *ctx = uic_context(NULL, mp);
COMMON_SRC_DIR = ui/common/
COMMON_OBJPRE = $(OBJ_DIR)$(COMMON_SRC_DIR)
-COMMON_OBJ = context.o
-COMMON_OBJ += document.o
-COMMON_OBJ += object.o
-COMMON_OBJ += types.o
-COMMON_OBJ += menu.o
-COMMON_OBJ += properties.o
-COMMON_OBJ += menu.o
-COMMON_OBJ += toolbar.o
-COMMON_OBJ += ucx_properties.o
-COMMON_OBJ += threadpool.o
-COMMON_OBJ += condvar.o
+COMMON_OBJ = context$(OBJ_EXT)
+COMMON_OBJ += document$(OBJ_EXT)
+COMMON_OBJ += object$(OBJ_EXT)
+COMMON_OBJ += types$(OBJ_EXT)
+COMMON_OBJ += menu$(OBJ_EXT)
+COMMON_OBJ += properties$(OBJ_EXT)
+COMMON_OBJ += menu$(OBJ_EXT)
+COMMON_OBJ += toolbar$(OBJ_EXT)
+COMMON_OBJ += ucx_properties$(OBJ_EXT)
+COMMON_OBJ += threadpool$(OBJ_EXT)
+COMMON_OBJ += condvar$(OBJ_EXT)
-TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)%)
-TOOLKITSOURCE += $(COMMON_OBJ:%.o=common/%.c)
+TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
+TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
#include <sys/stat.h>
#include <errno.h>
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
#include "../ui/toolkit.h"
static int ui_mkdir(char *path) {
#ifdef _WIN32
- return mkdir(path);
+ return _mkdir(path);
#else
return mkdir(path, S_IRWXU);
#endif
* POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef _WIN32
+
#include "threadpool.h"
#include "context.h"
-#ifndef _WIN32
-
#include <pthread.h>
#include <stdio.h>
#include <string.h>
UIEXPORT void ui_list_update(UiList *list) {
if(list->update) {
- list->update(list, 0);
+ list->update(list, -1);
}
}
void ui_int_set(UiInteger* i, int64_t value) {
if (i) {
if (i->set) {
+ ui_setop_enable(TRUE);
i->set(i, value);
+ ui_setop_enable(FALSE);
} else {
i->value = value;
}
void ui_double_set(UiDouble* d, double value) {
if (d) {
if (d->set) {
+ ui_setop_enable(TRUE);
d->set(d, value);
+ ui_setop_enable(FALSE);
} else {
d->value = value;
}
void ui_string_set(UiString* s, const char* value) {
if (s) {
if (s->set) {
+ ui_setop_enable(TRUE);
s->set(s, value);
+ ui_setop_enable(FALSE);
} else {
if(s->value.free) {
s->value.free(s->value.ptr);
void ui_text_set(UiText* s, const char* value) {
if (s) {
if (s->set) {
+ ui_setop_enable(TRUE);
s->set(s, value);
+ ui_setop_enable(FALSE);
} else {
if(s->value.free) {
s->value.free(s->value.ptr);
to->selection = from->selection;
to->length = from->length;
to->remove = from->remove;
+ to->restore = from->restore;
+ to->save = from->save;
+ to->destroy = from->destroy;
to->obj = from->obj;
- // do not copy the undo manager
+ // do not copy the undo manager, data1, data2
}
void uic_range_copy(UiRange *from, UiRange *to) {
void uic_list_copy(UiList *from, UiList *to) {
to->update = from->update;
+ to->getselection = from->getselection;
+ to->setselection = from->setselection;
to->obj = from->obj;
}
void uic_text_save(UiText *t) {
if(!t->obj) return;
- t->get(t);
+ t->save(t);
t->position(t);
}
t->length = NULL;
t->remove = NULL;
t->obj = NULL;
- t->undomgr = NULL;
}
void uic_range_unbind(UiRange *r) {
destr->observer = observer;
cxMempoolSetDestructor(destr, (cx_destructor_func)observer_destructor);
}
+
+static int ui_set_op = 0;
+
+void ui_setop_enable(int set) {
+ ui_set_op = set;
+}
+
+int ui_get_setop(void) {
+ return ui_set_op;
+}
e.document = event->obj->ctx->document;
e.eventdata = NULL;
e.intval = event->value;
+ e.set = ui_get_setop();
event->callback(&e, event->userdata);
}
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = event->var->value;
- e.intval = i->get(i);
+ e.intval = i->get(i);
+ e.set = ui_get_setop();
ui_notify_evt(i->observers, &e);
}
e.document = event->obj->ctx->document;
e.eventdata = NULL;
e.intval = gtk_toggle_button_get_active(widget);
+ e.set = ui_get_setop();
event->callback(&e, event->userdata);
}
UiObject* current = uic_current_obj(obj);
ui_setup_togglebutton(
- current,
+ obj,
widget,
args.label,
args.icon,
e.document = event->obj->ctx->document;
e.eventdata = NULL;
e.intval = gtk_check_button_get_active(widget);
+ e.set = ui_get_setop();
event->callback(&e, event->userdata);
}
e.document = event->obj->ctx->document;
e.eventdata = NULL;
e.intval = RADIOBUTTON_GET_ACTIVE(widget);
+ e.set = ui_get_setop();
event->callback(&e, event->userdata);
}
return 1;
}
-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_LAYOUT1(current, args);
- current->container->add(current->container, widget, FALSE);
-
- return widget;
-}
-
GtkWidget* ui_gtk_vbox_new(int spacing) {
#if GTK_MAJOR_VERSION >= 3
return gtk_box_new(GTK_ORIENTATION_VERTICAL, spacing);
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);
+ newobj->container = ui_splitpane_container(obj, pane0, orientation, max, args.initial_position);
uic_obj_add(obj, newobj);
+ g_object_set_data(G_OBJECT(pane0), "ui_splitpane", newobj->container);
+
return pane0;
}
return splitpane_create(obj, UI_VERTICAL, args);
}
-UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max) {
+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;
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;
}
+ cxListAdd(s->children, widget);
+
if(s->pos == 0) {
- gtk_paned_set_start_child(GTK_PANED(s->current_pane), widget);
+ PANED_SET_CHILD1(s->current_pane, widget);
+ if(s->initial_position > 0) {
+ gtk_paned_set_position(GTK_PANED(s->current_pane), s->initial_position);
+ }
s->pos++;
s->nchildren++;
} else {
if(s->nchildren+1 == s->max) {
- gtk_paned_set_end_child(GTK_PANED(s->current_pane), widget);
+ PANED_SET_CHILD2(s->current_pane, widget);
} else {
GtkWidget *pane = create_paned(s->orientation);
- gtk_paned_set_start_child(GTK_PANED(pane), widget);
- gtk_paned_set_end_child(GTK_PANED(s->current_pane), pane);
+ PANED_SET_CHILD1(pane, widget);
+ PANED_SET_CHILD2(s->current_pane, pane);
s->current_pane = pane;
}
}
}
+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) {
+ fprintf(stderr, "UI Error: not a splitpane\n");
+ return;
+ }
+
+ GtkWidget *w = cxListAt(ct->children, child_index);
+ if(w) {
+ gtk_widget_set_visible(w, visible);
+ }
+}
+
/* -------------------- ItemList Container -------------------- */
static void remove_item(void *data, void *item) {
elm = list->next(list);
index++;
}
+
+#if GTK_MAJOR_VERSION < 4
+ gtk_widget_show_all(ct->widget);
+#endif
}
static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *container) {
#include <cx/allocator.h>
#include <cx/hash_map.h>
+#include <cx/list.h>
+#include <cx/array_list.h>
#ifdef __cplusplus
extern "C" {
#endif
-
+
#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout))
#define ui_lb2bool(b) ((b) == UI_LAYOUT_TRUE ? TRUE : FALSE)
#define ui_bool2lb(b) ((b) ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE)
typedef struct UiDocumentView UiDocumentView;
-typedef struct UiLayout UiLayout;
-typedef enum UiLayoutBool UiLayoutBool;
-enum UiLayoutBool {
+typedef enum UiLayoutBool {
UI_LAYOUT_UNDEFINED = 0,
UI_LAYOUT_TRUE,
UI_LAYOUT_FALSE,
-};
+} UiLayoutBool;
+typedef struct UiLayout UiLayout;
struct UiLayout {
UiLayoutBool fill;
UiBool newline;
typedef struct UiSplitPaneContainer {
UiContainer container;
GtkWidget *current_pane;
+ CxList *children;
UiOrientation orientation;
int pos;
int max;
int nchildren;
+ int initial_position;
} UiSplitPaneContainer;
typedef struct UiHeaderbarContainer {
UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview);
void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
-UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max);
+UiContainer* ui_splitpane_container(UiObject *obj, GtkWidget *pane, UiOrientation orientation, int max, int init);
void ui_splitpane_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill);
#include "../common/context.h"
#include "../common/object.h"
+static void imageviewer_destroy(UiImageViewer *iv) {
+ if(iv->pixbuf) {
+ g_object_unref(iv->pixbuf);
+ }
+ free(iv);
+}
+
+#if GTK_MAJOR_VERSION >= 4
+
+static void imageviewer_draw(
+ GtkDrawingArea *drawingarea,
+ cairo_t *cr,
+ int width,
+ int height,
+ gpointer userdata)
+{
+ ui_cairo_draw_image(userdata, cr, width, height);
+}
-UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
- UiObject *current = uic_current_obj(obj);
-
- GtkWidget *scrolledwindow = SCROLLEDWINDOW_NEW();
-#if GTK_CHECK_VERSION(4, 0, 0)
- GtkWidget *image = gtk_picture_new();
#else
- GtkWidget *image = gtk_image_new();
+
+static gboolean imageviewer_draw(GtkWidget *widget, cairo_t *cr, gpointer userdata) {
+ int width = gtk_widget_get_allocated_width(widget);
+ int height = gtk_widget_get_allocated_height(widget);
+ ui_cairo_draw_image(userdata, cr, width, height);
+ return FALSE;
+}
+
#endif
+
+UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
+ UiObject *current = uic_current_obj(obj);
- ui_set_name_and_style(image, args.name, args.style_class);
+ GtkWidget *drawingarea = gtk_drawing_area_new();
+ GtkWidget *toplevel;
+ GtkWidget *widget = drawingarea;
+
+ gtk_widget_set_size_request(drawingarea, 100, 100);
#if GTK_MAJOR_VERSION < 4
GtkWidget *eventbox = gtk_event_box_new();
- SCROLLEDWINDOW_SET_CHILD(scrolledwindow, eventbox);
- gtk_container_add(GTK_CONTAINER(eventbox), image);
-#else
- SCROLLEDWINDOW_SET_CHILD(scrolledwindow, image);
- GtkWidget *eventbox = image;
+ gtk_container_add(GTK_CONTAINER(eventbox), drawingarea);
+ widget = eventbox;
#endif
- UI_APPLY_LAYOUT1(current, args);
- current->container->add(current->container, scrolledwindow, TRUE);
+ if(args.scrollarea) {
+ toplevel = SCROLLEDWINDOW_NEW();
+ SCROLLEDWINDOW_SET_CHILD(toplevel, widget);
+ args.adjustwidgetsize = TRUE;
+ } else {
+ toplevel = widget;
+ }
+
+ UiImageViewer *imgviewer = malloc(sizeof(UiImageViewer));
+ memset(imgviewer, 0, sizeof(UiImageViewer));
+ imgviewer->obj = obj;
+ imgviewer->onbuttonpress = args.onbuttonpress;
+ imgviewer->onbuttonpressdata = args.onbuttonpressdata;
+ imgviewer->onbuttonrelease = args.onbuttonrelease;
+ imgviewer->onbuttonreleasedata = args.onbuttonreleasedata;
+ if(args.image_padding > 0) {
+ imgviewer->padding_left = args.image_padding;
+ imgviewer->padding_right = args.image_padding;
+ imgviewer->padding_top = args.image_padding;
+ imgviewer->padding_bottom = args.image_padding;
+ } else {
+ imgviewer->padding_left = args.image_padding_left;
+ imgviewer->padding_right = args.image_padding_right;
+ imgviewer->padding_top = args.image_padding_top;
+ imgviewer->padding_bottom = args.image_padding_bottom;
+ }
+ imgviewer->adjustwidgetsize = args.adjustwidgetsize;
+ imgviewer->autoscale = args.autoscale;
+ imgviewer->useradjustable = args.useradjustable;
+ imgviewer->zoom_scale = 20;
+
+ 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);
+ imgviewer->var = var;
+ imgviewer->widget = drawingarea;
+
if(var) {
UiGeneric *value = var->value;
value->get = ui_imageviewer_get;
value->get_type = ui_imageviewer_get_type;
value->set = ui_imageviewer_set;
- value->obj = image;
+ value->obj = imgviewer;
if(value->value && value->type && !strcmp(value->type, UI_IMAGE_OBJECT_TYPE)) {
GdkPixbuf *pixbuf = value->value;
value->value = NULL;
ui_imageviewer_set(value, pixbuf, UI_IMAGE_OBJECT_TYPE);
+ g_object_unref(pixbuf);
}
}
+#if GTK_MAJOR_VERSION >= 4
+ gtk_drawing_area_set_draw_func(
+ GTK_DRAWING_AREA(drawingarea),
+ imageviewer_draw,
+ imgviewer,
+ NULL);
+
+ if(args.useradjustable) {
+ gtk_widget_set_focusable(drawingarea, TRUE);
+ }
+
+ GtkEventController *scrollcontroller = gtk_event_controller_scroll_new(GTK_EVENT_CONTROLLER_SCROLL_VERTICAL);
+ g_signal_connect(scrollcontroller, "scroll", G_CALLBACK(ui_imageviewer_scroll), imgviewer);
+ gtk_widget_add_controller(GTK_WIDGET(drawingarea), GTK_EVENT_CONTROLLER(scrollcontroller));
+
+ GtkGesture *drag = gtk_gesture_drag_new();
+ g_signal_connect(drag, "drag-begin", G_CALLBACK(ui_imageviewer_drag_begin_cb), imgviewer);
+ g_signal_connect(drag, "drag-end", G_CALLBACK(ui_imageviewer_drag_end_cb), imgviewer);
+ g_signal_connect(drag, "drag-update", G_CALLBACK(ui_imageviewer_drag_update_cb), imgviewer);
+ gtk_widget_add_controller(GTK_WIDGET(drawingarea), GTK_EVENT_CONTROLLER(drag));
+
+ GtkGesture *click = gtk_gesture_click_new();
+ g_signal_connect(click, "pressed", G_CALLBACK(ui_imageviewer_pressed_cb), imgviewer);
+ g_signal_connect(click, "released", G_CALLBACK(ui_imageviewer_released_cb), imgviewer);
+ gtk_widget_add_controller(GTK_WIDGET(drawingarea), GTK_EVENT_CONTROLLER(click));
+
+#elif GTK_MAJOR_VERSION == 3
+ g_signal_connect(
+ drawingarea,
+ "draw",
+ G_CALLBACK(imageviewer_draw),
+ imgviewer);
+
+ gtk_widget_add_events(eventbox, GDK_SCROLL_MASK);
+
+ g_signal_connect(
+ eventbox,
+ "scroll-event",
+ G_CALLBACK(ui_imageviewer_scroll_event),
+ imgviewer);
+ g_signal_connect(
+ eventbox,
+ "button-press-event",
+ G_CALLBACK(ui_imageviewer_button_press_event),
+ imgviewer);
+ g_signal_connect(
+ eventbox,
+ "button-release-event",
+ G_CALLBACK(ui_imageviewer_button_release_event),
+ imgviewer);
+
+#endif
+
if(args.contextmenu) {
- UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, eventbox);
- ui_widget_set_contextmenu(eventbox, menu);
+ UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, widget);
+ ui_widget_set_contextmenu(widget, menu);
}
+
+ UI_APPLY_LAYOUT1(current, args);
+ current->container->add(current->container, toplevel, TRUE);
- return scrolledwindow;
+ return toplevel;
+}
+
+static void imageviewer_reset(UiImageViewer *imgviewer) {
+ imgviewer->isautoscaled = FALSE;
+ imgviewer->transx = 0;
+ imgviewer->transy;
+ imgviewer->begin_transx = 0;
+ imgviewer->begin_transy = 0;
+ imgviewer->scale = 1;
+ imgviewer->user_scale = 1;
+}
+
+UIWIDGET ui_imageviewer_reset(UIWIDGET w) {
+ UiImageViewer *imgviewer = g_object_get_data(G_OBJECT(w), "uiimageviewer");
+ if(imgviewer) {
+ imageviewer_reset(imgviewer);
+ gtk_widget_queue_draw(w);
+ }
+}
+
+UIWIDGET ui_imageviewer_set_autoscale(UIWIDGET w, UiBool set) {
+ UiImageViewer *imgviewer = g_object_get_data(G_OBJECT(w), "uiimageviewer");
+ if(imgviewer) {
+ imgviewer->autoscale = set;
+ }
+}
+
+UIWIDGET ui_imageviewer_set_adjustwidgetsize(UIWIDGET w, UiBool set) {
+ UiImageViewer *imgviewer = g_object_get_data(G_OBJECT(w), "uiimageviewer");
+ if(imgviewer) {
+ imgviewer->adjustwidgetsize = set;
+ }
+}
+
+UIWIDGET ui_imageviewer_set_useradjustable(UIWIDGET w, UiBool set) {
+ UiImageViewer *imgviewer = g_object_get_data(G_OBJECT(w), "uiimageviewer");
+ if(imgviewer) {
+ imgviewer->useradjustable = set;
+ }
+}
+
+void ui_cairo_draw_image(UiImageViewer *imgviewer, cairo_t *cr, int width, int height) {
+ if(!imgviewer->pixbuf) {
+ return;
+ }
+
+ GdkPixbuf *pixbuf = imgviewer->pixbuf;
+ double dpixwidth = (double)gdk_pixbuf_get_width(pixbuf);
+ double dpixheight = (double)gdk_pixbuf_get_height(pixbuf);
+
+ double dwidth = width;
+ double dheight = height;
+ double scale = 1;
+ // if autoscale is enabled, scale the image to fill available space
+ // if useradjustable is also enabled, the autoscaling is only done once
+ if(imgviewer->autoscale && imgviewer->scale != 0) {
+ if(!imgviewer->isautoscaled) {
+ scale = dwidth / dpixwidth;
+ if(dpixheight * scale > dheight) {
+ scale = dheight / dpixheight;
+ }
+
+ if(imgviewer->useradjustable) {
+ imgviewer->isautoscaled = TRUE;
+ }
+
+ imgviewer->scale = scale;
+ } else {
+ scale = imgviewer->scale;
+ }
+
+ imgviewer->user_scale = scale;
+ } else {
+ // user-adjusted scaling
+ //scale = 1 + ((double)imgviewer->zoom / (double)imgviewer->zoom_scale);
+ scale = imgviewer->user_scale;
+ }
+
+ dpixwidth *= scale;
+ dpixheight *= scale;
+ double x = (dwidth - dpixwidth) / 2;
+ double y = (dheight - dpixheight) / 2;
+
+ x += imgviewer->transx;
+ y += imgviewer->transy;
+
+ cairo_translate(cr, x, y);
+ cairo_scale(cr, scale, scale);
+
+ gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
+ cairo_paint(cr);
}
void* ui_imageviewer_get(UiGeneric *g) {
+ UiImageViewer *imgviewer = g->obj;
+ g->value = imgviewer->pixbuf;
return g->value;
}
const char* ui_imageviewer_get_type(UiGeneric *g) {
-
+ return UI_IMAGE_OBJECT_TYPE;
}
int ui_imageviewer_set(UiGeneric *g, void *value, const char *type) {
return 1;
}
- // TODO: do we need to free the previous value here?
-
- g->value = value;
- g->type = type;
GdkPixbuf *pixbuf = value;
+ g_object_ref(pixbuf);
+
+ UiImageViewer *imgviewer = g->obj;
+ g->value = pixbuf;
+
+ imageviewer_reset(imgviewer);
+
+ if(imgviewer->pixbuf) {
+ g_object_unref(imgviewer->pixbuf);
+ }
+ imgviewer->pixbuf = pixbuf;
- if(pixbuf) {
+ if(imgviewer->adjustwidgetsize && !imgviewer->autoscale) {
int width = gdk_pixbuf_get_width(pixbuf);
int height = gdk_pixbuf_get_height(pixbuf);
-
-#if GTK_CHECK_VERSION(4, 0, 0)
- GdkTexture *texture = gdk_texture_new_for_pixbuf(pixbuf);
- gtk_picture_set_paintable(GTK_PICTURE(g->obj), GDK_PAINTABLE(texture));
-#else
- gtk_image_set_from_pixbuf(GTK_IMAGE(g->obj), pixbuf);
-#endif
- gtk_widget_set_size_request(g->obj, width, height);
+ gtk_widget_set_size_request(imgviewer->widget, width, height);
}
-
+ gtk_widget_queue_draw(imgviewer->widget);
return 0;
}
if(obj->set) {
obj->set(obj, pixbuf, UI_IMAGE_OBJECT_TYPE);
+ g_object_unref(pixbuf);
} else {
obj->value = pixbuf;
+ obj->type = UI_IMAGE_OBJECT_TYPE;
+ }
+
+ return 0;
+}
+
+UIEXPORT int ui_image_load_data(UiGeneric *obj, const void *imgdata, size_t size) {
+ GBytes *bytes = g_bytes_new_static(imgdata, size);
+ GInputStream *in = g_memory_input_stream_new_from_bytes(bytes);
+ GError *error = NULL;
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(in, NULL, &error);
+ g_object_unref(in);
+ if(!pixbuf) {
+ return 1;
}
+ if(obj->set) {
+ obj->set(obj, pixbuf, UI_IMAGE_OBJECT_TYPE);
+ g_object_unref(pixbuf);
+ } else {
+ obj->value = pixbuf;
+ obj->type = UI_IMAGE_OBJECT_TYPE;
+ }
+
return 0;
}
+
+void ui_image_ref(UIIMAGE img) {
+ g_object_ref(img);
+}
+
+void ui_image_unref(UIIMAGE img) {
+ g_object_unref(img);
+}
+
+#if GTK_MAJOR_VERSION >= 4
+
+gboolean ui_imageviewer_scroll(
+ GtkEventControllerScroll *widget,
+ gdouble dx,
+ gdouble dy,
+ gpointer userdata)
+{
+ UiImageViewer *imgviewer = userdata;
+ if(imgviewer->useradjustable) {
+ double step = dy / imgviewer->zoom_scale;
+ if(imgviewer->user_scale - step > 0) {
+ imgviewer->user_scale -= step;
+ }
+
+ imgviewer->scale = 0; // disable autoscale
+ gtk_widget_queue_draw(imgviewer->widget);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void ui_imageviewer_drag_begin_cb(
+ GtkGestureDrag *self,
+ gdouble start_x,
+ gdouble start_y,
+ gpointer userdata)
+{
+ UiImageViewer *imgviewer = userdata;
+ imgviewer->begin_transx = imgviewer->transx;
+ imgviewer->begin_transy = imgviewer->transy;
+}
+
+void ui_imageviewer_drag_end_cb(
+ GtkGestureDrag* self,
+ gdouble x,
+ gdouble y,
+ gpointer userdata)
+{
+
+}
+
+void ui_imageviewer_drag_update_cb(
+ GtkGestureDrag *self,
+ gdouble x,
+ gdouble y,
+ gpointer userdata)
+{
+ UiImageViewer *imgviewer = userdata;
+ if(imgviewer->useradjustable) {
+ imgviewer->transx = imgviewer->begin_transx + x;
+ imgviewer->transy = imgviewer->begin_transy + y;
+ gtk_widget_queue_draw(imgviewer->widget);
+ }
+}
+
+static void imgviewer_button_event(
+ GtkGestureClick *gesture,
+ UiImageViewer *imgviewer,
+ ui_callback callback,
+ void *userdata)
+{
+ UiEvent event;
+ event.obj = imgviewer->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = NULL;
+ event.intval = gtk_gesture_single_get_current_button(GTK_GESTURE_SINGLE(gesture));
+ event.set = 0;
+ callback(&event, userdata);
+}
+
+void ui_imageviewer_pressed_cb(
+ GtkGestureClick *self,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer userdata)
+{
+ UiImageViewer *imgviewer = userdata;
+ if(imgviewer->onbuttonpress) {
+ imgviewer_button_event(self, imgviewer, imgviewer->onbuttonpress, imgviewer->onbuttonpressdata);
+ }
+}
+
+void ui_imageviewer_released_cb(
+ GtkGestureClick *self,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer userdata)
+{
+ UiImageViewer *imgviewer = userdata;
+ if(imgviewer->onbuttonrelease) {
+ imgviewer_button_event(self, imgviewer, imgviewer->onbuttonrelease, imgviewer->onbuttonreleasedata);
+ }
+}
+
+#else
+
+gboolean ui_imageviewer_scroll_event(
+ GtkWidget *widget,
+ GdkEventScroll event,
+ gpointer userdata)
+{
+ // TODO
+ return FALSE;
+}
+
+gboolean ui_imageviewer_button_press_event(
+ GtkWidget *widget,
+ GdkEventButton event,
+ gpointer userdata)
+{
+ // TODO
+ return FALSE;
+}
+
+gboolean ui_imageviewer_button_release_event(
+ GtkWidget *widget,
+ GdkEventButton event,
+ gpointer userdata)
+{
+ // TODO
+ return FALSE;
+}
+
+#endif
extern "C" {
#endif
+typedef struct UiImageViewer {
+ UiObject *obj;
+ GtkWidget *widget;
+ UiVar *var;
+ int padding_left;
+ int padding_right;
+ int padding_top;
+ int padding_bottom;
+ UiBool autoscale;
+ UiBool adjustwidgetsize;
+ UiBool useradjustable;
+ GdkPixbuf *pixbuf;
+
+ double zoom_scale;
+ int transx;
+ int transy;
+ int begin_transx;
+ int begin_transy;
+ UiBool isautoscaled;
+ double user_scale;
+ double scale;
+
+ ui_callback onbuttonpress;
+ void *onbuttonpressdata;
+ ui_callback onbuttonrelease;
+ void *onbuttonreleasedata;
+} UiImageViewer;
+
+void ui_cairo_draw_image(UiImageViewer *imgviewer, cairo_t *cr, int width, int height);
void* ui_imageviewer_get(UiGeneric *g);
const char* ui_imageviewer_get_type(UiGeneric *g);
int ui_imageviewer_set(UiGeneric *g, void *value, const char *type);
+#if GTK_MAJOR_VERSION >= 4
+
+gboolean ui_imageviewer_scroll(
+ GtkEventControllerScroll *widget,
+ gdouble dx,
+ gdouble dy,
+ gpointer userdata);
+
+void ui_imageviewer_drag_begin_cb(
+ GtkGestureDrag* self,
+ gdouble start_x,
+ gdouble start_y,
+ gpointer userdata);
+
+void ui_imageviewer_drag_end_cb(
+ GtkGestureDrag* self,
+ gdouble x,
+ gdouble y,
+ gpointer userdata);
+
+void ui_imageviewer_drag_update_cb(
+ GtkGestureDrag* self,
+ gdouble x,
+ gdouble y,
+ gpointer userdata);
+
+void ui_imageviewer_pressed_cb(
+ GtkGestureClick *self,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer userdata);
+
+void ui_imageviewer_released_cb(
+ GtkGestureClick *self,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer userdata);
+
+#else
+
+gboolean ui_imageviewer_scroll_event(
+ GtkWidget *widget,
+ GdkEventScroll event,
+ gpointer userdata);
+
+gboolean ui_imageviewer_button_press_event(
+ GtkWidget *widget,
+ GdkEventButton event,
+ gpointer userdata);
+
+gboolean ui_imageviewer_button_release_event(
+ GtkWidget *widget,
+ GdkEventButton event,
+ gpointer userdata);
+
+#endif
+
#ifdef __cplusplus
}
#endif
};
*/
+static void listview_copy_static_elements(UiListView *listview, char **elm, size_t nelm) {
+ listview->elements = calloc(nelm, sizeof(char*));
+ listview->nelm = nelm;
+ for(int i=0;i<nelm;i++) {
+ listview->elements[i] = strdup(elm[i]);
+ }
+}
+
#if GTK_CHECK_VERSION(4, 10, 0)
list->setselection = ui_listview_setselection2;
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
+ ui_update_liststore_static(ls, listview->elements, listview->nelm);
}
// event handling
// is ignored
g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview);
}
+ if(args.contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view);
+ ui_widget_set_contextmenu(view, menu);
+ }
// add widget to parent
GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
list->setselection = ui_combobox_setselection;
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
+ ui_update_liststore_static(ls, listview->elements, listview->nelm);
}
// event handling
if(args.onactivate) {
- g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview);
+ g_signal_connect(view, "notify::selected", G_CALLBACK(ui_dropdown_notify), listview);
}
// add widget to parent
return view;
}
+void ui_listview_select(UIWIDGET listview, int index) {
+ GtkSelectionModel *model = gtk_list_view_get_model(GTK_LIST_VIEW(listview));
+ gtk_selection_model_select_item(model, index, TRUE);
+}
+
+void ui_combobox_select(UIWIDGET dropdown, int index) {
+ gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index);
+}
+
UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
UiObject* current = uic_current_obj(obj);
if(args.onactivate) {
g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
}
+ if(args.contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view);
+ ui_widget_set_contextmenu(view, menu);
+ }
// add widget to parent
GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
event.window = event.obj->window;
event.intval = view->selection.count;
event.eventdata = &view->selection;
+ event.set = ui_get_setop();
if(cb) {
cb(&event, cbdata);
}
}
-void ui_columnview_activate(void *ignore, guint position, gpointer userdata) {
- UiListView *view = userdata;
- listview_event(view->onactivate, view->onactivatedata, view);
-}
-
-void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer userdata) {
- UiListView *view = userdata;
+static void listview_update_selection(UiListView *view) {
free(view->selection.rows);
view->selection.count = 0;
view->selection.rows = NULL;
} else {
free(newselection);
}
+}
+
+void ui_dropdown_notify(GtkWidget *dropdown, GObject *pspec, gpointer userdata) {
+ UiListView *view = userdata;
+ guint index = gtk_drop_down_get_selected(GTK_DROP_DOWN(dropdown));
+ GObject *item = gtk_drop_down_get_selected_item(GTK_DROP_DOWN(dropdown));
+ if(item && view->onactivate) {
+ ObjWrapper *eventdata = (ObjWrapper*)item;
+ UiEvent event;
+ event.obj = view->obj;
+ event.document = event.obj->ctx->document;
+ event.window = event.obj->window;
+ event.intval = index;
+ event.eventdata = eventdata->data;
+ event.set = ui_get_setop();
+ view->onactivate(&event, view->onactivatedata);
+ }
+}
+
+void ui_columnview_activate(void *ignore, guint position, gpointer userdata) {
+ UiListView *view = userdata;
+ if(view->selection.count == 0) {
+ listview_update_selection(view);
+ }
+ listview_event(view->onactivate, view->onactivatedata, view);
+}
+
+void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer userdata) {
+ UiListView *view = userdata;
+ listview_update_selection(view);
listview_event(view->onselection, view->onselectiondata, view);
}
event.window = event.obj->window;
event.intval = view->selection.count;
event.eventdata = &view->selection;
+ event.set = ui_get_setop();
view->onactivate(&event, view->onactivatedata);
}
}
}
}
+void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm) {
+ g_list_store_remove_all(liststore);
+ for(int i=0;i<nelm;i++) {
+ ObjWrapper *obj = obj_wrapper_new(elm[i]);
+ g_list_store_append(liststore, obj);
+ }
+}
+
void ui_listview_update2(UiList *list, int i) {
UiListView *view = list->obj;
- ui_update_liststore(view->liststore, list);
+ if(i < 0) {
+ ui_update_liststore(view->liststore, list);
+ } else {
+ void *value = list->get(list, i);
+ if(value) {
+ ObjWrapper *obj = obj_wrapper_new(value);
+ // 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);
+ }
+ }
+ }
}
UiListSelection ui_listview_getselection2(UiList *list) {
}
void ui_listview_setselection2(UiList *list, UiListSelection selection) {
+ ui_setop_enable(TRUE);
UiListView *view = list->obj;
UiListSelection newselection;
newselection.count = view->selection.count;
gtk_selection_model_select_item(view->selectionmodel, selection.rows[i], FALSE);
}
}
+ ui_setop_enable(FALSE);
}
UiListSelection ui_combobox_getselection(UiList *list) {
}
void ui_combobox_setselection(UiList *list, UiListSelection selection) {
+ ui_setop_enable(TRUE);
UiListView *view = list->obj;
if(selection.count > 0) {
gtk_drop_down_set_selected(GTK_DROP_DOWN(view->widget), selection.rows[0]);
} else {
gtk_drop_down_set_selected(GTK_DROP_DOWN(view->widget), GTK_INVALID_LIST_POSITION);
}
+ ui_setop_enable(FALSE);
}
#else
+static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, void *elm) {
+ // set column values
+ int c = 0;
+ for(int i=0;i<model->columns;i++,c++) {
+ void *data = model->getvalue(elm, c);
+
+ GValue value = G_VALUE_INIT;
+ switch(model->types[i]) {
+ case UI_STRING:
+ case UI_STRING_FREE: {
+ g_value_init(&value, G_TYPE_STRING);
+ g_value_set_string(&value, data);
+ if(model->types[i] == UI_STRING_FREE) {
+ free(data);
+ }
+ break;
+ }
+ case UI_INTEGER: {
+ g_value_init(&value, G_TYPE_INT);
+ intptr_t intptr = (intptr_t)data;
+ g_value_set_int(&value, (int)intptr);
+ break;
+ }
+ case UI_ICON: {
+ g_value_init(&value, G_TYPE_OBJECT);
+ UiIcon *icon = data;
+#if GTK_MAJOR_VERSION >= 4
+ g_value_set_object(&value, icon->info); // TODO: does this work?
+#else
+ if(!icon->pixbuf && icon->info) {
+ GError *error = NULL;
+ GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error);
+ icon->pixbuf = pixbuf;
+ }
+
+ if(icon->pixbuf) {
+ g_value_set_object(&value, icon->pixbuf);
+ }
+#endif
+ break;
+ }
+ case UI_ICON_TEXT:
+ case UI_ICON_TEXT_FREE: {
+ UiIcon *icon = data;
+#if GTK_MAJOR_VERSION >= 4
+ if(icon) {
+ GValue iconvalue = G_VALUE_INIT;
+ g_value_init(&iconvalue, G_TYPE_OBJECT);
+ g_value_set_object(&iconvalue, ui_icon_pixbuf(icon));
+ gtk_list_store_set_value(store, &iter, c, &iconvalue);
+ }
+#else
+ GValue pixbufvalue = G_VALUE_INIT;
+ if(icon) {
+ if(!icon->pixbuf && icon->info) {
+ GError *error = NULL;
+ GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error);
+ icon->pixbuf = pixbuf;
+ }
+ g_value_init(&pixbufvalue, G_TYPE_OBJECT);
+ g_value_set_object(&pixbufvalue, icon->pixbuf);
+ gtk_list_store_set_value(store, iter, c, &pixbufvalue);
+ }
+#endif
+ c++;
+
+ char *str = model->getvalue(elm, c);
+ g_value_init(&value, G_TYPE_STRING);
+ g_value_set_string(&value, str);
+ if(model->types[i] == UI_ICON_TEXT_FREE) {
+ free(str);
+ }
+ break;
+ }
+ }
+
+ gtk_list_store_set_value(store, iter, c, &value);
+ }
+}
+
static GtkListStore* create_list_store(UiList *list, UiModel *model) {
int columns = model->columns;
GType types[2*columns];
GtkTreeIter iter;
gtk_list_store_insert (store, &iter, -1);
- // set column values
- int c = 0;
- for(int i=0;i<columns;i++,c++) {
- void *data = model->getvalue(elm, c);
-
- GValue value = G_VALUE_INIT;
- switch(model->types[i]) {
- case UI_STRING:
- case UI_STRING_FREE: {
- g_value_init(&value, G_TYPE_STRING);
- g_value_set_string(&value, data);
- if(model->types[i] == UI_STRING_FREE) {
- free(data);
- }
- break;
- }
- case UI_INTEGER: {
- g_value_init(&value, G_TYPE_INT);
- intptr_t intptr = (intptr_t)data;
- g_value_set_int(&value, (int)intptr);
- break;
- }
- case UI_ICON: {
- g_value_init(&value, G_TYPE_OBJECT);
- UiIcon *icon = data;
-#if GTK_MAJOR_VERSION >= 4
- g_value_set_object(&value, icon->info); // TODO: does this work?
-#else
- if(!icon->pixbuf && icon->info) {
- GError *error = NULL;
- GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error);
- icon->pixbuf = pixbuf;
- }
-
- if(icon->pixbuf) {
- g_value_set_object(&value, icon->pixbuf);
- }
-#endif
- break;
- }
- case UI_ICON_TEXT:
- case UI_ICON_TEXT_FREE: {
- UiIcon *icon = data;
-#if GTK_MAJOR_VERSION >= 4
- if(icon) {
- GValue iconvalue = G_VALUE_INIT;
- g_value_init(&iconvalue, G_TYPE_OBJECT);
- g_value_set_object(&iconvalue, ui_icon_pixbuf(icon));
- gtk_list_store_set_value(store, &iter, c, &iconvalue);
- }
-#else
- GValue pixbufvalue = G_VALUE_INIT;
- if(icon) {
- if(!icon->pixbuf && icon->info) {
- GError *error = NULL;
- GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error);
- icon->pixbuf = pixbuf;
- }
- g_value_init(&pixbufvalue, G_TYPE_OBJECT);
- g_value_set_object(&pixbufvalue, icon->pixbuf);
- gtk_list_store_set_value(store, &iter, c, &pixbufvalue);
- }
-#endif
- c++;
-
- char *str = model->getvalue(elm, c);
- g_value_init(&value, G_TYPE_STRING);
- g_value_set_string(&value, str);
- if(model->types[i] == UI_ICON_TEXT_FREE) {
- free(str);
- }
- break;
- }
- }
-
- gtk_list_store_set_value(store, &iter, c, &value);
- }
+ update_list_row(store, &iter, model, elm);
// next row
elm = list->next(list);
g_object_unref(listmodel);
UiListView *listview = malloc(sizeof(UiListView));
+ memset(listview, 0, sizeof(UiListView));
listview->obj = obj;
listview->widget = view;
listview->var = var;
return scroll_area;
}
+void ui_listview_select(UIWIDGET listview, int index) {
+ GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview));
+ GtkTreePath *path = gtk_tree_path_new_from_indicesv(&index, 1);
+ gtk_tree_selection_select_path(sel, path);
+ //g_object_unref(path);
+}
+
+void ui_combobox_select(UIWIDGET dropdown, int index) {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index);
+}
+
UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
UiObject* current = uic_current_obj(obj);
// 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;
tableview->widget = view;
tableview->var = var;
void ui_listview_update(UiList *list, int i) {
UiListView *view = list->obj;
- GtkListStore *store = create_list_store(list, view->model);
- gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store));
- g_object_unref(G_OBJECT(store));
+ if(i < 0) {
+ GtkListStore *store = create_list_store(list, view->model);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store));
+ g_object_unref(G_OBJECT(store));
+ } else {
+ void *elm = list->get(list, 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, elm);
+ }
+ }
}
UiListSelection ui_listview_getselection(UiList *list) {
}
void ui_listview_setselection(UiList *list, UiListSelection selection) {
+ ui_setop_enable(TRUE);
UiListView *view = list->obj;
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view->widget));
GtkTreePath *path = gtk_tree_path_new_from_indicesv(selection.rows, selection.count);
gtk_tree_selection_select_path(sel, path);
//g_object_unref(path);
+ ui_setop_enable(FALSE);
}
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.onactivate, args.onactivatedata);
+ 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_LAYOUT1(current, args);
return combobox;
}
-GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, ui_callback f, void *udata) {
+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;
UiList *list = var ? var->value : NULL;
GtkListStore *listmodel = create_list_store(list, model);
+ if(!list && elm && nelm > 0) {
+ listview_copy_static_elements(uicbox, elm, nelm);
+ for(int i=0;i<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]);
+ gtk_list_store_set_value(listmodel, &iter, 0, &value);
+ }
+ }
+
if(listmodel) {
gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(listmodel));
g_object_unref(listmodel);
event->userdata = udata;
event->callback = f;
event->value = 0;
- event->customdata = NULL;
+ event->customdata = uicbox;
g_signal_connect(
combobox,
}
void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e) {
+ int index = gtk_combo_box_get_active(widget);
+ UiListView *listview = e->customdata;
+ void *eventdata = NULL;
+ if(listview->var && listview->var->value) {
+ UiList *list = listview->var->value;
+ eventdata = ui_list_get(list, index);
+ } else if(listview->elements && listview->nelm > index) {
+ eventdata = listview->elements[index];
+ }
+
UiEvent event;
event.obj = e->obj;
event.window = event.obj->window;
event.document = event.obj->ctx->document;
- event.eventdata = NULL;
- event.intval = gtk_combo_box_get_active(widget);
+ event.eventdata = eventdata;
+ event.intval = index;
+ event.set = ui_get_setop();
e->callback(&event, e->userdata);
}
}
void ui_combobox_setselection(UiList *list, UiListSelection selection) {
+ ui_setop_enable(TRUE);
UiListView *combobox = list->obj;
if(selection.count > 0) {
gtk_combo_box_set_active(GTK_COMBO_BOX(combobox->widget), selection.rows[0]);
}
+ ui_setop_enable(FALSE);
}
e.document = event->obj->ctx->document;
e.eventdata = &selection;
e.intval = selection.count > 0 ? selection.rows[0] : -1;
+ e.set = ui_get_setop();
event->activate(&e, event->activatedata);
if(selection.count > 0) {
e.document = event->obj->ctx->document;
e.eventdata = &selection;
e.intval = selection.count > 0 ? selection.rows[0] : -1;
+ e.set = ui_get_setop();
event->selection(&e, event->selectiondata);
if(selection.count > 0) {
event.document = event.obj->ctx->document;
event.eventdata = dnd;
event.intval = 0;
+ event.set = ui_get_setop();
listview->ondragstart(&event, listview->ondragstartdata);
}
event.document = event.obj->ctx->document;
event.eventdata = &dnd;
event.intval = 0;
+ event.set = ui_get_setop();
listview->ondragcomplete(&event, listview->ondragcompletedata);
}
}
event.document = event.obj->ctx->document;
event.eventdata = &dnd;
event.intval = 0;
+ event.set = ui_get_setop();
listview->ondrop(&event, listview->ondropdata);
}
event.document = event.obj->ctx->document;
event.eventdata = &dnd;
event.intval = 0;
+ event.set = ui_get_setop();
listview->ondragstart(&event, listview->ondragstartdata);
}
}
event.document = event.obj->ctx->document;
event.eventdata = &dnd;
event.intval = 0;
+ event.set = ui_get_setop();
listview->ondragcomplete(&event, listview->ondragcompletedata);
}
}
event.document = event.obj->ctx->document;
event.eventdata = &dnd;
event.intval = 0;
+ event.set = ui_get_setop();
listview->ondrop(&event, listview->ondropdata);
}
}
void ui_listview_destroy(GtkWidget *w, UiListView *v) {
//gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL);
- ui_destroy_boundvar(v->obj->ctx, v->var);
+ if(v->var) {
+ ui_destroy_boundvar(v->obj->ctx, v->var);
+ }
+ if(v->elements) {
+ for(int i=0;i<v->nelm;i++) {
+ free(v->elements[i]);
+ }
+ free(v->elements);
+ }
#if GTK_CHECK_VERSION(4, 10, 0)
free(v->columns);
#endif
}
void ui_combobox_destroy(GtkWidget *w, UiListView *v) {
- ui_destroy_boundvar(v->obj->ctx, v->var);
+ if(v->var) {
+ ui_destroy_boundvar(v->obj->ctx, v->var);
+ }
+ if(v->elements) {
+ for(int i=0;i<v->nelm;i++) {
+ free(v->elements[i]);
+ }
+ free(v->elements);
+ }
free(v);
}
list->obj = uilistbox;
list->update = ui_listbox_dynamic_update;
- ui_listbox_dynamic_update(list, 0);
+ ui_listbox_dynamic_update(list, -1);
}
}
// unbind/free previous list vars
CxIterator i = cxListIterator(uilistbox->sublists);
cx_foreach(UiListBoxSubList *, s, i) {
+ // TODO: "unbind/free previous list vars" will also remove
+ // the widget list. This makes the widget optimization
+ // in ui_listbox_update_sublist pointless
+ // Is it actually possible to not recreate the whole list?
+ CxIterator r = cxListIterator(s->widgets);
+ cx_foreach(GtkWidget*, widget, r) {
+ LISTBOX_REMOVE(uilistbox->listbox, widget);
+ }
+
if(s->var) {
UiList *sl = s->var->value;
sl->obj = NULL;
event.document = event.obj->ctx->document;
event.eventdata = &eventdata;
event.intval = data->value0;
+ event.set = ui_get_setop();
if(data->callback) {
data->callback(&event, data->userdata);
GtkWidget *widget;
UiVar *var;
UiModel *model;
+ char **elements;
+ size_t nelm;
#if GTK_CHECK_VERSION(4, 10, 0)
GListStore *liststore;
GtkSelectionModel *selectionmodel;
void *onactivatedata;
ui_callback onbuttonclick;
void *onbuttonclickdata;
-
GtkListBoxRow *first_row;
};
#if GTK_CHECK_VERSION(4, 10, 0)
void ui_update_liststore(GListStore *liststore, UiList *list);
+void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm);
void ui_listview_update2(UiList *list, int i);
UiListSelection ui_listview_getselection2(UiList *list);
void ui_listview_setselection2(UiList *list, UiListSelection selection);
+void ui_dropdown_notify(GtkWidget *dropdown, GObject *pspec, gpointer userdata);
void ui_columnview_activate(void *ignore, guint position, gpointer userdata);
void ui_listview_selection_changed(GtkSelectionModel* self, guint position, guint n_items, gpointer user_data);
void ui_listview_enable_drop(UiListView *listview, UiListArgs *args);
UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata);
-GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, ui_callback f, void *udata);
+GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **elm, size_t nelm, ui_callback f, void *udata);
void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e);
void ui_combobox_modelupdate(UiList *list, int i);
UiListSelection ui_combobox_getselection(UiList *list);
}
*/
+static void menuitem_list_remove_binding(void *obj) {
+ UiActiveMenuItemList *ls = obj;
+ UiList *list = ls->var->value;
+ CxList *bindings = list->obj;
+ if(bindings) {
+ (void)cxListFindRemove(bindings, obj);
+ if(cxListSize(bindings) == 0) {
+ cxListFree(bindings);
+ list->obj = NULL;
+ list->update = NULL;
+ }
+ }
+}
+
void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) {
UiMenuItemList *il = (UiMenuItemList*)item;
const CxAllocator *a = obj->ctx->allocator;
ls->oldcount = 0;
ls->getvalue = il->getvalue;
- UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST);
- ls->list = var->value;
+ //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;
+ list->update = ui_menulist_update;
+ list->getselection = NULL;
+ list->setselection = NULL;
+
+ // It is possible, that the UiVar is from a global shared context,
+ // used by multiple windows. To support this usecase, the list->obj
+ // binding object is a list of all connected UiActiveMenuItemList.
+ CxList *bindings = list->obj;
+ if(!bindings) {
+ bindings = cxLinkedListCreate(var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS);
+ list->obj = bindings;
+ }
+ cxListAdd(bindings, ls);
+
+ // The destruction of the toplevel obj must remove the menulist binding
+ uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls);
+
+ ui_update_menuitem_list(ls);
+ }
ls->callback = il->callback;
ls->userdata = il->userdata;
-
- UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls);
- ls->list->observers = ui_obsvlist_add(ls->list->observers, observer);
- uic_list_register_observer_destructor(obj->ctx, ls->list, observer);
-
- ui_update_menuitem_list(NULL, ls);
+}
+
+void ui_menulist_update(UiList *list, int ignored) {
+ CxList *bindings = list->obj;
+ CxIterator i = cxListIterator(bindings);
+ cx_foreach(UiActiveMenuItemList *, ls, i) {
+ ui_update_menuitem_list(ls);
+ }
}
-void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) {
+void ui_update_menuitem_list(UiActiveMenuItemList *list) {
// remove old items
if(list->oldcount > 0) {
int i = 0;
}
}
- void* elm = ui_list_first(list->list);
+ UiList *ls = list->var->value;
+
+ void* elm = ui_list_first(ls);
if(elm) {
GtkWidget *widget = gtk_separator_menu_item_new();
gtk_menu_shell_insert(list->menu, widget, list->index);
event);
}
- elm = ui_list_next(list->list);
+ elm = ui_list_next(ls);
i++;
}
}
+static void menuitem_list_remove_binding(void *obj) {
+ UiActiveGMenuItemList *ls = obj;
+ UiList *list = ls->var->value;
+ CxList *bindings = list->obj;
+ if(bindings) {
+ (void)cxListFindRemove(bindings, obj);
+ if(cxListSize(bindings) == 0) {
+ cxListFree(bindings);
+ list->obj = NULL;
+ list->update = NULL;
+ }
+ }
+}
+
void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) {
UiMenuItemList *il = (UiMenuItemList*)item;
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(ui_global_context(), il->varname, UI_VAR_LIST);
+ UiVar* var = uic_create_var(obj->ctx, il->varname, UI_VAR_LIST);
ls->var = var;
- UiList *list = var->value;
+ if(var) {
+ UiList *list = var->value;
+ list->update = ui_menulist_update;
+ list->getselection = NULL;
+ list->setselection = NULL;
+
+ // It is possible, that the UiVar is from a global shared context,
+ // used by multiple windows. To support this usecase, the list->obj
+ // binding object is a list of all connected UiActiveMenuItemList.
+ CxList *bindings = list->obj;
+ if(!bindings) {
+ bindings = cxLinkedListCreate(var->from_ctx->mp->allocator, NULL, CX_STORE_POINTERS);
+ list->obj = bindings;
+ }
+ cxListAdd(bindings, ls);
+
+ // The destruction of the toplevel obj must remove the menulist binding
+ uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls);
+
+ ui_update_gmenu_item_list(ls);
+ }
ls->callback = il->callback;
ls->userdata = il->userdata;
- UiObserver *observer = ui_observer_new((ui_callback)ui_update_gmenu_item_list, ls);
- list->observers = ui_obsvlist_add(list->observers, observer);
- uic_list_register_observer_destructor(obj->ctx, list, observer);
-
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);
"destroy",
G_CALLBACK(ui_destroy_userdata),
event);
-
- ui_update_gmenu_item_list(NULL, ls);
}
void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) {
}
-void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list) {
+void ui_menulist_update(UiList *list, int ignored) {
+ CxList *bindings = list->obj;
+ CxIterator i = cxListIterator(bindings);
+ cx_foreach(UiActiveGMenuItemList *, ls, i) {
+ ui_update_gmenu_item_list(ls);
+ }
+}
+
+void ui_update_gmenu_item_list(UiActiveGMenuItemList *list) {
// remove old items
for(int i=0;i<list->oldcount;i++) {
g_menu_remove(list->menu, list->index);
GtkMenuShell *menu;
int index;
int oldcount;
- UiList *list;
- ui_getvaluefunc getvalue;
- ui_callback callback;
- void *userdata;
+ UiVar *var;
+ ui_getvaluefunc getvalue;
+ ui_callback callback;
+ void *userdata;
};
void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj);
void add_checkitemnv_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj);
void add_menuitem_list_widget(GtkWidget *p, int i, UiMenuItemI *item, UiObject *obj);
-void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list);
+void ui_menulist_update(UiList *list, int ignored);
+void ui_update_menuitem_list(UiActiveMenuItemList *list);
void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event);
void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event);
int64_t ui_checkitem_get(UiInteger *i);
void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event);
void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event);
-void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list);
+void ui_menulist_update(UiList *list, int ignored);
+void ui_update_gmenu_item_list(UiActiveGMenuItemList *list);
#endif
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 <stdio.h>
-#include <stdlib.h>
-
-#include "model.h"
-#include "image.h"
-#include "toolkit.h"
-
-#define IS_UI_LIST_MODEL(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), list_model_type))
-#define UI_LIST_MODEL(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), list_model_type, UiListModel))
-
-static void list_model_class_init(GObjectClass *cl, gpointer data);
-static void list_model_interface_init(GtkTreeModelIface *i, gpointer data);
-static void list_model_init(UiListModel *instance, GObjectClass *cl);
-
-static void list_model_dnd_dest_interface_init(GtkTreeDragDestIface *i, gpointer data);
-static void list_model_dnd_src_interface_init(GtkTreeDragSourceIface *i, gpointer data);
-
-static GObjectClass list_model_class;
-static const GTypeInfo list_model_info = {
- sizeof(GObjectClass),
- NULL,
- NULL,
- (GClassInitFunc)list_model_class_init,
- NULL,
- NULL,
- sizeof(UiListModel),
- 0,
- (GInstanceInitFunc)list_model_init
-};
-static const GInterfaceInfo list_model_interface_info = {
- (GInterfaceInitFunc)list_model_interface_init,
- NULL,
- NULL
-};
-static GType list_model_type;
-
-static const GInterfaceInfo list_model_dnd_dest_interface_info = {
- (GInterfaceInitFunc)list_model_dnd_dest_interface_init,
- NULL,
- NULL
-};
-static const GInterfaceInfo list_model_dnd_src_interface_info = {
- (GInterfaceInitFunc)list_model_dnd_src_interface_init,
- NULL,
- NULL
-};
-
-void ui_list_init() {
- list_model_type = g_type_register_static(
- G_TYPE_OBJECT,
- "UiListModel",
- &list_model_info,
- (GTypeFlags)0);
- g_type_add_interface_static(
- list_model_type,
- GTK_TYPE_TREE_MODEL,
- &list_model_interface_info);
- g_type_add_interface_static(
- list_model_type,
- GTK_TYPE_TREE_DRAG_DEST,
- &list_model_dnd_dest_interface_info);
- g_type_add_interface_static(
- list_model_type,
- GTK_TYPE_TREE_DRAG_SOURCE,
- &list_model_dnd_src_interface_info);
-}
-
-static void list_model_class_init(GObjectClass *cl, gpointer data) {
- cl->dispose = ui_list_model_dispose;
- cl->finalize = ui_list_model_finalize;
-
-}
-
-static void list_model_interface_init(GtkTreeModelIface *i, gpointer data) {
- i->get_flags = ui_list_model_get_flags;
- i->get_n_columns = ui_list_model_get_n_columns;
- i->get_column_type = ui_list_model_get_column_type;
- i->get_iter = ui_list_model_get_iter;
- i->get_path = ui_list_model_get_path;
- i->get_value = ui_list_model_get_value;
- i->iter_next = ui_list_model_iter_next;
- i->iter_children = ui_list_model_iter_children;
- i->iter_has_child = ui_list_model_iter_has_child;
- i->iter_n_children = ui_list_model_iter_n_children;
- i->iter_nth_child = ui_list_model_iter_nth_child;
- i->iter_parent = ui_list_model_iter_parent;
-}
-
-static void list_model_dnd_dest_interface_init(GtkTreeDragDestIface *i, gpointer data) {
- i->drag_data_received = ui_list_model_drag_data_received;
- i->row_drop_possible = ui_list_model_row_drop_possible;
-}
-
-static void list_model_dnd_src_interface_init(GtkTreeDragSourceIface *i, gpointer data) {
- i->drag_data_delete = ui_list_model_drag_data_delete;
- i->drag_data_get = ui_list_model_drag_data_get;
- i->row_draggable = ui_list_model_row_draggable;
-}
-
-static void list_model_init(UiListModel *instance, GObjectClass *cl) {
- instance->columntypes = NULL;
- instance->var = NULL;
- instance->numcolumns = 0;
- instance->stamp = g_random_int();
-}
-
-static GType ui_gtk_type(UiModelType type) {
- switch(type) {
- default: break;
- case UI_STRING: return G_TYPE_STRING;
- case UI_INTEGER: return G_TYPE_INT;
- }
- return G_TYPE_INVALID;
-}
-
-static void ui_model_set_value(GType type, void *data, GValue *value) {
- switch(type) {
- default: break;
- case G_TYPE_OBJECT: {
- value->g_type = G_TYPE_OBJECT;
- g_value_set_object(value, data);
- return;
- }
- case G_TYPE_STRING: {
- value->g_type = G_TYPE_STRING;
- g_value_set_string(value, data);
- return;
- }
- case G_TYPE_INT: {
- value->g_type = G_TYPE_INT;
- int *i = data;
- g_value_set_int(value, *i);
- return;
- }
- }
- value->g_type = G_TYPE_INVALID;
-}
-
-UiListModel* ui_list_model_new(UiObject *obj, UiVar *var, UiModel *info) {
- UiListModel *model = g_object_new(list_model_type, NULL);
- model->obj = obj;
- model->model = info;
- model->var = var;
- model->columntypes = calloc(sizeof(GType), 2 * info->columns);
- int ncol = 0;
- for(int i=0;i<info->columns;i++) {
- UiModelType type = info->types[i];
- if(type == UI_ICON_TEXT) {
- model->columntypes[ncol] = G_TYPE_OBJECT;
- ncol++;
- model->columntypes[ncol] = G_TYPE_STRING;
- } else {
- model->columntypes[ncol] = ui_gtk_type(info->types[i]);
- }
- ncol++;
- }
- model->numcolumns = ncol;
- return model;
-}
-
-void ui_list_model_dispose(GObject *obj) {
-
-}
-
-void ui_list_model_finalize(GObject *obj) {
-
-}
-
-
-GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model) {
- return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST);
-}
-
-gint ui_list_model_get_n_columns(GtkTreeModel *tree_model) {
- g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), 0);
- UiListModel *model = UI_LIST_MODEL(tree_model);
- return model->numcolumns;
-}
-
-GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index) {
- g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), G_TYPE_INVALID);
- UiListModel *model = UI_LIST_MODEL(tree_model);
- g_return_val_if_fail(index < model->numcolumns, G_TYPE_INVALID);
- return model->columntypes[index];
-}
-
-gboolean ui_list_model_get_iter(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreePath *path)
-{
- g_assert(IS_UI_LIST_MODEL(tree_model));
- UiListModel *model = UI_LIST_MODEL(tree_model);
- UiList *list = model->var->value;
-
- // check the depth of the path
- // a list must have a depth of 1
- gint depth = gtk_tree_path_get_depth(path);
- g_assert(depth == 1);
-
- // get row
- gint *indices = gtk_tree_path_get_indices(path);
- gint row = indices[0];
-
- // check row
- if(row == 0) {
- // we don't need to count if the first element is requested
- if(list->first(list) == NULL) {
- return FALSE;
- }
- } else if(row >= list->count(list)) {
- return FALSE;
- }
-
- // the UiList has an integrated iterator
- // we only get a value to adjust it
- void *val = NULL;
- if(row == 0) {
- val = list->first(list);
- } else {
- val = list->get(list, row);
- }
-
- iter->stamp = model->stamp;
- iter->user_data = list->iter;
- iter->user_data2 = (gpointer)(intptr_t)row; // list->index
- iter->user_data3 = val;
-
- return val ? TRUE : FALSE;
-}
-
-GtkTreePath* ui_list_model_get_path(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), NULL);
- g_return_val_if_fail(iter != NULL, NULL);
- g_return_val_if_fail(iter->user_data != NULL, NULL);
-
- UiListModel *model = UI_LIST_MODEL(tree_model);
-
- GtkTreePath *path = gtk_tree_path_new();
- gtk_tree_path_append_index(path, (int)(intptr_t)iter->user_data2); // list->index
-
- return path;
-}
-
-void ui_list_model_get_value(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gint column,
- GValue *value)
-{
- g_return_if_fail(IS_UI_LIST_MODEL(tree_model));
- g_return_if_fail(iter != NULL);
- g_return_if_fail(iter->user_data != NULL);
-
- UiListModel *model = UI_LIST_MODEL(tree_model);
- UiList *list = model->var->value;
-
- g_return_if_fail(column < model->numcolumns);
-
- // TODO: return correct value from column
-
- //value->g_type = G_TYPE_STRING;
- list->iter = iter->user_data;
- //list->index = (int)(intptr_t)iter->user_data2;
- //list->current = iter->user_data3;
- if(model->model->getvalue) {
- void *data = model->model->getvalue(iter->user_data3, column);
- if(model->columntypes[column] == G_TYPE_OBJECT) {
- UiImage *img = data;
- ui_model_set_value(model->columntypes[column], img->pixbuf, value);
- } else {
- ui_model_set_value(model->columntypes[column], data, value);
- }
- } else {
- value->g_type = G_TYPE_INVALID;
- }
-}
-
-gboolean ui_list_model_iter_next(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE);
- g_return_val_if_fail(iter != NULL, FALSE);
- //g_return_val_if_fail(iter->user_data != NULL, FALSE);
-
- if(!iter->user_data) {
- return FALSE;
- }
-
- UiListModel *model = UI_LIST_MODEL(tree_model);
- UiList *list = model->var->value;
- list->iter = iter->user_data;
- //list->index = (int)(intptr_t)iter->user_data2;
- void *val = list->next(list);
- iter->user_data = list->iter;
- intptr_t index = (intptr_t)iter->user_data2;
- index++;
- //iter->user_data2 = (gpointer)(intptr_t)list->index;
- iter->user_data2 = (gpointer)index;
- iter->user_data3 = val;
- return val ? TRUE : FALSE;
-}
-
-gboolean ui_list_model_iter_children(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent)
-{
- g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE);
-
- UiListModel *model = UI_LIST_MODEL(tree_model);
- UiList *list = model->var->value;
-
- if(parent) {
- return FALSE;
- }
-
- /*
- * a list element has no children
- * we set the iter to the first element
- */
- void *val = list->first(list);
- iter->stamp = model->stamp;
- iter->user_data = list->iter;
- iter->user_data2 = (gpointer)0;
- iter->user_data3 = val;
-
- return val ? TRUE : FALSE;
-}
-
-gboolean ui_list_model_iter_has_child(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- return FALSE;
-}
-
-gint ui_list_model_iter_n_children(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- g_assert(IS_UI_LIST_MODEL(tree_model));
-
- if(!iter) {
- // return number of rows
- UiListModel *model = UI_LIST_MODEL(tree_model);
- UiList *list = model->var->value;
- return list->count(list);
- }
-
- return 0;
-}
-
-gboolean ui_list_model_iter_nth_child(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent,
- gint n)
-{
- g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE);
-
- if(parent) {
- return FALSE;
- }
-
- UiListModel *model = UI_LIST_MODEL(tree_model);
- UiList *list = model->var->value;
-
- // check n
- if(n == 0) {
- // we don't need to count if the first element is requested
- if(list->first(list) == NULL) {
- return FALSE;
- }
- } else if(n >= list->count(list)) {
- return FALSE;
- }
-
- void *val = list->get(list, n);
- iter->stamp = model->stamp;
- iter->user_data = list->iter;
- iter->user_data2 = (gpointer)(intptr_t)n; // list->index
- iter->user_data3 = val;
-
- return val ? TRUE : FALSE;
-}
-
-gboolean ui_list_model_iter_parent(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *child)
-{
- return FALSE;
-}
-
-// ****** dnd ******
-
-gboolean ui_list_model_drag_data_received(
- GtkTreeDragDest *drag_dest,
- GtkTreePath *dest_path,
- GtkSelectionData *selection_data)
-{
- //printf("drag received\n");
- UiListModel *model = UI_LIST_MODEL(drag_dest);
- if(model->model->drop) {
- gint *indices = gtk_tree_path_get_indices(dest_path);
- gint row = indices[0];
- UiEvent e;
- e.obj = model->obj;
- e.window = e.obj->window;
- e.document = e.obj->ctx->document;
- e.eventdata = NULL;
- e.intval = 0;
- UiSelection s;
- s.data = selection_data;
- model->model->drop(&e, &s, model->var->value, row);
- }
- return TRUE;
-}
-
-gboolean ui_list_model_row_drop_possible(
- GtkTreeDragDest *drag_dest,
- GtkTreePath *dest_path,
- GtkSelectionData *selection_data)
-{
- //printf("row_drop_possible\n");
- UiListModel *model = UI_LIST_MODEL(drag_dest);
- if(model->model->candrop) {
- gint *indices = gtk_tree_path_get_indices(dest_path);
- gint row = indices[0];
- UiEvent e;
- e.obj = model->obj;
- e.window = e.obj->window;
- e.document = e.obj->ctx->document;
- e.eventdata = NULL;
- e.intval = 0;
- UiSelection s;
- s.data = selection_data;
- return model->model->candrop(&e, &s, model->var->value, row);
- }
- return TRUE;
-}
-
-gboolean ui_list_model_row_draggable(
- GtkTreeDragSource *drag_source,
- GtkTreePath *path)
-{
- //printf("row_draggable\n");
- UiListModel *model = UI_LIST_MODEL(drag_source);
- if(model->model->candrag) {
- gint *indices = gtk_tree_path_get_indices(path);
- gint row = indices[0];
- UiEvent e;
- e.obj = model->obj;
- e.window = e.obj->window;
- e.document = e.obj->ctx->document;
- e.eventdata = NULL;
- e.intval = 0;
- return model->model->candrag(&e, model->var->value, row);
- }
- return TRUE;
-}
-
-gboolean ui_list_model_drag_data_get(
- GtkTreeDragSource *drag_source,
- GtkTreePath *path,
- GtkSelectionData *selection_data)
-{
- //printf("drag_data_get\n");
- UiListModel *model = UI_LIST_MODEL(drag_source);
- if(model->model->data_get) {
- gint *indices = gtk_tree_path_get_indices(path);
- gint row = indices[0];
- UiEvent e;
- e.obj = model->obj;
- e.window = e.obj->window;
- e.document = e.obj->ctx->document;
- e.eventdata = NULL;
- e.intval = 0;
- UiSelection s;
- s.data = selection_data;
- model->model->data_get(&e, &s, model->var->value, row);
- }
- return TRUE;
-}
-
-gboolean ui_list_model_drag_data_delete(
- GtkTreeDragSource *drag_source,
- GtkTreePath *path)
-{
- //printf("drag_data_delete\n");
- UiListModel *model = UI_LIST_MODEL(drag_source);
- if(model->model->data_get) {
- gint *indices = gtk_tree_path_get_indices(path);
- gint row = indices[0];
- UiEvent e;
- e.obj = model->obj;
- e.window = e.obj->window;
- e.document = e.obj->ctx->document;
- e.eventdata = NULL;
- e.intval = 0;
- model->model->data_delete(&e, model->var->value, row);
- }
- return TRUE;
-}
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 MODEL_H
-#define MODEL_H
-
-#include "../ui/toolkit.h"
-#include "../common/context.h"
-#include "../ui/tree.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct UiListModel UiListModel;
-
-/*
- * UiList to GtkTreeModel wrapper
- */
-struct UiListModel {
- GObject object;
- UiObject *obj;
- UiModel *model;
- UiVar *var;
- GType *columntypes;
- int numcolumns;
- int stamp;
-};
-
-/*
- * initialize the class and register the type
- */
-void ui_list_init();
-
-/*
- * Creates a UiListModel for a given UiList
- */
-UiListModel* ui_list_model_new(UiObject *obj, UiVar *var, UiModel *info);
-
-void ui_list_model_dispose(GObject *obj);
-void ui_list_model_finalize(GObject *obj);
-
-
-// interface functions
-
-GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model);
-
-gint ui_list_model_get_n_columns(GtkTreeModel *tree_model);
-
-GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index);
-
-gboolean ui_list_model_get_iter(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreePath *path);
-
-GtkTreePath* ui_list_model_get_path(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-
-void ui_list_model_get_value(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gint column,
- GValue *value);
-
-gboolean ui_list_model_iter_next(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-
-gboolean ui_list_model_iter_children(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent);
-
-gboolean ui_list_model_iter_has_child(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-
-gint ui_list_model_iter_n_children(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-
-gboolean ui_list_model_iter_nth_child(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent,
- gint n);
-
-gboolean ui_list_model_iter_parent(
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *child);
-
-/* dnd */
-
-gboolean ui_list_model_drag_data_received(
- GtkTreeDragDest *drag_dest,
- GtkTreePath *dest,
- GtkSelectionData *selection_data);
-
-gboolean ui_list_model_row_drop_possible(
- GtkTreeDragDest *drag_dest,
- GtkTreePath *dest_path,
- GtkSelectionData *selection_data);
-
-gboolean ui_list_model_row_draggable(
- GtkTreeDragSource *drag_source,
- GtkTreePath *path);
-
-gboolean ui_list_model_drag_data_get(
- GtkTreeDragSource *drag_source,
- GtkTreePath *path,
- GtkSelectionData *selection_data);
-
-gboolean ui_list_model_drag_data_delete(
- GtkTreeDragSource *drag_source,
- GtkTreePath *path);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* MODEL_H */
GTKOBJ += dnd.o
GTKOBJ += headerbar.o
GTKOBJ += webview.o
+GTKOBJ += widget.o
TOOLKITOBJS += $(GTKOBJ:%=$(GTK_OBJPRE)%)
TOOLKITSOURCE += $(GTKOBJ:%.o=gtk/%.c)
}
}
+static void textarea_set_text_funcs(UiText *value) {
+
+}
+
+#if GTK_MAJOR_VERSION == 2
+static void textarea_set_undomgr(GtkWidget *text_area, UiText *value) {
+ GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_area));
+
+ if(!value->data2) {
+ value->data2 = ui_create_undomgr();
+ }
+
+ // register undo manager
+ g_signal_connect(
+ buf,
+ "insert-text",
+ G_CALLBACK(ui_textbuf_insert),
+ var);
+ g_signal_connect(
+ buf,
+ "delete-range",
+ G_CALLBACK(ui_textbuf_delete),
+ var);
+ g_signal_connect(
+ buf,
+ "mark-set",
+ G_CALLBACK(selection_handler),
+ uitext);
+}
+#endif
+
+static GtkTextBuffer* create_textbuffer(UiTextArea *textarea) {
+ GtkTextBuffer *buf = gtk_text_buffer_new(NULL);
+ if(textarea) {
+ g_signal_connect(
+ buf,
+ "changed",
+ G_CALLBACK(ui_textbuf_changed),
+ textarea);
+ } else {
+ fprintf(stderr, "Error: create_textbuffer: textarea == NULL\n");
+ }
+ return buf;
+}
+
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);
uitext->onchange = args.onchange;
uitext->onchangedata = args.onchangedata;
+ g_object_set_data(G_OBJECT(text_area), "ui_textarea", uitext);
+
g_signal_connect(
text_area,
"destroy",
// bind value
if(var) {
UiText *value = var->value;
- GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_area));
-
- if(value->value.ptr) {
- gtk_text_buffer_set_text(buf, value->value.ptr, -1);
- value->value.free(value->value.ptr);
+ GtkTextBuffer *buf;
+ if(value->data1 && value->datatype == UI_TEXT_TYPE_BUFFER) {
+ buf = value->data1;
+ } else {
+ buf = create_textbuffer(uitext);
+ if(value->value.ptr) {
+ gtk_text_buffer_set_text(buf, value->value.ptr, -1);
+ value->value.free(value->value.ptr);
+ }
}
-
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(text_area), buf);
+ value->obj = text_area;
+ value->save = ui_textarea_save;
+ value->restore = ui_textarea_restore;
+ value->destroy = ui_textarea_text_destroy;
value->get = ui_textarea_get;
value->set = ui_textarea_set;
value->getsubstr = ui_textarea_getsubstr;
value->selection = ui_textarea_selection;
value->length = ui_textarea_length;
value->remove = ui_textarea_remove;
+ value->data1 = buf;
+ value->data2 = NULL;
+ value->datatype == UI_TEXT_TYPE_BUFFER;
value->value.ptr = NULL;
value->value.free = NULL;
- value->obj = buf;
- if(!value->undomgr) {
- value->undomgr = ui_create_undomgr();
- }
-
- g_signal_connect(
- buf,
- "changed",
- G_CALLBACK(ui_textbuf_changed),
- uitext);
- // register undo manager
- g_signal_connect(
- buf,
- "insert-text",
- G_CALLBACK(ui_textbuf_insert),
- var);
- g_signal_connect(
- buf,
- "delete-range",
- G_CALLBACK(ui_textbuf_delete),
- var);
- g_signal_connect(
- buf,
- "mark-set",
- G_CALLBACK(selection_handler),
- uitext);
+#if GTK_MAJOR_VERSION == 2
+ textarea_set_undomgr(text_area, value);
+#endif
}
return scroll_area;
return SCROLLEDWINDOW_GET_CHILD(textarea);
}
+void ui_textarea_save(UiText *text) {
+ // NOOP
+}
+
+void ui_textarea_restore(UiText *text) {
+ GtkWidget *textarea = text->obj;
+ if(!text->data1) {
+ text->data1 = create_textbuffer(g_object_get_data(G_OBJECT(textarea), "ui_textarea"));
+ text->datatype = UI_TEXT_TYPE_BUFFER;
+ }
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(textarea), text->data1);
+}
+
+void ui_textarea_text_destroy(UiText *text) {
+ GtkTextBuffer *buf = text->data1;
+ g_object_unref(buf);
+}
+
char* ui_textarea_get(UiText *text) {
if(text->value.ptr) {
text->value.free(text->value.ptr);
}
- GtkTextBuffer *buf = text->obj;
+ GtkTextBuffer *buf = text->data1;
GtkTextIter start;
GtkTextIter end;
gtk_text_buffer_get_bounds(buf, &start, &end);
}
void ui_textarea_set(UiText *text, const char *str) {
- gtk_text_buffer_set_text((GtkTextBuffer*)text->obj, str, -1);
+ gtk_text_buffer_set_text((GtkTextBuffer*)text->data1, str, -1);
if(text->value.ptr) {
text->value.free(text->value.ptr);
}
if(text->value.ptr) {
text->value.free(text->value.ptr);
}
- GtkTextBuffer *buf = text->obj;
+ GtkTextBuffer *buf = text->data1;
GtkTextIter ib;
GtkTextIter ie;
- gtk_text_buffer_get_iter_at_offset(text->obj, &ib, begin);
- gtk_text_buffer_get_iter_at_offset(text->obj, &ie, end);
+ gtk_text_buffer_get_iter_at_offset(text->data1, &ib, begin);
+ gtk_text_buffer_get_iter_at_offset(text->data1, &ie, end);
char *str = gtk_text_buffer_get_text(buf, &ib, &ie, FALSE);
text->value.ptr = g_strdup(str);
text->value.free = (ui_freefunc)g_free;
void ui_textarea_insert(UiText *text, int pos, char *str) {
GtkTextIter offset;
- gtk_text_buffer_get_iter_at_offset(text->obj, &offset, pos);
- gtk_text_buffer_insert(text->obj, &offset, str, -1);
+ gtk_text_buffer_get_iter_at_offset(text->data1, &offset, pos);
+ gtk_text_buffer_insert(text->data1, &offset, str, -1);
if(text->value.ptr) {
text->value.free(text->value.ptr);
}
void ui_textarea_setposition(UiText *text, int pos) {
GtkTextIter iter;
- gtk_text_buffer_get_iter_at_offset(text->obj, &iter, pos);
- gtk_text_buffer_place_cursor(text->obj, &iter);
+ gtk_text_buffer_get_iter_at_offset(text->data1, &iter, pos);
+ gtk_text_buffer_place_cursor(text->data1, &iter);
}
int ui_textarea_position(UiText *text) {
GtkTextIter begin;
GtkTextIter end;
- gtk_text_buffer_get_selection_bounds(text->obj, &begin, &end);
+ gtk_text_buffer_get_selection_bounds(text->data1, &begin, &end);
text->pos = gtk_text_iter_get_offset(&begin);
return text->pos;
}
void ui_textarea_selection(UiText *text, int *begin, int *end) {
GtkTextIter b;
GtkTextIter e;
- gtk_text_buffer_get_selection_bounds(text->obj, &b, &e);
+ gtk_text_buffer_get_selection_bounds(text->data1, &b, &e);
*begin = gtk_text_iter_get_offset(&b);
*end = gtk_text_iter_get_offset(&e);
}
int ui_textarea_length(UiText *text) {
- GtkTextBuffer *buf = text->obj;
+ GtkTextBuffer *buf = text->data1;
GtkTextIter start;
GtkTextIter end;
gtk_text_buffer_get_bounds(buf, &start, &end);
}
void ui_textarea_remove(UiText *text, int begin, int end) {
- GtkTextBuffer *buf = text->obj;
+ GtkTextBuffer *buf = text->data1;
GtkTextIter ib;
GtkTextIter ie;
gtk_text_buffer_get_iter_at_offset(buf, &ib, begin);
e.document = textarea->ctx->document;
e.eventdata = value;
e.intval = 0;
+ e.set = ui_get_setop();
if(textarea->onchange) {
textarea->onchange(&e, textarea->onchangedata);
{
UiVar *var = data;
UiText *value = var->value;
- if(!value->undomgr) {
- value->undomgr = ui_create_undomgr();
+ if(!value->data2) {
+ value->data2 = ui_create_undomgr();
}
- UiUndoMgr *mgr = value->undomgr;
+ UiUndoMgr *mgr = value->data2;
if(!mgr->event) {
return;
}
{
UiVar *var = data;
UiText *value = var->value;
- if(!value->undomgr) {
- value->undomgr = ui_create_undomgr();
+ if(!value->data2) {
+ value->data2 = ui_create_undomgr();
}
- UiUndoMgr *mgr = value->undomgr;
+ UiUndoMgr *mgr = value->data2;
if(!mgr->event) {
return;
}
}
void ui_text_undo(UiText *value) {
- UiUndoMgr *mgr = value->undomgr;
+ UiUndoMgr *mgr = value->data2;
if(mgr->cur) {
UiTextBufOp *op = mgr->cur;
}
void ui_text_redo(UiText *value) {
- UiUndoMgr *mgr = value->undomgr;
+ UiUndoMgr *mgr = value->data2;
UiTextBufOp *elm = NULL;
if(mgr->cur) {
e.document = textfield->obj->ctx->document;
e.eventdata = value;
e.intval = 0;
+ e.set = ui_get_setop();
if(textfield->onchange) {
textfield->onchange(&e, textfield->onchangedata);
e.document = textfield->obj->ctx->document;
e.eventdata = NULL;
e.intval = 0;
+ e.set = ui_get_setop();
textfield->onactivate(&e, textfield->onactivatedata);
}
}
evt.document = evt.obj->ctx->document;
evt.eventdata = elm->path;
evt.intval = event->value0;
+ evt.set = ui_get_setop();
event->callback(&evt, event->userdata);
free(path.ptr);
}
UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var);
void ui_textarea_destroy(GtkWidget *object, UiTextArea *textarea);
+void ui_textarea_save(UiText *text);
+void ui_textarea_restore(UiText *text);
+void ui_textarea_text_destroy(UiText *text);
char* ui_textarea_get(UiText *text);
void ui_textarea_set(UiText *text, const char *str);
char* ui_textarea_getsubstr(UiText *text, int begin, int end);
}
void ui_set_visible(UIWIDGET widget, int visible) {
- // TODO: gtk4
-#if GTK_MAJOR_VERSION <= 3
+#if GTK_MAJOR_VERSION >= 4
+ gtk_widget_set_visible(widget, visible);
+#else
if(visible) {
gtk_widget_set_no_show_all(widget, FALSE);
gtk_widget_show_all(widget);
#if GTK_MAJOR_VERSION >= 3
-static GtkCssProvider* ui_gtk_css_provider;
-
#if GTK_MAJOR_VERSION == 4
static const char *ui_gtk_css =
"#path-textfield-box {\n"
#endif
void ui_css_init(void) {
- ui_gtk_css_provider = gtk_css_provider_new();
+ ui_add_styledata(ui_gtk_css, -1);
+}
+
+void ui_add_styledata(const char *styledata, int len) {
+ GtkCssProvider *css = gtk_css_provider_new();
#ifdef UI_GTK3
- gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1, NULL);
+ gtk_css_provider_load_from_data(css, styledata, len, NULL);
GdkScreen *screen = gdk_screen_get_default();
gtk_style_context_add_provider_for_screen(
screen,
- GTK_STYLE_PROVIDER(ui_gtk_css_provider),
+ GTK_STYLE_PROVIDER(css),
GTK_STYLE_PROVIDER_PRIORITY_USER);
#endif /* UI_GTK3 */
#if GTK_MINOR_VERSION < 12
- gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1);
+ gtk_css_provider_load_from_data(css, styledata, len);
#else
- gtk_css_provider_load_from_string(ui_gtk_css_provider, ui_gtk_css);
+ if(len < 0) {
+ gtk_css_provider_load_from_string(css, ui_gtk_css);
+ } else {
+ GBytes *style_data = g_bytes_new(styledata, len);
+ gtk_css_provider_load_from_bytes(css, style_data);
+ g_bytes_unref(style_data);
+
+ }
#endif /* GTK_MINOR_VERSION < 12 */
GdkDisplay *display = gdk_display_get_default();
- gtk_style_context_add_provider_for_display(display, GTK_STYLE_PROVIDER(ui_gtk_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ gtk_style_context_add_provider_for_display(display, GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
#endif /* UI_GTK4 */
}
#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 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
#define WINDOW_SHOW(window) gtk_widget_show_all(window)
#define WINDOW_DESTROY(window) gtk_widget_destroy(window)
#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 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
#ifdef UI_GTK2
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include "../common/context.h"
-#include "../common/object.h"
-#include "container.h"
-
-#include "tree.h"
-
-
-void* ui_strmodel_getvalue(void *elm, int column) {
- return column == 0 ? elm : NULL;
-}
-
-
-UIWIDGET ui_listview_str(UiObject *obj, UiList *list, ui_callback f, void *udata) {
- return ui_listview(obj, list, ui_strmodel_getvalue, f, udata);
-}
-
-UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
- // create treeview
- GtkWidget *view = gtk_tree_view_new();
- GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
- GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL);
- gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
-
- gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
-#ifdef UI_GTK3
-#if GTK_MINOR_VERSION >= 8
- gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(view), TRUE);
-#else
- // TODO: implement for older gtk3
-#endif
-#else
- // TODO: implement for gtk2
-#endif
-
- UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- model->getvalue = getvalue;
- UiList *list = var->value;
- UiListModel *listmodel = ui_list_model_new(obj, var, model);
- gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
-
- UiListView *listview = malloc(sizeof(UiListView));
- listview->obj = obj;
- listview->widget = view;
- listview->var = var;
- listview->model = model;
- g_signal_connect(
- view,
- "destroy",
- G_CALLBACK(ui_listview_destroy),
- listview);
-
- // bind var
- list->update = ui_listview_update;
- list->obj = listview;
-
- // add callback
- if(f) {
- UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
- event->obj = obj;
- event->userdata = udata;
- event->activate = f;
- event->selection = NULL;
-
- g_signal_connect(
- view,
- "row-activated",
- G_CALLBACK(ui_listview_activate_event),
- event);
- }
-
- // add widget to the current container
- GtkWidget *scroll_area = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(
- GTK_SCROLLED_WINDOW(scroll_area),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
- gtk_container_add(GTK_CONTAINER(scroll_area), view);
-
- UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, scroll_area, TRUE);
-
- // ct->current should point to view, not scroll_area, to make it possible
- // to add a context menu
- ct->current = view;
-
- return scroll_area;
-}
-
-UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
- UiVar *var = malloc(sizeof(UiVar));
- var->value = list;
- var->type = UI_VAR_SPECIAL;
- return ui_listview_var(obj, var, getvalue, f, udata);
-}
-
-UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
- UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
- if(var) {
- return ui_listview_var(obj, var, getvalue, f, udata);
- } else {
- // TODO: error
- }
- return NULL;
-}
-
-static void drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer udata) {
- printf("drag begin\n");
-
-}
-
-static void drag_end(
- GtkWidget *widget,
- GdkDragContext *context,
- guint time,
- gpointer udata)
-{
- printf("drag end\n");
-
-}
-
-static GtkTargetEntry targetentries[] =
- {
- { "STRING", 0, 0 },
- { "text/plain", 0, 1 },
- { "text/uri-list", 0, 2 },
- };
-
-UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) {
- // create treeview
- GtkWidget *view = gtk_tree_view_new();
-
- int addi = 0;
- for(int i=0;i<model->columns;i++) {
- GtkTreeViewColumn *column = NULL;
- if(model->types[i] == UI_ICON_TEXT) {
- column = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(column, model->titles[i]);
-
- GtkCellRenderer *iconrenderer = gtk_cell_renderer_pixbuf_new();
- GtkCellRenderer *textrenderer = gtk_cell_renderer_text_new();
-
- gtk_tree_view_column_pack_end(column, textrenderer, TRUE);
- 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);
-
- addi++;
- } else {
- GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(
- model->titles[i],
- renderer,
- "text",
- i + addi,
- NULL);
- }
- gtk_tree_view_column_set_resizable(column, TRUE);
- gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
- }
-
- //gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
-#ifdef UI_GTK3
- //gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(view), TRUE);
-#else
-
-#endif
-
- UiList *list = var->value;
- UiListModel *listmodel = ui_list_model_new(obj, var, model);
- gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
-
- //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));
- tableview->obj = obj;
- tableview->widget = view;
- tableview->var = var;
- tableview->model = model;
- g_signal_connect(
- view,
- "destroy",
- G_CALLBACK(ui_listview_destroy),
- tableview);
-
- // bind var
- list->update = ui_listview_update;
- list->obj = tableview;
-
- // add callback
- UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
- event->obj = obj;
- event->activate = cb.activate;
- event->selection = cb.selection;
- event->userdata = cb.userdata;
- if(cb.activate) {
- g_signal_connect(
- view,
- "row-activated",
- G_CALLBACK(ui_listview_activate_event),
- event);
- }
- if(cb.selection) {
- GtkTreeSelection *selection = gtk_tree_view_get_selection(
- GTK_TREE_VIEW(view));
- g_signal_connect(
- selection,
- "changed",
- G_CALLBACK(ui_listview_selection_event),
- event);
- }
- // TODO: destroy callback
-
-
- GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
- gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
-
- // add widget to the current container
- GtkWidget *scroll_area = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(
- GTK_SCROLLED_WINDOW(scroll_area),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
- gtk_container_add(GTK_CONTAINER(scroll_area), view);
-
- UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, scroll_area, TRUE);
-
- // ct->current should point to view, not scroll_area, to make it possible
- // to add a context menu
- ct->current = view;
-
- return scroll_area;
-}
-
-UIWIDGET ui_table(UiObject *obj, UiList *list, UiModel *model, UiListCallbacks cb) {
- UiVar *var = malloc(sizeof(UiVar));
- var->value = list;
- var->type = UI_VAR_SPECIAL;
- return ui_table_var(obj, var, model, cb);
-}
-
-UIWIDGET ui_table_nv(UiObject *obj, char *varname, UiModel *model, UiListCallbacks cb) {
- UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
- if(var) {
- return ui_table_var(obj, var, model, cb);
- } else {
- // TODO: error
- }
- return NULL;
-}
-
-GtkWidget* ui_get_tree_widget(UIWIDGET widget) {
- GList *c = gtk_container_get_children(GTK_CONTAINER(widget));
- if(c) {
- return c->data;
- }
- return NULL;
-}
-
-static char** targets2array(char *target0, va_list ap, int *nelm) {
- int al = 16;
- char **targets = calloc(16, sizeof(char*));
- targets[0] = target0;
-
- int i = 1;
- char *target;
- while((target = va_arg(ap, char*)) != NULL) {
- if(i >= al) {
- al *= 2;
- targets = realloc(targets, al*sizeof(char*));
- }
- targets[i] = target;
- i++;
- }
-
- *nelm = i;
- return targets;
-}
-
-static GtkTargetEntry* targetstr2gtktargets(char **str, int nelm) {
- GtkTargetEntry *targets = calloc(nelm, sizeof(GtkTargetEntry));
- for(int i=0;i<nelm;i++) {
- targets[i].target = str[i];
- }
- return targets;
-}
-
-void ui_table_dragsource(UIWIDGET tablewidget, int actions, char *target0, ...) {
- va_list ap;
- va_start(ap, target0);
- int nelm;
- char **targets = targets2array(target0, ap, &nelm);
- va_end(ap);
- ui_table_dragsource_a(tablewidget, actions, targets, nelm);
- free(targets);
-}
-
-void ui_table_dragsource_a(UIWIDGET tablewidget, int actions, char **targets, int nelm) {
- GtkTargetEntry* t = targetstr2gtktargets(targets, nelm);
- gtk_tree_view_enable_model_drag_source(
- GTK_TREE_VIEW(ui_get_tree_widget(tablewidget)),
- GDK_BUTTON1_MASK,
- t,
- nelm,
- GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_LINK);
- free(t);
-}
-
-void ui_table_dragdest(UIWIDGET tablewidget, int actions, char *target0, ...) {
- va_list ap;
- va_start(ap, target0);
- int nelm;
- char **targets = targets2array(target0, ap, &nelm);
- va_end(ap);
- ui_table_dragdest_a(tablewidget, actions, targets, nelm);
- free(targets);
-}
-
-void ui_table_dragdest_a(UIWIDGET tablewidget, int actions, char **targets, int nelm) {
- GtkTargetEntry* t = targetstr2gtktargets(targets, nelm);
- gtk_tree_view_enable_model_drag_dest(
- GTK_TREE_VIEW(ui_get_tree_widget(tablewidget)),
- t,
- nelm,
- GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_LINK);
- free(t);
-}
-
-void ui_listview_update(UiList *list, int i) {
- UiListView *view = list->obj;
- UiListModel *model = ui_list_model_new(view->obj, view->var, view->model);
- gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(model));
- g_object_unref(G_OBJECT(model));
- // TODO: free old model
-}
-
-void ui_listview_destroy(GtkWidget *w, UiListView *v) {
- gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL);
- ui_destroy_boundvar(v->obj->ctx, v->var);
- // TODO: destroy model?
- free(v);
-}
-
-void ui_combobox_destroy(GtkWidget *w, UiListView *v) {
- gtk_combo_box_set_model(GTK_COMBO_BOX(w), NULL);
- ui_destroy_boundvar(v->obj->ctx, v->var);
- // TODO: destroy model?
- free(v);
-}
-
-
-void ui_listview_activate_event(
- GtkTreeView *treeview,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- UiTreeEventData *event)
-{
- UiListSelection *selection = ui_listview_selection(
- gtk_tree_view_get_selection(treeview),
- event);
-
- UiEvent e;
- e.obj = event->obj;
- e.window = event->obj->window;
- e.document = event->obj->ctx->document;
- e.eventdata = selection;
- e.intval = selection->count > 0 ? selection->rows[0] : -1;
- event->activate(&e, event->userdata);
-
- if(selection->count > 0) {
- free(selection->rows);
- }
- free(selection);
-}
-
-void ui_listview_selection_event(
- GtkTreeSelection *treeselection,
- UiTreeEventData *event)
-{
- UiListSelection *selection = ui_listview_selection(treeselection, event);
-
- UiEvent e;
- e.obj = event->obj;
- e.window = event->obj->window;
- e.document = event->obj->ctx->document;
- e.eventdata = selection;
- e.intval = selection->count > 0 ? selection->rows[0] : -1;
- event->selection(&e, event->userdata);
-
- if(selection->count > 0) {
- free(selection->rows);
- }
- free(selection);
-}
-
-UiListSelection* ui_listview_selection(
- GtkTreeSelection *selection,
- UiTreeEventData *event)
-{
- GList *rows = gtk_tree_selection_get_selected_rows(selection, NULL);
-
- UiListSelection *ls = malloc(sizeof(UiListSelection));
- ls->count = g_list_length(rows);
- ls->rows = calloc(ls->count, sizeof(int));
- GList *r = rows;
- int i = 0;
- while(r) {
- GtkTreePath *path = r->data;
- ls->rows[i] = ui_tree_path_list_index(path);
- r = r->next;
- i++;
- }
- return ls;
-}
-
-int ui_tree_path_list_index(GtkTreePath *path) {
- int depth = gtk_tree_path_get_depth(path);
- if(depth == 0) {
- fprintf(stderr, "UiError: treeview selection: depth == 0\n");
- return -1;
- }
- int *indices = gtk_tree_path_get_indices(path);
- return indices[depth - 1];
-}
-
-
-/* --------------------------- ComboBox --------------------------- */
-
-UIWIDGET ui_combobox_str(UiObject *obj, UiList *list, ui_callback f, void *udata) {
- return ui_combobox(obj, list, ui_strmodel_getvalue, f, udata);
-}
-
-UIWIDGET ui_combobox(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
- UiVar *var = malloc(sizeof(UiVar));
- var->value = list;
- var->type = UI_VAR_SPECIAL;
- return ui_combobox_var(obj, var, getvalue, f, udata);
-}
-
-UIWIDGET ui_combobox_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
- UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST);
- if(var) {
- return ui_combobox_var(obj, var, getvalue, f, udata);
- } else {
- // TODO: error
- }
- return NULL;
-}
-
-UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) {
- UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
- model->getvalue = getvalue;
- UiListModel *listmodel = ui_list_model_new(obj, var, model);
-
- GtkWidget *combobox = ui_create_combobox(obj, listmodel, f, udata);
- UiContainer *ct = uic_get_current_container(obj);
- ct->add(ct, combobox, FALSE);
- return combobox;
-}
-
-GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata) {
- GtkWidget *combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
-
- UiListView *uicbox = malloc(sizeof(UiListView));
- uicbox->obj = obj;
- uicbox->widget = combobox;
- uicbox->var = model->var;
- uicbox->model = model->model;
-
- g_signal_connect(
- combobox,
- "destroy",
- G_CALLBACK(ui_combobox_destroy),
- uicbox);
-
- // bind var
- UiList *list = model->var->value;
- list->update = ui_combobox_modelupdate;
- 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(
- GTK_CELL_LAYOUT(combobox),
- renderer,
- "text",
- 0,
- NULL);
- gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
-
- // add callback
- if(f) {
- UiEventData *event = ui_malloc(obj->ctx, sizeof(UiEventData));
- event->obj = obj;
- event->userdata = udata;
- event->callback = f;
- event->value = 0;
-
- g_signal_connect(
- combobox,
- "changed",
- G_CALLBACK(ui_combobox_change_event),
- event);
- }
-
- return combobox;
-}
-
-void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e) {
- UiEvent event;
- event.obj = e->obj;
- event.window = event.obj->window;
- event.document = event.obj->ctx->document;
- event.eventdata = NULL;
- event.intval = gtk_combo_box_get_active(widget);
- e->callback(&event, e->userdata);
-}
-
-void ui_combobox_modelupdate(UiList *list, int i) {
- UiListView *view = list->obj;
- UiListModel *model = ui_list_model_new(view->obj, view->var, view->model);
- gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(model));
-}
-
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2017 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 TREE_H
-#define TREE_H
-
-#include "../ui/tree.h"
-#include "toolkit.h"
-#include "model.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct UiListView {
- UiObject *obj;
- GtkWidget *widget;
- UiVar *var;
- UiModel *model;
-} UiListView;
-
-typedef struct UiTreeEventData {
- UiObject *obj;
- ui_callback activate;
- ui_callback selection;
- void *userdata;
-} UiTreeEventData;
-
-void* ui_strmodel_getvalue(void *elm, int column);
-
-UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata);
-UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb);
-
-GtkWidget* ui_get_tree_widget(UIWIDGET widget);
-
-void ui_listview_update(UiList *list, int i);
-void ui_combobox_destroy(GtkWidget *w, UiListView *v);
-void ui_listview_destroy(GtkWidget *w, UiListView *v);
-
-void ui_listview_activate_event(
- GtkTreeView *tree_view,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- UiTreeEventData *event);
-void ui_listview_selection_event(
- GtkTreeSelection *treeselection,
- UiTreeEventData *event);
-UiListSelection* ui_listview_selection(
- GtkTreeSelection *selection,
- UiTreeEventData *event);
-int ui_tree_path_list_index(GtkTreePath *path);
-
-UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata);
-GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata);
-void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e);
-void ui_combobox_modelupdate(UiList *list, int i);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* TREE_H */
-
#ifdef UI_WEBVIEW
#include "../ui/webview.h"
+
+#if GTK_MAJOR_VERSION >= 4
#include <webkit/webkit.h>
+#else
+#include <webkit2/webkit2.h>
+#endif
#ifdef __cplusplus
extern "C" {
--- /dev/null
+/*
+ * 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 "widget.h"
+#include "container.h"
+
+#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_LAYOUT1(current, args);
+ current->container->add(current->container, widget, FALSE);
+
+ 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, FALSE);
+ return widget;
+}
+
+void ui_widget_set_size(UIWIDGET w, int width, int height) {
+ gtk_widget_set_size_request(w, width, height);
+}
+
+void ui_widget_redraw(UIWIDGET w) {
+ gtk_widget_queue_draw(w);
+}
-/**
- * @mainpage UAP Common Extensions
- * Library with common and useful functions, macros and data structures.
- * <p>
- * Latest available source:<br>
- * <a href="https://sourceforge.net/projects/ucx/files/">
- * https://sourceforge.net/projects/ucx/files/</a>
- * </p>
- *
- * <p>
- * Repositories:<br>
- * <a href="https://sourceforge.net/p/ucx/code">
- * https://sourceforge.net/p/ucx/code</a>
- * - or -
- * <a href="https://develop.uap-core.de/hg/ucx">
- * https://develop.uap-core.de/hg/ucx</a>
- * </p>
- *
- * <h2>LICENCE</h2>
- *
- * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved.
+/*
+ * 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:
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "ucx/ucx.h"
-
-int ucx_szmul_impl(size_t a, size_t b, size_t *result) {
- if(a == 0 || b == 0) {
- *result = 0;
- return 0;
- }
- size_t r = a * b;
- if(r / b == a) {
- *result = r;
- return 0;
- } else {
- *result = 0;
- return 1;
- }
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include "../ui/widget.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
}
+#endif
+
+#endif /* WIDGET_H */
UI_HEADERBAR_ALTERNATIVE_BOX
} UiHeaderbarAlternative;
-typedef struct UiWidgetArgs {
- UiTri fill;
- UiBool hexpand;
- UiBool vexpand;
- UiBool hfill;
- UiBool vfill;
- UiBool override_defaults;
- int colspan;
- int rowspan;
- const char *name;
- const char *style_class;
-} UiWidgetArgs;
typedef struct UiContainerArgs {
UiTri fill;
#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_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))
+#define ui_grid_w(obj, w, ...) for(w = ui_grid_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_tabview_w(obj, w, ...) for(w = ui_tabview_create(obj, (UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_scrolledwindow_w(obj, w, ...) for(w = ui_scrolledwindow_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_hsplitpane(obj, ...) for(ui_hsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_vsplitpane(obj, ...) for(ui_vsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_hsplitpane0(obj) for(ui_hsplitpane_create(obj, (UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_vsplitpane0(obj) for(ui_vsplitpane_create(obj, (UiSplitPaneArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_hsplitpane_w(obj, w, ...) for(w = ui_hsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+#define ui_vsplitpane_w(obj, w, ...) for(w = ui_vsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj))
+
#define ui_tab(obj, label) for(ui_tab_create(obj, label);ui_container_finish(obj);ui_container_begin_close(obj))
#define ui_headerbar_start(obj) for(ui_headerbar_start_create(obj);ui_container_finish(obj);ui_container_begin_close(obj))
UIEXPORT UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs args);
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);
UIEXPORT UiObject* ui_document_tab(UiTabbedPane *view);
-#ifdef UI_GTK
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
-#elif defined(UI_MOTIF)
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata, Widget parent, Arg *a, int n);
-#elif defined(UI_COCOA)
-typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
-#endif
-UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args);
-
-#define ui_customwidget(obj, create_widget, userdata, ...) ui_customwidget_create(obj, create_widget, userdata, (UiWidgetArgs) { __VA_ARGS__ })
-
/* used for macro */
UIEXPORT void ui_container_begin_close(UiObject *obj);
UIEXPORT UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args);
UIWIDGET ui_space_deprecated(UiObject *obj);
-UIWIDGET ui_separator_deprecated(UiObject *obj);
/* progress bar/spinner */
#define UI_IMAGE_OBJECT_TYPE "image"
+#ifdef UI_GTK
+#define UIIMAGE GdkPixbuf*
+#else
+#define UIIMAGE void*
+#endif
+
+
typedef struct UiImageViewerArgs {
UiTri fill;
UiBool hexpand;
UiBool scrollarea;
UiBool autoscale;
+ UiBool adjustwidgetsize;
+ UiBool useradjustable;
+ int image_padding;
+ int image_padding_left;
+ int image_padding_right;
+ int image_padding_top;
+ int image_padding_bottom;
UiGeneric *value;
const char *varname;
UiMenuBuilder *contextmenu;
+
+ ui_callback onbuttonpress;
+ void *onbuttonpressdata;
+ ui_callback onbuttonrelease;
+ void *onbuttonreleasedata;
} UiImageViewerArgs;
#define ui_imageviewer(obj, ...) ui_imageviewer_create(obj, (UiImageViewerArgs){ __VA_ARGS__ } )
UIEXPORT UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args);
+UIEXPORT UIWIDGET ui_imageviewer_reset(UIWIDGET w);
+UIEXPORT UIWIDGET ui_imageviewer_set_autoscale(UIWIDGET w, UiBool set);
+UIEXPORT UIWIDGET ui_imageviewer_set_adjustwidgetsize(UIWIDGET w, UiBool set);
+UIEXPORT UIWIDGET ui_imageviewer_set_useradjustable(UIWIDGET w, UiBool set);
+
UIEXPORT int ui_image_load_file(UiGeneric *obj, const char *path);
+UIEXPORT int ui_image_load_data(UiGeneric *obj, const void *imgdata, size_t size);
+
+UIEXPORT void ui_image_ref(UIIMAGE img);
+UIEXPORT void ui_image_unref(UIIMAGE img);
#ifdef __cplusplus
}
#define UI_TOOLKIT_H
#include <inttypes.h>
+#include <stdlib.h>
#ifdef UI_COCOA
#include <adwaita.h>
#endif
-#elif UI_MOTIF
-
-#include <Xm/XmAll.h>
-#define UIWIDGET Widget
-#define UIMENU Widget
-
#elif defined(UI_QT4) || defined(UI_QT5)
+#define UI_QT
+
#ifdef __cplusplus
+
#include <QApplication>
#include <QWidget>
#include <QMenu>
+
#define UIWIDGET QWidget*
+#define UIWINDOW QWidget*
#define UIMENU QMenu*
#else /* __cplusplus */
#define UIWIDGET void*
+#define UIWINDOW void*
#define UIMENU void*
#endif
+#elif UI_MOTIF
+
+#include <Xm/XmAll.h>
+#define UIWIDGET Widget
+#define UIMENU Widget
+
+
+#elif UI_WIN32
+
+#include <Windows.h>
+
+#define UIEXPORT __declspec(dllexport)
+
+#define UIWIDGET void*
+#define UIWINDOW void*
+#define UIMENU void*
+
#elif UI_WINUI
#define UIEXPORT __declspec(dllexport)
#define UI_GROUPS(...) (const int[]){ __VA_ARGS__, -1 }
/* public types */
+#ifndef __cplusplus
typedef _Bool UiBool;
+#else
+typedef bool UiBool;
+#endif
typedef struct UiObject UiObject;
typedef struct UiContainerX UiContainerX;
typedef struct UiTabbedPane UiTabbedPane;
-typedef enum UiTri UiTri;
-typedef enum UiLabelType UiLabelType;
+typedef enum UiTri {
+ UI_DEFAULT = 0,
+ UI_ON,
+ UI_OFF
+} UiTri;
-typedef enum UiDnDAction UiDnDAction;
enum UiMouseEventType { UI_PRESS = 0, UI_PRESS2 };
-enum UiLabelType { UI_LABEL_DEFAULT, UI_LABEL_TEXT, UI_LABEL_ICON, UI_LABEL_TEXT_ICON };
-
-enum UiDnDAction { UI_DND_ACTION_NONE, UI_DND_ACTION_COPY, UI_DND_ACTION_MOVE, UI_DND_ACTION_LINK, UI_DND_ACTION_CUSTOM };
+typedef enum UiLabelType {
+ UI_LABEL_DEFAULT,
+ UI_LABEL_TEXT,
+ UI_LABEL_ICON,
+ UI_LABEL_TEXT_ICON
+} UiLabelType;
+
+typedef enum UiDnDAction {
+ UI_DND_ACTION_NONE,
+ UI_DND_ACTION_COPY,
+ UI_DND_ACTION_MOVE,
+ UI_DND_ACTION_LINK,
+ UI_DND_ACTION_CUSTOM
+} UiDnDAction;
typedef void(*ui_callback)(UiEvent*, void*); /* event, user data */
void *window;
void *eventdata;
int intval;
+ int set;
};
struct UiMouseEvent {
};
struct UiText {
+ void (*save)(UiText*);
+ void (*destroy)(UiText*);
+ void (*restore)(UiText*);
void (*set)(UiText*, const char*);
char* (*get)(UiText*);
char* (*getsubstr)(UiText*, int, int); /* text, begin, end */
void (*insert)(UiText*, int, char*);
void (*setposition)(UiText*,int);
int (*position)(UiText*);
+ void (*setselection)(UiText*, int, int); /* text, begin, end */
void (*selection)(UiText*, int*, int*); /* text, begin, end */
int (*length)(UiText*);
void (*remove)(UiText*, int, int); /* text, begin, end */
UiStr value;
int pos;
void *obj;
- void *undomgr;
+ int datatype;
+ void *data1;
+ void *data2;
// TODO: replacefunc, ...
UiObserver *observers;
};
+/* UiText.datatype */
+#define UI_TEXT_TYPE_BUFFER 1
+
struct UiGeneric {
void* (*get)(UiGeneric*);
const char* (*get_type)(UiGeneric*);
UiObserver *observers;
};
-enum UiTri {
- UI_DEFAULT = 0,
- UI_ON,
- UI_OFF
-};
-
struct UiFileList {
char **files;
size_t nfiles;
UIEXPORT void ui_init(const char *appname, int argc, char **argv);
UIEXPORT const char* ui_appname();
+UIEXPORT void ui_add_styledata(const char *styledata, int len);
+
UIEXPORT UiContext* ui_global_context(void);
UIEXPORT void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata);
UIEXPORT void ui_condvar_signal(UiCondVar *var, void *data, int intdata);
UIEXPORT void ui_condvar_destroy(UiCondVar *var);
+UIEXPORT void ui_setop_enable(int set);
+UIEXPORT int ui_get_setop(void);
+
#ifdef __cplusplus
}
#endif
UiList* list;
const char* varname;
UiModel* model;
+ char **static_elements;
+ size_t static_nelm;
ui_getvaluefunc getvalue;
ui_callback onactivate;
void* onactivatedata;
UIEXPORT UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs args);
UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject* obj, UiListArgs args);
+UIEXPORT void ui_listview_select(UIWIDGET listview, int index);
+UIEXPORT void ui_combobox_select(UIWIDGET dropdown, int index);
+
UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args);
#define UI_H
#include "toolkit.h"
+#include "widget.h"
#include "container.h"
#include "menu.h"
#include "toolbar.h"
--- /dev/null
+/*
+ * 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_WIDGET_H
+#define UI_WIDGET_H
+
+#include "toolkit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct UiWidgetArgs {
+ UiTri fill;
+ UiBool hexpand;
+ UiBool vexpand;
+ UiBool hfill;
+ UiBool vfill;
+ UiBool override_defaults;
+ int colspan;
+ int rowspan;
+ const char *name;
+ const char *style_class;
+} UiWidgetArgs;
+
+#ifdef UI_GTK
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+#elif defined(UI_QT)
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+#elif defined(UI_MOTIF)
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata, Widget parent, Arg *a, int n);
+#elif defined(UI_COCOA)
+typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+#elif defined(UI_WINUI)
+typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+#elif defined(UI_WIN32)
+typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata);
+#endif
+UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args);
+
+#define ui_customwidget(obj, create_widget, userdata, ...) ui_customwidget_create(obj, create_widget, userdata, (UiWidgetArgs) { __VA_ARGS__ })
+
+
+UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args);
+
+#define ui_separator(obj, ...) ui_separator_create(obj, &(UiWidgetArgs){ __VA_ARGS__ } )
+
+UIEXPORT void ui_widget_set_size(UIWIDGET w, int width, int height);
+UIEXPORT void ui_widget_redraw(UIWIDGET w);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UI_WIDGET_H */
+