]> uap-core.de Git - note.git/commitdiff
update libidav
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 30 Nov 2025 17:20:13 +0000 (18:20 +0100)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 30 Nov 2025 17:20:13 +0000 (18:20 +0100)
71 files changed:
libidav/crypto.c
libidav/crypto.h
libidav/davqlexec.c
libidav/davqlparser.c
libidav/methods.c
libidav/pwdstore.c
libidav/resource.c
libidav/utils.c
libidav/webdav.c
libidav/xml.c
ui/cocoa/MainWindow.h
ui/cocoa/MainWindow.m
ui/cocoa/Toolbar.h
ui/cocoa/Toolbar.m
ui/cocoa/button.m
ui/cocoa/image.m
ui/common/args.h
ui/common/context.c
ui/common/context.h
ui/common/menu.c
ui/common/menu.h
ui/common/object.c
ui/common/object.h
ui/common/objs.mk
ui/common/types.c
ui/common/types.h
ui/common/wrapper.c
ui/common/wrapper.h
ui/gtk/container.c
ui/gtk/list.c
ui/gtk/list.h
ui/gtk/menu.c
ui/gtk/text.c
ui/gtk/toolkit.c
ui/gtk/window.c
ui/motif/Grid.c
ui/motif/Grid.h
ui/motif/button.c
ui/motif/container.c
ui/motif/container.h
ui/motif/graphics.c
ui/motif/graphics.h
ui/motif/label.c
ui/motif/label.h
ui/motif/list.c
ui/motif/list.h
ui/motif/menu.c
ui/motif/menu.h
ui/motif/objs.mk
ui/motif/text.c
ui/motif/text.h
ui/motif/toolkit.c
ui/motif/toolkit.h
ui/motif/window.c
ui/motif/window.h
ui/ui/container.h
ui/ui/toolkit.h
ui/ui/tree.h
ui/ui/webview.h
ui/ui/win32.h
ui/ui/window.h
ui/win32/button.c
ui/win32/button.h
ui/win32/container.c
ui/win32/container.h
ui/win32/grid.c
ui/win32/objs.mk
ui/win32/toolkit.c
ui/win32/toolkit.h
ui/win32/window.c
ui/win32/window.h

