]> uap-core.de Git - note.git/commitdiff
add attachment window
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 2 Apr 2025 19:27:44 +0000 (21:27 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 2 Apr 2025 19:27:44 +0000 (21:27 +0200)
application/application.h
application/attachment.c
application/attachment.h
application/gtk-text.c
ui/gtk/image.c
ui/gtk/image.h
ui/qt/label.cpp
ui/qt/qt5.pro
ui/qt/widget.cpp [new file with mode: 0644]
ui/qt/widget.h [new file with mode: 0644]
ui/ui/image.h

index 23ff571968b3f73450c3d86bf6450a39f50ee004..03a4fe434c141962c740af9d726726e7391020ed 100644 (file)
@@ -168,6 +168,15 @@ typedef struct AttachmentModel {
     UiGeneric *img;
 } AttachmentModel;
 
+typedef struct AttachmentWindow {
+    UiObject *obj;
+    
+    Resource *resource;
+    UiList *attachments;
+    
+    UiGeneric *image;
+} AttachmentWindow;
+
 void application_init();
 
 void application_startup(UiEvent *event, void *data);
index b51678f7c8bdb2cea5e3e5f5c449ed9267b046f5..501c483e58a68d64f9eaa37d4e199d3534a7d46d 100644 (file)
 
 #include "attachment.h"
 
+#include "note.h"
+
+#include <cx/printf.h>
+
 Attachment* attachment_create(
         const CxAllocator *a,
         int64_t parent,
@@ -41,7 +45,7 @@ Attachment* attachment_create(
     return attachment;
 }
 
-void attachment_create_ui_model(UiContext *ctx, Attachment *attachment) {
+void attachment_create_ui_model(UiContext *ctx, Attachment *attachment, Resource *resource) {
     if(attachment->ui) {
         return;
     }
@@ -54,6 +58,8 @@ void attachment_create_ui_model(UiContext *ctx, Attachment *attachment) {
         model->img = ui_generic_new(ctx, NULL);
     }
     model->ctx = ctx;
+    
+    model->parent_note = resource;
 }
 
 void attachment_set_image(Attachment *attachment, void *img) {
@@ -72,7 +78,63 @@ void attachment_item(UiObject *obj, int index, void *elm, void *userdata) {
     Attachment *attachment = elm;
     
     if(attachment->type == NOTE_ATTACHMENT_IMAGE) {
-        UIWIDGET imgviewer = ui_imageviewer(obj, .value = attachment->ui->img, .scrollarea = FALSE, .autoscale = TRUE);
+        UIWIDGET imgviewer = ui_imageviewer(obj,
+                .value = attachment->ui->img,
+                .scrollarea = FALSE,
+                .autoscale = TRUE,
+                .onbuttonpress = action_attachment_clicked,
+                .onbuttonpressdata = attachment);
         ui_widget_set_size(imgviewer, 100, 80);
     }
 }
+
+void action_attachment_clicked(UiEvent *event, void *userdata) {
+    Attachment *attachment = userdata;
+    
+    UiObject *attachment_window = attachment_window_create(attachment->ui->parent_note, attachment);
+    ui_show(attachment_window);
+}
+
+
+UiObject* attachment_window_create(Resource *resource, Attachment *selected_attachment) {
+    cxmutstr title = cx_asprintf("%s - attachments", note_get_title(resource));
+    UiObject *obj = ui_simple_window(title.ptr, NULL);
+    free(title.ptr);
+    
+    AttachmentWindow *wdata = attachment_window_create_data(obj, resource);
+    obj->window = wdata;
+    
+    ui_headerbar(obj) {
+        ui_headerbar_start(obj) {
+            ui_button(obj, .icon = UI_ICON_GO_BACK);
+            ui_button(obj, .icon = UI_ICON_GO_FORWARD);
+        }
+    }
+    
+    ui_imageviewer(obj, .value = wdata->image, .autoscale = TRUE, .scrollarea = TRUE, .useradjustable = TRUE, .fill = UI_ON);
+    
+    
+    return obj;
+}
+
+static void update_attachments(AttachmentWindow *wdata, NoteModel *model) {
+    void *elm = ui_list_first(model->attachments);
+    while(elm) {
+        ui_list_append(wdata->attachments, elm);
+        elm = ui_list_next(model->attachments);
+    }
+}
+
+AttachmentWindow* attachment_window_create_data(UiObject *obj, Resource *resource) {
+    AttachmentWindow *wdata = ui_malloc(obj->ctx, sizeof(AttachmentWindow));
+    memset(wdata, 0, sizeof(AttachmentWindow));
+    
+    wdata->obj = obj;
+    wdata->resource = resource;
+    wdata->attachments = ui_list_new(obj->ctx, NULL);
+    wdata->image = ui_generic_new(obj->ctx, NULL);
+    
+    update_attachments(wdata, resource->model);
+    
+    return wdata;
+}
index fcc2d5e46ecbce857cbbb2a0c3c5601ae5161ba3..d10fb165197214b1a6e1687b947e1fdcdce3be96 100644 (file)
@@ -40,7 +40,7 @@ Attachment* attachment_create(
         AttachmentType type,
         const char *name);
 
-void attachment_create_ui_model(UiContext *ctx, Attachment *attachment);
+void attachment_create_ui_model(UiContext *ctx, Attachment *attachment, Resource *resource);
 
 void attachment_set_image(Attachment *attachment, void *img);
 
@@ -49,6 +49,11 @@ void attachment_set_image(Attachment *attachment, void *img);
  */
 void attachment_item(UiObject *obj, int index, void *elm, void *userdata);
 
+void action_attachment_clicked(UiEvent *event, void *userdata);
+
+UiObject* attachment_window_create(Resource *resource, Attachment *selected_attachment);
+
+AttachmentWindow* attachment_window_create_data(UiObject *obj, Resource *resource);
 
 #ifdef __cplusplus
 }
index 379456588ae3a0c9bde26945695e24df290a93b1..8d9777bade374f55f0d98eaeaa588f9fa785a984 100644 (file)
@@ -275,7 +275,7 @@ static void editor_attach_image(NoteEditor *editor, GdkPixbuf *pixbuf, char *att
     
     // create attachment
     Attachment *attachment = attachment_create(model->note_allocator, note->resource_id, NOTE_ATTACHMENT_IMAGE, util_resource_name(attachment_path));
-    attachment_create_ui_model(model->ctx, attachment);
+    attachment_create_ui_model(model->ctx, attachment, note);
     g_object_ref(pixbuf);
     attachment_set_image(attachment, pixbuf);
     
index 41c9b44ef615d8d0943dbe46c3ed2a923661c58e..04cb75c4818e374cc1614c0d6b47dc90ab6eca8f 100644 (file)
@@ -88,6 +88,11 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
     
     UiImageViewer *imgviewer = malloc(sizeof(UiImageViewer));
     memset(imgviewer, 0, sizeof(UiImageViewer));
+    imgviewer->obj = obj;
+    imgviewer->onbuttonpress = args.onbuttonpress;
+    imgviewer->onbuttonpressdata = args.onbuttonpressdata;
+    imgviewer->onbuttonrelease = args.onbuttonrelease;
+    imgviewer->onbuttonreleasedata = args.onbuttonreleasedata;
     if(args.image_padding > 0) {
         imgviewer->padding_left = args.image_padding;
         imgviewer->padding_right = args.image_padding;
@@ -144,6 +149,11 @@ UIWIDGET ui_imageviewer_create(UiObject *obj, UiImageViewerArgs args) {
     g_signal_connect(drag, "drag-update", G_CALLBACK(ui_imageviewer_drag_update_cb), imgviewer);
     gtk_widget_add_controller(GTK_WIDGET(drawingarea), GTK_EVENT_CONTROLLER(drag));
     
+    GtkGesture *click = gtk_gesture_click_new();
+    g_signal_connect(click, "pressed", G_CALLBACK(ui_imageviewer_pressed_cb), imgviewer);
+    g_signal_connect(click, "released", G_CALLBACK(ui_imageviewer_released_cb), imgviewer);
+    gtk_widget_add_controller(GTK_WIDGET(drawingarea), GTK_EVENT_CONTROLLER(click));
+    
 #elif GTK_MAJOR_VERSION == 3
     g_signal_connect(
             drawingarea,
@@ -351,7 +361,7 @@ gboolean ui_imageviewer_scroll(
 }
 
 void ui_imageviewer_drag_begin_cb(
-        GtkGestureDragself,
+        GtkGestureDrag *self,
         gdouble start_x,
         gdouble start_y,
         gpointer userdata)
@@ -371,7 +381,7 @@ void ui_imageviewer_drag_end_cb(
 }
 
 void ui_imageviewer_drag_update_cb(
-        GtkGestureDragself,
+        GtkGestureDrag *self,
         gdouble x,
         gdouble y,
         gpointer userdata)
@@ -384,6 +394,48 @@ void ui_imageviewer_drag_update_cb(
     }
 }
 
+static void imgviewer_button_event(
+        GtkGestureClick *gesture,
+        UiImageViewer *imgviewer,
+        ui_callback callback,
+        void *userdata)
+{
+    UiEvent event;
+    event.obj = imgviewer->obj;
+    event.window = event.obj->window;
+    event.document = event.obj->ctx->document;
+    event.eventdata = NULL;
+    event.intval = gtk_gesture_single_get_current_button(GTK_GESTURE_SINGLE(gesture));
+    event.set = 0;
+    callback(&event, userdata);
+}
+
+void ui_imageviewer_pressed_cb(
+        GtkGestureClick *self,
+        gint n_press,
+        gdouble x,
+        gdouble y,
+        gpointer userdata)
+{
+    UiImageViewer *imgviewer = userdata;
+    if(imgviewer->onbuttonpress) {
+        imgviewer_button_event(self, imgviewer, imgviewer->onbuttonpress, imgviewer->onbuttonpressdata);
+    }
+}
+
+void ui_imageviewer_released_cb(
+        GtkGestureClick *self,
+        gint n_press,
+        gdouble x,
+        gdouble y,
+        gpointer userdata)
+{
+    UiImageViewer *imgviewer = userdata;
+    if(imgviewer->onbuttonrelease) {
+        imgviewer_button_event(self, imgviewer, imgviewer->onbuttonrelease, imgviewer->onbuttonreleasedata);
+    }
+}
+
 #else
 
 gboolean ui_imageviewer_scroll_event(
@@ -391,7 +443,7 @@ gboolean ui_imageviewer_scroll_event(
         GdkEventScroll event,
         gpointer userdata)
 {
-    printf("scroll event\n");
+    // TODO
     return FALSE;
 }
 
@@ -400,7 +452,8 @@ gboolean ui_imageviewer_button_press_event(
         GdkEventButton event,
         gpointer userdata)
 {
-    printf("button pressed\n");
+    // TODO
+    return FALSE;
 }
 
 gboolean ui_imageviewer_button_release_event(
@@ -408,7 +461,8 @@ gboolean ui_imageviewer_button_release_event(
         GdkEventButton event,
         gpointer userdata)
 {
-    printf("button released\n");
+    // TODO
+    return FALSE;
 }
 
 #endif
index 7e9bf9f0104c6b8fa1224d5121a6f430e5dd86ce..987c73b3262d872626d59e30197d4d427bb80b9b 100644 (file)
@@ -37,6 +37,7 @@ extern "C" {
 #endif
 
 typedef struct UiImageViewer {
+    UiObject *obj;
     GtkWidget *widget;
     UiVar *var;
     int padding_left;
@@ -56,6 +57,11 @@ typedef struct UiImageViewer {
     UiBool isautoscaled;
     double user_scale;
     double scale;
+    
+    ui_callback onbuttonpress;
+    void *onbuttonpressdata;
+    ui_callback onbuttonrelease;
+    void *onbuttonreleasedata;
 } UiImageViewer;
 
 void ui_cairo_draw_image(UiImageViewer *imgviewer, cairo_t *cr, int width, int height);
@@ -90,6 +96,20 @@ void ui_imageviewer_drag_update_cb(
         gdouble y,
         gpointer userdata);
 
+void ui_imageviewer_pressed_cb(
+        GtkGestureClick *self,
+        gint n_press,
+        gdouble x,
+        gdouble y,
+        gpointer userdata);
+
+void ui_imageviewer_released_cb(
+        GtkGestureClick *self,
+        gint n_press,
+        gdouble x,
+        gdouble y,
+        gpointer userdata);
+
 #else
 
 gboolean ui_imageviewer_scroll_event(
index ef7a9fcd085290f4cc0a87f67749980521e0b770..49917d0b39afb6f01c6bc22a61a3adf32dedeba1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2015 Olaf Wintermann. All rights reserved.
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
index 60cf702a1e9a17bffc8a08568cd9e05f7de1bf6b..43d9637200b3963f8c16dfc275afff984b1e67eb 100644 (file)
@@ -49,6 +49,7 @@ SOURCES += tree.cpp
 SOURCES += button.cpp
 SOURCES += label.cpp
 SOURCES += graphics.cpp
+SOURCES += widget.cpp
 
 HEADERS += toolkit.h
 HEADERS += window.h
@@ -62,4 +63,5 @@ HEADERS += tree.h
 HEADERS += button.h
 HEADERS += label.h
 HEADERS += graphics.h
+HEADERS += widget.h
 
diff --git a/ui/qt/widget.cpp b/ui/qt/widget.cpp
new file mode 100644 (file)
index 0000000..283043b
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "widget.h"
+
+#include "container.h"
+#include "../common/context.h"
+
+UIWIDGET ui_customwidget_create(UiObject *obj, ui_createwidget_func create_widget, void *userdata, UiWidgetArgs args) {
+    UIWIDGET widget = create_widget(obj, args, userdata);
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    UI_APPLY_LAYOUT(ctn->layout, args);
+    ctn->add(widget, false);
+    return widget;
+}
+
+UIWIDGET ui_separator_create(UiObject *obj, UiWidgetArgs *args) {
+    QFrame *separator = new QFrame();
+    separator->setFrameShape(QFrame::HLine);
+    separator->setFrameShadow(QFrame::Sunken);
+    
+    UiContainerPrivate *ctn = ui_obj_container(obj);
+    UI_APPLY_LAYOUT(ctn->layout, (*args));
+    
+    ctn->add(separator, false);
+    
+    return separator;
+}
+
+void ui_widget_set_size(UIWIDGET w, int width, int height) {
+    w->resize(width >= 0 ? width : w->width(), height >= 0 ? w->height());
+}
+
+void ui_widget_redraw(UIWIDGET w) {
+    w->repaint();
+}
diff --git a/ui/qt/widget.h b/ui/qt/widget.h
new file mode 100644 (file)
index 0000000..f9ed0bf
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include "toolkit.h"
+
+#include "../ui/widget.h"
+
+
+#endif /* WIDGET_H */
+
index d54c9e9704e4b01a082b52d0fe010e8635682645..b0a9e91de256d8758abcf54954175d1cdfe9f932 100644 (file)
@@ -61,6 +61,11 @@ typedef struct UiImageViewerArgs {
     UiGeneric *value;
     const char *varname;
     UiMenuBuilder *contextmenu;
+    
+    ui_callback onbuttonpress;
+    void *onbuttonpressdata;
+    ui_callback onbuttonrelease;
+    void *onbuttonreleasedata;
 } UiImageViewerArgs;
     
 #define ui_imageviewer(obj, ...) ui_imageviewer_create(obj, (UiImageViewerArgs){ __VA_ARGS__ } )