From ecf4a6c116f5a31fe001b02166eb325acd563314 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Mon, 21 Apr 2025 16:58:50 +0200 Subject: [PATCH] limit embedded widget size to current textview size --- application/gtk-image.c | 48 ++++++++++++++++++++++++++-------- application/gtk-image.h | 4 +-- application/gtk-text.c | 57 +++++++++++++++++++++++++++++++++++------ application/gtk-text.h | 9 +++++++ 4 files changed, 98 insertions(+), 20 deletions(-) diff --git a/application/gtk-image.c b/application/gtk-image.c index fec2cd2..983bea2 100644 --- a/application/gtk-image.c +++ b/application/gtk-image.c @@ -31,38 +31,66 @@ #if GTK_MAJOR_VERSION >= 4 -GtkWidget* embedded_image_create(GdkPixbuf *pix) { - GtkWidget *grid = gtk_grid_new(); - gtk_widget_add_css_class(grid, "ui_test"); // TODO: replace with new class - - GdkTexture *texture = gdk_texture_new_for_pixbuf(pix); - GtkWidget *picture = gtk_picture_new_for_paintable(GDK_PAINTABLE(texture)); +static void embedded_image_adjust_size(EmbeddedWidget *em, int max_width) { + GtkWidget *picture = em->wdata1; + GdkTexture *texture = em->wdata2; double width = gdk_texture_get_width(texture); double height = gdk_texture_get_height(texture); - if(width > EDITOR_IMAGE_MAX_WIDTH) { - height = height * (EDITOR_IMAGE_MAX_WIDTH / width); - width = EDITOR_IMAGE_MAX_WIDTH; + printf("max width: %d\n", max_width); + if(width > max_width) { + height = height * (max_width / width); + width = max_width; } gtk_widget_set_size_request(picture, width, height); +} + +GtkWidget* embedded_image_create(EmbeddedWidget *em, GdkPixbuf *pix) { + GtkWidget *grid = gtk_grid_new(); + gtk_widget_add_css_class(grid, "ui_test"); // TODO: replace with new class + + GdkTexture *texture = gdk_texture_new_for_pixbuf(pix); + GtkWidget *picture = gtk_picture_new_for_paintable(GDK_PAINTABLE(texture)); gtk_grid_attach(GTK_GRID(grid), picture, 0, 0, 1, 1); + em->wdata1 = picture; + em->wdata2 = texture; + em->adjust_size = embedded_image_adjust_size; return grid; } #else -GtkWidget* embedded_image_create(GdkPixbuf *pix) { +static void embedded_image_adjust_size(EmbeddedWidget *em, int max_width) { + GtkWidget *image = em->wdata1; + GdkPixmap *pix = em->wdata2; + + double width = gdk_pixbuf_get_width(pix); + double height = gdk_pixbuf_get_height(pix); + + if(width > max_width) { + height = height * (max_width / width); + width = max_width; + } + + gtk_widget_set_size_request(picture, width, height); +} + +GtkWidget* embedded_image_create(EmbeddedWidget *em, GdkPixbuf *pix) { GtkWidget *image = gtk_image_new_from_pixbuf(pix); int width = gdk_pixbuf_get_width(pix); int height = gdk_pixbuf_get_height(pix); gtk_widget_set_size_request(image, width, height); + em->wdata1 = image; + em->wdata2 = pix; + em->adjust_size = embedded_image_adjust_size; + return image; } diff --git a/application/gtk-image.h b/application/gtk-image.h index a710d75..6fe6b79 100644 --- a/application/gtk-image.h +++ b/application/gtk-image.h @@ -33,9 +33,9 @@ #include "note.h" #include "attachment.h" -#define EDITOR_IMAGE_MAX_WIDTH 600 +#include "gtk-text.h" -GtkWidget* embedded_image_create(GdkPixbuf *pix); +GtkWidget* embedded_image_create(EmbeddedWidget *em, GdkPixbuf *pix); #endif /* GTK_IMAGE_H */ diff --git a/application/gtk-text.c b/application/gtk-text.c index 35dd2e1..41b7fb1 100644 --- a/application/gtk-text.c +++ b/application/gtk-text.c @@ -84,8 +84,6 @@ static gboolean editor_drop_cb( double y, NoteEditor *editor); -static void editor_update_width(NoteEditor *editor); - #else static gboolean editor_textview_event_after(GtkWidget *textview, GdkEvent *ev, NoteEditor *editor); @@ -104,6 +102,9 @@ static void editor_update_width(NoteEditor *editor); #endif +// different implementations for gtk versions +static void editor_update_width(NoteEditor *editor); + static void editor_realize(GtkWidget *unused, NoteEditor *editor) { editor_update_width(editor); } @@ -177,7 +178,6 @@ void editor_init_textview(UiObject *obj, UIWIDGET textview) { static void editor_resize(NoteEditor *editor) { editor_update_width(editor); - printf("editor resize: %d\n", editor->width); } @@ -250,6 +250,8 @@ static void editor_set_buffer_cb( #endif } } + + editor_update_width(editor); } static void em_remove_anchor(BufferEmbeddedObjects *em, GtkTextChildAnchor *anchor) { @@ -326,25 +328,32 @@ static void editor_insert_image(NoteEditor *editor, Attachment *attachment, GtkT } GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(buffer, iter); - GtkWidget *image = embedded_image_create(pixbuf); + + // remember widget and store a reference in the textbuffer + // TODO: we need a cleanup strategy + EmbeddedWidget *em = malloc(sizeof(EmbeddedWidget)); + memset(em, 0, sizeof(EmbeddedWidget)); + + GtkWidget *image = embedded_image_create(em, pixbuf); gtk_text_view_add_child_at_anchor(textview, image, anchor); #if GTK_MAJOR_VERSION < 4 gtk_widget_show_all(image); #endif - // remember widget and store a reference in the textbuffer - // TODO: we need a cleanup strategy - EmbeddedWidget *em = malloc(sizeof(EmbeddedWidget)); em->widget = image; em->anchor = anchor; em->data1 = attachment; - em->data2 = NULL; em->serialize = md_serialize_image; g_object_ref(image); g_object_ref(anchor); g_object_set_data(G_OBJECT(anchor), "em", em); + int em_width = editor->width - EM_WIDGET_HPADDING; + if(em->adjust_size && em_width > 0) { + em->adjust_size(em, em_width); + } + BufferEmbeddedObjects *embedded_objects = g_object_get_data(G_OBJECT(buffer), "embedded"); cxListAdd(embedded_objects->objects, em); } @@ -435,10 +444,25 @@ static void editor_gtk4_resize( } } +static void editor_gtk4_draw_func( + GtkDrawingArea *drawing_area, + cairo_t *cr, + int width, + int height, + gpointer userdata) +{ + MainWindow *wdata = userdata; + NoteEditor *editor = g_object_get_data(G_OBJECT(ui_textarea_gettextwidget(wdata->textview)), "editor"); + if(editor && editor->width == 0) { + editor_resize(editor); + } +} + GtkWidget* editor_gtk4_workaround(UiObject *obj, UiWidgetArgs args, void *userdata) { GtkWidget *drawingarea = gtk_drawing_area_new(); //gtk_widget_add_css_class(drawingarea, "ui_test"); gtk_widget_set_size_request(drawingarea, 10, 1); + gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(drawingarea), editor_gtk4_draw_func, userdata, NULL); g_signal_connect(drawingarea, "resize", G_CALLBACK(editor_gtk4_resize), userdata); return drawingarea; } @@ -507,6 +531,7 @@ static gboolean editor_drop_cb( static void editor_update_width(NoteEditor *editor) { editor->width = gtk_widget_get_width(gtk_widget_get_parent(editor->textview)); + editor_update_embedded_widgets(editor); } #else @@ -591,6 +616,22 @@ void editor_try_follow_link(NoteEditor *editor, GtkTextIter *pos) { } } +void editor_update_embedded_widgets(NoteEditor *editor) { + GtkTextView *textview = GTK_TEXT_VIEW(editor->textview); + GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview); + + BufferEmbeddedObjects *embedded_objects = g_object_get_data(G_OBJECT(buffer), "embedded"); + int em_width = editor->width - EM_WIDGET_HPADDING; + if(embedded_objects && em_width > 0) { + CxIterator i = cxListIterator(embedded_objects->objects); + cx_foreach(EmbeddedWidget *, em, i) { + if(em->adjust_size) { + em->adjust_size(em, em_width); + } + } + } +} + static void buffer_embedded_objects_free(BufferEmbeddedObjects *em) { cxListFree(em->objects); free(em); diff --git a/application/gtk-text.h b/application/gtk-text.h index c6eeaea..1bed17a 100644 --- a/application/gtk-text.h +++ b/application/gtk-text.h @@ -36,6 +36,8 @@ extern "C" { #endif +#define EM_WIDGET_HPADDING 60 + typedef struct NoteEditor { UiObject *obj; GtkWidget *textview; @@ -60,8 +62,13 @@ typedef struct EmbeddedWidget EmbeddedWidget; struct EmbeddedWidget { GtkWidget *widget; GtkTextChildAnchor *anchor; + int width; + int height; + void (*adjust_size)(EmbeddedWidget *em, int max_width); void *data1; void *data2; + void *wdata1; // wdata1/wdata2 filled by widget constructor + void *wdata2; // and used by adjust_size void (*serialize)(EmbeddedWidget *e, CxBuffer *out); }; @@ -69,6 +76,8 @@ typedef void (*set_style_cb)(MDActiveStyles *style, GtkTextTag *tag); void editor_try_follow_link(NoteEditor *editor, GtkTextIter *pos); +void editor_update_embedded_widgets(NoteEditor *editor); + void init_textbuf(GtkTextBuffer *buf); void init_tagtable(GtkTextTagTable *table); -- 2.43.5