all: $(APP_BIN) $(TEST_BIN)
-$(APP_BIN): $(MAIN_OBJ) $(OBJ)
+$(APP_BIN): $(MAIN_OBJ) $(OBJ) $(BUILD_ROOT)/build/lib/libuitk.a
$(LD) -o $(APP_BIN) $(MAIN_OBJ) $(OBJ) -L$(BUILD_ROOT)/build/lib -luitk -lucx -lidav -ldbutils -lmd4c $(LDFLAGS) $(TK_LDFLAGS) $(DAV_LDFLAGS) $(DBU_LDFLAGS)
$(TEST_BIN): $(OBJ) $(TEST_OBJ) $(BUILD_ROOT)/build/lib/libuitk.a
#import "../ui/text.h"
+
+void ui_textarea_save(UiText *text);
+void ui_textarea_destroy(UiText *text);
+void ui_textarea_restore(UiText *text);
+void ui_textarea_set(UiText *text, const char *str);
+char* ui_textarea_get(UiText *text);
+char* ui_textarea_getsubstr(UiText *text, int begin, int end);
+void ui_textarea_insert(UiText *text, int pos, char *str);
+void ui_textarea_setposition(UiText *text, int pos);
+int ui_textarea_position(UiText *text);
+void ui_textarea_setselection(UiText *text, int begin, int end);
+void ui_textarea_selection(UiText *text, int *begin, int *end);
+int ui_textarea_length(UiText *text);
+void ui_textarea_remove(UiText *text, int begin, int end);
+
+char* ui_textfield_get(UiString *s);
+void ui_textfield_set(UiString *s, const char *value);
UiLayout layout = UI_INIT_LAYOUT(args);
ui_container_add(obj, scrollview, &layout, TRUE);
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_TEXT);
+ if(var) {
+ UiText *text = var->value;
+ text->obj = (__bridge void*)textview;
+ ui_textarea_restore(text);
+
+ text->save = ui_textarea_save;
+ text->destroy = ui_textarea_destroy;
+ text->restore = ui_textarea_restore;
+ text->set = ui_textarea_set;
+ text->get = ui_textarea_get;
+ text->getsubstr = ui_textarea_getsubstr;
+ text->insert = ui_textarea_insert;
+ text->setposition = ui_textarea_setposition;
+ text->position = ui_textarea_position;
+ text->setselection = ui_textarea_setselection;
+ text->selection = ui_textarea_selection;
+ text->length = ui_textarea_length;
+ text->remove = ui_textarea_remove;
+ }
+
return (__bridge void*)scrollview;
}
+
+
+
+
+void ui_textarea_save(UiText *text) {
+
+}
+
+void ui_textarea_destroy(UiText *text) {
+ (void)(__bridge_transfer NSTextStorage*)text->data1;
+}
+
+void ui_textarea_restore(UiText *text) {
+ NSTextView *textview = (__bridge NSTextView*)text->obj;
+ NSTextStorage *textStorage;
+ if(text->data1) {
+ textStorage = (__bridge NSTextStorage*)text->data1;
+
+ } else {
+ textStorage = [[NSTextStorage alloc] init];
+ }
+ [textview.layoutManager replaceTextStorage:textStorage];
+ text->data1 = (__bridge_retained void*)textStorage;
+}
+
+void ui_textarea_set(UiText *text, const char *str) {
+
+}
+
+char* ui_textarea_get(UiText *text) {
+ return NULL;
+}
+
+char* ui_textarea_getsubstr(UiText *text, int begin, int end) {
+ return NULL;
+}
+
+void ui_textarea_insert(UiText *text, int pos, char *str) {
+
+}
+
+void ui_textarea_setposition(UiText *text, int pos) {
+
+}
+
+int ui_textarea_position(UiText *text) {
+ return 0;
+}
+
+void ui_textarea_setselection(UiText *text, int begin, int end) {
+
+}
+
+void ui_textarea_selection(UiText *text, int *begin, int *end) {
+
+}
+
+int ui_textarea_length(UiText *text) {
+ return 0;
+}
+
+void ui_textarea_remove(UiText *text, int begin, int end) {
+
+}
+
+
+
+/* -------------------------- TextField -------------------------- */
+
+static UIWIDGET textfield_create(UiObject *obj, UiTextFieldArgs args, BOOL password, BOOL frameless) {
+ NSTextField *textfield;
+ if(password) {
+ textfield = [[NSSecureTextField alloc] init];
+ } else {
+ textfield = [[NSTextField alloc] init];
+ }
+
+ if(frameless) {
+ [textfield setBezeled: NO];
+ }
+
+ UiLayout layout = UI_INIT_LAYOUT(args);
+ ui_container_add(obj, textfield, &layout, FALSE);
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING);
+ if(var) {
+ UiString *s = var->value;
+ if(s->value.ptr) {
+ textfield.stringValue = [[NSString alloc] initWithUTF8String:s->value.ptr];
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ }
+ s->obj = (__bridge void*)textfield;
+ s->get = ui_textfield_get;
+ s->set = ui_textfield_set;
+ }
+
+ return (__bridge void*)textfield;
+}
+
+UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) {
+ return textfield_create(obj, args, FALSE, FALSE);
+}
+
+UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) {
+ return textfield_create(obj, args, FALSE, TRUE);
+}
+
+UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) {
+ return textfield_create(obj, args, TRUE, FALSE);
+}
+
+char* ui_textfield_get(UiString *s) {
+ NSTextField *textfield = (__bridge NSTextField*)s->obj;
+ NSString *str = textfield.stringValue;
+ const char *cstr = str.UTF8String;
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ s->value.ptr = strdup(cstr);
+ s->value.free = free;
+ return s->value.ptr;
+}
+
+void ui_textfield_set(UiString *s, const char *value) {
+ if(s->value.free) {
+ s->value.free(s->value.ptr);
+ }
+ s->value.ptr = NULL;
+ s->value.free = NULL;
+ NSTextField *textfield = (__bridge NSTextField*)s->obj;
+ textfield.stringValue = [[NSString alloc] initWithUTF8String:value];
+}
#include <sys/stat.h>
#include <errno.h>
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
#include "../ui/toolkit.h"
// is ignored
g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview);
}
+ if(args.contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view);
+ ui_widget_set_contextmenu(view, menu);
+ }
// add widget to parent
GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
if(args.onactivate) {
g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
}
+ if(args.contextmenu) {
+ UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view);
+ ui_widget_set_contextmenu(view, menu);
+ }
// add widget to parent
GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
return view;
}
+
+UIWIDGET ui_table_create(UiObject* obj, UiListArgs args) {
+ UiContainerPrivate *ctn = ui_obj_container(obj);
+ UI_APPLY_LAYOUT(ctn->layout, args);
+
+ QTreeView *view = new QTreeView();
+ view->setItemsExpandable(false);
+ view->setRootIsDecorated(false);
+ if(args.multiselection) {
+ view->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ }
+
+ UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.list, args.varname, UI_VAR_LIST);
+
+ TableModel *model = new TableModel(obj, view, var, args.model);
+ view->setModel(model);
+
+ if(var) {
+ UiList *list = (UiList*)var->value;
+ list->update = ui_listmodel_update;
+ list->getselection = ui_listmodel_getselection;
+ list->setselection = ui_listmodel_setselection;
+ list->obj = model;
+ }
+
+ model->setActivationCallback(args.onactivate, args.onactivatedata);
+ model->setSelectionCallback(args.onselection, args.onselectiondata);
+
+ QItemSelectionModel *s = view->selectionModel();
+ QObject::connect(
+ s,
+ SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ model,
+ SLOT(selectionChanged(const QItemSelection &, const QItemSelection &)));
+
+
+ ctn->add(view, false);
+
+ return view;
+}
void *rowData = ls->get(ls, index.row());
if(rowData && getvalue) {
void *value = getvalue(rowData, 0);
- return QString::fromUtf8((char*)value);
+ if(value) {
+ return QString::fromUtf8((char*)value);
+ }
}
}
return QVariant();
+TableModel::TableModel(UiObject *obj, QTreeView *view, UiVar *var, UiModel *model){
+ this->obj = obj;
+ this->view = view;
+ this->var = var;
+ this->model = model;
+ this->onactivate = nullptr;
+ this->onactivatedata = nullptr;
+ this->onselection = nullptr;
+ this->onselectiondata = nullptr;
+}
+
+void TableModel::setActivationCallback(ui_callback f, void *userdata) {
+ onactivate = f;
+ onactivatedata = userdata;
+}
+
+void TableModel::setSelectionCallback(ui_callback f, void *userdata) {
+ onselection = f;
+ onselectiondata = userdata;
+}
+
+void TableModel::update(int row) {
+ if(row >= 0) {
+ this->update(row);
+ } else {
+ this->beginResetModel();
+ this->endResetModel();
+ }
+}
+
+int TableModel::rowCount(const QModelIndex& parent) const {
+ UiList *list = (UiList*)var->value;
+ return ui_list_count(list);
+}
+
+int TableModel::columnCount(const QModelIndex &parent) const {
+ return model->columns;
+}
+
+QVariant TableModel::data(const QModelIndex &index, int role) const {
+ if(role == Qt::DisplayRole) {
+ UiList *ls = (UiList*)var->value;
+ void *rowData = ls->get(ls, index.row());
+ if(rowData && model->getvalue) {
+ int col = index.column();
+ void *value = model->getvalue(rowData, col);
+ if(value) {
+ UiModelType type = model->types[col];
+ switch(type) {
+ case UI_STRING: {
+ return QString::fromUtf8((char*)value);
+ }
+ case UI_STRING_FREE: {
+ QString s = QString::fromUtf8((char*)value);
+ free(value);
+ return s;
+ }
+ case UI_INTEGER: {
+ intptr_t i = (intptr_t)value;
+ return QString::number(i);
+ }
+ case UI_ICON: {
+ break;
+ }
+ case UI_ICON_TEXT: {
+ break;
+ }
+ case UI_ICON_TEXT_FREE: {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return QVariant();
+}
+
+QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const {
+ if(role == Qt::DisplayRole) {
+ char *label = model->titles[section];
+ return QString::fromUtf8(label);
+ }
+ return QVariant();
+}
+
+void TableModel::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
+ UiListSelection sel = ui_selection_model_to_selection(view->selectionModel());
+
+ UiEvent event;
+ event.obj = obj;
+ event.window = obj->window;
+ event.document = obj->ctx->document;
+ event.eventdata = &sel;
+ event.intval = sel.count;
+ event.set = ui_get_setop();
+
+ if(onactivate) {
+ onactivate(&event, onactivatedata);
+ }
+ if(onselection) {
+ onselection(&event, onselectiondata);
+ }
+
+ free(sel.rows);
+}
+
+
UiListSelection ui_selection_model_to_selection(QItemSelectionModel *model) {
UiListSelection sel;
const QItemSelection & deselected);
};
+class TableModel : public QAbstractListModel {
+ Q_OBJECT
+
+ UiModel *model;
+ ui_callback onactivate;
+ void *onactivatedata;
+ ui_callback onselection;
+ void *onselectiondata;
+
+public:
+ UiObject *obj;
+ UiVar *var;
+ QTreeView *view;
+
+ TableModel(UiObject *obj, QTreeView *view, UiVar *var, UiModel *model);
+
+ void setActivationCallback(ui_callback f, void *userdata);
+ void setSelectionCallback(ui_callback f, void *userdata);
+
+ void update(int row);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+public slots:
+ void selectionChanged(
+ const QItemSelection & selected,
+ const QItemSelection & deselected);
+};
+
UiListSelection ui_selection_model_to_selection(QItemSelectionModel *model);
WIN32_SRC_DIR = ui/win32/
WIN32_OBJPRE = $(OBJ_DIR)$(WIN32_SRC_DIR)
-WIN32OBJ = toolkit.obj
+WIN32OBJ = toolkit.obj
+WIN32OBJ += window.obj
TOOLKITOBJS += $(WIN32OBJ:%=$(WIN32_OBJPRE)%)
TOOLKITSOURCE += $(WIN32OBJ:%.obj=win32/%.c)
#include "toolkit.h"
#include "Windows.h"
+#include "window.h"
+
#include "../common/properties.h"
#include <stdio.h>
void ui_init(const char *appname, int argc, char **argv) {
application_name = appname;
+
+ ui_window_init();
}
const char* ui_appname() {
--- /dev/null
+/*
+ * 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"
+#include "Windows.h"
+
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static HINSTANCE hInstance;
+
+static const wchar_t *mainWindowClass = L"UiMainWindow";
+
+LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ switch(uMsg) {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ default:
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+ return 0;
+}
+
+void ui_window_init(void) {
+ hInstance = GetModuleHandle(NULL);
+
+ WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = hInstance;
+ wc.lpszClassName = mainWindowClass;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+
+ if(!RegisterClassEx(&wc)) {
+ MessageBox(NULL, "RegisterClassEx failed", "Error", MB_ICONERROR);
+ exit(-1);
+ }
+}
+
+static UiObject* create_window(const char *title, void *window_data, bool simple) {
+ CxMempool *mp = cxMempoolCreateSimple(256);
+ const CxAllocator *a = mp->allocator;
+ UiObject *obj = cxCalloc(a, 1, sizeof(UiObject));
+ obj->ctx = uic_context(obj, mp);
+ obj->window = window_data;
+
+ HWND hwnd = CreateWindowEx(
+ 0,
+ L"UiMainWindow",
+ "Test",
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ 800,
+ 600,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ UpdateWindow(hwnd);
+
+ return obj;
+}
+
+UiObject *ui_window(const char *title, void *window_data) {
+ return create_window(title, window_data, FALSE);
+}
+
--- /dev/null
+/*
+ * 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 <inttypes.h>
+#include "../ui/window.h"
+#include "../common/context.h"
+#include "../common/object.h"
+
+#include "toolkit.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ui_window_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WINDOW_H */
+