index 240406f48d67c3aace6afef8b29b5cb89688f271..fe3651a7fed9e1c38b876905b987ea1e4d0c75d9 100644 (file)
@@ -381,12 +381,12 @@ void dav_sha256_init(DAV_SHA_CTX *ctx) {
     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
@@ -848,13 +848,16 @@ DAV_SHA_CTX* dav_sha256_create(void) {
     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) {
@@ -1422,7 +1425,7 @@ char* dav_create_hash(const char *data, size_t len) {
     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);
 }
@@ -1448,7 +1451,6 @@ void dav_sha256_final(DAV_SHA_CTX *ctx, unsigned char *buf) {
     
     // 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) {
@@ -1514,7 +1516,10 @@ DavKey* dav_pw2key(const char *password, const unsigned char *salt, int saltlen,
 }
 #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);
index 3bc5937c3bbe15683b8bb2cc2f1b478153a30194..a56512abea26b0d52170eade9c9fe12174cd1874 100644 (file)
@@ -159,6 +159,7 @@ void dav_sha256_init(DAV_SHA_CTX *ctx);
 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);
 
index 83cf7202eb55265af5ff1bea4cdd3f79a6a4badb..afe62d127711f0e37281d55c7e720eacea43a147 100644 (file)
@@ -31,7 +31,6 @@
 #include <string.h>
 #include <inttypes.h>
 
-#include <cx/utils.h>
 #include <cx/map.h>
 #include <cx/hash_map.h>
 #include <cx/printf.h>
index 22fa594d98dc246823b7f6b2f4c9b514383b7831..eb2dd464bc1ccc939bc0b0421870958061ccb24f 100644 (file)
@@ -27,7 +27,6 @@
  */
 
 #include "davqlparser.h"
-#include <cx/utils.h>
 #include <cx/linked_list.h>
 #include <cx/printf.h>
 #include <string.h>
index cbe06855c51498aa7d17c623126eba9168cc1667..90e7597edd7f1b9f89db1553c5514fd07135d778 100644 (file)
@@ -36,7 +36,6 @@
 #include "session.h"
 #include "xml.h"
 
-#include <cx/utils.h>
 #include <cx/printf.h>
 #include <cx/hash_map.h>
 
@@ -481,10 +480,6 @@ int hrefeq(DavSession *sn, const char *href1, const char *href2) {
 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);
index ba97c09928d5cd92d03cce06efe74da18502619b..6a134d6007c55aedd89ee92a5483115a76257235 100644 (file)
@@ -34,7 +34,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <cx/utils.h>
+#include <cx/streams.h> 
+
 #include <cx/hash_map.h>
 
 #ifdef _WIN32
@@ -263,7 +264,7 @@ static int read_pwdentry(PwdStore *p, CxBuffer *in) {
 }
 
 static void remove_list_entries(PwdStore *s, const char *id) {
-    CxIterator i = cxListMutIterator(s->locations);
+    CxIterator i = cxListIterator(s->locations);
     cx_foreach(PwdIndexEntry*, ie, i) {
         if(!strcmp(ie->id, id)) {
             cxIteratorFlagRemoval(i);
@@ -271,7 +272,7 @@ static void remove_list_entries(PwdStore *s, const char *id) {
             break;
         }
     }
-    i = cxListMutIterator(s->noloc);
+    i = cxListIterator(s->noloc);
     cx_foreach(PwdIndexEntry*, ie, i) {
         if(!strcmp(ie->id, id)) {
             cxIteratorFlagRemoval(i);
index 19ddffa749005884b93eb485cfc7de89a172a1c0..b82473b3de8be26ecdb2ca5557f677b0de5a41e5 100644 (file)
@@ -37,7 +37,6 @@
 #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>
@@ -835,7 +834,7 @@ static int dav_seek_h(void *stream, long offset, int whence) {
     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;
@@ -938,7 +937,7 @@ int dav_store(DavResource *res) {
                     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);
@@ -1599,7 +1598,7 @@ CxMap* parse_crypto_prop_str(DavSession *sn, DavKey *key, const char *content) {
             property->value = n->children ? dav_convert_xml(sn, n->children) : NULL;
             
             cxmutstr propkey = dav_property_key(property->ns->name, property->name);
-            cxMapPut(map, cx_hash_key_cxstr(propkey), property);
+            cxMapPut(map, propkey, property);
             cx_strfree(&propkey);
         }
         n = n->next;
index c6f1eb1134e55ce3ba03030c7acafb556bd8ad27..767f52aceed7a5d20e602a325d3160a46a02c4c2 100644 (file)
@@ -34,7 +34,6 @@
 #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>
index 262e15c532555b08b4dfb07dfb5c3920ea8aedfa..ea5aac1f3ddc1e52671d16dd8a1c216625c96f9a 100644 (file)
@@ -36,7 +36,6 @@
 #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>
@@ -353,8 +352,8 @@ int dav_context_remove_session(DavContext *context, DavSession *sn) {
     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;
index 32221ad311be16213dbc4c78516d8f0a9a2a2743..cfea172ca9f93e4a371061f56b2b35cfaee6de18 100644 (file)
@@ -30,7 +30,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <cx/utils.h>
 #include <cx/printf.h>
 
 #include "xml.h"
index 8cf15e78d1a6f8f901f727f84762363fa6e4c13f..7c8cbf63d9688d0925b2c2a55105330f5f1758ac 100644 (file)
@@ -31,6 +31,8 @@
 
 @interface MainWindow : NSWindow<UiToplevelObject>
 
+@property UiObject *obj;
+@property (strong) NSSplitView *splitview;
 @property (strong) NSView *sidebar;
 @property (strong) NSView *leftPanel;
 @property (strong) NSView *rightPanel;
index 4793365561e3fb53f9d6885965296974e3f17510..c62079f03b64a79264976d96e896f97f89f4a0a3 100644 (file)
             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;
     
@@ -72,6 +68,7 @@
         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;
 }
 
index 4e50e7cf0d3912f5eaf939cdd50dbdb3cef97492..7ec7bbd5d4d11fcc6287a0f6bda5e36f26140c44 100644 (file)
@@ -28,6 +28,7 @@
 
 #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
 
index 04941cbbf56f53095b3253e2bdb33d666d47b671..8ab2ad83afa97042c7dfdd6ee0c1c067aaf007ca 100644 (file)
@@ -45,13 +45,21 @@ void ui_toolbar_init(void) {
 
 @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) {
@@ -61,18 +69,59 @@ void ui_toolbar_init(void) {
     [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;
@@ -94,6 +143,18 @@ void ui_toolbar_init(void) {
     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;
     }
     
index 4a7f25995f73afd42214f116b452feaba458e828..faa852d9e1d72eb45ee5605fc1bf94d5aed5aaec 100644 (file)
@@ -29,6 +29,7 @@
 #import "button.h"
 #import "EventData.h"
 #import "Container.h"
+#import "image.h"
 #import <objc/runtime.h>
 
 #import <cx/buffer.h>
@@ -41,6 +42,9 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) {
         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];
@@ -72,6 +76,9 @@ UIWIDGET togglebutton_create(UiObject* obj, UiToggleArgs *args, enum NSButtonTyp
         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) {
index e00c39ad77a041db82051c42b568246774d214a3..7adf301892dd2313f09eb445cdf49d11534dfdb8 100644 (file)
 
 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)
     };
 }
 
index e5331939787307de0ffbcebd317c7c88b1dcd6e2..ab6647178e475549a9caa5c1038386e641d985f6 100644 (file)
@@ -137,7 +137,7 @@ UIEXPORT void ui_container_args_set_margin(UiContainerArgs *args, int value);
 UIEXPORT void ui_container_args_set_margin_left(UiContainerArgs *args, int value);
 UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
 UIEXPORT void ui_container_args_set_margin_top(UiContainerArgs *args, int value);
-UIEXPORT void ui_container_args_set_margin_right(UiContainerArgs *args, int value);
+UIEXPORT void ui_container_args_set_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);
index 6c0cbcc1ab6fc3cd3ba500909387a20c8e209398..40c1544d4276c8fffbc5a8368a6552a66f0eb3c9 100644 (file)
@@ -114,7 +114,7 @@ void uic_context_attach_document(UiContext *ctx, void *document) {
             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);
             }
         }
@@ -124,16 +124,19 @@ void uic_context_attach_document(UiContext *ctx, void *document) {
 }
 
 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) {
@@ -143,6 +146,8 @@ static void uic_context_unbind_vars(UiContext *ctx) {
             uic_context_unbind_vars(subctx);
         }
     }
+    
+    ui_onchange_events_enable(TRUE);
 }
 
 void uic_context_detach_document(UiContext *ctx, void *document) {
@@ -213,8 +218,9 @@ UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) {
     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);
     
@@ -266,6 +272,40 @@ void* uic_create_value(UiContext *ctx, UiVarType type) {
     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) {
@@ -278,7 +318,7 @@ UiVar* uic_widget_var(UiContext *toplevel, UiContext *current, void *value, cons
 }
 
 
-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");
@@ -301,32 +341,36 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
         }
     }
     
-    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 : "";
@@ -335,23 +379,23 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
             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);
@@ -360,8 +404,8 @@ void uic_copy_binding(UiVar *from, UiVar *to, UiBool copytodoc) {
             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);
@@ -398,58 +442,47 @@ void uic_unbind_var(UiVar *var) {
     }
 }
 
+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) {
@@ -549,7 +582,7 @@ void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable,
     cxListFree(groups);
 }
 
-void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, 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;
     }
@@ -561,7 +594,7 @@ void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable
     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);
 }
 
@@ -622,7 +655,7 @@ void* ui_realloc(UiContext *ctx, void *ptr, size_t size) {
     return ctx ? cxRealloc(ctx->allocator, ptr, size) : NULL;
 }
 
