SHA256_Init(ctx);
}
-void dav_sha256_update(DAV_SHA_CTX *ctx, const void *data, size_t length) {
+void dav_sha256_update(DAV_SHA_CTX *ctx, const char *data, size_t length) {
SHA256_Update(ctx, data, length);
}
-void dav_sha256_final(char *md, DAV_SHA_CTX *ctx) {
- SHA256_Final(md, ctx);
+void dav_sha256_final(DAV_SHA_CTX *ctx, unsigned char *buf) {
+ SHA256_Final(buf, ctx);
}
#else
return ctx;
}
+void dav_sha256_init(DAV_SHA_CTX *ctx) {
+ CC_SHA256_Init(ctx);
+}
+
void dav_sha256_update(DAV_SHA_CTX *ctx, const char *data, size_t len) {
CC_SHA256_Update(ctx, data, len);
}
void dav_sha256_final(DAV_SHA_CTX *ctx, unsigned char *buf) {
CC_SHA256_Final(buf, ctx);
- free(ctx);
}
DavKey* dav_pw2key(const char *password, const unsigned char *salt, int saltlen, int pwfunc, int enc) {
DAV_SHA_CTX *ctx = dav_sha256_create();
if(ctx) {
dav_sha256_update(ctx, data, len);
- dav_sha256_final(ctx, hash);
+ dav_sha256_final_free(ctx, hash);
}
return util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH);
}
// cleanup
cng_cleanup(ctx->hAlg, NULL, ctx->hHash, ctx->pbHashObject);
- free(ctx);
}
DavKey* dav_pw2key(const char *password, const unsigned char *salt, int saltlen, int pwfunc, int enc) {
}
#endif
-
+void dav_sha256_final_free(DAV_SHA_CTX *ctx, unsigned char *buf) {
+ dav_sha256_final(ctx, buf);
+ free(ctx);
+}
CxBuffer* aes_encrypt_buffer(CxBuffer *in, DavKey *key) {
CxBuffer *encbuf = cxBufferCreate(NULL, in->size, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
DAV_SHA_CTX* dav_sha256_create(void);
void dav_sha256_update(DAV_SHA_CTX *ctx, const char *data, size_t len);
void dav_sha256_final(DAV_SHA_CTX *ctx, unsigned char *buf);
+void dav_sha256_final_free(DAV_SHA_CTX *ctx, unsigned char *buf);
DavKey* dav_pw2key(const char *password, const unsigned char *salt, int saltlen, int pwfunc, int enc);
#include <string.h>
#include <inttypes.h>
-#include <cx/utils.h>
#include <cx/map.h>
#include <cx/hash_map.h>
#include <cx/printf.h>
*/
#include "davqlparser.h"
-#include <cx/utils.h>
#include <cx/linked_list.h>
#include <cx/printf.h>
#include <string.h>
#include "session.h"
#include "xml.h"
-#include <cx/utils.h>
#include <cx/printf.h>
#include <cx/hash_map.h>
DavResource* parse_propfind_response(DavSession *sn, DavResource *root, CxBuffer *response) {
char *url = NULL;
curl_easy_getinfo(sn->handle, CURLINFO_EFFECTIVE_URL, &url);
- if(!root) {
- printf("methods.c: TODO: remove\n");
- root = dav_resource_new_href(sn, util_url_path(url)); // TODO: remove
- }
//printf("%.*s\n\n", response->size, response->space);
xmlDoc *doc = xmlReadMemory(response->space, response->size, url, NULL, 0);
#include <stdlib.h>
#include <string.h>
-#include <cx/utils.h>
+#include <cx/streams.h>
+
#include <cx/hash_map.h>
#ifdef _WIN32
}
static void remove_list_entries(PwdStore *s, const char *id) {
- CxIterator i = cxListMutIterator(s->locations);
+ CxIterator i = cxListIterator(s->locations);
cx_foreach(PwdIndexEntry*, ie, i) {
if(!strcmp(ie->id, id)) {
cxIteratorFlagRemoval(i);
break;
}
}
- i = cxListMutIterator(s->noloc);
+ i = cxListIterator(s->noloc);
cx_foreach(PwdIndexEntry*, ie, i) {
if(!strcmp(ie->id, id)) {
cxIteratorFlagRemoval(i);
#include "methods.h"
#include "crypto.h"
#include <cx/buffer.h>
-#include <cx/utils.h>
#include <cx/hash_map.h>
#include <cx/printf.h>
#include <cx/mempool.h>
HashStream *s = stream;
if(offset == 0 && whence == SEEK_SET) {
unsigned char buf[DAV_SHA256_DIGEST_LENGTH];
- dav_sha256_final(s->sha, buf);
+ dav_sha256_final_free(s->sha, buf);
s->sha = NULL;
} else {
s->error = 1;
data->length);
if(hstr.sha) {
- dav_sha256_final(hstr.sha, (unsigned char*)data->hash);
+ dav_sha256_final_free(hstr.sha, (unsigned char*)data->hash);
char *hash = util_hexstr((unsigned char*)data->hash, 32);
dav_set_string_property_ns(res, DAV_NS, "content-hash", hash);
free(hash);
property->value = n->children ? dav_convert_xml(sn, n->children) : NULL;
cxmutstr propkey = dav_property_key(property->ns->name, property->name);
- cxMapPut(map, cx_hash_key_cxstr(propkey), property);
+ cxMapPut(map, propkey, property);
cx_strfree(&propkey);
}
n = n->next;
#include <ctype.h>
#include <cx/string.h>
#include <cx/buffer.h>
-#include <cx/utils.h>
#include <cx/printf.h>
#include <libxml/tree.h>
#include <curl/curl.h>
#include "session.h"
#include "methods.h"
#include <cx/buffer.h>
-#include <cx/utils.h>
#include <cx/linked_list.h>
#include <cx/hash_map.h>
#include <cx/compare.h>
int ret = 0;
dav_context_lock(context);
CxList *sessions = context->sessions;
- ssize_t i = cxListFind(sessions, sn);
- if(i >= 0) {
+ size_t i = cxListFind(sessions, sn);
+ if(cxListIndexValid(sessions, i)) {
cxListRemove(sessions, i);
} else {
ret = 1;
#include <stdlib.h>
#include <string.h>
-#include <cx/utils.h>
#include <cx/printf.h>
#include "xml.h"
@interface MainWindow : NSWindow<UiToplevelObject>
+@property UiObject *obj;
+@property (strong) NSSplitView *splitview;
@property (strong) NSView *sidebar;
@property (strong) NSView *leftPanel;
@property (strong) NSView *rightPanel;
NSWindowStyleMaskMiniaturizable
backing:NSBackingStoreBuffered
defer:false];
+ _obj = obj;
- if(uic_toolbar_isenabled()) {
- UiToolbar *toolbar = [[UiToolbar alloc]initWithObject:obj];
- [self setToolbar:toolbar];
- }
-
int top = 4;
NSView *content = self.contentView;
splitview.dividerStyle = NSSplitViewDividerStyleThin;
splitview.translatesAutoresizingMaskIntoConstraints = false;
[self.contentView addSubview:splitview];
+ _splitview = splitview;
[NSLayoutConstraint activateConstraints:@[
[splitview.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:0],
}
_topOffset = top;
+ if(uic_toolbar_isenabled()) {
+ UiToolbar *toolbar = [[UiToolbar alloc]initWithWindow:self];
+ [self setToolbar:toolbar];
+ }
+
+
return self;
}
#import "toolkit.h"
#import "../common/toolbar.h"
+#import "MainWindow.h"
/*
* UiToolbarDelegate
NSMutableArray<NSString*> *defaultItems;
}
+@property MainWindow *window;
@property UiObject *obj;
-- (UiToolbar*) initWithObject:(UiObject*)object;
+- (UiToolbar*) initWithWindow:(MainWindow*)window;
@end
@implementation UiToolbar
-- (UiToolbar*) initWithObject:(UiObject*)object {
+- (UiToolbar*) initWithWindow:(MainWindow*)window {
self = [super initWithIdentifier:@"UiToolbar"];
- _obj = object;
+ _window = window;
+ _obj = window.obj;
allowedItems = [[NSMutableArray alloc]initWithCapacity:16];
defaultItems = [[NSMutableArray alloc]initWithCapacity:16];
+ if(window.sidebar) {
+ [allowedItems addObject:@"sidebar_separator"];
+ }
+ if(window.leftPanel) {
+ [allowedItems addObject:@"splitview_separator"];
+ }
+
CxMap *toolbarItems = uic_get_toolbar_items();
CxMapIterator i = cxMapIteratorKeys(toolbarItems);
cx_foreach(CxHashKey *, key, i) {
[allowedItems addObject: NSToolbarFlexibleSpaceItemIdentifier];
[allowedItems addObject: NSToolbarSpaceItemIdentifier];
- CxList *tbitems[3];
- tbitems[0] = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT);
- tbitems[1] = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER);
- tbitems[2] = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT);
- for(int t=0;t<3;t++) {
- CxIterator iter = cxListIterator(tbitems[t]);
+ // UI_TOOLBAR_LEFT = 0,
+ // UI_TOOLBAR_CENTER,
+ // UI_TOOLBAR_RIGHT,
+ // UI_TOOLBAR_SIDEBAR_LEFT,
+ // UI_TOOLBAR_SIDEBAR_RIGHT,
+ // UI_TOOLBAR_RIGHTPANEL_LEFT,
+ // UI_TOOLBAR_RIGHTPANEL_CENTER,
+ // UI_TOOLBAR_RIGHTPANEL_RIGHT
+ CxList *tbitems[8];
+ for(int i=0;i<8;i++) {
+ tbitems[i] = uic_get_toolbar_defaults(i);
+ }
+
+ if(window.sidebar) {
+ CxIterator iter = cxListIterator(tbitems[UI_TOOLBAR_SIDEBAR_LEFT]);
cx_foreach(char *, name, iter) {
NSString *s = [[NSString alloc] initWithUTF8String:name];
[defaultItems addObject:s];
}
+
+ CxList *sidebarRight = tbitems[UI_TOOLBAR_SIDEBAR_RIGHT];
+ if(cxListSize(sidebarRight) > 0) {
+ [defaultItems addObject:NSToolbarFlexibleSpaceItemIdentifier];
+ iter = cxListIterator(sidebarRight);
+ cx_foreach(char *, name, iter) {
+ NSString *s = [[NSString alloc] initWithUTF8String:name];
+ [defaultItems addObject:s];
+ }
+ }
+
+ [defaultItems addObject:@"sidebar_separator"];
}
+ int start_pos = UI_TOOLBAR_LEFT;
+ for(int x=0;x<2;x++) {
+ for(int t=start_pos;t<start_pos+3;t++) {
+ CxIterator iter = cxListIterator(tbitems[t]);
+ cx_foreach(char *, name, iter) {
+ NSString *s = [[NSString alloc] initWithUTF8String:name];
+ [defaultItems addObject:s];
+ }
+ if(t < start_pos+2 && cxListSize(tbitems[t+1]) > 0) {
+ [defaultItems addObject:NSToolbarFlexibleSpaceItemIdentifier];
+ }
+ }
+
+ if(x == 0 && window.rightPanel) {
+ [defaultItems addObject:@"splitview_separator"];
+ }
+ start_pos = UI_TOOLBAR_RIGHTPANEL_LEFT;
+ }
+
+
[self setDelegate:self];
[self setAllowsUserCustomization:YES];
return self;
CxMap *items = uic_get_toolbar_items();
UiToolbarItemI *item = cxMapGet(items, itemIdentifier.UTF8String);
if(!item) {
+ if([itemIdentifier isEqualToString:@"sidebar_separator"]) {
+ NSTrackingSeparatorToolbarItem *sep = [NSTrackingSeparatorToolbarItem trackingSeparatorToolbarItemWithIdentifier:itemIdentifier
+ splitView:_window.splitview
+ dividerIndex:0];
+ return sep;
+ } else if([itemIdentifier isEqualToString:@"splitview_separator"]) {
+ int dividerIndex = _window.sidebar != nil ? 1 : 0;
+ NSTrackingSeparatorToolbarItem *sep = [NSTrackingSeparatorToolbarItem trackingSeparatorToolbarItemWithIdentifier:itemIdentifier
+ splitView:_window.splitview
+ dividerIndex:dividerIndex];
+ return sep;
+ }
return nil;
}
#import "button.h"
#import "EventData.h"
#import "Container.h"
+#import "image.h"
#import <objc/runtime.h>
#import <cx/buffer.h>
NSString *label = [[NSString alloc] initWithUTF8String:args->label];
button.title = label;
}
+ if(args->icon) {
+ button.image = ui_cocoa_named_icon(args->icon);;
+ }
if(args->onclick) {
EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata];
NSString *label = [[NSString alloc] initWithUTF8String:args->label];
button.title = label;
}
+ if(args->icon) {
+ button.image = ui_cocoa_named_icon(args->icon);
+ }
UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);
if(var) {
static NSDictionary *standardIconNames;
+#define UI_ICON_ENTRY(x) @#x : x
+
void ui_icon_init(void) {
standardIconNames = @{
- @"NSImageNameActionTemplate": NSImageNameActionTemplate,
- @"NSImageNameAddTemplate": NSImageNameAddTemplate,
- @"NSImageNameAdvanced": NSImageNameAdvanced,
- @"NSImageNameApplicationIcon": NSImageNameApplicationIcon,
- @"NSImageNameBluetoothTemplate": NSImageNameBluetoothTemplate,
- @"NSImageNameBonjour": NSImageNameBonjour,
- @"NSImageNameBookmarksTemplate": NSImageNameBookmarksTemplate,
- @"NSImageNameCaution": NSImageNameCaution,
- // TODO
- @"NSImageNameRefreshTemplate": NSImageNameRefreshTemplate,
- @"NSImageNameFolder": NSImageNameFolder,
- @"NSImageNameGoForwardTemplate": NSImageNameGoForwardTemplate,
- @"NSImageNameGoBackTemplate": NSImageNameGoBackTemplate
+ UI_ICON_ENTRY(NSImageNameAddTemplate),
+ UI_ICON_ENTRY(NSImageNameBluetoothTemplate),
+ UI_ICON_ENTRY(NSImageNameBonjour),
+ UI_ICON_ENTRY(NSImageNameBookmarksTemplate),
+ UI_ICON_ENTRY(NSImageNameCaution),
+ UI_ICON_ENTRY(NSImageNameComputer),
+ UI_ICON_ENTRY(NSImageNameEnterFullScreenTemplate),
+ UI_ICON_ENTRY(NSImageNameExitFullScreenTemplate),
+ UI_ICON_ENTRY(NSImageNameFolder),
+ UI_ICON_ENTRY(NSImageNameFolderBurnable),
+ UI_ICON_ENTRY(NSImageNameFolderSmart),
+ UI_ICON_ENTRY(NSImageNameFollowLinkFreestandingTemplate),
+ UI_ICON_ENTRY(NSImageNameHomeTemplate),
+ UI_ICON_ENTRY(NSImageNameIChatTheaterTemplate),
+ UI_ICON_ENTRY(NSImageNameLockLockedTemplate),
+ UI_ICON_ENTRY(NSImageNameLockUnlockedTemplate),
+ UI_ICON_ENTRY(NSImageNameNetwork),
+ UI_ICON_ENTRY(NSImageNamePathTemplate),
+ UI_ICON_ENTRY(NSImageNameQuickLookTemplate),
+ UI_ICON_ENTRY(NSImageNameRefreshFreestandingTemplate),
+ UI_ICON_ENTRY(NSImageNameRefreshTemplate),
+ UI_ICON_ENTRY(NSImageNameRemoveTemplate),
+ UI_ICON_ENTRY(NSImageNameRevealFreestandingTemplate),
+ UI_ICON_ENTRY(NSImageNameShareTemplate),
+ UI_ICON_ENTRY(NSImageNameSlideshowTemplate),
+ UI_ICON_ENTRY(NSImageNameStatusAvailable),
+ UI_ICON_ENTRY(NSImageNameStatusNone),
+ UI_ICON_ENTRY(NSImageNameStatusPartiallyAvailable),
+ UI_ICON_ENTRY(NSImageNameStatusUnavailable),
+ UI_ICON_ENTRY(NSImageNameStopProgressFreestandingTemplate),
+ UI_ICON_ENTRY(NSImageNameStopProgressTemplate),
+ UI_ICON_ENTRY(NSImageNameTrashEmpty),
+ UI_ICON_ENTRY(NSImageNameTrashFull),
+ UI_ICON_ENTRY(NSImageNameActionTemplate),
+ UI_ICON_ENTRY(NSImageNameSmartBadgeTemplate),
+ UI_ICON_ENTRY(NSImageNameIconViewTemplate),
+ UI_ICON_ENTRY(NSImageNameListViewTemplate),
+ UI_ICON_ENTRY(NSImageNameColumnViewTemplate),
+ UI_ICON_ENTRY(NSImageNameFlowViewTemplate),
+ UI_ICON_ENTRY(NSImageNameInvalidDataFreestandingTemplate),
+ UI_ICON_ENTRY(NSImageNameGoForwardTemplate),
+ UI_ICON_ENTRY(NSImageNameGoBackTemplate),
+ UI_ICON_ENTRY(NSImageNameGoRightTemplate),
+ UI_ICON_ENTRY(NSImageNameGoLeftTemplate),
+ UI_ICON_ENTRY(NSImageNameRightFacingTriangleTemplate),
+ UI_ICON_ENTRY(NSImageNameLeftFacingTriangleTemplate),
+ UI_ICON_ENTRY(NSImageNameMobileMe),
+ UI_ICON_ENTRY(NSImageNameMultipleDocuments),
+ UI_ICON_ENTRY(NSImageNameUserAccounts),
+ UI_ICON_ENTRY(NSImageNamePreferencesGeneral),
+ UI_ICON_ENTRY(NSImageNameAdvanced),
+ UI_ICON_ENTRY(NSImageNameInfo),
+ UI_ICON_ENTRY(NSImageNameFontPanel),
+ UI_ICON_ENTRY(NSImageNameColorPanel),
+ UI_ICON_ENTRY(NSImageNameUser),
+ UI_ICON_ENTRY(NSImageNameUserGroup),
+ UI_ICON_ENTRY(NSImageNameEveryone),
+ UI_ICON_ENTRY(NSImageNameUserGuest),
+ UI_ICON_ENTRY(NSImageNameMenuOnStateTemplate),
+ UI_ICON_ENTRY(NSImageNameMenuMixedStateTemplate),
+ UI_ICON_ENTRY(NSImageNameApplicationIcon)
};
}
UIEXPORT void ui_container_args_set_margin_left(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_margin_top(UiContainerArgs *args, int value);
-UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_margin_bottom(UiContainerArgs *args, int value);
UIEXPORT void ui_container_args_set_colspan(UiContainerArgs *args, int colspan);
UIEXPORT void ui_container_args_set_rowspan(UiContainerArgs *args, int rowspan);
UIEXPORT void ui_container_args_set_def_hexpand(UiContainerArgs *args, UiBool value);
UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key);
if(docvar) {
// bind var to document var
- uic_copy_binding(var, docvar, TRUE);
+ uic_copy_var_binding(var, docvar, TRUE);
cxIteratorFlagRemoval(i);
}
}
}
static void uic_context_unbind_vars(UiContext *ctx) {
+ ui_onchange_events_enable(FALSE);
CxMapIterator mi = cxMapIterator(ctx->vars);
cx_foreach(CxMapEntry*, entry, mi) {
+ printf("detach %.*s\n", (int)entry->key->len, (char*)entry->key->data);
UiVar *var = entry->value;
// var->from && var->from_ctx && var->from_ctx != ctx
uic_save_var(var);
if(var->from) {
- uic_copy_binding(var, var->from, FALSE);
+ uic_copy_var_binding(var, var->from, FALSE);
cxMapPut(var->from->from_ctx->vars, *entry->key, var->from);
var->from = NULL;
}
+ uic_unbind_var(var);
}
if(ctx->documents) {
uic_context_unbind_vars(subctx);
}
}
+
+ ui_onchange_events_enable(TRUE);
}
void uic_context_detach_document(UiContext *ctx, void *document) {
var->original_value = NULL;
var->from = NULL;
var->from_ctx = ctx;
-
- cxMempoolSetDestructor(var, (cx_destructor_func)uic_unbind_var);
+ var->bound = FALSE;
+
+ cxMempoolSetDestructor(var, (cx_destructor_func)uic_unbind_var); // TODO: use another destructor that cleans the value (UiString free, UiText destroy, ...)
cxMapPut(ctx->vars, name, var);
return val;
}
+// destroys a value, that was created by uic_create_value
+void uic_destroy_value(UiContext *ctx, UiVarType type, void *value) {
+ switch(type) {
+ default: {
+ ui_free(ctx, value);
+ break;
+ }
+ case UI_VAR_SPECIAL: break;
+ case UI_VAR_STRING: {
+ UiString *s = value;
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ ui_free(ctx, value);
+ }
+ case UI_VAR_TEXT: {
+ UiText *t = value;
+ if(t->value.free) {
+ t->value.free(t->value.ptr);
+ t->value.free = NULL;
+ t->value.ptr = NULL;
+ }
+ if(t->destroy) {
+ t->destroy(t);
+ }
+ ui_free(ctx, value);
+ }
+ case UI_VAR_LIST: {
+ ui_list_free(ctx, value);
+ break;
+ }
+ }
+}
+
UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type) {
if (value) {
}
-void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
+void uic_copy_var_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
// check type
if(from->type != to->type) {
fprintf(stderr, "UI Error: var has incompatible type.\n");
}
}
- ui_setop_enable(TRUE);
+ uic_copy_value_binding(from->type, fromvalue, tovalue);
+}
+
+void uic_copy_value_binding(UiVarType type, void *from, void *to) {
+ ui_setop_enable(TRUE);
// copy binding
- // we don't copy the observer, because the from var has never one
- switch(from->type) {
+ // we don't copy the observer, because the from value never has oberservers
+ switch(type) {
default: fprintf(stderr, "uic_copy_binding: wtf!\n"); break;
case UI_VAR_SPECIAL: break;
case UI_VAR_INTEGER: {
- UiInteger *f = fromvalue;
- UiInteger *t = tovalue;
+ UiInteger *f = from;
+ UiInteger *t = to;
if(!f->obj) break;
uic_int_copy(f, t);
t->set(t, t->value);
break;
}
case UI_VAR_DOUBLE: {
- UiDouble *f = fromvalue;
- UiDouble *t = tovalue;
+ UiDouble *f = from;
+ UiDouble *t = to;
if(!f->obj) break;
uic_double_copy(f, t);
t->set(t, t->value);
break;
}
case UI_VAR_STRING: {
- UiString *f = fromvalue;
- UiString *t = tovalue;
+ UiString *f = from;
+ UiString *t = to;
if(!f->obj) break;
uic_string_copy(f, t);
char *tvalue = t->value.ptr ? t->value.ptr : "";
break;
}
case UI_VAR_TEXT: {
- UiText *f = fromvalue;
- UiText *t = tovalue;
+ UiText *f = from;
+ UiText *t = to;
if(!f->obj) break;
uic_text_copy(f, t);
t->restore(t);
break;
}
case UI_VAR_LIST: {
- UiList *f = fromvalue;
- UiList *t = tovalue;
+ UiList *f = from;
+ UiList *t = to;
uic_list_copy(f, t);
ui_list_update(t);
break;
}
case UI_VAR_RANGE: {
- UiRange *f = fromvalue;
- UiRange *t = tovalue;
+ UiRange *f = from;
+ UiRange *t = to;
if(!f->obj) break;
uic_range_copy(f, t);
t->setextent(t, t->extent);
break;
}
case UI_VAR_GENERIC: {
- UiGeneric *f = fromvalue;
- UiGeneric *t = tovalue;
+ UiGeneric *f = from;
+ UiGeneric *t = to;
if(!f->obj) break;
uic_generic_copy(f, t);
t->set(t, t->value, t->type);
}
}
+const char *uic_type2str(UiVarType type) {
+ switch(type) {
+ default: return "";
+ case UI_VAR_INTEGER: return "int";
+ case UI_VAR_DOUBLE: return "double";
+ case UI_VAR_STRING: return "string";
+ case UI_VAR_TEXT: return "text";
+ case UI_VAR_LIST: return "list";
+ case UI_VAR_RANGE: return "range";
+ case UI_VAR_GENERIC: return "generic";
+ }
+}
+
void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value) {
- // TODO: do we need/want this? Why adding vars to a context after
- // widgets reference these? Workarounds:
- // 1. add vars to ctx before creating ui
- // 2. create ui, create new document with vars, attach doc
- // also it would be possible to create a function, that scans unbound vars
- // and connects them to available vars
- /*
- UiContext *rootctx = uic_root_context(ctx);
- UiVar *b = NULL;
- if(rootctx->bound) {
- // some widgets are already bound to some vars
- b = ucx_map_cstr_get(rootctx->bound, name);
- if(b) {
- // a widget is bound to a var with this name
- // if ctx is the root context we can remove the var from bound
- // because set_doc or detach can't fuck things up
- if(ctx == rootctx) {
- ucx_map_cstr_remove(ctx->bound, name);
- // TODO: free stuff
- }
+ UiVar *var = cxMapGet(ctx->vars, name);
+ if(!var) {
+ // create new var and add it to the context var map
+ var = ui_malloc(ctx, sizeof(UiVar));
+ cxMapPut(ctx->vars, name, var);
+ } else {
+ // override var with new value
+ if(var->type != type) {
+ fprintf(stderr, "Error: var %s type mismatch: %s - %s\n", name, uic_type2str(var->type), uic_type2str(type));
+ return;
}
+ if(var->bound) {
+ fprintf(stderr, "Error: var %s already bound\n", name);
+ return;
+ }
+ UiInteger *prev_value = var->value;
+ uic_copy_value_binding(type, prev_value, value);
+ uic_destroy_value(var->from_ctx, var->type, var->value);
}
- */
- // create new var and add it to doc's vars
- UiVar *var = ui_malloc(ctx, sizeof(UiVar));
var->type = type;
var->value = value;
var->from = NULL;
var->from_ctx = ctx;
- size_t oldcount = cxMapSize(ctx->vars);
- cxMapPut(ctx->vars, name, var);
- if(cxMapSize(ctx->vars) != oldcount + 1) {
- fprintf(stderr, "UiError: var '%s' already exists\n", name);
- }
-
- // TODO: remove?
- // a widget is already bound to a var with this name
- // copy the binding (like uic_context_set_document)
- /*
- if(b) {
- uic_copy_binding(b, var, TRUE);
- }
- */
-}
-
-void uic_remove_bound_var(UiContext *ctx, UiVar *var) {
- // TODO
+ var->bound = TRUE;
}
-
// public API
void ui_attach_document(UiContext *ctx, void *document) {
cxListFree(groups);
}
-void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, int *groups, int ngroups) {
+void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *groups, int ngroups) {
if(enable == NULL) {
enable = (ui_enablefunc)ui_set_enabled;
}
cxListFree(ls);
}
-void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, int *states, int nstates) {
+void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates) {
ui_widget_set_groups2(ctx, widget, (ui_enablefunc)ui_set_visible, states, nstates);
}
return ctx ? cxRealloc(ctx->allocator, ptr, size) : NULL;
}
-UIEXPORT char* ui_strdup(UiContext *ctx, const char *str) {
+char* ui_strdup(UiContext *ctx, const char *str) {
if(!ctx) {
return NULL;
}
cxmutstr d = cx_strdup_a(ctx->allocator, s);
return d.ptr;
}
+
+void ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr) {
+ cxMempoolRegister(ctx->mp, data, (cx_destructor_func)destr);
+}
+
+void ui_set_destructor(void *mem, ui_destructor_func destr) {
+ cxMempoolSetDestructor(mem, (cx_destructor_func)destr);
+}
UiVarType type;
UiVar *from;
UiContext *from_ctx;
+ UiBool bound;
};
struct UiGroupWidget {
UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type);
UiVar* uic_create_value_var(UiContext *ctx, void *value);
void* uic_create_value(UiContext *ctx, UiVarType type);
+void uic_destroy_value(UiContext *ctx, UiVarType type, void *value);
UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, const char *varname, UiVarType type);
-void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc);
+void uic_copy_var_binding(UiVar *from, UiVar *to, UiBool copytodoc);
+void uic_copy_value_binding(UiVarType type, void *from, void *to);
void uic_save_var(UiVar *var);
void uic_unbind_var(UiVar *var);
+const char *uic_type2str(UiVarType type);
void uic_reg_var(UiContext *ctx, const char *name, UiVarType type, void *value);
-void uic_remove_bound_var(UiContext *ctx, UiVar *var);
-
size_t uic_group_array_size(const int *groups);
void uic_check_group_widgets(UiContext *ctx);
void uic_add_group_widget(UiContext *ctx, void *widget, ui_enablefunc enable, CxList *groups);
static int menu_item_counter = 0;
+static void *tmp_eventdata;
+static int tmp_eventdata_type;
+
+void uic_set_tmp_eventdata(void *eventdata, int type) {
+ tmp_eventdata = eventdata;
+ tmp_eventdata_type = type;
+}
+
+void* uic_get_tmp_eventdata(void) {
+ return tmp_eventdata;
+}
+
+int uic_get_tmp_eventdata_type(void) {
+ return tmp_eventdata_type;
+}
+
void uic_menu_init(void) {
global_builder.current = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS);
current_builder = &global_builder;
int* uic_copy_groups(const int* groups, size_t *ngroups);
+void uic_set_tmp_eventdata(void *eventdata, int type);
+void* uic_get_tmp_eventdata(void);
+int uic_get_tmp_eventdata_type(void);
+
#ifdef __cplusplus
}
#endif
#include "context.h"
#include <cx/linked_list.h>
+#include <cx/hash_map.h>
#include "../ui/container.h"
UiObject* uic_object_new_toplevel(void) {
fflush(stdout);
CxMempool *mp = cxMempoolCreateSimple(256);
- UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
+ UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObjectPrivate));
fflush(stdout);
obj->ctx = uic_context(obj, mp);
obj->ctx->parent = ui_global_context();
}
UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget) {
- UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObject));
+ UiObject *newobj = cxCalloc(ctx->allocator, 1, sizeof(UiObjectPrivate));
newobj->ctx = ctx;
newobj->widget = widget;
uic_object_created(newobj);
} else {
toplevel->container_begin = NULL;
}
+
+ // TODO: free container?
+}
+
+/*
+ * This might look like a weird function, but in case a container creates a
+ * sub-container, 2 container objects are added to the list, however we want
+ * only one container, otherwise ui_container_finish() would not work
+ */
+void uic_object_remove_second_last_container(UiObject *toplevel) {
+ if(toplevel->container_end && toplevel->container_end->prev) {
+ UiContainerX *end = toplevel->container_end;
+ UiContainerX *rm = toplevel->container_end->prev;
+
+ end->prev = rm->prev;
+ if(rm->prev) {
+ rm->prev->next = end;
+ } else {
+ toplevel->container_begin = end;
+ }
+
+ // TODO: free container?
+ } else {
+ fprintf(stderr, "Error: uic_object_remove_second_last_container expected at least 2 containers\n");
+ }
+}
+
+// public API
+
+void ui_object_set(UiObject *obj, const char *key, void *data) {
+ UiObjectPrivate *p = (UiObjectPrivate*)obj;
+ if(!p->ext) {
+ p->ext = cxHashMapCreate(obj->ctx->mp->allocator, CX_STORE_POINTERS, 4);
+ }
+ if(data) {
+ cxMapPut(p->ext, key, data);
+ } else {
+ cxMapRemove(p->ext, key);
+ }
+}
+
+void* ui_object_get(UiObject *obj, const char *key) {
+ UiObjectPrivate *p = (UiObjectPrivate*)obj;
+ return p->ext ? cxMapGet(p->ext, key) : NULL;
}
#define UIC_OBJECT_H
#include "../ui/toolkit.h"
+#include <cx/map.h>
#ifdef __cplusplus
extern "C" {
#endif
+
+typedef struct UiObjectPrivate {
+ UiObject obj;
+ CxMap *ext;
+} UiObjectPrivate;
typedef void (*ui_object_callback)(UiObject *obj, void *userdata);
void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer);
void uic_object_pop_container(UiObject *toplevel);
+void uic_object_remove_second_last_container(UiObject *toplevel);
COMMON_OBJ += condvar$(OBJ_EXT)
COMMON_OBJ += args$(OBJ_EXT)
COMMON_OBJ += wrapper$(OBJ_EXT)
+COMMON_OBJ += utils$(OBJ_EXT)
TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
static ui_list_init_func default_list_init;
static void *default_list_init_userdata;
+static ui_list_destroy_func default_list_destroy;
+static void *default_list_destroy_userdata;
UiObserver* ui_observer_new(ui_callback f, void *data) {
UiObserver *observer = malloc(sizeof(UiObserver));
list->count = ui_list_count;
}
+void uic_ucx_list_destroy(UiContext *ctx, UiList *list, void *unused) {
+ cxListFree(list->data);
+ ui_free(ctx, list);
+}
+
UiList* ui_list_new(UiContext *ctx, const char *name) {
return ui_list_new2(ctx, name, default_list_init ? default_list_init : uic_ucx_list_init, default_list_init_userdata);
}
return list;
}
-void ui_list_free(UiList *list) {
- cxListFree(list->data);
- free(list);
+void ui_list_free(UiContext *ctx, UiList *list) {
+ if(!default_list_destroy) {
+ uic_ucx_list_destroy(ctx, list, NULL);
+ } else {
+ default_list_destroy(ctx, list, default_list_destroy_userdata);
+ }
+
}
void* ui_list_first(UiList *list) {
return d;
}
+static void string_destroy(UiString *s) {
+ if(s->value.free && s->value.ptr) {
+ s->value.free(s->value.ptr);
+ }
+}
+
UiString* ui_string_new(UiContext *ctx, const char *name) {
UiString *s = ui_malloc(ctx, sizeof(UiString));
memset(s, 0, sizeof(UiString));
+ ui_set_destructor(s, (ui_destructor_func)string_destroy);
if(name) {
uic_reg_var(ctx, name, UI_VAR_STRING, s);
}
return s;
}
+static void text_destroy(UiText *t) {
+ if(t->destroy) {
+ t->destroy(t);
+ }
+}
+
UiText* ui_text_new(UiContext *ctx, const char *name) {
UiText *t = ui_malloc(ctx, sizeof(UiText));
memset(t, 0, sizeof(UiText));
+ ui_set_destructor(t, (ui_destructor_func)text_destroy);
if(name) {
uic_reg_var(ctx, name, UI_VAR_TEXT, t);
}
return r;
}
-UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
+static void generic_destroy(UiGeneric *g) {
+ if(g->destroy) {
+ g->destroy(g);
+ }
+}
+
+UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric));
memset(g, 0, sizeof(UiGeneric));
+ ui_set_destructor(g, (ui_destructor_func)generic_destroy);
if(name) {
uic_reg_var(ctx, name, UI_VAR_GENERIC, g);
}
}
static int ui_set_op = 0;
+static int ui_onchange_events_enabled = TRUE;
void ui_setop_enable(int set) {
ui_set_op = set;
return ui_set_op;
}
+void ui_onchange_events_enable(UiBool enable) {
+ ui_onchange_events_enabled = enable;
+}
+
+UiBool ui_onchange_events_is_enabled(void) {
+ return ui_onchange_events_enabled;
+}
+
/* ---------------- List initializers and wrapper functions ---------------- */
void ui_global_list_initializer(ui_list_init_func func, void *userdata) {
default_list_init_userdata = userdata;
}
+void ui_global_list_destructor(ui_list_destroy_func func, void *userdata) {
+ default_list_destroy = func;
+ default_list_destroy_userdata = userdata;
+}
+
void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list)) {
list->first = first;
}
#endif
void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused);
+void uic_ucx_list_destroy(UiContext *ctx, UiList *list, void *unused);
void uic_int_copy(UiInteger *from, UiInteger *to);
void uic_double_copy(UiDouble *from, UiDouble *to);
cxListRemove(cxlist, index);
}
+void ui_srclist_swap(UiList *list, int i1, int i2) {
+ CxList *cxlist = list->data;
+ cxListSwap(cxlist, i1, i2);
+}
+
void ui_srclist_clear(UiList *list) {
CxList *cxlist = list->data;
cxListClear(cxlist);
UIEXPORT void ui_srclist_add(UiList *list, UiSubList *item);
UIEXPORT void ui_srclist_insert(UiList *list, int index, UiSubList *item);
UIEXPORT void ui_srclist_remove(UiList *list, int index);
+UIEXPORT void ui_srclist_swap(UiList *list, int i1, int i2);
UIEXPORT void ui_srclist_clear(UiList *list);
UIEXPORT int ui_srclist_size(UiList *list);
UIEXPORT void ui_srclist_generate_sublist_num_data(UiList *list);
UiSplitPane* ui_create_splitpane_data(GtkWidget *pane, UiOrientation orientation, int max, int init) {
UiSplitPane *ct = malloc(sizeof(UiSplitPane));
+ memset(ct, 0, sizeof(UiSplitPane));
ct->current_pane = pane;
ct->orientation = orientation;
ct->max = max;
UiList *list = uisublist.var->value;
list->obj = sublist_ptr;
list->update = ui_listbox_list_update;
+ list->getselection = ui_listbox_list_getselection;
+ list->setselection = ui_listbox_list_setselection;
}
}
UiList *list = var->value;
list->obj = uilistbox;
list->update = ui_listbox_dynamic_update;
+ list->getselection = ui_listbox_dynamic_getselection;
+ list->setselection = ui_listbox_dynamic_setselection;
ui_listbox_dynamic_update(list, -1);
}
ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
}
+void ui_listbox_dynamic_setselection(UiList *list, UiListSelection sel) {
+ UiListBox *uilistbox = list->obj;
+ gtk_list_box_unselect_all(uilistbox->listbox);
+ if(sel.count > 0) {
+ int index = sel.rows[0];
+ if(index >= 0) {
+ GtkListBoxRow *row = gtk_list_box_get_row_at_index(uilistbox->listbox, index);
+ if(row) {
+ gtk_list_box_select_row(uilistbox->listbox, row);
+ }
+ }
+ }
+}
+
+UiListSelection ui_listbox_dynamic_getselection(UiList *list) {
+ UiListSelection sel = { 0, NULL };
+ UiListBox *uilistbox = list->obj;
+ GtkListBoxRow *row = gtk_list_box_get_selected_row(uilistbox->listbox);
+ if(row) {
+ sel.count = 1;
+ sel.rows = malloc(sizeof(int));
+ sel.rows[0] = gtk_list_box_row_get_index(row);
+ }
+ return sel;
+}
+
void ui_listbox_update(UiListBox *listbox, int from, int to) {
CxIterator i = cxListIterator(listbox->sublists);
size_t pos = 0;
static void listbox_button_clicked(GtkWidget *button, UiEventDataExt *data) {
UiListBoxSubList *sublist = data->customdata0;
- UiSubListEventData eventdata;
- eventdata.list = sublist->var->value;
- eventdata.sublist_index = sublist->index;
- eventdata.row_index = data->value0;
- eventdata.sublist_userdata = sublist->userdata;
- eventdata.row_data = eventdata.list->get(eventdata.list, eventdata.row_index);
- eventdata.event_data = data->customdata2;
+ UiSubListEventData *eventdata = &sublist->listbox->current_eventdata;
+ eventdata->list = sublist->var->value;
+ eventdata->sublist_index = sublist->index;
+ eventdata->row_index = data->value0;
+ eventdata->sublist_userdata = sublist->userdata;
+ eventdata->row_data = eventdata->list->get(eventdata->list, eventdata->row_index);
+ eventdata->event_data = data->customdata2;
UiEvent event;
event.obj = data->obj;
event.window = event.obj->window;
event.document = event.obj->ctx->document;
- event.eventdata = &eventdata;
+ event.eventdata = eventdata;
event.eventdatatype = UI_EVENT_DATA_SUBLIST;
event.intval = data->value0;
event.set = ui_get_setop();
}
if(data->customdata3) {
+ uic_set_tmp_eventdata(eventdata, UI_EVENT_DATA_SUBLIST);
+
UIMENU menu = data->customdata3;
g_object_set_data(G_OBJECT(button), "ui-button-popup", menu);
gtk_popover_popup(GTK_POPOVER(menu));
}
}
-#if GTK_CHECK_VERSION(3, 0, 0)
+#if GTK_CHECK_VERSION(4, 0, 0)
static void button_popover_closed(GtkPopover *popover, GtkWidget *button) {
g_object_set_data(G_OBJECT(button), "ui-button-popup", NULL);
if(g_object_get_data(G_OBJECT(button), "ui-button-invisible")) {
gtk_widget_set_visible(button, FALSE);
}
}
+#else
+static void popup_hide(GtkWidget *self, GtkWidget *button) {
+ g_object_set_data(G_OBJECT(button), "ui-button-popup", NULL);
+ if(g_object_get_data(G_OBJECT(button), "ui-button-invisible")) {
+ g_object_set_data(G_OBJECT(button), "ui-button-invisible", NULL);
+ gtk_widget_set_visible(button, FALSE);
+ }
+}
#endif
static void listbox_fill_row(UiListBox *listbox, GtkWidget *row, UiListBoxSubList *sublist, UiSubListItem *item, int index) {
if(item->button_menu) {
UIMENU menu = ui_contextmenu_create(item->button_menu, listbox->obj, button);
event->customdata3 = menu;
- g_signal_connect(menu, "closed", G_CALLBACK(button_popover_closed), button);
+#if GTK_CHECK_VERSION(4, 0, 0)
+ g_signal_connect(menu, "closed", G_CALLBACK(button_popover_closed), button);
+#else
+ g_signal_connect(menu, "hide", G_CALLBACK(popup_hide), button);
+#endif
ui_menubuilder_unref(item->button_menu);
}
}
ui_sourcelist_update_finished();
}
+void ui_listbox_list_setselection(UiList *list, UiListSelection sel) {
+ UiListBoxSubList *sublist = list->obj;
+ UiListBox *uilistbox = sublist->listbox;
+ gtk_list_box_unselect_all(uilistbox->listbox);
+ if(sel.count > 0) {
+ int index = sel.rows[0];
+ if(index >= 0 && index < sublist->numitems) {
+ int global_index = sublist->startpos + index;
+ GtkListBoxRow *row = gtk_list_box_get_row_at_index(uilistbox->listbox, global_index);
+ if(row) {
+ gtk_list_box_select_row(uilistbox->listbox, row);
+ }
+ }
+ }
+}
+
+UiListSelection ui_listbox_list_getselection(UiList *list) {
+ UiListSelection sel = { 0, NULL };
+ UiListBoxSubList *sublist = list->obj;
+ UiListBox *uilistbox = sublist->listbox;
+ GtkListBoxRow *row = gtk_list_box_get_selected_row(uilistbox->listbox);
+ if(row) {
+ int index = gtk_list_box_row_get_index(row);
+ size_t startpos = sublist->startpos;
+ if(index >= startpos && index < startpos+sublist->numitems) {
+ sel.count = 1;
+ sel.rows = malloc(sizeof(int));
+ sel.rows[0] = index - startpos;
+ }
+ }
+ return sel;
+}
+
void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) {
UiEventDataExt *data = g_object_get_data(G_OBJECT(row), "ui-listbox-row-eventdata");
if(!data) {
void *onbuttonclickdata;
GtkListBoxRow *first_row;
UiBool header_is_item;
+ UiSubListEventData current_eventdata;
};
void ui_combobox_setselection(UiList *list, UiListSelection selection);
void ui_listbox_dynamic_update(UiList *list, int i);
+void ui_listbox_dynamic_setselection(UiList *list, UiListSelection sel);
+UiListSelection ui_listbox_dynamic_getselection(UiList *list);
+
void ui_listbox_update(UiListBox *listbox, int from, int to);
void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index);
void ui_listbox_list_update(UiList *list, int i);
+void ui_listbox_list_setselection(UiList *list, UiListSelection sel);
+UiListSelection ui_listbox_list_getselection(UiList *list);
void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data);
event->callback = list->callback;
event->value = i - 1;
event->customdata = elm;
+ event->customint = UI_EVENT_DATA_LIST_ELM;
g_signal_connect(
widget,
evt.obj = event->obj;
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
+ if(event->customdata) {
+ evt.eventdata = event->customdata;
+ evt.eventdatatype = event->customint;
+ } else {
+ evt.eventdata = uic_get_tmp_eventdata();
+ evt.eventdatatype = uic_get_tmp_eventdata_type();
+ }
evt.eventdata = event->customdata;
evt.intval = event->value;
- event->callback(&evt, event->userdata);
+ event->callback(&evt, event->userdata);
+ uic_set_tmp_eventdata(NULL, 0);
}
void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) {
evt.obj = event->obj;
evt.window = event->obj->window;
evt.document = event->obj->ctx->document;
- evt.eventdata = event->customdata;
- evt.eventdatatype = event->customint;
+ if(event->customdata) {
+ evt.eventdata = event->customdata;
+ evt.eventdatatype = event->customint;
+ } else {
+ evt.eventdata = uic_get_tmp_eventdata();
+ evt.eventdatatype = uic_get_tmp_eventdata_type();
+ }
evt.intval = intval;
- event->callback(&evt, event->userdata);
+ event->callback(&evt, event->userdata);
+ uic_set_tmp_eventdata(NULL, 0);
}
void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) {
void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) {
+ if(!ui_onchange_events_is_enabled()) {
+ return;
+ }
+
UiText *value = textarea->var->value;
UiEvent e;
}
void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) {
- UiString *value = textfield->var->value;
+ if(!ui_onchange_events_is_enabled()) {
+ return;
+ }
+
+ UiString *value = textfield->var ? textfield->var->value : NULL;
UiEvent e;
e.obj = textfield->obj;
e.window = e.obj->window;
e.document = textfield->obj->ctx->document;
e.eventdata = value;
- e.eventdatatype = UI_EVENT_DATA_TEXT_VALUE;
+ e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
e.intval = 0;
e.set = ui_get_setop();
void ui_textfield_activate(GtkEntry* self, UiTextField *textfield) {
if(textfield->onactivate) {
+ UiString *value = textfield->var ? textfield->var->value : NULL;
+
UiEvent e;
e.obj = textfield->obj;
e.window = e.obj->window;
e.document = textfield->obj->ctx->document;
- e.eventdata = NULL;
- e.eventdatatype = 0;
+ e.eventdata = value;
+ e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
e.intval = 0;
e.set = ui_get_setop();
textfield->onactivate(&e, textfield->onactivatedata);
#include "../common/toolbar.h"
#include "../common/threadpool.h"
-#include <cx/utils.h>
#include <cx/string.h>
#include <cx/printf.h>
#ifndef UI_GTK2
void ui_app_quit() {
- g_application_quit(G_APPLICATION(app));
+ g_application_quit(G_APPLICATION(app)); // TODO: fix, does not work
}
GtkApplication* ui_get_application() {
#endif
}
-void ui_set_visible(UIWIDGET widget, int visible) {
+void ui_set_visible(UIWIDGET widget, UiBool visible) {
#if GTK_MAJOR_VERSION >= 4
gtk_widget_set_visible(widget, visible);
#else
#include "../common/context.h"
#include "../common/menu.h"
#include "../common/toolbar.h"
+#include "../common/utils.h"
#include <cx/mempool.h>
int window_width = window_default_width;
int window_height = window_default_height;
if(!simple) {
- const char *width = ui_get_property("ui.window.width");
- const char *height = ui_get_property("ui.window.height");
- if(width && height) {
- int w = atoi(width);
- int h = atoi(height);
- if(w > 0 && h > 0) {
- window_width = w;
- window_height = h;
- }
- }
+ ui_get_window_default_width(&window_width, &window_height);
}
gtk_window_set_default_size(
GTK_WINDOW(obj->widget),
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
- mywidget.columnspacing),
+ grid.columnspacing),
XmRImmediate,
(XtPointer) 0
},
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
- mywidget.rowspacing),
+ grid.rowspacing),
XmRImmediate,
(XtPointer) 0
},
{
- gridMargin,
- gridMargin,
+ gridPaddingLeft,
+ gridPaddingLeft,
XmRDimension,
sizeof (Dimension),
XtOffsetOf( GridRec,
- mywidget.margin),
+ grid.padding_left),
+ XmRImmediate,
+ (XtPointer) 0
+ },
+ {
+ gridPaddingRight,
+ gridPaddingRight,
+ XmRDimension,
+ sizeof (Dimension),
+ XtOffsetOf( GridRec,
+ grid.padding_right),
+ XmRImmediate,
+ (XtPointer) 0
+ },
+ {
+ gridPaddingTop,
+ gridPaddingTop,
+ XmRDimension,
+ sizeof (Dimension),
+ XtOffsetOf( GridRec,
+ grid.padding_top),
+ XmRImmediate,
+ (XtPointer) 0
+ },
+ {
+ gridPaddingBottom,
+ gridPaddingBottom,
+ XmRDimension,
+ sizeof (Dimension),
+ XtOffsetOf( GridRec,
+ grid.padding_bottom),
XmRImmediate,
(XtPointer) 0
}
void grid_initialize(Widget request, Widget new, ArgList args, Cardinal num_args) {
Grid mn = (Grid)new;
- mn->mywidget.max_col = 0;
- mn->mywidget.max_row = 0;
+ mn->grid.max_col = 0;
+ mn->grid.max_row = 0;
}
void grid_realize(Widget w,XtValueMask *valueMask,XSetWindowAttributes *attributes) {
}
void GridChangeManaged(Widget widget) {
-
+ grid_place_children((Grid)widget);
}
Boolean ConstraintSetValues(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
GridConstraintRec *constraints = neww->core.constraints;
Grid grid = (Grid)XtParent(neww);
- if(constraints->grid.x > grid->mywidget.max_col) {
- grid->mywidget.max_col = constraints->grid.x;
+ if(constraints->grid.x > grid->grid.max_col) {
+ grid->grid.max_col = constraints->grid.x;
}
- if(constraints->grid.y > grid->mywidget.max_row) {
- grid->mywidget.max_row = constraints->grid.y;
+ if(constraints->grid.y > grid->grid.max_row) {
+ grid->grid.max_row = constraints->grid.y;
}
}
GridConstraintRec *constraints = neww->core.constraints;
Grid grid = (Grid)XtParent(neww);
- if(constraints->grid.x > grid->mywidget.max_col) {
- grid->mywidget.max_col = constraints->grid.x;
+ if(constraints->grid.x > grid->grid.max_col) {
+ grid->grid.max_col = constraints->grid.x;
}
- if(constraints->grid.y > grid->mywidget.max_row) {
- grid->mywidget.max_row = constraints->grid.y;
+ if(constraints->grid.y > grid->grid.max_row) {
+ grid->grid.max_row = constraints->grid.y;
}
constraints->grid.pref_width = neww->core.width;
constraints->grid.pref_height = neww->core.height;
}
void grid_place_children(Grid w) {
- int ncols = w->mywidget.max_col+1;
- int nrows = w->mywidget.max_row+1;
+ if(!XtIsRealized((Widget)w)) {
+ return;
+ }
+
+ int ncols = w->grid.max_col+1;
+ int nrows = w->grid.max_row+1;
GridDef *cols = calloc(ncols, sizeof(GridDef));
GridDef *rows = calloc(nrows, sizeof(GridDef));
int num_cols_expanding = 0;
int num_rows_expanding = 0;
- int req_width = 0;
- int req_height = 0;
+ int req_width = w->grid.padding_left + w->grid.padding_right;
+ int req_height = w->grid.padding_top + w->grid.padding_bottom;
+ int width = w->core.width;
+ int height = w->core.height;
//printf("container width: %d\n", (int)w->core.width);
if(constraints->grid.pref_width < constraints->grid.min_width) {
constraints->grid.pref_width = constraints->grid.min_width;
}
+ int elm_width = constraints->grid.pref_width + constraints->grid.margin_left + constraints->grid.margin_right;
+ int elm_height = constraints->grid.pref_height + constraints->grid.margin_top + constraints->grid.margin_bottom;
+ if(!XtIsManaged(child)) {
+ elm_width = 0;
+ elm_height = 0;
+ }
if(constraints->grid.colspan > span_max || constraints->grid.rowspan > span_max) {
continue;
span_width = last_col->size;
}
- int diff = constraints->grid.pref_width - span_width;
+ int diff = elm_width - span_width;
if(diff > 0) {
last_col->size += diff;
}
- } else if(constraints->grid.pref_width > col->size) {
- col->size = constraints->grid.pref_width;
+ } else if(elm_width > col->size) {
+ col->size = elm_width;
}
// row size
if(constraints->grid.rowspan > 1) {
span_height = last_row->size;
}
- int diff = constraints->grid.pref_height - span_height;
+ int diff = elm_height - span_height;
if(diff > 0) {
last_row->size += diff;
}
- } else if(constraints->grid.pref_height > row->size) {
- row->size = constraints->grid.pref_height;
+ } else if(elm_height > row->size) {
+ row->size = elm_height;
}
}
span_max = 50000; // not sure if this is unreasonable low or high
req_height += rows[i].size;
}
+ int total_colspacing = 0;
+ int total_rowspacing = 0;
+ for(int i=0;i+1<ncols;i++) {
+ if(cols[i].size > 0) {
+ total_colspacing += w->grid.columnspacing;
+ }
+ }
+ for(int i=0;i+1<nrows;i++) {
+ if(rows[i].size > 0) {
+ total_rowspacing += w->grid.rowspacing;
+ }
+ }
+
if(req_width > 0 && req_height > 0) {
// add col/row spacing
- req_width += (ncols-1)*w->mywidget.columnspacing;
- req_height += (nrows-1)*w->mywidget.rowspacing;
+ req_width += total_colspacing; //(ncols-1)*w->grid.columnspacing;
+ req_height += total_rowspacing; //(nrows-1)*w->grid.rowspacing;
Widget parent = w->core.parent;
Dimension rwidth = req_width;
//rheight = w->core.height;
}
- if(!w->mywidget.sizerequest) {
+ if(!w->grid.sizerequest) {
Dimension actual_width, actual_height;
- w->mywidget.sizerequest = TRUE;
+ w->grid.sizerequest = TRUE;
//printf("sizerequest: %d x %d\n", (int)req_width, (int)req_height);
//XtGeometryResult result = XtMakeGeometryRequest((Widget)w, &request, &reply);
XtMakeResizeRequest((Widget)w, req_width, req_height, &actual_width, &actual_height);
- w->mywidget.sizerequest = FALSE;
+ w->grid.sizerequest = FALSE;
//printf("size request: %d %d\n", (int)actual_width, (int)actual_height);
}
// how much space can we add to each expanding col/row
int hexpand = 0;
- int width_diff = (int)w->core.width - req_width;
+ int width_diff = width - req_width;
int hexpand2 = 0;
if(width_diff > 0 && num_cols_expanding > 0) {
hexpand = width_diff / num_cols_expanding;
hexpand2 = width_diff-hexpand*num_cols_expanding;
}
- int x = 0;
+ int x = w->grid.padding_left;
for(int i=0;i<ncols;i++) {
cols[i].pos = x;
if(cols[i].expand) {
cols[i].size += hexpand + hexpand2;
}
- x += cols[i].size + w->mywidget.columnspacing;
+ if(cols[i].size > 0) {
+ x += cols[i].size + w->grid.columnspacing;
+ }
hexpand2 = 0;
}
int vexpand = 0;
- int height_diff = (int)w->core.height - req_height;
+ int height_diff = height - req_height;
int vexpand2 = 0;
if(height_diff > 0 && num_rows_expanding > 0) {
vexpand = height_diff / num_rows_expanding;
vexpand2 = height_diff-vexpand*num_rows_expanding;
}
- int y = 0;
+ int y = w->grid.padding_bottom;
for(int i=0;i<nrows;i++) {
rows[i].pos = y;
if(rows[i].expand) {
rows[i].size += vexpand + vexpand2;
}
- y += rows[i].size += w->mywidget.rowspacing;
+ if(rows[i].size > 0) {
+ y += rows[i].size += w->grid.rowspacing;
+ }
vexpand2 = 0;
}
GridConstraintRec *constraints = child->core.constraints;
GridDef c = cols[constraints->grid.x];
GridDef r = rows[constraints->grid.y];
- int x = c.pos;
- int y = r.pos;
+ int x = c.pos + constraints->grid.margin_left;
+ int y = r.pos + constraints->grid.margin_top;
int width = constraints->grid.pref_width;
int height = constraints->grid.pref_height;
if(constraints->grid.hfill) {
Dimension cwidth = 0;
for(int j=0;j<constraints->grid.colspan;j++) {
if(constraints->grid.x+j < ncols) {
- cwidth += cols[constraints->grid.x+j].size + (j > 0 ? w->mywidget.columnspacing : 0);
+ cwidth += cols[constraints->grid.x+j].size + (j > 0 ? w->grid.columnspacing : 0);
}
}
width = cwidth;
} else {
- width = c.size - w->mywidget.columnspacing;
+ width = c.size - w->grid.columnspacing - constraints->grid.margin_left - constraints->grid.margin_right;
}
}
if(constraints->grid.vfill) {
Dimension cheight = 0;
for(int j=0;j<constraints->grid.rowspan;j++) {
if(constraints->grid.y+j < nrows) {
- cheight += rows[constraints->grid.y+j].size + (j > 0 ? w->mywidget.rowspacing : 0);
+ cheight += rows[constraints->grid.y+j].size + (j > 0 ? w->grid.rowspacing : 0);
}
}
height = cheight;
} else {
- height = r.size - w->mywidget.rowspacing;
+ height = r.size - w->grid.rowspacing - constraints->grid.margin_top - constraints->grid.margin_bottom;
}
}
-
+
if(width > 0 && height > 0) {
XtConfigureWidget(child, x, y, width, height, child->core.border_width);
}
// resources
#define gridColumnSpacing "gridColumnSpacing"
-#define gridRowSpacing "gridRowSpacing"
-#define gridMargin "gridMargin"
+#define gridRowSpacing "gridRowSpacing"
+#define gridPaddingLeft "gridPaddingLeft"
+#define gridPaddingRight "gridPaddingRight"
+#define gridPaddingTop "gridPaddingTop"
+#define gridPaddingBottom "gridPaddingBottom"
// constraints
#define gridColumn "gridColumn"
CoreClassPart core_class;
CompositeClassPart composite_class;
ConstraintClassPart constraint_class;
- XmManagerClassPart manager_class;
- GridClassPart mywidgetclass;
+ XmManagerClassPart manager_class;
+ GridClassPart gridwidgetclass;
} GridClassRec;
typedef struct GridPart {
- int margin_left;
- int margin_right;
- int margin_top;
- int margin_bottom;
+ int padding_left;
+ int padding_right;
+ int padding_top;
+ int padding_bottom;
int max_col;
int max_row;
Dimension columnspacing;
Dimension rowspacing;
- Dimension margin;
Boolean sizerequest;
} GridPart;
CompositePart composite;
ConstraintPart constraint;
XmManagerPart manager;
- GridPart mywidget;
+ GridPart grid;
} GridRec;
typedef struct GridContraintPart {
XtAddCallback(
button,
XmNdestroyCallback,
- (XtCallbackProc)ui_destroy_eventdata,
+ (XtCallbackProc)ui_destroy_data,
eventdata);
}
XtAddCallback(
widget,
XmNdestroyCallback,
- (XtCallbackProc)ui_destroy_eventdata,
+ (XtCallbackProc)ui_destroy_data,
event);
}
XtAddCallback(
rbutton,
XmNdestroyCallback,
- (XtCallbackProc)ui_destroy_eventdata,
+ (XtCallbackProc)ui_destroy_data,
event);
}
XtAddCallback(
button,
XmNdestroyCallback,
- (XtCallbackProc)ui_destroy_eventdata,
+ (XtCallbackProc)ui_destroy_data,
event);
XmStringFree(label);
container->add(container, widget);
}
+void ui_container_apply_grid_margin(
+ Arg *args,
+ int *n,
+ int margin_left, int margin_right, int margin_top, int margin_bottom)
+{
+ int c = *n;
+ XtSetArg(args[c], gridMarginLeft, margin_left); c++;
+ XtSetArg(args[c], gridMarginRight, margin_right); c++;
+ XtSetArg(args[c], gridMarginTop, margin_top); c++;
+ XtSetArg(args[c], gridMarginBottom, margin_bottom); c++;
+ *n = c;
+}
/* ---------------------------- Box Container ---------------------------- */
int n = 0;
if(orientation == UI_BOX_VERTICAL) {
- //XtSetArg(xargs[n], gridRowSpacing, args->spacing); n++;
+ XtSetArg(xargs[n], gridRowSpacing, args->spacing); n++;
} else {
- //XtSetArg(xargs[n], gridColumnSpacing, args->spacing); n++;
+ XtSetArg(xargs[n], gridColumnSpacing, args->spacing); n++;
}
Widget parent = ui_container_prepare(ctn, &layout, xargs, &n);
}
static Widget ui_box_container_prepare(UiBoxContainer *box, UiLayout *layout, Arg *args, int *n) {
- int a = *n;
+ ui_container_apply_grid_margin(args, n, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
box->n++;
return box->container.widget;
}
UiLayout layout = UI_ARGS2LAYOUT(args);
Widget parent = ui_container_prepare(ctn, &layout, xargs, &n);
- XtSetArg(xargs[n], gridMargin, args->margin); n++;
XtSetArg(xargs[n], gridColumnSpacing, args->columnspacing); n++;
XtSetArg(xargs[n], gridRowSpacing, args->rowspacing); n++;
Widget grid = XtCreateManagedWidget(args->name ? args->name : "gridcontainer", gridClass, parent, xargs, n);
}
*n = a;
+ ui_container_apply_grid_margin(args, n, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
return ctn->widget;
}
grid->container.container.newline = FALSE;
}
+/* -------------------------- Frame Container -------------------------- */
+
+UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) {
+ Arg xargs[16];
+ int n = 0;
+
+ UiContainerPrivate *ctn = ui_obj_container(obj);
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+
+ Widget parent = ui_container_prepare(ctn, &layout, xargs, &n);
+ if(args->width > 0) {
+ XtSetArg(xargs[n], XmNwidth, args->width); n++;
+ }
+ if(args->height > 0) {
+ XtSetArg(xargs[n], XmNheight, args->height); n++;
+ }
+
+ char *name = args->name ? (char*)args->name : "frame";
+ Widget frame = XmCreateFrame(parent, name, xargs, n);
+ XtManageChild(frame);
+ ui_container_add(ctn, frame);
+
+ if(args->label) {
+ XmString s = XmStringCreateLocalized((char*)args->label);
+ n = 0;
+ XtSetArg(xargs[n], XmNlabelString, s); n++;
+ XtSetArg(xargs[n], XmNchildType, XmFRAME_TITLE_CHILD); n++;
+ Widget label = XmCreateLabel(frame, "frame_label", xargs, n);
+ XtManageChild(label);
+ XmStringFree(s);
+ }
+
+ UiContainerX *container = ui_frame_container(obj, frame);
+ uic_object_push_container(obj, container);
+
+ UiContainerArgs sub_args = {
+ .spacing = args->spacing,
+ .columnspacing = args->columnspacing,
+ .rowspacing = args->rowspacing,
+ .margin = args->padding
+ };
+ switch(args->subcontainer) {
+ default: break;
+ case UI_CONTAINER_VBOX: {
+ ui_vbox_create(obj, &sub_args);
+ uic_object_remove_second_last_container(obj);
+ break;
+ }
+ case UI_CONTAINER_HBOX: {
+ ui_hbox_create(obj, &sub_args);
+ uic_object_remove_second_last_container(obj);
+ break;
+ }
+ case UI_CONTAINER_GRID: {
+ ui_grid_create(obj, &sub_args);
+ uic_object_remove_second_last_container(obj);
+ break;
+ }
+ }
+
+
+ return frame;
+}
+
+UiContainerX* ui_frame_container(UiObject *obj, Widget frame) {
+ UiContainerPrivate *ctn = ui_malloc(obj->ctx, sizeof(UiContainerPrivate));
+ memset(ctn, 0, sizeof(UiContainerPrivate));
+ ctn->prepare = ui_frame_container_prepare;
+ ctn->add = ui_frame_container_add;
+ ctn->widget = frame;
+ return (UiContainerX*)ctn;
+}
+
+Widget ui_frame_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n) {
+ int a = *n;
+ XtSetArg(args[a], XmNchildType, XmFRAME_WORKAREA_CHILD);
+ *n = a+1;
+ return ctn->widget;
+}
+
+void ui_frame_container_add(UiContainerPrivate *ctn, Widget widget) {
+ // NOOP
+}
+
+/* -------------------------- SplitPane -------------------------- */
+
+UIWIDGET ui_splitpane_create(UiObject *obj, UiSplitPaneArgs *args, int orientation) {
+ return NULL; // TODO
+}
+
+UIWIDGET ui_hsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
+ return ui_splitpane_create(obj, args, XmHORIZONTAL);
+}
+
+UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
+ return ui_splitpane_create(obj, args, XmVERTICAL);
+}
/* -------------------------- TabView Container -------------------------- */
if(numbuttons == 0) {
return;
}
+ width--;
int button_width = width / numbuttons;
int x = 0;
-
+
CxIterator i = cxListIterator(tabview->tabs);
cx_foreach(UiTab *, tab, i) {
if(i.index + 1 == numbuttons) {
tabview->current_index = -1;
UiTabViewContainer *ct = ui_malloc(obj->ctx, sizeof(UiTabViewContainer));
+ memset(ct, 0, sizeof(UiTabViewContainer));
ct->container.widget = form;
ct->container.type = UI_CONTAINER_TABVIEW;
ct->container.prepare = ui_tabview_container_prepare;
int n = 0;
XtSetArg(xargs[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
+ if(args->width > 0) {
+ XtSetArg(xargs[n], XmNwidth, args->width); n++;
+ }
+ if(args->height > 0) {
+ XtSetArg(xargs[n], XmNheight, args->height); n++;
+ }
Widget parent = ui_container_prepare(ctn, &layout, xargs, &n);
Widget scrolledwindow = XmCreateScrolledWindow(parent, "scrolledwindow", xargs, n);
Widget ui_container_prepare(UiContainerPrivate *container, UiLayout *layout, Arg *args, int *n);
void ui_container_add(UiContainerPrivate *container, Widget widget);
+void ui_container_apply_grid_margin(
+ Arg *args,
+ int *n,
+ int margin_left, int margin_right, int margin_top, int margin_bottom);
void ui_motif_tabview_select(UiMotifTabView *tabview, int tab);
void ui_motif_tabview_add_tab(UiMotifTabView *tabview, int index, const char *name, Widget child);
Widget ui_grid_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n);
void ui_grid_container_add(UiContainerPrivate *ctn, Widget widget);
+UiContainerX* ui_frame_container(UiObject *obj, Widget frame);
+Widget ui_frame_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg *args, int *n);
+void ui_frame_container_add(UiContainerPrivate *ctn, Widget widget);
+
#ifdef __cplusplus
}
#endif
#include "graphics.h"
#include "container.h"
+
+UIWIDGET ui_drawingarea_create(UiObject *obj, UiDrawingAreaArgs *args) {
+ Arg xargs[16];
+ int n = 0;
+
+ UiContainerPrivate *ctn = ui_obj_container(obj);
+ UiLayout layout = UI_ARGS2LAYOUT(args);
+
+ Widget parent = ui_container_prepare(ctn, &layout, xargs, &n);
+ char *name = args->name ? (char*)args->name : "drawingarea";
+
+ Widget widget = XmCreateDrawingArea(parent, name, xargs, n);
+ XtManageChild(widget);
+ ui_container_add(ctn, widget);
+
+ UiDrawingArea *drawingarea = malloc(sizeof(UiDrawingArea));
+ drawingarea->obj = obj;
+ drawingarea->draw = args->draw;
+ drawingarea->drawdata = args->drawdata;
+ drawingarea->onclick = args->onclick;
+ drawingarea->onclickdata = args->onclickdata;
+ drawingarea->onmotion = args->onmotion;
+ drawingarea->onmotiondata = args->onmotiondata;
+ drawingarea->gc = NULL;
+
+ XtAddCallback(
+ widget,
+ XmNdestroyCallback,
+ (XtCallbackProc)ui_drawingarea_destroy,
+ drawingarea);
+ XtAddCallback(
+ widget,
+ XmNexposeCallback,
+ (XtCallbackProc)ui_drawingarea_expose,
+ drawingarea);
+
+ return widget;
+}
+
+void ui_drawingarea_destroy(Widget w, UiDrawingArea *drawingarea, XtPointer d) {
+ if(drawingarea->gc) {
+ XFreeGC(XtDisplay(w), drawingarea->gc);
+ }
+ free(drawingarea);
+}
+
+void ui_drawingarea_expose(Widget w, UiDrawingArea *drawingarea, XtPointer d) {
+ Display *dp = XtDisplay(w);
+
+ if(!drawingarea->gc) {
+ XGCValues gcvals;
+ gcvals.foreground = BlackPixelOfScreen(XtScreen(w));
+ drawingarea->gc = XCreateGC(dp, XtWindow(w), (GCForeground), &gcvals);
+ }
+
+ if(drawingarea->draw) {
+ UiEvent event;
+ event.obj = drawingarea->obj;
+ event.window = event.obj->window;
+ event.document = event.obj->ctx->document;
+ event.eventdata = NULL;
+ event.eventdatatype = 0;
+ event.intval = 0;
+ event.set = 0;
+
+ UiXlibGraphics g;
+ g.g.width = w->core.width;
+ g.g.height = w->core.height;
+ g.widget = w;
+ g.display = dp;
+ g.colormap = w->core.colormap;
+ g.gc = drawingarea->gc;
+
+ drawingarea->draw(&event, (UiGraphics*)&g, drawingarea->drawdata);
+ }
+}
+
+void ui_drawingarea_getsize(UIWIDGET drawingarea, int *width, int *height) {
+
+}
+
+void ui_drawingarea_redraw(UIWIDGET drawingarea) {
+
+}
#ifdef __cplusplus
extern "C" {
#endif
+
+typedef struct UiDrawingArea {
+ UiObject *obj;
+ ui_drawfunc draw;
+ void *drawdata;
+ ui_callback onclick;
+ void *onclickdata;
+ ui_callback onmotion;
+ void *onmotiondata;
+
+ GC gc;
+} UiDrawingArea;
+typedef struct UiXlibGraphics {
+ UiGraphics g;
+ Display *display;
+ Widget widget;
+ Colormap colormap;
+ GC gc;
+} UiXlibGraphics;
+
+void ui_drawingarea_destroy(Widget w, UiDrawingArea *drawingarea, XtPointer d);
+
+void ui_drawingarea_expose(Widget w, UiDrawingArea *drawingarea, XtPointer d);
#ifdef __cplusplus
XtSetArg(xargs[n], XmNalignment, align); n++;
XmString label = NULL;
- if(args->label) {
- label = XmStringCreateLocalized((char*)args->label);
- XtSetArg(xargs[n], XmNlabelString, label); n++;
+ char *lbl = (char*)args->label;
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
+ if(var) {
+ UiString *s = var->value;
+ lbl = s->value.ptr;
+ }
+
+ if(lbl) {
+ label = XmStringCreateLocalized(lbl);
+ } else {
+ label = XmStringCreateLocalized("");
}
+ XtSetArg(xargs[n], XmNlabelString, label); n++;
char *name = args->name ? (char*)args->name : "label";
Widget w = XmCreateLabel(parent, name, xargs, n);
XtManageChild(w);
ui_container_add(ctn, w);
XmStringFree(label);
+
+ if(var) {
+ UiString *s = var->value;
+ s->obj = w;
+ s->get = ui_label_get;
+ s->set = ui_label_set;
+ }
+
return w;
}
return label_create(obj, args, XmALIGNMENT_END);
}
+char* ui_label_get(UiString *s) {
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ s->value.free = NULL;
+ s->value.ptr = NULL;
+ }
+ Widget w = s->obj;
+ XmString s1 = NULL;
+ XtVaGetValues(w, XmNlabelString, &s1, NULL);
+ if(s1) {
+ char *value;
+ if(XmStringGetLtoR(s1, XmFONTLIST_DEFAULT_TAG, &value)) {
+ s->value.ptr = value;
+ s->value.free = (cx_destructor_func)XtFree;
+ }
+ }
+ return s->value.ptr;
+}
+
+void ui_label_set(UiString *s, const char *str) {
+ Widget w = s->obj;
+ XmString s1 = XmStringCreateLocalized(str ? (char*)str : "");
+ XtVaSetValues(w, XmNlabelString, s1, NULL);
+ XmStringFree(s1);
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ s->value.free = NULL;
+ s->value.ptr = NULL;
+ }
+}
/* -------------------------- progressbar/spiner -------------------------- */
Pixel color;
} UiProgressBar;
+char* ui_label_get(UiString *s);
+void ui_label_set(UiString *s, const char *str);
double ui_progressbar_get(UiDouble *d);
void ui_progressbar_set(UiDouble *d, double value);
#include <stdio.h>
#include <stdlib.h>
+#include <Xm/Xm.h>
#include "container.h"
} else {
XtSetArg(xargs[n], XmNselectionPolicy, XmSINGLE_SELECT); n++;
}
+ if(args->height > 0) {
+ XtSetArg(xargs[n], XmNheight, args->height); n++;
+ }
char *name = args->name ? (char*)args->name : "listview";
Widget parent = ui_container_prepare(ctn, &layout, xargs, &n);
UiListSelection sel = { cb->selected_item_count, NULL };
if(sel.count > 0) {
sel.rows = calloc(sel.count, sizeof(int));
- for(int i=0;i<sel.count;i++) {
- sel.rows[i] = cb->selected_item_positions[i]-1;
+ if(sel.count == 1) {
+ sel.rows[0] = cb->item_position-1;
+ } else if(cb->selected_item_positions) {
+ for(int i=0;i<sel.count;i++) {
+ sel.rows[i] = cb->selected_item_positions[i]-1;
+ }
}
}
free(listview->current_selection.rows);
UiListSelection ui_listview_getselection(UiList *list) {
UiListView *listview = list->obj;
- UiListSelection sel = { listview->current_selection.count, NULL };
- if(sel.count > 0) {
- sel.rows = calloc(sel.count, sizeof(int));
- memcpy(sel.rows, listview->current_selection.rows, sel.count*sizeof(int));
+ UiListSelection sel = { 0, NULL };
+ int *selpositions = NULL;
+ int numpos = 0;
+ XtVaGetValues(listview->widget, XmNselectedPositions, &selpositions, XmNselectedPositionCount, &numpos, NULL);
+ if(numpos > 0) {
+ sel.rows = calloc(numpos, sizeof(int));
+ sel.count = numpos;
+ memcpy(sel.rows, selpositions, numpos*sizeof(int));
+ // motif selected positions start at index 1 -> translate positions
+ for(int i=0;i<numpos;i++) {
+ sel.rows[i]--;
+ }
}
return sel;
}
UiList *list = var->value;
list->obj = listview;
list->update = ui_listview_update;
- list->getselection = ui_listview_getselection;
- list->setselection = ui_listview_setselection;
+ list->getselection = ui_dropdown_getselection;
+ list->setselection = ui_dropdown_setselection;
ui_listview_update(list, 0);
}
return widget;
}
+
+void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
+ UiListView *listview = list->obj;
+ if(selection.count > 0) {
+ XtVaSetValues(listview->widget, XmNselectedPosition, selection.rows[0], NULL);
+ } else {
+ XtVaSetValues(listview->widget, XmNselectedPosition, 0, NULL);
+ }
+}
+
+UiListSelection ui_dropdown_getselection(UiList *list) {
+ UiListView *listview = list->obj;
+ int pos = -1;
+ XtVaGetValues(listview->widget, XmNselectedPosition, &pos, NULL);
+ UiListSelection sel = { 0, NULL };
+ if(pos >= 0) {
+ sel.rows = malloc(sizeof(int));
+ sel.rows[0] = pos;
+ sel.count = 1;
+ }
+ return sel;
+}
UiListSelection ui_listview_getselection(UiList *list);
void ui_listview_setselection(UiList *list, UiListSelection selection);
+void ui_dropdown_setselection(UiList *list, UiListSelection selection);
+UiListSelection ui_dropdown_getselection(UiList *list);
+
void* ui_strmodel_getvalue(void *elm, int column);
#ifdef __cplusplus
/* UI_MENU_SEPARATOR */ add_menuseparator_widget
};
-void ui_create_menubar(UiObject *obj, Widget window) {
+Widget ui_create_menubar(UiObject *obj, Widget window) {
UiMenu *menus_begin = uic_get_menu_list();
if(!menus_begin) {
- return;
+ return NULL;
}
Widget menubar = XmCreateMenuBar(window, "menubar", NULL, 0);
add_menu_widget(menubar, 0, &menu->item, obj);
ls = (UiMenu*)ls->item.next;
}
+
+ return menubar;
}
void ui_add_menu_items(Widget parent, int i, UiMenu *menu, UiObject *obj) {
XtSetArg(args[n], XmNlabelString, s); n++;
}
- Widget submenu = XmVaCreateSimplePulldownMenu(parent, "menu_pulldown", i, NULL, NULL);
+ Widget submenu = XmCreatePulldownMenu(parent, "menu_pulldown", NULL, 0);
XtSetArg(args[n], XmNsubMenuId, submenu); n++;
- Widget menuItem = XtCreateManagedWidget(
+ (void)XtCreateManagedWidget(
"menuitem",
xmCascadeButtonWidgetClass,
parent,
args,
n);
-
if(s) {
XmStringFree(s);
}
XtAddCallback(
mitem,
XmNdestroyCallback,
- (XtCallbackProc)ui_destroy_eventdata,
+ (XtCallbackProc)ui_destroy_data,
eventdata);
}
XtAddCallback(
mitem,
XmNdestroyCallback,
- (XtCallbackProc)ui_destroy_eventdata,
+ (XtCallbackProc)ui_destroy_data,
eventdata);
}
typedef void(*ui_menu_add_f)(Widget, int, UiMenuItemI*, UiObject*);
-void ui_create_menubar(UiObject *obj, Widget window);
+Widget ui_create_menubar(UiObject *obj, Widget window);
void ui_add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj);
void add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj);
MOTIFOBJ += button.o
MOTIFOBJ += label.o
MOTIFOBJ += text.o
+MOTIFOBJ += pathbar.o
MOTIFOBJ += list.o
MOTIFOBJ += graphics.o
MOTIFOBJ += range.o
MOTIFOBJ += dnd.o
MOTIFOBJ += image.o
MOTIFOBJ += Grid.o
+MOTIFOBJ += entry.o
+MOTIFOBJ += Fsb.o
TOOLKITOBJS += $(MOTIFOBJ:%=$(MOTIF_OBJPRE)%)
TOOLKITSOURCE += $(MOTIFOBJ:%.o=motif/%.c)
#include "text.h"
#include "container.h"
+#include "pathbar.h"
+
+#include "../common/utils.h"
#include <cx/string.h>
ui_set_widget_groups(obj->ctx, textfield, args->groups);
+ UiEventDataExt *eventdata = malloc(sizeof(UiEventDataExt));
+ memset(eventdata, 0, sizeof(UiEventDataExt));
+ eventdata->obj = obj;
+ eventdata->callback = args->onactivate;
+ eventdata->userdata = args->onactivatedata;
+ eventdata->callback2 = args->onchange;
+ eventdata->userdata2 = args->onchangedata;
+
UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_STRING);
if(var) {
+ eventdata->customdata0 = var;
+
UiString *value = (UiString*)var->value;
value->obj = textfield;
value->get = ui_textfield_get;
}
}
+ XtAddCallback(
+ textfield,
+ XmNactivateCallback,
+ (XtCallbackProc)ui_textfield_activate,
+ eventdata);
+ XtAddCallback(
+ textfield,
+ XmNvalueChangedCallback,
+ (XtCallbackProc)ui_textfield_value_changed,
+ eventdata);
+ XtAddCallback(
+ textfield,
+ XmNdestroyCallback,
+ (XtCallbackProc)ui_destroy_data,
+ eventdata);
+
return textfield;
}
+static void textfield_event(UiEventDataExt *eventdata, ui_callback callback, void *userdata) {
+ if(callback) {
+ UiVar *var = eventdata->customdata0;
+ UiString *value = var ? var->value : NULL;
+
+ UiEvent e;
+ e.obj = eventdata->obj;
+ e.window = e.obj->window;
+ e.document = e.obj->ctx->document;
+ e.eventdata = value;
+ e.eventdatatype = value ? UI_EVENT_DATA_TEXT_VALUE : 0;
+ e.intval = 0;
+ e.set = ui_get_setop();
+ callback(&e, userdata);
+ }
+}
+
+void ui_textfield_activate(Widget widget, XtPointer ud, XtPointer cb) {
+ UiEventDataExt *eventdata = ud;
+ textfield_event(ud, eventdata->callback, eventdata->userdata);
+}
+
+void ui_textfield_value_changed(Widget widget, XtPointer ud, XtPointer cb) {
+ UiEventDataExt *eventdata = ud;
+ if(ui_onchange_events_is_enabled()) {
+ textfield_event(ud, eventdata->callback2, eventdata->userdata2);
+ }
+}
+
UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs *args) {
return create_textfield(obj, args, FALSE, FALSE);
}
}
-
-
-
-/* -------------------- path bar -------------------- */
-
-#define XNECreateText(parent,name,args,count) XmCreateTextField(parent,name,args,count)
-#define XNETextSetString(widget,value) XmTextFieldSetString(widget,value)
-#define XNETextGetString(widget) XmTextFieldGetString(widget)
-#define XNETextGetLastPosition(widget) XmTextFieldGetLastPosition(widget)
-#define XNETextSetInsertionPosition(widget, i) XmTextFieldSetInsertionPosition(widget, i)
-#define XNETextSetSelection(w, f, l, t) XmTextFieldSetSelection(w, f, l, t)
-
-typedef void(*updatedir_callback)(void*,char*,int);
-
-typedef struct PathBar {
- Widget widget;
- Widget textfield;
-
- Widget focus_widget;
-
- Widget left;
- Widget right;
- Dimension lw;
- Dimension rw;
-
- int shift;
-
- UiPathElm *current_pathelms;
- Widget *pathSegments;
- size_t numSegments;
- size_t segmentAlloc;
-
- char *path;
- int selection;
- Boolean input;
-
- int focus;
-
- updatedir_callback updateDir;
- void *updateDirData;
-
- ui_pathelm_func getpathelm;
- void *getpathelmdata;
-} PathBar;
-
-void PathBarSetPath(PathBar *bar, const char *path);
-
-void pathbar_resize(Widget w, PathBar *p, XtPointer d)
-{
- Dimension width, height;
- XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
-
- Dimension *segW = (void*)XtCalloc(p->numSegments, sizeof(Dimension));
-
- Dimension maxHeight = 0;
-
- /* get width/height from all widgets */
- Dimension pathWidth = 0;
- for(int i=0;i<p->numSegments;i++) {
- Dimension segWidth;
- Dimension segHeight;
- XtVaGetValues(p->pathSegments[i], XmNwidth, &segWidth, XmNheight, &segHeight, NULL);
- segW[i] = segWidth;
- pathWidth += segWidth;
- if(segHeight > maxHeight) {
- maxHeight = segHeight;
- }
- }
- Dimension tfHeight;
- XtVaGetValues(p->textfield, XmNheight, &tfHeight, NULL);
- if(tfHeight > maxHeight) {
- maxHeight = tfHeight;
- }
-
- Boolean arrows = False;
- if(pathWidth + 10 > width) {
- arrows = True;
- pathWidth += p->lw + p->rw;
- }
-
- /* calc max visible widgets */
- int start = 0;
- if(arrows) {
- Dimension vis = p->lw+p->rw;
- for(int i=p->numSegments;i>0;i--) {
- Dimension segWidth = segW[i-1];
- if(vis + segWidth + 10 > width) {
- start = i;
- arrows = True;
- break;
- }
- vis += segWidth;
- }
- } else {
- p->shift = 0;
- }
-
- int leftShift = 0;
- if(p->shift < 0) {
- if(start + p->shift < 0) {
- leftShift = start;
- start = 0;
- p->shift = -leftShift;
- } else {
- leftShift = -p->shift; /* negative shift */
- start += p->shift;
- }
- }
-
- int x = 0;
- if(arrows) {
- XtManageChild(p->left);
- XtManageChild(p->right);
- x = p->lw;
- } else {
- XtUnmanageChild(p->left);
- XtUnmanageChild(p->right);
- }
-
- for(int i=0;i<p->numSegments;i++) {
- if(i >= start && i < p->numSegments - leftShift && !p->input) {
- XtVaSetValues(p->pathSegments[i], XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL);
- x += segW[i];
- XtManageChild(p->pathSegments[i]);
- } else {
- XtUnmanageChild(p->pathSegments[i]);
- }
- }
-
- if(arrows) {
- XtVaSetValues(p->left, XmNx, 0, XmNy, 0, XmNheight, maxHeight, NULL);
- XtVaSetValues(p->right, XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL);
- }
-
- free(segW);
-
- Dimension rw, rh;
- XtMakeResizeRequest(w, width, maxHeight, &rw, &rh);
-
- XtVaSetValues(p->textfield, XmNwidth, rw, XmNheight, rh, NULL);
-}
-
-static void pathbarActivateTF(PathBar *p)
-{
- XtUnmanageChild(p->left);
- XtUnmanageChild(p->right);
- XNETextSetSelection(p->textfield, 0, XNETextGetLastPosition(p->textfield), 0);
- XtManageChild(p->textfield);
- p->input = 1;
-
- XmProcessTraversal(p->textfield, XmTRAVERSE_CURRENT);
-
- pathbar_resize(p->widget, p, NULL);
-}
-
-void PathBarActivateTextfield(PathBar *p)
-{
- p->focus = 1;
- pathbarActivateTF(p);
-}
-
-void pathbar_input(Widget w, PathBar *p, XtPointer c)
-{
- XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c;
- XEvent *xevent = cbs->event;
-
- if (cbs->reason == XmCR_INPUT) {
- if (xevent->xany.type == ButtonPress) {
- p->focus = 0;
- pathbarActivateTF(p);
- }
- }
-}
-
-void pathbar_losingfocus(Widget w, PathBar *p, XtPointer c)
-{
- if(--p->focus < 0) {
- p->input = False;
- XtUnmanageChild(p->textfield);
- }
-}
-
-static cxmutstr concat_path_s(cxstring base, cxstring path) {
- if(!path.ptr) {
- path = CX_STR("");
- }
-
- int add_separator = 0;
- if(base.length != 0 && base.ptr[base.length-1] == '/') {
- if(path.ptr[0] == '/') {
- base.length--;
- }
- } else {
- if(path.length == 0 || path.ptr[0] != '/') {
- add_separator = 1;
- }
- }
-
- cxmutstr url;
- if(add_separator) {
- url = cx_strcat(3, base, CX_STR("/"), path);
- } else {
- url = cx_strcat(2, base, path);
- }
-
- return url;
-}
-
-static char* ConcatPath(const char *path1, const char *path2) {
- return concat_path_s(cx_str(path1), cx_str(path2)).ptr;
-}
-
-void pathbar_pathinput(Widget w, PathBar *p, XtPointer d)
-{
- char *newpath = XNETextGetString(p->textfield);
- if(newpath) {
- if(newpath[0] == '~') {
- char *p = newpath+1;
- char *home = getenv("HOME");
- char *cp = ConcatPath(home, p);
- XtFree(newpath);
- newpath = cp;
- } else if(newpath[0] != '/') {
- char curdir[2048];
- curdir[0] = 0;
- getcwd(curdir, 2048);
- char *cp = ConcatPath(curdir, newpath);
- XtFree(newpath);
- newpath = cp;
- }
-
- /* update path */
- PathBarSetPath(p, newpath);
- if(p->updateDir) {
- p->updateDir(p->updateDirData, newpath, -1);
- }
- XtFree(newpath);
-
- /* hide textfield and show path as buttons */
- XtUnmanageChild(p->textfield);
- pathbar_resize(p->widget, p, NULL);
-
- if(p->focus_widget) {
- XmProcessTraversal(p->focus_widget, XmTRAVERSE_CURRENT);
- }
- }
-}
-
-void pathbar_shift_left(Widget w, PathBar *p, XtPointer d)
-{
- p->shift--;
- pathbar_resize(p->widget, p, NULL);
-}
-
-void pathbar_shift_right(Widget w, PathBar *p, XtPointer d)
-{
- if(p->shift < 0) {
- p->shift++;
- }
- pathbar_resize(p->widget, p, NULL);
-}
-
-static void pathTextEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) {
- PathBar *pb = data;
- if(event->type == KeyReleaseMask) {
- if(event->xkey.keycode == 9) {
- XtUnmanageChild(pb->textfield);
- pathbar_resize(pb->widget, pb, NULL);
- *dispatch = False;
- } else if(event->xkey.keycode == 36) {
- pathbar_pathinput(pb->textfield, pb, NULL);
- *dispatch = False;
- }
- }
-}
-
-PathBar* CreatePathBar(Widget parent, ArgList args, int n)
-{
- PathBar *bar = (PathBar*)XtMalloc(sizeof(PathBar));
- bar->path = NULL;
- bar->updateDir = NULL;
- bar->updateDirData = NULL;
-
- bar->focus_widget = NULL;
-
- bar->getpathelm = NULL;
- bar->getpathelmdata = NULL;
- bar->current_pathelms = NULL;
-
- bar->shift = 0;
-
- XtSetArg(args[n], XmNmarginWidth, 0); n++;
- XtSetArg(args[n], XmNmarginHeight, 0); n++;
- bar->widget = XmCreateDrawingArea(parent, "pathbar", args, n);
- XtAddCallback(
- bar->widget,
- XmNresizeCallback,
- (XtCallbackProc)pathbar_resize,
- bar);
- XtAddCallback(
- bar->widget,
- XmNinputCallback,
- (XtCallbackProc)pathbar_input,
- bar);
-
- Arg a[4];
- XtSetArg(a[0], XmNshadowThickness, 0);
- XtSetArg(a[1], XmNx, 0);
- XtSetArg(a[2], XmNy, 0);
- bar->textfield = XNECreateText(bar->widget, "pbtext", a, 3);
- bar->input = 0;
- XtAddCallback(
- bar->textfield,
- XmNlosingFocusCallback,
- (XtCallbackProc)pathbar_losingfocus,
- bar);
- XtAddCallback(bar->textfield, XmNactivateCallback,
- (XtCallbackProc)pathbar_pathinput, bar);
- XtAddEventHandler(bar->textfield, KeyPressMask | KeyReleaseMask, FALSE, pathTextEH, bar);
-
- XtSetArg(a[0], XmNarrowDirection, XmARROW_LEFT);
- bar->left = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
- XtSetArg(a[0], XmNarrowDirection, XmARROW_RIGHT);
- bar->right = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
- XtAddCallback(
- bar->left,
- XmNactivateCallback,
- (XtCallbackProc)pathbar_shift_left,
- bar);
- XtAddCallback(
- bar->right,
- XmNactivateCallback,
- (XtCallbackProc)pathbar_shift_right,
- bar);
-
- Pixel bg;
- XtVaGetValues(bar->textfield, XmNbackground, &bg, NULL);
- XtVaSetValues(bar->widget, XmNbackground, bg, NULL);
-
- XtManageChild(bar->left);
- XtManageChild(bar->right);
-
- XtVaGetValues(bar->left, XmNwidth, &bar->lw, NULL);
- XtVaGetValues(bar->right, XmNwidth, &bar->rw, NULL);
-
- bar->segmentAlloc = 16;
- bar->numSegments = 0;
- bar->pathSegments = (Widget*)XtCalloc(16, sizeof(Widget));
-
- bar->selection = 0;
-
- return bar;
-}
-
-void PathBarChangeDir(Widget w, PathBar *bar, XtPointer c)
-{
- XmToggleButtonSetState(bar->pathSegments[bar->selection], False, False);
-
- int i;
- for(i=0;i<bar->numSegments;i++) {
- if(bar->pathSegments[i] == w) {
- bar->selection = i;
- XmToggleButtonSetState(w, True, False);
- break;
- }
- }
-
- UiPathElm elm = bar->current_pathelms[i];
- cxmutstr path = cx_strdup(cx_strn(elm.path, elm.path_len));
- if(bar->updateDir) {
- XNETextSetString(bar->textfield, path.ptr);
- bar->updateDir(bar->updateDirData, path.ptr, i);
- }
- free(path.ptr);
-}
-
-static void ui_pathelm_destroy(UiPathElm *elms, size_t nelm) {
- for(int i=0;i<nelm;i++) {
- free(elms[i].name);
- free(elms[i].path);
- }
- free(elms);
-}
-
-void PathBarSetPath(PathBar *bar, const char *path)
-{
- if(bar->path) {
- free(bar->path);
- }
- bar->path = strdup(path);
-
- for(int i=0;i<bar->numSegments;i++) {
- XtDestroyWidget(bar->pathSegments[i]);
- }
- XtUnmanageChild(bar->textfield);
- XtManageChild(bar->left);
- XtManageChild(bar->right);
- bar->input = False;
-
- Arg args[4];
- XmString str;
-
- bar->numSegments = 0;
-
- ui_pathelm_destroy(bar->current_pathelms, bar->numSegments);
- size_t nelm = 0;
- UiPathElm* path_elm = bar->getpathelm(bar->path, strlen(bar->path), &nelm, bar->getpathelmdata);
- if (!path_elm) {
- return;
- }
- bar->current_pathelms = path_elm;
- bar->numSegments = nelm;
- bar->pathSegments = realloc(bar->pathSegments, nelm * sizeof(Widget*));
-
- for(int i=0;i<nelm;i++) {
- UiPathElm elm = path_elm[i];
-
- cxmutstr name = cx_strdup(cx_strn(elm.name, elm.name_len));
- str = XmStringCreateLocalized(elm.name);
- free(name.ptr);
-
- XtSetArg(args[0], XmNlabelString, str);
- XtSetArg(args[1], XmNfillOnSelect, True);
- XtSetArg(args[2], XmNindicatorOn, False);
- Widget button = XmCreateToggleButton(bar->widget, "pbbutton", args, 3);
- XtAddCallback(
- button,
- XmNvalueChangedCallback,
- (XtCallbackProc)PathBarChangeDir,
- bar);
- XmStringFree(str);
-
- bar->pathSegments[i] = button;
- }
-
- bar->selection = bar->numSegments-1;
- XmToggleButtonSetState(bar->pathSegments[bar->selection], True, False);
-
- XNETextSetString(bar->textfield, (char*)path);
- XNETextSetInsertionPosition(bar->textfield, XNETextGetLastPosition(bar->textfield));
-
- pathbar_resize(bar->widget, bar, NULL);
-}
-
-void PathBarDestroy(PathBar *pathbar) {
- if(pathbar->path) {
- XtFree(pathbar->path);
- }
- XtFree((void*)pathbar->pathSegments);
- XtFree((void*)pathbar);
-}
-
-
/* ---------------------------- Path Text Field ---------------------------- */
static void destroy_pathbar(Widget w, XtPointer *data, XtPointer d) {
XtFree((void*)pathbar);
}
-// TODO: move to common
-static UiPathElm* default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data) {
- cxstring *pathelms;
- size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len), CX_STR("/"), 4096, &pathelms);
-
- if (nelm == 0) {
- *ret_nelm = 0;
- return NULL;
- }
-
- UiPathElm* elms = (UiPathElm*)calloc(nelm, sizeof(UiPathElm));
- size_t n = nelm;
- int j = 0;
- for (int i = 0; i < nelm; i++) {
- cxstring c = pathelms[i];
- if (c.length == 0) {
- if (i == 0) {
- c.length = 1;
- }
- else {
- n--;
- continue;
- }
- }
-
- cxmutstr m = cx_strdup(c);
- elms[j].name = m.ptr;
- elms[j].name_len = m.length;
-
- size_t elm_path_len = c.ptr + c.length - full_path;
- cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len));
- elms[j].path = elm_path.ptr;
- elms[j].path_len = elm_path.length;
-
- j++;
- }
- *ret_nelm = n;
-
- return elms;
-}
-
static void pathbar_activate(void *data, char *path, int index) {
UiEventData *event = data;
UiEvent evt;
PathBar *pathbar = CreatePathBar(parent, xargs, n);
if(!args->getpathelm) {
- pathbar->getpathelm= default_pathelm_func;
+ pathbar->getpathelm= ui_default_pathelm_func;
} else {
pathbar->getpathelm = args->getpathelm;
pathbar->getpathelmdata = args->getpathelmdata;
XtAddCallback(
pathbar->widget,
XmNdestroyCallback,
- (XtCallbackProc)ui_destroy_eventdata,
+ (XtCallbackProc)ui_destroy_data,
eventdata);
}
int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen);
void ui_free_textbuf_op(UiTextBufOp *op);
+void ui_textfield_activate(Widget widget, XtPointer ud, XtPointer cb);
+void ui_textfield_value_changed(Widget widget, XtPointer ud, XtPointer cb);
+
char* ui_textfield_get(UiString *str);
void ui_textfield_set(UiString *str, const char *value);
NULL
};
+static String *fallback_resources = fallback;
+
void input_proc(XtPointer data, int *source, XtInputId *iid) {
void *ptr;
read(event_pipe[0], &ptr, sizeof(void*));
}
+void ui_motif_set_fallback_resources(String *fallbackres) {
+ fallback_resources = fallbackres;
+}
+
void ui_init(const char *appname, int argc, char **argv) {
application_name = appname;
uic_init_global_context();
XtToolkitInitialize();
XtSetLanguageProc(NULL, NULL, NULL);
app = XtCreateApplicationContext();
- XtAppSetFallbackResources(app, fallback);
+ XtAppSetFallbackResources(app, fallback_resources);
display = XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv);
return application_name;
}
+XtAppContext ui_motif_get_app(void) {
+ return app;
+}
+
Display* ui_motif_get_display() {
return display;
}
}
}
-void ui_exit_mainloop() {
+void ui_app_quit() {
XtAppSetExitFlag(app);
}
return TRUE;
}
+static Boolean ui_mainthread_job(void *data) {
+ UiJob *job = data;
+ if(job->job_func) {
+ job->job_func(job->job_data);
+ }
+ free(job);
+ return TRUE;
+}
+
static void* ui_jobthread(void *data) {
UiJob *job = data;
int result = job->job_func(job->job_data);
return NULL;
}
+void ui_call_mainthread(ui_threadfunc tf, void* td) {
+ UiJob *job = malloc(sizeof(UiJob));
+ memset(job, 0, sizeof(UiJob));
+ job->job_func = tf;
+ job->job_data = td;
+ write(event_pipe[1], &job, sizeof(void*)); // hack
+ XtAppAddWorkProc(app, ui_mainthread_job, job);
+}
+
void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) {
UiJob *job = malloc(sizeof(UiJob));
job->obj = obj;
4);
}
-void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d) {
+void ui_destroy_data(Widget w, XtPointer data, XtPointer d) {
free(data);
}
typedef enum UiOrientation UiOrientation;
enum UiOrientation { UI_HORIZONTAL = 0, UI_VERTICAL };
-void ui_exit_mainloop();
-
+XtAppContext ui_motif_get_app(void);
Display* ui_motif_get_display(void);
+void ui_motif_set_fallback_resources(String *fallback);
void ui_set_active_window(Widget w);
Widget ui_get_active_window();
void ui_secondary_event_loop(int *loop);
void ui_window_dark_theme(Display *dp, Window window);
-void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d);
+void ui_destroy_data(Widget w, XtPointer data, XtPointer d);
void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) ;
void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups);
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "window.h"
#include "toolkit.h"
#include "menu.h"
#include "toolbar.h"
#include "container.h"
-#include "../ui/window.h"
+#include "pathbar.h"
#include "../common/context.h"
+#include "../common/utils.h"
#include "Grid.h"
+#include "Fsb.h"
#include <cx/mempool.h>
uic_object_destroy(obj);
nwindows--;
if(nwindows == 0) {
- ui_exit_mainloop();
+ ui_app_quit();
}
}
obj->window = window_data;
obj->destroy = ui_window_widget_destroy;
+ int window_width = window_default_width;
+ int window_height = window_default_height;
+ if(!simple) {
+ ui_get_window_default_width(&window_width, &window_height);
+ }
+
+ UiMotifAppWindow *appwindow = cxZalloc(a, sizeof(UiMotifAppWindow));
+ ui_object_set(obj, "ui_motif_app_window", appwindow);
+
Arg args[16];
int n = 0;
XtSetArg(args[n], XmNtitle, title); n++;
XtSetArg(args[n], XmNminWidth, 100); n++;
XtSetArg(args[n], XmNminHeight, 50); n++;
- XtSetArg(args[n], XmNwidth, window_default_width); n++;
- XtSetArg(args[n], XmNheight, window_default_height); n++;
+ XtSetArg(args[n], XmNwidth, window_width); n++;
+ XtSetArg(args[n], XmNheight, window_height); n++;
Widget toplevel = XtAppCreateShell(
ui_appname(),
// menu
if(!simple) {
- ui_create_menubar(obj, window);
+ appwindow->menubar = ui_create_menubar(obj, window);
}
// content frame
UiObject* ui_simple_window(const char *title, void *window_data) {
return create_window(title, window_data, TRUE);
}
+
+void ui_window_size(UiObject *obj, int width, int height) {
+ XtVaSetValues(obj->widget, XmNwidth, width, XmNheight, height, NULL);
+}
+
+void ui_window_default_size(int width, int height) {
+ window_default_width = width;
+ window_default_height = height;
+}
+
+void ui_window_menubar_set_visible(UiObject *obj, UiBool visible) {
+ UiMotifAppWindow *window = ui_object_get(obj, "ui_motif_app_window");
+ if(window) {
+ if(window->menubar) {
+ ui_set_visible(window->menubar, visible);
+ }
+ } else {
+ fprintf(stderr, "Error: obj is not an application window\n");
+ }
+}
+
+static Atom net_wm_state;
+static Atom net_wm_state_fullscreen;
+static int net_wm_atoms_initialized = 0;
+
+void ui_window_fullscreen(UiObject *obj, UiBool fullscreen) {
+ Display *dpy = XtDisplay(obj->widget);
+
+ // init net_wm_state atoms
+ if(!net_wm_atoms_initialized) {
+ net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
+ net_wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ net_wm_atoms_initialized = 1;
+ }
+
+ XEvent ev;
+ memset(&ev, 0, sizeof(XEvent));
+ ev.type = ClientMessage;
+ ev.xclient.window = XtWindow(obj->widget);
+ ev.xclient.message_type = net_wm_state;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = fullscreen ? 1 : 0;
+ ev.xclient.data.l[1] = net_wm_state_fullscreen;
+ ev.xclient.data.l[2] = 0;
+ XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask | SubstructureRedirectMask, &ev);
+}
+
+static void filedialog_event(UiEventData *event, int result, UiFileList flist) {
+ UiEvent evt;
+ evt.obj = event->obj;
+ evt.document = evt.obj->ctx->document;
+ evt.window = evt.obj->window;
+ evt.intval = result;
+
+ evt.eventdata = &flist;
+ evt.eventdatatype = UI_EVENT_DATA_FILE_LIST;
+
+ if(event->callback) {
+ event->callback(&evt, event->userdata);
+ }
+}
+
+static void filedialog_select(
+ Widget widget,
+ UiEventData *data,
+ XmFileSelectionBoxCallbackStruct *selection)
+{
+ UiFileList flist;
+
+ char *value = NULL;
+ XmStringGetLtoR(selection->value, XmSTRING_DEFAULT_CHARSET, &value);
+ flist.files = &value;
+ flist.nfiles = 1;
+
+ filedialog_event(data, 1, flist);
+
+ XtFree(value);
+
+ XtUnmanageChild(widget);
+ XtDestroyWidget(widget);
+}
+
+static void filedialog_cancel(
+ Widget widget,
+ UiEventData *data,
+ XmFileSelectionBoxCallbackStruct *selection)
+{
+ UiFileList flist;
+ flist.files = NULL;
+ flist.nfiles = 0;
+ filedialog_event(data, 0, flist);
+
+ XtUnmanageChild(widget);
+ XtDestroyWidget(widget);
+}
+
+void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata) {
+ Widget dialog = XnCreateFileSelectionDialog(obj->widget, "dialog", NULL, 0);
+
+ UiEventData *data = malloc(sizeof(UiEventData));
+ memset(data, 0, sizeof(UiEventData));
+ data->obj = obj;
+ data->callback = file_selected_callback;
+ data->userdata = cbdata;
+
+ XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)filedialog_select, data);
+ XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)filedialog_cancel, data);
+ //XtAddCallback(dialog, XmNhelpCallback, (XtCallbackProc)filedialog_help, wd);
+
+ XtManageChild(dialog);
+}
+
+void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata) {
+ Arg args[16];
+ int n = 0;
+
+ // Save File Dialog needs this parameter
+ XtSetArg(args[n], XnNfsbType, FILEDIALOG_SAVE); n++;
+ char *selectedpath = (char*)name;
+ if(name) {
+ if(name[0] != '/') {
+ char cwd[PATH_MAX];
+ if(getcwd(cwd, PATH_MAX)) {
+ pathbar_concat_path(cwd, name);
+ } else {
+ fprintf(stderr, "Error: getcwd failed: %s\n", strerror(errno));
+ selectedpath = NULL;
+ }
+ }
+ if(selectedpath) {
+ XtSetArg(args[n], XnNselectedPath, selectedpath); n++;
+ }
+ }
+ Widget dialog = XnCreateFileSelectionDialog(obj->widget, "dialog", args, n);
+
+ UiEventData *data = malloc(sizeof(UiEventData));
+ memset(data, 0, sizeof(UiEventData));
+ data->obj = obj;
+ data->callback = file_selected_callback;
+ data->userdata = cbdata;
+
+ XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)filedialog_select, data);
+ XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)filedialog_cancel, data);
+ //XtAddCallback(dialog, XmNhelpCallback, (XtCallbackProc)filedialog_help, wd);
+
+ XtManageChild(dialog);
+
+ if(selectedpath != name) {
+ free(selectedpath);
+ }
+}
#ifndef WINDOW_H
#define WINDOW_H
+#include "../ui/window.h"
+#include "../ui/widget.h"
+
#ifdef __cplusplus
extern "C" {
#endif
+
+#define UI_MOTIF_APP_WINDOW 0xabcd
-
+typedef struct UiMotifAppWindow {
+ Widget menubar;
+} UiMotifAppWindow;
#ifdef __cplusplus
int margin_bottom;
int colspan;
int rowspan;
+ int width;
+ int height;
const char *name;
const char *style_class;
typedef void(*ui_enablefunc)(void*, int);
+typedef void (*ui_destructor_func)(void *memory);
+
+
struct UiObject {
/*
* native widget
void* (*get)(UiGeneric*);
const char* (*get_type)(UiGeneric*);
int (*set)(UiGeneric*, void *, const char *type);
+ void (*destroy)(UiGeneric*);
void *obj;
void *value;
};
typedef void (*ui_list_init_func)(UiContext *ctx, UiList *list, void *userdata);
+typedef void (*ui_list_destroy_func)(UiContext *ctx, UiList *list, void *userdata);
/*
* abstract list
UIEXPORT void ui_app_exit_on_shutdown(UiBool exitapp);
UIEXPORT void ui_main(void);
+UIEXPORT void ui_app_quit(void);
UIEXPORT void ui_show(UiObject *obj);
UIEXPORT void ui_close(UiObject *obj);
UIEXPORT void ui_detach_document(UiContext *ctx, void *document);
UIEXPORT void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...);
-UIEXPORT void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, int *groups, int ngroups);
-UIEXPORT void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, int *states, int nstates);
+UIEXPORT void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, const int *groups, int ngroups);
+UIEXPORT void ui_widget_set_visibility_states(UiContext *ctx, UIWIDGET widget, const int *states, int nstates);
UIEXPORT void ui_set_group(UiContext *ctx, int group);
UIEXPORT void ui_unset_group(UiContext *ctx, int group);
UIEXPORT void ui_free(UiContext *ctx, void *ptr);
UIEXPORT void* ui_realloc(UiContext *ctx, void *ptr, size_t size);
UIEXPORT char* ui_strdup(UiContext *ctx, const char *str);
+UIEXPORT void ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr);
+UIEXPORT void ui_set_destructor(void *mem, ui_destructor_func destr);
// types
UIEXPORT UiList* ui_list_new(UiContext *ctx, const char *name);
UIEXPORT UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func init, void *userdata);
-UIEXPORT void ui_list_free(UiList *list);
+UIEXPORT void ui_list_free(UiContext *ctx, UiList *list);
UIEXPORT void* ui_list_first(UiList *list);
UIEXPORT void* ui_list_next(UiList *list);
UIEXPORT void* ui_list_get(UiList *list, int i);
UIEXPORT void ui_setop_enable(int set);
UIEXPORT int ui_get_setop(void);
+UIEXPORT void ui_onchange_events_enable(UiBool enable);
+UIEXPORT UiBool ui_onchange_events_is_enabled(void);
UIEXPORT void ui_global_list_initializer(ui_list_init_func func, void *userdata);
+UIEXPORT void ui_global_list_destructor(ui_list_destroy_func func, void *userdata);
UIEXPORT void ui_list_class_set_first(UiList *list, void*(*first)(UiList *list));
UIEXPORT void ui_list_class_set_next(UiList *list, void*(*next)(UiList *list));
UIEXPORT void ui_list_class_set_get(UiList *list, void*(*get)(UiList *list, int i));
UIEXPORT void ui_list_class_set_data(UiList *list, void *data);
UIEXPORT void ui_list_class_set_iter(UiList *list, void *iter);
+UIEXPORT void ui_object_set(UiObject *obj, const char *key, void *data);
+UIEXPORT void* ui_object_get(UiObject *obj, const char *key);
+
#ifdef __cplusplus
}
#endif
const char *name;
const char *style_class;
- UiList* list;
+ UiList *list;
const char* varname;
- UiModel* model;
+ UiModel *model;
char **static_elements;
size_t static_nelm;
ui_getvaluefunc getvalue;
ui_getstylefunc getstyle;
void *getstyledata;
ui_callback onactivate;
- void* onactivatedata;
+ void *onactivatedata;
ui_callback onselection;
- void* onselectiondata;
+ void *onselectiondata;
ui_callback ondragstart;
- void* ondragstartdata;
+ void *ondragstartdata;
ui_callback ondragcomplete;
- void* ondragcompletedata;
+ void *ondragcompletedata;
ui_callback ondrop;
- void* ondropdata;
+ void *ondropdata;
UiBool multiselection;
UiMenuBuilder *contextmenu;
ui_list_savefunc onsave;
#define ui_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, &(UiListArgs) { __VA_ARGS__ } )
#define ui_sourcelist(obj, ...) ui_sourcelist_create(obj, &(UiSourceListArgs) { __VA_ARGS__ } )
-UIEXPORT UIWIDGET ui_listview_create(UiObject* obj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject* obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args);
+UIEXPORT UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args);
+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);
extern "C" {
#endif
+/*
+ * WebView type string used by UiGeneric
+ */
#define UI_WEBVIEW_OBJECT_TYPE "webview"
-
+
+/*
+ * UiWebViewData* is returned by a webviews UiGeneric->get function
+ */
+typedef struct UiWebViewData UiWebViewData;
+
typedef struct UiWebviewArgs {
UiBool fill;
UiBool hexpand;
#define ui_webview(obj, ...) ui_webview_create(obj, &(UiWebviewArgs){ __VA_ARGS__ } )
-UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args);
+UIEXPORT UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args);
-void ui_webview_load_url(UiGeneric *g, const char *url);
+UIEXPORT void ui_webview_load_url(UiGeneric *g, const char *url);
-void ui_webview_load_content(
+UIEXPORT void ui_webview_load_content(
UiGeneric *g,
const char *uri,
const char *content,
const char *mimetype,
const char *encoding);
+/*
+ * Frees a UiWebViewData object returned by a webviews UiGeneric->get function
+ */
+UIEXPORT void ui_webview_data_free(UiWebViewData *data);
-void ui_webview_reload(UiGeneric *g);
-UiBool ui_webview_can_go_back(UiGeneric *g);
-UiBool ui_webview_can_go_forward(UiGeneric *g);
-void ui_webview_go_back(UiGeneric *g);
-void ui_webview_go_forward(UiGeneric *g);
-const char * ui_webview_get_uri(UiGeneric *g);
-void ui_webview_enable_javascript(UiGeneric *g, UiBool enable);
-void ui_webview_set_zoom(UiGeneric *g, double zoom);
-double ui_webview_get_zoom(UiGeneric *g);
+UIEXPORT void ui_webview_reload(UiGeneric *g);
+UIEXPORT UiBool ui_webview_can_go_back(UiGeneric *g);
+UIEXPORT UiBool ui_webview_can_go_forward(UiGeneric *g);
+UIEXPORT void ui_webview_go_back(UiGeneric *g);
+UIEXPORT void ui_webview_go_forward(UiGeneric *g);
+UIEXPORT const char * ui_webview_get_uri(UiGeneric *g);
+UIEXPORT void ui_webview_enable_javascript(UiGeneric *g, UiBool enable);
+UIEXPORT void ui_webview_set_zoom(UiGeneric *g, double zoom);
+UIEXPORT double ui_webview_get_zoom(UiGeneric *g);
#ifdef __cplusplus
};\r
\r
struct W32WidgetClass {\r
- void (*eventproc)(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+ int (*eventproc)(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
void (*show)(W32Widget *widget, BOOLEAN show);\r
void (*enable)(W32Widget *widget, BOOLEAN enable);\r
W32Size (*get_preferred_size)(W32Widget *widget);\r
UIEXPORT void ui_window_size(UiObject *obj, int width, int height);
UIEXPORT void ui_window_default_size(int width, int height);
+UIEXPORT void ui_window_menubar_set_visible(UiObject *obj, UiBool visible);
+
+UIEXPORT void ui_window_fullscreen(UiObject *obj, UiBool fullscreen);
UIEXPORT void ui_splitview_window_set_pos(UiObject *obj, int pos);
UIEXPORT int ui_splitview_window_get_pos(UiObject *obj);
#include <stdio.h>\r
#include <stdlib.h>\r
\r
+#include <cx/array_list.h>\r
+\r
#include <commctrl.h>\r
\r
static W32WidgetClass button_widget_class = {\r
.destroy = w32_widget_default_destroy\r
};\r
\r
+static W32WidgetClass togglebutton_widget_class = {\r
+ .eventproc = ui_togglebutton_eventproc,\r
+ .enable = w32_widget_default_enable,\r
+ .show = w32_widget_default_show,\r
+ .get_preferred_size = ui_button_get_preferred_size,\r
+ .destroy = w32_widget_default_destroy\r
+};\r
+\r
+static W32WidgetClass radiobutton_widget_class = {\r
+ .eventproc = ui_radiobutton_eventproc,\r
+ .enable = w32_widget_default_enable,\r
+ .show = w32_widget_default_show,\r
+ .get_preferred_size = ui_button_get_preferred_size,\r
+ .destroy = w32_widget_default_destroy\r
+};\r
+\r
UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {\r
HINSTANCE hInstance = GetModuleHandle(NULL);\r
UiContainerPrivate *container = ui_obj_container(obj);\r
HWND hwnd = CreateWindow(\r
"BUTTON",\r
args->label,\r
- WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,\r
+ WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,\r
0, 0, 100, 30,\r
parent,\r
- (HMENU)0,\r
+ (HMENU)1,\r
hInstance,\r
NULL);\r
ui_win32_set_ui_font(hwnd);\r
return size;\r
}\r
\r
-void ui_button_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\r
+int ui_button_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\r
UiWidget *w = (UiWidget*)widget;\r
\r
+ if (uMsg != WM_COMMAND) {\r
+ return 0;\r
+ }\r
+\r
UiEvent e;\r
e.obj = w->obj;\r
e.document = e.obj->ctx->document;\r
if (w->callback) {\r
w->callback(&e, w->callbackdata);\r
}\r
+\r
+ return 0;\r
+}\r
+\r
+static UIWIDGET create_togglebutton(UiObject *obj, UiToggleArgs *args, unsigned long type) {\r
+ HINSTANCE hInstance = GetModuleHandle(NULL);\r
+ UiContainerPrivate *container = ui_obj_container(obj);\r
+ HWND parent = ui_container_get_parent(container);\r
+ UiLayout layout = UI_ARGS2LAYOUT(args);\r
+\r
+ HWND hwnd = CreateWindow(\r
+ "BUTTON",\r
+ args->label,\r
+ WS_VISIBLE | WS_CHILD | type,\r
+ 0, 0, 100, 30,\r
+ parent,\r
+ (HMENU)1,\r
+ hInstance,\r
+ NULL);\r
+ ui_win32_set_ui_font(hwnd);\r
+\r
+ W32Widget *widget = w32_widget_create(&togglebutton_widget_class, hwnd, sizeof(UiWidget));\r
+ ui_container_add(container, widget, &layout);\r
+\r
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);\r
+ if (var) {\r
+ UiInteger *i = var->value;\r
+ i->obj = widget;\r
+ i->get = ui_togglebutton_get;\r
+ i->set = ui_togglebutton_set;\r
+ if (i->value != 0) {\r
+ SendMessage(hwnd, BM_SETCHECK, BST_CHECKED, 0);\r
+ }\r
+ }\r
+\r
+ UiWidget *btn = (UiWidget*)widget;\r
+ btn->obj = obj;\r
+ btn->var = var;\r
+ btn->callback = args->onchange;\r
+ btn->callbackdata = args->onchangedata;\r
+\r
+ return widget;\r
+}\r
+\r
+UIWIDGET ui_togglebutton_create(UiObject *obj, UiToggleArgs *args) {\r
+ return create_togglebutton(obj, args, BS_AUTOCHECKBOX | BS_PUSHLIKE);\r
+}\r
+\r
+UIWIDGET ui_checkbox_create(UiObject *obj, UiToggleArgs *args) {\r
+ return create_togglebutton(obj, args, BS_AUTOCHECKBOX);\r
+}\r
+\r
+UIWIDGET ui_switch_create(UiObject *obj, UiToggleArgs *args) {\r
+ return create_togglebutton(obj, args, BS_AUTOCHECKBOX);\r
+}\r
+\r
+int64_t ui_togglebutton_get(UiInteger *i) {\r
+ UiWidget *btn = (UiWidget*)i->obj;\r
+ LRESULT state = SendMessage(btn->widget.hwnd, BM_GETCHECK, 0, 0);\r
+ i->value = state;\r
+ return state;\r
+}\r
+\r
+void ui_togglebutton_set(UiInteger *i, int64_t v) {\r
+ UiWidget *btn = (UiWidget*)i->obj;\r
+ WPARAM state = v ? BST_CHECKED : BST_UNCHECKED;\r
+ SendMessage(btn->widget.hwnd, BM_SETCHECK, state, 0);\r
+ i->value = v;\r
+}\r
+\r
+int ui_togglebutton_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\r
+ if (uMsg != WM_COMMAND) {\r
+ return 0;\r
+ }\r
+ UiWidget *w = (UiWidget*)widget;\r
+\r
+ UiEvent e;\r
+ e.obj = w->obj;\r
+ e.document = e.obj->ctx->document;\r
+ e.window = e.obj->window;\r
+ e.eventdata = NULL;\r
+ e.eventdatatype = 0;\r
+ e.intval = SendMessage(w->widget.hwnd, BM_GETCHECK, 0, 0);\r
+ e.set = ui_get_setop();\r
+\r
+ if (w->callback) {\r
+ w->callback(&e, w->callbackdata);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) {\r
+ HINSTANCE hInstance = GetModuleHandle(NULL);\r
+ UiContainerPrivate *container = ui_obj_container(obj);\r
+ HWND parent = ui_container_get_parent(container);\r
+ UiLayout layout = UI_ARGS2LAYOUT(args);\r
+\r
+ HWND hwnd = CreateWindow(\r
+ "BUTTON",\r
+ args->label,\r
+ WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | WS_GROUP ,\r
+ 0, 0, 100, 30,\r
+ parent,\r
+ (HMENU)1,\r
+ hInstance,\r
+ NULL);\r
+ ui_win32_set_ui_font(hwnd);\r
+\r
+ W32Widget *widget = w32_widget_create(&radiobutton_widget_class, hwnd, sizeof(UiWidget));\r
+ ui_container_add(container, widget, &layout);\r
+ UiWidget *btn = (UiWidget*)widget;\r
+\r
+ UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER);\r
+ if (var) {\r
+ UiInteger *i = var->value;\r
+ // Use a CxList as binding object (i->obj) and add all radiobuttons to it\r
+ // The first radiobutton, which binds to this var, creates the CxList\r
+ CxList *group = NULL;\r
+ if (i->obj) {\r
+ group = i->obj;\r
+ } else {\r
+ group = cxArrayListCreate(obj->ctx->allocator, NULL, CX_STORE_POINTERS, 8);\r
+ i->obj = group;\r
+ }\r
+\r
+ cxListAdd(group, btn);\r
+ if (i->value == cxListSize(group)) {\r
+ // TODO: select\r
+ }\r
+ }\r
+\r
+ btn->obj = obj;\r
+ btn->var = var;\r
+ btn->callback = args->onchange;\r
+ btn->callbackdata = args->onchangedata;\r
+\r
+ return widget;\r
+}\r
+\r
+int ui_radiobutton_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\r
+ if (uMsg != WM_COMMAND) {\r
+ return 0;\r
+ }\r
+ UiWidget *w = (UiWidget*)widget;\r
+\r
+ int checked = SendMessage(w->widget.hwnd, BM_GETCHECK, 0, 0);\r
+ if (!checked) {\r
+ return 0; // ignore uncheck events\r
+ }\r
+\r
+ int b = 0;\r
+ if (w->var) {\r
+ UiInteger *i = w->var->value;\r
+ CxList *group = i->obj;\r
+ // Find selected index and uncheck all radiobuttons in this group\r
+ // that are not this event widget\r
+ CxIterator iter = cxListIterator(group);\r
+ cx_foreach(UiWidget *, radiobutton, iter) {\r
+ if (radiobutton == w) {\r
+ i->value = iter.index+1;\r
+ b = i->value;\r
+ } else {\r
+ SendMessage(radiobutton->widget.hwnd, BM_SETCHECK, BST_UNCHECKED, 0);\r
+ }\r
+ }\r
+ }\r
+\r
+ UiEvent e;\r
+ e.obj = w->obj;\r
+ e.document = e.obj->ctx->document;\r
+ e.window = e.obj->window;\r
+ e.eventdata = NULL;\r
+ e.eventdatatype = 0;\r
+ e.intval = b;\r
+ e.set = ui_get_setop();\r
+\r
+ if (w->callback) {\r
+ w->callback(&e, w->callbackdata);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int64_t ui_radiobutton_get(UiInteger *i) {\r
+ return i->value;\r
+}\r
+\r
+void ui_radiobutton_set(UiInteger *i, int64_t v) {\r
+ CxList *group = i->obj;\r
+ CxIterator iter = cxListIterator(group);\r
+ cx_foreach(UiWidget *, radiobutton, iter) {\r
+ SendMessage(radiobutton->widget.hwnd, BM_SETCHECK, iter.index+1 == v ? BST_CHECKED : BST_UNCHECKED, 0);\r
+ }\r
+ i->value = v;\r
}\r
\r
W32Size ui_button_get_preferred_size(W32Widget *widget);\r
\r
-void ui_button_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+int ui_button_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+\r
+int64_t ui_togglebutton_get(UiInteger *i);\r
+void ui_togglebutton_set(UiInteger *i, int64_t v);\r
+int ui_togglebutton_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+\r
+int64_t ui_radiobutton_get(UiInteger *i);\r
+void ui_radiobutton_set(UiInteger *i, int64_t v);\r
+int ui_radiobutton_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
\r
#endif //BUTTON_H\r
\r
\r
static W32WidgetClass grid_layout_widget_class = {\r
- .eventproc = NULL,\r
+ .eventproc = ui_grid_widget_event,\r
.enable = NULL,\r
.show = w32_widget_default_show,\r
.get_preferred_size = ui_grid_layout_get_preferred_size,\r
ctn->container.newline = FALSE;\r
}\r
\r
+int ui_grid_widget_event(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {\r
+ if (uMsg == WM_ERASEBKGND) {\r
+ HDC hdc = (HDC)wParam;\r
+ UiGridWidget *grid = (UiGridWidget*)widget;\r
+ RECT rc;\r
+ GetClientRect(hwnd, &rc);\r
+ FillRect(hdc, &rc, grid->brush);\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+\r
W32Size ui_grid_layout_get_preferred_size(W32Widget *widget) {\r
UiGridLayout *grid = widget->layoutmanager;\r
W32Size size;\r
TEXT("STATIC"),\r
NULL,\r
WS_CHILD | WS_VISIBLE,\r
- 0, 0, 100, 100,\r
+ 0, 0, 300, 300,\r
parent,\r
NULL,\r
hInstance,\r
NULL);\r
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)ui_default_eventproc);\r
\r
- W32Widget *widget = w32_widget_new(&grid_layout_widget_class, hwnd);\r
- ui_container_add(container, widget, &layout);\r
+ UiGridWidget *widget = w32_widget_create(&grid_layout_widget_class, hwnd, sizeof(UiGridWidget));\r
+ ui_container_add(container, (W32Widget*)widget, &layout);\r
\r
UiContainerX *gridContainer = ui_grid_container_create(obj, hwnd, args->columnspacing, args->rowspacing, INSETS_ZERO);\r
uic_object_push_container(obj, gridContainer);\r
\r
UiGridLayoutContainer *grid = (UiGridLayoutContainer*)gridContainer;\r
- widget->layout = (W32LayoutFunc)ui_grid_layout;\r
- widget->layoutmanager = grid->layout;\r
+ widget->widget.layout = (W32LayoutFunc)ui_grid_layout;\r
+ widget->widget.layoutmanager = grid->layout;\r
+ widget->brush = GetSysColorBrush(COLOR_BTNFACE);\r
grid->layout->preferred_width = 200;\r
grid->layout->preferred_height = 200;\r
\r
- return widget;\r
+ return (W32Widget*)widget;\r
}\r
\r
UiContainerX* ui_grid_container_create(UiObject *obj, HWND hwnd, short columnspacing, short rowspacing, GridEdgeInsets padding) {\r
typedef struct UiContainerPrivate UiContainerPrivate;\r
typedef struct UiGridLayoutContainer UiGridLayoutContainer;\r
typedef struct UiBoxContainer UiBoxContainer;\r
+typedef struct UiGridWidget UiGridWidget;\r
\r
enum UiBoxOrientation {\r
UI_BOX_VERTICAL = 0,\r
UiBool def_vfill;\r
};\r
\r
+struct UiGridWidget {\r
+ W32Widget widget;\r
+ HBRUSH brush;\r
+};\r
+\r
UiContainerPrivate* ui_obj_container(UiObject *obj);\r
HWND ui_container_get_parent(UiContainerPrivate *ctn);\r
void ui_container_add(UiContainerPrivate *ctn, W32Widget *widget, UiLayout *layout);\r
\r
+int ui_grid_widget_event(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
W32Size ui_grid_layout_get_preferred_size(W32Widget *widget);\r
\r
UiContainerX* ui_box_container_create(UiObject *obj, HWND hwnd, UiBoxOrientation orientation, short spacing, GridEdgeInsets padding);\r
\r
child_x = col->pos + elm->layout.margin.left;\r
child_y = row->pos + elm->layout.margin.top;\r
- SetWindowPos(elm->widget->hwnd, NULL, child_x, child_y, child_width, child_height, SWP_NOZORDER);\r
+ SetWindowPos(elm->widget->hwnd, NULL, child_x, child_y, child_width, child_height, SWP_NOZORDER | SWP_NOACTIVATE);\r
+ InvalidateRect(elm->widget->hwnd, NULL, TRUE);\r
+ //UpdateWindow(elm->widget->hwnd);\r
if (elm->widget->layout) {\r
elm->widget->layout(elm->widget->layoutmanager, child_width, child_height);\r
}\r
WIN32OBJ += container.obj
WIN32OBJ += button.obj
WIN32OBJ += grid.obj
+WIN32OBJ += text.obj
+WIN32OBJ += list.obj
TOOLKITOBJS += $(WIN32OBJ:%=$(WIN32_OBJPRE)%)
TOOLKITSOURCE += $(WIN32OBJ:%.obj=win32/%.c)
uic_toolbar_init();
uic_load_app_properties();
- ui_window_init();
-
- INITCOMMONCONTROLSEX icex = { sizeof(icex), ICC_WIN95_CLASSES };
+ INITCOMMONCONTROLSEX icex = {
+ sizeof(icex),
+ ICC_WIN95_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES | ICC_BAR_CLASSES | ICC_TAB_CLASSES | ICC_STANDARD_CLASSES | ICC_USEREX_CLASSES
+ };
InitCommonControlsEx(&icex);
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
NONCLIENTMETRICS ncm = { sizeof(ncm) };
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE);
ui_font = CreateFontIndirect(&ncm.lfMessageFont);
+
+ ui_window_init();
}
HFONT ui_win32_get_font(void) {
void ui_show(UiObject *obj) {
ui_set_visible(obj->widget, TRUE);
+}
+
+LRESULT CALLBACK ui_default_eventproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ W32Widget *widget = (W32Widget*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (widget && widget->wclass->eventproc) {
+ if (widget->wclass->eventproc(widget, hwnd, uMsg, wParam, lParam)) {
+ return 1;
+ }
+ }
+
+ switch(uMsg) {
+ case WM_DESTROY: {
+ PostQuitMessage(0);
+ break;
+ }
+ case WM_COMMAND: {
+ HWND hwndCtrl = (HWND)lParam;
+ W32Widget *cmdWidget = (W32Widget*)GetWindowLongPtr(hwndCtrl, GWLP_USERDATA);
+ if (cmdWidget && cmdWidget->wclass->eventproc) {
+ cmdWidget->wclass->eventproc(cmdWidget, hwnd, uMsg, wParam, lParam);
+ }
+ break;
+ }
+ case WM_NOTIFY: {
+ LPNMHDR hdr = (LPNMHDR)lParam;
+ HWND hwndCtrl = hdr->hwndFrom;
+ W32Widget *cmdWidget = (W32Widget*)GetWindowLongPtr(hwndCtrl, GWLP_USERDATA);
+ if (cmdWidget && cmdWidget->wclass->eventproc) {
+ cmdWidget->wclass->eventproc(cmdWidget, hwnd, uMsg, wParam, lParam);
+ }
+ break;
+ }
+ case WM_SIZE: {
+ int width = LOWORD(lParam);
+ int height = HIWORD(lParam);
+ if (widget->layout) {
+ widget->layout(widget->layoutmanager, width, height);
+ }
+ break;
+ }
+ default: break;//return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);;
}
\ No newline at end of file
int64_t intvalue;
} UiWidget;
+LRESULT CALLBACK ui_default_eventproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
HFONT ui_win32_get_font(void);
void ui_win32_set_ui_font(HWND control);
static const char *mainWindowClass = "UiMainWindow";
-LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
- W32Widget *widget = (W32Widget*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (widget && widget->wclass->eventproc) {
- widget->wclass->eventproc(widget, hwnd, uMsg, wParam, lParam);
- }
- switch(uMsg) {
- case WM_DESTROY: {
- PostQuitMessage(0);
- break;
- }
- case WM_COMMAND: {
- HWND hwndCtrl = (HWND)lParam;
- W32Widget *cmdWidget = (W32Widget*)GetWindowLongPtr(hwndCtrl, GWLP_USERDATA);
- if (cmdWidget && cmdWidget->wclass->eventproc) {
- cmdWidget->wclass->eventproc(cmdWidget, hwnd, uMsg, wParam, lParam);
- }
- }
- case WM_SIZE: {
- int width = LOWORD(lParam);
- int height = HIWORD(lParam);
- if (widget->layout) {
- widget->layout(widget->layoutmanager, width, height);
- }
- break;
- }
- default: return DefWindowProc(hwnd, uMsg, wParam, lParam);
- }
- return 0;
-}
void ui_window_init(void) {
hInstance = GetModuleHandle(NULL);
WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
- wc.lpfnWndProc = WindowProc;
+ wc.lpfnWndProc = ui_default_eventproc;
wc.hInstance = hInstance;
wc.lpszClassName = mainWindowClass;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
}
-void ui_window_widget_event(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+int ui_window_widget_event(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
//UiWindow *window = (UiWindow*)widget;
+ return 0;
}
void ui_window_widget_show(W32Widget *w, BOOLEAN show) {
void ui_window_init(void);
-void ui_window_widget_event(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+int ui_window_widget_event(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void ui_window_widget_show(W32Widget *w, BOOLEAN show);
#ifdef __cplusplus