From: Olaf Wintermann Date: Tue, 17 Dec 2024 20:25:25 +0000 (+0100) Subject: add empty window X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=1c1775482be98bed247efa2a50e86e66d9d16333;p=note.git add empty window --- diff --git a/application/Makefile b/application/Makefile index 1ab56e2..58cbacd 100644 --- a/application/Makefile +++ b/application/Makefile @@ -32,13 +32,17 @@ include ../config.mk CFLAGS += -I../ui/ -I../ucx -I.. SRC = main.c +SRC += application.c +SRC += window.c OBJ = $(SRC:%.c=../build/application/%.$(OBJ_EXT)) + +APP_BIN = ../build/bin/note$(APP_EXT) -all: ../build/bin/idav$(APP_EXT) +all: $(APP_BIN) -../build/bin/idav$(APP_EXT): $(OBJ) $(BUILD_ROOT)/build/lib/libuitk.a - $(CC) -o ../build/bin/idav$(APP_EXT) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx -lidav $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) +$(APP_BIN): $(OBJ) $(BUILD_ROOT)/build/lib/libuitk.a + $(CC) -o $(APP_BIN) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx -lidav $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) ../build/application/%.$(OBJ_EXT): %.c $(CC) $(CFLAGS) $(TK_CFLAGS) $(DAV_CFLAGS) -o $@ -c $< diff --git a/application/application.c b/application/application.c new file mode 100644 index 0000000..d78e430 --- /dev/null +++ b/application/application.c @@ -0,0 +1,34 @@ +/* + * 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 "application.h" +#include "window.h" + +void application_startup(UiEvent *event, void *data) { + window_create(); +} diff --git a/application/application.h b/application/application.h new file mode 100644 index 0000000..1859d7a --- /dev/null +++ b/application/application.h @@ -0,0 +1,45 @@ +/* + * 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 APPLICATION_H +#define APPLICATION_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void application_startup(UiEvent *event, void *data); + + +#ifdef __cplusplus +} +#endif + +#endif /* APPLICATION_H */ + diff --git a/application/main.c b/application/main.c index 45d80ef..5fb3c4c 100644 --- a/application/main.c +++ b/application/main.c @@ -35,8 +35,11 @@ #include +#include "application.h" + int app_main(int argc, char **argv) { - ui_init("notes", argc, argv); + ui_init("note", argc, argv); + ui_onstartup(application_startup, NULL); ui_main(); return 0; } diff --git a/application/window.c b/application/window.c new file mode 100644 index 0000000..aa3013f --- /dev/null +++ b/application/window.c @@ -0,0 +1,41 @@ +/* + * 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 "window.h" + + +void window_create() { + UiObject *obj = ui_sidebar_window("note", NULL); + + UiSubList sublists[] = { NULL }; + ui_sidebar(obj) { + ui_sourcelist(obj, .sublists = sublists); + } + + ui_show(obj); +} diff --git a/application/window.h b/application/window.h new file mode 100644 index 0000000..23c2125 --- /dev/null +++ b/application/window.h @@ -0,0 +1,46 @@ +/* + * 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 WINDOW_H +#define WINDOW_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void window_create(); + + +#ifdef __cplusplus +} +#endif + +#endif /* WINDOW_H */ + diff --git a/ui/cocoa/EventData.h b/ui/cocoa/EventData.h new file mode 100644 index 0000000..31f0107 --- /dev/null +++ b/ui/cocoa/EventData.h @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#import "../ui/toolkit.h" +#import "../common/context.h" + +@interface EventData : NSObject +@property UiObject *obj; +@property ui_callback callback; +@property void *userdata; +@property void *data; +@property int value; + +- (EventData*)init:(ui_callback)cb userdata:(void*)userdata; + +- (void)handleEvent:(id)sender; + +@end diff --git a/ui/cocoa/EventData.m b/ui/cocoa/EventData.m new file mode 100644 index 0000000..85992f1 --- /dev/null +++ b/ui/cocoa/EventData.m @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#import "EventData.h" + +@implementation EventData + +- (EventData*)init:(ui_callback)cb userdata:(void*)userdata { + _callback = cb; + _userdata = userdata; + return self; +} + +- (void)handleEvent:(id)sender { + if(self.callback) { + UiEvent event; + event.obj = self.obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + event.eventdata = self.data; + event.intval = self.value; + self.callback(&event, self.userdata); + } +} + + +@end diff --git a/ui/cocoa/GridLayout.h b/ui/cocoa/GridLayout.h new file mode 100644 index 0000000..0817a6d --- /dev/null +++ b/ui/cocoa/GridLayout.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#import "toolkit.h" + +#import "Container.h" + +#import + +typedef struct GridElm { + NSView *view; + int margin; + int x; + int y; + int colspan; + int rowspan; + BOOL hexpand; + BOOL vexpand; + BOOL hfill; + BOOL vfill; +} GridElm; + +typedef struct GridDef { + int size; + int pos; + int preferred_size; + BOOL extend; +} GridDef; + +@interface GridLayout : NSView + +@property int columnspacing; +@property int rowspacing; +@property CxList *children; +@property NSSize preferredSize; + +@property NSButton *test; + +@property int x; +@property int y; +@property int cols; +@property int rows; + +- (GridLayout*)init; + +@end diff --git a/ui/cocoa/GridLayout.m b/ui/cocoa/GridLayout.m new file mode 100644 index 0000000..51095f4 --- /dev/null +++ b/ui/cocoa/GridLayout.m @@ -0,0 +1,214 @@ +/* + * 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. + */ + +#import "GridLayout.h" + + + +@implementation GridLayout + +@synthesize label=_label; +@synthesize uilayout=_uilayout; +@synthesize newline=_newline; + +- (GridLayout*)init { + self = [super init]; + _columnspacing = 0; + _rowspacing = 0; + _children = cxArrayListCreateSimple(sizeof(GridElm), 32); + + return self; +} + +/* +- (void) layout { + [super layout]; + + NSRect r1 = _test.frame; + NSSize s1 = _test.intrinsicContentSize; + NSEdgeInsets e1 = _test.alignmentRectInsets; + + printf("fuck\n"); +} + */ + + +- (void) layout { + int ncols = _cols+1; + int nrows = _rows+1; + + GridDef *coldef = calloc(ncols, sizeof(GridDef)); + GridDef *rowdef = calloc(nrows, sizeof(GridDef)); + + NSRect viewFrame = self.frame; + + int colspacing = _columnspacing; + int rowspacing = _rowspacing; + + CxIterator i = cxListIterator(_children); + cx_foreach(GridElm *, elm, i) { + NSSize size = elm->view.intrinsicContentSize; + NSEdgeInsets alignment = elm->view.alignmentRectInsets; + if(size.width != NSViewNoIntrinsicMetric) { + CGFloat width = size.width + alignment.left + alignment.right; + if(width > coldef[elm->x].preferred_size) { + coldef[elm->x].preferred_size = width; + } + } + if(size.height != NSViewNoIntrinsicMetric) { + CGFloat height = size.height + alignment.top + alignment.right; + //CGFloat height = size.height; + if(height > rowdef[elm->y].preferred_size) { + rowdef[elm->y].preferred_size = height; + } + } + + if(elm->hexpand) { + coldef[elm->x].extend = TRUE; + } + if(elm->vexpand) { + rowdef[elm->y].extend = TRUE; + } + } + + int col_ext = 0; + int row_ext = 0; + + int preferred_width = 0; + int preferred_height = 0; + for(int j=0;jextend) { + col->size = col->preferred_size + hext; + } else { + col->size = col->preferred_size; + } + } + for(int j=0;jextend) { + row->size = row->preferred_size + vext; + } else { + row->size = row->preferred_size; + } + } + + int pos = 0; + for(int j=0;jview.intrinsicContentSize; + GridDef *col = &coldef[elm->x]; + GridDef *row = &rowdef[elm->y]; + + NSEdgeInsets alignment = elm->view.alignmentRectInsets; + NSRect frame; + frame.size.width = col->size; + frame.size.height = row->size; + 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); + elm->view.frame = frame; + } + + free(coldef); + free(rowdef); +} + + +- (NSSize)intrinsicContentSize { + return self.preferredSize; +} + +- (void) addView:(NSView*)view fill:(BOOL)fill { + if(_newline) { + _y++; + _x = 0; + _newline = FALSE; + } + + GridElm elm; + elm.x = _x; + elm.y = _y; + 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; + elm.view = view; + cxListAdd(_children, &elm); + + [self addSubview:view]; + self.needsLayout = YES; + + if(_x > _cols) { + _cols = _x; + } + if(_y > _rows) { + _rows = _y; + } + _x++; +} + +- (void) dealloc { + cxListDestroy(_children); +} + +@end diff --git a/ui/cocoa/MainWindow.h b/ui/cocoa/MainWindow.h new file mode 100644 index 0000000..50e2eef --- /dev/null +++ b/ui/cocoa/MainWindow.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#import "toolkit.h" +#import "../ui/window.h" + +@interface MainWindow : NSWindow + +@property UiObject *uiobj; + +- (MainWindow*)init:(UiObject*)obj; + +@end diff --git a/ui/cocoa/MainWindow.m b/ui/cocoa/MainWindow.m new file mode 100644 index 0000000..a46ab57 --- /dev/null +++ b/ui/cocoa/MainWindow.m @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#import "MainWindow.h" +#import "Container.h" +#import "GridLayout.h" +#import "../common/object.h" + +@implementation MainWindow + +- (MainWindow*)init:(UiObject*)obj { + self.uiobj = obj; + NSRect frame = NSMakeRect(300, 200, 600, 500); + + self = [self initWithContentRect:frame + styleMask:NSWindowStyleMaskTitled | + NSWindowStyleMaskResizable | + NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable + backing:NSBackingStoreBuffered + defer:false]; + + // create a vertical stackview as default container + //BoxContainer *vbox = [[BoxContainer alloc] init:NSUserInterfaceLayoutOrientationVertical spacing:0]; + GridLayout *vbox = [[GridLayout alloc] init]; + vbox.translatesAutoresizingMaskIntoConstraints = false; + [self.contentView addSubview:vbox]; + [NSLayoutConstraint activateConstraints:@[ + [vbox.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:4], + [vbox.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor], + [vbox.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor], + [vbox.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor] + ]]; + + uic_object_push_container(obj, ui_create_container(obj, vbox)); + + return self; +} + +@end diff --git a/ui/cocoa/Makefile b/ui/cocoa/Makefile index 8c13a4f..08304f4 100644 --- a/ui/cocoa/Makefile +++ b/ui/cocoa/Makefile @@ -27,7 +27,7 @@ # $(COCOA_OBJPRE)%.o: cocoa/%.m - $(CC) -o $@ -c $(CFLAGS) $< + $(CC) -o $@ -c -I../ucx -fobjc-arc $(CFLAGS) $(TK_CFLAGS) $< $(UI_LIB): $(OBJ) $(AR) $(ARFLAGS) $(UI_LIB) $(OBJ) diff --git a/ui/cocoa/UiJob.h b/ui/cocoa/UiJob.h new file mode 100644 index 0000000..a4c5988 --- /dev/null +++ b/ui/cocoa/UiJob.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#import "toolkit.h" + diff --git a/ui/cocoa/UiJob.m b/ui/cocoa/UiJob.m new file mode 100644 index 0000000..b3e0830 --- /dev/null +++ b/ui/cocoa/UiJob.m @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#import "UiJob.h" diff --git a/ui/cocoa/WindowManager.h b/ui/cocoa/WindowManager.h new file mode 100644 index 0000000..7f1b225 --- /dev/null +++ b/ui/cocoa/WindowManager.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#import "toolkit.h" + +@interface WindowManager : NSObject + +@property NSMutableArray *windows; + ++ (WindowManager*) sharedWindowManager; + +- (WindowManager*)init; + +- (void)addWindow:(NSWindow*)win; + +@end diff --git a/ui/cocoa/WindowManager.m b/ui/cocoa/WindowManager.m new file mode 100644 index 0000000..ca03182 --- /dev/null +++ b/ui/cocoa/WindowManager.m @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#import "WindowManager.h" + +@implementation WindowManager + +static WindowManager *instance = nil; + ++ (WindowManager*) sharedWindowManager { + if(instance == nil) { + instance = [[WindowManager alloc] init]; + } + return instance; +} + +- (WindowManager*)init { + _windows = [[NSMutableArray alloc] initWithCapacity:16]; + return self; +} + +- (void)addWindow:(NSWindow*)win { + [_windows addObject:win]; + [win setDelegate:self]; +} + +- (void) windowWillClose:(NSNotification *) notification { + NSWindow *window = notification.object; + [_windows removeObject:window]; +} + +@end diff --git a/ui/cocoa/appdelegate.h b/ui/cocoa/appdelegate.h new file mode 100644 index 0000000..7c2ce1e --- /dev/null +++ b/ui/cocoa/appdelegate.h @@ -0,0 +1,37 @@ +/* + * 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 "../ui/toolkit.h" +#include "../common/context.h" +#include "../common/object.h" + +@interface AppDelegate : NSObject + + +@end diff --git a/ui/cocoa/appdelegate.m b/ui/cocoa/appdelegate.m new file mode 100644 index 0000000..38226cf --- /dev/null +++ b/ui/cocoa/appdelegate.m @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#import "AppDelegate.h" + +#import "toolkit.h" + +@implementation AppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + ui_cocoa_onstartup(); +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + ui_cocoa_onexit(); +} + + +- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app { + return YES; +} + + +@end diff --git a/ui/cocoa/button.h b/ui/cocoa/button.h new file mode 100644 index 0000000..8857d2f --- /dev/null +++ b/ui/cocoa/button.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#import "toolkit.h" + +#import "../ui/button.h" diff --git a/ui/cocoa/button.m b/ui/cocoa/button.m new file mode 100644 index 0000000..b153553 --- /dev/null +++ b/ui/cocoa/button.m @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#import "button.h" +#import "EventData.h" +#import "Container.h" +#import + +UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) { + NSButton *button = [[NSButton alloc] init]; + if(args.label) { + NSString *label = [[NSString alloc] initWithUTF8String:args.label]; + button.title = label; + } + + if(args.onclick) { + EventData *event = [[EventData alloc] init:args.onclick userdata:args.onclickdata]; + event.obj = obj; + button.target = event; + button.action = @selector(handleEvent:); + objc_setAssociatedObject(button, "eventdata", event, OBJC_ASSOCIATION_RETAIN); + } + + UiLayout layout = UI_INIT_LAYOUT(args); + ui_container_add(obj, button, &layout, FALSE); + + return (__bridge void*)button; +} diff --git a/ui/cocoa/container.h b/ui/cocoa/container.h index 1289b63..a024a18 100644 --- a/ui/cocoa/container.h +++ b/ui/cocoa/container.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -26,19 +26,65 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#import "../ui/toolkit.h" #import "toolkit.h" -typedef void(*ui_container_add_f)(UiContainer*, NSView*); +#import "../ui/container.h" -struct UiContainer { - NSView* widget; - void (*add)(UiContainer*, NSView*); - NSRect (*getframe)(UiContainer*); +#define ui_lb2bool(b) ((b) == UI_LAYOUT_TRUE ? TRUE : FALSE) +#define ui_bool2lb(b) ((b) ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE) + +typedef struct UiLayout UiLayout; +typedef enum UiLayoutBool UiLayoutBool; + +enum UiLayoutBool { + UI_LAYOUT_UNDEFINED = 0, + UI_LAYOUT_TRUE, + UI_LAYOUT_FALSE, +}; + +struct UiLayout { + UiTri fill; + //UiBool newline; + //char *label; + UiBool hexpand; + UiBool vexpand; + UiBool hfill; + UiBool vfill; + //int width; + int colspan; + int rowspan; }; -UiContainer* ui_window_container(UiObject *obj, NSWindow *window); +#define UI_INIT_LAYOUT(args) (UiLayout) {\ + .fill = args.fill, \ + .hexpand = args.hexpand, \ + .vexpand = args.vexpand, \ + .hfill = args.hfill, \ + .vfill = args.vfill, \ + .colspan = args.colspan, \ + .rowspan = args.rowspan } + + +@protocol Container + +@property UiLayout uilayout; +@property const char *label; +@property UiBool newline; + +- (void) addView:(NSView*)view fill:(BOOL)fill; + +@end + +@interface BoxContainer : NSStackView + +- (BoxContainer*)init:(NSUserInterfaceLayoutOrientation)orientation spacing:(int)spacing; + +@end + + + + -NSRect ui_container_getframe(UiContainer *ct); -void ui_container_add(UiContainer *ct, NSView *view); +UiContainerX* ui_create_container(UiObject *obj, id container); +void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout, UiBool fill); diff --git a/ui/cocoa/container.m b/ui/cocoa/container.m index dd6697d..9dc5965 100644 --- a/ui/cocoa/container.m +++ b/ui/cocoa/container.m @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -26,81 +26,143 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#import -#import +#import "Container.h" +#import "GridLayout.h" -#import "container.h" +/* ------------------------- container classes ------------------------- */ +@implementation BoxContainer -UiContainer* ui_window_container(UiObject *obj, NSWindow *window) { - UiContainer *ct = ucx_mempool_malloc( - obj->ctx->mempool, - sizeof(UiContainer)); - ct->widget = [window contentView]; - ct->add = ui_container_add; - ct->getframe = ui_container_getframe; - return ct; +@synthesize label=_label; +@synthesize uilayout=_uilayout; +@synthesize newline=_newline; + +- (BoxContainer*)init:(NSUserInterfaceLayoutOrientation)orientation spacing:(int)spacing { + self = [super init]; + _label = NULL; + _uilayout = (UiLayout){ 0 }; + _newline = false; + + self.distribution = NSStackViewDistributionFillProportionally; + self.spacing = spacing; + + self.orientation = orientation; + if(orientation == NSUserInterfaceLayoutOrientationHorizontal) { + self.alignment = NSLayoutAttributeHeight; + } else { + self.alignment = NSLayoutAttributeWidth; + } + + + return self; } -UIWIDGET ui_sidebar(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - NSRect frame = ct->getframe(ct); +- (void) addView:(NSView*)view fill:(BOOL)fill { + if(_uilayout.fill != UI_LAYOUT_UNDEFINED) { + fill = ui_lb2bool(_uilayout.fill); + } - // create and add views - NSSplitView *splitview = [[NSSplitView alloc] initWithFrame:frame]; - [splitview setVertical:YES]; - [splitview setDividerStyle:NSSplitViewDividerStyleThin]; - ct->add(ct, splitview); + [self addArrangedSubview:view]; - NSRect lframe; - lframe.origin.x = 0; - lframe.origin.y = 0; - lframe.size.width = 200; - lframe.size.height = frame.size.height; + if(self.orientation == NSUserInterfaceLayoutOrientationHorizontal) { + [view.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = YES; + if(!fill) { + [view.widthAnchor constraintEqualToConstant:view.intrinsicContentSize.width].active = YES; + } + } else { + [view.widthAnchor constraintEqualToAnchor:self.widthAnchor].active = YES; + if(!fill) { + [view.heightAnchor constraintEqualToConstant:view.intrinsicContentSize.height].active = YES; + } + } - NSRect rframe; - rframe.origin.x = 0; - rframe.origin.y = 0; - rframe.size.width = frame.size.width - 201; - rframe.size.height = frame.size.height; + // at the moment, only the fill layout option needs to be reset + _uilayout.fill = UI_DEFAULT; +} + +@end + + + +/* -------------------- public container functions --------------------- */ + +static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, NSUserInterfaceLayoutOrientation orientation) { + BoxContainer *box = [[BoxContainer alloc] init:orientation spacing:args.spacing]; + box.translatesAutoresizingMaskIntoConstraints = false; - NSView *sidebar = [[NSView alloc]initWithFrame:lframe]; - NSView *contentarea = [[NSView alloc]initWithFrame:rframe]; + // add box to the parent + UiLayout layout = UI_INIT_LAYOUT(args); + ui_container_add(obj, box, &layout, TRUE); - [splitview addSubview:sidebar]; - [splitview addSubview:contentarea]; + // add new box to the obj container chain + uic_object_push_container(obj, ui_create_container(obj, box)); - // add ui objects for the sidebar and contentarea - // the sidebar is added last, so that new views are added first to it - UiObject *left = uic_object_new(obj, sidebar); - UiContainer *ct1 = ucx_mempool_malloc( - obj->ctx->mempool, - sizeof(UiContainer)); - ct1->widget = sidebar; - ct1->add = ui_container_add; - ct1->getframe = ui_container_getframe; - left->container = ct1; + return (__bridge void*)box; +} + +UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) { + return ui_box_create(obj, args, NSUserInterfaceLayoutOrientationVertical); +} + +UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) { + return ui_box_create(obj, args, NSUserInterfaceLayoutOrientationHorizontal); +} + +UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) { + GridLayout *grid = [[GridLayout alloc] init]; + grid.translatesAutoresizingMaskIntoConstraints = false; - UiObject *right = uic_object_new(obj, sidebar); - UiContainer *ct2 = ucx_mempool_malloc( - obj->ctx->mempool, - sizeof(UiContainer)); - ct2->widget = contentarea; - ct2->add = ui_container_add; - ct2->getframe = ui_container_getframe; - right->container = ct2; + // add box to the parent + UiLayout layout = UI_INIT_LAYOUT(args); + ui_container_add(obj, grid, &layout, TRUE); - uic_obj_add(obj, right); - uic_obj_add(obj, left); + // add new box to the obj container chain + uic_object_push_container(obj, ui_create_container(obj, grid)); - return splitview; + return (__bridge void*)grid; +} + + +void ui_container_begin_close(UiObject *obj) { + UiContainerX *ct = obj->container_end; + ct->close = 1; +} + +int ui_container_finish(UiObject *obj) { + UiContainerX *ct = obj->container_end; + if(ct->close) { + ui_end_new(obj); + return 0; + } + return 1; } +/* ------------------------- private functions ------------------------- */ -NSRect ui_container_getframe(UiContainer *ct) { - return [ct->widget frame]; +UiContainerX* ui_create_container(UiObject *obj, id container) { + UiContainerX *ctn = ui_malloc(obj->ctx, sizeof(UiContainerX)); + ctn->container = (__bridge void*)container; + ctn->close = 0; + ctn->prev = NULL; + ctn->next = NULL; + return ctn; } -void ui_container_add(UiContainer *ct, NSView *view) { - [ct->widget addSubview: view]; +void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout, UiBool fill) { + UiContainerX *ctn = obj->container_end; + id container = (__bridge id)ctn->container; + container.uilayout = *layout; + [container addView:view fill:fill]; +} + +/* ---------------------- public layout functions ----------------------- */ + +void ui_newline(UiObject *obj) { + UiContainerX *ctn = obj->container_end; + if(ctn) { + id container = (__bridge id)ctn->container; + container.newline = TRUE; + } else { + fprintf(stderr, "Error: obj has no container\n"); + } } diff --git a/ui/cocoa/objs.mk b/ui/cocoa/objs.mk index 0a35acd..80f882a 100644 --- a/ui/cocoa/objs.mk +++ b/ui/cocoa/objs.mk @@ -30,16 +30,15 @@ COCOA_SRC_DIR = ui/cocoa/ COCOA_OBJPRE = $(OBJ_DIR)/$(COCOA_SRC_DIR) COCOAOBJ = toolkit.o +COCOAOBJ += AppDelegate.o +COCOAOBJ += GridLayout.o +COCOAOBJ += EventData.o +COCOAOBJ += UiJob.o +COCOAOBJ += MainWindow.o +COCOAOBJ += WindowManager.o COCOAOBJ += window.o -COCOAOBJ += menu.o -COCOAOBJ += stock.o -COCOAOBJ += toolbar.o -COCOAOBJ += container.o -COCOAOBJ += text.o -COCOAOBJ += resource.o -COCOAOBJ += tree.o -COCOAOBJ += graphics.o - +COCOAOBJ += Container.o +COCOAOBJ += button.o TOOLKITOBJS += $(COCOAOBJ:%=$(COCOA_OBJPRE)%) TOOLKITSOURCE += $(COCOAOBJ:%.o=cocoa/%.m) diff --git a/ui/cocoa/toolkit.h b/ui/cocoa/toolkit.h index a4c73b8..b44ba19 100644 --- a/ui/cocoa/toolkit.h +++ b/ui/cocoa/toolkit.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -31,58 +31,7 @@ #include "../common/context.h" #include "../common/object.h" - -@interface UiApplicationDelegate : NSObject { - -} - -- (void)applicationWillTerminate:(NSNotification*)notification; - -- (BOOL)applicationShouldHandleReopen:(NSApplication *)app hasVisibleWindows:(BOOL)visible; - -- (BOOL)application:(NSApplication *)application openFile:(NSString *)filename; - -@end - -@interface EventWrapper : NSObject { - void *data; - ui_callback callback; - int value; -} - -- (EventWrapper*) initWithData: (void*)data callback:(ui_callback) f; - -- (void*) data; -- (void) setData:(void*)d; -- (ui_callback) callback; -- (void) setCallback: (ui_callback)f; -- (int) intval; -- (void) setIntval:(int)i; - -- (BOOL)handleEvent:(id)sender; -- (BOOL)handleStateEvent:(id)sender; -- (BOOL)handleToggleEvent:(id)sender; - -@end - -@interface UiThread : NSObject { - UiObject *obj; - ui_threadfunc job_func; - void *job_data; - ui_callback finish_callback; - void *finish_data; -} - -- (id) initWithObject:(UiObject*)object; -- (void) setJobFunction:(ui_threadfunc)func; -- (void) setJobData:(void*)data; -- (void) setFinishCallback:(ui_callback)callback; -- (void) setFinishData:(void*)data; - -- (void) start; -- (void) runJob:(id)n; -- (void) finish:(id)n; - -@end - +void ui_cocoa_onstartup(void); +void ui_cocoa_onopen(const char *file); +void ui_cocoa_onexit(void); diff --git a/ui/cocoa/toolkit.m b/ui/cocoa/toolkit.m index c9f2a72..9299672 100644 --- a/ui/cocoa/toolkit.m +++ b/ui/cocoa/toolkit.m @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2012 Olaf Wintermann. All rights reserved. + * 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: @@ -26,321 +26,126 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#import -#import -#import -#import -#import - -#import "../common/context.h" -#import "../common/document.h" -#import "../common/properties.h" - #import "toolkit.h" -#import "window.h" -#import "menu.h" -#import "toolbar.h" -#import "stock.h" -NSAutoreleasePool *pool; +#include "../common/document.h" +#include "../common/properties.h" +#include "../common/menu.h" +#include "../common/toolbar.h" +#include "../common/threadpool.h" -static char *application_name; +#import "AppDelegate.h" -static ui_callback appclose_fnc; -static void *appclose_udata; +static const char *application_name; -static ui_callback openfile_fnc; -static void *openfile_udata; +static int app_argc; +static const char **app_argv; -void ui_init(char *appname, int argc, char **argv) { - pool = [[NSAutoreleasePool alloc] init]; - [NSApplication sharedApplication]; - [NSBundle loadNibNamed:@"MainMenu" owner:NSApp]; - - UiApplicationDelegate *delegate = [[UiApplicationDelegate alloc]init]; - [NSApp setDelegate: delegate]; - - - uic_docmgr_init(); - ui_menu_init(); - ui_toolbar_init(); - ui_stock_init(); - - uic_load_app_properties(); -} +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; -char* ui_appname() { - return application_name; -} - -void ui_exitfunc(ui_callback f, void *userdata) { - appclose_fnc = f; - appclose_udata = userdata; -} +/* ------------------- App Init / Event Loop functions ------------------- */ -void ui_openfilefunc(ui_callback f, void *userdata) { - openfile_fnc = f; - openfile_udata = userdata; -} +void ui_init(const char *appname, int argc, char **argv) { + application_name = appname; + app_argc = argc; + app_argv = (const char**)argv; + + uic_init_global_context(); -void ui_show(UiObject *obj) { - uic_check_group_widgets(obj->ctx); - if([obj->widget class] == [UiCocoaWindow class]) { - UiCocoaWindow *window = (UiCocoaWindow*)obj->widget; - [window makeKeyAndOrderFront:nil]; - } else { - printf("Error: ui_show: Object is not a Window!\n"); - } -} + uic_docmgr_init(); + uic_menu_init(); + uic_toolbar_init(); -void ui_set_show_all(UIWIDGET widget, int value) { - // TODO -} + uic_load_app_properties(); -void ui_set_visible(UIWIDGET widget, int visible) { - // TODO + [NSApplication sharedApplication]; + //[NSBundle loadNibNamed:@"MainMenu" owner:NSApp ]; + //[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:&topLevelObjects]; } -void ui_set_enabled(UIWIDGET widget, int enabled) { - [(id)widget setEnabled: enabled]; +const char* ui_appname() { + return application_name; } - - -void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { - UiThread *thread = [[UiThread alloc]initWithObject:obj]; - [thread setJobFunction:tf]; - [thread setJobData:td]; - [thread setFinishCallback:f]; - [thread setFinishData:fd]; - [thread start]; +void ui_onstartup(ui_callback f, void *userdata) { + startup_func = f; + startup_data = userdata; } -void ui_main() { - [NSApp run]; - [pool release]; +void ui_onopen(ui_callback f, void *userdata) { + open_func = f; + open_data = userdata; } - -void ui_clipboard_set(char *str) { - NSString *string = [[NSString alloc] initWithUTF8String:str]; - NSPasteboard * pasteBoard = [NSPasteboard generalPasteboard]; - [pasteBoard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; - [pasteBoard setString:string forType:NSStringPboardType]; +void ui_onexit(ui_callback f, void *userdata) { + exit_func = f; + exit_data = userdata; } -char* ui_clipboard_get() { - NSPasteboard * pasteBoard = [NSPasteboard generalPasteboard]; - NSArray *classes = [[NSArray alloc] initWithObjects:[NSString class], nil]; - NSDictionary *options = [NSDictionary dictionary]; - NSArray *data = [pasteBoard readObjectsForClasses:classes options:options]; - - if(data != nil) { - NSString *str = [data componentsJoinedByString: @""]; - - // copy C string - size_t length = [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - const char *cstr = [str UTF8String]; - char *value = malloc(length + 1); - memcpy(value, cstr, length); - value[length] = '\0'; - - return value; - } else { - return NULL; +void ui_cocoa_onstartup(void) { + UiEvent e; + e.obj = NULL; + e.window = NULL; + e.document = NULL; + e.eventdata = NULL; + e.intval = 0; + if(startup_func) { + startup_func(&e, startup_data); } } - -@implementation UiApplicationDelegate - -- (void)applicationWillTerminate:(NSNotification*)notification { - printf("terminate\n"); -} - -- (BOOL)applicationShouldHandleReopen:(NSApplication *)app hasVisibleWindows:(BOOL)visible; { - if(!visible) { - printf("reopen\n"); +void ui_cocoa_onopen(const char *file) { + UiEvent e; + e.obj = NULL; + e.window = NULL; + e.document = NULL; + e.eventdata = NULL; + e.intval = 0; + if(open_func) { + open_func(&e, open_data); } - return NO; } -- (BOOL)application:(NSApplication*)application openFile:(NSString*)filename { - if(openfile_fnc) { - UiEvent event; - event.obj = NULL; - event.document = NULL; - event.window = NULL; - event.eventdata = (void*)[filename UTF8String]; - event.intval = 0; - openfile_fnc(&event, openfile_udata); +void ui_cocoa_onexit(void) { + UiEvent e; + e.obj = NULL; + e.window = NULL; + e.document = NULL; + e.eventdata = NULL; + e.intval = 0; + if(exit_func) { + exit_func(&e, exit_data); } - - return NO; -} - -@end - - -@implementation EventWrapper - -- (EventWrapper*) initWithData: (void*)d callback:(ui_callback) f { - data = d; - callback = f; - value = 0; - return self; -} - - -- (void*) data { - return data; -} - -- (void) setData:(void*)d { - data = d; -} - - -- (ui_callback) callback { - return callback; -} - -- (void) setCallback: (ui_callback)f { - callback = f; -} - -- (int) intval { - return value; } -- (void) setIntval:(int)i { - value = i; +void ui_main(void) { + NSApplicationMain(app_argc, app_argv); } +/* ------------------- Window Visibility functions ------------------- */ -- (BOOL)handleEvent:(id)sender { - NSWindow *activeWindow = [NSApp keyWindow]; - - UiEvent event; - event.eventdata = NULL; - if([activeWindow class] == [UiCocoaWindow class]) { - event.obj = [(UiCocoaWindow*)activeWindow object]; - event.window = event.obj->window; - event.document = event.obj->ctx->document; - event.intval = value; - } - if(callback) { - callback(&event, data); - } - - return true; -} - -- (BOOL)handleStateEvent:(id)sender { - NSWindow *activeWindow = [NSApp keyWindow]; - int state = [sender state] ? NSOffState : NSOnState; - - UiEvent event; - event.intval = state; - event.eventdata = NULL; - if([activeWindow class] == [UiCocoaWindow class]) { - event.obj = [(UiCocoaWindow*)activeWindow object]; - event.window = event.obj->window; - event.document = event.obj->ctx->document; - // if the sender is a menu item, we have to save the state for this - // window - UiMenuItem *wmi = [(UiCocoaWindow*)activeWindow getMenuItem: sender]; - if(wmi) { - // update state in window data - wmi->state = state; - } - } else { - event.window = NULL; - event.document = NULL; - } - if(callback) { - callback(&event, data); - } - [sender setState: state]; - - return true; -} - -- (BOOL)handleToggleEvent:(id)sender { - NSWindow *activeWindow = [NSApp keyWindow]; - - UiEvent event; - event.intval = [sender state]; - event.eventdata = NULL; - if([activeWindow class] == [UiCocoaWindow class]) { - event.obj = [(UiCocoaWindow*)activeWindow object]; - event.window = event.obj->window; - event.document = event.obj->ctx->document; - } else { - event.window = NULL; - event.document = NULL; - } - if(callback) { - callback(&event, data); +void ui_show(UiObject *obj) { + if(obj->wobj) { + NSWindow *window = (__bridge NSWindow*)obj->wobj; + [window makeKeyAndOrderFront:nil]; } - - return true; -} - -@end - -@implementation UiThread - -- (id) initWithObject:(UiObject*)object { - obj = object; - job_func = NULL; - job_data = NULL; - finish_callback = NULL; - finish_data = NULL; - return self; } -- (void) setJobFunction:(ui_threadfunc)func { - job_func = func; -} +void ui_close(UiObject *obj) { -- (void) setJobData:(void*)data { - job_data = data; } -- (void) setFinishCallback:(ui_callback)callback { - finish_callback = callback; -} +/* ------------------- Job Control / Threadpool functions ------------------- */ -- (void) setFinishData:(void*)data { - finish_data = data; -} +void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { -- (void) start { - [NSThread detachNewThreadSelector:@selector(runJob:) - toTarget:self - withObject:nil]; } -- (void) runJob:(id)n { - int result = job_func(job_data); - if(!result) { - [self performSelectorOnMainThread:@selector(finish:) - withObject:nil - waitUntilDone:NO]; - } -} +void ui_call_mainthread(ui_threadfunc tf, void* td) { -- (void) finish:(id)n { - UiEvent event; - event.obj = obj; - event.window = obj->window; - event.document = obj->ctx->document; - event.eventdata = NULL; - event.intval = 0; - finish_callback(&event, finish_data); } - -@end - - diff --git a/ui/cocoa/window.h b/ui/cocoa/window.h index d1cfe46..478b591 100644 --- a/ui/cocoa/window.h +++ b/ui/cocoa/window.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2012 Olaf Wintermann. All rights reserved. + * 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: @@ -26,27 +26,4 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#import -#import "../ui/window.h" -#import -#import - -#import "menu.h" - - - -@interface UiCocoaWindow : NSWindow { - UiObject *uiobj; - UcxMap *menus; // key: NSMenu value: UcxList of UiMenuItem - UcxMap *items; // key: NSMenuItem value: UiMenuItem -} - -- (UiCocoaWindow*) init: (NSRect)frame object: (UiObject*)obj; -- (UiObject*) object; -- (void) setObject:(UiObject*)obj; -- (void) setMenuItems:(UcxList*)menuItems; -- (void) setMenuItemLists:(UcxList*)itemLists; -- (UiMenuItem*) getMenuItem:(NSMenuItem*)item; -- (void) updateMenu:(NSMenu*)menu; - -@end +#import "toolkit.h" \ No newline at end of file diff --git a/ui/cocoa/window.m b/ui/cocoa/window.m index e7c5ecd..fbf7833 100644 --- a/ui/cocoa/window.m +++ b/ui/cocoa/window.m @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2012 Olaf Wintermann. All rights reserved. + * 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: @@ -26,195 +26,43 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include - #import "window.h" -#import "menu.h" -#import "toolbar.h" -#import "container.h" -#import -#import "../common/context.h" -static int window_default_width = 600; -static int window_default_height = 500; +#import "MainWindow.h" +#import "WindowManager.h" -@implementation UiCocoaWindow +#include "../ui/window.h" +#include "../ui/properties.h" +#include "../common/context.h" +#include "../common/menu.h" +#include "../common/toolbar.h" -- (UiCocoaWindow*) init: (NSRect)frame object: (UiObject*)obj { - self = [self initWithContentRect:frame - styleMask:NSTitledWindowMask | - NSResizableWindowMask | - NSClosableWindowMask | - NSMiniaturizableWindowMask - backing:NSBackingStoreBuffered - defer:false]; - - uiobj = obj; - UcxAllocator *allocator = uiobj->ctx->mempool->allocator; - menus = ucx_map_new_a(allocator, 8); - items = ucx_map_new_a(allocator, 64); - - return self; -} +#include -- (UiObject*) object { - return uiobj; -} - -- (void) setObject:(UiObject*)obj { - uiobj = obj; -} - -- (void) setMenuItems:(UcxList*)menuItems { - UcxAllocator *allocator = uiobj->ctx->mempool->allocator; - - UCX_FOREACH(elm, menuItems) { - UiStateItem *item = elm->data; - NSMenu *menu = [item->item menu]; - - // create UiMenuItem which represents an NSMenuItem for a Window - UiMenuItem *windowItem = ucx_mempool_malloc(uiobj->ctx->mempool, sizeof(UiMenuItem)); - windowItem->item = item->item; - windowItem->state = 0; - if(item->var) { - // bind value - UiVar *var = uic_connect_var(uiobj->ctx, item->var, UI_VAR_INTEGER); - if(var) { - UiInteger *value = var->value; - value->obj = windowItem; - value->get = ui_menuitem_get; - value->set = ui_menuitem_set; - value = 0; - } else { - // TODO: error - } - } - - // add item - UiAbstractMenuItem *abstractItem = malloc(sizeof(UiAbstractMenuItem)); - abstractItem->update = ui_update_item; - abstractItem->item_data = windowItem; - UcxList *itemList = ucx_map_get(menus, ucx_key(&menu, sizeof(void*))); - itemList = ucx_list_append_a(allocator, itemList, abstractItem); - ucx_map_put(menus, ucx_key(&menu, sizeof(void*)), itemList); - - ucx_map_put(items, ucx_key(&windowItem->item, sizeof(void*)), windowItem); - } -} - -- (void) setMenuItemLists:(UcxList*)itemLists { - UcxAllocator *allocator = uiobj->ctx->mempool->allocator; - - UCX_FOREACH(elm, itemLists) { - UiMenuItemList *list = elm->data; - - UiAbstractMenuItem *abstractItem = malloc(sizeof(UiAbstractMenuItem)); - abstractItem->update = ui_update_item_list; - abstractItem->item_data = list; - - UcxList *itemList = ucx_map_get(menus, ucx_key(&list->menu, sizeof(void*))); - itemList = ucx_list_append_a(allocator, itemList, abstractItem); - ucx_map_put(menus, ucx_key(&list->menu, sizeof(void*)), itemList); - - } -} - -- (UiMenuItem*) getMenuItem:(NSMenuItem*)item { - return ucx_map_get(items, ucx_key(&item, sizeof(void*))); -} - -- (void) updateMenu:(NSMenu*)menu { - UcxList *itemList = ucx_map_get(menus, ucx_key(&menu, sizeof(void*))); - UCX_FOREACH(elm, itemList) { - UiAbstractMenuItem *item = elm->data; - item->update(self, item->item_data); - } - - // update group items - // TODO: use only one loop for all items - int ngroups = 0; - int *groups = ui_active_groups(uiobj->ctx, &ngroups); +static UiObject* create_window(const char *title, BOOL simple) { + CxMempool *mp = cxBasicMempoolCreate(256); + UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject)); + obj->ref = 0; - NSArray *groupItems = [menu itemArray]; - int count = [groupItems count]; - for(int i=0;ictx = uic_context(obj, mp); - // create native window - NSRect frame = NSMakeRect( - 300, - 200, - window_default_width, - window_default_height); - - /* - UiCocoaWindow *window = [[UiCocoaWindow alloc] initWithContentRect:frame - styleMask:NSTitledWindowMask | NSResizableWindowMask | - NSClosableWindowMask | NSMiniaturizableWindowMask - backing:NSBackingStoreBuffered - defer:false]; - */ - UiCocoaWindow *window = [[UiCocoaWindow alloc] init:frame object:obj]; - - NSString *titleStr = [[NSString alloc] initWithUTF8String:title]; - [window setTitle:titleStr]; - - UiMenuDelegate *menuDelegate = ui_menu_delegate(); - [window setMenuItems: [menuDelegate items]]; - [window setMenuItemLists: [menuDelegate lists]]; - - NSToolbar *toolbar = ui_create_toolbar(obj); - [window setToolbar: toolbar]; - - obj->widget = (NSView*)window; - obj->window = window_data; - obj->container = ui_window_container(obj, window); + MainWindow *window = [[MainWindow alloc] init:obj]; + [[WindowManager sharedWindowManager] addWindow:window]; + window.releasedWhenClosed = false; + obj->wobj = (__bridge void*)window; return obj; } -void ui_close(UiObject *obj) { - // TODO -} - -char* ui_openfiledialog(UiObject *obj) { - NSOpenPanel* op = [NSOpenPanel openPanel]; - if ([op runModal] == NSOKButton) { - NSArray *urls = [op URLs]; - NSURL *url = [urls objectAtIndex:0]; - - const char *str = [[url path] UTF8String]; - return (char*)strdup(str); - } - return NULL; +UiObject* ui_window(const char *title, void *window_data) { + UiObject *obj = create_window(title, FALSE); + obj->window = window_data; + return obj; } -char* ui_savefiledialog(UiObject *obj) { - NSSavePanel* sp = [NSSavePanel savePanel]; - if ([sp runModal] == NSOKButton) { - NSURL *url = [sp URL]; - - const char *str = [[url path] UTF8String]; - return (char*)strdup(str); - } - return NULL; +UiObject* ui_simple_window(const char *title, void *window_data) { + UiObject *obj = create_window(title, TRUE); + obj->window = window_data; + return obj; } diff --git a/ui/common/condvar.c b/ui/common/condvar.c index 8b405c9..c61e70c 100644 --- a/ui/common/condvar.c +++ b/ui/common/condvar.c @@ -28,7 +28,7 @@ #include "condvar.h" - +#include UiCondVar* ui_condvar_create(void) { UiPosixCondVar *var = malloc(sizeof(UiPosixCondVar)); diff --git a/ui/common/context.c b/ui/common/context.c index 3480620..251d2c7 100644 --- a/ui/common/context.c +++ b/ui/common/context.c @@ -187,6 +187,13 @@ UiVar* uic_get_var(UiContext *ctx, const char *name) { } UiVar* uic_create_var(UiContext *ctx, const char *name, UiVarType type) { + if(ctx->vars_unbound) { + UiVar *unbound = cxMapGet(ctx->vars_unbound, name); + if(unbound) { + return unbound; + } + } + UiVar *var = uic_get_var(ctx, name); if(var) { if(var->type == type) { diff --git a/ui/common/menu.c b/ui/common/menu.c index eb47d58..3765fe1 100644 --- a/ui/common/menu.c +++ b/ui/common/menu.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -174,7 +175,7 @@ void ui_menu_radioitem_create(UiMenuToggleItemArgs args) { mitem_set_id(&item->item); item->item.prev = NULL; item->item.next = NULL; - item->item.type = UI_MENU_CHECK_ITEM; + item->item.type = UI_MENU_RADIO_ITEM; item->label = nl_strdup(args.label); item->stockid = nl_strdup(args.stockid); diff --git a/ui/common/menu.h b/ui/common/menu.h index 63b577d..6091124 100644 --- a/ui/common/menu.h +++ b/ui/common/menu.h @@ -101,6 +101,7 @@ struct UiMenuRadioItem { char *label; char *stockid; char *icon; + char *varname; ui_callback callback; void *userdata; int *groups; diff --git a/ui/common/object.c b/ui/common/object.c index 5fd1130..c13bf5d 100644 --- a/ui/common/object.c +++ b/ui/common/object.c @@ -32,6 +32,8 @@ #include "object.h" #include "context.h" +#include "../ui/container.h" + void ui_end(UiObject *obj) { if(!obj->next) { return; @@ -49,20 +51,30 @@ void ui_end(UiObject *obj) { } } +void ui_end_new(UiObject *obj) { + if(!obj->container_end) { + return; + } + UiContainerX *rm = obj->container_end; + uic_object_pop_container(obj); + ui_free(obj->ctx, rm); +} + void ui_object_ref(UiObject *obj) { obj->ref++; } -void ui_object_unref(UiObject *obj) { +int ui_object_unref(UiObject *obj) { // it is possible to have 0 references, in case // a window was created but ui_show was never called if(obj->ref == 0 || --obj->ref == 0) { if(obj->destroy) { obj->destroy(obj); - } else { - uic_object_destroy(obj); } + uic_object_destroy(obj); + return 0; } + return 1; } void uic_object_destroy(UiObject *obj) { @@ -109,3 +121,23 @@ UiObject* uic_current_obj(UiObject *toplevel) { UiContainer* uic_get_current_container(UiObject *obj) { return uic_current_obj(obj)->container; } + +void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer) { + newcontainer->prev = toplevel->container_end; + if(toplevel->container_end) { + toplevel->container_end->next = newcontainer; + toplevel->container_end = newcontainer; + } else { + toplevel->container_begin = newcontainer; + toplevel->container_end = newcontainer; + } +} + +void uic_object_pop_container(UiObject *toplevel) { + toplevel->container_end = toplevel->container_end->prev; + if(toplevel->container_end) { + toplevel->container_end->next = NULL; + } else { + toplevel->container_begin = NULL; + } +} diff --git a/ui/common/object.h b/ui/common/object.h index bc8bd79..a5011a0 100644 --- a/ui/common/object.h +++ b/ui/common/object.h @@ -42,7 +42,11 @@ UiObject* uic_ctx_object_new(UiContext *ctx, UIWIDGET widget); void uic_obj_add(UiObject *toplevel, UiObject *ctobj); UiObject* uic_current_obj(UiObject *toplevel); -UiContainer* uic_get_current_container(UiObject *obj);; +UiContainer* uic_get_current_container(UiObject *obj); // deprecated + +void uic_object_push_container(UiObject *toplevel, UiContainerX *newcontainer); +void uic_object_pop_container(UiObject *toplevel); + #ifdef __cplusplus diff --git a/ui/common/threadpool.c b/ui/common/threadpool.c index 71adb9f..d3725c9 100644 --- a/ui/common/threadpool.c +++ b/ui/common/threadpool.c @@ -29,10 +29,12 @@ #include "threadpool.h" #include "context.h" -#include - #ifndef _WIN32 +#include +#include +#include +#include static threadpool_job kill_job; diff --git a/ui/common/threadpool.h b/ui/common/threadpool.h index 2ab5e35..d167062 100644 --- a/ui/common/threadpool.h +++ b/ui/common/threadpool.h @@ -31,6 +31,10 @@ #include "../ui/toolkit.h" +#ifndef _WIN32 +#include +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/ui/gtk/button.c b/ui/gtk/button.c index adbbc43..5123e27 100644 --- a/ui/gtk/button.c +++ b/ui/gtk/button.c @@ -398,12 +398,14 @@ typedef struct UiRadioButtonData { } UiRadioButtonData; static void destroy_radiobutton(GtkWidget *w, UiRadioButtonData *data) { - ui_destroy_vardata(w, data->eventdata); if(data->first) { + ui_destroy_vardata(w, data->eventdata); g_slist_free(data->value->obj); data->value->obj = NULL; data->value->get = NULL; data->value->set = NULL; + } else { + free(data->eventdata); } free(data); } diff --git a/ui/gtk/container.c b/ui/gtk/container.c index 36e46cd..0a96b7c 100644 --- a/ui/gtk/container.c +++ b/ui/gtk/container.c @@ -891,6 +891,42 @@ UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) { #endif +/* -------------------- Sidebar -------------------- */ + +#ifdef UI_LIBADWAITA +UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) { + GtkWidget *sidebar_toolbar_view = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar"); + if(!sidebar_toolbar_view) { + fprintf(stderr, "Error: window is not configured for sidebar\n"); + return NULL; + } + + GtkWidget *box = ui_gtk_vbox_new(args.spacing); + ui_box_set_margin(box, args.margin); + adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box); + + UiObject *newobj = uic_object_new(obj, box); + newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX); + uic_obj_add(obj, newobj); + + return box; +} +#else +UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) { + GtkWidget *sidebar_vbox = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar"); + + GtkWidget *box = ui_gtk_vbox_new(args.spacing); + ui_box_set_margin(box, args.margin); + BOX_ADD_EXPAND(sidebar_vbox, box); + + UiObject *newobj = uic_object_new(obj, box); + newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX); + uic_obj_add(obj, newobj); + + return box; +} +#endif + /* -------------------- Splitpane -------------------- */ static GtkWidget* create_paned(UiOrientation orientation) { diff --git a/ui/gtk/list.c b/ui/gtk/list.c index 34bf993..342496f 100644 --- a/ui/gtk/list.c +++ b/ui/gtk/list.c @@ -36,6 +36,7 @@ #include "container.h" #include +#include #include "list.h" #include "icon.h" @@ -982,3 +983,296 @@ void ui_combobox_setselection(UiList *list, UiListSelection selection) { gtk_combo_box_set_active(GTK_COMBO_BOX(combobox->widget), selection.rows[0]); } } + + +/* ------------------------------ Source List ------------------------------ */ + +static void ui_destroy_sourcelist(GtkWidget *w, UiListBox *v) { + cxListDestroy(v->sublists); + free(v); +} + +static void sublist_destroy(UiObject *obj, UiListBoxSubList *sublist) { + free(sublist->header); + ui_destroy_boundvar(obj->ctx, sublist->var); + cxListDestroy(sublist->widgets); +} + +static void listbox_create_header(GtkListBoxRow* row, GtkListBoxRow* before, gpointer user_data) { + // first rows in sublists have the ui_listbox property + UiListBox *listbox = g_object_get_data(G_OBJECT(row), "ui_listbox"); + if(!listbox) { + return; + } + + UiListBoxSubList *sublist = g_object_get_data(G_OBJECT(row), "ui_listbox_sublist"); + if(!sublist) { + return; + } + + if(sublist->separator) { + GtkWidget *separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + gtk_list_box_row_set_header(row, separator); + } else if(sublist->header) { + GtkWidget *header = gtk_label_new(sublist->header); + gtk_widget_set_halign(header, GTK_ALIGN_START); + if(row == listbox->first_row) { + WIDGET_ADD_CSS_CLASS(header, "ui-listbox-header-first"); + } else { + WIDGET_ADD_CSS_CLASS(header, "ui-listbox-header"); + } + gtk_list_box_row_set_header(row, header); + } +} + +#ifdef UI_GTK3 +typedef struct _UiSidebarListBoxClass { + GtkListBoxClass parent_class; +} UiSidebarListBoxClass; + +typedef struct _UiSidebarListBox { + GtkListBox parent_instance; +} UiSidebarListBox; + +G_DEFINE_TYPE(UiSidebarListBox, ui_sidebar_list_box, GTK_TYPE_LIST_BOX) + +/* Initialize the instance */ +static void ui_sidebar_list_box_class_init(UiSidebarListBoxClass *klass) { + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + gtk_widget_class_set_css_name (widget_class, "placessidebar"); +} + +static void ui_sidebar_list_box_init(UiSidebarListBox *self) { + +} +#endif + +UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) { + UiObject* current = uic_current_obj(obj); + +#ifdef UI_GTK3 + GtkWidget *listbox = g_object_new(ui_sidebar_list_box_get_type(), NULL); +#else + GtkWidget *listbox = gtk_list_box_new(); +#endif + if(!args.style_class) { +#if GTK_MAJOR_VERSION >= 4 + WIDGET_ADD_CSS_CLASS(listbox, "navigation-sidebar"); +#else + WIDGET_ADD_CSS_CLASS(listbox, "sidebar"); +#endif + } + gtk_list_box_set_header_func(GTK_LIST_BOX(listbox), listbox_create_header, NULL, NULL); + GtkWidget *scroll_area = SCROLLEDWINDOW_NEW(); + SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox); + + ui_set_name_and_style(listbox, args.name, args.style_class); + ui_set_widget_groups(obj->ctx, listbox, args.groups); + UI_APPLY_LAYOUT1(current, args); + current->container->add(current->container, scroll_area, TRUE); + + UiListBox *uilistbox = malloc(sizeof(UiListBox)); + uilistbox->obj = obj; + uilistbox->listbox = GTK_LIST_BOX(listbox); + uilistbox->getvalue = args.getvalue; + uilistbox->onactivate = args.onactivate; + uilistbox->onactivatedata = args.onactivatedata; + uilistbox->onbuttonclick = args.onbuttonclick; + uilistbox->onbuttonclickdata = args.onbuttonclickdata; + uilistbox->sublists = cxArrayListCreateSimple(sizeof(UiListBoxSubList), 4); + uilistbox->sublists->collection.advanced_destructor = (cx_destructor_func2)sublist_destroy; + uilistbox->sublists->collection.destructor_data = obj; + uilistbox->first_row = NULL; + + if(args.numsublists == 0 && args.sublists) { + args.numsublists = INT_MAX; + } + for(int i=0;ictx, + current->ctx, + sublist.value, + sublist.varname, + UI_VAR_LIST); + uisublist.numitems = 0; + uisublist.header = sublist.header ? strdup(sublist.header) : NULL; + uisublist.separator = sublist.separator; + uisublist.widgets = cxLinkedListCreateSimple(CX_STORE_POINTERS); + uisublist.listbox = uilistbox; + uisublist.userdata = sublist.userdata; + uisublist.index = i; + + cxListAdd(uilistbox->sublists, &uisublist); + + // bind UiList + UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(uilistbox->sublists)-1); + UiList *list = uisublist.var->value; + if(list) { + list->obj = sublist_ptr; + list->update = ui_listbox_list_update; + } + } + // fill items + ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists)); + + // register uilistbox for both widgets, so it doesn't matter which + // widget is used later + g_object_set_data(G_OBJECT(scroll_area), "ui_listbox", uilistbox); + g_object_set_data(G_OBJECT(listbox), "ui_listbox", uilistbox); + + // signals + g_signal_connect( + listbox, + "destroy", + G_CALLBACK(ui_destroy_sourcelist), + uilistbox); + + if(args.onactivate) { + g_signal_connect( + listbox, + "row-activated", + G_CALLBACK(ui_listbox_row_activate), + NULL); + } + + return scroll_area; +} + +void ui_listbox_update(UiListBox *listbox, int from, int to) { + CxIterator i = cxListIterator(listbox->sublists); + size_t pos = 0; + cx_foreach(UiListBoxSubList *, sublist, i) { + if(i.index < from) { + pos += sublist->numitems; + continue; + } + if(i.index > to) { + break; + } + + // reload sublist + ui_listbox_update_sublist(listbox, sublist, pos); + pos += sublist->numitems; + } +} + +static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *sublist, UiSubListItem *item, int index) { + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); + if(item->icon) { + GtkWidget *icon = ICON_IMAGE(item->icon); + BOX_ADD(hbox, icon); + } + GtkWidget *label = gtk_label_new(item->label); + gtk_widget_set_halign(label, GTK_ALIGN_START); + BOX_ADD_EXPAND(hbox, label); + // TODO: badge, button + GtkWidget *row = gtk_list_box_row_new(); + LISTBOX_ROW_SET_CHILD(row, hbox); + + // signals + UiEventDataExt *event = malloc(sizeof(UiEventDataExt)); + memset(event, 0, sizeof(UiEventDataExt)); + event->obj = listbox->obj; + event->customdata0 = sublist; + event->customdata1 = sublist->var; + event->customdata2 = item->eventdata; + event->callback = listbox->onactivate; + event->userdata = listbox->onactivatedata; + event->callback2 = listbox->onbuttonclick; + event->userdata2 = listbox->onbuttonclickdata; + event->value0 = index; + + g_signal_connect( + row, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); + + g_object_set_data(G_OBJECT(row), "ui-listbox-row-eventdata", event); + + return row; +} + +void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index) { + // clear sublist + CxIterator r = cxListIterator(sublist->widgets); + cx_foreach(GtkWidget*, widget, r) { + LISTBOX_REMOVE(listbox->listbox, widget); + } + cxListClear(sublist->widgets); + + sublist->numitems = 0; + + // create items for each UiList element + UiList *list = sublist->var->value; + if(!list) { + return; + } + + size_t index = 0; + void *elm = list->first(list); + while(elm) { + UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL }; + listbox->getvalue(sublist->userdata, elm, index, &item); + + // create listbox item + GtkWidget *row = create_listbox_row(listbox, sublist, &item, (int)index); + if(index == 0) { + // first row in the sublist, set ui_listbox data to the row + // which is then used by the headerfunc + g_object_set_data(G_OBJECT(row), "ui_listbox", listbox); + g_object_set_data(G_OBJECT(row), "ui_listbox_sublist", sublist); + + if(listbox_insert_index == 0) { + // first row in the GtkListBox + listbox->first_row = GTK_LIST_BOX_ROW(row); + } + } + intptr_t rowindex = listbox_insert_index + index; + g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex); + gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index); + cxListAdd(sublist->widgets, row); + + // cleanup + free(item.label); + free(item.icon); + free(item.button_label); + free(item.button_icon); + free(item.badge); + + // next row + elm = list->next(list); + index++; + } + + sublist->numitems = cxListSize(sublist->widgets); +} + +void ui_listbox_list_update(UiList *list, int i) { + UiListBoxSubList *sublist = list->obj; +} + +void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) { + UiEventDataExt *data = g_object_get_data(G_OBJECT(row), "ui-listbox-row-eventdata"); + if(!data) { + return; + } + UiListBoxSubList *sublist = data->customdata0; + + UiEvent event; + event.obj = data->obj; + event.window = event.obj->window; + event.document = event.obj->ctx->document; + event.eventdata = data->customdata2; + event.intval = data->value0; + + if(data->callback) { + data->callback(&event, data->userdata); + } +} diff --git a/ui/gtk/list.h b/ui/gtk/list.h index 3978fb3..286cfab 100644 --- a/ui/gtk/list.h +++ b/ui/gtk/list.h @@ -32,6 +32,8 @@ #include "../ui/tree.h" #include "toolkit.h" +#include + #ifdef __cplusplus extern "C" { #endif @@ -57,7 +59,33 @@ typedef struct UiTreeEventData { void *activatedata; void *selectiondata; } UiTreeEventData; + +typedef struct UiListBox UiListBox; + +typedef struct UiListBoxSubList { + UiVar *var; + size_t numitems; + char *header; + UiBool separator; + CxList *widgets; + UiListBox *listbox; + void *userdata; + size_t index; +} UiListBoxSubList; + +struct UiListBox { + UiObject *obj; + GtkListBox *listbox; + CxList *sublists; // contains UiListBoxSubList elements + ui_sublist_getvalue_func getvalue; + ui_callback onactivate; + void *onactivatedata; + ui_callback onbuttonclick; + void *onbuttonclickdata; + GtkListBoxRow *first_row; +}; + void* ui_strmodel_getvalue(void *elm, int column); UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata); @@ -94,6 +122,12 @@ void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e); void ui_combobox_modelupdate(UiList *list, int i); UiListSelection ui_combobox_getselection(UiList *list); void ui_combobox_setselection(UiList *list, UiListSelection selection); + +void ui_listbox_update(UiListBox *listbox, int from, int to); +void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index); +void ui_listbox_list_update(UiList *list, int i); + +void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data); #ifdef __cplusplus } diff --git a/ui/gtk/text.c b/ui/gtk/text.c index fe8aac3..39f4a6b 100644 --- a/ui/gtk/text.c +++ b/ui/gtk/text.c @@ -551,6 +551,8 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor uitext->var = var; uitext->onchange = args.onchange; uitext->onchangedata = args.onchangedata; + uitext->onactivate = args.onactivate; + uitext->onactivatedata = args.onactivatedata; g_signal_connect( textfield, @@ -599,6 +601,14 @@ static UIWIDGET create_textfield(UiObject *obj, UiBool frameless, UiBool passwor uitext); } + if(args.onactivate) { + g_signal_connect( + textfield, + "activate", + G_CALLBACK(ui_textfield_activate), + uitext); + } + return textfield; } @@ -638,6 +648,17 @@ void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield) { } } +void ui_textfield_activate(GtkEntry* self, UiTextField *textfield) { + if(textfield->onactivate) { + UiEvent e; + e.obj = textfield->obj; + e.window = e.obj->window; + e.document = textfield->obj->ctx->document; + e.eventdata = NULL; + e.intval = 0; + textfield->onactivate(&e, textfield->onactivatedata); + } +} char* ui_textfield_get(UiString *str) { if(str->value.ptr) { diff --git a/ui/gtk/text.h b/ui/gtk/text.h index 6e8d198..f7b8ad7 100644 --- a/ui/gtk/text.h +++ b/ui/gtk/text.h @@ -74,6 +74,8 @@ typedef struct UiTextField { UiVar *var; ui_callback onchange; void *onchangedata; + ui_callback onactivate; + void *onactivatedata; } UiTextField; typedef struct UiPathTextField { @@ -140,6 +142,7 @@ int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen); void ui_textfield_destroy(GtkWidget *object, UiTextField *textfield); void ui_textfield_changed(GtkEditable *editable, UiTextField *textfield); +void ui_textfield_activate(GtkEntry* self, UiTextField *textfield); char* ui_textfield_get(UiString *str); void ui_textfield_set(UiString *str, const char *value); diff --git a/ui/gtk/toolkit.c b/ui/gtk/toolkit.c index 91ce244..19a0990 100644 --- a/ui/gtk/toolkit.c +++ b/ui/gtk/toolkit.c @@ -300,6 +300,10 @@ void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) { free(data); } +void ui_destroy_widget_var(GtkWidget *object, UiVar *var) { + ui_destroy_boundvar(NULL, var); +} + void ui_destroy_boundvar(UiContext *ctx, UiVar *var) { uic_unbind_var(var); @@ -362,6 +366,18 @@ static const char *ui_gtk_css = ".ui_label_title {\n" " font-weight: bold;\n" "}\n" +".ui-listbox-header {\n" +" font-weight: bold;\n" +" margin-left: 10px;\n" +" margin-top: 12px;\n" +" margin-bottom: 10px;\n" +"}\n" +".ui-listbox-header-first {\n" +" font-weight: bold;\n" +" margin-left: 10px;\n" +" margin-top: 4px;\n" +" margin-bottom: 10px;\n" +"}\n" ; #elif GTK_MAJOR_VERSION == 3 @@ -380,6 +396,21 @@ static const char *ui_gtk_css = ".ui_label_title {\n" " font-weight: bold;\n" "}\n" +"placessidebar row {\n" +" padding-left: 10px;\n" +"}\n" +".ui-listbox-header {\n" +" font-weight: bold;\n" +" margin-left: 10px;\n" +" margin-top: 12px;\n" +" margin-bottom: 10px;\n" +"}\n" +".ui-listbox-header-first {\n" +" font-weight: bold;\n" +" margin-left: 10px;\n" +" margin-top: 4px;\n" +" margin-bottom: 10px;\n" +"}\n" ; #endif diff --git a/ui/gtk/toolkit.h b/ui/gtk/toolkit.h index cdaf42a..c85ac3e 100644 --- a/ui/gtk/toolkit.h +++ b/ui/gtk/toolkit.h @@ -40,7 +40,7 @@ extern "C" { #pragma clang diagnostic ignored "-Wdeprecated-declarations" -#if GLIB_MAJOR_VERSION * 1000 + GLIB_MINOR_VERSION > 74 +#if GLIB_MAJOR_VERSION * 1000 + GLIB_MINOR_VERSION > 2074 #define UI_G_APPLICATION_FLAGS G_APPLICATION_DEFAULT_FLAGS #else #define UI_G_APPLICATION_FLAGS G_APPLICATION_FLAGS_NONE @@ -70,6 +70,9 @@ extern "C" { #define EXPANDER_SET_CHILD(expander, child) gtk_expander_set_child(GTK_EXPANDER(expander), child) #define WIDGET_ADD_CSS_CLASS(w, cssclass) gtk_widget_add_css_class(w, cssclass) #define WIDGET_REMOVE_CSS_CLASS(w, cssclass) gtk_widget_remove_css_class(w, cssclass) +#define ICON_IMAGE(icon) gtk_image_new_from_icon_name(icon) +#define LISTBOX_REMOVE(listbox, row) gtk_list_box_remove(GTK_LIST_BOX(listbox), row) +#define LISTBOX_ROW_SET_CHILD(row, child) gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), child) #else #define WINDOW_SHOW(window) gtk_widget_show_all(window) #define WINDOW_DESTROY(window) gtk_widget_destroy(window) @@ -86,6 +89,9 @@ extern "C" { #define EXPANDER_SET_CHILD(expander, child) gtk_container_add(GTK_CONTAINER(expander), child) #define WIDGET_ADD_CSS_CLASS(w, cssclass) gtk_style_context_add_class(gtk_widget_get_style_context(w), cssclass) #define WIDGET_REMOVE_CSS_CLASS(w, cssclass) gtk_style_context_remove_class(gtk_widget_get_style_context(w), cssclass) +#define ICON_IMAGE(icon) gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_BUTTON) +#define LISTBOX_REMOVE(listbox, row) gtk_container_remove(GTK_CONTAINER(listbox), row) +#define LISTBOX_ROW_SET_CHILD(row, child) gtk_container_add(GTK_CONTAINER(row), child) #endif #ifdef UI_GTK2 @@ -168,6 +174,7 @@ void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, void ui_destroy_userdata(GtkWidget *object, void *userdata); void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data); +void ui_destroy_widget_var(GtkWidget *object, UiVar *var); void ui_destroy_boundvar(UiContext *ctx, UiVar *var); void ui_set_active_window(UiObject *obj); diff --git a/ui/gtk/window.c b/ui/gtk/window.c index 96e1e68..5b04651 100644 --- a/ui/gtk/window.c +++ b/ui/gtk/window.c @@ -101,7 +101,7 @@ static gboolean close_request(GtkWidget* self, GdkEvent* event, UiObject *obj) { } #endif -static UiObject* create_window(const char *title, void *window_data, UiBool simple) { +static UiObject* create_window(const char *title, void *window_data, UiBool sidebar, UiBool simple) { CxMempool *mp = cxBasicMempoolCreate(256); UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject)); obj->ref = 0; @@ -136,7 +136,7 @@ static UiObject* create_window(const char *title, void *window_data, UiBool simp } else { gtk_window_set_default_size( GTK_WINDOW(obj->widget), - window_default_width, + window_default_width + sidebar*250, window_default_height); } @@ -163,8 +163,27 @@ static UiObject* create_window(const char *title, void *window_data, UiBool simp GtkWidget *vbox = ui_gtk_vbox_new(0); #ifdef UI_LIBADWAITA GtkWidget *toolbar_view = adw_toolbar_view_new(); - adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), toolbar_view); adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(toolbar_view), vbox); + + GtkWidget *content_box = ui_gtk_vbox_new(0); + BOX_ADD_EXPAND(GTK_BOX(vbox), content_box); + + if(sidebar) { + GtkWidget *splitview = adw_overlay_split_view_new(); + adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), splitview); + + GtkWidget *sidebar_toolbar_view = adw_toolbar_view_new(); + adw_overlay_split_view_set_sidebar(ADW_OVERLAY_SPLIT_VIEW(splitview), sidebar_toolbar_view); + GtkWidget *sidebar_headerbar = adw_header_bar_new(); + adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), sidebar_headerbar); + + adw_overlay_split_view_set_content(ADW_OVERLAY_SPLIT_VIEW(splitview), toolbar_view); + + g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_toolbar_view); + } else { + adw_application_window_set_content(ADW_APPLICATION_WINDOW(obj->widget), toolbar_view); + } + GtkWidget *headerbar = adw_header_bar_new(); adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar_view), headerbar); @@ -174,10 +193,19 @@ static UiObject* create_window(const char *title, void *window_data, UiBool simp ui_fill_headerbar(obj, headerbar); } #elif GTK_MAJOR_VERSION >= 4 + GtkWidget *content_box = ui_gtk_vbox_new(0); WINDOW_SET_CONTENT(obj->widget, vbox); + if(sidebar) { + GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); + GtkWidget *sidebar_vbox = ui_gtk_vbox_new(0); + gtk_paned_set_start_child(GTK_PANED(paned), sidebar_vbox); + gtk_paned_set_end_child(GTK_PANED(paned), content_box); + BOX_ADD_EXPAND(GTK_BOX(vbox), paned); + g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_vbox); + } else { + BOX_ADD_EXPAND(GTK_BOX(vbox), content_box); + } #else - gtk_container_add(GTK_CONTAINER(obj->widget), vbox); - if(!simple) { // menu if(uic_get_menu_list()) { @@ -198,6 +226,21 @@ static UiObject* create_window(const char *title, void *window_data, UiBool simp //GtkWidget *hb = ui_create_headerbar(obj); //gtk_window_set_titlebar(GTK_WINDOW(obj->widget), hb); } + + GtkWidget *content_box = ui_gtk_vbox_new(0); + WINDOW_SET_CONTENT(obj->widget, vbox); + if(sidebar) { + GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); + GtkWidget *sidebar_vbox = ui_gtk_vbox_new(0); + gtk_paned_add1(GTK_PANED(paned), sidebar_vbox); + gtk_paned_add2(GTK_PANED(paned), content_box); + BOX_ADD_EXPAND(GTK_BOX(vbox), paned); + g_object_set_data(G_OBJECT(obj->widget), "ui_sidebar", sidebar_vbox); + gtk_paned_set_position (GTK_PANED(paned), 200); + } else { + BOX_ADD_EXPAND(GTK_BOX(vbox), content_box); + } + #endif // window content @@ -213,8 +256,6 @@ static UiObject* create_window(const char *title, void *window_data, UiBool simp gtk_container_add(GTK_CONTAINER(frame), content_box); obj->container = ui_box_container(obj, content_box); */ - GtkWidget *content_box = ui_gtk_vbox_new(0); - BOX_ADD_EXPAND(GTK_BOX(vbox), content_box); obj->container = ui_box_container(obj, content_box, UI_CONTAINER_VBOX); nwindows++; @@ -223,11 +264,15 @@ static UiObject* create_window(const char *title, void *window_data, UiBool simp UiObject* ui_window(const char *title, void *window_data) { - return create_window(title, window_data, FALSE); + return create_window(title, window_data, FALSE, FALSE); +} + +UiObject *ui_sidebar_window(const char *title, void *window_data) { + return create_window(title, window_data, TRUE, FALSE); } UiObject* ui_simple_window(const char *title, void *window_data) { - return create_window(title, window_data, TRUE); + return create_window(title, window_data, FALSE, TRUE); } void ui_window_size(UiObject *obj, int width, int height) { diff --git a/ui/motif/Grid.c b/ui/motif/Grid.c new file mode 100644 index 0000000..32034d1 --- /dev/null +++ b/ui/motif/Grid.c @@ -0,0 +1,582 @@ +/* + * 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. + */ + +/* + * + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "Grid.h" + +#include + + + +static XtActionsRec actionslist[] = { + {"getfocus",grid_getfocus}, + {"loosefocus",grid_loosefocus}, + {"NULL",NULL} +}; + +//static char defaultTranslations[] = ": mousedown()\n"; +static char defaultTranslations[] = "\ +: getfocus()\n\ +: loosefocus()\n"; + + +///* +static XtResource constraints[] = +{ + { + gridColumn, + gridColumn, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.x), + XmRImmediate, + (XtPointer) 0 + }, + { + gridRow, + gridRow, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.y), + XmRImmediate, + (XtPointer) 0 + }, + { + gridColspan, + gridColspan, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.colspan), + XmRImmediate, + (XtPointer) 0 + }, + { + gridRowspan, + gridRowspan, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.rowspan), + XmRImmediate, + (XtPointer) 0 + }, + { + gridMarginLeft, + gridMarginLeft, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.margin_left), + XmRImmediate, + (XtPointer) 0 + }, + { + gridMarginRight, + gridMarginRight, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.margin_right), + XmRImmediate, + (XtPointer) 0 + }, + { + gridMarginTop, + gridMarginTop, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.margin_top), + XmRImmediate, + (XtPointer) 0 + }, + { + gridMarginBottom, + gridMarginBottom, + XmRDimension, + sizeof (Dimension), + XtOffsetOf( GridConstraintRec, + grid.margin_bottom), + XmRImmediate, + (XtPointer) 0 + }, + { + gridHExpand, + gridHExpand, + XmRBoolean, + sizeof (Boolean), + XtOffsetOf( GridConstraintRec, + grid.hexpand), + XmRImmediate, + (XtPointer) 0 + }, + { + gridVExpand, + gridVExpand, + XmRBoolean, + sizeof (Boolean), + XtOffsetOf( GridConstraintRec, + grid.vexpand), + XmRImmediate, + (XtPointer) 0 + }, + { + gridHFill, + gridHFill, + XmRBoolean, + sizeof (Boolean), + XtOffsetOf( GridConstraintRec, + grid.hfill), + XmRImmediate, + (XtPointer) 0 + }, + { + gridVFill, + gridVFill, + XmRBoolean, + sizeof (Boolean), + XtOffsetOf( GridConstraintRec, + grid.vfill), + XmRImmediate, + (XtPointer) 0 + } + +}; +//*/ +//static XtResource constraints[] = {}; + +GridClassRec gridClassRec = { + // Core Class + { + //(WidgetClass)&constraintClassRec, // superclass + (WidgetClass)&xmManagerClassRec, + "Grid", // class_name + sizeof(GridRec), // widget_size + grid_class_initialize, // class_initialize + NULL, // class_part_initialize + FALSE, // class_inited + (XtInitProc)grid_initialize, // initialize + NULL, // initialize_hook + grid_realize, // realize + actionslist, // actions + XtNumber(actionslist), // num_actions + NULL, // resources + 0, // num_resources + NULLQUARK, // xrm_class + True, // compress_motion + True, // compress_exposure + True, // compress_enterleave + False, // visible_interest + (XtWidgetProc)grid_destroy, // destroy + (XtWidgetProc)grid_resize, // resize + (XtExposeProc)grid_expose, // expose + grid_set_values, // set_values + NULL, // set_values_hook + XtInheritSetValuesAlmost, // set_values_almost + NULL, // get_values_hook + (XtAcceptFocusProc)grid_acceptfocus, // accept_focus + XtVersion, // version + NULL, // callback_offsets + //NULL, // tm_table + defaultTranslations, + XtInheritQueryGeometry, // query_geometry + NULL, // display_accelerator + NULL, // extension + }, + // Composite Class + { + GridGeometryManager, /* geometry_manager */ + GridChangeManaged, /* change_managed */ + XtInheritInsertChild, /* insert_child */ + XtInheritDeleteChild, /* delete_child */ + NULL, /* extension */ + }, + // Constraint Class + { + constraints, /* resources */ + XtNumber(constraints), /* num_resources */ + sizeof(GridConstraintRec), /* constraint_size */ + grid_constraint_init, /* initialize */ + NULL, /* destroy */ + ConstraintSetValues, /* set_values */ + NULL, /* extension */ + }, + // XmManager Class + ///* + { + NULL, + NULL, + 0, + NULL, + 0, + NULL, + NULL + }, + //*/ + // MyWidget Class + { + 0 + } +}; + +WidgetClass gridClass = (WidgetClass)&gridClassRec; + + +void grid_class_initialize(Widget request, Widget new, ArgList args, Cardinal *num_args) { + +} +void grid_initialize(Widget request, Widget new, ArgList args, Cardinal num_args) { + MyWidget mn = (MyWidget)new; + + mn->mywidget.max_col = 0; + mn->mywidget.max_row = 0; + +} +void grid_realize(MyWidget w,XtValueMask *valueMask,XSetWindowAttributes *attributes) { + XtMakeResizeRequest((Widget)w, 400, 400, NULL, NULL); + (coreClassRec.core_class.realize)((Widget)w, valueMask, attributes); + grid_place_children(w); +} + + +void grid_destroy(MyWidget widget) { + +} +void grid_resize(MyWidget widget) { + grid_place_children(widget); +} + +void grid_expose(MyWidget widget, XEvent *event, Region region) { + +} + + +Boolean grid_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) { + return False; +} + +Boolean grid_acceptfocus(Widget w, Time *t) { + +} + +void grid_getfocus(MyWidget myw, XEvent *event, String *params, Cardinal *nparam) { + +} + +void grid_loosefocus(MyWidget myw, XEvent *event, String *params, Cardinal *nparam) { + +} + + + +XtGeometryResult GridGeometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply) { + GridRec *grid = (GridRec*)XtParent(widget); + GridConstraintRec *constraints = widget->core.constraints; + //XtVaSetValues(widget, XmNwidth, request->width, XmNheight, request->height, NULL); + if((request->request_mode & CWWidth) == CWWidth) { + widget->core.width = request->width; + constraints->grid.pref_width = request->width; + } + if((request->request_mode & CWHeight) == CWHeight) { + widget->core.height = request->height; + constraints->grid.pref_height = request->height; + } + grid_place_children((MyWidget)XtParent(widget)); + return XtGeometryYes; +} + +void GridChangeManaged(Widget widget) { + +} + +Boolean ConstraintSetValues(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) { + GridConstraintRec *constraints = neww->core.constraints; + MyWidget grid = (MyWidget)XtParent(neww); + if(constraints->grid.x > grid->mywidget.max_col) { + grid->mywidget.max_col = constraints->grid.x; + } + if(constraints->grid.y > grid->mywidget.max_row) { + grid->mywidget.max_row = constraints->grid.y; + } +} + + +void grid_constraint_init( + Widget request, + Widget neww, + ArgList args, + Cardinal* num_args +) +{ + GridConstraintRec *constraints = neww->core.constraints; + + MyWidget grid = (MyWidget)XtParent(neww); + if(constraints->grid.x > grid->mywidget.max_col) { + grid->mywidget.max_col = constraints->grid.x; + } + if(constraints->grid.y > grid->mywidget.max_row) { + grid->mywidget.max_row = constraints->grid.y; + } + constraints->grid.pref_width = neww->core.width; + constraints->grid.pref_height = neww->core.height; +} + +void grid_place_children(MyWidget w) { + int ncols = w->mywidget.max_col+1; + int nrows = w->mywidget.max_row+1; + GridDef *cols = calloc(ncols, sizeof(GridDef)); + GridDef *rows = calloc(nrows, sizeof(GridDef)); + int num_cols_expanding = 0; + int num_rows_expanding = 0; + int req_width = 0; + int req_height = 0; + + // calculate the minimum size requirements for all columns and rows + // we need to run this 2 times: for widgets without colspan/rowspan first + // and then again for colspan/rowspan > 1 + int span_max = 1; + for(int r=0;r<2;r++) { + for(int i=0;icomposite.num_children;i++) { + Widget child = w->composite.children[i]; + GridConstraintRec *constraints = child->core.constraints; + + if(constraints->grid.colspan > span_max || constraints->grid.rowspan > span_max) { + continue; + } + + int x = constraints->grid.x; + int y = constraints->grid.y; + // make sure ncols/nrows is correct + // errors shouldn't happen, unless someone messes up the grid internals + if(x >= ncols) { + fprintf(stderr, "Error: widget x out of bounds\n"); + continue; + } + if(y >= nrows) { + fprintf(stderr, "Error: widget y out of bounds\n"); + continue; + } + GridDef *col = &cols[x]; + GridDef *row = &rows[y]; + + if(constraints->grid.hexpand) { + if(constraints->grid.colspan > 1) { + // check if any column in the span is expanding + // if not, make the last column expanding + GridDef *last_col = col; + for(int c=x;cexpand) { + break; + } + } + last_col->expand = TRUE; + } else { + col->expand = TRUE; + } + } + if(constraints->grid.vexpand) { + if(constraints->grid.rowspan > 1) { + GridDef *last_row = row; + for(int c=x;cexpand) { + break; + } + } + last_row->expand = TRUE; + } else { + row->expand = TRUE; + } + } + + // column size + if(constraints->grid.colspan > 1) { + // check size of all columns in span + Dimension span_width = col->size; + GridDef *last_col = col; + for(int s=x+1;ssize; + + } + int diff = constraints->grid.pref_width - span_width; + if(diff > 0) { + last_col->size += diff; + } + } else if(constraints->grid.pref_width > col->size) { + col->size = constraints->grid.pref_width; + } + // row size + if(constraints->grid.rowspan > 1) { + Dimension span_height = row->size; + GridDef *last_row = row; + for(int s=x+1;ssize; + + } + int diff = constraints->grid.pref_height - span_height; + if(diff > 0) { + last_row->size += diff; + } + } else if(constraints->grid.pref_height > row->size) { + row->size = constraints->grid.pref_height; + } + } + span_max = 50000; // not sure if this is unreasonable low or high + } + + + for(int i=0;i 0 && req_height > 0) { + Widget parent = w->core.parent; + Dimension rwidth = req_width; + Dimension rheight = req_height; + if(rwidth < w->core.width) { + //rwidth = w->core.width; + } + if(rheight < w->core.height) { + //rheight = w->core.height; + } + + if(!w->mywidget.sizerequest) { + Dimension actual_width, actual_height; + w->mywidget.sizerequest = TRUE; + XtMakeResizeRequest((Widget)w, req_width, req_height, &actual_width, &actual_height); + w->mywidget.sizerequest = FALSE; + //printf("size request: %d %d\n", (int)actual_width, (int)actual_height); + } + + + + } + + int hexpand = 0; + int width_diff = (int)w->core.width - req_width; + int hexpand2 = 0; + if(width_diff > 0 && num_cols_expanding > 0) { + hexpand = width_diff / num_cols_expanding; + hexpand2 = width_diff-hexpand*num_cols_expanding; + } + int x = 0; + for(int i=0;icore.height - req_height; + int vexpand2 = 0; + if(height_diff > 0 && num_rows_expanding > 0) { + vexpand = height_diff / num_rows_expanding; + vexpand2 = height_diff-vexpand*num_rows_expanding; + } + int y = 0; + for(int i=0;icomposite.num_children;i++) { + Widget child = w->composite.children[i]; + GridConstraintRec *constraints = child->core.constraints; + GridDef c = cols[constraints->grid.x]; + GridDef r = rows[constraints->grid.y]; + int x = c.pos; + int y = r.pos; + int width = constraints->grid.pref_width; + int height = constraints->grid.pref_height; + if(constraints->grid.hfill) { + if(constraints->grid.colspan > 1) { + Dimension cwidth = 0; + for(int j=0;jgrid.colspan;j++) { + if(constraints->grid.x+j < ncols) { + cwidth += cols[constraints->grid.x+j].size; + } + } + width = cwidth; + } else { + width = c.size; + } + } + if(constraints->grid.vfill) { + if(constraints->grid.rowspan > 1) { + Dimension cheight = 0; + for(int j=0;jgrid.rowspan;j++) { + if(constraints->grid.y+j < nrows) { + cheight += rows[constraints->grid.y+j].size; + } + } + height = cheight; + } else { + height = r.size; + } + } + + XtConfigureWidget(child, x, y, width, height, child->core.border_width); + //printf("child %d %d - %d %d\n", (int)child->core.x, (int)child->core.y, (int)child->core.width, (int)child->core.height); + } + + free(cols); + free(rows); +} + diff --git a/ui/motif/Grid.h b/ui/motif/Grid.h new file mode 100644 index 0000000..429ca39 --- /dev/null +++ b/ui/motif/Grid.h @@ -0,0 +1,152 @@ +/* + * 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 GRID_H +#define GRID_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define gridColumn "gridColumn" +#define gridRow "gridRow" +#define gridColspan "gridColspan" +#define gridRowspan "gridRowspan" +#define gridHExpand "gridHExpand" +#define gridVExpand "gridVExpand" +#define gridHFill "gridHFill" +#define gridVFill "gridVFill" +#define gridMarginLeft "gridMarginLeft" +#define gridMarginRight "gridMarginRight" +#define gridMarginTop "gridMarginTop" +#define gridMarginBottom "gridMarginBottom" + + +typedef struct GridDef { + Dimension size; + Dimension pos; + Boolean expand; +} GridDef; + +typedef struct GridClassPart { + int test; +} GridClassPart; + +typedef struct GridClassRec { + CoreClassPart core_class; + CompositeClassPart composite_class; + ConstraintClassPart constraint_class; + XmManagerClassPart manager_class; + GridClassPart mywidgetclass; +} GridClassRec; + + +typedef struct GridPart { + int margin_left; + int margin_right; + int margin_top; + int margin_bottom; + int max_col; + int max_row; + + Boolean sizerequest; +} GridPart; + +typedef struct GridRec { + CorePart core; + CompositePart composite; + ConstraintPart constraint; + XmManagerPart manager; + GridPart mywidget; +} GridRec; + +typedef struct GridContraintPart { + Dimension x; + Dimension y; + Dimension margin_left; + Dimension margin_right; + Dimension margin_top; + Dimension margin_bottom; + Boolean hexpand; + Boolean vexpand; + Boolean hfill; + Boolean vfill; + Dimension colspan; + Dimension rowspan; + Dimension pref_width; + Dimension pref_height; +} GridContraintPart; + +typedef struct GridConstraintRec { + XmManagerConstraintPart manager; + GridContraintPart grid; +} GridConstraintRec; + +typedef GridRec* MyWidget; + +extern WidgetClass gridClass; + +void grid_class_initialize(); +void grid_initialize(); +void grid_realize(); +void grid_destroy(); +void grid_resize(); +void grid_expose(); +Boolean grid_set_values(); +Boolean grid_acceptfocus(Widget , Time*); + +void grid_place_children(MyWidget w); + +void grid_getfocus(); +void grid_loosefocus(); + +void grid_constraint_init( + Widget request, + Widget neww, + ArgList args, + Cardinal* num_args +); + +XtGeometryResult GridGeometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply); +void GridChangeManaged(Widget widget); +Boolean ConstraintSetValues(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args); + + +#ifdef __cplusplus +} +#endif + +#endif /* GRID_H */ + diff --git a/ui/motif/button.c b/ui/motif/button.c index 8757fdf..825a755 100644 --- a/ui/motif/button.c +++ b/ui/motif/button.c @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -38,69 +38,54 @@ #include #include +#include -UIWIDGET ui_button(UiObject *obj, char *label, ui_callback f, void *data) { - UiContainer *ct = uic_get_current_container(obj); - XmString str = XmStringCreateLocalized(label); - + +UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) { + Arg xargs[16]; int n = 0; - Arg args[16]; - - XtSetArg(args[n], XmNlabelString, str); - n++; - - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget button = XmCreatePushButton(parent, "button", args, n); - ct->add(ct, button); - - if(f) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = data; - event->callback = f; - event->value = 0; + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + + XmString label = NULL; + if(args.label) { + label = XmStringCreateLocalized((char*)args.label); + XtSetArg(xargs[n], XmNlabelString, label); n++; + } + + char *name = args.name ? (char*)args.name : "button"; + Widget button = XmCreatePushButton(parent, name, xargs, n); + XtManageChild(button); + ctn->add(ctn, button); + + ui_set_widget_groups(obj->ctx, button, args.groups); + + if(args.onclick) { + UiEventData *eventdata = malloc(sizeof(UiEventData)); + eventdata->callback = args.onclick; + eventdata->userdata = args.onclickdata; + eventdata->obj = obj; + eventdata->value = 0; XtAddCallback( button, XmNactivateCallback, (XtCallbackProc)ui_push_button_callback, - event); + eventdata); + XtAddCallback( + button, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + eventdata); } - XtManageChild(button); + XmStringFree(label); return button; } -// wrapper -int64_t ui_toggle_button_get(UiInteger *i) { - int state = 0; - XtVaGetValues(i->obj, XmNset, &state, NULL); - i->value = state; - return state; -} - -void ui_toggle_button_set(UiInteger *i, int64_t value) { - Arg arg; - XtSetArg(arg, XmNset, value); - XtSetValues(i->obj, &arg, 1); - i->value = value; -} - -void ui_toggle_button_callback( - Widget widget, - UiEventData *event, - XmToggleButtonCallbackStruct *tb) -{ - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - // TODO: e.document - e.intval = tb->set; - event->callback(&e, event->userdata); -} - void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d) { UiEvent e; e.obj = event->obj; @@ -110,105 +95,344 @@ void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d) { event->callback(&e, event->userdata); } +UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) { + Arg xargs[16]; + int n = 0; + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + XtSetArg(xargs[n], XmNfillOnSelect, True); n++; + XtSetArg(xargs[n], XmNindicatorOn, False); n++; + + XmString label = NULL; + if(args.label) { + label = XmStringCreateLocalized((char*)args.label); + XtSetArg(xargs[n], XmNlabelString, label); n++; + } + + char *name = args.name ? (char*)args.name : "togglebutton"; + Widget button = XmCreateToggleButton(parent, name, xargs, n); + XtManageChild(button); + ctn->add(ctn, button); + + ui_set_widget_groups(obj->ctx, button, args.groups); + + ui_bind_togglebutton(obj, button, args.varname, args.value, args.onchange, args.onchangedata, args.enable_group); + + XmStringFree(label); + return button; +} + +UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) { + Arg xargs[16]; + int n = 0; + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + + XmString label = NULL; + if(args.label) { + label = XmStringCreateLocalized((char*)args.label); + XtSetArg(xargs[n], XmNlabelString, label); n++; + } + + char *name = args.name ? (char*)args.name : "button"; + Widget button = XmCreateToggleButton(parent, name, xargs, n); + XtManageChild(button); + ctn->add(ctn, button); + + ui_set_widget_groups(obj->ctx, button, args.groups); + + ui_bind_togglebutton(obj, button, args.varname, args.value, args.onchange, args.onchangedata, args.enable_group); + + XmStringFree(label); + return button; +} + +UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) { + return ui_checkbox_create(obj, args); +} + +static void togglebutton_changed(Widget w, UiVarEventData *event, XmToggleButtonCallbackStruct *tb) { + if(event->value > 0) { + // button in configured to enable/disable states + if(tb->set) { + ui_set_group(event->obj->ctx, event->value); + } else { + ui_unset_group(event->obj->ctx, event->value); + } + } + + UiEvent e; + e.obj = event->obj; + e.window = e.obj->window; + e.document = e.obj->ctx->document; + e.eventdata = NULL; + e.intval = XmToggleButtonGetState(w); + + if(event->callback) { + event->callback(&e, event->userdata); + } + + if(event->var && event->var->value) { + UiInteger *v = event->var->value; + v->value = e.intval; + ui_notify_evt(v->observers, &e); + } +} -static void radio_callback( +void ui_bind_togglebutton( + UiObject *obj, Widget widget, - RadioEventData *event, - XmToggleButtonCallbackStruct *tb) + const char *varname, + UiInteger *value, + ui_callback onchange, + void *onchangedata, + int enable_state) { - if(tb->set) { - RadioButtonGroup *group = event->group; - if(group->current) { - Arg arg; - XtSetArg(arg, XmNset, FALSE); - XtSetValues(group->current, &arg, 1); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER); + if(var) { + value = (UiInteger*)var->value; + value->obj = widget; + value->get = ui_togglebutton_get; + value->set = ui_togglebutton_set; + + if(value->value) { + XmToggleButtonSetState(widget, True, False); } - group->current = widget; } + + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + event->obj = obj; + event->callback = onchange; + event->userdata = onchangedata; + event->var = var; + event->observers = NULL; + event->value = enable_state; + XtAddCallback( + widget, + XmNvalueChangedCallback, + (XtCallbackProc)togglebutton_changed, + event); + XtAddCallback( + widget, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + event); } -UIWIDGET ui_radiobutton(UiObject *obj, char *label, UiInteger *rgroup) { - UiContainer *ct = uic_get_current_container(obj); - XmString str = XmStringCreateLocalized(label); +int64_t ui_togglebutton_get(UiInteger *i) { + Widget togglebutton = i->obj; + Boolean state = XmToggleButtonGetState(togglebutton); + i->value = state; + return state; +} + +void ui_togglebutton_set(UiInteger *i, int64_t value) { + Widget togglebutton = i->obj; + i->value = value; + XmToggleButtonSetState(togglebutton, (Boolean)value, False); +} + +static void destroy_list(Widget w, CxList *list, XtPointer d) { + cxListDestroy(list); +} + +static void radiobutton_changed(Widget w, UiVarEventData *event, XmToggleButtonCallbackStruct *tb) { + if(event->value > 0) { + // button in configured to enable/disable states + if(tb->set) { + ui_set_group(event->obj->ctx, event->value); + } else { + ui_unset_group(event->obj->ctx, event->value); + } + } - int n = 0; - Arg args[16]; - - XtSetArg(args[n], XmNlabelString, str); - n++; - XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY_ROUND); - n++; - - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget button = XmCreateToggleButton(parent, "radiobutton", args, n); - ct->add(ct, button); - - if(rgroup) { - RadioButtonGroup *group; - if(rgroup->obj) { - group = rgroup->obj; - if(!group->buttons) { - group->buttons = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 8); + if(!tb->set) { + return; // only handle set-events + } + + UiInteger *value = NULL; + int64_t v = 0; + if(event->var) { + value = event->var->value; + // find widget index and update all radiobuttons + // the UiInteger value must always be up-to-date + CxList *list = value->obj; + CxIterator i = cxListIterator(list); + cx_foreach(Widget, button, i) { + Boolean state = False; + if(button == w) { + value->value = i.index+1; // update value + state = True; } - cxListAdd(group->buttons, button); - group->ref++; - } else { - group = malloc(sizeof(RadioButtonGroup)); - group->buttons = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 8); - cxListAdd(group->buttons, button); - group->current = button; - // this is the first button in the radiobutton group - // so we should enable it - Arg arg; - XtSetArg(arg, XmNset, TRUE); - XtSetValues(button, &arg, 1); - rgroup->obj = group; + XmToggleButtonSetState(button, state, False); + } + v = value->value; + } + + UiEvent e; + e.obj = event->obj; + e.window = e.obj->window; + e.document = e.obj->ctx->document; + e.eventdata = value; + e.intval = v; + + if(event->callback) { + event->callback(&e, event->userdata); + } + + if(value) { + ui_notify_evt(value->observers, &e); + } +} + +void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const char *varname, ui_callback onchange, void *onchangedata, int enable_group) { + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER); + if(var) { + UiInteger *value = var->value; + CxList *rb = value->obj; + if(!rb) { + // first button in the radiobutton group + // create a list for all buttons and use the list as value obj + rb = cxArrayListCreateSimple(CX_STORE_POINTERS, 4); + value->obj = rb; + value->get = ui_radiobutton_get; + value->set = ui_radiobutton_set; - group->current = button; + // the first radio button is also responsible for cleanup + XtAddCallback( + rbutton, + XmNdestroyCallback, + (XtCallbackProc)destroy_list, + rb); } + cxListAdd(rb, rbutton); - RadioEventData *event = malloc(sizeof(RadioEventData)); - event->obj = obj; - event->callback = NULL; - event->userdata = NULL; - event->group = group; - XtAddCallback( - button, + // set the radiobutton state, if the value is already set + if(cxListSize(rb) == value->value) { + XmToggleButtonSetState(rbutton, True, False); + } + } + + // the radio button needs to handle change events to update all + // other buttons in the radio button group + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + event->obj = obj; + event->callback = onchange; + event->userdata = onchangedata; + event->observers = NULL; + event->var = var; + event->value = enable_group; + XtAddCallback( + rbutton, XmNvalueChangedCallback, - (XtCallbackProc)radio_callback, + (XtCallbackProc)radiobutton_changed, + event); + XtAddCallback( + rbutton, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, event); +} + +UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs args) { + Arg xargs[16]; + int n = 0; + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + XtSetArg(xargs[n], XmNindicatorType, XmONE_OF_MANY_ROUND); n++; + XmString label = NULL; + if(args.label) { + label = XmStringCreateLocalized((char*)args.label); + XtSetArg(xargs[n], XmNlabelString, label); n++; + } + + char *name = args.name ? (char*)args.name : "button"; + Widget button = XmCreateToggleButton(parent, name, xargs, n); + XtManageChild(button); + ctn->add(ctn, button); + + ui_set_widget_groups(obj->ctx, button, args.groups); + + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER); + if(var) { + UiInteger *value = var->value; + CxList *rb = value->obj; + if(!rb) { + // first button in the radiobutton group + // create a list for all buttons and use the list as value obj + rb = cxArrayListCreateSimple(CX_STORE_POINTERS, 4); + value->obj = rb; + value->get = ui_radiobutton_get; + value->set = ui_radiobutton_set; + + // the first radio button is also responsible for cleanup + XtAddCallback( + button, + XmNdestroyCallback, + (XtCallbackProc)destroy_list, + rb); + } + cxListAdd(rb, button); - rgroup->get = ui_radiobutton_get; - rgroup->set = ui_radiobutton_set; + // set the radiobutton state, if the value is already set + if(cxListSize(rb) == value->value) { + XmToggleButtonSetState(button, True, False); + } } - XtManageChild(button); + // the radio button needs to handle change events to update all + // other buttons in the radio button group + UiVarEventData *event = malloc(sizeof(UiVarEventData)); + event->obj = obj; + event->callback = args.onchange; + event->userdata = args.onchangedata; + event->observers = NULL; + event->var = var; + event->value = args.enable_group; + XtAddCallback( + button, + XmNvalueChangedCallback, + (XtCallbackProc)radiobutton_changed, + event); + XtAddCallback( + button, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + event); + + XmStringFree(label); return button; + + } -int64_t ui_radiobutton_get(UiInteger *value) { - RadioButtonGroup *group = value->obj; - - int i = cxListFind(group->buttons, group->current); - if (i >= 0) { - value->value = i; - return i; - } else { - return 0; - } +int64_t ui_radiobutton_get(UiInteger *i) { + // the UiInteger should be updated automatically by change events + return i->value; } -void ui_radiobutton_set(UiInteger *value, int64_t i) { - RadioButtonGroup *group = value->obj; - Arg arg; - - XtSetArg(arg, XmNset, FALSE); - XtSetValues(group->current, &arg, 1); - - Widget button = cxListAt(group->buttons, i); - if(button) { - XtSetArg(arg, XmNset, TRUE); - XtSetValues(button, &arg, 1); - group->current = button; +void ui_radiobutton_set(UiInteger *i, int64_t value) { + CxList *list = i->obj; + if(i->value > 0) { + Widget current = cxListAt(list, i->value-1); + if(current) { + XmToggleButtonSetState(current, False, False); + } + } + if(value > 0 && value <= cxListSize(list)) { + Widget button = cxListAt(list, value-1); + if(button) { + XmToggleButtonSetState(button, True, False); + i->value = value; + } } } diff --git a/ui/motif/button.h b/ui/motif/button.h index 9fd7dca..b6dd711 100644 --- a/ui/motif/button.h +++ b/ui/motif/button.h @@ -36,30 +36,24 @@ extern "C" { #endif -typedef struct { - CxList *buttons; - Widget current; - int ref; -} RadioButtonGroup; - -typedef struct { - UiObject *obj; - ui_callback callback; - void *userdata; - RadioButtonGroup *group; -} RadioEventData; +void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d); -// wrapper -int64_t ui_toggle_button_get(UiInteger *i); -void ui_toggle_button_set(UiInteger *i, int64_t value); -void ui_toggle_button_callback( +void ui_bind_togglebutton( + UiObject *obj, Widget widget, - UiEventData *data, - XmToggleButtonCallbackStruct *e); -void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d); + const char *varname, + UiInteger *value, + ui_callback onchange, + void *onchangedata, + int enable_state); + +int64_t ui_togglebutton_get(UiInteger *i); +void ui_togglebutton_set(UiInteger *i, int64_t value); + +void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const char *varname, ui_callback onchange, void *onchangedata, int enable_group); -int64_t ui_radiobutton_get(UiInteger *value); -void ui_radiobutton_set(UiInteger *value, int64_t i); +int64_t ui_radiobutton_get(UiInteger *i); +void ui_radiobutton_set(UiInteger *i, int64_t value); #ifdef __cplusplus } diff --git a/ui/motif/container.c b/ui/motif/container.c index 007c10f..57f3795 100644 --- a/ui/motif/container.c +++ b/ui/motif/container.c @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -34,753 +34,191 @@ #include "../common/context.h" #include "../common/object.h" -#include -#include -#include +#include "Grid.h" -#define UI_GRID_MAX_COLUMNS 512 +/* ---------------------------- Box Container ---------------------------- */ -static UiBool ui_lb2bool(UiLayoutBool b) { - return b == UI_LAYOUT_TRUE ? TRUE : FALSE; -} - -static UiLayoutBool ui_bool2lb(UiBool b) { - return b ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE; -} - - -UiContainer* ui_frame_container(UiObject *obj, Widget frame) { - UiContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiContainer)); - ct->widget = frame; - ct->prepare = ui_frame_container_prepare; - ct->add = ui_frame_container_add; - return ct; -} - -Widget ui_frame_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { - return ct->widget; -} - -void ui_frame_container_add(UiContainer *ct, Widget widget) { - ui_reset_layout(ct->layout); - ct->current = widget; -} - - -UiContainer* ui_box_container(UiObject *obj, Widget box, int margin, int spacing, UiBoxOrientation orientation) { - UiBoxContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiBoxContainer)); - ct->container.widget = box; - ct->container.prepare = ui_box_container_prepare; - ct->container.add = ui_box_container_add; - ct->orientation = orientation; - ct->margin = margin; - ct->spacing = spacing; - return (UiContainer*)ct; -} - -Widget ui_box_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { - UiBoxContainer *bc = (UiBoxContainer*)ct; - if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { - fill = ui_lb2bool(ct->layout.fill); - } - - if(bc->has_fill && fill) { - fprintf(stderr, "UiError: container has 2 filled widgets"); - fill = FALSE; - } - if(fill) { - bc->has_fill = TRUE; - } +static UIWIDGET box_create(UiObject *obj, UiContainerArgs args, UiBoxOrientation orientation) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); - int a = *n; - // determine fixed and dynamic attachments - void *f1; - void *f2; - void *d1; - void *d2; - void *w1; - void *w2; - if(bc->orientation == UI_BOX_VERTICAL) { - f1 = XmNleftAttachment; - f2 = XmNrightAttachment; - d1 = XmNtopAttachment; - d2 = XmNbottomAttachment; - w1 = XmNtopWidget; - w2 = XmNbottomWidget; - - // margin/spacing - XtSetArg(args[a], XmNleftOffset, bc->margin); a++; - XtSetArg(args[a], XmNrightOffset, bc->margin); a++; - - XtSetArg(args[a], XmNtopOffset, bc->prev_widget ? bc->spacing : bc->margin); a++; - } else { - f1 = XmNtopAttachment; - f2 = XmNbottomAttachment; - d1 = XmNleftAttachment; - d2 = XmNrightAttachment; - w1 = XmNleftWidget; - w2 = XmNrightWidget; - - // margin/spacing - XtSetArg(args[a], XmNtopOffset, bc->margin); a++; - XtSetArg(args[a], XmNbottomOffset, bc->margin); a++; - - XtSetArg(args[a], XmNleftOffset, bc->prev_widget ? bc->spacing : bc->margin); a++; - } - XtSetArg(args[a], f1, XmATTACH_FORM); a++; - XtSetArg(args[a], f2, XmATTACH_FORM); a++; - - if(fill) { - XtSetArg(args[a], d2, XmATTACH_FORM); a++; - } - if(bc->prev_widget) { - XtSetArg(args[a], d1, XmATTACH_WIDGET); a++; - XtSetArg(args[a], w1, bc->prev_widget); a++; - } else { - XtSetArg(args[a], d1, XmATTACH_FORM); a++; - } - - *n = a; - return ct->widget; -} - -void ui_box_container_add(UiContainer *ct, Widget widget) { - UiBoxContainer *bc = (UiBoxContainer*)ct; - // determine dynamic attachments - void *d1; - void *d2; - void *w1; - void *w2; - if(bc->orientation == UI_BOX_VERTICAL) { - d1 = XmNtopAttachment; - d2 = XmNbottomAttachment; - w1 = XmNtopWidget; - w2 = XmNbottomWidget; - - } else { - d1 = XmNleftAttachment; - d2 = XmNrightAttachment; - w1 = XmNleftWidget; - w2 = XmNrightWidget; - } - - if(bc->prev_widget) { - int v = 0; - XtVaGetValues(bc->prev_widget, d2, &v, NULL); - if(v == XmATTACH_FORM) { - XtVaSetValues( - bc->prev_widget, - d2, - XmATTACH_WIDGET, - w2, - widget, - NULL); - XtVaSetValues( - widget, - d1, - XmATTACH_NONE, - d2, - XmATTACH_FORM, - NULL); - } - } - bc->prev_widget = widget; - - ui_reset_layout(ct->layout); - ct->current = widget; -} - -UiContainer* ui_grid_container(UiObject *obj, Widget form, int columnspacing, int rowspacing) { - UiGridContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiGridContainer)); - ct->container.widget = form; - ct->container.prepare = ui_grid_container_prepare; - ct->container.add = ui_grid_container_add; - ct->columnspacing = columnspacing; - ct->rowspacing = rowspacing; - ct->lines = cxLinkedListCreateSimple(CX_STORE_POINTERS); - return (UiContainer*)ct; -} - -void ui_grid_newline(UiGridContainer *grid) { - if(grid->current) { - grid->current = NULL; - } - grid->container.layout.newline = FALSE; -} - -Widget ui_grid_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { - UiGridContainer *grid = (UiGridContainer*)ct; - if(ct->layout.newline) { - ui_grid_newline(grid); - } - return ct->widget; -} - -void ui_grid_container_add(UiContainer *ct, Widget widget) { - UiGridContainer *grid = (UiGridContainer*)ct; + Arg xargs[16]; + int n = 0; - if(grid->current) { - cxListAdd(grid->current, widget); + if(orientation == UI_BOX_VERTICAL) { + //XtSetArg(xargs[n], gridRowSpacing, args.spacing); n++; } else { - grid->current = cxLinkedListCreateSimple(CX_STORE_POINTERS); - cxListAdd(grid->current, widget); - cxListAdd(grid->lines, grid->current); - } - - ui_reset_layout(ct->layout); - ct->current = widget; -} - -static void ui_grid_resize(Widget widget, XtPointer udata, XtPointer cdata) { - UiGridContainer *grid = udata; - - CxList *rowdim = cxArrayListCreateSimple(sizeof(int), grid->lines->size); - int coldim[UI_GRID_MAX_COLUMNS]; - memset(coldim, 0, UI_GRID_MAX_COLUMNS*sizeof(int)); - int numcol = 0; - - // get the minimum size of the columns and rows - int sumw = 0; - int sumh = 0; - CxIterator lineIterator = cxListIterator(grid->lines); - cx_foreach(CxList *, row, lineIterator) { - int rheight = 0; - int i=0; - int sum_width = 0; - CxIterator colIterator = cxListIterator(row); - cx_foreach(Widget, w, colIterator) { - int widget_width = 0; - int widget_height = 0; - XtVaGetValues( - w, - XmNwidth, - &widget_width, - XmNheight, - &widget_height, - NULL); - - // get the maximum height in this row - if(widget_height > rheight) { - rheight = widget_height; - } - - // get the maximum width in this column - if(widget_width > coldim[i]) { - coldim[i] = widget_width; - } - sum_width += widget_width; - if(sum_width > sumw) { - sumw = sum_width; - } - - i++; - if(i > numcol) { - numcol = i; - } - } - cxListAdd(rowdim, &rheight); - sumh += rheight; - } - - // check container size - int gwidth = 0; - int gheight = 0; - XtVaGetValues(widget, XmNwidth, &gwidth, XmNheight, &gheight, NULL); - if(gwidth < sumw || gheight < sumh) { - XtVaSetValues(widget, XmNwidth, sumw, XmNheight, sumh, NULL); - cxListDestroy(rowdim); - return; + //XtSetArg(xargs[n], gridColumnSpacing, args.spacing); n++; } + Widget parent = ctn->prepare(ctn, xargs, &n); + Widget grid = XtCreateManagedWidget(args.name ? args.name : "boxcontainer", gridClass, parent, xargs, n); + ctn->add(ctn, grid); - // adjust the positions of all children - int y = 0; - lineIterator = cxListIterator(grid->lines); - cx_foreach(CxList *, row, lineIterator) { - int x = 0; - int i=0; - int *rowheight = cxListAt(rowdim, lineIterator.index); - CxIterator colIterator = cxListIterator(row); - cx_foreach(Widget, w, colIterator) { - XtVaSetValues( - w, - XmNx, x, - XmNy, y, - XmNwidth, coldim[i], - XmNheight, *rowheight, - NULL); - - x += coldim[i]; - i++; - } - y += *rowheight; - } + UiContainerX *container = ui_box_container(obj, grid, orientation); + uic_object_push_container(obj, container); - cxListDestroy(rowdim); + return grid; } -UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow) { - UiContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiContainer)); - ct->widget = scrolledwindow; - ct->prepare = ui_scrolledwindow_container_prepare; - ct->add = ui_scrolledwindow_container_add; - return ct; +// public +UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) { + return box_create(obj, args, UI_BOX_VERTICAL); } -Widget ui_scrolledwindow_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { - return ct->widget; +// public +UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) { + return box_create(obj, args, UI_BOX_HORIZONTAL); } -void ui_scrolledwindow_container_add(UiContainer *ct, Widget widget) { - ui_reset_layout(ct->layout); - ct->current = widget; +UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation) { + UiBoxContainer *ctn = ui_malloc(obj->ctx, sizeof(UiBoxContainer)); + memset(ctn, 0, sizeof(UiBoxContainer)); + ctn->container.prepare = orientation == UI_BOX_VERTICAL ? ui_vbox_prepare : ui_hbox_prepare; + ctn->container.add = ui_box_container_add; + ctn->container.widget = grid; + ctn->n = 0; + return (UiContainerX*)ctn; } - -UiContainer* ui_tabview_container(UiObject *obj, Widget frame) { - UiTabViewContainer *ct = cxCalloc( - obj->ctx->allocator, - 1, - sizeof(UiTabViewContainer)); - ct->context = obj->ctx; - ct->container.widget = frame; - ct->container.prepare = ui_tabview_container_prepare; - ct->container.add = ui_tabview_container_add; - ct->tabs = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 16); - return (UiContainer*)ct; +static Widget ui_box_container_prepare(UiBoxContainer *box, Arg *args, int *n) { + int a = *n; + box->n++; + return box->container.widget; } -Widget ui_tabview_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) { +Widget ui_vbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n) { + UiBoxContainer *box = (UiBoxContainer*)ctn; int a = *n; - XtSetArg(args[a], XmNleftAttachment, XmATTACH_FORM); a++; - XtSetArg(args[a], XmNrightAttachment, XmATTACH_FORM); a++; - XtSetArg(args[a], XmNtopAttachment, XmATTACH_FORM); a++; - XtSetArg(args[a], XmNbottomAttachment, XmATTACH_FORM); a++; + XtSetArg(args[a], gridRow, box->n); a++; + if(box->container.layout.fill == UI_ON) { + XtSetArg(args[a], gridVExpand, TRUE); a++; + XtSetArg(args[a], gridVFill, TRUE); a++; + } + XtSetArg(args[a], gridHExpand, TRUE); a++; + XtSetArg(args[a], gridHFill, TRUE); a++; *n = a; - return ct->widget; + return ui_box_container_prepare(box, args, n); } -void ui_tabview_container_add(UiContainer *ct, Widget widget) { - UiTabViewContainer *tabview = (UiTabViewContainer*)ct; - - if(tabview->current) { - XtUnmanageChild(tabview->current); +Widget ui_hbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n) { + UiBoxContainer *box = (UiBoxContainer*)ctn; + int a = *n; + XtSetArg(args[a], gridColumn, box->n); a++; + if(box->container.layout.fill == UI_ON) { + XtSetArg(args[a], gridHExpand, TRUE); a++; + XtSetArg(args[a], gridHFill, TRUE); a++; } - - tabview->current = widget; - cxListAdd(tabview->tabs, widget); - - ui_select_tab(ct->widget, 0); - ui_reset_layout(ct->layout); - ct->current = widget; + XtSetArg(args[a], gridVExpand, TRUE); a++; + XtSetArg(args[a], gridVFill, TRUE); a++; + *n = a; + return ui_box_container_prepare(box, args, n); } -UIWIDGET ui_box(UiObject *obj, int margin, int spacing, UiBoxOrientation orientation) { - UiContainer *ct = uic_get_current_container(obj); - - Arg args[16]; - int n = 0; - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget form = XmCreateForm(parent, "vbox", args, n); - ct->add(ct, form); - XtManageChild(form); - - UiObject *newobj = uic_object_new(obj, form); - newobj->container = ui_box_container(obj, form, margin, spacing, orientation); - uic_obj_add(obj, newobj); +void ui_box_container_add(UiContainerPrivate *ctn, Widget widget) { + ui_reset_layout(ctn->layout); - return form; -} - -UIWIDGET ui_vbox(UiObject *obj) { - return ui_box(obj, 0, 0, UI_BOX_VERTICAL); -} - -UIWIDGET ui_hbox(UiObject *obj) { - return ui_box(obj, 0, 0, UI_BOX_HORIZONTAL); -} - -UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) { - return ui_box(obj, margin, spacing, UI_BOX_VERTICAL); -} - -UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) { - return ui_box(obj, margin, spacing, UI_BOX_HORIZONTAL); -} - -UIWIDGET ui_grid(UiObject *obj) { - return ui_grid_sp(obj, 0, 0, 0); } -UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) { - UiContainer *ct = uic_get_current_container(obj); - - Arg args[16]; - int n = 0; - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget grid = XmCreateDrawingArea(parent, "grid", args, n); - ct->add(ct, grid); - XtManageChild(grid); - - UiObject *newobj = uic_object_new(obj, grid); - newobj->container = ui_grid_container(obj, grid, columnspacing, rowspacing); - uic_obj_add(obj, newobj); - - XtAddCallback (grid, XmNresizeCallback , ui_grid_resize, newobj->container); - - return grid; -} -UIWIDGET ui_scrolledwindow(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - - Arg args[16]; - int n = 0; - XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); // TODO: dosn't work, use XmAPPLICATION_DEFINED - n++; - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget scrolledwindow = XmCreateScrolledWindow(parent, "scrolledwindow", args, n); - ct->add(ct, scrolledwindow); - XtManageChild(scrolledwindow); - - UiObject *newobj = uic_object_new(obj, scrolledwindow); - newobj->container = ui_scrolledwindow_container(obj, scrolledwindow); - uic_obj_add(obj, newobj); - - return scrolledwindow; -} +/* ---------------------------- Grid Container ---------------------------- */ -UIWIDGET ui_sidebar(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - - Arg args[16]; +// public +UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) { + Arg xargs[16]; int n = 0; - XtSetArg(args[n], XmNorientation, XmHORIZONTAL); - n++; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget pane = XmCreatePanedWindow(parent, "pane", args, n); - ct->add(ct, pane); - XtManageChild(pane); - - // add sidebar widget - Widget sidebar = XmCreateForm(pane, "sidebar", args, 0); - XtManageChild(sidebar); - - UiObject *left = uic_object_new(obj, sidebar); - left->container = ui_box_container(left, sidebar, 0, 0, UI_BOX_VERTICAL); + XtSetArg(xargs[n], XmNbackground, 0); n++; - // add content widget - XtSetArg (args[0], XmNpaneMaximum, 8000); - Widget content = XmCreateForm(pane, "content_area", args, 1); - XtManageChild(content); + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); - UiObject *right = uic_object_new(obj, content); - right->container = ui_box_container(right, content, 0, 0, UI_BOX_VERTICAL); + Widget parent = ctn->prepare(ctn, xargs, &n); + Widget grid = XtCreateManagedWidget(args.name ? args.name : "gridcontainer", gridClass, parent, xargs, n); + ctn->add(ctn, grid); - uic_obj_add(obj, right); - uic_obj_add(obj, left); + UiContainerX *container = ui_grid_container(obj, grid); + uic_object_push_container(obj, container); - return sidebar; -} - -UIWIDGET ui_tabview(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - - // create a simple frame as container widget - // when tabs are selected, the current child will be replaced by the - // the new tab widget - Arg args[16]; - int n = 0; - XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); - n++; - XtSetArg(args[n], XmNshadowThickness, 0); - n++; - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget form = XmCreateForm(parent, "tabview", args, n); - ct->add(ct, form); - XtManageChild(form); - - UiObject *tabviewobj = uic_object_new(obj, form); - tabviewobj->container = ui_tabview_container(obj, form); - uic_obj_add(obj, tabviewobj); - - XtVaSetValues(form, XmNuserData, tabviewobj->container, NULL); - - return form; + return grid; } -void ui_tab(UiObject *obj, char *title) { - UiContainer *ct = uic_get_current_container(obj); - ct->layout.label = title; - - ui_vbox(obj); +UiContainerX* ui_grid_container(UiObject *obj, Widget grid) { + UiGridContainer *ctn = ui_malloc(obj->ctx, sizeof(UiGridContainer)); + memset(ctn, 0, sizeof(UiBoxContainer)); + ctn->container.prepare = ui_grid_container_prepare; + ctn->container.add = ui_grid_container_add; + ctn->container.widget = grid; + ctn->x = 0; + ctn->y = 0; + return (UiContainerX*)ctn; } -void ui_select_tab(UIWIDGET tabview, int tab) { - UiTabViewContainer *ct = NULL; - XtVaGetValues(tabview, XmNuserData, &ct, NULL); - if(ct) { - XtUnmanageChild(ct->current); - Widget w = cxListAt(ct->tabs, tab); - if(w) { - XtManageChild(w); - ct->current = w; - } else { - fprintf(stderr, "UiError: front tab index: %d\n", tab); - } - } else { - fprintf(stderr, "UiError: widget is not a tabview\n"); +Widget ui_grid_container_prepare(UiContainerPrivate *ctn, Arg *args, int *n) { + UiGridContainer *grid = (UiGridContainer*)ctn; + if(ctn->layout.newline) { + grid->y++; + grid->x = 0; } -} - - -/* document tabview */ - -static void ui_tabbar_resize(Widget widget, XtPointer udata, XtPointer cdata) { - MotifTabbedPane *v = (MotifTabbedPane*)udata; - int width = 0; - int height = 0; - XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL); - int button_width = width / 4; - int x = 0; - CxIterator tabIterator = cxListIterator(v->tabs); - cx_foreach(UiTab*, tab, tabIterator) { - XtVaSetValues( - tab->tab_button, - XmNx, x, - XmNy, 0, - XmNwidth, - button_width, - - NULL); - x += button_width; + int a = *n; + XtSetArg(args[a], gridColumn, grid->x); a++; + XtSetArg(args[a], gridRow, grid->y); a++; + if(ctn->layout.colspan > 0) { + XtSetArg(args[a], gridColspan, ctn->layout.colspan); a++; } - - if(height <= v->height) { - XtVaSetValues(widget, XmNheight, v->height + 4, NULL); + if(ctn->layout.rowspan > 0) { + XtSetArg(args[a], gridRowspan, ctn->layout.rowspan); a++; } -} - -static void ui_tabbar_expose(Widget widget, XtPointer udata, XtPointer cdata) { - MotifTabbedPane *v = (MotifTabbedPane*)udata; - XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *)cdata; - XEvent *event = cbs->event; - Display *dpy = XtDisplay(widget); - - XGCValues gcvals; - GC gc; - Pixel fgpix; - - int tab_x; - int tab_width; - XtVaGetValues(v->current->tab_button, XmNx, &tab_x, XmNwidth, &tab_width, XmNhighlightColor, &fgpix, NULL); - - gcvals.foreground = v->bg1; - gc = XCreateGC( dpy, XtWindow(widget), (GCForeground), &gcvals); - - int width = 0; - int height = 0; - XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL); - XFillRectangle(dpy, XtWindow(widget), gc, 0, 0, width, height); - - gcvals.foreground = fgpix; - gc = XCreateGC( dpy, XtWindow(widget), (GCForeground), &gcvals); - - XFillRectangle(dpy, XtWindow(widget), gc, tab_x, 0, tab_width, height); - -} - -UiTabbedPane* ui_tabbed_document_view(UiObject *obj) { - int n = 0; - Arg args[16]; - - UiContainer *ct = uic_get_current_container(obj); - Widget parent = ct->prepare(ct, args, &n, TRUE); - - Widget tabview = XmCreateForm(parent, "tabview_form", args, n); - XtManageChild(tabview); - - XtSetArg(args[0], XmNorientation, XmHORIZONTAL); - XtSetArg(args[1], XmNpacking, XmPACK_TIGHT); - XtSetArg(args[2], XmNspacing, 1); - XtSetArg(args[3], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[4], XmNrightAttachment, XmATTACH_FORM); - XtSetArg(args[5], XmNtopAttachment, XmATTACH_FORM); - XtSetArg(args[6], XmNmarginWidth, 0); - XtSetArg(args[7], XmNmarginHeight, 0); - Widget tabbar = XmCreateDrawingArea(tabview, "tabbar", args, 8); - XtManageChild(tabbar); - XtSetArg(args[0], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[1], XmNrightAttachment, XmATTACH_FORM); - XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET); - XtSetArg(args[3], XmNtopWidget, tabbar); - XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM); - XtSetArg(args[5], XmNshadowThickness, 0); - Widget tabct = XmCreateForm(tabview, "tabview", args, 6); - XtManageChild(tabct); - - MotifTabbedPane *tabbedpane = ui_malloc(obj->ctx, sizeof(MotifTabbedPane)); - tabbedpane->view.ctx = uic_current_obj(obj)->ctx; - tabbedpane->view.widget = tabct; - tabbedpane->view.document = NULL; - tabbedpane->tabbar = tabbar; - tabbedpane->tabs = cxArrayListCreate(obj->ctx->allocator, cx_cmp_uintptr, CX_STORE_POINTERS, 16); - tabbedpane->current = NULL; - tabbedpane->height = 0; - - XtAddCallback(tabbar, XmNresizeCallback , ui_tabbar_resize, tabbedpane); - XtAddCallback(tabbar, XmNexposeCallback, ui_tabbar_expose, tabbedpane); - - return &tabbedpane->view; -} - -UiObject* ui_document_tab(UiTabbedPane *view) { - MotifTabbedPane *v = (MotifTabbedPane*)view; - int n = 0; - Arg args[16]; - - // hide the current tab content - if(v->current) { - XtUnmanageChild(v->current->content->widget); + if(grid->container.layout.fill == UI_ON) { + grid->container.layout.hfill = TRUE; + grid->container.layout.vfill = TRUE; + grid->container.layout.hexpand = TRUE; + grid->container.layout.vexpand = TRUE; } - UiTab *tab = ui_malloc(view->ctx, sizeof(UiTab)); - - // create the new tab content - XtSetArg(args[0], XmNshadowThickness, 0); - XtSetArg(args[1], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[2], XmNrightAttachment, XmATTACH_FORM); - XtSetArg(args[3], XmNtopAttachment, XmATTACH_FORM); - XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM); - XtSetArg(args[5], XmNuserData, tab); - Widget frame = XmCreateFrame(view->widget, "tab", args, 6); - XtManageChild(frame); - - UiObject *content = ui_malloc(view->ctx, sizeof(UiObject)); - content->widget = NULL; // initialization for uic_context() - content->ctx = uic_context(content, view->ctx->mp); - content->ctx->parent = view->ctx; - content->ctx->attach_document = uic_context_attach_document; - content->ctx->detach_document2 = uic_context_detach_document2; - content->widget = frame; - content->window = view->ctx->obj->window; - content->container = ui_frame_container(content, frame); - content->next = NULL; - - // add tab button - cxListAdd(v->tabs, tab); - - XmString label = XmStringCreateLocalized("tab"); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNshadowThickness, 0); - XtSetArg(args[2], XmNhighlightThickness, 0); - - Widget button = XmCreatePushButton(v->tabbar, "tab_button", args, 3); - tab->tabbedpane = v; - tab->content = content; - tab->tab_button = button; - XtManageChild(button); - XtAddCallback( - button, - XmNactivateCallback, - (XtCallbackProc)ui_tab_button_callback, - tab); - - if(v->height == 0) { - XtVaGetValues( - button, - XmNarmColor, - &v->bg1, - XmNbackground, - &v->bg2, - XmNheight, - &v->height, - NULL); - v->height += 2; // border + if(grid->container.layout.hfill) { + XtSetArg(args[a], gridHFill, TRUE); a++; + } + if(grid->container.layout.vfill) { + XtSetArg(args[a], gridVFill, TRUE); a++; + } + if(grid->container.layout.hexpand) { + XtSetArg(args[a], gridHExpand, TRUE); a++; + } + if(grid->container.layout.vexpand) { + XtSetArg(args[a], gridVExpand, TRUE); a++; } - ui_change_tab(v, tab); - ui_tabbar_resize(v->tabbar, v, NULL); - - return content; + *n = a; + return ctn->widget; } -void ui_tab_button_callback(Widget widget, UiTab *tab, XtPointer d) { - MotifTabbedPane *t = tab->tabbedpane; - if(t->current) { - XtUnmanageChild(t->current->content->widget); - XtVaSetValues(t->current->tab_button, XmNset, 0, NULL); - } - XtManageChild(tab->content->widget); - - ui_change_tab(t, tab); - +void ui_grid_container_add(UiContainerPrivate *ctn, Widget widget) { + UiGridContainer *grid = (UiGridContainer*)ctn; + grid->x++; + ui_reset_layout(ctn->layout); } -void ui_change_tab(MotifTabbedPane *pane, UiTab *tab) { - UiContext *ctx = tab->content->ctx; - ctx->parent->detach_document2(ctx->parent, pane->current->content->ctx->document); - ctx->parent->attach_document(ctx->parent, ctx->document); - - if(pane->current) { - XtVaSetValues(pane->current->tab_button, XmNshadowThickness, 0, XmNbackground, pane->bg1, NULL); - } - XtVaSetValues(tab->tab_button, XmNshadowThickness, 1, XmNbackground, pane->bg2, NULL); - - pane->current = tab; - pane->index = cxListFind(pane->tabs, tab); - printf("index: %d\n", pane->index); - - // redraw tabbar - Display *dpy = XtDisplay(pane->tabbar); - Window window = XtWindow(pane->tabbar); - if(dpy && window) { - XClearArea(dpy, XtWindow(pane->tabbar), 0, 0, 0, 0, TRUE); - XFlush(dpy); - } + +/* -------------------- Container Helper Functions -------------------- */ + +void ui_container_begin_close(UiObject *obj) { + UiContainerPrivate *ct = ui_obj_container(obj); + ct->container.close = 1; } -void ui_tab_set_document(UiContext *ctx, void *document) { - if(ctx->parent->document) { - //ctx->parent->detach_document(ctx->parent, ctx->parent->document); - } - uic_context_attach_document(ctx, document); - //uic_context_set_document(ctx->parent, document); - //ctx->parent->document = document; - - UiTab *tab = NULL; - XtVaGetValues( - ctx->obj->widget, - XmNuserData, - &tab, - NULL); - if(tab) { - if(tab->tabbedpane->current == tab) { - ctx->parent->attach_document(ctx->parent, ctx->document); - } - } else { - fprintf(stderr, "UiError: ui_bar_set_document: Cannot set document"); +int ui_container_finish(UiObject *obj) { + UiContainerPrivate *ct = ui_obj_container(obj); + if(ct->container.close) { + ui_end_new(obj); + return 0; } + return 1; } - /* * -------------------- Layout Functions -------------------- * @@ -788,27 +226,7 @@ void ui_tab_set_document(UiContext *ctx, void *document) { * */ -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; -} - -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; -} - 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/motif/container.h b/ui/motif/container.h index a012f8b..17550bc 100644 --- a/ui/motif/container.h +++ b/ui/motif/container.h @@ -37,120 +37,75 @@ #ifdef __cplusplus extern "C" { #endif - -#define ui_reset_layout(layout) memset(&(layout), 0, sizeof(UiLayout)) -typedef struct MotifTabbedPane MotifTabbedPane; -typedef struct UiTab UiTab; -typedef struct UiBoxContainer UiBoxContainer; -typedef struct UiGridContainer UiGridContainer; -typedef struct UiTabViewContainer UiTabViewContainer; -typedef struct UiLayout UiLayout; - -typedef Widget (*ui_container_add_f)(UiContainer*, Arg*, int*, UiBool); - -typedef enum UiLayoutBool UiLayoutBool; +#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.colspan = args.colspan; \ + layout.rowspan = args.rowspan + typedef enum UiBoxOrientation UiBoxOrientation; + +#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) - -enum UiLayoutBool { - UI_LAYOUT_UNDEFINED = 0, - UI_LAYOUT_TRUE, - UI_LAYOUT_FALSE, -}; - -enum UiBoxOrientation { - UI_BOX_VERTICAL = 0, - UI_BOX_HORIZONTAL -}; +#define ui_obj_container(obj) (UiContainerPrivate*)obj->container_end + +typedef struct UiLayout UiLayout; struct UiLayout { - UiLayoutBool fill; + UiTri fill; UiBool newline; char *label; UiBool hexpand; UiBool vexpand; - int gridwidth; -}; - -struct UiContainer { - Widget widget; - Widget (*prepare)(UiContainer*, Arg *, int*, UiBool); - void (*add)(UiContainer*, Widget); - UiLayout layout; - Widget current; - Widget menu; + UiBool hfill; + UiBool vfill; + int width; + int colspan; + int rowspan; }; -struct UiBoxContainer { - UiContainer container; - Widget prev_widget; - UiBool has_fill; - UiBoxOrientation orientation; - int margin; - int spacing; -}; - -struct UiGridContainer { - UiContainer container; - CxList *lines; - CxList *current; - int columnspacing; - int rowspacing; +enum UiBoxOrientation { + UI_BOX_VERTICAL = 0, + UI_BOX_HORIZONTAL }; -struct UiTabViewContainer { - UiContainer container; - UiContext *context; - Widget widget; - CxList *tabs; - Widget current; -}; +typedef struct UiContainerPrivate UiContainerPrivate; -struct MotifTabbedPane { - UiTabbedPane view; - Widget tabbar; - CxList *tabs; - UiTab *current; - int index; - Pixel bg1; - Pixel bg2; - int height; -}; -struct UiTab { - MotifTabbedPane *tabbedpane; - UiObject *content; - Widget tab_button; +struct UiContainerPrivate { + UiContainerX container; + Widget (*prepare)(UiContainerPrivate*, Arg *, int*); + void (*add)(UiContainerPrivate*, Widget); + Widget widget; + UiLayout layout; }; - - -UiContainer* ui_frame_container(UiObject *obj, Widget frame); -Widget ui_frame_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_frame_container_add(UiContainer *ct, Widget widget); - -UiContainer* ui_box_container(UiObject *obj, Widget box, int margin, int spacing, UiBoxOrientation orientation); -Widget ui_box_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_box_container_add(UiContainer *ct, Widget widget); - -UiContainer* ui_grid_container(UiObject *obj, Widget form, int columnspacing, int rowspacing); -Widget ui_grid_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_grid_container_add(UiContainer *ct, Widget widget); -UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow); -Widget ui_scrolledwindow_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_scrolledwindow_container_add(UiContainer *ct, Widget widget); +typedef struct UiBoxContainer { + UiContainerPrivate container; + Dimension n; +} UiBoxContainer; -UiContainer* ui_tabview_container(UiObject *obj, Widget rowcolumn); -Widget ui_tabview_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill); -void ui_tabview_container_add(UiContainer *ct, Widget widget); +typedef struct UiGridContainer { + UiContainerPrivate container; + Dimension x; + Dimension y; +} UiGridContainer; -void ui_tab_button_callback(Widget widget, UiTab *tab, XtPointer d); -void ui_change_tab(MotifTabbedPane *pane, UiTab *tab); +UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation); +Widget ui_vbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n); +Widget ui_hbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n); +void ui_box_container_add(UiContainerPrivate *ctn, Widget widget); -void ui_tab_set_document(UiContext *ctx, void *document); -void ui_tab_detach_document(UiContext *ctx); +UiContainerX* ui_grid_container(UiObject *obj, Widget grid); +Widget ui_grid_container_prepare(UiContainerPrivate *ctn, Arg *args, int *n); +void ui_grid_container_add(UiContainerPrivate *ctn, Widget widget); #ifdef __cplusplus } diff --git a/ui/motif/dnd.c b/ui/motif/dnd.c index 2f2313e..44b9384 100644 --- a/ui/motif/dnd.c +++ b/ui/motif/dnd.c @@ -28,18 +28,3 @@ #include "dnd.h" -void ui_selection_settext(UiSelection *sel, char *str, int len) { - -} - -void ui_selection_seturis(UiSelection *sel, char **uris, int nelm) { - -} - -char* ui_selection_gettext(UiSelection *sel) { - return NULL; -} - -char** ui_selection_geturis(UiSelection *sel, size_t *nelm) { - return NULL; -} diff --git a/ui/motif/graphics.c b/ui/motif/graphics.c index fefeca6..fab9930 100644 --- a/ui/motif/graphics.c +++ b/ui/motif/graphics.c @@ -34,250 +34,3 @@ #include "graphics.h" #include "container.h" - -static void ui_drawingarea_expose(Widget widget, XtPointer u, XtPointer c) { - UiDrawEvent *drawevent = u; - //XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *)c; - //XEvent *event = cbs->event; - Display *dpy = XtDisplay(widget); - - UiEvent ev; - ev.obj = drawevent->obj; - ev.window = drawevent->obj->window; - ev.document = drawevent->obj->ctx->document; - ev.eventdata = NULL; - ev.intval = 0; - - XtVaGetValues( - widget, - XmNwidth, - &drawevent->gr.g.width, - XmNheight, - &drawevent->gr.g.height, - NULL); - - XGCValues gcvals; - gcvals.foreground = BlackPixelOfScreen(XtScreen(widget)); - drawevent->gr.gc = XCreateGC(dpy, XtWindow(widget), (GCForeground), &gcvals); - - drawevent->callback(&ev, &drawevent->gr.g, drawevent->userdata); -} - -UIWIDGET ui_drawingarea(UiObject *obj, ui_drawfunc f, void *userdata) { - UiContainer *ct = uic_get_current_container(obj); - - int n = 0; - Arg args[16]; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget drawingarea = XmCreateDrawingArea(parent, "drawingarea", args, n); - - if(f) { - UiDrawEvent *event = malloc(sizeof(UiDrawEvent)); - event->obj = obj; - event->callback = f; - event->userdata = userdata; - - event->gr.display = XtDisplay(drawingarea); - event->gr.widget = drawingarea; - - Colormap colormap; - XtVaGetValues(drawingarea, XmNcolormap, &colormap, NULL); - event->gr.colormap = colormap; - - XtAddCallback( - drawingarea, - XmNexposeCallback, - ui_drawingarea_expose, - event); - - XtVaSetValues(drawingarea, XmNuserData, event, NULL); - } - - XtManageChild(drawingarea); - return drawingarea; -} - -static void ui_drawingarea_input(Widget widget, XtPointer u, XtPointer c) { - XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c; - XEvent *xevent = cbs->event; - UiMouseEventData *event = u; - - if (cbs->reason == XmCR_INPUT) { - if (xevent->xany.type == ButtonPress) { - UiMouseEvent me; - me.x = xevent->xbutton.x; - me.y = xevent->xbutton.y; - // TODO: configurable double click time - me.type = xevent->xbutton.time - event->last_event > 300 ? UI_PRESS : UI_PRESS2; - - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.eventdata = &me; - e.intval = 0; - event->callback(&e, event->userdata); - - - event->last_event = me.type == UI_PRESS2 ? 0 : xevent->xbutton.time; - } - } - -} - -void ui_drawingarea_mousehandler(UiObject *obj, UIWIDGET widget, ui_callback f, void *u) { - if(f) { - UiMouseEventData *event = malloc(sizeof(UiMouseEventData)); - event->obj = obj; - event->callback = f; - event->userdata = u; - event->last_event = 0; - - XtAddCallback(widget, XmNinputCallback, ui_drawingarea_input, event); - } -} - -void ui_drawingarea_getsize(UIWIDGET drawingarea, int *width, int *height) { - XtVaGetValues( - drawingarea, - XmNwidth, - width, - XmNheight, - height, - NULL); -} - -void ui_drawingarea_redraw(UIWIDGET drawingarea) { - //XClearArea(XtDisplay(drawingarea), drawingarea->core.window, 0, 0, drawingarea->core.width, drawingarea->core.height, True); - UiDrawEvent *event; - XtVaGetValues(drawingarea, XmNuserData, &event, NULL); - ui_drawingarea_expose(drawingarea, event, NULL); -} - - -/* -------------------- text layout functions -------------------- */ -UiTextLayout* ui_text(UiGraphics *g) { - UiTextLayout *text = malloc(sizeof(UiTextLayout)); - memset(text, 0, sizeof(UiTextLayout)); - text->text = NULL; - text->length = 0; - text->widget = ((UiXlibGraphics*)g)->widget; - text->fontset = NULL; - return text; -} - -static void create_default_fontset(UiTextLayout *layout) { - char **missing = NULL; - int num_missing = 0; - char *def = NULL; - Display *dpy = XtDisplay(layout->widget); - XFontSet fs = XCreateFontSet( - dpy, - "-dt-interface system-medium-r-normal-s*utf*:," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-1," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-10," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-15," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-2," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-3," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-4," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-5," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-iso8859-9," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-e," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-r," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-ru," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-u," - "-misc-liberation sans-medium-r-normal--0-0-0-0-p-0-koi8-uni," - "-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208", - &missing, &num_missing, &def); - layout->fontset = fs; -} - -void ui_text_free(UiTextLayout *text) { - // TODO -} - -void ui_text_setstring(UiTextLayout *layout, char *str) { - ui_text_setstringl(layout, str, strlen(str)); -} - -void ui_text_setstringl(UiTextLayout *layout, char *str, int len) { - layout->text = str; - layout->length = len; - layout->changed = 1; -} - -void ui_text_setfont(UiTextLayout *layout, char *font, int size) { - create_default_fontset(layout);//TODO - layout->changed = 1; -} - -void ui_text_getsize(UiTextLayout *layout, int *width, int *height) { - if(layout->changed) { - XRectangle ext, lext; - XmbTextExtents(layout->fontset, layout->text, layout->length, &ext, &lext); - layout->width = ext.width; - layout->height = ext.height; - layout->changed = 0; - } - *width = layout->width; - *height = layout->height; -} - -void ui_text_setwidth(UiTextLayout *layout, int width) { - layout->maxwidth = width; -} - - -/* -------------------- drawing functions -------------------- */ - -void ui_graphics_color(UiGraphics *g, int red, int green, int blue) { - UiXlibGraphics *gr = (UiXlibGraphics*)g; - XColor color; - color.flags= DoRed | DoGreen | DoBlue; - color.red = red * 257; - color.green = green * 257; - color.blue = blue * 257; - XAllocColor(gr->display, gr->colormap, &color); - XSetForeground(gr->display, gr->gc, color.pixel); -} - -void ui_draw_line(UiGraphics *g, int x1, int y1, int x2, int y2) { - UiXlibGraphics *gr = (UiXlibGraphics*)g; - XDrawLine(gr->display, XtWindow(gr->widget), gr->gc, x1, y1, x2, y2); -} - -void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, int fill) { - UiXlibGraphics *gr = (UiXlibGraphics*)g; - if(fill) { - XFillRectangle(gr->display, XtWindow(gr->widget), gr->gc, x, y, w, h); - } else { - XDrawRectangle(gr->display, XtWindow(gr->widget), gr->gc, x, y, w, h); - } -} - -void ui_draw_text(UiGraphics *g, int x, int y, UiTextLayout *text) { - UiXlibGraphics *gr = (UiXlibGraphics*)g; - int width, height; - ui_text_getsize(text, &width, &height); - if(text->maxwidth > 0) { - XRectangle clip; - clip.x = x; - clip.y = y; - clip.width = text->maxwidth; - clip.height = height; - XSetClipRectangles(gr->display, gr->gc, 0, 0, &clip, 1, Unsorted); - } - - XmbDrawString( - gr->display, - XtWindow(gr->widget), - text->fontset, - gr->gc, - x, - y + height, - text->text, - text->length); - - XSetClipMask(gr->display, gr->gc, None); -} diff --git a/ui/motif/graphics.h b/ui/motif/graphics.h index fa248b7..addec59 100644 --- a/ui/motif/graphics.h +++ b/ui/motif/graphics.h @@ -36,38 +36,6 @@ extern "C" { #endif -typedef struct UiXlibGraphics { - UiGraphics g; - Display *display; - Widget widget; - Colormap colormap; - GC gc; -} UiXlibGraphics; - -typedef struct UiDrawEvent { - ui_drawfunc callback; - UiObject *obj; - void *userdata; - UiXlibGraphics gr; -} UiDrawEvent; - -typedef struct UiMouseEventData { - UiObject *obj; - ui_callback callback; - void *userdata; - Time last_event; -} UiMouseEventData; - -struct UiTextLayout { - char *text; - size_t length; - Widget widget; - XFontSet fontset; - int maxwidth; - int width; - int height; - int changed; -}; #ifdef __cplusplus diff --git a/ui/motif/image.c b/ui/motif/image.c index 5142dbc..b3b8a11 100644 --- a/ui/motif/image.c +++ b/ui/motif/image.c @@ -6,35 +6,3 @@ #include "image.h" -UiIcon* ui_icon(const char *name, int size) { - return NULL; -} - -UiIcon* ui_icon_unscaled(const char *name, int size) { - return NULL; -} - -void ui_free_icon(UiIcon *icon) { - -} - -UiImage* ui_icon_image(UiIcon *icon) { - return NULL; -} - -UiImage* ui_image(const char *filename) { - return NULL; -} - -UiImage* ui_named_image(const char *filename, const char *name) { - return NULL; -} - -UiImage* ui_load_image_from_path(const char *path, const char *name) { - return NULL; -} - -void ui_free_image(UiImage *img) { - -} - diff --git a/ui/motif/label.c b/ui/motif/label.c index 8962197..453e67a 100644 --- a/ui/motif/label.c +++ b/ui/motif/label.c @@ -34,36 +34,3 @@ #include "../common/context.h" #include "../common/object.h" -UIWIDGET ui_label(UiObject *obj, char *label) { - UiContainer *ct = uic_get_current_container(obj); - XmString str = XmStringCreateLocalized(label); - - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNlabelString, str); - n++; - - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget widget = XmCreateLabel(parent, "label", args, n); - ct->add(ct, widget); - XtManageChild(widget); - - return widget; -} - -UIWIDGET ui_space(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - XmString str = XmStringCreateLocalized(""); - - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNlabelString, str); - n++; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget widget = XmCreateLabel(parent, "space_label", args, n); - ct->add(ct, widget); - XtManageChild(widget); - - return widget; -} diff --git a/ui/motif/list.c b/ui/motif/list.c index 0c5b193..9bf6fbc 100644 --- a/ui/motif/list.c +++ b/ui/motif/list.c @@ -34,175 +34,3 @@ #include "list.h" #include "../common/object.h" - -void* ui_strmodel_getvalue(void *elm, int column) { - return column == 0 ? elm : NULL; -} - - -UIWIDGET ui_listview_str(UiObject *obj, UiList *list, ui_callback f, void *udata) { - return ui_listview(obj, list, ui_strmodel_getvalue, f, udata); -} - -UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - int count; - XmStringTable items = ui_create_stringlist(var->value, getvalue, &count); - - Arg args[8]; - int n = 0; - XtSetArg(args[n], XmNitemCount, count); - n++; - XtSetArg(args[n], XmNitems, count == 0 ? NULL : items); - n++; - - UiContainer *ct = uic_get_current_container(obj); - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget widget = XmCreateScrolledList(parent, "listview", args, n); - ct->add(ct, XtParent(widget)); - XtManageChild(widget); - - UiListView *listview = cxMalloc(obj->ctx->allocator, sizeof(UiListView)); - listview->widget = widget; - listview->list = var; - listview->getvalue = getvalue; - - for (int i=0;ictx->allocator, - sizeof(UiListViewEventData)); - event->event.obj = obj; - event->event.userdata = udata; - event->event.callback = f; - event->event.value = 0; - event->var = var; - XtAddCallback( - widget, - XmNdefaultActionCallback, - (XtCallbackProc)ui_list_selection_callback, - event); - } - - return widget; -} - -UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - return ui_listview_var(obj, var, getvalue, f, udata); -} - -UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - UiListVar *value = var->value; - return ui_listview_var(obj, var, getvalue, f, udata); - } else { - // TODO: error - } - return NULL; -} - - -XmStringTable ui_create_stringlist(UiList *list, ui_getvaluefunc getvalue, int *count) { - int num = list->count(list); - XmStringTable items = (XmStringTable)XtMalloc(num * sizeof(XmString)); - void *data = list->first(list); - for(int i=0;inext(list); - } - - *count = num; - return items; -} - - -void ui_listview_update(UiEvent *event, UiListView *view) { - int count; - XmStringTable items = ui_create_stringlist( - view->list->value, - view->getvalue, - &count); - - XtVaSetValues( - view->widget, - XmNitems, count == 0 ? NULL : items, - XmNitemCount, - count, - NULL); - - for (int i=0;ievent.obj; - e.window = event->event.obj->window; - e.document = event->event.obj->ctx->document; - UiList *list = event->var->value; - e.eventdata = list->get(list, cbs->item_position - 1); - e.intval = cbs->item_position - 1; - event->event.callback(&e, event->event.userdata); -} - - -/* --------------------------- ComboBox --------------------------- */ - -UIWIDGET ui_combobox_str(UiObject *obj, UiList *list, ui_callback f, void *udata) { - return ui_combobox(obj, list, ui_strmodel_getvalue, f, udata); -} - -UIWIDGET ui_combobox(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = list; - var->type = UI_VAR_SPECIAL; - return ui_combobox_var(obj, var, getvalue, f, udata); -} - -UIWIDGET ui_combobox_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); - if(var) { - UiListVar *value = var->value; - return ui_combobox_var(obj, var, getvalue, f, udata); - } else { - // TODO: error - } - return NULL; -} - -UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { - UiListView *listview = cxMalloc( - obj->ctx->allocator, - sizeof(UiListView)); - - UiContainer *ct = uic_get_current_container(obj); - Arg args[16]; - int n = 0; - XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_NONE); - n++; - XtSetArg(args[n], XmNtraversalOn, FALSE); - n++; - XtSetArg(args[n], XmNwidth, 160); - n++; - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget combobox = XmCreateDropDownList(parent, "combobox", args, n); - XtManageChild(combobox); - listview->widget = combobox; - listview->list = var; - listview->getvalue = getvalue; - - ui_listview_update(NULL, listview); - - return parent; -} diff --git a/ui/motif/list.h b/ui/motif/list.h index 35f97ea..332ce2c 100644 --- a/ui/motif/list.h +++ b/ui/motif/list.h @@ -37,24 +37,7 @@ extern "C" { #endif -typedef struct UiListView { - Widget widget; - UiVar *list; - ui_getvaluefunc getvalue; -} UiListView; - -typedef struct UiListViewEventData { - UiEventData event; - UiVar *var; -} UiListViewEventData; - -void* ui_strmodel_getvalue(void *elm, int column); - -XmStringTable ui_create_stringlist(UiList *list, ui_getvaluefunc getvalue, int *count); -void ui_listview_update(UiEvent *event, UiListView *view); -void ui_list_selection_callback (Widget widget, UiListViewEventData *event, XtPointer data); - -UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata); + #ifdef __cplusplus } diff --git a/ui/motif/menu.c b/ui/motif/menu.c index 1b27a62..76d7a30 100644 --- a/ui/motif/menu.c +++ b/ui/motif/menu.c @@ -36,128 +36,88 @@ #include "stock.h" #include "container.h" #include "../common/context.h" +#include "../common/menu.h" #include "../ui/window.h" #include #include + static ui_menu_add_f createMenuItem[] = { /* UI_MENU */ add_menu_widget, - /* UI_MENU_SUBMENU */ add_menu_widget, /* UI_MENU_ITEM */ add_menuitem_widget, - /* UI_MENU_STOCK_ITEM */ add_menuitem_st_widget, /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, - /* UI_MENU_CHECK_ITEM_NV */ add_checkitemnv_widget, + /* UI_MENU_RADIO_ITEM */ add_radioitem_widget, /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, - /* UI_MENU_ITEM_LIST_NV */ NULL, // TODO + /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget, + /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget, /* UI_MENU_SEPARATOR */ add_menuseparator_widget }; -// private menu functions -void ui_create_menubar(UiObject *obj) { - UiMenu *menus = uic_get_menu_list(); - if(!menus) { +void ui_create_menubar(UiObject *obj, Widget window) { + UiMenu *menus_begin = uic_get_menu_list(); + if(!menus_begin) { return; } - Widget menubar = XmCreateMenuBar(obj->widget, "main_list", NULL, 0); + Widget menubar = XmCreateMenuBar(window, "menubar", NULL, 0); XtManageChild(menubar); - UiMenu *menu = menus; - int menu_index = 0; - while(menu) { - menu_index += add_menu_widget(menubar, menu_index, &menu->item, obj); - - menu = (UiMenu*)menu->item.next; + UiMenu *ls = menus_begin; + while(ls) { + UiMenu *menu = ls; + add_menu_widget(menubar, 0, &menu->item, obj); + ls = (UiMenu*)ls->item.next; } } -int add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { - UiMenu *menu = (UiMenu*)item; - - Widget menuItem = XtVaCreateManagedWidget( - menu->label, - xmCascadeButtonWidgetClass, - parent, - NULL); - Widget m = XmVaCreateSimplePulldownMenu(parent, menu->label, i, NULL, NULL); - - UiMenuItemI *mi = menu->items_begin; - int menu_index = 0; - while(mi) { - menu_index += createMenuItem[mi->type](m, menu_index, mi, obj); - mi = mi->next; +void ui_add_menu_items(Widget 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++; } - - return 1; } -int add_menuitem_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiMenuItem *mi = (UiMenuItem*)item; +void add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenu *menu = (UiMenu*)item; + Arg args[4]; + int n = 0; - Arg args[1]; - XmString label = XmStringCreateLocalized(mi->label); - XtSetArg(args[0], XmNlabelString, label); + XmString s = NULL; + if(menu->label) { + s = XmStringCreateLocalized((char*)menu->label); + XtSetArg(args[n], XmNlabelString, s); n++; + } - Widget mitem = XtCreateManagedWidget( - "menubutton", - xmPushButtonWidgetClass, + Widget submenu = XmVaCreateSimplePulldownMenu(parent, "menu_pulldown", i, NULL, NULL); + XtSetArg(args[n], XmNsubMenuId, submenu); n++; + Widget menuItem = XtCreateManagedWidget( + "menuitem", + xmCascadeButtonWidgetClass, parent, args, - 1); - XmStringFree(label); + n); - if(mi->callback != NULL) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = mi->userdata; - event->callback = mi->callback; - event->value = 0; - XtAddCallback( - mitem, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - if(mi->groups) { - uic_add_group_widget(obj->ctx, mitem, (ui_enablefunc)XtSetSensitive, mi->groups); + if(s) { + XmStringFree(s); } - return 1; + ui_add_menu_items(submenu, i, menu, obj); } -int add_menuitem_st_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { - UiStMenuItem *mi = (UiStMenuItem*)item; - - UiStockItem *si = ui_get_stock_item(mi->stockid); - if(!si) { - fprintf(stderr, "UI Error: unknown stock id: %s\n", mi->stockid); - return 0; - } +void add_menuitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuItem *it = (UiMenuItem*)item; - int n = 0; + XmString s = NULL; Arg args[4]; - XmString label = XmStringCreateLocalized(si->label); - XmString at = NULL; - - XtSetArg(args[n], XmNlabelString, label); - n++; - if(si->accelerator) { - XtSetArg(args[n], XmNaccelerator, si->accelerator); - n++; - } - if(si->accelerator_label) { - at = XmStringCreateLocalized(si->accelerator_label); - XtSetArg(args[n], XmNacceleratorText, at); - n++; + int n = 0; + if(it->label) { + s = XmStringCreateLocalized((char*)it->label); + XtSetArg(args[n], XmNlabelString, s); n++; } Widget mitem = XtCreateManagedWidget( @@ -166,319 +126,81 @@ int add_menuitem_st_widget(Widget parent, int i, UiMenuItemI *item, UiObject *ob parent, args, n); - XmStringFree(label); - if(at) { - XmStringFree(at); + if(s) { + XmStringFree(s); } - if(mi->callback != NULL) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = mi->userdata; - event->callback = mi->callback; - event->value = 0; + if(it->callback) { + UiEventData *eventdata = malloc(sizeof(UiEventData)); + eventdata->callback = it->callback; + eventdata->userdata = it->userdata; + eventdata->obj = obj; + eventdata->value = 0; XtAddCallback( mitem, XmNactivateCallback, (XtCallbackProc)ui_push_button_callback, - event); - } - - if(mi->groups) { - uic_add_group_widget(obj->ctx, mitem, (ui_enablefunc)XtSetSensitive, mi->groups); + eventdata); + XtAddCallback( + mitem, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + eventdata); } - return 1; + ui_set_widget_groups(obj->ctx, mitem, it->groups); } -int add_menuseparator_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - Widget s = XmCreateSeparatorGadget (parent, "menu_separator", NULL, 0); +void add_menuseparator_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { + Widget s = XmCreateSeparatorGadget (p, "menuseparator", NULL, 0); XtManageChild(s); - return 1; } -int add_checkitem_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiCheckItem *ci = (UiCheckItem*)item; +void add_checkitem_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { + UiMenuCheckItem *it = (UiMenuCheckItem*)item; - Arg args[3]; - XmString label = XmStringCreateLocalized(ci->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNvisibleWhenOff, 1); - Widget checkbox = XtCreateManagedWidget( - "menutogglebutton", - xmToggleButtonWidgetClass, - parent, - args, - 2); - XmStringFree(label); - - if(ci->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = ci->userdata; - event->callback = ci->callback; - XtAddCallback( - checkbox, - XmNvalueChangedCallback, - (XtCallbackProc)ui_toggle_button_callback, - event); + Arg args[4]; + int n = 0; + XmString s = NULL; + if(it->label) { + s = XmStringCreateLocalized(it->label); + XtSetArg(args[n], XmNlabelString, s); n++; } - return 1; -} - -int add_checkitemnv_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiCheckItemNV *ci = (UiCheckItemNV*)item; - - Arg args[3]; - XmString label = XmStringCreateLocalized(ci->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNvisibleWhenOff, 1); + //XtSetArg(args[n], XmNvisibleWhenOff, 0); n++; Widget checkbox = XtCreateManagedWidget( "menutogglebutton", xmToggleButtonWidgetClass, - parent, + p, args, - 2); - XmStringFree(label); - - UiVar *var = uic_create_var(obj->ctx, ci->varname, UI_VAR_INTEGER); - if(var) { - UiInteger *value = var->value; - value->obj = checkbox; - value->get = ui_toggle_button_get; - value->set = ui_toggle_button_set; - value = 0; - } else { - // TODO: error - } - - return 1; -} - -int add_menuitem_list_widget( - Widget parent, - int i, - UiMenuItemI *item, - UiObject *obj) -{ - UiMenuItemList *il = (UiMenuItemList*)item; - - UiActiveMenuItemList *ls = cxMalloc( - obj->ctx->allocator, - sizeof(UiActiveMenuItemList)); - - ls->object = obj; - ls->menu = parent; - ls->index = i; - ls->oldcount = 0; - ls->list = il->list; - ls->callback = il->callback; - ls->userdata = il->userdata; - - ls->list->observers = ui_add_observer( - ls->list->observers, - (ui_callback)ui_update_menuitem_list, - ls); - - ui_update_menuitem_list(NULL, ls); - - return 0; -} - -void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { - Arg args[4]; - - // remove old items - if(list->oldcount > 0) { - Widget *children; - int nc; - - XtVaGetValues( - list->menu, - XmNchildren, - &children, - XmNnumChildren, - &nc, - NULL); - - for(int i=0;ioldcount;i++) { - XtDestroyWidget(children[list->index + i]); - } - } - - char *str = ui_list_first(list->list); - if(str) { - // add separator - XtSetArg(args[0], XmNpositionIndex, list->index); - Widget s = XmCreateSeparatorGadget (list->menu, "menu_separator", args, 1); - XtManageChild(s); - } - int i = 1; - while(str) { - XmString label = XmStringCreateLocalized(str); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNpositionIndex, list->index + i); - - Widget mitem = XtCreateManagedWidget( - "menubutton", - xmPushButtonWidgetClass, - list->menu, - args, - 2); - XmStringFree(label); - - if(list->callback) { - // TODO: use mempool - UiEventData *event = malloc(sizeof(UiEventData)); - event->obj = list->object; - event->userdata = list->userdata; - event->callback = list->callback; - event->value = i - 1; - - XtAddCallback( - mitem, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - - str = ui_list_next(list->list); - i++; - } - - list->oldcount = i; -} - -void ui_menu_event_wrapper(Widget widget, XtPointer udata, XtPointer cdata) { - UiEventData *event = udata; - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.intval = 0; - event->callback(&e, event->userdata); -} - - -/* - * widget menu functions - */ - -static void ui_popup_handler(Widget widget, XtPointer data, XEvent *event, Boolean *c) { - Widget menu = data; - XmMenuPosition(menu, (XButtonPressedEvent *)event); - XtManageChild(menu); - - *c = FALSE; -} - -UIMENU ui_contextmenu(UiObject *obj) { - UiContainer *ct = uic_get_current_container(obj); - if(ct->current) { - return ui_contextmenu_w(obj, ct->current); - } else { - return NULL; // TODO: warn + n); + if(s) { + XmStringFree(s); } -} - -UIMENU ui_contextmenu_w(UiObject *obj, UIWIDGET widget) { - UiContainer *ct = uic_get_current_container(obj); - - Widget menu = XmCreatePopupMenu(widget, "popup_menu", NULL, 0); - ct->menu = menu; - XtAddEventHandler(widget, ButtonPressMask, FALSE, ui_popup_handler, menu); + ui_bind_togglebutton(obj, checkbox, it->varname, NULL, it->callback, it->userdata, 0); - return menu; + ui_set_widget_groups(obj->ctx, checkbox, it->groups); } -void ui_contextmenu_popup(UIMENU menu) { +void add_radioitem_widget(Widget p, int index, UiMenuItemI *item, UiObject *obj) { + UiMenuRadioItem *it = (UiMenuRadioItem*)item; -} - -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; - } - - // add groups - CxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!groups) { - groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16); - } - cxListAdd(groups, &group); + Arg args[4]; + int n = 0; + XmString s = NULL; + if(it->label) { + s = XmStringCreateLocalized(it->label); + XtSetArg(args[n], XmNlabelString, s); n++; } - va_end(ap); + XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY_ROUND); n++; - // create menuitem - Arg args[4]; - XmString labelstr = XmStringCreateLocalized(label); - XtSetArg(args[0], XmNlabelString, labelstr); + Widget button = XmCreateToggleButton(p, "menuradiobutton", args, n); + XtManageChild(button); - Widget item = XmCreatePushButton(ct->menu, "menu_button", args, 1); - XtManageChild(item); - XmStringFree(labelstr); -} - -void ui_widget_menuitem_st(UiObject *obj, char *stockid, ui_callback f, void *userdata) { - ui_widget_menuitem_stgr(obj, stockid, f, userdata, -1); + ui_bind_radiobutton(obj, button, NULL, it->varname, it->callback, it->userdata, 0); } -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 - CxList *groups = NULL; - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!groups) { - groups = cxArrayListCreate(cxDefaultAllocator, NULL, sizeof(int), 16); - } - cxListAdd(groups, &group); - } - va_end(ap); - - // create menuitem - UiStockItem *stockItem = ui_get_stock_item(stockid); - Arg args[4]; - XmString labelstr = XmStringCreateLocalized(stockItem->label); - XtSetArg(args[0], XmNlabelString, labelstr); +void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj) { - Widget item = XmCreatePushButton(ct->menu, "menu_button", args, 1); - XtManageChild(item); - XmStringFree(labelstr); } diff --git a/ui/motif/menu.h b/ui/motif/menu.h index db75775..45b55a9 100644 --- a/ui/motif/menu.h +++ b/ui/motif/menu.h @@ -36,34 +36,19 @@ extern "C" { #endif - -typedef struct UiActiveMenuItemList UiActiveMenuItemList; - -typedef int(*ui_menu_add_f)(Widget, int, UiMenuItemI*, UiObject*); - -struct UiActiveMenuItemList { - UiObject *object; - Widget menu; - int index; - int oldcount; - UiList *list; - ui_callback callback; - void *userdata; -}; - -void ui_create_menubar(UiObject *obj); - -int add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_menuitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_menuitem_st_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_menuseparator_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_checkitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_checkitemnv_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); -int add_menuitem_list_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); - -void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list); -void ui_menu_event_wrapper(Widget widget, XtPointer udata, XtPointer cdata); - +typedef void(*ui_menu_add_f)(Widget, int, UiMenuItemI*, UiObject*); + +void ui_create_menubar(UiObject *obj, Widget window); +void ui_add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); + +void add_menu_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); +void add_menuitem_widget(Widget parent, int i, UiMenuItemI *item, UiObject *obj); +void add_menuitem_st_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj); +void add_menuseparator_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj); +void add_checkitem_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj); +void add_radioitem_widget(Widget p, int index, UiMenuItemI *item, UiObject *obj); +void add_checkitemnv_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj); +void add_menuitem_list_widget(Widget p, int i, UiMenuItemI *item, UiObject *obj); #ifdef __cplusplus } diff --git a/ui/motif/objs.mk b/ui/motif/objs.mk index 179deac..10e29cd 100644 --- a/ui/motif/objs.mk +++ b/ui/motif/objs.mk @@ -39,11 +39,11 @@ MOTIFOBJ += button.o MOTIFOBJ += label.o MOTIFOBJ += text.o MOTIFOBJ += list.o -MOTIFOBJ += tree.o MOTIFOBJ += graphics.o MOTIFOBJ += range.o MOTIFOBJ += dnd.o MOTIFOBJ += image.o +MOTIFOBJ += Grid.o TOOLKITOBJS += $(MOTIFOBJ:%=$(MOTIF_OBJPRE)%) TOOLKITSOURCE += $(MOTIFOBJ:%.o=motif/%.c) diff --git a/ui/motif/range.c b/ui/motif/range.c index 91cb045..81416cc 100644 --- a/ui/motif/range.c +++ b/ui/motif/range.c @@ -34,104 +34,3 @@ #include "../common/context.h" #include "../common/object.h" - -static UIWIDGET ui_scrollbar(UiObject *obj, UiOrientation orientation, UiRange *range, ui_callback f, void *userdata) { - UiContainer *ct = uic_get_current_container(obj); - - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNorientation, orientation == UI_HORIZONTAL ? XmHORIZONTAL : XmVERTICAL); - n++; - XtSetArg (args[n], XmNmaximum, 10); - n++; - XtSetArg (args[n], XmNsliderSize, 1); - n++; - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget scrollbar = XmCreateScrollBar(parent, "scrollbar", args, n); - XtManageChild(scrollbar); - ct->add(ct, scrollbar); - - if(range) { - range->get = ui_scrollbar_get; - range->set = ui_scrollbar_set; - range->setrange = ui_scrollbar_setrange; - range->setextent = ui_scrollbar_setextent; - range->obj = scrollbar; - } - - if(f) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = userdata; - event->callback = f; - event->value = 0; - XtAddCallback( - scrollbar, - XmNvalueChangedCallback, - (XtCallbackProc)ui_scrollbar_callback, - event); - } - - return scrollbar; -} - -UIWIDGET ui_hscrollbar(UiObject *obj, UiRange *range, ui_callback f, void *userdata) { - return ui_scrollbar(obj, UI_HORIZONTAL, range, f, userdata); -} - -UIWIDGET ui_vscrollbar(UiObject *obj, UiRange *range, ui_callback f, void *userdata) { - return ui_scrollbar(obj, UI_VERTICAL, range, f, userdata); -} - -void ui_scrollbar_callback(Widget scrollbar, UiEventData *event, XtPointer cdata) { - UiEvent e; - e.obj = event->obj; - e.window = event->obj->window; - e.document = event->obj->ctx->document; - e.intval = event->value; - event->callback(&e, event->userdata); -} - -double ui_scrollbar_get(UiRange *range) { - int intval; - XtVaGetValues( - range->obj, - XmNvalue, - &intval, - NULL); - double value = (double)intval / 10; - range->value = value; - return value; -} - -void ui_scrollbar_set(UiRange *range, double value) { - XtVaSetValues( - range->obj, - XmNvalue, - (int)(value * 10), - NULL); - range->value = value; -} - -void ui_scrollbar_setrange(UiRange *range, double min, double max) { - XtVaSetValues( - range->obj, - XmNminimum, - (int)(min * 10), - XmNmaximum, - (int)(max * 10), - NULL); - range->min = min; - range->max = max; -} - -void ui_scrollbar_setextent(UiRange *range, double extent) { - XtVaSetValues( - range->obj, - XmNsliderSize, - (int)(extent * 10), - NULL); - range->extent = extent; -} diff --git a/ui/motif/range.h b/ui/motif/range.h index 1c6da04..0dbb77e 100644 --- a/ui/motif/range.h +++ b/ui/motif/range.h @@ -36,11 +36,6 @@ extern "C" { #endif -void ui_scrollbar_callback(Widget scrollbar, UiEventData *event, XtPointer cdata); -double ui_scrollbar_get(UiRange *range); -void ui_scrollbar_set(UiRange *range, double value); -void ui_scrollbar_setrange(UiRange *range, double min, double max); -void ui_scrollbar_setextent(UiRange *range, double extent); #ifdef __cplusplus diff --git a/ui/motif/stock.c b/ui/motif/stock.c index 4866d54..190fdbd 100644 --- a/ui/motif/stock.c +++ b/ui/motif/stock.c @@ -33,44 +33,4 @@ #include "../ui/properties.h" #include -static CxMap *stock_items; -void ui_stock_init() { - stock_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 64); - - ui_add_stock_item(UI_STOCK_NEW, "New", "CtrlN", "Ctrl+N", NULL); - ui_add_stock_item(UI_STOCK_OPEN, "Open", "CtrlO", "Ctrl+O", NULL); - ui_add_stock_item(UI_STOCK_SAVE, "Save", "CtrlS", "Ctrl+S", NULL); - ui_add_stock_item(UI_STOCK_SAVE_AS, "Save as ...", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_REVERT_TO_SAVED, "Revert to saved", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_CLOSE, "Close", "CtrlW", "Ctrl+W", NULL); - ui_add_stock_item(UI_STOCK_UNDO, "Undo", "CtrlZ", "Ctrl+Z", NULL); - ui_add_stock_item(UI_STOCK_REDO, "Redo", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_GO_BACK, "Back", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_GO_FORWARD, "Forward", NULL, NULL, NULL); - ui_add_stock_item(UI_STOCK_CUT, "Cut", "CtrlX", "Ctrl+X", NULL); - ui_add_stock_item(UI_STOCK_COPY, "Copy", "CtrlC", "Ctrl+C", NULL); - ui_add_stock_item(UI_STOCK_PASTE, "Paste", "CtrlV", "Ctrl+V", NULL); - ui_add_stock_item(UI_STOCK_DELETE, "Delete", NULL, NULL, NULL); -} - -void ui_add_stock_item(char *id, char *label, char *accelerator, char *accelerator_label, void *icon) { - UiStockItem *i = malloc(sizeof(UiStockItem)); - i->label = label; - i->accelerator = accelerator; - i->accelerator_label = accelerator_label; - // TODO: icon - - cxMapPut(stock_items, id, i); -} - -UiStockItem* ui_get_stock_item(char *id) { - UiStockItem *item = cxMapGet(stock_items, id); - if(item) { - char *label = uistr_n(id); - if(label) { - item->label = label; - } - } - return item; -} diff --git a/ui/motif/stock.h b/ui/motif/stock.h index 03e643f..c3cdb7f 100644 --- a/ui/motif/stock.h +++ b/ui/motif/stock.h @@ -35,18 +35,7 @@ extern "C" { #endif -typedef struct UiStockItem { - char *label; - char *accelerator; - char *accelerator_label; - // TODO: icon -} UiStockItem; - -void ui_stock_init(); - -void ui_add_stock_item(char *id, char *label, char *accelerator, char *accelerator_label, void *icon); - -UiStockItem* ui_get_stock_item(char *id); + #ifdef __cplusplus } diff --git a/ui/motif/text.c b/ui/motif/text.c index 1e98b84..7226407 100644 --- a/ui/motif/text.c +++ b/ui/motif/text.c @@ -28,480 +28,666 @@ #include #include +#include #include "text.h" #include "container.h" +#include -UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var) { - UiContainer *ct = uic_get_current_container(obj); + + +/* ------------------------------ Text Field ------------------------------ */ + +static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs args, int frameless, int password) { + Arg xargs[16]; int n = 0; - Arg args[16]; - - //XtSetArg(args[n], XmNeditable, TRUE); - //n++; - XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); - n++; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget text_area = XmCreateScrolledText(parent, "text_area", args, n); - ct->add(ct, XtParent(text_area)); - XtManageChild(text_area); - - UiTextArea *uitext = cxMalloc( - obj->ctx->allocator, - sizeof(UiTextArea)); - uitext->ctx = obj->ctx; - uitext->last_selection_state = 0; - XtAddCallback( - text_area, - XmNmotionVerifyCallback, - (XtCallbackProc)ui_text_selection_callback, - uitext); - - // bind value - if(var->value) { - UiText *value = var->value; - if(value->value.ptr) { - XmTextSetString(text_area, value->value.ptr); - value->value.free(value->value.ptr); - } - - value->set = ui_textarea_set; - value->get = ui_textarea_get; - value->getsubstr = ui_textarea_getsubstr; - value->insert = ui_textarea_insert; - value->setposition = ui_textarea_setposition; - value->position = ui_textarea_position; - value->selection = ui_textarea_selection; - value->length = ui_textarea_length; - value->value.ptr = NULL; - value->obj = text_area; + + if(frameless) { + XtSetArg(xargs[n], XmNshadowThickness, 0); + n++; + } + if(password) { + // TODO + } + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + char *name = args.name ? (char*)args.name : "textfield"; + Widget textfield = XmCreateTextField(parent, name, xargs, n); + XtManageChild(textfield); + + ui_set_widget_groups(obj->ctx, textfield, args.groups); + + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING); + if(var) { + UiString *value = (UiString*)var->value; + value->obj = textfield; + value->get = ui_textfield_get; + value->set = ui_textfield_set; - if(!value->undomgr) { - value->undomgr = ui_create_undomgr(); + if(value->value.ptr) { + ui_textfield_set(value, value->value.ptr); } - - XtAddCallback( - text_area, - XmNmodifyVerifyCallback, - (XtCallbackProc)ui_text_modify_callback, - var); } - return text_area; + return textfield; } -UIWIDGET ui_textarea(UiObject *obj, UiText *value) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = value; - var->type = UI_VAR_SPECIAL; - return ui_textarea_var(obj, var); +UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) { + return create_textfield(obj, args, FALSE, FALSE); } -UIWIDGET ui_textarea_nv(UiObject *obj, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_TEXT); - if(var) { - return ui_textarea_var(obj, var); - } else { - // TODO: error - } - return NULL; +UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) { + return create_textfield(obj, args, TRUE, FALSE); } -char* ui_textarea_get(UiText *text) { - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - char *str = XmTextGetString(text->obj); - text->value.ptr = str; - text->value.free = (ui_freefunc)XtFree; - return str; +UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) { + return create_textfield(obj, args, FALSE, FALSE); } -void ui_textarea_set(UiText *text, const char *str) { - XmTextSetString(text->obj, str); - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - text->value.ptr = NULL; +char* ui_textfield_get(UiString *str) { + str->value.free(str->value.ptr); + char *value = XmTextFieldGetString(str->obj); + str->value.ptr = value; + str->value.free = (ui_freefunc)XtFree; + return value; } -char* ui_textarea_getsubstr(UiText *text, int begin, int end) { - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - int length = end - begin; - char *str = XtMalloc(length + 1); - XmTextGetSubstring(text->obj, begin, length, length + 1, str); - text->value.ptr = str; - text->value.free = (ui_freefunc)XtFree; - return str; +void ui_textfield_set(UiString *str, const char *value) { + XmTextFieldSetString(str->obj, (void*)value); + str->value.ptr = NULL; + str->value.free(str->value.ptr); } -void ui_textarea_insert(UiText *text, int pos, char *str) { - text->value.ptr = NULL; - XmTextInsert(text->obj, pos, str); - if(text->value.ptr) { - text->value.free(text->value.ptr); - } -} -void ui_textarea_setposition(UiText *text, int pos) { - XmTextSetInsertionPosition(text->obj, pos); -} -int ui_textarea_position(UiText *text) { - long begin; - long end; - XmTextGetSelectionPosition(text->obj, &begin, &end); - text->pos = begin; - return text->pos; -} -void ui_textarea_selection(UiText *text, int *begin, int *end) { - XmTextGetSelectionPosition(text->obj, (long*)begin, (long*)end); -} -int ui_textarea_length(UiText *text) { - return (int)XmTextGetLastPosition(text->obj); -} +/* -------------------- path bar -------------------- */ + +#define XNECreateText(parent,name,args,count) XmCreateTextField(parent,name,args,count) +#define XNETextSetString(widget,value) XmTextFieldSetString(widget,value) +#define XNETextGetString(widget) XmTextFieldGetString(widget) +#define XNETextGetLastPosition(widget) XmTextFieldGetLastPosition(widget) +#define XNETextSetInsertionPosition(widget, i) XmTextFieldSetInsertionPosition(widget, i) +#define XNETextSetSelection(w, f, l, t) XmTextFieldSetSelection(w, f, l, t) + +typedef void(*updatedir_callback)(void*,char*,int); + +typedef struct PathBar { + Widget widget; + Widget textfield; + + Widget focus_widget; + + Widget left; + Widget right; + Dimension lw; + Dimension rw; + + int shift; + + UiPathElm *current_pathelms; + Widget *pathSegments; + size_t numSegments; + size_t segmentAlloc; + + char *path; + int selection; + Boolean input; + + int focus; + + updatedir_callback updateDir; + void *updateDirData; + + ui_pathelm_func getpathelm; + void *getpathelmdata; +} PathBar; +void PathBarSetPath(PathBar *bar, const char *path); -void ui_text_set(UiText *text, char *str) { - if(text->set) { - text->set(text, str); +void pathbar_resize(Widget w, PathBar *p, XtPointer d) +{ + Dimension width, height; + XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL); + + Dimension *segW = (void*)XtCalloc(p->numSegments, sizeof(Dimension)); + + Dimension maxHeight = 0; + + /* get width/height from all widgets */ + Dimension pathWidth = 0; + for(int i=0;inumSegments;i++) { + Dimension segWidth; + Dimension segHeight; + XtVaGetValues(p->pathSegments[i], XmNwidth, &segWidth, XmNheight, &segHeight, NULL); + segW[i] = segWidth; + pathWidth += segWidth; + if(segHeight > maxHeight) { + maxHeight = segHeight; + } + } + Dimension tfHeight; + XtVaGetValues(p->textfield, XmNheight, &tfHeight, NULL); + if(tfHeight > maxHeight) { + maxHeight = tfHeight; + } + + Boolean arrows = False; + if(pathWidth + 10 > width) { + arrows = True; + pathWidth += p->lw + p->rw; + } + + /* calc max visible widgets */ + int start = 0; + if(arrows) { + Dimension vis = p->lw+p->rw; + for(int i=p->numSegments;i>0;i--) { + Dimension segWidth = segW[i-1]; + if(vis + segWidth + 10 > width) { + start = i; + arrows = True; + break; + } + vis += segWidth; + } } else { - if(text->value.ptr) { - text->value.free(text->value.ptr); + p->shift = 0; + } + + int leftShift = 0; + if(p->shift < 0) { + if(start + p->shift < 0) { + leftShift = start; + start = 0; + p->shift = -leftShift; + } else { + leftShift = -p->shift; /* negative shift */ + start += p->shift; } - text->value.ptr = XtNewString(str); - text->value.free = (ui_freefunc)XtFree; } -} - -char* ui_text_get(UiText *text) { - if(text->get) { - return text->get(text); + + int x = 0; + if(arrows) { + XtManageChild(p->left); + XtManageChild(p->right); + x = p->lw; } else { - return text->value.ptr; + XtUnmanageChild(p->left); + XtUnmanageChild(p->right); + } + + for(int i=0;inumSegments;i++) { + if(i >= start && i < p->numSegments - leftShift && !p->input) { + XtVaSetValues(p->pathSegments[i], XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL); + x += segW[i]; + XtManageChild(p->pathSegments[i]); + } else { + XtUnmanageChild(p->pathSegments[i]); + } + } + + if(arrows) { + XtVaSetValues(p->left, XmNx, 0, XmNy, 0, XmNheight, maxHeight, NULL); + XtVaSetValues(p->right, XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL); } + + free(segW); + + Dimension rw, rh; + XtMakeResizeRequest(w, width, maxHeight, &rw, &rh); + + XtVaSetValues(p->textfield, XmNwidth, rw, XmNheight, rh, NULL); } +static void pathbarActivateTF(PathBar *p) +{ + XtUnmanageChild(p->left); + XtUnmanageChild(p->right); + XNETextSetSelection(p->textfield, 0, XNETextGetLastPosition(p->textfield), 0); + XtManageChild(p->textfield); + p->input = 1; -UiUndoMgr* ui_create_undomgr() { - UiUndoMgr *mgr = malloc(sizeof(UiUndoMgr)); - mgr->begin = NULL; - mgr->end = NULL; - mgr->cur = NULL; - mgr->length = 0; - mgr->event = 1; - return mgr; + XmProcessTraversal(p->textfield, XmTRAVERSE_CURRENT); + + pathbar_resize(p->widget, p, NULL); } -void ui_destroy_undomgr(UiUndoMgr *mgr) { - UiTextBufOp *op = mgr->begin; - while(op) { - UiTextBufOp *nextOp = op->next; - if(op->text) { - free(op->text); - } - free(op); - op = nextOp; - } - free(mgr); +void PathBarActivateTextfield(PathBar *p) +{ + p->focus = 1; + pathbarActivateTF(p); } -void ui_text_selection_callback( - Widget widget, - UiTextArea *textarea, - XtPointer data) +void pathbar_input(Widget w, PathBar *p, XtPointer c) { - long left = 0; - long right = 0; - XmTextGetSelectionPosition(widget, &left, &right); - int sel = left < right ? 1 : 0; - if(sel != textarea->last_selection_state) { - if(sel) { - ui_set_group(textarea->ctx, UI_GROUP_SELECTION); - } else { - ui_unset_group(textarea->ctx, UI_GROUP_SELECTION); + XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c; + XEvent *xevent = cbs->event; + + if (cbs->reason == XmCR_INPUT) { + if (xevent->xany.type == ButtonPress) { + p->focus = 0; + pathbarActivateTF(p); } } - textarea->last_selection_state = sel; } -void ui_text_modify_callback(Widget widget, UiVar *var, XtPointer data) { - UiText *value = var->value; - if(!value->obj) { - // TODO: bug, fix - return; - } - if(!value->undomgr) { - value->undomgr = ui_create_undomgr(); +void pathbar_losingfocus(Widget w, PathBar *p, XtPointer c) +{ + if(--p->focus < 0) { + p->input = False; + XtUnmanageChild(p->textfield); } - - XmTextVerifyCallbackStruct *txv = (XmTextVerifyCallbackStruct*)data; - int type = txv->text->length > 0 ? UI_TEXTBUF_INSERT : UI_TEXTBUF_DELETE; - UiUndoMgr *mgr = value->undomgr; - if(!mgr->event) { - return; +} + +static cxmutstr concat_path_s(cxstring base, cxstring path) { + if(!path.ptr) { + path = CX_STR(""); } - char *text = txv->text->ptr; - int length = txv->text->length; - - if(mgr->cur) { - UiTextBufOp *elm = mgr->cur->next; - if(elm) { - mgr->cur->next = NULL; - mgr->end = mgr->cur; - while(elm) { - elm->prev = NULL; - UiTextBufOp *next = elm->next; - ui_free_textbuf_op(elm); - elm = next; - } + int add_separator = 0; + if(base.length != 0 && base.ptr[base.length-1] == '/') { + if(path.ptr[0] == '/') { + base.length--; } - - UiTextBufOp *last_op = mgr->cur; - if( - last_op->type == UI_TEXTBUF_INSERT && - ui_check_insertstr(last_op->text, last_op->len, text, length) == 0) - { - // append text to last op - int ln = last_op->len; - char *newtext = malloc(ln + length + 1); - memcpy(newtext, last_op->text, ln); - memcpy(newtext+ln, text, length); - newtext[ln+length] = '\0'; - - last_op->text = newtext; - last_op->len = ln + length; - last_op->end += length; - - return; + } else { + if(path.length == 0 || path.ptr[0] != '/') { + add_separator = 1; } } - char *str; - if(type == UI_TEXTBUF_INSERT) { - str = malloc(length + 1); - memcpy(str, text, length); - str[length] = 0; + cxmutstr url; + if(add_separator) { + url = cx_strcat(3, base, CX_STR("/"), path); } else { - length = txv->endPos - txv->startPos; - str = malloc(length + 1); - XmTextGetSubstring(value->obj, txv->startPos, length, length+1, str); - } - - UiTextBufOp *op = malloc(sizeof(UiTextBufOp)); - op->prev = NULL; - op->next = NULL; - op->type = type; - op->start = txv->startPos; - op->end = txv->endPos + 1; - op->len = length; - op->text = str; - - cx_linked_list_add( - (void**)&mgr->begin, - (void**)&mgr->end, - offsetof(UiTextBufOp, prev), - offsetof(UiTextBufOp, next), - op); - - mgr->cur = op; + url = cx_strcat(2, base, path); + } + + return url; } -int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen) { - // return 1 if oldstr + newstr are one word - - int has_space = 0; - for(int i=0;itextfield); + if(newpath) { + if(newpath[0] == '~') { + char *p = newpath+1; + char *home = getenv("HOME"); + char *cp = ConcatPath(home, p); + XtFree(newpath); + newpath = cp; + } else if(newpath[0] != '/') { + char curdir[2048]; + curdir[0] = 0; + getcwd(curdir, 2048); + char *cp = ConcatPath(curdir, newpath); + XtFree(newpath); + newpath = cp; } - } - - for(int i=0;i 32) { - return 1; + + /* update path */ + PathBarSetPath(p, newpath); + if(p->updateDir) { + p->updateDir(p->updateDirData, newpath, -1); + } + XtFree(newpath); + + /* hide textfield and show path as buttons */ + XtUnmanageChild(p->textfield); + pathbar_resize(p->widget, p, NULL); + + if(p->focus_widget) { + XmProcessTraversal(p->focus_widget, XmTRAVERSE_CURRENT); } } - - return 0; } -void ui_free_textbuf_op(UiTextBufOp *op) { - if(op->text) { - free(op->text); - } - free(op); +void pathbar_shift_left(Widget w, PathBar *p, XtPointer d) +{ + p->shift--; + pathbar_resize(p->widget, p, NULL); } - -void ui_text_undo(UiText *value) { - UiUndoMgr *mgr = value->undomgr; - - if(mgr->cur) { - UiTextBufOp *op = mgr->cur; - mgr->event = 0; - switch(op->type) { - case UI_TEXTBUF_INSERT: { - XmTextReplace(value->obj, op->start, op->end, ""); - break; - } - case UI_TEXTBUF_DELETE: { - XmTextInsert(value->obj, op->start, op->text); - break; - } +void pathbar_shift_right(Widget w, PathBar *p, XtPointer d) +{ + if(p->shift < 0) { + p->shift++; + } + pathbar_resize(p->widget, p, NULL); +} + +static void pathTextEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) { + PathBar *pb = data; + if(event->type == KeyReleaseMask) { + if(event->xkey.keycode == 9) { + XtUnmanageChild(pb->textfield); + pathbar_resize(pb->widget, pb, NULL); + *dispatch = False; + } else if(event->xkey.keycode == 36) { + pathbar_pathinput(pb->textfield, pb, NULL); + *dispatch = False; } - mgr->event = 1; - mgr->cur = mgr->cur->prev; } } -void ui_text_redo(UiText *value) { - UiUndoMgr *mgr = value->undomgr; +PathBar* CreatePathBar(Widget parent, ArgList args, int n) +{ + PathBar *bar = (PathBar*)XtMalloc(sizeof(PathBar)); + bar->path = NULL; + bar->updateDir = NULL; + bar->updateDirData = NULL; + + bar->focus_widget = NULL; + + bar->getpathelm = NULL; + bar->getpathelmdata = NULL; + bar->current_pathelms = NULL; + + bar->shift = 0; + + XtSetArg(args[n], XmNmarginWidth, 0); n++; + XtSetArg(args[n], XmNmarginHeight, 0); n++; + bar->widget = XmCreateDrawingArea(parent, "pathbar", args, n); + XtAddCallback( + bar->widget, + XmNresizeCallback, + (XtCallbackProc)pathbar_resize, + bar); + XtAddCallback( + bar->widget, + XmNinputCallback, + (XtCallbackProc)pathbar_input, + bar); + + Arg a[4]; + XtSetArg(a[0], XmNshadowThickness, 0); + XtSetArg(a[1], XmNx, 0); + XtSetArg(a[2], XmNy, 0); + bar->textfield = XNECreateText(bar->widget, "pbtext", a, 3); + bar->input = 0; + XtAddCallback( + bar->textfield, + XmNlosingFocusCallback, + (XtCallbackProc)pathbar_losingfocus, + bar); + XtAddCallback(bar->textfield, XmNactivateCallback, + (XtCallbackProc)pathbar_pathinput, bar); + XtAddEventHandler(bar->textfield, KeyPressMask | KeyReleaseMask, FALSE, pathTextEH, bar); + + XtSetArg(a[0], XmNarrowDirection, XmARROW_LEFT); + bar->left = XmCreateArrowButton(bar->widget, "pbbutton", a, 1); + XtSetArg(a[0], XmNarrowDirection, XmARROW_RIGHT); + bar->right = XmCreateArrowButton(bar->widget, "pbbutton", a, 1); + XtAddCallback( + bar->left, + XmNactivateCallback, + (XtCallbackProc)pathbar_shift_left, + bar); + XtAddCallback( + bar->right, + XmNactivateCallback, + (XtCallbackProc)pathbar_shift_right, + bar); + + Pixel bg; + XtVaGetValues(bar->textfield, XmNbackground, &bg, NULL); + XtVaSetValues(bar->widget, XmNbackground, bg, NULL); + + XtManageChild(bar->left); + XtManageChild(bar->right); - UiTextBufOp *elm = NULL; - if(mgr->cur) { - if(mgr->cur->next) { - elm = mgr->cur->next; + XtVaGetValues(bar->left, XmNwidth, &bar->lw, NULL); + XtVaGetValues(bar->right, XmNwidth, &bar->rw, NULL); + + bar->segmentAlloc = 16; + bar->numSegments = 0; + bar->pathSegments = (Widget*)XtCalloc(16, sizeof(Widget)); + + bar->selection = 0; + + return bar; +} + +void PathBarChangeDir(Widget w, PathBar *bar, XtPointer c) +{ + XmToggleButtonSetState(bar->pathSegments[bar->selection], False, False); + + int i; + for(i=0;inumSegments;i++) { + if(bar->pathSegments[i] == w) { + bar->selection = i; + XmToggleButtonSetState(w, True, False); + break; } - } else if(mgr->begin) { - elm = mgr->begin; } - if(elm) { - UiTextBufOp *op = elm; - mgr->event = 0; - switch(op->type) { - case UI_TEXTBUF_INSERT: { - XmTextInsert(value->obj, op->start, op->text); - break; - } - case UI_TEXTBUF_DELETE: { - XmTextReplace(value->obj, op->start, op->end, ""); - break; - } - } - mgr->event = 1; - mgr->cur = elm; + UiPathElm elm = bar->current_pathelms[i]; + cxmutstr name = cx_strdup(cx_strn(elm.name, elm.name_len)); + if(bar->updateDir) { + bar->updateDir(bar->updateDirData, name.ptr, i); } + free(name.ptr); } - -/* ------------------------- textfield ------------------------- */ - -static UIWIDGET create_textfield(UiObject *obj, int width, UiBool frameless, UiBool password, UiString *value) { - UiContainer *ct = uic_get_current_container(obj); - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNeditMode, XmSINGLE_LINE_EDIT); - n++; - if(width > 0) { - XtSetArg(args[n], XmNcolumns, width / 2 + 1); - n++; +static void ui_pathelm_destroy(UiPathElm *elms, size_t nelm) { + for(int i=0;ipath) { + free(bar->path); } - if(password) { - // TODO + bar->path = strdup(path); + + for(int i=0;inumSegments;i++) { + XtDestroyWidget(bar->pathSegments[i]); } + XtUnmanageChild(bar->textfield); + XtManageChild(bar->left); + XtManageChild(bar->right); + bar->input = False; - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget textfield = XmCreateText(parent, "text_field", args, n); - ct->add(ct, textfield); - XtManageChild(textfield); + Arg args[4]; + XmString str; - // bind value - if(value) { - if(value->value.ptr) { - XmTextSetString(textfield, value->value.ptr); - value->value.free(value->value.ptr); - } + bar->numSegments = 0; + + ui_pathelm_destroy(bar->current_pathelms, bar->numSegments); + size_t nelm = 0; + UiPathElm* path_elm = bar->getpathelm(bar->path, strlen(bar->path), &nelm, bar->getpathelmdata); + if (!path_elm) { + return; + } + bar->current_pathelms = path_elm; + bar->numSegments = nelm; + bar->pathSegments = realloc(bar->pathSegments, nelm * sizeof(Widget*)); + + for(int i=0;iset = ui_textfield_set; - value->get = ui_textfield_get; - value->value.ptr = NULL; - value->obj = textfield; + cxmutstr name = cx_strdup(cx_strn(elm.name, elm.name_len)); + str = XmStringCreateLocalized(elm.name); + free(name.ptr); + + XtSetArg(args[0], XmNlabelString, str); + XtSetArg(args[1], XmNfillOnSelect, True); + XtSetArg(args[2], XmNindicatorOn, False); + Widget button = XmCreateToggleButton(bar->widget, "pbbutton", args, 3); + XtAddCallback( + button, + XmNvalueChangedCallback, + (XtCallbackProc)PathBarChangeDir, + bar); + XmStringFree(str); + + bar->pathSegments[i] = button; } - return textfield; + bar->selection = bar->numSegments-1; + XmToggleButtonSetState(bar->pathSegments[bar->selection], True, False); + + XNETextSetString(bar->textfield, (char*)path); + XNETextSetInsertionPosition(bar->textfield, XNETextGetLastPosition(bar->textfield)); + + pathbar_resize(bar->widget, bar, NULL); } -static UIWIDGET create_textfield_nv(UiObject *obj, int width, UiBool frameless, UiBool password, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_STRING); - if(var) { - UiString *value = var->value; - return ui_textfield(obj, value); - } else { - // TODO: error +void PathBarDestroy(PathBar *pathbar) { + if(pathbar->path) { + XtFree(pathbar->path); } - return NULL; + XtFree((void*)pathbar->pathSegments); + XtFree((void*)pathbar); } -UIWIDGET ui_textfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, FALSE, FALSE, value); -} -UIWIDGET ui_textfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, FALSE, FALSE, varname); -} +/* ---------------------------- Path Text Field ---------------------------- */ -UIWIDGET ui_textfield_w(UiObject *obj, int width, UiString *value) { - return create_textfield(obj, width, FALSE, FALSE, value); +static void destroy_pathbar(Widget w, XtPointer *data, XtPointer d) { + PathBar *pathbar = (PathBar*)data; + // TODO: check if there is somonething missing + XtFree((void*)pathbar->pathSegments); + XtFree((void*)pathbar); } -UIWIDGET ui_textfield_wnv(UiObject *obj, int width, char *varname) { - return create_textfield_nv(obj, width, FALSE, FALSE, varname); -} +// TODO: move to common +static UiPathElm* default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data) { + cxstring *pathelms; + size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len), CX_STR("/"), 4096, &pathelms); -UIWIDGET ui_frameless_textfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, TRUE, FALSE, value); -} + if (nelm == 0) { + *ret_nelm = 0; + return NULL; + } -UIWIDGET ui_frameless_textfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, TRUE, FALSE, varname); -} + UiPathElm* elms = (UiPathElm*)calloc(nelm, sizeof(UiPathElm)); + size_t n = nelm; + int j = 0; + for (int i = 0; i < nelm; i++) { + cxstring c = pathelms[i]; + if (c.length == 0) { + if (i == 0) { + c.length = 1; + } + else { + n--; + continue; + } + } -UIWIDGET ui_passwordfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, FALSE, TRUE, value); -} + cxmutstr m = cx_strdup(c); + elms[j].name = m.ptr; + elms[j].name_len = m.length; + + size_t elm_path_len = c.ptr + c.length - full_path; + cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len)); + elms[j].path = elm_path.ptr; + elms[j].path_len = elm_path.length; -UIWIDGET ui_passwordfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, FALSE, TRUE, varname); -} + j++; + } + *ret_nelm = n; -UIWIDGET ui_passwordfield_w(UiObject *obj, int width, UiString *value) { - return create_textfield(obj, width, FALSE, TRUE, value); + return elms; } -UIWIDGET ui_passwordfield_wnv(UiObject *obj, int width, char *varname) { - return create_textfield_nv(obj, width, FALSE, TRUE, varname); +static void pathbar_activate(void *data, char *path, int index) { + UiEventData *event = data; + UiEvent evt; + evt.obj = event->obj; + evt.window = evt.obj->window; + evt.document = evt.obj->ctx->document; + evt.eventdata = path; + evt.intval = index; + event->callback(&evt, event->userdata); } +UIWIDGET ui_path_textfield_create(UiObject* obj, UiPathTextFieldArgs args) { + Arg xargs[16]; + int n = 0; + + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + Widget parent = ctn->prepare(ctn, xargs, &n); + // TODO: name + -char* ui_textfield_get(UiString *str) { - if(str->value.ptr) { - str->value.free(str->value.ptr); + PathBar *pathbar = CreatePathBar(parent, xargs, n); + if(!args.getpathelm) { + pathbar->getpathelm= default_pathelm_func; + } else { + pathbar->getpathelm = args.getpathelm; + pathbar->getpathelmdata = args.getpathelmdata; + } + + + XtManageChild(pathbar->widget); + ctn->add(ctn, pathbar->widget); + + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING); + if (var) { + UiString* value = (UiString*)var->value; + value->obj = pathbar; + value->get = ui_path_textfield_get; + value->set = ui_path_textfield_set; + + if(value->value.ptr) { + char *str = strdup(value->value.ptr); + ui_string_set(value, str); + free(str); + } } - char *value = XmTextGetString(str->obj); + + if(args.onactivate) { + UiEventData *eventdata = malloc(sizeof(UiEventData)); + eventdata->callback = args.onactivate; + eventdata->userdata = args.onactivatedata; + eventdata->obj = obj; + eventdata->value = 0; + + pathbar->updateDir = pathbar_activate; + pathbar->updateDirData = eventdata; + + XtAddCallback( + pathbar->widget, + XmNdestroyCallback, + (XtCallbackProc)ui_destroy_eventdata, + eventdata); + } + + XtAddCallback( + pathbar->widget, + XmNdestroyCallback, + (XtCallbackProc)destroy_pathbar, + pathbar); + + return pathbar->widget; +} + +char* ui_path_textfield_get(UiString *str) { + PathBar *pathbar = str->obj; + str->value.free(str->value.ptr); + char *value = XmTextFieldGetString(pathbar->textfield); str->value.ptr = value; str->value.free = (ui_freefunc)XtFree; return value; } -void ui_textfield_set(UiString *str, char *value) { - XmTextSetString(str->obj, value); - if(str->value.ptr) { - str->value.free(str->value.ptr); - } - str->value.ptr = NULL; +void ui_path_textfield_set(UiString *str, const char *value) { + PathBarSetPath(str->obj, value); } - diff --git a/ui/motif/text.h b/ui/motif/text.h index d40ce5c..a9e84ac 100644 --- a/ui/motif/text.h +++ b/ui/motif/text.h @@ -37,54 +37,13 @@ extern "C" { #endif -#define UI_TEXTBUF_INSERT 0 -#define UI_TEXTBUF_DELETE 1 -typedef struct UiTextBufOp UiTextBufOp; -struct UiTextBufOp { - UiTextBufOp *prev; - UiTextBufOp *next; - int type; // UI_TEXTBUF_INSERT, UI_TEXTBUF_DELETE - int start; - int end; - int len; - char *text; -}; - -typedef struct UiUndoMgr { - UiTextBufOp *begin; - UiTextBufOp *end; - UiTextBufOp *cur; - int length; - int event; -} UiUndoMgr; - -typedef struct UiTextArea { - UiContext *ctx; - int last_selection_state; -} UiTextArea; - -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_selection(UiText *text, int *begin, int *end); -int ui_textarea_length(UiText *text); - -UiUndoMgr* ui_create_undomgr(); -void ui_destroy_undomgr(UiUndoMgr *mgr); -void ui_text_selection_callback( - Widget widget, - UiTextArea *textarea, - XtPointer data); -void ui_text_modify_callback(Widget widget, UiVar *var, XtPointer data); -int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen); -void ui_free_textbuf_op(UiTextBufOp *op); - char* ui_textfield_get(UiString *str); -void ui_textfield_set(UiString *str, char *value); +void ui_textfield_set(UiString *str, const char *value); + +char* ui_path_textfield_get(UiString *str); +void ui_path_textfield_set(UiString *str, const char *value); + #ifdef __cplusplus } #endif diff --git a/ui/motif/toolbar.c b/ui/motif/toolbar.c index 35914f9..2860f13 100644 --- a/ui/motif/toolbar.c +++ b/ui/motif/toolbar.c @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -42,340 +42,3 @@ #include "../common/context.h" -static CxMap *toolbar_items; -static CxList *defaults; - -void ui_toolbar_init() { - toolbar_items = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); - defaults = cxLinkedListCreateSimple(CX_STORE_POINTERS); -} - -void ui_toolitem(char *name, char *label, ui_callback f, void *userdata) { - UiToolItem *item = malloc(sizeof(UiToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_widget; - item->label = label; - item->image = NULL; - item->callback = f; - item->userdata = userdata; - item->groups = NULL; - item->isimportant = FALSE; - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_st(char *name, char *stockid, ui_callback f, void *userdata) { - ui_toolitem_stgr(name, stockid, f, userdata, -1); -} - -void ui_toolitem_stgr(char *name, char *stockid, ui_callback f, void *userdata, ...) { - UiStToolItem *item = malloc(sizeof(UiStToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_st_widget; - item->stockid = stockid; - item->callback = f; - item->userdata = userdata; - item->groups = NULL; - item->isimportant = FALSE; - - // add groups - va_list ap; - va_start(ap, userdata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!item->groups) { - item->groups = cxArrayListCreateSimple(sizeof(int), 16); - } - cxListAdd(item->groups, &group); - } - va_end(ap); - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_img(char *name, char *label, char *img, ui_callback f, void *udata) { - // TODO - - UiToolItem *item = malloc(sizeof(UiToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_widget; - item->label = label; - item->image = img; - item->callback = f; - item->userdata = udata; - item->groups = NULL; - item->isimportant = FALSE; - - cxMapPut(toolbar_items, name, item); -} - - -void ui_toolitem_toggle_stgr(char *name, char *stockid, ui_callback f, void *udata, ...) { - // TODO - - UiStToolItem *item = malloc(sizeof(UiStToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_st_toggle_widget; - item->stockid = stockid; - item->callback = f; - item->userdata = udata; - item->groups = NULL; - item->isimportant = FALSE; - - // add groups - va_list ap; - va_start(ap, udata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!item->groups) { - item->groups = cxArrayListCreateSimple(sizeof(int), 16); - } - cxListAdd(item->groups, &group); - } - va_end(ap); - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolitem_toggle_imggr(char *name, char *label, char *img, ui_callback f, void *udata, ...) { - // TODO - - UiToolItem *item = malloc(sizeof(UiToolItem)); - item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget; - item->label = label; - item->image = img; - item->callback = f; - item->userdata = udata; - item->groups = NULL; - item->isimportant = FALSE; - - // add groups - va_list ap; - va_start(ap, udata); - int group; - while((group = va_arg(ap, int)) != -1) { - if(!item->groups) { - item->groups = cxArrayListCreateSimple(sizeof(int), 16); - } - cxListAdd(item->groups, &group); - } - va_end(ap); - - cxMapPut(toolbar_items, name, item); -} - -void ui_toolbar_combobox( - char *name, - UiList *list, - ui_getvaluefunc getvalue, - ui_callback f, - void *udata) -{ - UiToolbarComboBox *cb = malloc(sizeof(UiToolbarComboBox)); - cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox; - cb->list = list; - cb->getvalue = getvalue; - cb->callback = f; - cb->userdata = udata; - - cxMapPut(toolbar_items, name, cb); -} - -void ui_toolbar_combobox_str( - char *name, - UiList *list, - ui_callback f, - void *udata) -{ - ui_toolbar_combobox(name, list, ui_strmodel_getvalue, f, udata); -} - -void ui_toolbar_combobox_nv( - char *name, - char *listname, - ui_getvaluefunc getvalue, - ui_callback f, - void *udata) -{ - UiToolbarComboBoxNV *cb = malloc(sizeof(UiToolbarComboBoxNV)); - cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox_nv; - cb->listname = listname; - cb->getvalue = getvalue; - cb->callback = f; - cb->userdata = udata; - - cxMapPut(toolbar_items, name, cb); -} - - -void ui_toolbar_add_default(char *name) { - char *s = strdup(name); - cxListAdd(defaults, s); -} - -Widget ui_create_toolbar(UiObject *obj, Widget parent) { - if(!defaults) { - return NULL; - } - - Arg args[8]; - XtSetArg(args[0], XmNshadowType, XmSHADOW_ETCHED_OUT); - XtSetArg(args[1], XmNshadowThickness, 1); - XtSetArg(args[2], XmNtopAttachment, XmATTACH_FORM); - XtSetArg(args[3], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[4], XmNrightAttachment, XmATTACH_FORM); - Widget frame = XmCreateFrame(parent, "toolbar_frame", args, 5); - - XtSetArg(args[0], XmNorientation, XmHORIZONTAL); - XtSetArg(args[1], XmNpacking, XmPACK_TIGHT); - XtSetArg(args[2], XmNspacing, 1); - Widget toolbar = XmCreateRowColumn (frame, "toolbar", args, 3); - - CxIterator i = cxListIterator(defaults); - cx_foreach(char *, def, i) { - UiToolItemI *item = cxMapGet(toolbar_items, def); - if(item) { - item->add_to(toolbar, item, obj); - } else if(!strcmp(def, "@separator")) { - // TODO - } else { - fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", def); - } - } - - XtManageChild(toolbar); - XtManageChild(frame); - - return frame; -} - -void add_toolitem_widget(Widget parent, UiToolItem *item, UiObject *obj) { - Arg args[4]; - - XmString label = XmStringCreateLocalized(item->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNshadowThickness, 1); - XtSetArg(args[2], XmNtraversalOn, FALSE); - Widget button = XmCreatePushButton(parent, "toolbar_button", args, 3); - - XmStringFree(label); - - if(item->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; - XtAddCallback( - button, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - - XtManageChild(button); - - if(item->groups) { - uic_add_group_widget(obj->ctx, button, (ui_enablefunc)XtSetSensitive, item->groups); - } -} - -void add_toolitem_st_widget(Widget parent, UiStToolItem *item, UiObject *obj) { - Arg args[8]; - - UiStockItem *stock_item = ui_get_stock_item(item->stockid); - - XmString label = XmStringCreateLocalized(stock_item->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNshadowThickness, 1); - XtSetArg(args[2], XmNtraversalOn, FALSE); - Widget button = XmCreatePushButton(parent, "toolbar_button", args, 3); - - XmStringFree(label); - - if(item->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; - XtAddCallback( - button, - XmNactivateCallback, - (XtCallbackProc)ui_push_button_callback, - event); - } - - XtManageChild(button); - - if(item->groups) { - uic_add_group_widget(obj->ctx, button, (ui_enablefunc)XtSetSensitive, item->groups); - } -} - -void add_toolitem_toggle_widget(Widget parent, UiToolItem *item, UiObject *obj) { - Arg args[8]; - - XmString label = XmStringCreateLocalized(item->label); - XtSetArg(args[0], XmNlabelString, label); - XtSetArg(args[1], XmNshadowThickness, 1); - XtSetArg(args[2], XmNtraversalOn, FALSE); - XtSetArg(args[3], XmNindicatorOn, XmINDICATOR_NONE); - Widget button = XmCreateToggleButton(parent, "toolbar_toggle_button", args, 4); - - XmStringFree(label); - - if(item->callback) { - UiEventData *event = cxMalloc( - obj->ctx->allocator, - sizeof(UiEventData)); - event->obj = obj; - event->userdata = item->userdata; - event->callback = item->callback; - XtAddCallback( - button, - XmNvalueChangedCallback, - (XtCallbackProc)ui_toggle_button_callback, - event); - } - - XtManageChild(button); - - if(item->groups) { - uic_add_group_widget(obj->ctx, button, (ui_enablefunc)XtSetSensitive, item->groups); - } -} - -void add_toolitem_st_toggle_widget(Widget parent, UiStToolItem *item, UiObject *obj) { - -} - -void add_toolbar_combobox(Widget tb, UiToolbarComboBox *item, UiObject *obj) { - UiListView *listview = cxMalloc( - obj->ctx->allocator, - sizeof(UiListView)); - - UiVar *var = cxMalloc(obj->ctx->allocator, sizeof(UiVar)); - var->value = item->list; - var->type = UI_VAR_SPECIAL; - - Arg args[8]; - XtSetArg(args[0], XmNshadowThickness, 1); - XtSetArg(args[1], XmNindicatorOn, XmINDICATOR_NONE); - XtSetArg(args[2], XmNtraversalOn, FALSE); - XtSetArg(args[3], XmNwidth, 120); - Widget combobox = XmCreateDropDownList(tb, "toolbar_combobox", args, 4); - XtManageChild(combobox); - listview->widget = combobox; - listview->list = var; - listview->getvalue = item->getvalue; - - ui_listview_update(NULL, listview); - - if(item->callback) { - // TODO: - - } -} - -void add_toolbar_combobox_nv(Widget tb, UiToolbarComboBoxNV *item, UiObject *obj) { - -} diff --git a/ui/motif/toolbar.h b/ui/motif/toolbar.h index 777adf3..8b9e3c2 100644 --- a/ui/motif/toolbar.h +++ b/ui/motif/toolbar.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -37,66 +37,6 @@ extern "C" { #endif -typedef struct UiToolItemI UiToolItemI; -typedef struct UiToolItem UiToolItem; -typedef struct UiStToolItem UiStToolItem; - -typedef struct UiToolbarComboBox UiToolbarComboBox; -typedef struct UiToolbarComboBoxNV UiToolbarComboBoxNV; - -typedef void(*ui_toolbar_add_f)(Widget, UiToolItemI*, UiObject*); - -struct UiToolItemI { - ui_toolbar_add_f add_to; -}; - -struct UiToolItem { - UiToolItemI item; - char *label; - void *image; - ui_callback callback; - void *userdata; - CxList *groups; - Boolean isimportant; -}; - -struct UiStToolItem { - UiToolItemI item; - char *stockid; - ui_callback callback; - void *userdata; - CxList *groups; - Boolean isimportant; -}; - -struct UiToolbarComboBox { - UiToolItemI item; - UiList *list; - ui_getvaluefunc getvalue; - ui_callback callback; - void *userdata; -}; - -struct UiToolbarComboBoxNV { - UiToolItemI item; - char *listname; - ui_getvaluefunc getvalue; - ui_callback callback; - void *userdata; -}; - -void ui_toolbar_init(); - -Widget ui_create_toolbar(UiObject *obj, Widget parent); - -void add_toolitem_widget(Widget tb, UiToolItem *item, UiObject *obj); -void add_toolitem_st_widget(Widget tb, UiStToolItem *item, UiObject *obj); -void add_toolitem_toggle_widget(Widget tb, UiToolItem *item, UiObject *obj); -void add_toolitem_st_toggle_widget(Widget tb, UiStToolItem *item, UiObject *obj); - -void add_toolbar_combobox(Widget tb, UiToolbarComboBox *item, UiObject *obj); -void add_toolbar_combobox_nv(Widget tb, UiToolbarComboBoxNV *item, UiObject *obj); - #ifdef __cplusplus } #endif diff --git a/ui/motif/toolkit.c b/ui/motif/toolkit.c index f975b4f..2218064 100644 --- a/ui/motif/toolkit.c +++ b/ui/motif/toolkit.c @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -33,15 +33,21 @@ #include "toolkit.h" #include "toolbar.h" +#include "container.h" #include "stock.h" +#include "../common/menu.h" +#include "../common/toolbar.h" #include "../common/document.h" #include "../common/properties.h" #include +#include +#include + static XtAppContext app; static Display *display; static Widget active_window; -static char *application_name; +static const char *application_name; static ui_callback startup_func; static void *startup_data; @@ -68,6 +74,11 @@ static String fallback[] = { "*rt*fontType: FONT_IS_XFT", "*rt*fontName: Sans", "*rt*fontSize: 11", + + "*window_frame.shadowType: SHADOW_ETCHED_OUT", + "*window_frame.shadowThickness: 1", + "*togglebutton.shadowThickness: 1", + "*togglebutton.highlightThickness: 2", NULL }; @@ -76,8 +87,9 @@ void input_proc(XtPointer data, int *source, XtInputId *iid) { read(event_pipe[0], &ptr, sizeof(void*)); } -void ui_init(char *appname, int argc, char **argv) { +void ui_init(const char *appname, int argc, char **argv) { application_name = appname; + uic_init_global_context(); XtToolkitInitialize(); XtSetLanguageProc(NULL, NULL, NULL); @@ -85,15 +97,10 @@ void ui_init(char *appname, int argc, char **argv) { XtAppSetFallbackResources(app, fallback); display = XtOpenDisplay(app, NULL, appname, appname, NULL, 0, &argc, argv); - char **missing = NULL; - int nm = 0; - char *def = NULL; - XCreateFontSet(display, "-dt-interface system-medium-r-normal-s*utf*", &missing, &nm, &def); uic_docmgr_init(); - ui_toolbar_init(); - ui_stock_init(); - + uic_menu_init(); + uic_toolbar_init(); uic_load_app_properties(); if(pipe(event_pipe)) { @@ -108,11 +115,11 @@ void ui_init(char *appname, int argc, char **argv) { NULL); } -char* ui_appname() { +const char* ui_appname() { return application_name; } -Display* ui_get_display() { +Display* ui_motif_get_display() { return display; } @@ -157,11 +164,12 @@ void ui_secondary_event_loop(int *loop) { void ui_show(UiObject *obj) { uic_check_group_widgets(obj->ctx); XtRealizeWidget(obj->widget); - ui_window_dark_theme(XtDisplay(obj->widget), XtWindow(obj->widget)); // TODO: if } -// implemented in window.c -//void ui_close(UiObject *obj) +void ui_close(UiObject *obj) { + +} + void ui_set_enabled(UIWIDGET widget, int enabled) { XtSetSensitive(widget, enabled); @@ -182,17 +190,16 @@ void ui_set_visible(UIWIDGET widget, int visible) { } static Boolean ui_job_finished(void *data) { - printf("WorkProc\n"); UiJob *job = data; - - UiEvent event; - event.obj = job->obj; - event.window = job->obj->window; - event.document = job->obj->ctx->document; - event.intval = 0; - event.eventdata = NULL; - - job->finish_callback(&event, job->finish_data); + if(job->finish_callback) { + UiEvent event; + event.obj = job->obj; + event.window = job->obj->window; + event.document = job->obj->ctx->document; + event.intval = 0; + event.eventdata = NULL; + job->finish_callback(&event, job->finish_data); + } free(job); return TRUE; } @@ -201,7 +208,6 @@ static void* ui_jobthread(void *data) { UiJob *job = data; int result = job->job_func(job->job_data); if(!result) { - printf("XtAppAddWorkProc\n"); write(event_pipe[1], &job, sizeof(void*)); // hack XtAppAddWorkProc(app, ui_job_finished, job); @@ -221,7 +227,6 @@ void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) } void ui_clipboard_set(char *str) { - printf("copy: {%s}\n", str); int length = strlen(str) + 1; Display *dp = XtDisplayOfObject(active_window); @@ -287,6 +292,9 @@ Widget ui_get_active_window() { return active_window; } +/* + * doesn't work with gnome anymore + */ void ui_window_dark_theme(Display *dp, Window window) { Atom atom = XInternAtom(dp, "_GTK_THEME_VARIANT", False); Atom type = XInternAtom(dp, "UTF8_STRING", False); @@ -300,3 +308,23 @@ void ui_window_dark_theme(Display *dp, Window window) { (const unsigned char*)"dark", 4); } + +void ui_destroy_eventdata(Widget w, XtPointer *data, XtPointer d) { + free(data); +} + +void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) { + if(!groups) { + return; + } + size_t ngroups = uic_group_array_size(groups); + ui_set_widget_ngroups(ctx, widget, groups, ngroups); +} + +void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups) { + if(ngroups > 0) { + uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); + ui_set_enabled(widget, FALSE); + } +} + diff --git a/ui/motif/toolkit.h b/ui/motif/toolkit.h index b14cbd9..df564e8 100644 --- a/ui/motif/toolkit.h +++ b/ui/motif/toolkit.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -38,8 +38,6 @@ extern "C" { #endif -Display* ui_get_display(); - typedef struct UiEventData { UiObject *obj; ui_callback callback; @@ -47,6 +45,31 @@ typedef struct UiEventData { int value; } UiEventData; +typedef struct UiEventDataExt { + UiObject *obj; + ui_callback callback; + void *userdata; + ui_callback callback2; + void *userdata2; + int value0; + int value1; + int value2; + int value3; + void *customdata0; + void *customdata1; + void *customdata2; + void *customdata3; +} UiEventDataExt; + +typedef struct UiVarEventData { + UiObject *obj; + UiVar *var; + UiObserver **observers; + ui_callback callback; + void *userdata; + int value; +} UiVarEventData; + typedef struct UiJob { UiObject *obj; ui_threadfunc job_func; @@ -60,12 +83,19 @@ enum UiOrientation { UI_HORIZONTAL = 0, UI_VERTICAL }; void ui_exit_mainloop(); +Display* ui_motif_get_display(void); + void ui_set_active_window(Widget w); Widget ui_get_active_window(); void ui_secondary_event_loop(int *loop); void ui_window_dark_theme(Display *dp, Window window); +void ui_destroy_eventdata(Widget w, XtPointer *data, XtPointer d); + +void ui_set_widget_groups(UiContext *ctx, Widget widget, const int *groups) ; +void ui_set_widget_ngroups(UiContext *ctx, Widget widget, const int *groups, size_t ngroups); + #ifdef __cplusplus } #endif diff --git a/ui/motif/window.c b/ui/motif/window.c index b2f1504..ec131f3 100644 --- a/ui/motif/window.c +++ b/ui/motif/window.c @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * 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: @@ -36,6 +36,8 @@ #include "../ui/window.h" #include "../common/context.h" +#include "Grid.h" + #include static int nwindows = 0; @@ -45,17 +47,7 @@ static int window_default_height = 500; static void window_close_handler(Widget window, void *udata, void *cdata) { UiObject *obj = udata; - UiEvent ev; - ev.window = obj->window; - ev.document = obj->ctx->document; - ev.obj = obj; - ev.eventdata = NULL; - ev.intval = 0; - - if(obj->ctx->close_callback) { - obj->ctx->close_callback(&ev, obj->ctx->close_data); - } - // TODO: free UiObject + uic_object_destroy(obj); nwindows--; if(nwindows == 0) { @@ -63,7 +55,8 @@ static void window_close_handler(Widget window, void *udata, void *cdata) { } } -static UiObject* create_window(char *title, void *window_data, UiBool simple) { + +static UiObject* create_window(const char *title, void *window_data, Boolean simple) { CxMempool *mp = cxBasicMempoolCreate(256); const CxAllocator *a = mp->allocator; UiObject *obj = cxCalloc(a, 1, sizeof(UiObject)); @@ -72,23 +65,20 @@ static UiObject* create_window(char *title, void *window_data, UiBool simple) { Arg args[16]; int n = 0; - - XtSetArg(args[0], XmNtitle, title); - //XtSetArg(args[1], XmNbaseWidth, window_default_width); - //XtSetArg(args[2], XmNbaseHeight, window_default_height); - XtSetArg(args[1], XmNminWidth, 100); - XtSetArg(args[2], XmNminHeight, 50); - XtSetArg(args[3], XmNwidth, window_default_width); - XtSetArg(args[4], XmNheight, window_default_height); + XtSetArg(args[n], XmNtitle, title); n++; + XtSetArg(args[n], XmNminWidth, 100); n++; + XtSetArg(args[n], XmNminHeight, 50); n++; + XtSetArg(args[n], XmNwidth, window_default_width); n++; + XtSetArg(args[n], XmNheight, window_default_height); n++; Widget toplevel = XtAppCreateShell( - "Test123", - "abc", + ui_appname(), + "mainwindow", //applicationShellWidgetClass, vendorShellWidgetClass, - ui_get_display(), + ui_motif_get_display(), args, - 5); + n); Atom wm_delete_window; wm_delete_window = XmInternAtom( @@ -101,111 +91,35 @@ static UiObject* create_window(char *title, void *window_data, UiBool simple) { window_close_handler, obj); - // TODO: use callback - ui_set_active_window(toplevel); - Widget window = XtVaCreateManagedWidget( title, xmMainWindowWidgetClass, toplevel, NULL); - obj->widget = window; - Widget form = XtVaCreateManagedWidget( - "window_form", - xmFormWidgetClass, - window, - NULL); - Widget toolbar = NULL; + // menu if(!simple) { - ui_create_menubar(obj); - toolbar = ui_create_toolbar(obj, form); + ui_create_menubar(obj, window); } - // window content - XtSetArg(args[0], XmNshadowType, XmSHADOW_ETCHED_OUT); - XtSetArg(args[1], XmNshadowThickness, 0); - XtSetArg(args[2], XmNleftAttachment, XmATTACH_FORM); - XtSetArg(args[3], XmNrightAttachment, XmATTACH_FORM); - XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM); - if(toolbar) { - XtSetArg(args[5], XmNtopAttachment, XmATTACH_WIDGET); - XtSetArg(args[6], XmNtopWidget, toolbar); - n = 7; - } else { - XtSetArg(args[5], XmNtopAttachment, XmATTACH_FORM); - n = 6; - } - Widget frame = XmCreateFrame(form, "content_frame", args, n); + // content frame + n = 0; + Widget frame = XmCreateFrame(window, "window_frame", args, n); XtManageChild(frame); - Widget content_form = XmCreateForm(frame, "content_form", NULL, 0); - XtManageChild(content_form); - obj->container = ui_box_container(obj, content_form, 0, 0, UI_BOX_VERTICAL); + Widget vbox = XtCreateManagedWidget("window_vbox", gridClass, frame, NULL, 0); + UiContainerX *container = ui_box_container(obj, vbox, UI_BOX_VERTICAL); + uic_object_push_container(obj, container); - XtManageChild(form); - obj->widget = toplevel; nwindows++; 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); } -UiObject* ui_simplewindow(char *title, void *window_data) { +UiObject* ui_simple_window(const char *title, void *window_data) { return create_window(title, window_data, TRUE); } - -void ui_close(UiObject *obj) { - XtDestroyWidget(obj->widget); - window_close_handler(obj->widget, obj, NULL); -} - -typedef struct FileDialogData { - int running; - char *file; -} FileDialogData; - -static void filedialog_select( - Widget widget, - FileDialogData *data, - XmFileSelectionBoxCallbackStruct *selection) -{ - char *path = NULL; - XmStringGetLtoR(selection->value, XmSTRING_DEFAULT_CHARSET, &path); - data->running = 0; - data->file = strdup(path); - XtFree(path); - XtUnmanageChild(widget); -} - -static void filedialog_cancel( - Widget widget, - FileDialogData *data, - XmFileSelectionBoxCallbackStruct *selection) - -{ - data->running = 0; - XtUnmanageChild(widget); -} - -char* ui_openfiledialog(UiObject *obj) { - Widget dialog = XmCreateFileSelectionDialog(obj->widget, "openfiledialog", NULL, 0); - XtManageChild(dialog); - - FileDialogData data; - data.running = 1; - data.file = NULL; - - XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)filedialog_select, &data); - XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)filedialog_cancel, &data); - - ui_secondary_event_loop(&data.running); - return data.file; -} - -char* ui_savefiledialog(UiObject *obj) { - return ui_openfiledialog(obj); -} diff --git a/ui/motif/window.h b/ui/motif/window.h new file mode 100644 index 0000000..33bb66d --- /dev/null +++ b/ui/motif/window.h @@ -0,0 +1,44 @@ +/* + * 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 WINDOW_H +#define WINDOW_H + +#ifdef __cplusplus +extern "C" { +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* WINDOW_H */ + diff --git a/ui/ui/container.h b/ui/ui/container.h index ec35c9c..3a4021b 100644 --- a/ui/ui/container.h +++ b/ui/ui/container.h @@ -141,6 +141,20 @@ typedef struct UiHeaderbarArgs { int alt_spacing; } UiHeaderbarArgs; +typedef struct UiSidebarArgs { + const char *name; + const char *style_class; + int margin; + int spacing; +} UiSidebarArgs; + + +struct UiContainerX { + void *container; + int close; + UiContainerX *prev; + UiContainerX *next; +}; #define UI_CTN(obj, ctn) for(ctn;ui_container_finish(obj);ui_container_begin_close(obj)) @@ -153,6 +167,7 @@ typedef struct UiHeaderbarArgs { #define ui_scrolledwindow(obj, ...) for(ui_scrolledwindow_create(obj, (UiFrameArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_tabview(obj, ...) for(ui_tabview_create(obj, (UiTabViewArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_headerbar(obj, ...) for(ui_headerbar_create(obj, (UiHeaderbarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) +#define ui_sidebar(obj, ...) for(ui_sidebar_create(obj, (UiSidebarArgs){ __VA_ARGS__ });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_vbox0(obj) for(ui_vbox_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_hbox0(obj) for(ui_hbox_create(obj, (UiContainerArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) @@ -162,6 +177,7 @@ typedef struct UiHeaderbarArgs { #define ui_scrolledwindow0(obj) for(ui_scrolledwindow_create(obj, (UiFrameArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_tabview0(obj) for(ui_tabview_create(obj, (UiTabViewArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_headerbar0(obj) for(ui_headerbar_create(obj, (UiHeaderbarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) +#define ui_sidebar0(obj) for(ui_sidebar_create(obj, (UiSidebarArgs){ 0 });ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_tab(obj, label) for(ui_tab_create(obj, label);ui_container_finish(obj);ui_container_begin_close(obj)) @@ -169,7 +185,8 @@ typedef struct UiHeaderbarArgs { #define ui_headerbar_center(obj) for(ui_headerbar_center_create(obj);ui_container_finish(obj);ui_container_begin_close(obj)) #define ui_headerbar_end(obj) for(ui_headerbar_end_create(obj);ui_container_finish(obj);ui_container_begin_close(obj)) -UIEXPORT void ui_end(UiObject *obj); +UIEXPORT void ui_end(UiObject *obj); // deprecated +UIEXPORT void ui_end_new(UiObject *obj); // TODO: rename to ui_end UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args); UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args); @@ -189,10 +206,8 @@ UIEXPORT void ui_headerbar_start_create(UiObject *obj); UIEXPORT void ui_headerbar_center_create(UiObject *obj); UIEXPORT void ui_headerbar_end_create(UiObject *obj); +UIEXPORT UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args); -UIEXPORT UIWIDGET ui_scrolledwindow_deprecated(UiObject *obj); // TODO - -UIEXPORT UIWIDGET ui_sidebar(UiObject *obj); // TODO UIEXPORT UIWIDGET ui_hsplitpane(UiObject *obj, int max); // TODO UIEXPORT UIWIDGET ui_vsplitpane(UiObject *obj, int max); // TODO diff --git a/ui/ui/text.h b/ui/ui/text.h index bbe300b..cb54f4c 100644 --- a/ui/ui/text.h +++ b/ui/ui/text.h @@ -71,6 +71,8 @@ typedef struct UiTextFieldArgs { const char *varname; ui_callback onchange; void *onchangedata; + ui_callback onactivate; + void *onactivatedata; const int *groups; } UiTextFieldArgs; diff --git a/ui/ui/toolkit.h b/ui/ui/toolkit.h index 9e3ab36..d723909 100644 --- a/ui/ui/toolkit.h +++ b/ui/ui/toolkit.h @@ -33,14 +33,13 @@ #ifdef UI_COCOA +#include #ifdef __OBJC__ #import -#define UIWIDGET NSView* -#define UIMENU NSMenu* -#else -typedef void* UIWIDGET; -typedef void* UIMENU; #endif +typedef void* UIWIDGET; // NSView* +typedef void* UIWINDOW; // NSWindow* +typedef void* UIMENU; // NSMenu* #elif UI_GTK2 || UI_GTK3 || UI_GTK4 @@ -152,9 +151,10 @@ extern "C" { #define UI_GROUPS(...) (const int[]){ __VA_ARGS__, -1 } /* public types */ -typedef int UiBool; +typedef _Bool UiBool; typedef struct UiObject UiObject; +typedef struct UiContainerX UiContainerX; typedef struct UiEvent UiEvent; typedef struct UiMouseEvent UiMouseEvent; typedef struct UiObserver UiObserver; @@ -215,7 +215,7 @@ struct UiObject { */ UIWIDGET widget; -#ifdef UI_WINUI +#if defined(UI_COCOA) || defined(UI_WINUI) /* * native window object */ @@ -233,10 +233,17 @@ struct UiObject { UiContext *ctx; /* - * container interface + * container interface (deprecated) */ UiContainer *container; + /* + * container list + * TODO: remove old UiContainer and rename UiContainerX to UiContainer + */ + UiContainerX *container_begin; + UiContainerX *container_end; + /* * next container object */ @@ -434,13 +441,13 @@ UIEXPORT void ui_context_closefunc(UiContext *ctx, ui_callback fnc, void *udata) UIEXPORT void ui_context_destroy(UiContext *ctx); UIEXPORT void ui_object_ref(UiObject *obj); -UIEXPORT void ui_object_unref(UiObject *obj); +UIEXPORT int ui_object_unref(UiObject *obj); UIEXPORT void ui_onstartup(ui_callback f, void *userdata); UIEXPORT void ui_onopen(ui_callback f, void *userdata); UIEXPORT void ui_onexit(ui_callback f, void *userdata); -UIEXPORT void ui_main(); +UIEXPORT void ui_main(void); UIEXPORT void ui_show(UiObject *obj); UIEXPORT void ui_close(UiObject *obj); diff --git a/ui/ui/tree.h b/ui/ui/tree.h index 83ad1e8..28c9f31 100644 --- a/ui/ui/tree.h +++ b/ui/ui/tree.h @@ -35,11 +35,15 @@ extern "C" { #endif -typedef struct UiModel UiModel; -typedef struct UiListCallbacks UiListCallbacks; -typedef struct UiListDnd UiListDnd; +typedef struct UiModel UiModel; +typedef struct UiListCallbacks UiListCallbacks; +typedef struct UiListDnd UiListDnd; -typedef struct UiListArgs UiListArgs; +typedef struct UiListArgs UiListArgs; +typedef struct UiSourceListArgs UiSourceListArgs; + +typedef struct UiSubList UiSubList; +typedef struct UiSubListItem UiSubListItem; typedef enum UiModelType { UI_STRING = 0, @@ -130,6 +134,81 @@ struct UiListArgs { const int *groups; }; +typedef void (*ui_sublist_getvalue_func)(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item); + +struct UiSubList { + UiList *value; + const char *varname; + const char *header; + UiBool separator; + void *userdata; +}; + +/* + * list item members must be filled by the sublist getvalue func + * all members must be allocated (by malloc, strdup, ...) the pointer + * will be passed to free + */ +struct UiSubListItem { + char *icon; + char *label; + char *button_icon; + char *button_label; + char *badge; + void *eventdata; +}; + +struct UiSourceListArgs { + UiTri fill; + UiBool hexpand; + UiBool vexpand; + UiBool hfill; + UiBool vfill; + int colspan; + int rowspan; + const char *name; + const char *style_class; + + const int *groups; + + /* + * list of sublists + * a sublist must have a varname or a value + * + * the last entry in the list must contain all NULL values or numsublists + * must contain the number of sublists + */ + UiSubList *sublists; + /* + * optional number of sublists + * if the value is 0, it is assumed, that sublists is null-terminated + * (last item contains only NULL values) + */ + size_t numsublists; + + /* + * callback for each list item, that should fill all necessary + * UiSubListItem fields + */ + ui_sublist_getvalue_func getvalue; + + /* + * activated when a list item is selected + */ + ui_callback onactivate; + void *onactivatedata; + + /* + * activated, when the additional list item button is clicked + */ + ui_callback onbuttonclick; + void *onbuttonclickdata; +}; + +#define UI_SUBLIST(...) (UiSubList){ __VA_ARGS__ } +#define UI_SUBLISTS(...) (UiSubList[]){ __VA_ARGS__, (UiSubList){NULL,NULL,NULL,0} } + + UIEXPORT UiModel* ui_model(UiContext *ctx, ...); UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model); UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi); @@ -138,16 +217,14 @@ UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi); #define ui_table(obj, ...) ui_table_create(obj, (UiListArgs) { __VA_ARGS__ } ) #define ui_combobox(obj, ...) ui_combobox_create(obj, (UiListArgs) { __VA_ARGS__ } ) #define ui_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, (UiListArgs) { __VA_ARGS__ } ) +#define ui_sourcelist(obj, ...) ui_sourcelist_create(obj, (UiSourceListArgs) { __VA_ARGS__ } ) UIEXPORT UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args); UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs args); UIEXPORT UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs args); UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject* obj, UiListArgs args); -void ui_table_dragsource_deprecated(UIWIDGET tablewidget, int actions, char *target0, ...); -void ui_table_dragsource_a_deprecated(UIWIDGET tablewidget, int actions, char **targets, int nelm); -void ui_table_dragdest_deprecated(UIWIDGET tablewidget, int actions, char *target0, ...); -void ui_table_dragdest_a_deprecated(UIWIDGET tablewidget, int actions, char **targets, int nelm); +UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args); #ifdef __cplusplus diff --git a/ui/ui/window.h b/ui/ui/window.h index ec568a9..352abb7 100644 --- a/ui/ui/window.h +++ b/ui/ui/window.h @@ -72,9 +72,10 @@ typedef struct UiDialogWindowArgs { void *onclickdata; } UiDialogWindowArgs; -UIEXPORT UiObject* ui_window(const char *title, void *window_data); -UIEXPORT UiObject* ui_simple_window(const char *title, void *window_data); -UIEXPORT UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args); +UIEXPORT UiObject *ui_window(const char *title, void *window_data); +UIEXPORT UiObject *ui_sidebar_window(const char *title, void *window_data); +UIEXPORT UiObject *ui_simple_window(const char *title, void *window_data); +UIEXPORT UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args); #define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, (UiDialogWindowArgs){ __VA_ARGS__ }); #define ui_dialog_window0(parent) ui_dialog_window_create(parent, (UiDialogWindowArgs){ 0 }); diff --git a/ui/wpf/Makefile b/ui/wpf/Makefile new file mode 100644 index 0000000..13deefb --- /dev/null +++ b/ui/wpf/Makefile @@ -0,0 +1,38 @@ +# +# 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. +# + +$(WPF_OBJPRE)%.o: wpf/%.c + $(CC) -o $@ -c $(CFLAGS) $< + +$(UI_LIB): $(OBJ) uiw + $(AR) $(ARFLAGS) $(UI_LIB) $(OBJ) + +uiw: + cd wpf/UIwrapper; $(MSBUILD) + cp $(BUILD_ROOT)/build/UIwrapper/UIwrapper.dll $(BUILD_ROOT)/build/bin/ + cp $(BUILD_ROOT)/build/UIcore/UIcore.dll $(BUILD_ROOT)/build/bin/ diff --git a/ui/wpf/UIcore/Application.cs b/ui/wpf/UIcore/Application.cs new file mode 100644 index 0000000..50c9c89 --- /dev/null +++ b/ui/wpf/UIcore/Application.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; + +namespace UI +{ + public class Application + { + private static Application instance; + + private System.Windows.Application application; + + private Thread thread; + + public String Name; + + public IApplicationCallbacks callbacks; + + public List Windows = new List(); + public ApplicationMenu Menu = new ApplicationMenu(); + public MainToolBar ToolBar = new MainToolBar(); + + private Application() : base() + { + thread = new Thread(() => RunApplication()); + thread.SetApartmentState(ApartmentState.STA); + } + + public static Application GetInstance() + { + if (instance == null) + { + instance = new Application(); + GC.KeepAlive(instance); + } + return instance; + } + + public Thread Start() + { + thread.Start(); + return thread; + } + + private void RunApplication() + { + application = new System.Windows.Application(); + + if(callbacks != null) + { + callbacks.OnStartup(); + } + application.Run(); + if(callbacks != null) + { + callbacks.OnExit(); + } + } + + public void AddWindow(Window window) + { + Windows.Add(window); + } + + public void RemoveWindow(Window window) + { + Windows.Remove(window); + if (Windows.Count == 0) + { + application.Shutdown(); + } + } + } + + public class ResultExec + { + public T Result; + public Func Func; + + public void Exec() + { + Result = Func.Invoke(); + } + } + + public class VoidExec + { + public Action Action; + + public void Exec() + { + Action.Invoke(); + } + } + + public interface IApplicationCallbacks + { + void OnStartup(); + void OnOpen(); + void OnExit(); + } +} diff --git a/ui/wpf/UIcore/Container.cs b/ui/wpf/UIcore/Container.cs new file mode 100644 index 0000000..4453ea6 --- /dev/null +++ b/ui/wpf/UIcore/Container.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; + +namespace UI +{ + public interface Container + { + Layout Layout { get; set; } + + void Add(UIElement control, bool fill); + } + + public class Layout + { + public bool? Fill { get; set; } + public bool Hexpand { get; set; } + public bool Vexpand { get; set; } + public bool NewLine { get; set; } + public int GridWidth { get; set; } + public String Label { get; set; } + + public Layout() + { + Reset(); + } + + public bool IsFill(bool fill) + { + if (Fill != null) + { + + return (bool)Fill; + } + return fill; + } + + public void Reset() + { + Fill = null; + Hexpand = false; + Vexpand = false; + NewLine = false; + GridWidth = 1; + Label = null; + } + } + + public enum BoxOrientation + { + VERTICAL, + HORIZONTAL + } + + public class BoxContainer : Grid, Container + { + public Layout Layout { get; set; } + + private BoxOrientation Orientation; + private int Spacing; + + private int x = 0; + private int y = 0; + + private bool filled = false; + + public BoxContainer(BoxOrientation orientation, int margin, int spacing) : base() + { + Layout = new Layout(); + Margin = new Thickness(margin); + Spacing = spacing; + + Orientation = orientation; + if(Orientation == BoxOrientation.HORIZONTAL) + { + RowDefinition row = new RowDefinition(); + row.Height = new GridLength(1, GridUnitType.Star); + RowDefinitions.Add(row); + } + else + { + ColumnDefinition col = new ColumnDefinition(); + col.Width = new GridLength(1, GridUnitType.Star); + ColumnDefinitions.Add(col); + } + } + + public BoxContainer(Container parent, BoxOrientation orientation, int margin, int spacing) : this(orientation, margin, spacing) + { + parent.Add(this, true); + } + + public void Add(UIElement control, bool fill) + { + fill = Layout.IsFill(fill); + + if(Orientation == BoxOrientation.HORIZONTAL) + { + if(Spacing > 0) + { + ColumnDefinition spaceCol = new ColumnDefinition(); + spaceCol.Width = new GridLength(Spacing, GridUnitType.Pixel); + ColumnDefinitions.Add(spaceCol); + x++; + } + + ColumnDefinition col = new ColumnDefinition(); + if(filled && fill) + { + fill = false; + Console.WriteLine("BoxContainer can only contain one filled control"); + } + if(fill) + { + col.Width = new GridLength(1, GridUnitType.Star); + filled = true; + } + else + { + col.Width = GridLength.Auto; + } + ColumnDefinitions.Add(col); + } + else + { + if (Spacing > 0) + { + RowDefinition spaceRow = new RowDefinition(); + spaceRow.Height = new GridLength(Spacing, GridUnitType.Pixel); + RowDefinitions.Add(spaceRow); + y++; + } + + RowDefinition row = new RowDefinition(); + if (filled && fill) + { + fill = false; + Console.WriteLine("BoxContainer can only contain one filled control"); + } + if(fill) + { + row.Height = new GridLength(1, GridUnitType.Star); + filled = true; + } + else + { + row.Height = GridLength.Auto; + } + RowDefinitions.Add(row); + } + + Grid.SetColumn(control, x); + Grid.SetRow(control, y); + Children.Add(control); + + if(Orientation == BoxOrientation.HORIZONTAL) + { + x++; + } + else + { + y++; + } + + Layout.Reset(); + } + } + + public class GridContainer : Grid, Container + { + public Layout Layout { get; set; } + + private int X = 0; + private int Y = 0; + private int CurrentWidth = 0; + private int CurrentHeight = 0; + + private int ColSpacing; + private int RowSpacing; + + public GridContainer(Container parent, int margin, int colspacing, int rowspacing) : base() + { + Layout = new Layout(); + + Margin = new Thickness(margin); + ColSpacing = colspacing; + RowSpacing = rowspacing; + + parent.Add(this, true); + } + + public void Add(UIElement control, bool fill) + { + if(Layout.NewLine) + { + X = 0; + Y++; + } + + ColumnDefinition col; + RowDefinition row; + bool getcol = false; + if(X >= CurrentWidth) + { + if (ColSpacing > 0 && X != 0) + { + ColumnDefinition spaceCol = new ColumnDefinition(); + spaceCol.Width = new GridLength(ColSpacing, GridUnitType.Pixel); + ColumnDefinitions.Add(spaceCol); + X++; + } + + col = new ColumnDefinition(); + col.Width = GridLength.Auto; + ColumnDefinitions.Add(col); + + CurrentWidth = X + 1; + } + else + { + if (ColSpacing > 0 && X % 2 > 0) + { + X++; + } + col = ColumnDefinitions.ElementAt(X); + } + + if(getcol) + { + col = ColumnDefinitions.ElementAt(X); + } + + if (Y >= CurrentHeight) + { + if (RowSpacing > 0 && Y != 0) + { + RowDefinition spaceRow = new RowDefinition(); + spaceRow.Height = new GridLength(RowSpacing, GridUnitType.Pixel); + RowDefinitions.Add(spaceRow); + Y++; + } + + row = new RowDefinition(); + row.Height = GridLength.Auto; + RowDefinitions.Add(row); + CurrentHeight = Y + 1; + } + else + { + row = RowDefinitions.ElementAt(Y); + } + + if(Layout.Hexpand) + { + col.Width = new GridLength(1, GridUnitType.Star); + } + if(Layout.Vexpand) + { + row.Height = new GridLength(1, GridUnitType.Star); + } + + int gridwidth = Layout.GridWidth; + if(gridwidth > 1) + { + gridwidth++; + } + + Grid.SetColumn(control, X); + Grid.SetRow(control, Y); + Grid.SetColumnSpan(control, gridwidth); + Children.Add(control); + + Layout.Reset(); + X += gridwidth; + } + } + + public class ScrollViewerContainer : ScrollViewer, Container + { + public Layout Layout { get; set; } + + public ScrollViewerContainer(Container parent) : base() + { + Layout = new Layout(); + + HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; + VerticalScrollBarVisibility = ScrollBarVisibility.Auto; + + parent.Add(this, true); + } + + public void Add(UIElement control, bool fill) + { + Content = control; + } + } + + public class TabViewContainer : TabControl, Container + { + public Layout Layout { get; set; } + + public TabViewContainer(Container parent) : base() + { + Layout = new Layout(); + parent.Add(this, true); + } + + public void Add(UIElement control, bool fill) + { + TabItem tab = new TabItem(); + tab.Header = Layout.Label != null ? Layout.Label : "New Tab"; + Items.Add(tab); + tab.Content = control; + Layout.Reset(); + } + } +} diff --git a/ui/wpf/UIcore/Controls.cs b/ui/wpf/UIcore/Controls.cs new file mode 100644 index 0000000..0162bd2 --- /dev/null +++ b/ui/wpf/UIcore/Controls.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; + +namespace UI +{ + public class Controls + { + public static Button Button(Container container, String label, RoutedEventHandler e) + { + Button button = new Button(); + button.Content = label; + container.Add(button, false); + + button.Click += e; + + return button; + } + + public static Label Label(Container container, String str, int alignment) + { + HorizontalAlignment a; + switch (alignment) + { + case 0: a = HorizontalAlignment.Left; break; + case 1: a = HorizontalAlignment.Right; break; + case 2: a = HorizontalAlignment.Center; break; + default: a = HorizontalAlignment.Left; break; + } + + Label label = new Label(); + label.HorizontalAlignment = a; + label.Content = str; + container.Add(label, false); + + return label; + } + + public static Label Space(Container container) + { + return Label(container, null, 2); + } + + public static Separator Separator(Container container) + { + Separator separator = new Separator(); + container.Add(separator, false); + return separator; + } + } +} diff --git a/ui/wpf/UIcore/DrawingArea.cs b/ui/wpf/UIcore/DrawingArea.cs new file mode 100644 index 0000000..6fb8368 --- /dev/null +++ b/ui/wpf/UIcore/DrawingArea.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Shapes; +using System.Diagnostics; + +namespace UI +{ + public class DrawingArea : System.Windows.Controls.Canvas + { + public Action resizeCallback; + + public Color Color; + private Brush Brush; + + public DrawingArea(Container container) : base() + { + this.SizeChanged += UpdateSize; + ResetGraphics(); + + container.Add(this, true); + } + + public void UpdateSize(object sender, SizeChangedEventArgs e) + { + if(resizeCallback != null) + { + Children.Clear(); + ResetGraphics(); + + Size s = e.NewSize; + resizeCallback((int)s.Width, (int)s.Height); + } + } + + public void Redraw() + { + if (resizeCallback != null) + { + Children.Clear(); + ResetGraphics(); + + resizeCallback((int)ActualWidth, (int)ActualHeight); + } + + } + + private void ResetGraphics() + { + Color = Color.FromRgb(0, 0, 0); + Brush = System.Windows.Media.Brushes.Black; + } + + public void SetColor(int r, int g, int b) + { + Color = Color.FromRgb((byte)r, (byte)g, (byte)b); + Brush = new SolidColorBrush(Color); + } + + public void DrawLine(int x1, int y1, int x2, int y2) + { + Line line = new Line(); + line.Stroke = Brush; + line.StrokeThickness = 1; + line.SnapsToDevicePixels = true; + + line.X1 = x1; + line.Y1 = y1; + line.X2 = x2; + line.Y2 = y2; + + Children.Add(line); + } + + public void DrawRect(int x, int y, int w, int h, bool fill) + { + Rectangle rect = new Rectangle(); + rect.Stroke = Brush; + rect.StrokeThickness = 1; + rect.SnapsToDevicePixels = true; + if(fill) + { + rect.Fill = Brush; + } + + rect.Width = w; + rect.Height = h; + SetLeft(rect, x); + SetTop(rect, y); + + Children.Add(rect); + } + } +} diff --git a/ui/wpf/UIcore/MainToolBar.cs b/ui/wpf/UIcore/MainToolBar.cs new file mode 100644 index 0000000..b160b9f --- /dev/null +++ b/ui/wpf/UIcore/MainToolBar.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace UI +{ + public class MainToolBar + { + Dictionary Items = new Dictionary(); + List Defaults = new List(); + + public MainToolBar() + { + + } + + public bool HasItems() + { + return Defaults.Count > 0 ? true : false; + } + + public void AddDefault(string itemName) + { + Defaults.Add(itemName); + } + + public void AddToolItem(string name, string label, Action action) + { + ToolItem item = new ToolItem(); + item.Label = label; + item.Action = action; + Items.Add(name, item); + } + + public ToolBarTray CreateToolBarTray(IntPtr objptr) + { + ToolBarTray tray = new ToolBarTray(); + ToolBar toolbar = new ToolBar(); + tray.ToolBars.Add(toolbar); + foreach(string s in Defaults) + { + IToolItem item = Items[s]; + item.AddTo(toolbar, objptr); + } + + return tray; + } + } + + public interface IToolItem + { + void AddTo(System.Windows.Controls.ToolBar toolbar, IntPtr uiobj); + } + + public class ToolItem : IToolItem + { + public string Label { get; set; } + // TODO: icon + public Action Action { get; set; } + + public void AddTo(System.Windows.Controls.ToolBar toolbar, IntPtr uiobj) + { + Button button = new Button(); + button.Content = Label; + + EventCallback e = new EventCallback(uiobj, Action); + button.Click += e.Callback; + + toolbar.Items.Add(button); + } + } +} diff --git a/ui/wpf/UIcore/Menu.cs b/ui/wpf/UIcore/Menu.cs new file mode 100644 index 0000000..e01cc22 --- /dev/null +++ b/ui/wpf/UIcore/Menu.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace UI +{ + public class ApplicationMenu + { + private List current = new List(); + + public List Menus = new List(); + + public void AddMenu(String label) + { + current.Clear(); + Menu menu = new Menu(label); + current.Add(menu); + Menus.Add(menu); + } + + public Boolean IsEmpty() + { + return Menus.Count == 0 ? true : false; + } + + public void AddSubMenu(String label) + { + Menu menu = new Menu(label); + current.Last().Items.Add(menu); + current.Add(menu); + } + + public void EndSubMenu() + { + current.Remove(current.Last()); + } + + public void AddMenuItem(String label, Action action) + { + if(current.Count != 0) + { + MenuItem item = new MenuItem(label, action); + current.Last().Items.Add(item); + } + } + + public System.Windows.Controls.Menu CreateMenu(IntPtr uiobj) + { + System.Windows.Controls.Menu menu = new System.Windows.Controls.Menu(); + menu.Background = new SolidColorBrush(Color.FromRgb(255, 255, 255)); + foreach (Menu m in Menus) + { + System.Windows.Controls.MenuItem i = new System.Windows.Controls.MenuItem(); + i.Header = m.Label; + m.AddItems(i, uiobj); + menu.Items.Add(i); + } + return menu; + } + } + + public interface IMenuItem + { + void AddTo(System.Windows.Controls.MenuItem menu, IntPtr uiobj); + } + + public class Menu : IMenuItem + { + public String Label; + public List Items = new List(); + + public Menu(String label) + { + Label = label; + } + + public void AddItems(System.Windows.Controls.MenuItem i, IntPtr uiobj) + { + foreach (IMenuItem item in Items) + { + item.AddTo(i, uiobj); + } + } + + void IMenuItem.AddTo(System.Windows.Controls.MenuItem menu, IntPtr uiobj) + { + System.Windows.Controls.MenuItem i = new System.Windows.Controls.MenuItem(); + i.Header = Label; + AddItems(i, uiobj); + menu.Items.Add(i); + } + } + + public class MenuItem : IMenuItem + { + String Label; + Action Action; + + public MenuItem(String label, Action action) + { + Label = label; + Action = action; + } + + void IMenuItem.AddTo(System.Windows.Controls.MenuItem menu, IntPtr uiobj) + { + System.Windows.Controls.MenuItem i = new System.Windows.Controls.MenuItem(); + EventCallback cb = new EventCallback(uiobj, Action); + i.Click += cb.Callback; + i.Header = Label; + menu.Items.Add(i); + } + } +} diff --git a/ui/wpf/UIcore/Properties/AssemblyInfo.cs b/ui/wpf/UIcore/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3ae74c5 --- /dev/null +++ b/ui/wpf/UIcore/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("UIcore")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UIcore")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("e93c93b6-d270-4178-998f-7e68d9591874")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ui/wpf/UIcore/TextArea.cs b/ui/wpf/UIcore/TextArea.cs new file mode 100644 index 0000000..4ca01ef --- /dev/null +++ b/ui/wpf/UIcore/TextArea.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UI +{ + public class TextArea : System.Windows.Controls.TextBox + { + public TextArea(Container container, String text, bool textarea) : base() + { + bool fill = false; + if (textarea) + { + AcceptsReturn = true; + IsUndoEnabled = false; // we need our own undo stack + VerticalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Auto; + HorizontalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Auto; + fill = true; + } + else + { + HorizontalScrollBarVisibility = System.Windows.Controls.ScrollBarVisibility.Auto; + MinWidth = 15; + } + + if (text != null) + { + Text = text; + } + + container.Add(this, fill); + } + + + // ------------------ UiText methods ------------------ + + public void SetText(String str) + { + Text = str; + } + + public String GetText() + { + return Text; + } + + public String GetSubString(int begin, int end) + { + return null; + } + + public void Insert(int pos, String str) + { + + } + + public int Position() + { + return CaretIndex; + } + + public int Selection() + { + return 0; + } + + public int Length() + { + return Text.Length; + } + + public void Remove(int begin, int end) + { + + } + } +} diff --git a/ui/wpf/UIcore/Toolkit.cs b/ui/wpf/UIcore/Toolkit.cs new file mode 100644 index 0000000..e58388a --- /dev/null +++ b/ui/wpf/UIcore/Toolkit.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; + +namespace UI +{ + public class EventCallback + { + public IntPtr Object; + public Action Action; + + public EventCallback(IntPtr uiobj, Action action) + { + Object = uiobj; + Action = action; + } + + public void Callback(object sender, RoutedEventArgs a) + { + Action.Invoke(Object); + } + } +} diff --git a/ui/wpf/UIcore/UIcore.csproj b/ui/wpf/UIcore/UIcore.csproj new file mode 100644 index 0000000..296e238 --- /dev/null +++ b/ui/wpf/UIcore/UIcore.csproj @@ -0,0 +1,68 @@ + + + + + Debug + AnyCPU + {8573F7D8-F05F-4195-9005-1C219B976146} + Library + Properties + UIcore + UIcore + v4.5 + 512 + + + true + full + true + ..\..\..\build\UIcore\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + ..\..\..\build\UIcore\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/wpf/UIcore/Window.cs b/ui/wpf/UIcore/Window.cs new file mode 100644 index 0000000..fedcca1 --- /dev/null +++ b/ui/wpf/UIcore/Window.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; + +namespace UI +{ + public class MainWindow : Window, Container + { + public Layout Layout + { + get + { + return Container.Layout; + } + set + { + Container.Layout = value; + } + } + + public IntPtr Object; + public Container Container; + + public MainWindow(String title, IntPtr uiobj) + { + Title = title; + Object = uiobj; + Width = 300; + Height = 300; + + Grid windowGrid = new Grid(); + ColumnDefinition column = new ColumnDefinition(); + column.Width = new GridLength(1, GridUnitType.Star); + windowGrid.ColumnDefinitions.Add(column); + this.AddChild(windowGrid); + int rowIndex = 0; + + // menu + Application app = Application.GetInstance(); + System.Windows.Controls.Menu menu = null; + if (!app.Menu.IsEmpty()) + { + menu = app.Menu.CreateMenu(uiobj); + + RowDefinition menuRow = new RowDefinition(); + menuRow.Height = GridLength.Auto; + windowGrid.RowDefinitions.Add(menuRow); + + Grid.SetRow(menu, rowIndex); + Grid.SetColumn(menu, 0); + windowGrid.Children.Add(menu); + rowIndex++; + } + + // toolbar + if(app.ToolBar.HasItems()) + { + System.Windows.Controls.ToolBarTray tray = app.ToolBar.CreateToolBarTray(uiobj); + RowDefinition menuRow = new RowDefinition(); + menuRow.Height = GridLength.Auto; + windowGrid.RowDefinitions.Add(menuRow); + + Grid.SetRow(tray, rowIndex); + Grid.SetColumn(tray, 0); + windowGrid.Children.Add(tray); + rowIndex++; + + if(menu != null) + { + menu.Background = tray.Background; + } + } + + // content + RowDefinition contentRow = new RowDefinition(); + contentRow.Height = new GridLength(1, GridUnitType.Star); + windowGrid.RowDefinitions.Add(contentRow); + BoxContainer vbox = new BoxContainer(BoxOrientation.VERTICAL, 0, 0); + Grid.SetColumn(vbox, 0); + Grid.SetRow(vbox, rowIndex); + windowGrid.Children.Add(vbox); + rowIndex++; + + Container = vbox; + + Closed += CloseEvent; + } + + public void ShowWindow() + { + this.Show(); + Application.GetInstance().AddWindow(this); + } + + public void CloseEvent(object sender, System.EventArgs e) + { + Application.GetInstance().RemoveWindow(this); + } + + public void Add(UIElement control, bool fill) + { + Container.Add(control, fill); + } + } +} diff --git a/ui/wpf/UIwrapper/UIwrapper.sln b/ui/wpf/UIwrapper/UIwrapper.sln new file mode 100644 index 0000000..b2bfaba --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UIwrapper", "UIwrapper\UIwrapper.vcxproj", "{367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5}" + ProjectSection(ProjectDependencies) = postProject + {8573F7D8-F05F-4195-9005-1C219B976146} = {8573F7D8-F05F-4195-9005-1C219B976146} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UIcore", "..\UIcore\UIcore.csproj", "{8573F7D8-F05F-4195-9005-1C219B976146}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5}.Debug|Any CPU.ActiveCfg = Debug|x64 + {367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5}.Debug|Any CPU.Build.0 = Debug|x64 + {367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5}.Debug|x64.ActiveCfg = Debug|x64 + {367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5}.Debug|x64.Build.0 = Debug|x64 + {367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5}.Release|Any CPU.ActiveCfg = Release|Win32 + {367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5}.Release|x64.ActiveCfg = Release|x64 + {367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5}.Release|x64.Build.0 = Release|x64 + {8573F7D8-F05F-4195-9005-1C219B976146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8573F7D8-F05F-4195-9005-1C219B976146}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8573F7D8-F05F-4195-9005-1C219B976146}.Debug|x64.ActiveCfg = Debug|Any CPU + {8573F7D8-F05F-4195-9005-1C219B976146}.Debug|x64.Build.0 = Debug|Any CPU + {8573F7D8-F05F-4195-9005-1C219B976146}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8573F7D8-F05F-4195-9005-1C219B976146}.Release|Any CPU.Build.0 = Release|Any CPU + {8573F7D8-F05F-4195-9005-1C219B976146}.Release|x64.ActiveCfg = Release|Any CPU + {8573F7D8-F05F-4195-9005-1C219B976146}.Release|x64.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ui/wpf/UIwrapper/UIwrapper.v12.suo b/ui/wpf/UIwrapper/UIwrapper.v12.suo new file mode 100644 index 0000000..bf51dce Binary files /dev/null and b/ui/wpf/UIwrapper/UIwrapper.v12.suo differ diff --git a/ui/wpf/UIwrapper/UIwrapper/AssemblyInfo.cpp b/ui/wpf/UIwrapper/UIwrapper/AssemblyInfo.cpp new file mode 100644 index 0000000..f01c134 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/AssemblyInfo.cpp @@ -0,0 +1,38 @@ +#include "stdafx.h" + +using namespace System; +using namespace System::Reflection; +using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; + +// +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +// +[assembly:AssemblyTitleAttribute(L"UIwrapper")]; +[assembly:AssemblyDescriptionAttribute(L"")]; +[assembly:AssemblyConfigurationAttribute(L"")]; +[assembly:AssemblyCompanyAttribute(L"")]; +[assembly:AssemblyProductAttribute(L"UIwrapper")]; +[assembly:AssemblyCopyrightAttribute(L"Copyright (c) 2015")]; +[assembly:AssemblyTrademarkAttribute(L"")]; +[assembly:AssemblyCultureAttribute(L"")]; + +// +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder für die Revisions- und Buildnummer den Standard +// übernehmen, indem Sie "*" eingeben: + +[assembly:AssemblyVersionAttribute("1.0.*")]; + +[assembly:ComVisible(false)]; + +[assembly:CLSCompliantAttribute(true)]; \ No newline at end of file diff --git a/ui/wpf/UIwrapper/UIwrapper/ReadMe.txt b/ui/wpf/UIwrapper/UIwrapper/ReadMe.txt new file mode 100644 index 0000000..04c6621 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/ReadMe.txt @@ -0,0 +1,30 @@ +======================================================================== + DYNAMIC LINK LIBRARY: UIwrapper-Projektübersicht +======================================================================== + +Diese UIwrapper-DLL wurde vom Anwendungs-Assistenten für Sie erstellt. + +Diese Datei bietet eine Übersicht über den Inhalt der einzelnen Dateien, aus +denen Ihre UIwrapper-Anwendung besteht. + +UIwrapper.vcxproj + Dies ist die Hauptprojektdatei für VC++-Projekte, die mit dem Anwendungs-Assistenten generiert werden. Sie enthält Informationen über die Version von Visual C++, mit der die Datei generiert wurde, sowie über die Plattformen, Konfigurationen und Projektfunktionen, die im Anwendungs-Assistenten ausgewählt wurden. + +UIwrapper.vcxproj.filters + Dies ist die Filterdatei für VC++-Projekte, die mithilfe eines Anwendungs-Assistenten erstellt werden. Sie enthält Informationen über die Zuordnung zwischen den Dateien im Projekt und den Filtern. Diese Zuordnung wird in der IDE zur Darstellung der Gruppierung von Dateien mit ähnlichen Erweiterungen unter einem bestimmten Knoten verwendet (z. B. sind CPP-Dateien dem Filter "Quelldateien" zugeordnet). + +UIwrapper.cpp + Dies ist die Hauptquelldatei der DLL. + +UIwrapper.h + Diese Datei enthält eine Klassendeklaration. + +AssemblyInfo.cpp + Enthält benutzerdefinierte Attribute zum Ändern von Assemblymetadaten. + +///////////////////////////////////////////////////////////////////////////// +Weitere Hinweise: + +Der Anwendungs-Assistent weist Sie mit "TODO:" auf Teile des Quellcodes hin, die Sie ergänzen oder anpassen sollten. + +///////////////////////////////////////////////////////////////////////////// diff --git a/ui/wpf/UIwrapper/UIwrapper/Stdafx.cpp b/ui/wpf/UIwrapper/UIwrapper/Stdafx.cpp new file mode 100644 index 0000000..90c52a5 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/Stdafx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : Quelldatei, die nur die Standard-Includes einbindet. +// UIwrapper.pch ist der vorkompilierte Header. +// stdafx.obj enthält die vorkompilierten Typinformationen. + +#include "stdafx.h" diff --git a/ui/wpf/UIwrapper/UIwrapper/Stdafx.h b/ui/wpf/UIwrapper/UIwrapper/Stdafx.h new file mode 100644 index 0000000..415de88 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/Stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : Includedatei für Standardsystem-Includedateien +// oder häufig verwendete projektspezifische Includedateien, +// die nur in unregelmäßigen Abständen geändert werden. + +#pragma once + + diff --git a/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj b/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj new file mode 100644 index 0000000..678b4ec --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {367C474F-D7EA-44E3-9CB7-A4A35DCE9CC5} + v4.5.2 + ManagedCProj + UIwrapper + + + + DynamicLibrary + true + v140 + true + Unicode + + + DynamicLibrary + true + v140 + true + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)..\..\..\build\UIwrapper\ + + + true + $(SolutionDir)..\..\..\build\UIwrapper\ + + + false + + + false + $(SolutionDir)..\..\..\build\UIwrapper\ + $(SolutionDir)..\..\..\build\UIwrapper\$(Configuration)\ + $(LibraryPath) + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + $(SolutionDir)..\..\..\build\UIcore\;%(AdditionalUsingDirectories) + + + true + + C:\Users\Olaf\Projekte\toolkit\build\UIcore\ + + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + Use + $(SolutionDir)..\..\..\build\UIcore\;%(AdditionalUsingDirectories) + + + true + + + + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + + + true + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + Use + $(SolutionDir)..\..\..\build\UIcore\;%(AdditionalUsingDirectories) + None + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj.filters b/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj.filters new file mode 100644 index 0000000..79778ef --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj.filters @@ -0,0 +1,88 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + + + + + + Ressourcendateien + + + + + Ressourcendateien + + + \ No newline at end of file diff --git a/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj.user b/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj.user new file mode 100644 index 0000000..2a22e69 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/UIwrapper.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ui/wpf/UIwrapper/UIwrapper/app.ico b/ui/wpf/UIwrapper/UIwrapper/app.ico new file mode 100644 index 0000000..d06d92b Binary files /dev/null and b/ui/wpf/UIwrapper/UIwrapper/app.ico differ diff --git a/ui/wpf/UIwrapper/UIwrapper/app.rc b/ui/wpf/UIwrapper/UIwrapper/app.rc new file mode 100644 index 0000000..04d5f65 Binary files /dev/null and b/ui/wpf/UIwrapper/UIwrapper/app.rc differ diff --git a/ui/wpf/UIwrapper/UIwrapper/container.cpp b/ui/wpf/UIwrapper/UIwrapper/container.cpp new file mode 100644 index 0000000..a2aa381 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/container.cpp @@ -0,0 +1,78 @@ + + +#include "stdafx.h" +#include + +#include "container.h" + +#using "UIcore.dll" + +UI_EXPORT void* __stdcall UIvbox(gcroot *parent, int margin, int spacing) { + UI::BoxContainer ^vbox = gcnew UI::BoxContainer(*parent, UI::BoxOrientation::VERTICAL, margin, spacing); + gcroot *container = new gcroot(); + *container = vbox; + return container; +} + +UI_EXPORT void* __stdcall UIhbox(gcroot *parent, int margin, int spacing) { + UI::BoxContainer ^hbox = gcnew UI::BoxContainer(*parent, UI::BoxOrientation::HORIZONTAL, margin, spacing); + gcroot *container = new gcroot(); + *container = hbox; + return container; +} + +UI_EXPORT void* __stdcall UIgrid(gcroot *parent, int margin, int columnspacing, int rowspacing) { + UI::GridContainer ^grid = gcnew UI::GridContainer(*parent, margin, columnspacing, rowspacing); + gcroot *container = new gcroot(); + *container = grid; + return container; +} + +UI_EXPORT void* __stdcall UIscrolledwindow(gcroot *parent) { + UI::ScrollViewerContainer ^scrollviewer = gcnew UI::ScrollViewerContainer(*parent); + gcroot *container = new gcroot(); + *container = scrollviewer; + return container; +} + +UI_EXPORT void* __stdcall UItabview(gcroot *parent) { + UI::TabViewContainer ^tabview = gcnew UI::TabViewContainer(*parent); + gcroot *container = new gcroot(); + *container = tabview; + return container; +} + +UI_EXPORT void __stdcall UItab(gcroot *container, char *label) { + UI::Container ^ct = *container; + ct->Layout->Label = gcnew String(label); +} + + + +/* ------------------- layout functions ------------------- */ + +UI_EXPORT void __stdcall UIlayout_fill(gcroot *container, int fill) { + UI::Container ^ct = *container; + ct->Layout->Fill = fill != 0; +} + +UI_EXPORT void __stdcall UIlayout_hexpand(gcroot *container, int expand) { + UI::Container ^ct = *container; + ct->Layout->Hexpand = expand != 0; +} + +UI_EXPORT void __stdcall UIlayout_vexpand(gcroot *container, int expand) { + UI::Container ^ct = *container; + ct->Layout->Vexpand = expand != 0; +} + +UI_EXPORT void __stdcall UIlayout_gridwidth(gcroot *container, int width) { + UI::Container ^ct = *container; + ct->Layout->GridWidth = width; +} + +UI_EXPORT void __stdcall UIlayout_newline(gcroot *container) { + UI::Container ^ct = *container; + ct->Layout->NewLine = true; +} + diff --git a/ui/wpf/UIwrapper/UIwrapper/container.h b/ui/wpf/UIwrapper/UIwrapper/container.h new file mode 100644 index 0000000..93654f4 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/container.h @@ -0,0 +1,5 @@ + + +#pragma once + +#include "toolkit.h" diff --git a/ui/wpf/UIwrapper/UIwrapper/controls.cpp b/ui/wpf/UIwrapper/UIwrapper/controls.cpp new file mode 100644 index 0000000..e2c6331 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/controls.cpp @@ -0,0 +1,110 @@ + + +#include "stdafx.h" +#include + +#include "controls.h" + +#using "UIcore.dll" + +/* ------------------------------ Buttons ------------------------------ */ + +UI_EXPORT void* __stdcall UIbutton(gcroot *container, char *label, UIcallback f, void *eventdata) { + gcroot *button = new gcroot(); + + EventWrapper ^evt = gcnew EventWrapper(f, eventdata); + RoutedEventHandler ^handler = gcnew RoutedEventHandler(evt, &EventWrapper::Callback); + + *button = UI::Controls::Button(*container, gcnew String(label), handler); + return button; +} + + +/* ------------------------------ Labels ------------------------------ */ + +UI_EXPORT void* __stdcall UIlabel(gcroot *container, char *label, int alignment) { + gcroot *control = new gcroot(); + *control = UI::Controls::Label(*container, gcnew String(label), alignment); + return control; +} + +UI_EXPORT void* __stdcall UIspace(gcroot *container) { + gcroot *control = new gcroot(); + *control = UI::Controls::Space(*container); + return control; +} + +UI_EXPORT void* __stdcall UIseparator(gcroot *container) { + gcroot *control = new gcroot(); + *control = UI::Controls::Separator(*container); + return control; +} + + + +/* ------------------------------ Textarea ------------------------------ */ + +UI_EXPORT void* __stdcall UItextarea(gcroot *container, char *text) { + String ^str = nullptr; + if (text) { + str = gcnew String(text); + } + + gcroot *textarea = new gcroot(); + *textarea = gcnew UI::TextArea(*container, str, true); + + return textarea; +} + +UI_EXPORT void __stdcall UItextarea_set(gcroot *textarea, char *str) { + (*textarea)->SetText(gcnew String(str)); +} + +UI_EXPORT char* __stdcall UItextarea_get(gcroot *textarea) { + String ^str = (*textarea)->GetText(); + return (char*)(void*)Marshal::StringToHGlobalAnsi(str); +} + +UI_EXPORT char* __stdcall UItextarea_getsubstr(gcroot *textarea, int begin, int end) { + String ^str = (*textarea)->GetSubString(begin, end); + return (char*)(void*)Marshal::StringToHGlobalAnsi(str); +} + +UI_EXPORT void __stdcall UItextarea_insert(gcroot *textarea, int position, char *str) { + // TODO +} + +UI_EXPORT int __stdcall UItextarea_position(gcroot *textarea) { + return (*textarea)->Position(); +} + +UI_EXPORT void __stdcall UItextarea_selection(gcroot *textarea, int *begin, int *end) { + // TODO +} + +UI_EXPORT int __stdcall UItextarea_length(gcroot *textarea) { + return (*textarea)->Length(); +} + +UI_EXPORT void __stdcall UItextarea_remove(gcroot *textarea, int begin, int end) { + // TODO +} + +UI_EXPORT void __stdcall UIfreestr(char *str) { + Marshal::FreeHGlobal((IntPtr)(void*)str); +} + + +/* ------------------------------ Textfield ------------------------------ */ + +UI_EXPORT void* __stdcall UItextfield(gcroot *container, char *text) { + String ^str = nullptr; + if (text) { + str = gcnew String(text); + } + + gcroot *textfield = new gcroot(); + *textfield = gcnew UI::TextArea(*container, str, false); + + return textfield; +} \ No newline at end of file diff --git a/ui/wpf/UIwrapper/UIwrapper/controls.h b/ui/wpf/UIwrapper/UIwrapper/controls.h new file mode 100644 index 0000000..f5c2060 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/controls.h @@ -0,0 +1,6 @@ + + +#pragma once + +#include "toolkit.h" + diff --git a/ui/wpf/UIwrapper/UIwrapper/graphics.cpp b/ui/wpf/UIwrapper/UIwrapper/graphics.cpp new file mode 100644 index 0000000..62744cf --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/graphics.cpp @@ -0,0 +1,63 @@ +#include "stdafx.h" +#include + +#include "graphics.h" + +#using "UIcore.dll" + + +DrawEventWrapper::DrawEventWrapper(void *gc, UIdrawfunc callback, void *eventdata) { + this->callback = callback; + this->eventdata = eventdata; + this->gc = gc; + action = gcnew Action(this, &DrawEventWrapper::Callback); +} + + +void DrawEventWrapper::Callback(int width, int height) +{ + if (callback) + { + UI::DrawingArea ^d = (UI::DrawingArea^)PtrToObject(gc); + callback(gc, eventdata, width, height); + } +} + + +UI_EXPORT void* __stdcall UIdrawingarea(gcroot *container, UIdrawfunc f, void *data) +{ + gcroot *canvas = new gcroot(); + *canvas = gcnew UI::DrawingArea(*container); + + DrawEventWrapper ^ev = gcnew DrawEventWrapper(ObjectToPtr(*canvas), f, data); + (*canvas)->resizeCallback = ev->action; + + return canvas; +} + + +UI_EXPORT void __stdcall UIdrawingarea_redraw(gcroot *drawingarea) +{ + (*drawingarea)->Redraw(); +} + + +/* ------------------------- drawing functions ------------------------- */ + +UI_EXPORT void __stdcall UIgraphics_color(void *g, int red, int green, int blue) +{ + UI::DrawingArea ^d = (UI::DrawingArea^)PtrToObject(g); + d->SetColor(red, green, blue); +} + +UI_EXPORT void __stdcall UIdraw_line(void *g, int x1, int y1, int x2, int y2) +{ + UI::DrawingArea ^d = (UI::DrawingArea^)PtrToObject(g); + d->DrawLine(x1, y1, x2, y2); +} + +UI_EXPORT void __stdcall UIdraw_rect(void *g, int x, int y, int w, int h, int fill) +{ + UI::DrawingArea ^d = (UI::DrawingArea^)PtrToObject(g); + d->DrawRect(x, y, w, h, fill ? true : false); +} diff --git a/ui/wpf/UIwrapper/UIwrapper/graphics.h b/ui/wpf/UIwrapper/UIwrapper/graphics.h new file mode 100644 index 0000000..d969501 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/graphics.h @@ -0,0 +1,17 @@ +#pragma once + +#include "toolkit.h" + +typedef void(*UIdrawfunc)(void *gc, void *event, int width, int height); + +public ref class DrawEventWrapper { +public: + UIdrawfunc callback = NULL; + void *eventdata = NULL; + void *gc; + Action ^action; + + DrawEventWrapper(void *gc, UIdrawfunc callback, void *eventdata); + + void Callback(int width, int height); +}; diff --git a/ui/wpf/UIwrapper/UIwrapper/menu.cpp b/ui/wpf/UIwrapper/UIwrapper/menu.cpp new file mode 100644 index 0000000..7f888e3 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/menu.cpp @@ -0,0 +1,26 @@ + +#include "stdafx.h" +#include + +#include "menu.h" + +#using "UIcore.dll" + +UI_EXPORT void __stdcall UImenu(char *label) { + UI::Application::GetInstance()->Menu->AddMenu(gcnew String(label)); +} + +UI_EXPORT void __stdcall UIsubmenu(char *label) { + UI::Application::GetInstance()->Menu->AddSubMenu(gcnew String(label)); +} + +UI_EXPORT void __stdcall UIsubmenu_end() { + UI::Application::GetInstance()->Menu->EndSubMenu(); +} + + +UI_EXPORT void __stdcall UImenuitem(char *label, UIcallback f, void *eventdata) { + ObjEventWrapper ^e = gcnew ObjEventWrapper(f, eventdata); + UI::Application::GetInstance()->Menu->AddMenuItem(gcnew String(label), e->GetAction()); +} + diff --git a/ui/wpf/UIwrapper/UIwrapper/menu.h b/ui/wpf/UIwrapper/UIwrapper/menu.h new file mode 100644 index 0000000..9f37764 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/menu.h @@ -0,0 +1,4 @@ + +#pragma once + +#include "toolkit.h" \ No newline at end of file diff --git a/ui/wpf/UIwrapper/UIwrapper/resource.h b/ui/wpf/UIwrapper/UIwrapper/resource.h new file mode 100644 index 0000000..1f2251c --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/resource.h @@ -0,0 +1,3 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by app.rc diff --git a/ui/wpf/UIwrapper/UIwrapper/toolbar.cpp b/ui/wpf/UIwrapper/UIwrapper/toolbar.cpp new file mode 100644 index 0000000..4874f5d --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/toolbar.cpp @@ -0,0 +1,49 @@ +/* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +* +* Copyright 2015 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 "stdafx.h" +#include + +#include "toolbar.h" + +#using "UIcore.dll" + +UI_EXPORT void __stdcall UItoolitem(char *name, char *label, UIcallback f, void *eventdata) { + ObjEventWrapper ^e = gcnew ObjEventWrapper(f, eventdata); + UI::Application::GetInstance()->ToolBar->AddToolItem(gcnew String(name), gcnew String(label), e->GetAction()); +} + + + + + +UI_EXPORT void __stdcall UItoolbar_add_default(char *name) { + UI::Application::GetInstance()->ToolBar->AddDefault(gcnew String(name)); +} + diff --git a/ui/wpf/UIwrapper/UIwrapper/toolbar.h b/ui/wpf/UIwrapper/UIwrapper/toolbar.h new file mode 100644 index 0000000..849b70a --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/toolbar.h @@ -0,0 +1,32 @@ +/* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +* +* Copyright 2015 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. +*/ + + +#pragma once + +#include "toolkit.h" diff --git a/ui/wpf/UIwrapper/UIwrapper/toolkit.cpp b/ui/wpf/UIwrapper/UIwrapper/toolkit.cpp new file mode 100644 index 0000000..54ec131 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/toolkit.cpp @@ -0,0 +1,127 @@ +// Dies ist die Haupt-DLL. + +#include "stdafx.h" +#include + +#include "toolkit.h" + +#using "UIcore.dll" + +static UIcallback startup_func; +void *startup_data; +static UIcallback open_func; +void *open_data; +static UIcallback exit_func; +void *exit_data; + +public ref class AppCallbacks : public UI::IApplicationCallbacks { +public: + UIcallback startupFunc = NULL; + void *startupData = NULL; + UIcallback openFunc = NULL; + void *openData = NULL; + UIcallback exitFunc = NULL; + void *exitData = NULL; + + virtual void __clrcall OnStartup() { + if (startupFunc) { + startupFunc(NULL, startupData); + } + } + virtual void __clrcall OnOpen() { + if (openFunc) { + openFunc(NULL, openData); + } + } + virtual void __clrcall OnExit() { + if (exitFunc) { + exitFunc(NULL, exitData); + } + } +}; + + +void* ObjectToPtr(Object ^obj) { + GCHandle handle = GCHandle::Alloc(obj); + IntPtr pointer = GCHandle::ToIntPtr(handle); + return pointer.ToPointer(); +} + +Object^ PtrToObject(void *ptr) { + GCHandle h = GCHandle::FromIntPtr(IntPtr(ptr)); + Object^ object = h.Target; + //h.Free(); + return object; +} + +// EventWrapper + +ObjEventWrapper::ObjEventWrapper(UIcallback callback, void *eventdata) { + this->callback = callback; + this->eventdata = eventdata; + action = gcnew Action(this, &ObjEventWrapper::Callback); +} + +Action^ ObjEventWrapper::GetAction() { + return action; +} + +void ObjEventWrapper::Callback(IntPtr uiobj) { + if (callback) { + callback(uiobj.ToPointer(), eventdata); + } +} + + +EventWrapper::EventWrapper(UIcallback callback, void *eventdata) { + this->callback = callback; + this->eventdata = eventdata; +} + +void EventWrapper::Callback(Object ^sender, RoutedEventArgs ^e) { + if (callback) { + callback(NULL, eventdata); + } +} + + + +UI_EXPORT void __stdcall UIinit(char *appname) { + UI::Application ^app = UI::Application::GetInstance(); + app->Name = gcnew String(appname); +} + +UI_EXPORT void __stdcall UIonstartup(UIcallback f, void *userdata) { + startup_func = f; + startup_data = userdata; +} + +UI_EXPORT void __stdcall UIonopen(UIcallback f, void *userdata) { + open_func = f; + open_data = userdata; +} + +UI_EXPORT void __stdcall UIonexit(UIcallback f, void *userdata) { + exit_func = f; + exit_data = userdata; +} + +UI_EXPORT void __stdcall UImain() { + AppCallbacks ^ac = gcnew AppCallbacks(); + ac->startupFunc = startup_func; + ac->startupData = startup_data; + ac->openFunc = open_func; + ac->openData = open_data; + ac->exitFunc = exit_func; + ac->exitData = exit_data; + + UI::Application ^app = UI::Application::GetInstance(); + app->callbacks = ac; + + Thread ^thread = app->Start(); + thread->Join(); +} + +UI_EXPORT void __stdcall UIshow(gcroot *window) { + (*window)->ShowWindow(); +} diff --git a/ui/wpf/UIwrapper/UIwrapper/toolkit.h b/ui/wpf/UIwrapper/UIwrapper/toolkit.h new file mode 100644 index 0000000..def17df --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/toolkit.h @@ -0,0 +1,42 @@ +// UIwrapper.h + +#pragma once + +#include + +using namespace System; +using namespace System::Runtime::InteropServices; +using namespace System::Threading; +using namespace System::Windows; +using namespace System::Windows::Controls; + +#define UI_EXPORT extern "C" __declspec(dllexport) + +extern "C" typedef void(*UIcallback)(void*, void*); + +void* ObjectToPtr(Object ^obj); +Object^ PtrToObject(void *ptr); + +public ref class ObjEventWrapper { + UIcallback callback = NULL; + void *eventdata = NULL; + Action ^action; + +public: + ObjEventWrapper(UIcallback callback, void *eventdata); + + Action^ GetAction(); + + void Callback(IntPtr uiobj); +}; + +public ref class EventWrapper { + UIcallback callback = NULL; + void *eventdata = NULL; + + +public: + EventWrapper(UIcallback callback, void *eventdata); + void Callback(Object ^sender, RoutedEventArgs ^e); +}; + diff --git a/ui/wpf/UIwrapper/UIwrapper/window.cpp b/ui/wpf/UIwrapper/UIwrapper/window.cpp new file mode 100644 index 0000000..c8281b0 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/window.cpp @@ -0,0 +1,17 @@ + + +#include "stdafx.h" +#include + +#include "window.h" + +#using "UIcore.dll" + +UI_EXPORT void* __stdcall UIwindow(char *title, void *uiobj) { + UI::MainWindow ^window = gcnew UI::MainWindow(gcnew String(title), IntPtr(uiobj)); + gcroot *ptr = new gcroot(); + *ptr = window; + return ptr; +} + + diff --git a/ui/wpf/UIwrapper/UIwrapper/window.h b/ui/wpf/UIwrapper/UIwrapper/window.h new file mode 100644 index 0000000..f5c2060 --- /dev/null +++ b/ui/wpf/UIwrapper/UIwrapper/window.h @@ -0,0 +1,6 @@ + + +#pragma once + +#include "toolkit.h" + diff --git a/ui/wpf/button.c b/ui/wpf/button.c new file mode 100644 index 0000000..c6165c0 --- /dev/null +++ b/ui/wpf/button.c @@ -0,0 +1,58 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 +#include + +#include "button.h" +#include "../common/object.h" + +UIWIDGET ui_button(UiObject *obj, char *label, ui_callback f, void *data) { + UiEventData *event = NULL; + ui_callback callback = NULL; + if(f) { + event = malloc(sizeof(UiEventData)); + event->obj = obj; + event->callback = f; + event->user_data = data; + event->value = 0; + callback = (ui_callback)ui_button_callback; + } + + UiContainer *container = uic_get_current_container(obj); + return UIbutton(container, label, callback, event); +} + +void ui_button_callback(UiObject *obj, UiEventData *e) { + UiEvent event; + event.obj = e->obj; + event.document = event.obj->ctx->document; + event.window = event.obj->window; + event.intval = 0; + e->callback(&event, e->user_data); +} diff --git a/ui/wpf/button.h b/ui/wpf/button.h new file mode 100644 index 0000000..98641a0 --- /dev/null +++ b/ui/wpf/button.h @@ -0,0 +1,48 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 BUTTON_H +#define BUTTON_H + +#include "../ui/button.h" +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UI_IMPORT UIWIDGET __stdcall UIbutton(void *container, char *label, ui_callback f, void *event); + +void ui_button_callback(UiObject *obj, UiEventData *e); + +#ifdef __cplusplus +} +#endif + +#endif /* BUTTON_H */ + diff --git a/ui/wpf/container.c b/ui/wpf/container.c new file mode 100644 index 0000000..3b3ef93 --- /dev/null +++ b/ui/wpf/container.c @@ -0,0 +1,147 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 +#include + +#include "container.h" +#include "../common/object.h" + +UIWIDGET ui_vbox(UiObject *obj) { + return ui_vbox_sp(obj, 0, 0); +} + +UIWIDGET ui_hbox(UiObject *obj) { + return ui_hbox_sp(obj, 0, 0); +} + +UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) { + UiContainer *ct = uic_get_current_container(obj); + + UIWIDGET vbox = UIvbox(ct, margin, spacing); + + UiObject *newobj = uic_object_new(obj, vbox); + newobj->container = (UiContainer*)vbox; + uic_obj_add(obj, newobj); + + return vbox; +} + +UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) { + UiContainer *ct = uic_get_current_container(obj); + + UIWIDGET hbox = UIhbox(ct, margin, spacing); + + UiObject *newobj = uic_object_new(obj, hbox); + newobj->container = (UiContainer*)hbox; + uic_obj_add(obj, newobj); + + return hbox; +} + +UIWIDGET ui_grid(UiObject *obj) { + return ui_grid_sp(obj, 0, 0, 0); +} + +UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) { + UiContainer *ct = uic_get_current_container(obj); + + UIWIDGET grid = UIgrid(ct, margin, columnspacing, rowspacing); + + UiObject *newobj = uic_object_new(obj, grid); + newobj->container = (UiContainer*)grid; + uic_obj_add(obj, newobj); + + return grid; +} + +UIWIDGET ui_scrolledwindow(UiObject *obj) { + UiContainer *ct = uic_get_current_container(obj); + + UIWIDGET scrolledwindow = UIscrolledwindow(ct); + + UiObject *newobj = uic_object_new(obj, scrolledwindow); + newobj->container = (UiContainer*)scrolledwindow; + uic_obj_add(obj, newobj); + + return scrolledwindow; +} + +/* + * TODO: sidebar + */ + +UIWIDGET ui_tabview(UiObject *obj) { + UiContainer *ct = uic_get_current_container(obj); + + UIWIDGET tabview = UItabview(ct); + + UiObject *newobj = uic_object_new(obj, tabview); + newobj->container = (UiContainer*)tabview; + uic_obj_add(obj, newobj); + + return tabview; +} + +void ui_tab(UiObject *obj, char *title) { + UiContainer *ct = uic_get_current_container(obj); + UItab(ct, title); +} + + +/* + * -------------------- Layout Functions -------------------- + * + * functions for setting layout attributes for the current container + * + */ + +void ui_layout_fill(UiObject *obj, UiBool fill) { + UiContainer *ct = uic_get_current_container(obj); + UIlayout_fill(ct, fill); +} + +void ui_layout_hexpand(UiObject *obj, UiBool expand) { + UiContainer *ct = uic_get_current_container(obj); + UIlayout_hexpand(ct, expand); +} + +void ui_layout_vexpand(UiObject *obj, UiBool expand) { + UiContainer *ct = uic_get_current_container(obj); + UIlayout_vexpand(ct, expand); +} + +void ui_layout_gridwidth(UiObject *obj, int width) { + UiContainer *ct = uic_get_current_container(obj); + UIlayout_gridwidth(ct, width); +} + +void ui_newline(UiObject *obj) { + UiContainer *ct = uic_get_current_container(obj); + UIlayout_newline(ct); +} \ No newline at end of file diff --git a/ui/wpf/container.h b/ui/wpf/container.h new file mode 100644 index 0000000..aa799c0 --- /dev/null +++ b/ui/wpf/container.h @@ -0,0 +1,59 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 CONTAINER_H +#define CONTAINER_H + +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UI_IMPORT void* __stdcall UIvbox(UiContainer *parent, int margin, int spacing); +UI_IMPORT void* __stdcall UIhbox(UiContainer *parent, int margin, int spacing); +UI_IMPORT void* __stdcall UIgrid(UiContainer *parent, int margin, int columnspacing, int rowspacing); + +UI_IMPORT void* __stdcall UIscrolledwindow(UiContainer *parent); + +UI_IMPORT void* __stdcall UItabview(UiContainer *parent); +UI_IMPORT void __stdcall UItab(UiContainer *container, char *label); + +UI_IMPORT void __stdcall UIlayout_fill(UiContainer *container, int fill); +UI_IMPORT void __stdcall UIlayout_hexpand(UiContainer *container, int expand); +UI_IMPORT void __stdcall UIlayout_vexpand(UiContainer *container, int expand); +UI_IMPORT void __stdcall UIlayout_gridwidth(UiContainer *container, int width); + +UI_IMPORT void __stdcall UIlayout_newline(UiContainer *container); + +#ifdef __cplusplus +} +#endif + +#endif /* CONTAINER_H */ + diff --git a/ui/wpf/graphics.c b/ui/wpf/graphics.c new file mode 100644 index 0000000..73417ac --- /dev/null +++ b/ui/wpf/graphics.c @@ -0,0 +1,74 @@ +#include +#include + +#include "graphics.h" +#include "container.h" +#include "../../ucx/mempool.h" +#include "../common/context.h" +#include "../common/object.h" + +UIWIDGET ui_drawingarea(UiObject *obj, ui_drawfunc f, void *userdata) { + UiDrawEvent *eventdata = NULL; + ui_draw_callback cb = NULL; + if(f) { + eventdata = malloc(sizeof(UiDrawEvent)); + eventdata->obj = obj; + eventdata->draw = f; + eventdata->userdata = userdata; + cb = ui_draw_event; + } + + UiContainer *container = uic_get_current_container(obj); + return UIdrawingarea(container, cb, eventdata); +} + +void ui_draw_event(void *gc, UiDrawEvent *event, int width, int height) { + UiEvent e; + e.obj = event->obj; + e.window = e.obj->window; + e.document = e.obj->ctx->document; + e.eventdata = NULL; + e.intval = 0; + + UiWPFGraphics g; + g.g.width = width; + g.g.height = height; + g.gc = gc; + + event->draw(&e, &g.g, event->userdata); +} + + +void ui_drawingarea_mousehandler(UiObject *obj, UIWIDGET widget, ui_callback f, void *u) { + +} + +void ui_drawingarea_getsize(UIWIDGET drawingarea, int *width, int *height) { + +} + +void ui_drawingarea_redraw(UIWIDGET drawingarea) { + UIdrawingarea_redraw(drawingarea); +} + + +/* ------------------------- drawing functions ------------------------- */ + +void ui_graphics_color(UiGraphics *g, int red, int green, int blue) { + UiWPFGraphics *wg = (UiWPFGraphics*)g; + UIgraphics_color(wg->gc, red, green, blue); +} + +void ui_draw_line(UiGraphics *g, int x1, int y1, int x2, int y2) { + UiWPFGraphics *wg = (UiWPFGraphics*)g; + UIdraw_line(wg->gc, x1, y1, x2, y2); +} + +void ui_draw_rect(UiGraphics *g, int x, int y, int w, int h, int fill) { + UiWPFGraphics *wg = (UiWPFGraphics*)g; + UIdraw_rect(wg->gc, x, y, w, h, fill); +} + +void ui_draw_text(UiGraphics *g, int x, int y, UiTextLayout *text) { + +} diff --git a/ui/wpf/graphics.h b/ui/wpf/graphics.h new file mode 100644 index 0000000..f71f931 --- /dev/null +++ b/ui/wpf/graphics.h @@ -0,0 +1,56 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +/* + * File: graphics.h + * Author: Olaf + * + * Created on 22. Januar 2017, 18:34 + */ + +#ifndef GRAPHICS_H +#define GRAPHICS_H + +#include "toolkit.h" +#include "../ui/graphics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UiDrawEvent { + UiObject *obj; + ui_drawfunc draw; + void *userdata; +} UiDrawEvent; + +typedef struct UiWPFGraphics { + UiGraphics g; + void *gc; +} UiWPFGraphics; + +typedef void(*ui_draw_callback)(void *gc, UiDrawEvent *event, int width, int height); + +UI_IMPORT UIWIDGET __stdcall UIdrawingarea(void *container, ui_draw_callback f, void *userdata); + +UI_IMPORT void __stdcall UIdrawingarea_redraw(UIWIDGET drawingarea); + +void ui_draw_event(void *gc, UiDrawEvent *event, int width, int height); + +// drawing functions + +UI_IMPORT void __stdcall UIgraphics_color(UiGraphics *g, int red, int green, int blue); +UI_IMPORT void __stdcall UIdraw_line(UiGraphics *g, int x1, int y1, int x2, int y2); +UI_IMPORT void __stdcall UIdraw_rect(UiGraphics *g, int x, int y, int w, int h, int fill); +//void UIdraw_text(UiGraphics *g, int x, int y, UiTextLayout *text); + + +#ifdef __cplusplus +} +#endif + +#endif /* GRAPHICS_H */ + diff --git a/ui/wpf/label.c b/ui/wpf/label.c new file mode 100644 index 0000000..a60a0c5 --- /dev/null +++ b/ui/wpf/label.c @@ -0,0 +1,28 @@ +#include +#include + +#include "label.h" +#include "container.h" +#include "../../ucx/mempool.h" +#include "../common/context.h" +#include "../common/object.h" + +UIWIDGET ui_label(UiObject *obj, char *label) { + return UIlabel(uic_get_current_container(obj), label, 2); +} + +UIWIDGET ui_llabel(UiObject *obj, char *label) { + return UIlabel(uic_get_current_container(obj), label, 0); +} + +UIWIDGET ui_rlabel(UiObject *obj, char *label) { + return UIlabel(uic_get_current_container(obj), label, 1); +} + +UIWIDGET ui_space(UiObject *obj) { + return UIspace(uic_get_current_container(obj)); +} + +UIWIDGET ui_separator(UiObject *obj) { + return UIseparator(uic_get_current_container(obj)); +} diff --git a/ui/wpf/label.h b/ui/wpf/label.h new file mode 100644 index 0000000..2e41f6a --- /dev/null +++ b/ui/wpf/label.h @@ -0,0 +1,28 @@ +/* + * File: label.h + * Author: Olaf + * + * Created on 19. Januar 2016, 18:12 + */ + +#ifndef LABEL_H +#define LABEL_H + +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UI_IMPORT UIWIDGET __stdcall UIlabel(void *container, char *label, int alignment); + +UI_IMPORT UIWIDGET __stdcall UIspace(void *container); + +UI_IMPORT UIWIDGET __stdcall UIseparator(void *container); + +#ifdef __cplusplus +} +#endif + +#endif /* LABEL_H */ + diff --git a/ui/wpf/menu.c b/ui/wpf/menu.c new file mode 100644 index 0000000..32fbffb --- /dev/null +++ b/ui/wpf/menu.c @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#include +#include +#include + +#include "menu.h" + +void ui_menu(char *label) { + UImenu(label); +} + +void ui_submenu(char *label) { + UIsubmenu(label); +} + +void ui_submenu_end() { + UIsubmenu_end(); +} + +void ui_menuitem(char *label, ui_callback f, void *userdata) { + UIcallback cb = NULL; + void *e = NULL; + if (f) { + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = NULL; + event->user_data = userdata; + event->callback = f; + event->value = 0; + cb = (UIcallback)ui_obj_callback; + e = event; + } + + UImenuitem(label, cb, e); +} + + +void ui_obj_callback(UiObject *obj, UiEventData *e) { + UiEvent event; + event.obj = obj; + event.window = obj->window; + event.intval = 0; + event.eventdata = NULL; + event.document = obj->ctx->document; + e->callback(&event, e->user_data); +} diff --git a/ui/wpf/menu.h b/ui/wpf/menu.h new file mode 100644 index 0000000..1d34ae0 --- /dev/null +++ b/ui/wpf/menu.h @@ -0,0 +1,32 @@ +/* + * File: menu.h + * Author: Olaf + * + * Created on 25. Januar 2015, 13:37 + */ + +#ifndef MENU_H +#define MENU_H + +#include "../ui/menu.h" +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UI_IMPORT void __stdcall UImenu(char *label); +UI_IMPORT void __stdcall UIsubmenu(char *label); +UI_IMPORT void __stdcall UIsubmenu_end(); +UI_IMPORT void __stdcall UImenuitem(char *label, UIcallback f, void *udata); + + + +void ui_obj_callback(UiObject *obj, UiEventData *e); + +#ifdef __cplusplus +} +#endif + +#endif /* MENU_H */ + diff --git a/ui/wpf/objs.mk b/ui/wpf/objs.mk new file mode 100644 index 0000000..85cc43b --- /dev/null +++ b/ui/wpf/objs.mk @@ -0,0 +1,43 @@ +# +# 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. +# + +WPF_SRC_DIR = ui/wpf/ +WPF_OBJPRE = $(OBJ_DIR)$(WPF_SRC_DIR) + +WPFOBJ = toolkit.o +WPFOBJ += window.o +WPFOBJ += container.o +WPFOBJ += menu.o +WPFOBJ += toolbar.o +WPFOBJ += button.o +WPFOBJ += label.o +WPFOBJ += text.o +WPFOBJ += graphics.o + +TOOLKITOBJS += $(WPFOBJ:%=$(WPF_OBJPRE)%) +TOOLKITSOURCE += $(WPFOBJ:%.o=wpf/%.c) diff --git a/ui/wpf/text.c b/ui/wpf/text.c new file mode 100644 index 0000000..7dbb8cc --- /dev/null +++ b/ui/wpf/text.c @@ -0,0 +1,140 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 +#include + +#include "text.h" + +UIWIDGET ui_textarea(UiObject *obj, UiText *value) { + UiContainer *container = uic_get_current_container(obj); + UIWIDGET textarea = UItextarea(container, value ? value->value : NULL); + + if(value) { + value->get = ui_textarea_get; + value->set = ui_textarea_set; + value->getsubstr = ui_textarea_getsubstr; + value->insert = ui_textarea_insert; + value->position = ui_textarea_position; + value->selection = ui_textarea_selection; + value->length = ui_textarea_length; + value->remove = ui_textarea_remove; + value->value = NULL; + value->obj = textarea; + if(!value->undomgr) { + //value->undomgr = ; + } + } + + 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 = var->value; + return ui_textarea(obj, value); + } else { + // TODO: error + } + return NULL; +} + +char* ui_textarea_get(UiText *text) { + if(text->value) { + UIfreestr(text->value); + } + text->value = UItextarea_get(text->obj); + return text->value; +} + +void ui_textarea_set(UiText *text, char *str) { + if(text->value) { + UIfreestr(text->value); + text->value = NULL; + } + UItextarea_set(text->obj, str); +} + +char* ui_textarea_getsubstr(UiText *text, int begin, int end) { + if(text->value) { + UIfreestr(text->value); + } + text->value = UItextarea_getsubstr(text->obj, begin, end); + return text->value; +} + +void ui_textarea_insert(UiText *text, int pos, char *str) { + if(text->value) { + UIfreestr(text->value); + text->value = NULL; + } + UItextarea_insert(text->obj, pos, str); +} + +int ui_textarea_position(UiText *text) { + return UItextarea_position(text->obj); +} + +void ui_textarea_selection(UiText *text, int *begin, int *end) { + UItextarea_selection(text->obj, begin, end); +} + +int ui_textarea_length(UiText *text) { + return UItextarea_length(text->obj); +} + +void ui_textarea_remove(UiText *text, int begin, int end) { + if(text->value) { + UIfreestr(text->value); + text->value = NULL; + } + UItextarea_remove(text->obj, begin, end); +} + + +UIWIDGET ui_textfield(UiObject *obj, UiString *value) { + UiContainer *container = uic_get_current_container(obj); + UIWIDGET textfield = UItextfield(container, value ? value->value : NULL); + + if(value) { + // TODO + } + 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 = var->value; + return ui_textfield(obj, value); + } else { + // TODO: error + } + return NULL; +} diff --git a/ui/wpf/text.h b/ui/wpf/text.h new file mode 100644 index 0000000..6b72327 --- /dev/null +++ b/ui/wpf/text.h @@ -0,0 +1,69 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 TEXT_H +#define TEXT_H + +#include "../ui/text.h" +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UI_IMPORT UIWIDGET __stdcall UItextarea(void *container, char *text); + +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); +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); + +UI_IMPORT void __stdcall UItextarea_set(UIWIDGET textarea, char *str); +UI_IMPORT char* __stdcall UItextarea_get(UIWIDGET textarea); +UI_IMPORT char* __stdcall UItextarea_getsubstr(UIWIDGET textarea, int begin, int end); +UI_IMPORT void __stdcall UItextarea_insert(UIWIDGET textarea, int pos, char *str); +UI_IMPORT int __stdcall UItextarea_position(UIWIDGET textarea); +UI_IMPORT void __stdcall UItextarea_selection(UIWIDGET textarea, int *begin, int *end); +UI_IMPORT int __stdcall UItextarea_length(UIWIDGET textarea); +UI_IMPORT void __stdcall UItextarea_remove(UIWIDGET textarea, int begin, int end); + +UI_IMPORT void __stdcall UIfreestr(char *str); + + +UI_IMPORT UIWIDGET __stdcall UItextfield(void *container, char *text); + +#ifdef __cplusplus +} +#endif + +#endif /* TEXT_H */ + diff --git a/ui/wpf/toolbar.c b/ui/wpf/toolbar.c new file mode 100644 index 0000000..d286c75 --- /dev/null +++ b/ui/wpf/toolbar.c @@ -0,0 +1,56 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 +#include + +#include "toolbar.h" +#include "menu.h" +#include "../common/context.h" + +void ui_toolitem(char *name, char *label, ui_callback f, void *udata) { + UIcallback cb = NULL; + void *e = NULL; + if (f) { + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = NULL; + event->user_data = udata; + event->callback = f; + event->value = 0; + cb = (UIcallback)ui_obj_callback; + e = event; + } + + UItoolitem(name, label, cb, e); +} + +void ui_toolbar_add_default(char *name) { + UItoolbar_add_default(name); +} + + diff --git a/ui/wpf/toolbar.h b/ui/wpf/toolbar.h new file mode 100644 index 0000000..b504498 --- /dev/null +++ b/ui/wpf/toolbar.h @@ -0,0 +1,50 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 TOOLBAR_H +#define TOOLBAR_H + +#include "../ui/toolbar.h" +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UI_IMPORT void __stdcall UItoolitem(char *name, char *label, UIcallback callback, void *eventdata); + + +UI_IMPORT void __stdcall UItoolbar_add_default(char *name); + + +#ifdef __cplusplus +} +#endif + +#endif /* TOOLBAR_H */ + diff --git a/ui/wpf/toolkit.c b/ui/wpf/toolkit.c new file mode 100644 index 0000000..35242dc --- /dev/null +++ b/ui/wpf/toolkit.c @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include +#include +#include + +#include "toolkit.h" + + +void ui_init(char *appname, int argc, char **argv) { + UIinit(appname); +} + +void ui_onstartup(ui_callback f, void *userdata) { + UIonstartup(f, userdata); +} + +void ui_onopen(ui_callback f, void *userdata) { + UIonopen(f, userdata); +} + +void ui_onexit(ui_callback f, void *userdata) { + UIonexit(f, userdata); +} + +void ui_main() { + UImain(); +} + +void ui_show(UiObject *obj) { + UIshow(obj->widget); +} + +void ui_set_enabled(UIWIDGET widget, int enabled) { + +} + +void ui_set_show_all(UIWIDGET widget, int value) { + +} \ No newline at end of file diff --git a/ui/wpf/toolkit.h b/ui/wpf/toolkit.h new file mode 100644 index 0000000..7b5f766 --- /dev/null +++ b/ui/wpf/toolkit.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef TOOLKIT_H +#define TOOLKIT_H + +#include +#include "../ui/toolkit.h" +#include "../common/context.h" +#include "../common/object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UI_IMPORT __declspec(dllimport) +__declspec(dllimport) int __stdcall myfunc(char *str); + +typedef struct UiEventData { + UiObject *obj; + ui_callback callback; + void *user_data; + int value; +} UiEventData; + +typedef void(*UIcallback)(void*,void*); + +UI_IMPORT void __stdcall UIinit(char *appname); + +UI_IMPORT void __stdcall UIonstartup(ui_callback f, void *userdata); +UI_IMPORT void __stdcall UIonopen(ui_callback f, void *userdata); +UI_IMPORT void __stdcall UIonexit(ui_callback f, void *userdata); +UI_IMPORT void __stdcall UImain(); +UI_IMPORT void __stdcall UIshow(UIWIDGET widget); + +#ifdef __cplusplus +} +#endif + +#endif /* TOOLKIT_H */ + diff --git a/ui/wpf/window.c b/ui/wpf/window.c new file mode 100644 index 0000000..268c074 --- /dev/null +++ b/ui/wpf/window.c @@ -0,0 +1,49 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 +#include +#include + +#include "../ui/window.h" +#include "../ui/properties.h" +#include "../common/context.h" + +#include "window.h" + +UiObject* ui_window(char *title, void *window_data) { + UcxMempool *mp = ucx_mempool_new(256); + UiObject *obj = ucx_mempool_calloc(mp, 1, sizeof(UiObject)); + obj->widget = UIwindow(title, obj); + obj->ctx = uic_context(obj, mp); + obj->container = (UiContainer*)obj->widget; + //obj->window = window_data; + //obj->next = NULL; + + return obj; +} diff --git a/ui/wpf/window.h b/ui/wpf/window.h new file mode 100644 index 0000000..a0b3ba9 --- /dev/null +++ b/ui/wpf/window.h @@ -0,0 +1,45 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 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 WINDOW_H +#define WINDOW_H + +#include "toolkit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UI_IMPORT UIWIDGET __stdcall UIwindow(char *title, void *uiobj); + +#ifdef __cplusplus +} +#endif + +#endif /* WINDOW_H */ +