-UIEXPORT char* ui_strdup(UiContext *ctx, const char *str) {
+char* ui_strdup(UiContext *ctx, const char *str) {
     if(!ctx) {
         return NULL;
     }
@@ -630,3 +663,11 @@ UIEXPORT char* ui_strdup(UiContext *ctx, const char *str) {
     cxmutstr d = cx_strdup_a(ctx->allocator, s);
     return d.ptr;
 }
+
+void  ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr) {
+    cxMempoolRegister(ctx->mp, data, (cx_destructor_func)destr);
+}
+
+void  ui_set_destructor(void *mem, ui_destructor_func destr) {
+    cxMempoolSetDestructor(mem, (cx_destructor_func)destr);
+}
index f5170902d2a5a2c657936a9af0cc047fb929f76b..15e7700386ceb573cf2935a65f7f4b33374a9f3d 100644 (file)
@@ -97,6 +97,7 @@ struct UiVar {
     UiVarType type;
     UiVar     *from;
     UiContext *from_ctx;
+    UiBool    bound;
 };
 
 struct UiGroupWidget {
@@ -130,17 +131,18 @@ UiVar* uic_get_var(UiContext *ctx, const char *name);
 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);
index cdf3a8ca421e821fac558023eef84f43f12d457e..b0cfc46bbe59052c37abde53c0616815aea4a55d 100644 (file)
@@ -41,6 +41,22 @@ static UiMenuBuilder global_builder;
 
 static int menu_item_counter = 0;
 
+static void *tmp_eventdata;
+static int tmp_eventdata_type;
+
+void uic_set_tmp_eventdata(void *eventdata, int type) {
+    tmp_eventdata = eventdata;
+    tmp_eventdata_type = type;
+}
+
+void* uic_get_tmp_eventdata(void) {
+    return tmp_eventdata;
+}
+
+int uic_get_tmp_eventdata_type(void) {
+    return tmp_eventdata_type;
+}
+
 void uic_menu_init(void) {
     global_builder.current = cxLinkedListCreate(cxDefaultAllocator, NULL, CX_STORE_POINTERS);
     current_builder = &global_builder;
index e9dce38f518b0d0aa5ce9c705adece897da085b0..f44f6b4f9504333acdae7bc1fa6debe34e88cca6 100644 (file)
@@ -131,6 +131,10 @@ void uic_add_menu_to_stack(UiMenu* menu);
 
 int* uic_copy_groups(const int* groups, size_t *ngroups);
 
+void uic_set_tmp_eventdata(void *eventdata, int type);
+void* uic_get_tmp_eventdata(void);
+int uic_get_tmp_eventdata_type(void);
+
 #ifdef __cplusplus
 }
 #endif
index 4c41e28ea2d2630af32cc74bc5a267bc8c78e8e0..9b0a8b7b022a1481bf05798ab9c72c2cc0b96c6b 100644 (file)
@@ -32,6 +32,7 @@
 #include "context.h"
 
 #include <cx/linked_list.h>
+#include <cx/hash_map.h>
 
 #include "../ui/container.h"
 
@@ -108,7 +109,7 @@ void uic_object_destroy(UiObject *obj) {
 UiObject* uic_object_new_toplevel(void) {
     fflush(stdout);
     CxMempool *mp = cxMempoolCreateSimple(256);
-    UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
+    UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObjectPrivate));
     fflush(stdout);
     obj->ctx = uic_context(obj, mp);
     obj->ctx->parent = ui_global_context();
@@ -119,7 +120,7 @@ UiObject* uic_object_new_toplevel(void) {
 }
 
 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);
@@ -144,4 +145,48 @@ void uic_object_pop_container(UiObject *toplevel) {
     } else {
         toplevel->container_begin = NULL;
     }
+    
+    // TODO: free container?
+}
+
+/*
+ * This might look like a weird function, but in case a container creates a
+ * sub-container, 2 container objects are added to the list, however we want
+ * only one container, otherwise ui_container_finish() would not work
+ */
+void uic_object_remove_second_last_container(UiObject *toplevel) {
+    if(toplevel->container_end && toplevel->container_end->prev) {
+        UiContainerX *end = toplevel->container_end;
+        UiContainerX *rm = toplevel->container_end->prev;
+        
+        end->prev = rm->prev;
+        if(rm->prev) {
+            rm->prev->next = end;
+        } else {
+            toplevel->container_begin = end;
+        }
+        
+        // TODO: free container?
+    } else {
+        fprintf(stderr, "Error: uic_object_remove_second_last_container expected at least 2 containers\n");
+    }
+}
+
+// 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;
 }
index a899a8346b41eaa3a032efad37b3962bbfbd88eb..43278752ef904f4cef2741721d3b639f66ff6832 100644 (file)
 #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);
 
@@ -51,6 +57,7 @@ UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget);
 
 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);
 
 
 
index 4d401b54643e134cc4fc7275f965b749da4b836b..176180c05949cc9d55cda9051404665dcada13dc 100644 (file)
@@ -42,6 +42,7 @@ COMMON_OBJ += threadpool$(OBJ_EXT)
 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)
index 3d3d94fa776f46293a37ebb37a26433fcf34aee4..53fbbec1f4ce41b28a41d7a8d2b00ecef31b3bac 100644 (file)
@@ -40,6 +40,8 @@
 
 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));
@@ -105,6 +107,11 @@ void uic_ucx_list_init(UiContext *ctx, UiList *list, void *unused) {
     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);
 }
