diff --git a/unix/image.c b/unix/image.c index 522d6b66..a79e550f 100644 --- a/unix/image.c +++ b/unix/image.c @@ -45,7 +45,7 @@ void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, in cstride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixelWidth); buf = (unsigned char *) uiAlloc((cstride * pixelHeight * 4) * sizeof (unsigned char), "unsigned char[]"); p = buf; - for (y = 0; y < pixelWidth * pixelHeight; y += pixelStride) { + for (y = 0; y < pixelStride * pixelHeight; y += pixelStride) { memmove(p, src + y, cstride); p += cstride; } @@ -57,3 +57,64 @@ void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, in cairo_surface_flush(cs); g_ptr_array_add(i->images, cs); } + +struct matcher { + cairo_surface_t *best; + int distX; + int distY; + int targetX; + int targetY; + gboolean foundLarger; +}; + +// TODO is this the right algorithm? +static void match(gpointer surface, gpointer data) +{ + cairo_surface_t *cs = (cairo_surface_t *) surface; + struct matcher *m = (struct matcher *) data; + int x, y; + int x2, y2; + + x = cairo_image_surface_get_width(cs); + y = cairo_image_surface_get_height(cs); + if (m->best == NULL) + goto writeMatch; + + if (x < m->targetX && y < m->targetY) + if (m->foundLarger) + // always prefer larger ones + return; + if (x >= m->targetX && y >= m->targetY && !m->foundLarger) + // we set foundLarger below + goto writeMatch; + + x2 = abs(m->targetX - x); + y2 = abs(m->targetY - y); + if (x2 < m->distX && y2 < m->distY) + goto writeMatch; + + // TODO weight one dimension? threshhold? + return; + +writeMatch: + // must set this here too; otherwise the first image will never have ths set + if (x >= m->targetX && y >= m->targetY && !m->foundLarger) + m->foundLarger = TRUE; + m->best = cs; + m->distX = abs(m->targetX - x); + m->distY = abs(m->targetY - y); +} + +cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w) +{ + struct matcher m; + + m.best = NULL; + m.distX = G_MAXINT; + m.distY = G_MAXINT; + m.targetX = i->width * gtk_widget_get_scale_factor(w); + m.targetY = i->height * gtk_widget_get_scale_factor(w); + m.foundLarger = FALSE; + g_ptr_array_foreach(i->images, match, &m); + return m.best; +} diff --git a/unix/table.c b/unix/table.c index 22deb9bf..e0c61eae 100644 --- a/unix/table.c +++ b/unix/table.c @@ -334,6 +334,25 @@ struct uiTable { int backgroundColumn; }; +// use the same size as GtkFileChooserWidget's treeview +// TODO refresh when icon theme changes +// TODO doesn't work when scaled +// TODO is this even necessary? +static void setImageSize(GtkCellRenderer *r) +{ + gint size; + gint width, height; + gint xpad, ypad; + + size = 16; // fallback used by GtkFileChooserWidget + if (gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height) != FALSE) + size = MAX(width, height); + gtk_cell_renderer_get_padding(r, &xpad, &ypad); + gtk_cell_renderer_set_fixed_size(r, + 2 * xpad + size, + 2 * ypad + size); +} + static void dataFunc(GtkTreeViewColumn *c, GtkCellRenderer *r, GtkTreeModel *mm, GtkTreeIter *iter, gpointer data) { struct tablePart *part = (struct tablePart *) data; @@ -352,9 +371,12 @@ static void dataFunc(GtkTreeViewColumn *c, GtkCellRenderer *r, GtkTreeModel *mm, g_object_set(r, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); break; case partImage: +//TODO setImageSize(r); gtk_tree_model_get_value(mm, iter, part->imageColumn, &value); img = (uiImage *) g_value_get_pointer(&value); - // TODO + g_object_set(r, "surface", + imageAppropriateSurface(img, part->tv->treeWidget), + NULL); g_object_set(r, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); break; case partButton: diff --git a/unix/uipriv_unix.h b/unix/uipriv_unix.h index 785c5824..d8d639dd 100644 --- a/unix/uipriv_unix.h +++ b/unix/uipriv_unix.h @@ -8,6 +8,7 @@ #include // see drawtext.c #include #include +#include #include "../ui.h" #include "../ui_unix.h" #include "../common/uipriv.h" @@ -50,3 +51,6 @@ extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc); // graphemes.c extern ptrdiff_t *graphemes(const char *text, PangoContext *context); + +// image.c +extern cairo_surface_t *imageAppropriateSurface(uiImage *i, GtkWidget *w);