From: Olaf Wintermann Date: Mon, 31 Mar 2025 19:12:02 +0000 (+0200) Subject: show list of image attachments X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=4d477523e55064faf2b55f03c214357b2090090b;p=note.git show list of image attachments --- diff --git a/application/Makefile b/application/Makefile index 0549e3e..89823cb 100644 --- a/application/Makefile +++ b/application/Makefile @@ -56,8 +56,8 @@ TEST_BIN = ../build/bin/notetest$(APP_EXT) all: $(APP_BIN) $(TEST_BIN) -$(APP_BIN): $(MAIN_OBJ) $(OBJ) $(BUILD_ROOT)/build/lib/libuitk.a - $(CC) -o $(APP_BIN) $(MAIN_OBJ) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx -lidav -ldbutils -lmd4c $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) $(DBU_LDFLAGS) +$(APP_BIN): $(MAIN_OBJ) $(OBJ) + $(LD) -o $(APP_BIN) $(MAIN_OBJ) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx -lidav -ldbutils -lmd4c $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) $(DBU_LDFLAGS) $(TEST_BIN): $(OBJ) $(TEST_OBJ) $(BUILD_ROOT)/build/lib/libuitk.a $(CC) -o $(TEST_BIN) $(TEST_OBJ) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx -lidav -ldbutils -lmd4c $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) $(DBU_LDFLAGS) diff --git a/application/attachment.c b/application/attachment.c index 3bb2f52..b51678f 100644 --- a/application/attachment.c +++ b/application/attachment.c @@ -72,6 +72,7 @@ void attachment_item(UiObject *obj, int index, void *elm, void *userdata) { Attachment *attachment = elm; if(attachment->type == NOTE_ATTACHMENT_IMAGE) { - ui_imageviewer(obj, .value = attachment->ui->img, .scrollarea = FALSE); + UIWIDGET imgviewer = ui_imageviewer(obj, .value = attachment->ui->img, .scrollarea = FALSE, .autoscale = TRUE); + ui_widget_set_size(imgviewer, 100, 80); } } diff --git a/application/window.c b/application/window.c index 85333e1..73a247a 100644 --- a/application/window.c +++ b/application/window.c @@ -89,9 +89,11 @@ void window_create() { ui_button(obj, .icon = "insert-link"); } ui_hbox_w(obj, wdata->attachments, .margin = 10, .fill = UI_OFF) { - ui_scrolledwindow(obj, .name = "note_attachments_sw") { + void *sw; + ui_scrolledwindow_w(obj, sw, .name = "note_attachments_sw") { ui_itemlist(obj, .varname = "note_attachments", .container = UI_CONTAINER_HBOX, .create_ui = attachment_item, .userdata = wdata); } + ui_widget_set_size(sw, -1, 120); } //ui_set_visible(wdata->attachments, FALSE); //ui_widget_set_groups(obj->ctx, wdata->attachments, (ui_enablefunc)ui_set_visible, APP_STATE_NOTE_HAS_ATTACHMENTS, -1); diff --git a/configure b/configure index e2b8929..32aae07 100755 --- a/configure +++ b/configure @@ -72,7 +72,7 @@ Installation directories: Options: --debug add extra compile flags for debug builds --release add extra compile flags for release builds - --toolkit=(libadwaita|gtk4|gtk3|cocoa|motif) + --toolkit=(libadwaita|gtk4|gtk3|cocoa|qt5|motif) __EOF__ } @@ -245,6 +245,9 @@ __EOF__ # check languages lang_c= lang_cpp= +if detect_cpp_compiler ; then + lang_cpp=1 +fi if detect_c_compiler ; then lang_c=1 fi @@ -677,6 +680,44 @@ dependency_error_gtk2legacy() dep_checked_gtk2legacy=1 return 0 } +dependency_error_qt5() +{ + print_check_msg "$dep_checked_qt5" "checking for qt5... " + # dependency qt5 + while true + do + if [ -z "$lang_cpp" ] ; then + break + fi + if [ -z "$PKG_CONFIG" ]; then + break + fi + if which qmake-qt5 > /dev/null ; then + : + else + break + fi + if test_pkg_config "Qt5Widgets" "" "" "" ; then + TEMP_CFLAGS="$TEMP_CFLAGS `"$PKG_CONFIG" --cflags Qt5Widgets`" + TEMP_LDFLAGS="$TEMP_LDFLAGS `"$PKG_CONFIG" --libs Qt5Widgets`" + else + break + fi + TEMP_CFLAGS="$TEMP_CFLAGS -DUI_QT5" + cat >> $TEMP_DIR/make.mk << __EOF__ +# Dependency: qt5 +QMAKE = qmake-qt5 +QT_PRO_FILE = qt5.pro +__EOF__ + print_check_msg "$dep_checked_qt5" "yes\n" + dep_checked_qt5=1 + return 1 + done + + print_check_msg "$dep_checked_qt5" "no\n" + dep_checked_qt5=1 + return 0 +} dependency_error_openssl() { print_check_msg "$dep_checked_openssl" "checking for openssl... " @@ -815,6 +856,9 @@ do break fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ +LD = \$(CC) +__EOF__ break done break @@ -830,6 +874,7 @@ do cat >> "$TEMP_DIR/make.mk" << __EOF__ OBJ_EXT = .o LIB_EXT = .a +LIB_PREFIX = lib PACKAGE_SCRIPT = package_osx.sh __EOF__ break @@ -850,6 +895,7 @@ do cat >> "$TEMP_DIR/make.mk" << __EOF__ OBJ_EXT = .o LIB_EXT = .a +LIB_PREFIX = lib PACKAGE_SCRIPT = package_unix.sh __EOF__ break @@ -959,6 +1005,21 @@ APP_PLATFORM_SRC = cocoa-text.m __EOF__ return 0 } +checkopt_toolkit_qt5() +{ + VERR=0 + if dependency_error_qt5 ; then + VERR=1 + fi + if [ $VERR -ne 0 ]; then + return 1 + fi + cat >> "$TEMP_DIR/make.mk" << __EOF__ +TOOLKIT = qt +LD = \$(CXX) +__EOF__ + return 0 +} checkopt_toolkit_motif() { VERR=0 @@ -1164,6 +1225,14 @@ else ERROR=1 DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" fi + elif [ "$OPT_TOOLKIT" = "qt5" ]; then + echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options + if checkopt_toolkit_qt5 ; then + : + else + ERROR=1 + DEPENDENCIES_FAILED="option 'toolkit' $DEPENDENCIES_FAILED" + fi elif [ "$OPT_TOOLKIT" = "motif" ]; then echo " toolkit: $OPT_TOOLKIT" >> $TEMP_DIR/options if checkopt_toolkit_motif ; then diff --git a/make/project.xml b/make/project.xml index 3b9cacc..2977368 100644 --- a/make/project.xml +++ b/make/project.xml @@ -2,6 +2,7 @@ c + LD = \$(CC) @@ -99,21 +100,15 @@ - + -DUI_COCOA -lobjc -framework Cocoa @@ -132,11 +127,13 @@ OBJ_EXT = .o LIB_EXT = .a + LIB_PREFIX = lib PACKAGE_SCRIPT = package_osx.sh OBJ_EXT = .o LIB_EXT = .a + LIB_PREFIX = lib PACKAGE_SCRIPT = package_unix.sh @@ -179,28 +176,11 @@ TOOLKIT = cocoa APP_PLATFORM_SRC = cocoa-text.m - motif TOOLKIT = motif diff --git a/ui/Makefile b/ui/Makefile index a0d1148..6905986 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -33,7 +33,7 @@ OBJ_DIR = ../build/ include common/objs.mk -UI_LIB = ../build/lib/libuitk$(LIB_EXT) +UI_LIB = ../build/lib/$(LIB_PREFIX)uitk$(LIB_EXT) include $(TOOLKIT)/objs.mk OBJ = $(TOOLKITOBJS) $(COMMONOBJS) @@ -42,6 +42,6 @@ all: $(UI_LIB) include $(TOOLKIT)/Makefile -$(COMMON_OBJPRE)%.o: common/%.c +$(COMMON_OBJPRE)uic_%$(OBJ_EXT): common/%.c $(CC) -o $@ -c -I../ucx/ $(CFLAGS) $(TK_CFLAGS) $< diff --git a/ui/cocoa/GridLayout.m b/ui/cocoa/GridLayout.m index 401fe42..c937948 100644 --- a/ui/cocoa/GridLayout.m +++ b/ui/cocoa/GridLayout.m @@ -53,7 +53,6 @@ NSSize s1 = _test.intrinsicContentSize; NSEdgeInsets e1 = _test.alignmentRectInsets; - printf("fuck\n"); } */ @@ -80,7 +79,19 @@ GridDef *row = &rows[y]; NSSize size = elm->view.intrinsicContentSize; + NSSize size2 = elm->view.fittingSize; NSEdgeInsets alignment = elm->view.alignmentRectInsets; + // TODO: remove alignment + alignment.left = 0; + alignment.right = 0; + alignment.top = 0; + alignment.bottom = 0; + if(size.width == NSViewNoIntrinsicMetric) { + size.width = size2.width; + } + if(size.height == NSViewNoIntrinsicMetric) { + size.height = size2.height; + } if(size.width != NSViewNoIntrinsicMetric) { CGFloat width = size.width + alignment.left + alignment.right; if(width > cols[elm->x].preferred_size && elm->colspan <= 1 && span_max == 1) { @@ -244,12 +255,12 @@ for(int c=elm->x;csize; + frame.size.width = col->size + alignment.left + alignment.right; } } else { - frame.size.width = elm->preferred_width; + frame.size.width = elm->preferred_width + alignment.left + alignment.right; } if(elm->vfill) { if(elm->rowspan > 1) { @@ -268,7 +279,8 @@ frame.size.height = elm->preferred_height; } frame.origin.x = col->pos - (alignment.left+alignment.right)/2; - frame.origin.y = viewFrame.size.height - row->pos - frame.size.height + ((alignment.top+alignment.right)/2); + //frame.origin.y = viewFrame.size.height - row->pos - frame.size.height + ((alignment.top+alignment.right)/2); + frame.origin.y = viewFrame.size.height - row->pos - frame.size.height; elm->view.frame = frame; } @@ -294,10 +306,17 @@ elm.margin = 0; elm.colspan = _uilayout.colspan; elm.rowspan = _uilayout.rowspan; - elm.hfill = _uilayout.hfill; - elm.vfill = _uilayout.vfill; - elm.hexpand = _uilayout.hexpand; - elm.vexpand = _uilayout.vexpand; + if(_uilayout.fill) { + elm.hfill = TRUE; + elm.vfill = TRUE; + elm.hexpand = TRUE; + elm.vexpand = TRUE; + } else { + elm.hfill = _uilayout.hfill; + elm.vfill = _uilayout.vfill; + elm.hexpand = _uilayout.hexpand; + elm.vexpand = _uilayout.vexpand; + } elm.view = view; cxListAdd(_children, &elm); diff --git a/ui/cocoa/appdelegate.m b/ui/cocoa/appdelegate.m index 38226cf..ae4d3fc 100644 --- a/ui/cocoa/appdelegate.m +++ b/ui/cocoa/appdelegate.m @@ -29,10 +29,12 @@ #import "AppDelegate.h" #import "toolkit.h" +#import "menu.h" @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + ui_menu_init(); ui_cocoa_onstartup(); } diff --git a/ui/cocoa/menu.h b/ui/cocoa/menu.h new file mode 100644 index 0000000..9836fa3 --- /dev/null +++ b/ui/cocoa/menu.h @@ -0,0 +1,44 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "../ui/menu.h" +#import "toolkit.h" + +#import "../common/menu.h" + +void ui_menu_init(void); + +typedef void(*ui_menu_add_f)(NSMenu*, int, UiMenuItemI*); + +void add_menu_widget(NSMenu *parent, int i, UiMenuItemI *item); +void add_menuitem_widget(NSMenu *parent, int i, UiMenuItemI *item); +void add_menuseparator_widget(NSMenu *parent, int i, UiMenuItemI *item); +void add_checkitem_widget(NSMenu *parent, int i, UiMenuItemI *item); +void add_radioitem_widget(NSMenu *parent, int index, UiMenuItemI *item); +void add_checkitemnv_widget(NSMenu *parent, int i, UiMenuItemI *item); +void add_menuitem_list_widget(NSMenu *parent, int i, UiMenuItemI *item); diff --git a/ui/cocoa/menu.m b/ui/cocoa/menu.m new file mode 100644 index 0000000..10dd588 --- /dev/null +++ b/ui/cocoa/menu.m @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2014 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import +#import +#import + +#import "menu.h" +#import "window.h" + +static ui_menu_add_f createMenuItem[] = { + /* UI_MENU */ add_menu_widget, + /* UI_MENU_ITEM */ add_menuitem_widget, + /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, + /* UI_MENU_RADIO_ITEM */ add_radioitem_widget, + /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_SEPARATOR */ add_menuseparator_widget +}; + +static void add_menu_items(NSMenu *parent, int i, UiMenu *menu) { + UiMenuItemI *it = menu->items_begin; + int index = 0; + while(it) { + createMenuItem[it->type](parent, index, it); + it = it->next; + index++; + } +} + +void add_menu_widget(NSMenu *parent, int i, UiMenuItemI *item) { + UiMenu *it = (UiMenu*)item; + NSString *str = [[NSString alloc] initWithUTF8String:it->label]; + NSMenu *menu = [[NSMenu alloc] initWithTitle: str]; + NSMenuItem *menuItem = [parent addItemWithTitle:str action:nil keyEquivalent:@""]; + [parent setSubmenu:menu forItem:menuItem]; + + add_menu_items(menu, i, it); +} + +void add_menuitem_widget(NSMenu *parent, int i, UiMenuItemI *item) { + UiMenuItem *it = (UiMenuItem*)item; + NSString *str = [[NSString alloc] initWithUTF8String:it->label]; + NSMenuItem *menuItem = [parent addItemWithTitle:str action:nil keyEquivalent:@""]; +} + +void add_menuseparator_widget(NSMenu *parent, int i, UiMenuItemI *item) { + +} + +void add_checkitem_widget(NSMenu *parent, int i, UiMenuItemI *item) { + +} + +void add_radioitem_widget(NSMenu *parent, int index, UiMenuItemI *item) { + +} + +void add_checkitemnv_widget(NSMenu *parent, int i, UiMenuItemI *item) { + +} + +void add_menuitem_list_widget(NSMenu *parent, int i, UiMenuItemI *item) { + +} + + +void ui_menu_init(void) { + UiMenu *menus_begin = uic_get_menu_list(); + UiMenu *ls = menus_begin; + while(ls) { + if(ls->item.type == UI_MENU) { + NSString *str = [[NSString alloc] initWithUTF8String:ls->label]; + NSMenu *menu = [[NSMenu alloc] initWithTitle: str]; + NSMenuItem *menuItem = [[NSApp mainMenu] addItemWithTitle:str action:nil keyEquivalent:@""]; + [[NSApp mainMenu] setSubmenu:menu forItem:menuItem]; + + add_menu_items(menu, 0, ls); + } + ls = (UiMenu*)ls->item.next; + } +} diff --git a/ui/cocoa/objs.mk b/ui/cocoa/objs.mk index 9324579..f3f20c7 100644 --- a/ui/cocoa/objs.mk +++ b/ui/cocoa/objs.mk @@ -40,6 +40,7 @@ COCOAOBJ += window.o COCOAOBJ += Container.o COCOAOBJ += button.o COCOAOBJ += text.o +COCOAOBJ += menu.o TOOLKITOBJS += $(COCOAOBJ:%=$(COCOA_OBJPRE)%) TOOLKITSOURCE += $(COCOAOBJ:%.o=cocoa/%.m) diff --git a/ui/cocoa/text.m b/ui/cocoa/text.m index 74d6a79..37d04a8 100644 --- a/ui/cocoa/text.m +++ b/ui/cocoa/text.m @@ -32,12 +32,17 @@ #import UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) { - //NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:(NSRect){ 0, 0, 40, 40}]; - NSTextView *textview = [[NSTextView alloc] initWithFrame:(NSRect){ 0, 0, 40, 40}]; - //scrollview.documentView = textview; + NSTextView *textview = [[NSTextView alloc] init]; + textview.autoresizingMask = NSViewWidthSizable; + textview.minSize = NSMakeSize(0, 0); + textview.maxSize = NSMakeSize(FLT_MAX, FLT_MAX); + + NSScrollView *scrollview = [[NSScrollView alloc] init]; + scrollview.hasVerticalScroller = YES; + scrollview.documentView = textview; UiLayout layout = UI_INIT_LAYOUT(args); - ui_container_add(obj, textview, &layout, TRUE); + ui_container_add(obj, scrollview, &layout, TRUE); - return (__bridge void*)textview; + return (__bridge void*)scrollview; } diff --git a/ui/cocoa/toolkit.m b/ui/cocoa/toolkit.m index 9299672..2501a3f 100644 --- a/ui/cocoa/toolkit.m +++ b/ui/cocoa/toolkit.m @@ -34,6 +34,8 @@ #include "../common/toolbar.h" #include "../common/threadpool.h" +#import "menu.h" + #import "AppDelegate.h" static const char *application_name; diff --git a/ui/common/condvar.c b/ui/common/condvar.c index c61e70c..16f4954 100644 --- a/ui/common/condvar.c +++ b/ui/common/condvar.c @@ -26,6 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _WIN32 + #include "condvar.h" #include @@ -68,3 +70,5 @@ void ui_condvar_destroy(UiCondVar *var) { free(p); } + +#endif \ No newline at end of file diff --git a/ui/common/context.h b/ui/common/context.h index fdcd6a8..f07b6da 100644 --- a/ui/common/context.h +++ b/ui/common/context.h @@ -45,9 +45,7 @@ typedef struct UiListPtr UiListPtr; typedef struct UiListVar UiListVar; typedef struct UiGroupWidget UiGroupWidget; -typedef enum UiVarType UiVarType; - -enum UiVarType { +typedef enum UiVarType { UI_VAR_SPECIAL = 0, UI_VAR_INTEGER, UI_VAR_DOUBLE, @@ -56,7 +54,7 @@ enum UiVarType { UI_VAR_LIST, UI_VAR_RANGE, UI_VAR_GENERIC -}; +} UiVarType; struct UiContext { UiContext *parent; diff --git a/ui/common/objs.mk b/ui/common/objs.mk index b8980af..bc1b385 100644 --- a/ui/common/objs.mk +++ b/ui/common/objs.mk @@ -29,18 +29,18 @@ COMMON_SRC_DIR = ui/common/ COMMON_OBJPRE = $(OBJ_DIR)$(COMMON_SRC_DIR) -COMMON_OBJ = context.o -COMMON_OBJ += document.o -COMMON_OBJ += object.o -COMMON_OBJ += types.o -COMMON_OBJ += menu.o -COMMON_OBJ += properties.o -COMMON_OBJ += menu.o -COMMON_OBJ += toolbar.o -COMMON_OBJ += ucx_properties.o -COMMON_OBJ += threadpool.o -COMMON_OBJ += condvar.o +COMMON_OBJ = context$(OBJ_EXT) +COMMON_OBJ += document$(OBJ_EXT) +COMMON_OBJ += object$(OBJ_EXT) +COMMON_OBJ += types$(OBJ_EXT) +COMMON_OBJ += menu$(OBJ_EXT) +COMMON_OBJ += properties$(OBJ_EXT) +COMMON_OBJ += menu$(OBJ_EXT) +COMMON_OBJ += toolbar$(OBJ_EXT) +COMMON_OBJ += ucx_properties$(OBJ_EXT) +COMMON_OBJ += threadpool$(OBJ_EXT) +COMMON_OBJ += condvar$(OBJ_EXT) -TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)%) -TOOLKITSOURCE += $(COMMON_OBJ:%.o=common/%.c) +TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%) +TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c) diff --git a/ui/common/properties.c b/ui/common/properties.c index 45a9b4e..1d7311a 100644 --- a/ui/common/properties.c +++ b/ui/common/properties.c @@ -116,7 +116,7 @@ char* ui_configfile(char *name) { static int ui_mkdir(char *path) { #ifdef _WIN32 - return mkdir(path); + return _mkdir(path); #else return mkdir(path, S_IRWXU); #endif diff --git a/ui/common/threadpool.c b/ui/common/threadpool.c index d3725c9..7a37407 100644 --- a/ui/common/threadpool.c +++ b/ui/common/threadpool.c @@ -26,11 +26,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _WIN32 + #include "threadpool.h" #include "context.h" -#ifndef _WIN32 - #include #include #include diff --git a/ui/gtk/container.h b/ui/gtk/container.h index e7734ad..b39a3e4 100644 --- a/ui/gtk/container.h +++ b/ui/gtk/container.h @@ -42,7 +42,7 @@ #ifdef __cplusplus extern "C" { #endif - + #define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout)) #define ui_lb2bool(b) ((b) == UI_LAYOUT_TRUE ? TRUE : FALSE) #define ui_bool2lb(b) ((b) ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE) @@ -51,15 +51,14 @@ typedef void (*ui_container_add_f)(UiContainer*, GtkWidget*, UiBool); typedef struct UiDocumentView UiDocumentView; -typedef struct UiLayout UiLayout; -typedef enum UiLayoutBool UiLayoutBool; -enum UiLayoutBool { +typedef enum UiLayoutBool { UI_LAYOUT_UNDEFINED = 0, UI_LAYOUT_TRUE, UI_LAYOUT_FALSE, -}; +} UiLayoutBool; +typedef struct UiLayout UiLayout; struct UiLayout { UiLayoutBool fill; UiBool newline; diff --git a/ui/gtk/image.c b/ui/gtk/image.c index 3c2a0e6..41c9b44 100644 --- a/ui/gtk/image.c +++ b/ui/gtk/image.c @@ -33,38 +33,89 @@ #include "../common/context.h" #include "../common/object.h" +static void imageviewer_destroy(UiImageViewer *iv) { + if(iv->pixbuf) { + g_object_unref(iv->pixbuf); + } + free(iv); +} + +#if GTK_MAJOR_VERSION >= 4 + +static void imageviewer_draw( + GtkDrawingArea *drawingarea, + cairo_t *cr, + int width, + int height, + gpointer userdata) +{ + ui_cairo_draw_image(userdata, cr, width, height); +} -UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) { - UiObject *current = uic_current_obj(obj); - - GtkWidget *scrolledwindow = SCROLLEDWINDOW_NEW(); -#if GTK_CHECK_VERSION(4, 0, 0) - GtkWidget *image = gtk_picture_new(); #else - GtkWidget *image = gtk_image_new(); + +static gboolean imageviewer_draw(GtkWidget *widget, cairo_t *cr, gpointer userdata) { + int width = gtk_widget_get_allocated_width(widget); + int height = gtk_widget_get_allocated_height(widget); + ui_cairo_draw_image(userdata, cr, width, height); + return FALSE; +} + #endif + +UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) { + UiObject *current = uic_current_obj(obj); - ui_set_name_and_style(image, args.name, args.style_class); + GtkWidget *drawingarea = gtk_drawing_area_new(); + GtkWidget *toplevel; + GtkWidget *widget = drawingarea; + + gtk_widget_set_size_request(drawingarea, 100, 100); #if GTK_MAJOR_VERSION < 4 GtkWidget *eventbox = gtk_event_box_new(); - SCROLLEDWINDOW_SET_CHILD(scrolledwindow, eventbox); - gtk_container_add(GTK_CONTAINER(eventbox), image); -#else - SCROLLEDWINDOW_SET_CHILD(scrolledwindow, image); - GtkWidget *eventbox = image; + gtk_container_add(GTK_CONTAINER(eventbox), drawingarea); + widget = eventbox; #endif - UI_APPLY_LAYOUT1(current, args); - current->container->add(current->container, scrolledwindow, TRUE); + if(args.scrollarea) { + toplevel = SCROLLEDWINDOW_NEW(); + SCROLLEDWINDOW_SET_CHILD(toplevel, widget); + args.adjustwidgetsize = TRUE; + } else { + toplevel = widget; + } + + UiImageViewer *imgviewer = malloc(sizeof(UiImageViewer)); + memset(imgviewer, 0, sizeof(UiImageViewer)); + if(args.image_padding > 0) { + imgviewer->padding_left = args.image_padding; + imgviewer->padding_right = args.image_padding; + imgviewer->padding_top = args.image_padding; + imgviewer->padding_bottom = args.image_padding; + } else { + imgviewer->padding_left = args.image_padding_left; + imgviewer->padding_right = args.image_padding_right; + imgviewer->padding_top = args.image_padding_top; + imgviewer->padding_bottom = args.image_padding_bottom; + } + imgviewer->adjustwidgetsize = args.adjustwidgetsize; + imgviewer->autoscale = args.autoscale; + imgviewer->useradjustable = args.useradjustable; + imgviewer->zoom_scale = 20; + + g_object_set_data_full(G_OBJECT(drawingarea), "uiimageviewer", imgviewer, (GDestroyNotify)imageviewer_destroy); UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_GENERIC); + imgviewer->var = var; + imgviewer->widget = drawingarea; + if(var) { UiGeneric *value = var->value; value->get = ui_imageviewer_get; value->get_type = ui_imageviewer_get_type; value->set = ui_imageviewer_set; - value->obj = image; + value->obj = imgviewer; if(value->value && value->type && !strcmp(value->type, UI_IMAGE_OBJECT_TYPE)) { GdkPixbuf *pixbuf = value->value; value->value = NULL; @@ -72,20 +123,164 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) { } } +#if GTK_MAJOR_VERSION >= 4 + gtk_drawing_area_set_draw_func( + GTK_DRAWING_AREA(drawingarea), + imageviewer_draw, + imgviewer, + NULL); + + if(args.useradjustable) { + gtk_widget_set_focusable(drawingarea, TRUE); + } + + GtkEventController *scrollcontroller = gtk_event_controller_scroll_new(GTK_EVENT_CONTROLLER_SCROLL_VERTICAL); + g_signal_connect(scrollcontroller, "scroll", G_CALLBACK(ui_imageviewer_scroll), imgviewer); + gtk_widget_add_controller(GTK_WIDGET(drawingarea), GTK_EVENT_CONTROLLER(scrollcontroller)); + + GtkGesture *drag = gtk_gesture_drag_new(); + g_signal_connect(drag, "drag-begin", G_CALLBACK(ui_imageviewer_drag_begin_cb), imgviewer); + g_signal_connect(drag, "drag-end", G_CALLBACK(ui_imageviewer_drag_end_cb), imgviewer); + g_signal_connect(drag, "drag-update", G_CALLBACK(ui_imageviewer_drag_update_cb), imgviewer); + gtk_widget_add_controller(GTK_WIDGET(drawingarea), GTK_EVENT_CONTROLLER(drag)); + +#elif GTK_MAJOR_VERSION == 3 + g_signal_connect( + drawingarea, + "draw", + G_CALLBACK(imageviewer_draw), + imgviewer); + + gtk_widget_add_events(eventbox, GDK_SCROLL_MASK); + + g_signal_connect( + eventbox, + "scroll-event", + G_CALLBACK(ui_imageviewer_scroll_event), + imgviewer); + g_signal_connect( + eventbox, + "button-press-event", + G_CALLBACK(ui_imageviewer_button_press_event), + imgviewer); + g_signal_connect( + eventbox, + "button-release-event", + G_CALLBACK(ui_imageviewer_button_release_event), + imgviewer); + +#endif + if(args.contextmenu) { - UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, eventbox); - ui_widget_set_contextmenu(eventbox, menu); + UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, widget); + ui_widget_set_contextmenu(widget, menu); } + + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, toplevel, TRUE); - return scrolledwindow; + return toplevel; +} + +static void imageviewer_reset(UiImageViewer *imgviewer) { + imgviewer->isautoscaled = FALSE; + imgviewer->transx = 0; + imgviewer->transy; + imgviewer->begin_transx = 0; + imgviewer->begin_transy = 0; + imgviewer->scale = 1; + imgviewer->user_scale = 1; +} + +UIWIDGET ui_imageviewer_reset(UIWIDGET w) { + UiImageViewer *imgviewer = g_object_get_data(G_OBJECT(w), "uiimageviewer"); + if(imgviewer) { + imageviewer_reset(imgviewer); + gtk_widget_queue_draw(w); + } +} + +UIWIDGET ui_imageviewer_set_autoscale(UIWIDGET w, UiBool set) { + UiImageViewer *imgviewer = g_object_get_data(G_OBJECT(w), "uiimageviewer"); + if(imgviewer) { + imgviewer->autoscale = set; + } +} + +UIWIDGET ui_imageviewer_set_adjustwidgetsize(UIWIDGET w, UiBool set) { + UiImageViewer *imgviewer = g_object_get_data(G_OBJECT(w), "uiimageviewer"); + if(imgviewer) { + imgviewer->adjustwidgetsize = set; + } +} + +UIWIDGET ui_imageviewer_set_useradjustable(UIWIDGET w, UiBool set) { + UiImageViewer *imgviewer = g_object_get_data(G_OBJECT(w), "uiimageviewer"); + if(imgviewer) { + imgviewer->useradjustable = set; + } +} + +void ui_cairo_draw_image(UiImageViewer *imgviewer, cairo_t *cr, int width, int height) { + if(!imgviewer->pixbuf) { + return; + } + + GdkPixbuf *pixbuf = imgviewer->pixbuf; + double dpixwidth = (double)gdk_pixbuf_get_width(pixbuf); + double dpixheight = (double)gdk_pixbuf_get_height(pixbuf); + + double dwidth = width; + double dheight = height; + double scale = 1; + // if autoscale is enabled, scale the image to fill available space + // if useradjustable is also enabled, the autoscaling is only done once + if(imgviewer->autoscale && imgviewer->scale != 0) { + if(!imgviewer->isautoscaled) { + scale = dwidth / dpixwidth; + if(dpixheight * scale > dheight) { + scale = dheight / dpixheight; + } + + if(imgviewer->useradjustable) { + imgviewer->isautoscaled = TRUE; + } + + imgviewer->scale = scale; + } else { + scale = imgviewer->scale; + } + + imgviewer->user_scale = scale; + } else { + // user-adjusted scaling + //scale = 1 + ((double)imgviewer->zoom / (double)imgviewer->zoom_scale); + scale = imgviewer->user_scale; + } + + dpixwidth *= scale; + dpixheight *= scale; + double x = (dwidth - dpixwidth) / 2; + double y = (dheight - dpixheight) / 2; + + x += imgviewer->transx; + y += imgviewer->transy; + + cairo_translate(cr, x, y); + cairo_scale(cr, scale, scale); + + gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); + cairo_paint(cr); } void* ui_imageviewer_get(UiGeneric *g) { + UiImageViewer *imgviewer = g->obj; + g->value = imgviewer->pixbuf; return g->value; } const char* ui_imageviewer_get_type(UiGeneric *g) { - + return UI_IMAGE_OBJECT_TYPE; } int ui_imageviewer_set(UiGeneric *g, void *value, const char *type) { @@ -93,25 +288,24 @@ int ui_imageviewer_set(UiGeneric *g, void *value, const char *type) { return 1; } - // TODO: do we need to free the previous value here? - - g->value = value; - g->type = type; GdkPixbuf *pixbuf = value; - if(pixbuf) { + UiImageViewer *imgviewer = g->obj; + g->value = pixbuf; + + imageviewer_reset(imgviewer); + + if(imgviewer->pixbuf) { + g_object_unref(imgviewer->pixbuf); + } + imgviewer->pixbuf = pixbuf; + + if(imgviewer->adjustwidgetsize && !imgviewer->autoscale) { int width = gdk_pixbuf_get_width(pixbuf); int height = gdk_pixbuf_get_height(pixbuf); - -#if GTK_CHECK_VERSION(4, 0, 0) - GdkTexture *texture = gdk_texture_new_for_pixbuf(pixbuf); - gtk_picture_set_paintable(GTK_PICTURE(g->obj), GDK_PAINTABLE(texture)); -#else - gtk_image_set_from_pixbuf(GTK_IMAGE(g->obj), pixbuf); -#endif - gtk_widget_set_size_request(g->obj, width, height); + gtk_widget_set_size_request(imgviewer->widget, width, height); } - + gtk_widget_queue_draw(imgviewer->widget); return 0; } @@ -130,6 +324,91 @@ int ui_image_load_file(UiGeneric *obj, const char *path) { } else { obj->value = pixbuf; } - + return 0; } + +#if GTK_MAJOR_VERSION >= 4 + +gboolean ui_imageviewer_scroll( + GtkEventControllerScroll *widget, + gdouble dx, + gdouble dy, + gpointer userdata) +{ + UiImageViewer *imgviewer = userdata; + if(imgviewer->useradjustable) { + double step = dy / imgviewer->zoom_scale; + if(imgviewer->user_scale - step > 0) { + imgviewer->user_scale -= step; + } + + imgviewer->scale = 0; // disable autoscale + gtk_widget_queue_draw(imgviewer->widget); + return TRUE; + } + return FALSE; +} + +void ui_imageviewer_drag_begin_cb( + GtkGestureDrag* self, + gdouble start_x, + gdouble start_y, + gpointer userdata) +{ + UiImageViewer *imgviewer = userdata; + imgviewer->begin_transx = imgviewer->transx; + imgviewer->begin_transy = imgviewer->transy; +} + +void ui_imageviewer_drag_end_cb( + GtkGestureDrag* self, + gdouble x, + gdouble y, + gpointer userdata) +{ + +} + +void ui_imageviewer_drag_update_cb( + GtkGestureDrag* self, + gdouble x, + gdouble y, + gpointer userdata) +{ + UiImageViewer *imgviewer = userdata; + if(imgviewer->useradjustable) { + imgviewer->transx = imgviewer->begin_transx + x; + imgviewer->transy = imgviewer->begin_transy + y; + gtk_widget_queue_draw(imgviewer->widget); + } +} + +#else + +gboolean ui_imageviewer_scroll_event( + GtkWidget *widget, + GdkEventScroll event, + gpointer userdata) +{ + printf("scroll event\n"); + return FALSE; +} + +gboolean ui_imageviewer_button_press_event( + GtkWidget *widget, + GdkEventButton event, + gpointer userdata) +{ + printf("button pressed\n"); +} + +gboolean ui_imageviewer_button_release_event( + GtkWidget *widget, + GdkEventButton event, + gpointer userdata) +{ + printf("button released\n"); +} + +#endif diff --git a/ui/gtk/image.h b/ui/gtk/image.h index 00c205d..7e9bf9f 100644 --- a/ui/gtk/image.h +++ b/ui/gtk/image.h @@ -36,11 +36,79 @@ extern "C" { #endif +typedef struct UiImageViewer { + GtkWidget *widget; + UiVar *var; + int padding_left; + int padding_right; + int padding_top; + int padding_bottom; + UiBool autoscale; + UiBool adjustwidgetsize; + UiBool useradjustable; + GdkPixbuf *pixbuf; + + double zoom_scale; + int transx; + int transy; + int begin_transx; + int begin_transy; + UiBool isautoscaled; + double user_scale; + double scale; +} UiImageViewer; + +void ui_cairo_draw_image(UiImageViewer *imgviewer, cairo_t *cr, int width, int height); void* ui_imageviewer_get(UiGeneric *g); const char* ui_imageviewer_get_type(UiGeneric *g); int ui_imageviewer_set(UiGeneric *g, void *value, const char *type); +#if GTK_MAJOR_VERSION >= 4 + +gboolean ui_imageviewer_scroll( + GtkEventControllerScroll *widget, + gdouble dx, + gdouble dy, + gpointer userdata); + +void ui_imageviewer_drag_begin_cb( + GtkGestureDrag* self, + gdouble start_x, + gdouble start_y, + gpointer userdata); + +void ui_imageviewer_drag_end_cb( + GtkGestureDrag* self, + gdouble x, + gdouble y, + gpointer userdata); + +void ui_imageviewer_drag_update_cb( + GtkGestureDrag* self, + gdouble x, + gdouble y, + gpointer userdata); + +#else + +gboolean ui_imageviewer_scroll_event( + GtkWidget *widget, + GdkEventScroll event, + gpointer userdata); + +gboolean ui_imageviewer_button_press_event( + GtkWidget *widget, + GdkEventButton event, + gpointer userdata); + +gboolean ui_imageviewer_button_release_event( + GtkWidget *widget, + GdkEventButton event, + gpointer userdata); + +#endif + #ifdef __cplusplus } #endif diff --git a/ui/gtk/objs.mk b/ui/gtk/objs.mk index ed89f4d..abad5a0 100644 --- a/ui/gtk/objs.mk +++ b/ui/gtk/objs.mk @@ -47,6 +47,7 @@ GTKOBJ += entry.o GTKOBJ += dnd.o GTKOBJ += headerbar.o GTKOBJ += webview.o +GTKOBJ += widget.o TOOLKITOBJS += $(GTKOBJ:%=$(GTK_OBJPRE)%) TOOLKITSOURCE += $(GTKOBJ:%.o=gtk/%.c) diff --git a/ui/gtk/widget.c b/ui/gtk/widget.c index 63d0478..505bca6 100644 --- a/ui/gtk/widget.c +++ b/ui/gtk/widget.c @@ -41,3 +41,20 @@ UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func cre return widget; } + +UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) { + UiObject* current = uic_current_obj(obj); + GtkWidget *widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + ui_set_name_and_style(widget, args->name, args->style_class); + UI_APPLY_LAYOUT1(current, (*args)); + current->container->add(current->container, widget, FALSE); + return widget; +} + +void ui_widget_set_size(UIWIDGET w, int width, int height) { + gtk_widget_set_size_request(w, width, height); +} + +void ui_widget_redraw(UIWIDGET w) { + gtk_widget_queue_draw(w); +} diff --git a/ui/qt/Makefile b/ui/qt/Makefile index a1e7f99..824c467 100644 --- a/ui/qt/Makefile +++ b/ui/qt/Makefile @@ -30,8 +30,8 @@ QT_MAKEFILE = ../build/ui/qt/Makefile.mk UI_QT_LIB = ../build/ui/qt/ -$(QT_MAKEFILE): qt/qt4.pro - qmake-qt4 -o - qt/qt4.pro > $(QT_MAKEFILE) +$(QT_MAKEFILE): qt/$(QT_PRO_FILE) + $(QMAKE) -o - $< > $(QT_MAKEFILE) $(UI_LIB): $(QT_MAKEFILE) $(OBJ) FORCE $(MAKE) -f $(QT_MAKEFILE) diff --git a/ui/qt/button.cpp b/ui/qt/button.cpp index 04b84a4..311c611 100644 --- a/ui/qt/button.cpp +++ b/ui/qt/button.cpp @@ -30,61 +30,136 @@ #include "container.h" #include "toolkit.h" -UIWIDGET ui_button(UiObject *obj, char *label, ui_callback f, void *data) { - QString str = QString::fromUtf8(label); +UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + QString str = QString::fromUtf8(args.label); + QPushButton *button = new QPushButton(str); + + if(args.onclick) { + UiEventWrapper *event = new UiEventWrapper(obj, args.onclick, args.onclickdata); + button->connect(button, SIGNAL(clicked()), event, SLOT(slot())); + button->connect(button, SIGNAL(destroyed()), event, SLOT(destroy())); + } + + ctn->add(button, false); + + return button; +} + +static void togglebutton_event(UiEvent *event, UiEventWrapper *wrapper) { + QPushButton *button = (QPushButton*)wrapper->customdata1; + event->intval = button->isChecked(); + if(wrapper->var) { + event->eventdata = wrapper->var->value; + } +} + +UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + QString str = QString::fromUtf8(args.label); QPushButton *button = new QPushButton(str); + button->setCheckable(true); - if(f) { - UiEventWrapper *event = new UiEventWrapper(obj, f, data); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER); + + if(args.onchange) { + UiEventWrapper *event = new UiEventWrapper(obj, args.onchange, args.onchangedata); + event->var = var; + event->customdata1 = button; + event->prepare_event = togglebutton_event; button->connect(button, SIGNAL(clicked()), event, SLOT(slot())); + button->connect(button, SIGNAL(destroyed()), event, SLOT(destroy())); + } + + if(var) { + UiInteger *i = (UiInteger*)var->value; + + if(i->value) { + button->setChecked(true); + } + + i->obj = button; + i->get = ui_togglebutton_get; + i->set = ui_togglebutton_set; } - UiContainer *ct = uic_get_current_container(obj); - ct->add(button, false); + ctn->add(button, false); return button; } +int64_t ui_togglebutton_get(UiInteger *value) { + QPushButton *button = (QPushButton*)value->obj; + value->value = button->isChecked(); + return value->value; +} +void ui_togglebutton_set(UiInteger *value, int64_t i) { + QPushButton *button = (QPushButton*)value->obj; + value->value = i; + if(i != 0) { + button->setChecked(true); + } +} -// TODO: checkbox +static void checkbox_event(UiEvent *event, UiEventWrapper *wrapper) { + QPushButton *button = (QPushButton*)wrapper->customdata1; + event->intval = button->isChecked(); + if(wrapper->var) { + event->eventdata = wrapper->var->value; + } +} -UIWIDGET ui_radiobutton(UiObject *obj, char *label, UiInteger *rgroup) { - QString str = QString::fromUtf8(label); - QRadioButton *button = new QRadioButton(str); - button->setAutoExclusive(false); - - if(rgroup) { - QButtonGroup *buttonGroup = (QButtonGroup*)rgroup->obj; - if(!buttonGroup) { - buttonGroup = new QButtonGroup(); - rgroup->obj = buttonGroup; - button->setChecked(true); +UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + QString str = QString::fromUtf8(args.label); + QCheckBox *checkbox = new QCheckBox(str); + + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER); + + if(args.onchange) { + UiEventWrapper *event = new UiEventWrapper(obj, args.onchange, args.onchangedata); + event->var = var; + event->customdata1 = checkbox; + event->prepare_event = checkbox_event; + checkbox->connect(checkbox, SIGNAL(clicked()), event, SLOT(slot())); + checkbox->connect(checkbox, SIGNAL(destroyed()), event, SLOT(destroy())); + } + + if(var) { + UiInteger *i = (UiInteger*)var->value; + + if(i->value) { + checkbox->setChecked(true); } - buttonGroup->addButton(button, buttonGroup->buttons().size()); - rgroup->get = ui_radiobutton_get; - rgroup->set = ui_radiobutton_set; + i->obj = checkbox; + i->get = ui_checkbox_get; + i->set = ui_checkbox_set; } - UiContainer *ct = uic_get_current_container(obj); - ct->add(button, false); + ctn->add(checkbox, false); - return button; + return checkbox; } -int ui_radiobutton_get(UiInteger *value) { - QButtonGroup *buttonGroup = (QButtonGroup*)value->obj; - value->value = buttonGroup->checkedId(); +int64_t ui_checkbox_get(UiInteger *value) { + QPushButton *button = (QPushButton*)value->obj; + value->value = button->isChecked(); return value->value; } -void ui_radiobutton_set(UiInteger *value, int i) { - QButtonGroup *buttonGroup = (QButtonGroup*)value->obj; - QAbstractButton *button = buttonGroup->button(i); - if(button) { +void ui_checkbox_set(UiInteger *value, int64_t i) { + QPushButton *button = (QPushButton*)value->obj; + value->value = i; + if(i != 0) { button->setChecked(true); - value->value = i; } } diff --git a/ui/qt/button.h b/ui/qt/button.h index 1761333..b848ec6 100644 --- a/ui/qt/button.h +++ b/ui/qt/button.h @@ -34,12 +34,19 @@ #include #include #include +#include extern "C" { -int ui_radiobutton_get(UiInteger *value); + +int64_t ui_togglebutton_get(UiInteger *value); +void ui_togglebutton_set(UiInteger *value, int64_t i); -void ui_radiobutton_set(UiInteger *value, int i); +int64_t ui_checkbox_get(UiInteger *value); +void ui_checkbox_set(UiInteger *value, int64_t i); + +int64_t ui_radiobutton_get(UiInteger *value); +void ui_radiobutton_set(UiInteger *value, int64_t i); } diff --git a/ui/qt/container.cpp b/ui/qt/container.cpp index 9cb27d8..bf5bf93 100644 --- a/ui/qt/container.cpp +++ b/ui/qt/container.cpp @@ -28,16 +28,31 @@ #include #include "container.h" +#include "../common/object.h" + +#include #include #include +#include +static void delete_container(UiContainerPrivate *ct) { + delete ct; +} + +void ui_container_add(UiObject *obj, UiContainerPrivate *ct) { + UiContainerX *container = (UiContainerX*)ui_malloc(obj->ctx, sizeof(UiContainerX)); + container->close = 0; + container->container = ct; + container->prev = NULL; + container->next = NULL; + cxMempoolRegister(obj->ctx->mp, ct, (cx_destructor_func)delete_container); + uic_object_push_container(obj, container); +} /* -------------------- UiBoxContainer -------------------- */ UiBoxContainer::UiBoxContainer(QBoxLayout* box) { - this->current = NULL; - this->menu = NULL; this->box = box; box->setContentsMargins(QMargins(0,0,0,0)); box->setSpacing(0); @@ -71,36 +86,47 @@ void UiBoxContainer::add(QWidget* widget, bool fill) { current = widget; } -UIWIDGET ui_box(UiObject *obj, QBoxLayout::Direction dir) { - UiContainer *ct = uic_get_current_container(obj); +UIWIDGET ui_box(UiObject *obj, UiContainerArgs args, QBoxLayout::Direction dir) { + UiContainerPrivate *ctn = (UiContainerPrivate*)ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + QWidget *widget = new QWidget(); QBoxLayout *box = new QBoxLayout(dir); widget->setLayout(box); - ct->add(widget, true); + ctn->add(widget, true); - UiObject *newobj = uic_object_new(obj, widget); - newobj->container = new UiBoxContainer(box); - uic_obj_add(obj, newobj); + ui_container_add(obj, new UiBoxContainer(box)); return widget; } -UIWIDGET ui_vbox(UiObject *obj) { - return ui_box(obj, QBoxLayout::TopToBottom); +UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) { + return ui_box(obj, args, QBoxLayout::TopToBottom); } -UIWIDGET ui_hbox(UiObject *obj) { - return ui_box(obj, QBoxLayout::LeftToRight); +UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) { + return ui_box(obj, args, QBoxLayout::LeftToRight); } - /* -------------------- UiGridContainer -------------------- */ -UiGridContainer::UiGridContainer(QGridLayout* grid, int margin, int columnspacing, int rowspacing) { +UiGridContainer::UiGridContainer( + QGridLayout *grid, + int margin, + int columnspacing, + int rowspacing, + bool def_hexpand, + bool def_vexpand, + bool def_hfill, + bool def_vfill) +{ this->current = NULL; - this->menu = NULL; this->grid = grid; + this->def_hexpand = def_hexpand; + this->def_vexpand = def_vexpand; + this->def_hfill = def_hfill; + this->def_vfill = def_vfill; grid->setContentsMargins(QMargins(margin, margin, margin, margin)); grid->setHorizontalSpacing(columnspacing); grid->setVerticalSpacing(rowspacing); @@ -113,144 +139,149 @@ void UiGridContainer::add(QWidget* widget, bool fill) { y++; } - Qt::Alignment alignment = Qt::AlignTop; - grid->setColumnStretch(x, layout.hexpand ? 1 : 0); + int hexpand = false; + int vexpand = false; + int hfill = false; + int vfill = false; + if(!layout.override_defaults) { + if(def_hexpand) { + hexpand = true; + hfill = true; + } else if(def_hfill) { + hfill = true; + } + if(def_vexpand) { + vexpand = true; + vfill = true; + } else if(def_vfill) { + vfill = true; + } + } + + if(layout.fill != UI_LAYOUT_UNDEFINED) { + fill = ui_lb2bool(layout.fill); + } + if(layout.hexpand) { + hexpand = true; + //hfill = true; + } else if(layout.hfill) { + hfill = true; + } if(layout.vexpand) { + vexpand = true; + //vfill = true; + } else if(layout.vfill) { + vfill = true; + } + if(fill) { + hfill = true; + vfill = true; + } + + if(hexpand) { + col_expanding = true; + } + if(vexpand) { + row_expanding = true; + } + + if(hexpand) { + grid->setColumnStretch(x, 1); + } + if(vexpand) { grid->setRowStretch(y, 1); - alignment = 0; - } else { - grid->setRowStretch(y, 0); } - int gwidth = layout.gridwidth > 0 ? layout.gridwidth : 1; + Qt::Alignment alignment = 0; + if(!hfill) { + alignment = Qt::AlignLeft; + } + if(!vfill) { + alignment = Qt::AlignTop; + } + + int colspan = layout.colspan > 0 ? layout.colspan : 1; + int rowspan = layout.rowspan > 0 ? layout.rowspan : 1; + + grid->addWidget(widget, y, x, rowspan, colspan, alignment); + + if(x > max_x) { + max_x = x; + } + if(y > max_y) { + max_y = y; + } - grid->addWidget(widget, y, x, 1, gwidth, alignment); - x += gwidth; + x += colspan; ui_reset_layout(layout); current = widget; } -UIWIDGET ui_grid(UiObject *obj) { - return ui_grid_sp(obj, 0, 0, 0); +void UiGridContainer::end() { + if(!col_expanding) { + QSpacerItem *filler = new QSpacerItem(0, 0); + x = max_x + 1; + grid->setColumnStretch(x, 1); + grid->addItem(filler, 0, x, 1, 1, 0); + } + if(!row_expanding) { + QSpacerItem *filler = new QSpacerItem(0, 0); + y++; + grid->setRowStretch(y, 1); + grid->addItem(filler, y, 0, 1, 1, 0); + } } -UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) { - UiContainer *ct = uic_get_current_container(obj); +UIEXPORT UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) { + UiContainerPrivate *ctn = (UiContainerPrivate*)ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + QWidget *widget = new QWidget(); QGridLayout *grid = new QGridLayout(); widget->setLayout(grid); - ct->add(widget, true); + ctn->add(widget, true); - UiObject *newobj = uic_object_new(obj, widget); - newobj->container = new UiGridContainer(grid, margin, columnspacing, rowspacing); - uic_obj_add(obj, newobj); + ui_container_add(obj, new UiGridContainer( + grid, + args.margin, + args.columnspacing, + args.rowspacing, + args.def_hexpand, + args.def_vexpand, + args.def_hfill, + args.def_vfill)); return widget; } -/* -------------------- UiTabViewContainer -------------------- */ -UiTabViewContainer::UiTabViewContainer(QTabWidget* tabwidget) { - this->current = NULL; - this->menu = NULL; - this->tabwidget = tabwidget; -} +/* -------------------- Container Helper Functions -------------------- */ -void UiTabViewContainer::add(QWidget* widget, bool fill) { - QString str = QString::fromUtf8(layout.label); - tabwidget->addTab(widget, str); +void ui_container_begin_close(UiObject *obj) { + obj->container_end->close = true; } - -/* -------------------- UiStackContainer -------------------- */ - -UiStackContainer::UiStackContainer(QStackedWidget *stack) { - this->stack = stack; -} - -void UiStackContainer::add(QWidget* widget, bool fill) { - stack->addWidget(widget); - current = widget; -} - -UIWIDGET ui_tabview(UiObject *obj) { - QStackedWidget *tabwidget = new QStackedWidget(); - - UiContainer *ct = uic_get_current_container(obj); - ct->add(tabwidget, true); - - UiObject *tabviewobj = uic_object_new(obj, tabwidget); - tabviewobj->container = new UiStackContainer(tabwidget); - uic_obj_add(obj, tabviewobj); - - return tabwidget; -} - -void ui_tab(UiObject *obj, char *title) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.label = title; - ui_vbox(obj); -} - -void ui_select_tab(UIWIDGET tabview, int tab) { - QStackedWidget *w = (QStackedWidget*)tabview; - w->setCurrentIndex(tab); -} - - -/* -------------------- UiSidebarContainer -------------------- */ - -UiSidebarContainer::UiSidebarContainer(QSplitter *splitter) { - this->splitter = splitter; -} - -UIWIDGET ui_sidebar(UiObject *obj) { - QSplitter *splitter = new QSplitter(Qt::Horizontal); - UiContainer *ct = uic_get_current_container(obj); - ct->add(splitter, true); - - UiObject *left = uic_object_new(obj, splitter); - left->container = new UiSidebarContainer(splitter); - - UiObject *right = uic_object_new(obj, splitter); - right->container = new UiSidebarContainer(splitter); - - uic_obj_add(obj, right); - uic_obj_add(obj, left); - - return splitter; -} - -void UiSidebarContainer::add(QWidget *widget, bool fill) { - splitter->addWidget(widget); -} - - -/* -------------------- layout functions -------------------- */ - -void ui_layout_fill(UiObject *obj, UiBool fill) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.fill = ui_bool2lb(fill); -} - -void ui_layout_hexpand(UiObject *obj, UiBool expand) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.hexpand = expand; +int ui_container_finish(UiObject *obj) { + if(obj->container_end->close) { + UiContainerPrivate *ctn = (UiContainerPrivate*)obj->container_end->container; + ctn->end(); + ui_end_new(obj); + return 0; + } + return 1; } -void ui_layout_vexpand(UiObject *obj, UiBool expand) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.vexpand = expand; -} -void ui_layout_gridwidth(UiObject *obj, int width) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.gridwidth = width; -} +/* + * -------------------- Layout Functions -------------------- + * + * functions for setting layout attributes for the current container + * + */ void ui_newline(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); + UiContainerPrivate *ct = ui_obj_container(obj); ct->layout.newline = TRUE; } diff --git a/ui/qt/container.h b/ui/qt/container.h index 1a1c353..16ced63 100644 --- a/ui/qt/container.h +++ b/ui/qt/container.h @@ -30,6 +30,7 @@ #define CONTAINER_H #include "toolkit.h" +#include "../ui/container.h" #include "window.h" #include @@ -39,37 +40,52 @@ #include #include +#define UI_APPLY_LAYOUT(layout, args) \ + layout.fill = args.fill; \ + layout.hexpand = args.hexpand; \ + layout.vexpand = args.vexpand; \ + layout.hfill = args.hfill; \ + layout.vfill = args.vfill; \ + layout.override_defaults = args.override_defaults; \ + layout.colspan = args.colspan; \ + layout.rowspan = args.rowspan + +#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout)) #define ui_lb2bool(b) ((b) == UI_LAYOUT_TRUE ? TRUE : FALSE) #define ui_bool2lb(b) ((b) ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE) -#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout)) -typedef struct UiLayout UiLayout; +#define ui_obj_container(obj) (UiContainerPrivate*)((UiContainerX*)obj->container_end)->container -enum UiLayoutBool { +typedef enum UiLayoutBool { UI_LAYOUT_UNDEFINED = 0, UI_LAYOUT_TRUE, UI_LAYOUT_FALSE, -}; -typedef enum UiLayoutBool UiLayoutBool; +} UiLayoutBool; +typedef struct UiLayout UiLayout; struct UiLayout { - UiLayoutBool fill; - bool newline; - char *label; - bool hexpand; - bool vexpand; - int gridwidth; + UiTri fill; + UiBool newline; + char *label; + UiBool hexpand; + UiBool vexpand; + UiBool hfill; + UiBool vfill; + UiBool override_defaults; + int width; + int colspan; + int rowspan; }; -struct UiContainer { +struct UiContainerPrivate { UiLayout layout; UIWIDGET current; - QMenu *menu; virtual void add(QWidget *widget, bool fill) = 0; + virtual void end() {} }; -class UiBoxContainer : public UiContainer { +class UiBoxContainer : public UiContainerPrivate { public: QBoxLayout *box; bool hasStretchedWidget = false; @@ -80,40 +96,36 @@ public: virtual void add(QWidget *widget, bool fill); }; -class UiGridContainer : public UiContainer { +class UiGridContainer : public UiContainerPrivate { public: QGridLayout *grid; int x = 0; int y = 0; + bool def_hexpand; + bool def_vexpand; + bool def_hfill; + bool def_vfill; + bool col_expanding = false; + bool row_expanding = false; + int max_x; + int max_y; - UiGridContainer(QGridLayout *grid, int margin, int columnspacing, int rowspacing); + UiGridContainer( + QGridLayout *grid, + int margin, + int columnspacing, + int rowspacing, + bool def_hexpand, + bool def_vexpand, + bool def_hfill, + bool def_vfill); virtual void add(QWidget *widget, bool fill); + virtual void end(); }; -class UiTabViewContainer : public UiContainer { -public: - QTabWidget *tabwidget; - - UiTabViewContainer(QTabWidget *tabwidget); - virtual void add(QWidget *widget, bool fill); -}; +void ui_container_add(UiObject *obj, UiContainerPrivate *ct); -class UiStackContainer : public UiContainer { -public: - QStackedWidget *stack; - - UiStackContainer(QStackedWidget *stack); - virtual void add(QWidget *widget, bool fill); -}; - -class UiSidebarContainer : public UiContainer { -public: - QSplitter *splitter; - - UiSidebarContainer(QSplitter *splitter); - virtual void add(QWidget *widget, bool fill); -}; #endif /* CONTAINER_H */ diff --git a/ui/qt/graphics.cpp b/ui/qt/graphics.cpp index d9a03c1..f3a9de2 100644 --- a/ui/qt/graphics.cpp +++ b/ui/qt/graphics.cpp @@ -30,122 +30,4 @@ #include "container.h" -DrawingArea::DrawingArea(UiObject *obj, ui_drawfunc cb, void *data) { - object = obj; - drawCallback = cb; - userdata = data; -} - -DrawingArea::~DrawingArea() { - -} - -void DrawingArea::paintEvent(QPaintEvent *event) { - QPainter painter(this); - - UiQtGraphics g; - g.g.width = this->width(); - g.g.height = this->height(); - g.painter = &painter; - - UiEvent ev; - ev.obj = object; - ev.window = object->window; - ev.document = object->ctx->document; - ev.eventdata = NULL; - ev.intval = 0; - - drawCallback(&ev, &g.g, userdata); -} - - - -UIWIDGET ui_drawingarea(UiObject *obj, ui_drawfunc f, void *userdata) { - DrawingArea *widget = new DrawingArea(obj, f, userdata); - - UiContainer *ct = uic_get_current_container(obj); - ct->add(widget, true); - - return widget; -} - -void ui_drawingarea_mousehandler(UiObject *obj, UIWIDGET widget, ui_callback f, void *u) { - -} - -void ui_drawingarea_getsize(UIWIDGET drawingarea, int *width, int *height) { - -} - -void ui_drawingarea_redraw(UIWIDGET drawingarea) { - -} - - -/* -------------------- text layout functions -------------------- */ - -UiTextLayout* ui_text(UiGraphics *g) { - UiTextLayout *textlayout = new UiTextLayout(); - return textlayout; -} - -void ui_text_free(UiTextLayout *text) { - delete text; -} - -void ui_text_setstring(UiTextLayout *layout, char *str) { - layout->text.setText(QString::fromUtf8(str)); -} - -void ui_text_setstringl(UiTextLayout *layout, char *str, int len) { - layout->text.setText(QString::fromUtf8(str, len)); -} - -void ui_text_setfont(UiTextLayout *layout, char *font, int size) { - layout->font = QFont(QString::fromUtf8(font), size); -} - -void ui_text_getsize(UiTextLayout *layout, int *width, int *height) { - QSizeF size = layout->text.size(); - *width = (int)size.width(); - *height = (int)size.height(); -} - -void ui_text_setwidth(UiTextLayout *layout, int width) { - layout->text.setTextWidth((qreal)width); -} - - -/* -------------------- drawing functions -------------------- */ - -void ui_graphics_color(UiGraphics *g, int red, int green, int blue) { - UiQtGraphics *gr = (UiQtGraphics*)g; - gr->color = QColor(red, green, blue); - gr->painter->setPen(gr->color); -} - -void ui_draw_line(UiGraphics *g, int x1, int y1, int x2, int y2) { - UiQtGraphics *gr = (UiQtGraphics*)g; - - gr->painter->drawLine(x1, y1, x2, y2); -} - -void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, int fill) { - UiQtGraphics *gr = (UiQtGraphics*)g; - - QRect rect(x, y, w, h); - if(fill) { - gr->painter->fillRect(rect, gr->color); - - } else { - gr->painter->drawRect(rect); - } -} - -void ui_draw_text(UiGraphics *g, int x, int y, UiTextLayout *text) { - UiQtGraphics *gr = (UiQtGraphics*)g; - - gr->painter->setFont(text->font); - gr->painter->drawStaticText(x, y, text->text); -} diff --git a/ui/qt/graphics.h b/ui/qt/graphics.h index b4c5f0b..62d4df2 100644 --- a/ui/qt/graphics.h +++ b/ui/qt/graphics.h @@ -37,31 +37,6 @@ #include #include -typedef struct UiQtGraphics { - UiGraphics g; - QPainter *painter; - QColor color; -} UiXlibGraphics; - -struct UiTextLayout { - QStaticText text; - QFont font; -}; - - -class DrawingArea : public QWidget { - Q_OBJECT - - UiObject *object; - ui_drawfunc drawCallback; - void *userdata; - -public: - DrawingArea(UiObject *obj, ui_drawfunc cb, void *data); - ~DrawingArea(); - - virtual void paintEvent(QPaintEvent * event); -}; #endif /* GRAPHICS_H */ diff --git a/ui/qt/label.cpp b/ui/qt/label.cpp index 85bfc57..ef7a9fc 100644 --- a/ui/qt/label.cpp +++ b/ui/qt/label.cpp @@ -29,23 +29,35 @@ #include "label.h" #include "container.h" #include "toolkit.h" +#include "ui/display.h" -UIWIDGET ui_label(UiObject *obj, char *label) { - QString str = QString::fromUtf8(label); + +UIWIDGET ui_label_create(UiObject* obj, UiLabelArgs args) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + QString str = QString::fromUtf8(args.label); QLabel *widget = new QLabel(str); - UiContainer *ct = uic_get_current_container(obj); - ct->add(widget, false); + Qt::AlignmentFlag align = Qt::AlignCenter; + if(args.align == UI_ALIGN_LEFT) { + align = Qt::AlignLeft; + } else if(args.align == UI_ALIGN_RIGHT) { + align = Qt::AlignRight; + } + widget->setAlignment(align); + + ctn->add(widget, false); return widget; } -UIWIDGET ui_space(UiObject *obj) { - // TODO: maybe there is a better widget for this purpose - QLabel *widget = new QLabel(); - - UiContainer *ct = uic_get_current_container(obj); - ct->add(widget, true); - - return widget; +UIWIDGET ui_llabel_create(UiObject* obj, UiLabelArgs args) { + args.align = UI_ALIGN_LEFT; + return ui_label_create(obj, args); +} + +UIWIDGET ui_rlabel_create(UiObject* obj, UiLabelArgs args) { + args.align = UI_ALIGN_RIGHT; + return ui_label_create(obj, args); } diff --git a/ui/qt/menu.cpp b/ui/qt/menu.cpp index 6482e01..86bf75f 100644 --- a/ui/qt/menu.cpp +++ b/ui/qt/menu.cpp @@ -35,391 +35,203 @@ #include "menu.h" #include "toolkit.h" #include "../common/context.h" +#include "../common/menu.h" #include "../ui/properties.h" #include "../ui/window.h" #include "stock.h" #include "container.h" -static UcxList *menus; -static UcxList *current; -/* -------------------------- UiMenu -------------------------- */ +static ui_menu_add_f createMenuItem[] = { + /* UI_MENU */ add_menu_widget, + /* UI_MENU_ITEM */ add_menuitem_widget, + /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, + /* UI_MENU_RADIO_ITEM */ add_radioitem_widget, + /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_SEPARATOR */ add_menuseparator_widget +}; -UiMenu::UiMenu(char* label) { - this->items = NULL; - this->label = label; -} - -void UiMenu::addMenuItem(UiMenuItemI* item) { - items = ucx_list_append(items, item); -} - -void UiMenu::addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu) { - QMenu *m = NULL; - if(menubar) { - m = menubar->addMenu(label); - } else { - m = menu->addMenu(label); +/* + * create all menu child items + */ +static void add_menu_items(QMenu *parent, int i, UiMenu *menu, UiObject *obj) { + UiMenuItemI *it = menu->items_begin; + int index = 0; + while(it) { + createMenuItem[it->type](parent, index, it, obj); + it = it->next; + index++; + } +} + +void add_menu_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenu *m = (UiMenu*)item; + QMenu *menu = parent->addMenu(m->label); + add_menu_items(menu, i, m, obj); +} + +static UiAction* create_action( + UiObject *obj, + const char *icon, + const char *label, + ui_callback callback, + void *userdata, + int *states) +{ + QString str = QString::fromUtf8(label); + UiAction *action = new UiAction(obj, str, callback, userdata); + if(icon) { + action->setIcon(QIcon::fromTheme(icon)); + action->setIconVisibleInMenu(true); } - UCX_FOREACH(elm, items) { - UiMenuItemI *item = (UiMenuItemI*)elm->data; - item->addTo(obj, NULL, m); + if(states) { + size_t nstates = uic_group_array_size(states); + uic_add_group_widget_i(obj->ctx, action, (ui_enablefunc)ui_action_enable, states, nstates); + action->setEnabled(false); } + + return action; } - -/* -------------------------- UiMenuItem -------------------------- */ - -UiMenuItem::UiMenuItem(char* label, ui_callback f, void* userdata) { - this->label = label; - this->callback = f; - this->userdata = userdata; - this->groups = NULL; -} - -void UiMenuItem::addGroup(int group) { - groups = ucx_list_append(groups, (void*)(intptr_t)group); -} - -void UiMenuItem::setCheckable(bool c) { - checkable = c; -} - -void UiMenuItem::addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu) { - QString str = QString::fromUtf8(label); - UiAction *action = new UiAction(obj, str, callback, userdata); - action->setCheckable(checkable); - if(checkable) { - action->setChecked(false); - } - menu->addAction(action); +void add_menuitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuItem *it = (UiMenuItem*)item; + UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->groups); + parent->addAction(action); QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); } - -/* -------------------------- UiStMenuItem -------------------------- */ - -UiStMenuItem::UiStMenuItem(char* stockid, ui_callback f, void* userdata) { - this->stockid = stockid; - this->callback = f; - this->userdata = userdata; - this->groups = NULL; -} - -void UiStMenuItem::addGroup(int group) { - groups = ucx_list_append(groups, (void*)(intptr_t)group); +void add_menuseparator_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { + parent->addSeparator(); } -void UiStMenuItem::addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu) { - UiStockItem *stockItem = ui_get_stock_item(stockid); +void add_checkitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuCheckItem *it = (UiMenuCheckItem*)item; - QString str = QString::fromUtf8(stockItem->label); - UiAction *action = new UiAction(obj, str, callback, userdata); - action->setIcon(QIcon::fromTheme(stockItem->icon_name)); - action->setIconVisibleInMenu(true); - menu->addAction(action); - //UiEventWrapper *ev = new UiEventWrapper(callback, userdata); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); -} - - -/* -------------------------- UiMenuSeparator -------------------------- */ - -void UiMenuSeparator::addTo(UiObject* obj, QMenuBar* menubar, QMenu* menu) { - menu->addSeparator(); -} - - -/* -------------------------- UiCheckItemNV -------------------------- */ - -UiCheckItemNV::UiCheckItemNV(char* label, char* varname) { - this->label = label; - this->varname = varname; -} - -void UiCheckItemNV::addTo(UiObject* obj, QMenuBar* menubar, QMenu* menu) { - QString str = QString::fromUtf8(label); - UiAction *action = new UiAction(obj, str, NULL, NULL); + UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->groups); + parent->addAction(action); action->setCheckable(true); - menu->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); + action->prepare_event = ui_checkableaction_prepare_event; - UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_INTEGER); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, it->varname, UI_VAR_INTEGER); if(var) { UiInteger *value = (UiInteger*)var->value; - action->setChecked(value->value); value->obj = action; - value->get = ui_checkitem_get; - value->set = ui_checkitem_set; - value = 0; - } else { - // TODO: error + value->get = ui_checkableaction_get; + value->set = ui_checkableaction_set; + + action->setChecked((bool)value->value); } + action->var = var; } - -/* -------------------------- UiAction -------------------------- */ - -UiAction::UiAction(UiObject *obj, QString &label, ui_callback f, void* userdata) : QAction(label, NULL) { - //QAction(label, NULL); - this->obj = obj; - this->callback = f; - this->userdata = userdata; -} - -void UiAction::trigger() { - if(!callback) { - return; - } +void add_radioitem_widget(QMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuRadioItem *it = (UiMenuRadioItem*)item; - UiEvent e; - e.obj = obj; - e.window = obj->window; - e.document = obj->ctx->document; - e.eventdata = NULL; + UiAction *action = create_action(obj, it->icon, it->label, it->callback, it->userdata, it->groups); + parent->addAction(action); + action->setCheckable(true); + action->prepare_event = ui_actiongroup_prepare_event; - if(isCheckable()) { - e.intval = isChecked(); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, it->varname, UI_VAR_INTEGER); + if(var) { + UiInteger *value = (UiInteger*)var->value; + QActionGroup *group = (QActionGroup*)value->obj; + if(!group) { + group = new QActionGroup(parent); + value->obj = group; + } + group->addAction(action); + value->get = ui_actiongroup_get; + value->set = ui_actiongroup_set; + if(value->value != 0) { + ui_actiongroup_set(value, value->value); + } + } + action->var; +} + +void ui_actiongroup_prepare_event(UiEvent *event, UiAction *action) { + if(action->var) { + UiInteger *value = (UiInteger*)action->var->value; + event->eventdata = value; + event->intval = value->get(value); + } +} + +int64_t ui_actiongroup_get(UiInteger *value) { + QActionGroup *group = (QActionGroup*)value->obj; + auto actions = group->actions(); + int i = 1; + foreach(const QAction *action, actions) { + if(action->isChecked()) { + value->value = i; + break; + } + i++; + } + return value->value; +} + +void ui_actiongroup_set(UiInteger *value, int64_t i) { + QActionGroup *group = (QActionGroup*)value->obj; + auto actions = group->actions(); + if(i > 0) { + if(i-1 < actions.size()) { + actions[i]->setEnabled(true); + } + value->value = i; } else { - e.intval = 0; - } - - callback(&e, userdata); -} - - -void ui_menu(char *label) { - // free current menu hierarchy - ucx_list_free(current); - - // create menu - UiMenu *menu = new UiMenu(label); - - current = ucx_list_prepend(NULL, menu); - menus = ucx_list_append(menus, menu); -} - -void ui_submenu(char *label) { - UiMenu *menu = new UiMenu(label); - - // add submenu to current menu - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(menu); - - // set the submenu to current menu - current = ucx_list_prepend(current, menu); -} - -void ui_submenu_end() { - if(ucx_list_size(current) < 2) { - return; - } - current = ucx_list_remove(current, current); - //UcxList *c = current; -} - - -void ui_menuitem(char *label, ui_callback f, void *userdata) { - ui_menuitem_gr(label, f, userdata, -1); -} - -void ui_menuitem_st(char *stockid, ui_callback f, void *userdata) { - ui_menuitem_stgr(stockid, f, userdata, -1); -} - -void ui_menuitem_gr(char *label, ui_callback f, void *userdata, ...) { - if(!current) { - return; + foreach(QAction *action, actions) { + action->setEnabled(false); + } + value->value = 0; } - - UiMenuItem *item = new UiMenuItem(label, f, userdata); - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - item->addGroup(group); - } - va_end(ap); - - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); } -void ui_menuitem_stgr(char *stockid, ui_callback f, void *userdata, ...) { - if(!current) { - return; - } - - UiStMenuItem *item = new UiStMenuItem(stockid, f, userdata); - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - item->addGroup(group); - } - va_end(ap); - - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); -} - -void ui_menuseparator() { - if(!current) { - return; - } +void add_menuitem_list_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj) { - UiMenuSeparator *item = new UiMenuSeparator(); - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); } -void ui_checkitem(char *label, ui_callback f, void *userdata) { - if(!current) { - return; - } - - UiMenuItem *item = new UiMenuItem(label, f, userdata); - item->setCheckable(true); - - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); -} -void ui_checkitem_nv(char *label, char *vname) { - if(!current) { +void ui_add_menus(UiObject *obj, QMainWindow *window) { + UiMenu *menus_begin = uic_get_menu_list(); + if(menus_begin == NULL) { return; } - UiCheckItemNV *item = new UiCheckItemNV(label, vname); - - UiMenu *cm = (UiMenu*)current->data; - cm->addMenuItem(item); -} - -void ui_menuitem_list(UiList *items, ui_callback f, void *userdata) { - -} - -void ui_add_menus(UiObject *obj, QMainWindow *window) { QMenuBar *mb = window->menuBar(); - UCX_FOREACH(elm, menus) { - UiMenu *menu = (UiMenu*)elm->data; - menu->addTo(obj, mb, NULL); + UiMenu *ls = menus_begin; + while(ls) { + if(ls->item.type == UI_MENU) { + QMenu *menu = mb->addMenu(ls->label); + add_menu_items(menu, 0, ls, obj); + } + ls = (UiMenu*)ls->item.next; } } -int ui_checkitem_get(UiInteger *i) { - QAction *action = (QAction*)i->obj; - i->value = action->isChecked(); - return i->value; -} - -void ui_checkitem_set(UiInteger *i, int value) { - QAction *action = (QAction*)i->obj; - i->value = value; - action->setChecked(value); -} - - -/* - * widget menu functions - */ - -UiContextMenuHandler::UiContextMenuHandler(QWidget *widget, QMenu* menu) { - this->widget = widget; - this->menu = menu; -} - -void UiContextMenuHandler::contextMenuEvent(const QPoint & pos) { - menu->popup(widget->mapToGlobal(pos)); -} -UIMENU ui_contextmenu(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - return ui_contextmenu_w(obj, ct->current); -} - -UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) { - UiContainer *ct = uic_get_current_container(obj); - - QMenu *menu = new QMenu(widget); - widget->setContextMenuPolicy(Qt::CustomContextMenu); - - UiContextMenuHandler *handler = new UiContextMenuHandler(widget, menu); - QObject::connect( - widget, - SIGNAL(customContextMenuRequested(QPoint)), - handler, - SLOT(contextMenuEvent(QPoint))); - - ct->menu = menu; - - return menu; -} - -void ui_contextmenu_popup(UIMENU menu) { - -} - -void ui_widget_menuitem(UiObject *obj, char *label, ui_callback f, void *userdata) { - ui_widget_menuitem_gr(obj, label, f, userdata, -1); -} - -void ui_widget_menuitem_gr(UiObject *obj, char *label, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; +void ui_checkableaction_prepare_event(UiEvent *event, UiAction *action) { + if(action->var) { + event->eventdata = action->var->value; } - - // add groups - UcxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - ucx_list_append(groups, (void*)(intptr_t)group); - } - va_end(ap); - - // create menuitem - QString str = QString::fromUtf8(label); - UiAction *action = new UiAction(obj, str, f, userdata); - ct->menu->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); + event->intval = action->isChecked(); } -void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) { - ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1); +int64_t ui_checkableaction_get(UiInteger *value) { + UiAction *action= (UiAction*)value->obj; + value->value = action->isChecked(); + return value->value; } -void ui_widget_menuitem_stgr(UiObject *obj, char *stockid, ui_callback f, void *userdata, ...) { - UiContainer *ct = uic_get_current_container(obj); - if(!ct->menu) { - return; - } - - // add groups - UcxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - ucx_list_append(groups, (void*)(intptr_t)group); +void ui_checkableaction_set(UiInteger *value, int64_t i) { + UiAction *action = (UiAction*)value->obj; + value->value = i; + if(i != 0) { + action->setChecked((bool)i); } - va_end(ap); - - // create menuitem - UiStockItem *stockItem = ui_get_stock_item(stockid); - - QString str = QString::fromUtf8(stockItem->label); - UiAction *action = new UiAction(obj, str, f, userdata); - action->setIcon(QIcon::fromTheme(stockItem->icon_name)); - action->setIconVisibleInMenu(true); - ct->menu->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); } + diff --git a/ui/qt/menu.h b/ui/qt/menu.h index 7bffb08..9903ae0 100644 --- a/ui/qt/menu.h +++ b/ui/qt/menu.h @@ -30,105 +30,34 @@ #define MENU_H #include "../ui/menu.h" -#include +#include "../common/menu.h" + +#include "toolkit.h" #include #include #include #include -class UiMenuItemI { -public: - virtual void addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu) = 0; -}; - -class UiMenu : public UiMenuItemI { -public: - - UcxList *items; - char *label; - - UiMenu(char *label); - - void addMenuItem(UiMenuItemI *item); - - virtual void addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu); -}; - -class UiMenuItem : public UiMenuItemI { - char *label; - ui_callback callback; - void *userdata; - UcxList *groups; - bool checkable = false; - -public: - UiMenuItem(char *label, ui_callback f, void *userdata); - void addGroup(int group); - void setCheckable(bool c); - - virtual void addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu); -}; - -class UiStMenuItem : public UiMenuItemI { - char *stockid; - ui_callback callback; - void *userdata; - UcxList *groups; - -public: - UiStMenuItem(char *stockid, ui_callback f, void *userdata); - void addGroup(int group); - - virtual void addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu); -}; - -class UiMenuSeparator : public UiMenuItemI { -public: - virtual void addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu); -}; - -class UiCheckItemNV : public UiMenuItemI { - char *label; - char *varname; - -public: - UiCheckItemNV(char *label, char *varname); - virtual void addTo(UiObject *obj, QMenuBar *menubar, QMenu *menu); -}; - - -class UiAction : public QAction { - Q_OBJECT - - UiObject *obj; - ui_callback callback; - void *userdata; - -public: - UiAction(UiObject *obj, QString &label, ui_callback f, void *userdata); +void ui_add_menus(UiObject *obj, QMainWindow *window); -private slots: - void trigger(); -}; +typedef void(*ui_menu_add_f)(QMenu*, int, UiMenuItemI*, UiObject*); -void ui_add_menus(UiObject *obj, QMainWindow *window); +void add_menu_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj); +void add_menuitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj); +void add_menuseparator_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj); +void add_checkitem_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj); +void add_radioitem_widget(QMenu *parent, int index, UiMenuItemI *item, UiObject *obj); +void add_checkitemnv_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj); +void add_menuitem_list_widget(QMenu *parent, int i, UiMenuItemI *item, UiObject *obj); -extern "C" int ui_checkitem_get(UiInteger *i); -extern "C" void ui_checkitem_set(UiInteger *i, int value); +void ui_checkableaction_prepare_event(UiEvent *event, UiAction *action); +int64_t ui_checkableaction_get(UiInteger *value); +void ui_checkableaction_set(UiInteger *value, int64_t i); -class UiContextMenuHandler : public QObject { - Q_OBJECT - - QWidget *widget; - QMenu *menu; - -public: - UiContextMenuHandler(QWidget *widget, QMenu *menu); - -public slots: - void contextMenuEvent(const QPoint & pos); -}; +void ui_actiongroup_prepare_event(UiEvent *event, UiAction *action); +int64_t ui_actiongroup_get(UiInteger *value); +void ui_actiongroup_set(UiInteger *value, int64_t i); #endif /* MENU_H */ diff --git a/ui/qt/model.cpp b/ui/qt/model.cpp index 7cdf63e..d6ead68 100644 --- a/ui/qt/model.cpp +++ b/ui/qt/model.cpp @@ -28,143 +28,3 @@ #include "model.h" -UiListSelection* listSelection(QItemSelectionModel *s) { - UiListSelection *selection = new UiListSelection(); - - QModelIndexList list = s->selectedRows(); - selection->count = list.count(); - if(selection->count > 0) { - selection->rows = new int[selection->count]; - } - - QModelIndex index; - int i=0; - foreach(index, list) { - selection->rows[i] = index.row(); - i++; - } - return selection; -} - -ListModel::ListModel(UiObject* obj, QListView* view, UiListPtr* list, ui_model_getvalue_f getvalue, ui_callback f, void* userdata) { - this->obj = obj; - this->view = view; - this->list = list; - this->getvalue = getvalue; - this->callback = f; - this->userdata = userdata; -} - -int ListModel::rowCount(const QModelIndex& parent) const { - return list->list->count(list->list); -} - -QVariant ListModel::data(const QModelIndex &index, int role) const { - if(role == Qt::DisplayRole) { - UiList *ls = list->list; - void *rowData = ls->get(ls, index.row()); - if(rowData && getvalue) { - void *value = getvalue(rowData, 0); - return QString::fromUtf8((char*)value); - } - } - return QVariant(); -} - -void ListModel::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { - UiListSelection *selection = listSelection(view->selectionModel()); - - UiEvent e; - e.obj = obj; - e.window = obj->window; - e.document = obj->ctx->document; - e.eventdata = selection; - e.intval = selection->count > 0 ? selection->rows[0] : -1; - callback(&e, userdata); - - if(selection->count > 0) { - delete selection->rows; - } - delete selection; -} - -TableModel::TableModel(UiObject *obj, QTreeView *view, UiListPtr *list, UiModelInfo *info) { - this->obj = obj; - this->list = list; - this->info = info; - this->view = view; -} - -int TableModel::rowCount(const QModelIndex &parent) const { - return list->list->count(list->list); -} - -int TableModel::columnCount(const QModelIndex &parent) const { - return info->columns; -} - -QVariant TableModel::data(const QModelIndex &index, int role) const { - if(role == Qt::DisplayRole) { - UiList *ls = list->list; - void *rowData = ls->get(ls, index.row()); - if(rowData && info->getvalue) { - void *value = info->getvalue(rowData, index.column()); - switch(info->types[index.column()]) { - case UI_STRING: { - return QString::fromUtf8((char*)value); - } - case UI_INTEGER: { - int *intptr = (int*)value; - return QVariant(*intptr); - } - } - } - } - return QVariant(); -} - -QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const { - if(role == Qt::DisplayRole) { - char *label = info->titles[section]; - return QString::fromUtf8(label); - } - return QVariant(); -} - -void TableModel::update() { - emit dataChanged(QModelIndex(),QModelIndex()); -} - -void TableModel::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { - UiListSelection *selection = listSelection(view->selectionModel()); - - UiEvent e; - e.obj = obj; - e.window = obj->window; - e.document = obj->ctx->document; - e.eventdata = selection; - e.intval = selection->count > 0 ? selection->rows[0] : -1; - info->selection(&e, info->userdata); - - if(selection->count > 0) { - delete selection->rows; - } - delete selection; -} - -void TableModel::activate(const QModelIndex &) { - UiListSelection *selection = listSelection(view->selectionModel()); - - UiEvent e; - e.obj = obj; - e.window = obj->window; - e.document = obj->ctx->document; - e.eventdata = selection; - e.intval = selection->count > 0 ? selection->rows[0] : -1; - info->activate(&e, info->userdata); - - if(selection->count > 0) { - delete selection->rows; - } - delete selection; -} diff --git a/ui/qt/model.h b/ui/qt/model.h index b74b186..d9a707d 100644 --- a/ui/qt/model.h +++ b/ui/qt/model.h @@ -39,53 +39,6 @@ #include #include -class ListModel : public QAbstractListModel { - Q_OBJECT - - UiObject *obj; - UiListPtr *list; - ui_model_getvalue_f getvalue; - ui_callback callback; - void *userdata; - QListView *view; - -public: - ListModel(UiObject *obj, QListView *view, UiListPtr *list, ui_model_getvalue_f getvalue, ui_callback f, void *userdata); - - int rowCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - -public slots: - void selectionChanged( - const QItemSelection & selected, - const QItemSelection & deselected); -}; - -class TableModel : public QAbstractTableModel { - Q_OBJECT - - UiObject *obj; - UiListPtr *list; - UiModelInfo *info; - QTreeView *view; -public: - TableModel(UiObject *obj, QTreeView *view, UiListPtr *list, UiModelInfo *info); - - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - - void update(); - -public slots: - void selectionChanged( - const QItemSelection & selected, - const QItemSelection & deselected); - void activate(const QModelIndex &); -}; - -UiListSelection* listSelection(QItemSelectionModel *s); #endif /* MODEL_H */ diff --git a/ui/qt/qt5.pro b/ui/qt/qt5.pro new file mode 100644 index 0000000..60cf702 --- /dev/null +++ b/ui/qt/qt5.pro @@ -0,0 +1,65 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2025 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +TARGET = uitk +TEMPLATE = lib +CONFIG += staticlib warn_off debug +DESTDIR = ../build/lib +MOC_DIR = ../build/ui/qt +OBJECTS_DIR = ../build/ui/qt + +QT += core gui widgets + +DEFINES += UI_QT5 + +SOURCES += toolkit.cpp +SOURCES += window.cpp +SOURCES += menu.cpp +SOURCES += toolbar.cpp +SOURCES += stock.cpp +SOURCES += container.cpp +SOURCES += text.cpp +SOURCES += model.cpp +SOURCES += tree.cpp +SOURCES += button.cpp +SOURCES += label.cpp +SOURCES += graphics.cpp + +HEADERS += toolkit.h +HEADERS += window.h +HEADERS += menu.h +HEADERS += toolbar.h +HEADERS += stock.h +HEADERS += container.h +HEADERS += text.h +HEADERS += model.h +HEADERS += tree.h +HEADERS += button.h +HEADERS += label.h +HEADERS += graphics.h + diff --git a/ui/qt/stock.cpp b/ui/qt/stock.cpp index 43a3ea9..1ead20b 100644 --- a/ui/qt/stock.cpp +++ b/ui/qt/stock.cpp @@ -26,52 +26,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include "stock.h" #include "../ui/properties.h" -static UcxMap *stock_items; -void ui_stock_init() { - stock_items = ucx_map_new(64); - - ui_add_stock_item(UI_STOCK_NEW, "New", "document-new"); - ui_add_stock_item(UI_STOCK_OPEN, "Open", "document-open"); - ui_add_stock_item(UI_STOCK_SAVE, "Save", "document-save"); - ui_add_stock_item(UI_STOCK_SAVE_AS, "Save as ...", "document-save-as"); - ui_add_stock_item(UI_STOCK_REVERT_TO_SAVED, "Revert to saved", "document-revert"); - ui_add_stock_item(UI_STOCK_CLOSE, "Close", "window-close"); - ui_add_stock_item(UI_STOCK_UNDO, "Undo", "edit-undo"); - ui_add_stock_item(UI_STOCK_REDO, "Redo", "edit-redo"); - ui_add_stock_item(UI_STOCK_GO_BACK, "Back", "go-previous"); - ui_add_stock_item(UI_STOCK_GO_FORWARD, "Forward", "go-next"); - ui_add_stock_item(UI_STOCK_CUT, "Cut", "edit-cut"); - ui_add_stock_item(UI_STOCK_COPY, "Copy", "edit-copy"); - ui_add_stock_item(UI_STOCK_PASTE, "Paste", "edit-paste"); - ui_add_stock_item(UI_STOCK_DELETE, "Delete", "edit-delete"); -} - -void ui_add_stock_item(char *id, char *label, char *icon) { - UiStockItem *item = new UiStockItem(label, icon); - ucx_map_cstr_put(stock_items, id, item); -} - -UiStockItem* ui_get_stock_item(char *id) { - UiStockItem *item = (UiStockItem*)ucx_map_cstr_get(stock_items, id); - if(item) { - char *label = uistr_n(id); - if(label) { - item->label = label; - } - } - return item; -} - - -UiStockItem::UiStockItem(char* label, char* icon_name) { - this->label = label; - this->icon_name = icon_name; -} diff --git a/ui/qt/stock.h b/ui/qt/stock.h index f183f6e..f80f1a4 100644 --- a/ui/qt/stock.h +++ b/ui/qt/stock.h @@ -31,19 +31,7 @@ #include "../ui/stock.h" -class UiStockItem { -public: - - char *label; - char *icon_name; - - UiStockItem(char *label, char *icon_name); -}; -void ui_stock_init(); -void ui_add_stock_item(char *id, char *label, char *icon); -UiStockItem* ui_get_stock_item(char *id); - #endif /* STOCK_H */ diff --git a/ui/qt/text.cpp b/ui/qt/text.cpp index 3d7027e..f900ac0 100644 --- a/ui/qt/text.cpp +++ b/ui/qt/text.cpp @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,124 +32,203 @@ #include "../common/context.h" #include "../common/document.h" -UIWIDGET ui_textarea(UiObject *obj, UiText *value) { - QTextDocument *txtdoc = value && value->obj ? (QTextDocument*)value->obj : new QTextDocument(); - - if(value) { - if(value->value && value->obj) { - QString str = QString::fromUtf8(value->value); - txtdoc->setPlainText(str); +/* + * Gets or creates a QTextDocument for the UiText value and initializes it + * with the UiText string value + */ +static QTextDocument* get_or_create_doc(UiText *value) { + QTextDocument *document = nullptr; + if(value->data1) { + document = (QTextDocument*)value->data1; + } else { + document = new QTextDocument(); + if(value->value.ptr) { + QString str = QString::fromUtf8(value->value.ptr); + document->setPlainText(str); } + } + + if(value->value.free) { + value->value.free(value->value.ptr); + } + value->value.ptr = NULL; + value->value.free = NULL; + + return document; +} + +UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + QTextEdit *textarea = new QTextEdit(); + ctn->add(textarea, true); + + QTextDocument *document = nullptr; + + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING); + if(var) { + UiText *value = (UiText*)var->value; + + document = get_or_create_doc(value); + value->save = ui_textarea_save; + value->restore = ui_textarea_restore; + value->destroy = ui_textarea_text_destroy; value->get = ui_textarea_get; value->set = ui_textarea_set; value->getsubstr = ui_textarea_getsubstr; value->insert = ui_textarea_insert; value->setposition = ui_textarea_setposition; value->position = ui_textarea_position; + value->setselection = ui_textarea_setselection; value->selection = ui_textarea_selection; value->length = ui_textarea_length; value->remove = ui_textarea_remove; - value->obj = txtdoc; - value->value = NULL; + value->obj = textarea; + value->data1 = document; + } else { + document = new QTextDocument(); } - UiContainer *ct = uic_get_current_container(obj); - QTextEdit *textedit = new QTextEdit(); - textedit->setDocument(txtdoc); - ct->add(textedit, true); + textarea->setDocument(document); - return textedit; + return textarea; } -UIWIDGET ui_textarea_nv(UiObject *obj, char *varname) { - UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_TEXT); - if(var) { - UiText *value = (UiText*)var->value; - return ui_textarea(obj, value); - } else { - // TODO: error - } - return NULL; +void ui_textarea_save(UiText *text) { + // NOOP +} + +void ui_textarea_restore(UiText *text) { + QTextEdit *textarea = (QTextEdit*)text->obj; + QTextDocument *document = get_or_create_doc(text); + textarea->setDocument(document); } +void ui_textarea_text_destroy(UiText *text) { + QTextDocument *document = (QTextDocument*)text->data1; + if(document) { + delete document; + } +} char* ui_textarea_get(UiText *text) { - if(text->value) { - free(text->value); + // clean previous value + if(text->value.free) { + text->value.free(text->value.ptr); } - QTextDocument *doc = (QTextDocument*)text->obj; + // get string + QTextDocument *doc = (QTextDocument*)text->data1; QString str = doc->toPlainText(); - QByteArray array = str.toLocal8Bit(); + QByteArray array = str.toUtf8(); const char *cstr = array.constData(); - if(text->value) { - free(text->value); - } - text->value = strdup(cstr); - return text->value; + // store a copy of the string in the UiText value + text->value.ptr = strdup(cstr); + text->value.free = free; + return text->value.ptr; } -void ui_textarea_set(UiText *text, char *str) { - // set text - QTextDocument *doc = (QTextDocument*)text->obj; +void ui_textarea_set(UiText *text, const char *str) { + if(text->value.free) { + text->value.free(text->value.ptr); + } + text->value.ptr = NULL; + text->value.free = NULL; + + QTextDocument *doc = (QTextDocument*)text->data1; QString qstr = QString::fromUtf8(str); doc->setPlainText(qstr); - // cleanup - if(text->value) { - free(text->value); - } - text->value = NULL; } char* ui_textarea_getsubstr(UiText *text, int begin, int end) { - QTextDocument *doc = (QTextDocument*)text->obj; - return NULL; // TODO + QTextDocument *doc = (QTextDocument*)text->data1; + QTextCursor cursor(doc); + cursor.setPosition(begin, QTextCursor::MoveAnchor); + cursor.setPosition(end, QTextCursor::KeepAnchor); + QString str = cursor.selectedText(); + QByteArray bytes = str.toUtf8(); + const char *cstr = bytes.constData(); + return cstr ? strdup(cstr) : NULL; } void ui_textarea_insert(UiText *text, int pos, char *str) { - QTextDocument *doc = (QTextDocument*)text->obj; + QTextDocument *doc = (QTextDocument*)text->data1; + QTextCursor cursor(doc); + cursor.setPosition(pos); + cursor.insertText(str); } void ui_textarea_setposition(UiText *text, int pos) { - // TODO + QTextEdit *textview = (QTextEdit*)text->obj; + QTextCursor cursor = textview->textCursor(); + cursor.setPosition(pos); + textview->setTextCursor(cursor); } int ui_textarea_position(UiText *text) { - QTextDocument *doc = (QTextDocument*)text->obj; - return 0; // TODO + QTextEdit *textview = (QTextEdit*)text->obj; + QTextCursor cursor = textview->textCursor(); + return cursor.position(); } void ui_textarea_selection(UiText *text, int *begin, int *end) { - QTextDocument *doc = (QTextDocument*)text->obj; + QTextEdit *textview = (QTextEdit*)text->obj; + QTextCursor cursor = textview->textCursor(); + if(cursor.hasSelection()) { + if(begin) { + *begin = cursor.selectionStart(); + } + if(end) { + *end = cursor.selectionEnd(); + } + } +} + +void ui_textarea_setselection(UiText *text, int begin, int end) { + QTextEdit *textview = (QTextEdit*)text->obj; + QTextCursor cursor = textview->textCursor(); + cursor.setPosition(begin, QTextCursor::MoveAnchor); + cursor.setPosition(end, QTextCursor::KeepAnchor); + textview->setTextCursor(cursor); } int ui_textarea_length(UiText *text) { - QTextDocument *doc = (QTextDocument*)text->obj; - return 0; // TODO + QTextDocument *doc = (QTextDocument*)text->data1; + return doc->characterCount(); } void ui_textarea_remove(UiText *text, int begin, int end) { - QTextDocument *doc = (QTextDocument*)text->obj; + // TODO } +/* ------------------------------ TextField ------------------------------ */ -/* ------------------- TextField ------------------- */ - -UIWIDGET ui_textfield(UiObject *obj, UiString *value) { +static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs args, bool password, bool frameless) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + QLineEdit *textfield = new QLineEdit(); + ctn->add(textfield, false); - UiContainer *ct = uic_get_current_container(obj); - ct->add(textfield, false); + if(password) { + textfield->setEchoMode(QLineEdit::Password); + } - if(value) { - if(value->value) { - QString str = QString::fromUtf8(value->value); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING); + if(var) { + UiString *value = (UiString*)var->value; + if(value->value.ptr) { + QString str = QString::fromUtf8(value->value.ptr); textfield->setText(str); - free(value->value); - value->value = NULL; + if(value->value.free) { + value->value.free(value->value.ptr); + } + value->value.ptr = NULL; } + value->set = ui_textfield_set; value->get = ui_textfield_get; value->obj = textfield; @@ -158,38 +237,40 @@ UIWIDGET ui_textfield(UiObject *obj, UiString *value) { return textfield; } -UIWIDGET ui_textfield_nv(UiObject *obj, char *varname) { - UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_STRING); - if(var) { - UiString *value = (UiString*)var->value; - return ui_textfield(obj, value); - } else { - // TODO: error - } - return NULL; +UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) { + return create_textfield(obj, args, false, false); +} + +UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) { + return create_textfield(obj, args, false, true); +} + +UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) { + return create_textfield(obj, args, true, false); } char* ui_textfield_get(UiString *str) { QLineEdit *textfield = (QLineEdit*)str->obj; QString qstr = textfield->text(); - if(str->value) { - free(str->value); + if(str->value.free) { + str->value.free(str->value.ptr); } - QByteArray array = qstr.toLocal8Bit(); + QByteArray array = qstr.toUtf8(); const char *cstr = array.constData(); - str->value = strdup(cstr); + str->value.ptr = strdup(cstr); + str->value.free = free; - return str->value; + return str->value.ptr; } -void ui_textfield_set(UiString *str, char *value) { +void ui_textfield_set(UiString *str, const char *value) { QLineEdit *textfield = (QLineEdit*)str->obj; QString qstr = QString::fromUtf8(value); textfield->setText(qstr); - if(str->value) { - free(str->value); + if(str->value.free) { + str->value.free(str->value.ptr); } - str->value = NULL; + str->value.ptr = NULL; } diff --git a/ui/qt/text.h b/ui/qt/text.h index 3ca8fd2..fcfe612 100644 --- a/ui/qt/text.h +++ b/ui/qt/text.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,18 +36,24 @@ // value implementations extern "C" { - char* ui_textarea_get(UiText *text); - void ui_textarea_set(UiText *text, char *str); - char* ui_textarea_getsubstr(UiText *text, int begin, int end); - void ui_textarea_insert(UiText *text, int pos, char *str); - void ui_textarea_setposition(UiText *text, int pos); - int ui_textarea_position(UiText *text); - void ui_textarea_selection(UiText *text, int *begin, int *end); - int ui_textarea_length(UiText *text); - void ui_textarea_remove(UiText *text, int begin, int end); - char* ui_textfield_get(UiString *str); - void ui_textfield_set(UiString *str, char *value); +void ui_textarea_save(UiText *text); +void ui_textarea_restore(UiText *text); +void ui_textarea_text_destroy(UiText *text); +char* ui_textarea_get(UiText *text); +void ui_textarea_set(UiText *text, const char *str); +char* ui_textarea_getsubstr(UiText *text, int begin, int end); +void ui_textarea_insert(UiText *text, int pos, char *str); +void ui_textarea_setposition(UiText *text, int pos); +int ui_textarea_position(UiText *text); +void ui_textarea_setselection(UiText *text, int begin, int end); +void ui_textarea_selection(UiText *text, int *begin, int *end); +int ui_textarea_length(UiText *text); +void ui_textarea_remove(UiText *text, int begin, int end); + +char* ui_textfield_get(UiString *str) ; +void ui_textfield_set(UiString *str, const char *value); + } diff --git a/ui/qt/toolbar.cpp b/ui/qt/toolbar.cpp index c810e8c..1128585 100644 --- a/ui/qt/toolbar.cpp +++ b/ui/qt/toolbar.cpp @@ -26,140 +26,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include "toolbar.h" #include "menu.h" #include "stock.h" -static UcxMap *toolbar_items = ucx_map_new(16); -static UcxList *defaults; - -/* ------------------------- UiToolItem ------------------------- */ - -UiToolItem::UiToolItem(char *label, ui_callback f, void *userdata) { - this->label = label; - this->image = NULL; - this->callback = f; - this->userdata = userdata; - this->isimportant = false; - this->groups = NULL; -} - -void UiToolItem::addGroup(int group) { - groups = ucx_list_append(groups, (void*)(intptr_t)group); -} - -void UiToolItem::addTo(UiObject *obj, QToolBar *toolbar) { - QString str = QString::fromUtf8(label); - UiAction *action = new UiAction(obj, str, callback, userdata); - action->setIcon(QIcon::fromTheme(image)); - toolbar->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); -} - - -/* ------------------------- UiStockToolItem ------------------------- */ - -UiStockToolItem::UiStockToolItem(char *stockid, ui_callback f, void *userdata) { - this->stockid = stockid; - this->callback = f; - this->userdata = userdata; - this->isimportant = false; - this->groups = NULL; -} - -void UiStockToolItem::addGroup(int group) { - groups = ucx_list_append(groups, (void*)(intptr_t)group); -} - -void UiStockToolItem::addTo(UiObject *obj, QToolBar *toolbar) { - UiStockItem *stockItem = ui_get_stock_item(stockid); - QString str = QString::fromUtf8(stockItem->label); - - UiAction *action = new UiAction(obj, str, callback, userdata); - action->setIcon(QIcon::fromTheme(stockItem->icon_name)); - toolbar->addAction(action); - QObject::connect(action, SIGNAL(triggered()), action, SLOT(trigger())); -} - - - -void ui_toolitem_vstgr( - char *name, - char *stockid, - int isimportant, - ui_callback f, - void *userdata, - va_list ap) -{ - UiStockToolItem *item = new UiStockToolItem(stockid, f, userdata); - item->isimportant = isimportant; - - // add groups - int group; - while((group = va_arg(ap, int)) != -1) { - item->addGroup(group); - } - - ucx_map_cstr_put(toolbar_items, name, item); -} - -void ui_toolitem_img(char *name, char *label, char *img, ui_callback f, void *udata) { - UiToolItem *item = new UiToolItem(label, f, udata); - item->image = img; - item->isimportant = false; - - ucx_map_cstr_put(toolbar_items, name, item); -} - -void ui_toolitem(char *name, char *label, ui_callback f, void *udata) { - ui_toolitem_img(name, label, NULL, f, udata); -} - -void ui_toolitem_st(char *name, char *stockid, ui_callback f, void *userdata) { - ui_toolitem_stgr(name, stockid, f, userdata, -1); -} - -void ui_toolitem_sti(char *name, char *stockid, ui_callback f, void *userdata) { - ui_toolitem_stgri(name, stockid, f, userdata, -1); -} - -void ui_toolitem_stgr(char *name, char *stockid, ui_callback f, void *userdata, ...) { - va_list ap; - va_start(ap, userdata); - ui_toolitem_vstgr(name, stockid, 0, f, userdata, ap); - va_end(ap); -} - -void ui_toolitem_stgri(char *name, char *stockid, ui_callback f, void *userdata, ...) { - va_list ap; - va_start(ap, userdata); - ui_toolitem_vstgr(name, stockid, 1, f, userdata, ap); - va_end(ap); -} - - -void ui_toolbar_add_default(char *name) { - char *s = strdup(name); - defaults = ucx_list_append(defaults, s); -} - - -QToolBar* ui_create_toolbar(UiObject *obj) { - QToolBar *toolbar = new QToolBar(); - - UCX_FOREACH(elm, defaults) { - UiToolItemI *item = (UiToolItemI*)ucx_map_cstr_get(toolbar_items, (char*)elm->data); - if(item) { - item->addTo(obj, toolbar); - } else if(!strcmp((char*)elm->data, "@separator")) { - - } else { - fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", elm->data); - } - } - - return toolbar; -} diff --git a/ui/qt/toolbar.h b/ui/qt/toolbar.h index 77f059e..7a4dc2a 100644 --- a/ui/qt/toolbar.h +++ b/ui/qt/toolbar.h @@ -31,52 +31,9 @@ #include "toolkit.h" #include "../ui/toolbar.h" -#include #include -class UiToolItemI { -public: - virtual void addTo(UiObject *obj, QToolBar *toolbar) = 0; -}; -class UiToolItem : public UiToolItemI { -public: - char *label; - char *image; - ui_callback callback; - void *userdata; - UcxList *groups; - bool isimportant; - - UiToolItem(char *label, ui_callback f, void *userdata); - void addGroup(int group); - virtual void addTo(UiObject *obj, QToolBar *toolbar); -}; - -class UiStockToolItem : public UiToolItemI { -public: - char *stockid; - ui_callback callback; - void *userdata; - UcxList *groups; - bool isimportant; - - UiStockToolItem(char *stockid, ui_callback f, void *userdata); - void addGroup(int group); - virtual void addTo(UiObject *obj, QToolBar *toolbar); -}; - - -void ui_toolitem_vstgr( - char *name, - char *stockid, - int isimportant, - ui_callback f, - void *userdata, - va_list ap); - - -QToolBar* ui_create_toolbar(UiObject *obj); #endif /* TOOLBAR_H */ diff --git a/ui/qt/toolkit.cpp b/ui/qt/toolkit.cpp index 13c8f29..3db9203 100644 --- a/ui/qt/toolkit.cpp +++ b/ui/qt/toolkit.cpp @@ -35,18 +35,25 @@ #include "../common/document.h" #include "../common/properties.h" +#include "../common/menu.h" +#include "../common/toolbar.h" -static char *application_name; +static const char *application_name; -static ui_callback appclose_fnc; -static void *appclose_udata; +static ui_callback startup_func; +static void *startup_data; +static ui_callback open_func; +void *open_data; +static ui_callback exit_func; +void *exit_data; + +static int is_toplevel_realized = 0; -//static QApplication app(qargc, qargv); int app_argc; char **app_argv; QApplication *application = NULL; -void ui_init(char *appname, int argc, char **argv) { +void ui_init(const char *appname, int argc, char **argv) { application_name = appname; app_argc = argc; @@ -54,30 +61,39 @@ void ui_init(char *appname, int argc, char **argv) { application = new QApplication(app_argc, app_argv); uic_docmgr_init(); + uic_menu_init(); + uic_toolbar_init(); uic_load_app_properties(); - - ui_stock_init(); + } -char* ui_appname() { +const char* ui_appname() { return application_name; } -void ui_exitfunc(ui_callback f, void *udata) { - appclose_fnc = f; - appclose_udata = udata; +void ui_onstartup(ui_callback f, void *userdata) { + startup_func = f; + startup_data = userdata; } -void ui_openfilefunc(ui_callback f, void *userdata) { - // OS X only +void ui_onopen(ui_callback f, void *userdata) { + open_func = f; + open_data = userdata; +} + +void ui_onexit(ui_callback f, void *userdata) { + exit_func = f; + exit_data = userdata; } void ui_main() { + if(startup_func) { + startup_func(NULL, startup_data); + } application->exec(); - - if(appclose_fnc) { - appclose_fnc(NULL, appclose_udata); + if(exit_func) { + exit_func(NULL, exit_data); } uic_store_app_properties(); @@ -103,6 +119,7 @@ void ui_set_visible(UIWIDGET widget, int visible) { +/* --------------------- Implemtation UiEventWrapper --------------------- */ UiEventWrapper::UiEventWrapper(UiObject *obj, ui_callback f, void* userdata) { this->obj = obj; @@ -111,11 +128,64 @@ UiEventWrapper::UiEventWrapper(UiObject *obj, ui_callback f, void* userdata) { } void UiEventWrapper::slot() { + if(!callback) { + return; + } + + UiEvent e; + e.obj = obj; + e.window = obj->window; + e.document = obj->ctx->document; + e.eventdata = NULL; + e.intval = 0; + e.set = ui_get_setop(); + if(prepare_event) { + prepare_event(&e, this); + } + callback(&e, userdata); + + // TODO: notify var observers +} + +void UiEventWrapper::destroy() { + delete this; +} + + +/* --------------------- Implemtation UiAction --------------------- */ + +UiAction::UiAction(UiObject *obj, QString &label, ui_callback f, void *userdata) : QAction(label, NULL) { + this->obj = obj; + this->callback = f; + this->userdata = userdata; +} + +UiAction::~UiAction() { + +} + +void UiAction::trigger() { + if(!callback) { + return; + } + UiEvent e; e.obj = obj; e.window = obj->window; e.document = obj->ctx->document; e.eventdata = NULL; e.intval = 0; + e.set = ui_get_setop(); + if(prepare_event) { + prepare_event(&e, this); + } callback(&e, userdata); + + // TODO: notify var observers +} + +// ui_enablefunc for UiAction +void ui_action_enable(UiAction *action, int enable) { + action->setEnabled((bool)enable); } + diff --git a/ui/qt/toolkit.h b/ui/qt/toolkit.h index f767ef6..1db8df7 100644 --- a/ui/qt/toolkit.h +++ b/ui/qt/toolkit.h @@ -35,20 +35,62 @@ #include +class UiEventWrapper; + +typedef void (*ui_prepare_event_func)(UiEvent *event, UiEventWrapper *wrapper); + class UiEventWrapper : public QObject { Q_OBJECT UiObject *obj; ui_callback callback; void *userdata; - + public: + UiVar *var; + + void *customdata1 = nullptr; + void *customdata2 = nullptr; + int customvalue1 = 0; + int customvalue2 = 0; + + ui_prepare_event_func prepare_event = nullptr; + UiEventWrapper(UiObject *obj, ui_callback f, void *userdata); public slots: void slot(); + void destroy(); +}; + +class UiAction; + +typedef void (*ui_prepare_action_event_func)(UiEvent *event, UiAction *action); + +class UiAction : public QAction { + Q_OBJECT + + UiObject *obj; + ui_callback callback; + void *userdata; + +public: + UiVar *var; + + ui_prepare_action_event_func prepare_event = nullptr; + void *customdata1 = nullptr; + void *customdata2 = nullptr; + int customvalue1 = 0; + int customvalue2 = 0; + + UiAction(UiObject *obj, QString &label, ui_callback f, void *userdata); + ~UiAction(); + +private slots: + void trigger(); }; +void ui_action_enable(UiAction *action, int enable); #endif /* TOOLKIT_H */ diff --git a/ui/qt/tree.cpp b/ui/qt/tree.cpp index d62b20c..336041a 100644 --- a/ui/qt/tree.cpp +++ b/ui/qt/tree.cpp @@ -34,109 +34,3 @@ #include -extern "C" void* ui_strmodel_getvalue(void *elm, int column) { - return column == 0 ? elm : NULL; -} - -UIWIDGET ui_listview_str(UiObject *obj, UiList *list, ui_callback f, void *udata) { - return ui_listview(obj, list, ui_strmodel_getvalue, f, udata); -} -UIWIDGET ui_listview_var(UiObject *obj, UiListPtr *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata) { - QListView *view = new QListView(); - ListModel *model = new ListModel(obj, view, list, getvalue, f, udata); - view->setModel(model); - - // TODO: observer update - - QItemSelectionModel *s = view->selectionModel(); - QObject::connect( - s, - SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - model, - SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); - - UiContainer *ct = uic_get_current_container(obj); - ct->add(view, true); - return view; -} - -UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_model_getvalue_f getvalue, ui_callback f, void *udata) { - UiListPtr *listptr = (UiListPtr*)ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListPtr)); - listptr->list = list; - return ui_listview_var(obj, listptr, getvalue, f, udata); -} - -UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_model_getvalue_f getvalue, ui_callback f, void *udata) { - UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - UiListVar *value = (UiListVar*)var->value; - return ui_listview_var(obj, value->listptr, getvalue, f, udata); - } else { - // TODO: error - } - return NULL; -} - - -UIWIDGET ui_table_var(UiObject *obj, UiListPtr *list, UiModelInfo *modelinfo) { - QTreeView *view = new QTreeView(); - TableModel *model = new TableModel(obj, view, list, modelinfo); - view->setModel(model); - - view->setItemsExpandable(false); - view->setRootIsDecorated(false); - - // TODO: observer update - UiTableView *u = new UiTableView(); - u->widget = view; - u->model = model; - list->list->observers = ui_add_observer( - list->list->observers, - (ui_callback)ui_table_update, - u); - - view->setSelectionMode(QAbstractItemView::ExtendedSelection); - QItemSelectionModel *s = view->selectionModel(); - QObject::connect( - s, - SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - model, - SLOT(selectionChanged(const QItemSelection &, const QItemSelection &))); - QObject::connect( - view, - SIGNAL(doubleClicked(const QModelIndex &)), - model, - SLOT(activate(const QModelIndex &))); - - - UiContainer *ct = uic_get_current_container(obj); - ct->add(view, true); - return view; -} - -void ui_table_update(UiEvent *event, UiTableView *view) { - // TODO - printf("update\n"); - - //view->model->update(); - view->widget->setModel(NULL); - view->widget->setModel(view->model); -} - -UIWIDGET ui_table(UiObject *obj, UiList *list, UiModelInfo *modelinfo) { - UiListPtr *listptr = (UiListPtr*)ucx_mempool_malloc(obj->ctx->mempool, sizeof(UiListPtr)); - listptr->list = list; - return ui_table_var(obj, listptr, modelinfo); -} - -UIWIDGET ui_table_nv(UiObject *obj, char *varname, UiModelInfo *modelinfo) { - UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - UiListVar *value = (UiListVar*)var->value; - return ui_table_var(obj, value->listptr, modelinfo); - } else { - // TODO: error - } - return NULL; -} - diff --git a/ui/qt/tree.h b/ui/qt/tree.h index 54dd0cd..664b32b 100644 --- a/ui/qt/tree.h +++ b/ui/qt/tree.h @@ -34,13 +34,7 @@ #include -class UiTableView { -public: - QTreeView *widget; - TableModel *model; -}; -extern "C" void ui_table_update(UiEvent *event, UiTableView *view); #endif /* TREE_H */ diff --git a/ui/qt/window.cpp b/ui/qt/window.cpp index 119ea3e..a30dc6b 100644 --- a/ui/qt/window.cpp +++ b/ui/qt/window.cpp @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include "../common/context.h" #include "window.h" @@ -36,34 +36,36 @@ #include #include +#include -static UiObject* create_window(char *title, void *window_data, bool simple) { - UcxMempool *mp = ucx_mempool_new(256); - UiObject *obj = (UiObject*)ucx_mempool_calloc(mp, 1, sizeof(UiObject)); +static UiObject* create_window(const char *title, void *window_data, bool simple) { + CxMempool *mp = cxMempoolCreateSimple(256); + UiObject *obj = (UiObject*)cxCalloc(mp->allocator, 1, sizeof(UiObject)); obj->ctx = uic_context(obj, mp); obj->window = window_data; obj->next = NULL; QMainWindow *window = new QMainWindow(); + window->setWindowTitle(title); obj->widget = window; if(!simple) { ui_add_menus(obj, window); - QToolBar *toolbar = ui_create_toolbar(obj); - window->addToolBar(Qt::TopToolBarArea, toolbar); + //QToolBar *toolbar = ui_create_toolbar(obj); + //window->addToolBar(Qt::TopToolBarArea, toolbar); } QBoxLayout *box = new QVBoxLayout(); QWidget *boxWidget = new QWidget(); boxWidget->setLayout(box); window->setCentralWidget(boxWidget); - obj->container = new UiBoxContainer(box); + ui_container_add(obj, new UiBoxContainer(box)); obj->widget = window; return obj; } -UiObject* ui_window(char *title, void *window_data) { +UiObject* ui_window(const char *title, void *window_data) { return create_window(title, window_data, FALSE); } diff --git a/ui/ui/container.h b/ui/ui/container.h index faa91e7..3f828ea 100644 --- a/ui/ui/container.h +++ b/ui/ui/container.h @@ -259,6 +259,7 @@ struct UiContainerX { #define ui_hbox_w(obj, w, ...) for(w = ui_hbox_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_grid_w(obj, w, ...) for(w = ui_grid_create(obj, (UiContainerArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_tabview_w(obj, w, ...) for(w = ui_tabview_create(obj, (UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) +#define ui_scrolledwindow_w(obj, w, ...) for(w = ui_scrolledwindow_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_hsplitpane(obj, ...) for(ui_hsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_vsplitpane(obj, ...) for(ui_vsplitpane_create(obj, (UiSplitPaneArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) diff --git a/ui/ui/image.h b/ui/ui/image.h index 94ab8a6..d54c9e9 100644 --- a/ui/ui/image.h +++ b/ui/ui/image.h @@ -51,6 +51,13 @@ typedef struct UiImageViewerArgs { UiBool scrollarea; UiBool autoscale; + UiBool adjustwidgetsize; + UiBool useradjustable; + int image_padding; + int image_padding_left; + int image_padding_right; + int image_padding_top; + int image_padding_bottom; UiGeneric *value; const char *varname; UiMenuBuilder *contextmenu; @@ -60,6 +67,11 @@ typedef struct UiImageViewerArgs { UIEXPORT UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args); +UIEXPORT UIWIDGET ui_imageviewer_reset(UIWIDGET w); +UIEXPORT UIWIDGET ui_imageviewer_set_autoscale(UIWIDGET w, UiBool set); +UIEXPORT UIWIDGET ui_imageviewer_set_adjustwidgetsize(UIWIDGET w, UiBool set); +UIEXPORT UIWIDGET ui_imageviewer_set_useradjustable(UIWIDGET w, UiBool set); + UIEXPORT int ui_image_load_file(UiGeneric *obj, const char *path); #ifdef __cplusplus diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index 732473c..2af07c5 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -30,6 +30,7 @@ #define UI_TOOLKIT_H #include +#include #ifdef UI_COCOA @@ -60,24 +61,41 @@ typedef void* UIMENU; // NSMenu* #include #endif -#elif UI_MOTIF - -#include -#define UIWIDGET Widget -#define UIMENU Widget - #elif defined(UI_QT4) || defined(UI_QT5) +#define UI_QT + #ifdef __cplusplus + #include #include #include + #define UIWIDGET QWidget* +#define UIWINDOW QWidget* #define UIMENU QMenu* #else /* __cplusplus */ #define UIWIDGET void* +#define UIWINDOW void* #define UIMENU void* #endif +#elif UI_MOTIF + +#include +#define UIWIDGET Widget +#define UIMENU Widget + + +#elif UI_WIN32 + +#include + +#define UIEXPORT __declspec(dllexport) + +#define UIWIDGET void* +#define UIWINDOW void* +#define UIMENU void* + #elif UI_WINUI #define UIEXPORT __declspec(dllexport) @@ -193,16 +211,29 @@ typedef struct UiThreadpool UiThreadpool; typedef struct UiTabbedPane UiTabbedPane; -typedef enum UiTri UiTri; -typedef enum UiLabelType UiLabelType; +typedef enum UiTri { + UI_DEFAULT = 0, + UI_ON, + UI_OFF +} UiTri; -typedef enum UiDnDAction UiDnDAction; enum UiMouseEventType { UI_PRESS = 0, UI_PRESS2 }; -enum UiLabelType { UI_LABEL_DEFAULT, UI_LABEL_TEXT, UI_LABEL_ICON, UI_LABEL_TEXT_ICON }; - -enum UiDnDAction { UI_DND_ACTION_NONE, UI_DND_ACTION_COPY, UI_DND_ACTION_MOVE, UI_DND_ACTION_LINK, UI_DND_ACTION_CUSTOM }; +typedef enum UiLabelType { + UI_LABEL_DEFAULT, + UI_LABEL_TEXT, + UI_LABEL_ICON, + UI_LABEL_TEXT_ICON +} UiLabelType; + +typedef enum UiDnDAction { + UI_DND_ACTION_NONE, + UI_DND_ACTION_COPY, + UI_DND_ACTION_MOVE, + UI_DND_ACTION_LINK, + UI_DND_ACTION_CUSTOM +} UiDnDAction; typedef void(*ui_callback)(UiEvent*, void*); /* event, user data */ @@ -346,6 +377,7 @@ struct UiText { void (*insert)(UiText*, int, char*); void (*setposition)(UiText*,int); int (*position)(UiText*); + void (*setselection)(UiText*, int, int); /* text, begin, end */ void (*selection)(UiText*, int*, int*); /* text, begin, end */ int (*length)(UiText*); void (*remove)(UiText*, int, int); /* text, begin, end */ @@ -428,12 +460,6 @@ struct UiRange { UiObserver *observers; }; -enum UiTri { - UI_DEFAULT = 0, - UI_ON, - UI_OFF -}; - struct UiFileList { char **files; size_t nfiles; diff --git a/ui/ui/widget.h b/ui/ui/widget.h index 3ac2e15..e08233d 100644 --- a/ui/ui/widget.h +++ b/ui/ui/widget.h @@ -49,12 +49,16 @@ typedef struct UiWidgetArgs { #ifdef UI_GTK typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata); +#elif defined(UI_QT) +typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata); #elif defined(UI_MOTIF) typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata, Widget parent, Arg *a, int n); #elif defined(UI_COCOA) typedef UIWIDGET (*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata); #elif defined(UI_WINUI) typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata); +#elif defined(UI_WIN32) +typedef UIWIDGET(*ui_createwidget_func)(UiObject *obj, UiWidgetArgs args, void *userdata); #endif UIEXPORT UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args); @@ -65,6 +69,9 @@ UIEXPORT UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args); #define ui_separator(obj, ...) ui_separator_create(obj, &(UiWidgetArgs){ __VA_ARGS__ } ) +UIEXPORT void ui_widget_set_size(UIWIDGET w, int width, int height); +UIEXPORT void ui_widget_redraw(UIWIDGET w); + #ifdef __cplusplus } diff --git a/ui/win32/Makefile b/ui/win32/Makefile new file mode 100644 index 0000000..97b3d25 --- /dev/null +++ b/ui/win32/Makefile @@ -0,0 +1,33 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2012 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +$(WIN32_OBJPRE)%.obj: win32/%.c + $(CC) -o $@ -c -I../ucx $(CFLAGS) $(TK_CFLAGS) $< + +$(UI_LIB): $(OBJ) + $(AR) $(ARFLAGS) $(UI_LIB) $(OBJ) diff --git a/ui/win32/objs.mk b/ui/win32/objs.mk new file mode 100644 index 0000000..e74d9c6 --- /dev/null +++ b/ui/win32/objs.mk @@ -0,0 +1,35 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2012 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +WIN32_SRC_DIR = ui/win32/ +WIN32_OBJPRE = $(OBJ_DIR)$(WIN32_SRC_DIR) + +WIN32OBJ = toolkit.obj + +TOOLKITOBJS += $(WIN32OBJ:%=$(WIN32_OBJPRE)%) +TOOLKITSOURCE += $(WIN32OBJ:%.obj=win32/%.c) diff --git a/ui/win32/toolkit.c b/ui/win32/toolkit.c new file mode 100644 index 0000000..4afbc73 --- /dev/null +++ b/ui/win32/toolkit.c @@ -0,0 +1,85 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "toolkit.h" +#include "Windows.h" + +#include "../common/properties.h" + +#include +#include + +static const char *application_name; + +static ui_callback startup_func; +static void *startup_data; +static ui_callback open_func; +void *open_data; +static ui_callback exit_func; +void *exit_data; + +void ui_init(const char *appname, int argc, char **argv) { + application_name = appname; +} + +const char* ui_appname() { + return application_name; +} + +void ui_onstartup(ui_callback f, void *userdata) { + startup_func = f; + startup_data = userdata; +} + +void ui_onopen(ui_callback f, void *userdata) { + open_func = f; + open_data = userdata; +} + +void ui_onexit(ui_callback f, void *userdata) { + exit_func = f; + exit_data = userdata; +} + +void ui_main() { + if(startup_func) { + startup_func(NULL, startup_data); + } + + // event loop + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if(exit_func) { + exit_func(NULL, exit_data); + } + uic_store_app_properties(); +} diff --git a/ui/win32/toolkit.h b/ui/win32/toolkit.h new file mode 100644 index 0000000..3b5071c --- /dev/null +++ b/ui/win32/toolkit.h @@ -0,0 +1,48 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TOOLKIT_H +#define TOOLKIT_H + +#include +#include "../ui/toolkit.h" +#include "../common/context.h" +#include "../common/object.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif /* TOOLKIT_H */ +