@@ -121,9 +128,13 @@ UiList* ui_list_new2(UiContext *ctx, const char *name, ui_list_init_func listini
     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) {
@@ -313,18 +324,32 @@ UiDouble* ui_double_new(UiContext *ctx, const char *name) {
     return d;
 }
 
+static void string_destroy(UiString *s) {
+    if(s->value.free && s->value.ptr) {
+        s->value.free(s->value.ptr);
+    }
+}
+
 UiString* ui_string_new(UiContext *ctx, const char *name) {
     UiString *s = ui_malloc(ctx, sizeof(UiString));
     memset(s, 0, sizeof(UiString));
+    ui_set_destructor(s, (ui_destructor_func)string_destroy);
     if(name) {
         uic_reg_var(ctx, name, UI_VAR_STRING, s);
     }
     return s;
 }
 
+static void text_destroy(UiText *t) {
+    if(t->destroy) {
+        t->destroy(t);
+    }
+}
+
 UiText* ui_text_new(UiContext *ctx, const char *name) {
     UiText *t = ui_malloc(ctx, sizeof(UiText));
     memset(t, 0, sizeof(UiText));
+    ui_set_destructor(t, (ui_destructor_func)text_destroy);
     if(name) {
         uic_reg_var(ctx, name, UI_VAR_TEXT, t);
     }
@@ -340,9 +365,16 @@ UiRange* ui_range_new(UiContext *ctx, const char *name) {
     return r;
 }
 
-UIEXPORT UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
+static void generic_destroy(UiGeneric *g) {
+    if(g->destroy) {
+        g->destroy(g);
+    }
+}
+
+UiGeneric* ui_generic_new(UiContext *ctx, const char *name) {
     UiGeneric *g = ui_malloc(ctx, sizeof(UiGeneric));
     memset(g, 0, sizeof(UiGeneric));
+    ui_set_destructor(g, (ui_destructor_func)generic_destroy);
     if(name) {
         uic_reg_var(ctx, name, UI_VAR_GENERIC, g);
     }
@@ -766,6 +798,7 @@ void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObser
 }
 
 static int ui_set_op = 0;
+static int ui_onchange_events_enabled = TRUE;
 
 void ui_setop_enable(int set) {
     ui_set_op = set;
@@ -775,6 +808,14 @@ int ui_get_setop(void) {
     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) {
@@ -782,6 +823,11 @@ 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;
 }
index 46d6c2e2f11a35f7890f9ffb13bf8159924758c6..2f4a5249ea8bd3e53de2e1f5608c2ba2e4054e35 100644 (file)
@@ -36,6 +36,7 @@ extern "C" {
 #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);
index 50ecf407f9e15928741a8e9d857de6cd26f768f8..575dd2989f65b13ddec22503fd89ad0c612f3947 100644 (file)
@@ -125,6 +125,11 @@ void ui_srclist_remove(UiList *list, int index) {
     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);
index 88fd8c813b538aabd1100b85c8fa0d7103ae748c..6ce7c9e236cb55ba8e1f7a377c83f9fbe9d3a9ee 100644 (file)
@@ -56,6 +56,7 @@ UIEXPORT UiList* ui_srclist_new(UiContext *ctx, const char *name);
 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);
index 9ca07f959e0883c2adb962ed6b2ea44b64cecc91..16f7c216a002cc4453089e44f1ff85b673ab493a 100644 (file)
@@ -1140,6 +1140,7 @@ UIWIDGET ui_vsplitpane_create(UiObject *obj, UiSplitPaneArgs *args) {
 
 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;
index e4612bfbfb3ad3ab705657a262ae352295a161e9..abb576ce6fc70667c55b0622ce3f6a570e14101e 100644 (file)
@@ -2160,6 +2160,8 @@ static void add_sublist(UiListBox *uilistbox, CxList *sublists, UiSubList *subli
         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;
     }
 }
 
@@ -2223,6 +2225,8 @@ UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
             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);
         }
@@ -2294,6 +2298,32 @@ void ui_listbox_dynamic_update(UiList *list, int x) {
     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;
@@ -2318,19 +2348,19 @@ void ui_listbox_update(UiListBox *listbox, int from, int to) {
 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();
@@ -2340,13 +2370,15 @@ static void listbox_button_clicked(GtkWidget *button, UiEventDataExt *data) {
     }
     
     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")) {
@@ -2354,6 +2386,14 @@ static void button_popover_closed(GtkPopover *popover, GtkWidget *button) {
         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) {
@@ -2433,7 +2473,11 @@ static void listbox_fill_row(UiListBox *listbox, GtkWidget *row, UiListBoxSubLis
         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);
         }
     }
@@ -2645,6 +2689,39 @@ void ui_listbox_list_update(UiList *list, int i) {
     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) {
index 06f7fac6d7db4fe9e11640002afb53c3f4fae5b5..635ac58f258635bc0d533d8dab99b37755134953 100644 (file)
@@ -127,6 +127,7 @@ struct UiListBox {
     void                     *onbuttonclickdata;
     GtkListBoxRow            *first_row;
     UiBool                   header_is_item;
+    UiSubListEventData       current_eventdata;
 };
 
 
@@ -189,9 +190,14 @@ UiListSelection ui_combobox_getselection(UiList *list);
 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);
         
index c399d85726579a886daaf5731abc25264ceed6d1..74597ae6462f5ffdea62f85ce0471a1c9b2e8ee4 100644 (file)
@@ -284,6 +284,7 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) {
             event->callback = list->callback;
             event->value = i - 1;
             event->customdata = elm;
+            event->customint = UI_EVENT_DATA_LIST_ELM;
 
             g_signal_connect(
                 widget,
@@ -309,9 +310,17 @@ void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) {
     evt.obj = event->obj;
     evt.window = event->obj->window;
     evt.document = event->obj->ctx->document;
+    if(event->customdata) {
+        evt.eventdata = event->customdata;
+        evt.eventdatatype = event->customint;
+    } else {
+        evt.eventdata = uic_get_tmp_eventdata();
+        evt.eventdatatype = uic_get_tmp_eventdata_type();
+    }
     evt.eventdata = event->customdata;
     evt.intval = event->value;
-    event->callback(&evt, event->userdata);    
+    event->callback(&evt, event->userdata);   
+    uic_set_tmp_eventdata(NULL, 0);
 }
 
 void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) {
@@ -747,10 +756,16 @@ void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEvent
     evt.obj = event->obj;
     evt.window = event->obj->window;
     evt.document = event->obj->ctx->document;
-    evt.eventdata = event->customdata;
-    evt.eventdatatype = event->customint;
+    if(event->customdata) {
+        evt.eventdata = event->customdata;
+        evt.eventdatatype = event->customint;
+    } else {
+        evt.eventdata = uic_get_tmp_eventdata();
+        evt.eventdatatype = uic_get_tmp_eventdata_type();
+    }
     evt.intval = intval;
-    event->callback(&evt, event->userdata);    
+    event->callback(&evt, event->userdata);
+    uic_set_tmp_eventdata(NULL, 0);
 }
 
 void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) {
index 085964278b1b93527d7c7f92580d4e1e88187526..ccace09b1001e1f28123834a9c2da26e63b89958 100644 (file)
@@ -335,6 +335,10 @@ void ui_textarea_realize_event(GtkWidget *widget, gpointer data) {
 
 
 void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) {
+    if(!ui_onchange_events_is_enabled()) {
+        return;
+    }
+    
     UiText *value = textarea->var->value;
     
     UiEvent e;
@@ -698,14 +702,18 @@ void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield) {
 }
 
 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();
     
@@ -720,12 +728,14 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) {
 
 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);
