]> uap-core.de Git - note.git/commitdiff
update toolkit
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Thu, 15 May 2025 19:26:28 +0000 (21:26 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Thu, 15 May 2025 19:26:28 +0000 (21:26 +0200)
12 files changed:
application/Makefile
ui/cocoa/text.h
ui/cocoa/text.m
ui/common/properties.c
ui/gtk/list.c
ui/qt/list.cpp
ui/qt/model.cpp
ui/qt/model.h
ui/win32/objs.mk
ui/win32/toolkit.c
ui/win32/window.c [new file with mode: 0644]
ui/win32/window.h [new file with mode: 0644]

index 89823cba5a67ba723bc51d173c919d402669bc63..ec1f0e74d15a0f8aba5b8fc24656b27c5c12af6a 100644 (file)
@@ -56,7 +56,7 @@ TEST_BIN = ../build/bin/notetest$(APP_EXT)
 
 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 
index 9bd685f736961b7843317591576f8c4b8c8533f0..23bc4389d1029e8eb96433ad08ac79c6307fe6eb 100644 (file)
 
 #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);
index 37d04a8c320ec92b937114b3dcdc6d38d9919048..7b9ba6e6d9f808643d922f150f19609b9f462820 100644 (file)
@@ -44,5 +44,161 @@ UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) {
     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];
+}
index 1d7311a49dec18f6fedbcdb68c9c5aee3e0b2242..629112f7777380f46d86f3503447814b17e6518a 100644 (file)
 #include <sys/stat.h>
 #include <errno.h>
 
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
 #include "../ui/toolkit.h"
 
 
index e5ffa58524c9e5b6002c9dc1839c71346f0fe53b..978ab532780fcf7e823a7b11754a6cabeda3d8f8 100644 (file)
@@ -269,6 +269,10 @@ UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) {
         // 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();
@@ -438,6 +442,10 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) {
     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();
index 3253ca74322bf0712975421eb39420cf3cf9caee..6ab288a53da871339aaaf0b04adca5f1f69b1b69 100644 (file)
@@ -73,3 +73,43 @@ UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args) {
     
     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;
+}
index 1ac457489be406ede8c0c8eceee6d65e9eb1149a..f3a4b3ba76da4dcc2d2c5748b0f3cbbc079b98b0 100644 (file)
@@ -70,7 +70,9 @@ QVariant ListModel::data(const QModelIndex &index, int role) const {
         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();
@@ -99,6 +101,113 @@ void ListModel::selectionChanged(const QItemSelection& selected, const QItemSele
 
 
 
+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;
index e2c2e594ad319ce5e445b439c5593f43f0f2d90d..839b38e23394753061a92ea82ed208d41c2af89b 100644 (file)
@@ -71,6 +71,38 @@ public slots:
         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);
 
index e74d9c69fef12363468d411144f58f66a37d9729..0dce885962a16d776147aa7203084fd5e2595607 100644 (file)
@@ -29,7 +29,8 @@
 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)
index 4afbc73f58f5fe4e02411f8914671477c08139af..cd1f1ba1d0c9aa40cd3f765694138ef42747d849 100644 (file)
@@ -29,6 +29,8 @@
 #include "toolkit.h"
 #include "Windows.h"
 
+#include "window.h"
+
 #include "../common/properties.h"
 
 #include <stdio.h>
@@ -45,6 +47,8 @@ void                 *exit_data;
 
 void ui_init(const char *appname, int argc, char **argv) {
       application_name = appname;
+         
+         ui_window_init();
 }
 
 const char* ui_appname() {
diff --git a/ui/win32/window.c b/ui/win32/window.c
new file mode 100644 (file)
index 0000000..184f7fd
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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);
+}
+
diff --git a/ui/win32/window.h b/ui/win32/window.h
new file mode 100644 (file)
index 0000000..305f40a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 */
+