index b22b66c2d91730240655f1391fececfd3df5b156..f5a2545d45aa422c4bb9deeb184de55693838ec9 100644 (file)
@@ -40,7 +40,6 @@
 #include "../common/toolbar.h"
 #include "../common/threadpool.h"
 
-#include <cx/utils.h>
 #include <cx/string.h>
 #include <cx/printf.h>
 
@@ -165,7 +164,7 @@ void ui_main() {
 
 #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() {
@@ -264,7 +263,7 @@ void ui_set_show_all(UIWIDGET widget, int value) {
 #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
index f90997f32e39ba9f380bf021389de9ee05fe7820..13c521e730efa8afc729a527fe8a891739f08535 100644 (file)
@@ -35,6 +35,7 @@
 #include "../common/context.h"
 #include "../common/menu.h"
 #include "../common/toolbar.h"
+#include "../common/utils.h"
 
 #include <cx/mempool.h>
 
@@ -169,16 +170,7 @@ static UiObject* create_window(const char *title, void *window_data, UiBool side
     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),
index a286f8a5408007d3ca89684884556747eea84579..da74124f14b673ffbbecb3f1366250100ee99048 100644 (file)
@@ -60,7 +60,7 @@ static XtResource resources[] =
         XmRDimension,
         sizeof (Dimension),
         XtOffsetOf( GridRec,
-                   mywidget.columnspacing),
+                   grid.columnspacing),
         XmRImmediate,
         (XtPointer) 0
     },
@@ -70,17 +70,47 @@ static XtResource resources[] =
         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
     }
@@ -305,8 +335,8 @@ void grid_class_initialize(void) {
 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) {
@@ -364,17 +394,17 @@ XtGeometryResult GridGeometryManager(Widget       widget, XtWidgetGeometry *request, X
 }
 
 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;
     }
 }
 
@@ -389,25 +419,31 @@ void grid_constraint_init(
     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);
     
@@ -428,6 +464,12 @@ void grid_place_children(Grid w) {
             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;
@@ -489,12 +531,12 @@ void grid_place_children(Grid w) {
                     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) {
@@ -505,12 +547,12 @@ void grid_place_children(Grid w) {
                     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
@@ -530,10 +572,23 @@ void grid_place_children(Grid w) {
         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;
@@ -545,9 +600,9 @@ void grid_place_children(Grid w) {
             //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);
             
@@ -558,7 +613,7 @@ void grid_place_children(Grid w) {
             //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);
         }
         
@@ -568,37 +623,41 @@ void grid_place_children(Grid w) {
     
     // 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;
     }
@@ -608,8 +667,8 @@ void grid_place_children(Grid w) {
         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) {
@@ -617,12 +676,12 @@ void grid_place_children(Grid w) {
                 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) {
@@ -630,15 +689,15 @@ void grid_place_children(Grid w) {
                 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);
         }
index f135cbdcfb4e73ed8f5c62ab427c08805afbf6e8..af75b41ed64c74c94a51acad7baa8dc5309f6246 100644 (file)
@@ -42,8 +42,11 @@ extern "C" {
 
 // 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"
@@ -75,21 +78,20 @@ typedef struct GridClassRec {
     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;
@@ -99,7 +101,7 @@ typedef struct GridRec {
     CompositePart   composite;
     ConstraintPart  constraint;
     XmManagerPart   manager;
-    GridPart    mywidget;
+    GridPart        grid;
 } GridRec;
 
 typedef struct GridContraintPart {
index d2528c4c1541c196e4f8e59de05629ef7d56db08..6393e761d0edc7c5271e16234b8c1b32b8f1587e 100644 (file)
@@ -77,7 +77,7 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) {
        XtAddCallback(
                 button,
                 XmNdestroyCallback,
-                (XtCallbackProc)ui_destroy_eventdata,
+                (XtCallbackProc)ui_destroy_data,
                 eventdata);
     }
     
@@ -224,7 +224,7 @@ void ui_bind_togglebutton(
     XtAddCallback(
             widget,
             XmNdestroyCallback,
-            (XtCallbackProc)ui_destroy_eventdata,
+            (XtCallbackProc)ui_destroy_data,
             event);
 }
 
@@ -341,7 +341,7 @@ void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const
     XtAddCallback(
             rbutton,
             XmNdestroyCallback,
-            (XtCallbackProc)ui_destroy_eventdata,
+            (XtCallbackProc)ui_destroy_data,
             event);
 }
 
@@ -411,7 +411,7 @@ UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs *args) {
     XtAddCallback(
             button,
             XmNdestroyCallback,
-            (XtCallbackProc)ui_destroy_eventdata,
+            (XtCallbackProc)ui_destroy_data,
             event);
     
     XmStringFree(label);
index 444bedbc19d6fade55fd6d3f456cffe80d4eca83..34648626b7314e14c7cdce46ce4cc5140c3f1ee2 100644 (file)
@@ -55,6 +55,18 @@ void ui_container_add(UiContainerPrivate *container, Widget widget) {
     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 ---------------------------- */
 
@@ -66,9 +78,9 @@ static UIWIDGET box_create(UiObject *obj, UiContainerArgs *args, UiBoxOrientatio
     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);
@@ -102,7 +114,7 @@ UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orie
 }
 
 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;
 }
@@ -151,7 +163,6 @@ UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
     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);
@@ -218,6 +229,7 @@ Widget ui_grid_container_prepare(UiContainerPrivate *ctn, UiLayout *layout, Arg
     }
     
     *n = a;
+    ui_container_apply_grid_margin(args, n, layout->margin_left, layout->margin_right, layout->margin_top, layout->margin_bottom);
     return ctn->widget;
 }
 
@@ -227,6 +239,103 @@ void ui_grid_container_add(UiContainerPrivate *ctn, Widget 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 -------------------------- */
 
@@ -244,9 +353,10 @@ static void ui_tabbar_resize(Widget widget, XtPointer udata, XtPointer cdata) {
     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) {
@@ -342,6 +452,7 @@ UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args) {
     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;
@@ -592,6 +703,12 @@ UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs *args) {
     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);
index 9dd73cc806e0adcbc0893f400d03d92df1ffd6cd..30262e5dee5c23298d62411a39d71f748fef4b9d 100644 (file)
@@ -129,6 +129,10 @@ typedef struct UiTabViewContainer {
 
 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);
@@ -156,6 +160,10 @@ UiContainerX* ui_grid_container(
 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
index fab993067fd2a78dd5bf08485cc1097ca8100772..2863695cbcdd9b90e665d9fbebad8647571c7a46 100644 (file)
 #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) {
+    
+}
index addec590efecd5b0ef256c6f2b9a6dbb7f96f738..82b533ebf6bb5309af2cae3ce9838cf69f5f7d24 100644 (file)
 #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
index 749c9e3eff9aebf3ad19c2fef8d66a30db1952ca..2acb2c30855d826683a7b0b45aa10acb316ebe46 100644 (file)
@@ -47,17 +47,34 @@ static UIWIDGET label_create(UiObject *obj, UiLabelArgs *args, int align) {
     
     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;
 } 
 
@@ -73,6 +90,36 @@ UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs *args) {
     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 -------------------------- */
 
index a79dd64555aacc0209996021af209265f7af348b..8d7ca0feb75c73f92b3e428781893a382c470d55 100644 (file)
@@ -46,6 +46,8 @@ typedef struct UiProgressBar {
     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);
index 0bb1cbe143bbc1063eb4122e7242a62420fe107a..b1e96eeac493e57270ff3dd0e40d3b8c1392889c 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <Xm/Xm.h>
 
 #include "container.h"
 
@@ -62,6 +63,9 @@ UIWIDGET ui_listview_create(UiObject* obj, UiListArgs *args) {
     } 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);
@@ -144,8 +148,12 @@ static void listview_save_selection(UiListView *listview, XmListCallbackStruct *
     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);
@@ -209,10 +217,18 @@ void ui_listview_update(UiList *list, int i) {
 
 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;
 }
@@ -299,8 +315,8 @@ UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs *args) {
         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);
     }
     
@@ -317,3 +333,25 @@ UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs *args) {
     
     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;
+}
index 2d88c72b884651a9bc11fb20a0b58a46a5d67c59..04756a2140239a7f86fff469ff77e55f3a7aea7d 100644 (file)
@@ -69,6 +69,9 @@ void ui_listview_update(UiList *list, int i);
 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
index c2038a84cf1a27297d694703a17df7dc72cc7717..f3e1f41d6f06cbb4546bd7e5b8889682591aec32 100644 (file)
@@ -55,10 +55,10 @@ static ui_menu_add_f createMenuItem[] = {
     /* 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);
@@ -70,6 +70,8 @@ void ui_create_menubar(UiObject *obj, Widget window) {
         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) {
@@ -93,16 +95,15 @@ void add_menu_widget(Widget parent, int i, UiMenuItemI *item, 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);
     }
@@ -145,7 +146,7 @@ void add_menuitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj)
        XtAddCallback(
                 mitem,
                 XmNdestroyCallback,
-                (XtCallbackProc)ui_destroy_eventdata,
+                (XtCallbackProc)ui_destroy_data,
                 eventdata);
     }
     
@@ -337,7 +338,7 @@ void ui_update_menuitem_list(UiActiveMenuItemList *list) {
             XtAddCallback(
                     mitem,
                     XmNdestroyCallback,
-                    (XtCallbackProc)ui_destroy_eventdata,
+                    (XtCallbackProc)ui_destroy_data,
                     eventdata);
         }
         
index efa99cefc5d20cf88b8832f6be3d16ac9b7c792b..4c40d797ff596e88f0dcdb6287a20b5deefcf9fb 100644 (file)
@@ -52,7 +52,7 @@ struct UiActiveMenuItemList {
     
 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);
index b1b51b21f4aeafedffbd205c5fe3cbb0391bce9a..8d5d0fd9284a5450ddacf6e4a0517ac5cc8a5b0a 100644 (file)
@@ -39,12 +39,15 @@ MOTIFOBJ += toolbar.o
 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)
index 5c5db1f39215680a5a693257ce23d592d5806ced..52f4f169663cca77df7e8410abb3fdad17bd8c0f 100644 (file)
@@ -32,6 +32,9 @@
 
 #include "text.h"
 #include "container.h"
+#include "pathbar.h"
+
+#include "../common/utils.h"
 
 #include <cx/string.h>
 
@@ -407,8 +410,18 @@ static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs *args, int frame
     
     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;
@@ -419,9 +432,54 @@ static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs *args, int frame
         }
     }
     
+    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);
 }
@@ -453,459 +511,6 @@ void ui_textfield_set(UiString *str, const char *value) {
 }
 
 
-
-
-
-/* -------------------- 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) {
@@ -915,47 +520,6 @@ 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;
@@ -981,7 +545,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
 
     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;
@@ -1018,7 +582,7 @@ UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs *args) {
         XtAddCallback(
                 pathbar->widget,
                 XmNdestroyCallback,
-                (XtCallbackProc)ui_destroy_eventdata,
+                (XtCallbackProc)ui_destroy_data,
                 eventdata);
     }
     
index a7e4f8572cad3f0eea41899c25aed8b266b03a7a..9f2932e3486c701b339c756491f65d0eef5765f7 100644 (file)
@@ -86,6 +86,9 @@ void ui_text_modify_callback(Widget widget, UiVar *var, XtPointer data);
 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);
 
index c2a1f2abd4506062cd604e72502c9205b73d2e17..17b4726f227b392f88d48fb51aa9da08fc9ff471 100644 (file)
@@ -84,11 +84,17 @@ static String fallback[] = {
        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();
@@ -96,7 +102,7 @@ void ui_init(const char *appname, int argc, char **argv) {
     XtToolkitInitialize();
     XtSetLanguageProc(NULL, NULL, NULL);
     app = XtCreateApplicationContext();
-    XtAppSetFallbackResources(app, fallback);
+    XtAppSetFallbackResources(app, fallback_resources);
     
     display =  XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv);
     
@@ -120,6 +126,10 @@ const char* ui_appname() {
     return application_name;
 }
 
+XtAppContext ui_motif_get_app(void) {
+    return app;
+}
+
 Display* ui_motif_get_display() {
     return display;
 }
@@ -157,7 +167,7 @@ void ui_main() {
     }
 }
 
-void ui_exit_mainloop() {
+void ui_app_quit() {
     XtAppSetExitFlag(app);
 }
 
@@ -216,6 +226,15 @@ static Boolean ui_job_finished(void *data) {
     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);
@@ -227,6 +246,15 @@ static void* ui_jobthread(void *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;
@@ -321,7 +349,7 @@ void ui_window_dark_theme(Display *dp, Window window) {
             4);
 }
 
-void ui_destroy_eventdata(Widget w, XtPointer data, XtPointer d) {
+void ui_destroy_data(Widget w, XtPointer data, XtPointer d) {
     free(data);
 }
 
index a2397e81a2d4f3fdd0f748238611870bc479dc20..069e31c89ee1141b97d9d8f0ca2c8b689f24ea82 100644 (file)
@@ -82,9 +82,9 @@ typedef struct UiJob {
 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();
@@ -92,7 +92,7 @@ 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);
index 7c3f638b3bfc459cf0fb90354a0057e24253ff74..9489f077c96d24ddb4fcbae7acdf3d8d08c2ba81 100644 (file)
 
 #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>
 
@@ -50,7 +57,7 @@ void ui_window_widget_destroy(UiObject *obj) {
     uic_object_destroy(obj);
     nwindows--;
     if(nwindows == 0) {
-        ui_exit_mainloop();
+        ui_app_quit();
     }
 }
 
@@ -74,13 +81,22 @@ static UiObject* create_window(const char *title, void *window_data, Boolean sim
     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(),
@@ -110,7 +126,7 @@ static UiObject* create_window(const char *title, void *window_data, Boolean sim
     
     // menu
     if(!simple) {
-        ui_create_menubar(obj, window);
+        appwindow->menubar = ui_create_menubar(obj, window);
     }
     
     // content frame
@@ -142,3 +158,154 @@ UiObject* ui_window(const char *title, void *window_data) {
 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);
+    }
+}
index 33bb66d2e183c13032c6b46c2053086a5ca62b4a..8c2c5eeb49eb35d16ec0e48e28a270f003ee52db 100644 (file)
 #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
index 3355850cbb0ea9b3a1679ac667abd30b5c956b37..0bc42b702a06008308746ee59d0f0e8a6c74fbf7 100644 (file)
@@ -98,6 +98,8 @@ typedef struct UiFrameArgs {
     int margin_bottom;
     int colspan;
     int rowspan;
+    int width;
+    int height;
     const char *name;
     const char *style_class;
 
index 6c2433014df2d25ae014a25007a645e4f0475dec..7b8309a3c0e3739752d489efff8589de3b84328b 100644 (file)
@@ -256,6 +256,9 @@ typedef void(*ui_freefunc)(void*);
 
 typedef void(*ui_enablefunc)(void*, int);
 
+typedef void (*ui_destructor_func)(void *memory);
+
+
 struct UiObject {
     /*
      * native widget
@@ -405,6 +408,7 @@ struct UiGeneric {
     void* (*get)(UiGeneric*);
     const char* (*get_type)(UiGeneric*);
     int (*set)(UiGeneric*, void *, const char *type);
+    void (*destroy)(UiGeneric*);
     void *obj;
     
     void *value;
@@ -413,6 +417,7 @@ struct UiGeneric {
 };
     
 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
@@ -537,6 +542,7 @@ UIEXPORT int ui_app_save_settings(void);
 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);
 
@@ -557,8 +563,8 @@ UIEXPORT void ui_attach_document(UiContext *ctx, void *document);
 UIEXPORT void ui_detach_document(UiContext *ctx, void *document);
 
 UIEXPORT void ui_widget_set_groups(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, ...);
-UIEXPORT void ui_widget_set_groups2(UiContext *ctx, UIWIDGET widget, ui_enablefunc enable, 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);
@@ -572,6 +578,8 @@ UIEXPORT void* ui_calloc(UiContext *ctx, size_t nelem, size_t elsize);
 UIEXPORT void  ui_free(UiContext *ctx, void *ptr);
 UIEXPORT void* ui_realloc(UiContext *ctx, void *ptr, size_t size);
 UIEXPORT char* ui_strdup(UiContext *ctx, const char *str);
+UIEXPORT void  ui_reg_destructor(UiContext *ctx, void *data, ui_destructor_func destr);
+UIEXPORT void  ui_set_destructor(void *mem, ui_destructor_func destr);
 
 // types
 
@@ -629,7 +637,7 @@ UIEXPORT void ui_notify_evt(UiObserver *observer, UiEvent *event);
 
 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);
@@ -674,9 +682,12 @@ UIEXPORT void ui_condvar_destroy(UiCondVar *var);
 
 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));
@@ -684,6 +695,9 @@ UIEXPORT void ui_list_class_set_count(UiList *list, int(*count)(UiList *list));
 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
index 33a903c06196df279a8d87a2c6005bc1700c06f0..a71092b1df7a262079ca2191cb691c3764235434 100644 (file)
@@ -132,9 +132,9 @@ struct UiListArgs {
 
     const char *name;
     const char *style_class;
-    UiListlist;
+    UiList *list;
     const char* varname;
-    UiModelmodel;
+    UiModel *model;
     char **static_elements;
     size_t static_nelm;
     ui_getvaluefunc getvalue;
@@ -143,15 +143,15 @@ struct UiListArgs {
     ui_getstylefunc getstyle;
     void *getstyledata;
     ui_callback onactivate;
-    voidonactivatedata;
+    void *onactivatedata;
     ui_callback onselection;
-    voidonselectiondata;
+    void *onselectiondata;
     ui_callback ondragstart;
-    voidondragstartdata;
+    void *ondragstartdata;
     ui_callback ondragcomplete;
-    voidondragcompletedata;
+    void *ondragcompletedata;
     ui_callback ondrop;
-    voidondropdata;
+    void *ondropdata;
     UiBool multiselection;
     UiMenuBuilder *contextmenu;
     ui_list_savefunc onsave;
@@ -300,10 +300,10 @@ UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi);
 #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(UiObjectobj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_table_create(UiObjectobj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_combobox_create(UiObjectobj, UiListArgs *args);
-UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObjectobj, 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);
index 90d5268b719198e23348c1dcba1f57756b1122ca..9636165f22bda227e84245327b98bcd0512279a6 100644 (file)
 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;
@@ -63,11 +71,11 @@ typedef struct UiWebviewArgs {
 
 #define ui_webview(obj, ...) ui_webview_create(obj, &(UiWebviewArgs){ __VA_ARGS__ } )
 
-UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args);
+UIEXPORT UIWIDGET ui_webview_create(UiObject *obj, UiWebviewArgs *args);
 
-void ui_webview_load_url(UiGeneric *g, const char *url);
+UIEXPORT void ui_webview_load_url(UiGeneric *g, const char *url);
 
-void ui_webview_load_content(
+UIEXPORT void ui_webview_load_content(
         UiGeneric *g,
         const char *uri,
         const char *content,
@@ -75,16 +83,20 @@ void ui_webview_load_content(
         const char *mimetype,
         const char *encoding);
 
+/*
+ * Frees a UiWebViewData object returned by a webviews UiGeneric->get function
+ */
+UIEXPORT void ui_webview_data_free(UiWebViewData *data);
 
-void ui_webview_reload(UiGeneric *g);
-UiBool ui_webview_can_go_back(UiGeneric *g);
-UiBool ui_webview_can_go_forward(UiGeneric *g);
-void ui_webview_go_back(UiGeneric *g);
-void ui_webview_go_forward(UiGeneric *g);
-const char * ui_webview_get_uri(UiGeneric *g);
-void ui_webview_enable_javascript(UiGeneric *g, UiBool enable);
-void ui_webview_set_zoom(UiGeneric *g, double zoom);
-double ui_webview_get_zoom(UiGeneric *g);
+UIEXPORT void ui_webview_reload(UiGeneric *g);
+UIEXPORT UiBool ui_webview_can_go_back(UiGeneric *g);
+UIEXPORT UiBool ui_webview_can_go_forward(UiGeneric *g);
+UIEXPORT void ui_webview_go_back(UiGeneric *g);
+UIEXPORT void ui_webview_go_forward(UiGeneric *g);
+UIEXPORT const char * ui_webview_get_uri(UiGeneric *g);
+UIEXPORT void ui_webview_enable_javascript(UiGeneric *g, UiBool enable);
+UIEXPORT void ui_webview_set_zoom(UiGeneric *g, double zoom);
+UIEXPORT double ui_webview_get_zoom(UiGeneric *g);
 
 
 #ifdef __cplusplus
index 54d054349251be52b01c64f6f1c50e7ed6e0e6db..1137265ed9e36cea73f96da930af60bddd8c7a07 100644 (file)
@@ -49,7 +49,7 @@ struct W32Size {
 };\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
index 83e85a34dd3f65ec8b2d303f222134d7a4cd3b8b..3619b3a0102aef270b6829b9c0b389ff9586120c 100644 (file)
@@ -83,6 +83,9 @@ UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs
 
 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);
index ed6520a63ba5102803729139f3bce78808b7870e..fca53bd064c71f3691d55311f8eeb75cce9f44b1 100644 (file)
@@ -32,6 +32,8 @@
 #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
@@ -42,6 +44,22 @@ static W32WidgetClass button_widget_class = {
     .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
@@ -51,10 +69,10 @@ UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs *args) {
     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
@@ -82,9 +100,13 @@ W32Size ui_button_get_preferred_size(W32Widget *widget) {
     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
@@ -97,4 +119,200 @@ void ui_button_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam,
     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
index 8770e892a3f0e77ede10b91018d43e5fefa37f09..d35a0674d89e9033aabd51a221cd8226ad92f267 100644 (file)
 \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
index 9ae6f2629da9f3cfa1ea1055266e4f42685eced4..889ad5f86dc4aba3a174a06de9e276a41ca9a4a8 100644 (file)
@@ -35,7 +35,7 @@
 \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
@@ -62,6 +62,18 @@ void ui_container_add(UiContainerPrivate *ctn, W32Widget *widget, UiLayout *layo
     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
@@ -134,25 +146,27 @@ UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
             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
index 8809ab222d3459359d0331b7a0918a51e57622d7..2d0ca9dc9d06bdccf3d19d3f77e90c959f947ce9 100644 (file)
@@ -40,6 +40,7 @@ extern "C" {
 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
@@ -88,10 +89,16 @@ struct UiGridLayoutContainer {
     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
index 023a16be07a99b428ed45b9f808a87f3f0a0d6b2..aad2d5da11ad52912141b25ec5cbc205ceadfde9 100644 (file)
@@ -293,7 +293,9 @@ void ui_grid_layout(UiGridLayout *grid, int width, int height) {
 \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
index 1241582406b24e270dcc3f5808f616353cab6484..85a6fb337774327b87c72ec3a288242e1b98cbeb 100644 (file)
@@ -37,6 +37,8 @@ WIN32OBJ += image.obj
 WIN32OBJ += container.obj
 WIN32OBJ += button.obj
 WIN32OBJ += grid.obj
+WIN32OBJ += text.obj
+WIN32OBJ += list.obj
 
 TOOLKITOBJS += $(WIN32OBJ:%=$(WIN32_OBJPRE)%)
 TOOLKITSOURCE += $(WIN32OBJ:%.obj=win32/%.c)
index 1f13f95e89e785e85ad6963e2f50958e0b17a4d1..f73cc5bbcf6dc21e0820a626bee07de62dc873e6 100644 (file)
@@ -62,9 +62,10 @@ void ui_init(const char *appname, int argc, char **argv) {
     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);
@@ -72,6 +73,8 @@ void ui_init(const char *appname, int argc, char **argv) {
     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) {
@@ -123,4 +126,47 @@ void ui_main() {
 
 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
index f3be04ce117c38bb308414de26bb24d441339696..53e2b3ea733415e134ef89765e79ec8f159bf261 100644 (file)
@@ -53,6 +53,8 @@ typedef struct UiWidget {
     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);
 
index 98d587fbee03b8513c6bee664aa1ebc5a97bc5de..6fbe7af1f0bd1a169cc0672d7b6ff5d43bb87c2a 100644 (file)
@@ -52,41 +52,12 @@ static HINSTANCE hInstance;
 
 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);
@@ -137,8 +108,9 @@ UiObject *ui_window(const char *title, void *window_data) {
 }
 
 
-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) {
index 5d4c8f7fee97f35f905aa14288807fbe283a18a3..4562b016a233d1b0c9d2a61c57d7eec34de2bbcf 100644 (file)
@@ -48,7 +48,7 @@ typedef struct UiWindow {
 
 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