Ref #160: Replace print dialog by standard GTK dialog
authorColin Clark <colin.clark@cclark.uk>
Thu, 22 Nov 2018 15:08:54 +0000 (15:08 +0000)
committerColin Clark <colin.clark@cclark.uk>
Thu, 22 Nov 2018 15:08:54 +0000 (15:08 +0000)
https://github.com/BestImageViewer/geeqie/issues/160

Permit exif tags to be included in the image text annotations (as for
the Overlay screen Display)

po/POTFILES.in
src/Makefile.am
src/image-overlay.c
src/options.c
src/options.h
src/osd.c [new file with mode: 0644]
src/osd.h [new file with mode: 0644]
src/preferences.c
src/print.c
src/rcfile.c

index 74ecb06..5db6035 100644 (file)
@@ -70,6 +70,7 @@ src/menu.c
 src/metadata.c
 src/misc.c
 src/options.c
+src/osd.c
 src/pan-view/pan-calendar.c
 src/pan-view/pan-folder.c
 src/pan-view/pan-grid.c
index 8354c30..f5d8884 100644 (file)
@@ -220,6 +220,8 @@ geeqie_SOURCES = \
        misc.h          \
        options.c       \
        options.h       \
+       osd.c   \
+       osd.h   \
        pan-view.h      \
        pixbuf-renderer.c       \
        pixbuf-renderer.h       \
index b0585f6..e94d752 100644 (file)
 #include "main.h"
 #include "image-overlay.h"
 
-#include "collect.h"
-#include "exif.h"
 #include "filedata.h"
 #include "histogram.h"
 #include "image.h"
 #include "img-view.h"
 #include "layout.h"
-#include "metadata.h"
+#include "osd.h"
 #include "pixbuf-renderer.h"
 #include "pixbuf_util.h"
 #include "ui_fileops.h"
 #include "image-load.h"
-#include "glua.h"
 
 /*
  *----------------------------------------------------------------------------
@@ -232,287 +229,6 @@ void image_osd_toggle(ImageWindow *imd)
                }
 }
 
-static gchar *keywords_to_string(FileData *fd)
-{
-       GList *keywords;
-       GString *kwstr = NULL;
-       gchar *ret = NULL;
-
-       g_assert(fd);
-
-       keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
-
-       if (keywords)
-               {
-               GList *work = keywords;
-
-               while (work)
-                       {
-                       gchar *kw = work->data;
-                       work = work->next;
-
-                       if (!kw) continue;
-                       if (!kwstr)
-                               kwstr = g_string_new("");
-                       else
-                               g_string_append(kwstr, ", ");
-
-                       g_string_append(kwstr, kw);
-                       }
-               string_list_free(keywords);
-               }
-
-       if (kwstr)
-               {
-               ret = kwstr->str;
-               g_string_free(kwstr, FALSE);
-               }
-
-       return ret;
-}
-
-static gchar *image_osd_mkinfo(const gchar *str, ImageWindow *imd, GHashTable *vars)
-{
-       gchar delim = '%', imp = '|', sep[] = " - ";
-       gchar *start, *end;
-       guint pos, prev;
-       gboolean want_separator = FALSE;
-       gchar *name, *data;
-       GString *new;
-       gchar *ret;
-
-       if (!str || !*str) return g_strdup("");
-
-       new = g_string_new(str);
-
-       prev = -1;
-
-       while (TRUE)
-               {
-               guint limit = 0;
-               gchar *trunc = NULL;
-               gchar *limpos = NULL;
-               gchar *extra = NULL;
-               gchar *extrapos = NULL;
-               gchar *p;
-
-               start = strchr(new->str + (prev + 1), delim);
-               if (!start)
-                       break;
-               end = strchr(start+1, delim);
-               if (!end)
-                       break;
-
-               /* Search for optionnal modifiers
-                * %name:99:extra% -> name = "name", limit=99, extra = "extra"
-                */
-               for (p = start + 1; p < end; p++)
-                       {
-                       if (p[0] == ':')
-                               {
-                               if (g_ascii_isdigit(p[1]) && !limpos)
-                                       {
-                                       limpos = p + 1;
-                                       if (!trunc) trunc = p;
-                                       }
-                               else
-                                       {
-                                       extrapos = p + 1;
-                                       if (!trunc) trunc = p;
-                                       break;
-                                       }
-                               }
-                       }
-
-               if (limpos)
-                       limit = (guint) atoi(limpos);
-
-               if (extrapos)
-                       extra = g_strndup(extrapos, end - extrapos);
-
-               name = g_strndup(start+1, (trunc ? trunc : end)-start-1);
-               pos = start - new->str;
-               data = NULL;
-
-               if (strcmp(name, "keywords") == 0)
-                       {
-                       data = keywords_to_string(imd->image_fd);
-                       }
-               else if (strcmp(name, "comment") == 0)
-                       {
-                       data = metadata_read_string(imd->image_fd, COMMENT_KEY, METADATA_PLAIN);
-                       }
-               else if (strcmp(name, "imagecomment") == 0)
-                       {
-                       data = exif_get_image_comment(imd->image_fd);
-                       }
-               else if (strcmp(name, "rating") == 0)
-                       {
-                       data = metadata_read_string(imd->image_fd, RATING_KEY, METADATA_PLAIN);
-                       }
-#ifdef HAVE_LUA
-               else if (strncmp(name, "lua/", 4) == 0)
-                       {
-                       gchar *tmp;
-                       tmp = strchr(name+4, '/');
-                       if (!tmp)
-                               break;
-                       *tmp = '\0';
-                       data = lua_callvalue(imd->image_fd, name+4, tmp+1);
-                       }
-#endif
-               else
-                       {
-                       data = g_strdup(g_hash_table_lookup(vars, name));
-                       if (!data)
-                               data = metadata_read_string(imd->image_fd, name, METADATA_FORMATTED);
-                       }
-
-               if (data && *data && limit > 0 && strlen(data) > limit + 3)
-                       {
-                       gchar *new_data = g_strdup_printf("%-*.*s...", limit, limit, data);
-                       g_free(data);
-                       data = new_data;
-                       }
-
-               if (data)
-                       {
-                       /* Since we use pango markup to display, we need to escape here */
-                       gchar *escaped = g_markup_escape_text(data, -1);
-                       g_free(data);
-                       data = escaped;
-                       }
-
-               if (extra)
-                       {
-                       if (data && *data)
-                               {
-                               /* Display data between left and right parts of extra string
-                                * the data is expressed by a '*' character. A '*' may be escaped
-                                * by a \. You should escape all '*' characters, do not rely on the
-                                * current implementation which only replaces the first unescaped '*'.
-                                * If no "*" is present, the extra string is just appended to data string.
-                                * Pango mark up is accepted in left and right parts.
-                                * Any \n is replaced by a newline
-                                * Examples:
-                                * "<i>*</i>\n" -> data is displayed in italics ended with a newline
-                                * "\n"         -> ended with newline
-                                * "ISO *"      -> prefix data with "ISO " (ie. "ISO 100")
-                                * "\**\*"      -> prefix data with a star, and append a star (ie. "*100*")
-                                * "\\*"        -> prefix data with an anti slash (ie "\100")
-                                * "Collection <b>*</b>\n" -> display data in bold prefixed by "Collection " and a newline is appended
-                                *
-                                * FIXME: using background / foreground colors lead to weird results.
-                                */
-                               gchar *new_data;
-                               gchar *left = NULL;
-                               gchar *right = extra;
-                               gchar *p;
-                               guint len = strlen(extra);
-
-                               /* Search for left and right parts and unescape characters */
-                               for (p = extra; *p; p++, len--)
-                                       if (p[0] == '\\')
-                                               {
-                                               if (p[1] == 'n')
-                                                       {
-                                                       memmove(p+1, p+2, --len);
-                                                       p[0] = '\n';
-                                                       }
-                                               else if (p[1] != '\0')
-                                                       memmove(p, p+1, len--); // includes \0
-                                               }
-                                       else if (p[0] == '*' && !left)
-                                               {
-                                               right = p + 1;
-                                               left = extra;
-                                               }
-
-                               if (left) right[-1] = '\0';
-
-                               new_data = g_strdup_printf("%s%s%s", left ? left : "", data, right);
-                               g_free(data);
-                               data = new_data;
-                               }
-                       g_free(extra);
-                       }
-
-               g_string_erase(new, pos, end-start+1);
-               if (data && *data)
-                       {
-                       if (want_separator)
-                               {
-                               /* insert separator */
-                               g_string_insert(new, pos, sep);
-                               pos += strlen(sep);
-                               want_separator = FALSE;
-                               }
-
-                       g_string_insert(new, pos, data);
-                       pos += strlen(data);
-               }
-
-               if (pos-prev >= 1 && new->str[pos] == imp)
-                       {
-                       /* pipe character is replaced by a separator, delete it
-                        * and raise a flag if needed */
-                       g_string_erase(new, pos--, 1);
-                       want_separator |= (data && *data);
-                       }
-
-               if (new->str[pos] == '\n') want_separator = FALSE;
-
-               prev = pos - 1;
-
-               g_free(name);
-               g_free(data);
-               }
-
-       /* search and destroy empty lines */
-       end = new->str;
-       while ((start = strchr(end, '\n')))
-               {
-               end = start;
-               while (*++(end) == '\n')
-                       ;
-               g_string_erase(new, start-new->str, end-start-1);
-               }
-
-       g_strchomp(new->str);
-
-       ret = new->str;
-       g_string_free(new, FALSE);
-
-       return ret;
-}
-
-typedef enum {
-       OSDT_NONE       = 0,
-       OSDT_FREE       = 1 << 0,
-       OSDT_NO_DUP     = 1 << 1
-} OsdTemplateFlags;
-
-static void osd_template_insert(GHashTable *vars, gchar *keyword, gchar *value, OsdTemplateFlags flags)
-{
-       if (!value)
-               {
-               g_hash_table_insert(vars, keyword, g_strdup(""));
-               return;
-               }
-
-       if (flags & OSDT_NO_DUP)
-               {
-               g_hash_table_insert(vars, keyword, value);
-               return;
-               }
-       else
-               {
-               g_hash_table_insert(vars, keyword, g_strdup(value));
-               }
-
-       if (flags & OSDT_FREE) g_free((gpointer) value);
-}
-
 static GdkPixbuf *image_osd_info_render(OverlayStateData *osd)
 {
        GdkPixbuf *pixbuf = NULL;
@@ -624,7 +340,7 @@ static GdkPixbuf *image_osd_info_render(OverlayStateData *osd)
                        osd_template_insert(vars, "res", NULL, OSDT_NONE);
                        }
 
-               text = image_osd_mkinfo(options->image_overlay.template_string, imd, vars);
+               text = image_osd_mkinfo(options->image_overlay.template_string, imd->image_fd, vars);
                g_hash_table_destroy(vars);
 
        } else {
index 6c665e8..4502d68 100644 (file)
@@ -197,10 +197,10 @@ ConfOptions *init_options(ConfOptions *options)
        options->star_rating.star = STAR_RATING_STAR;
        options->star_rating.rejected = STAR_RATING_REJECTED;
 
+       options->printer.template_string = NULL;
        options->printer.image_font = g_strdup("Serif 10");
        options->printer.page_font = g_strdup("Serif 10");
        options->printer.page_text = NULL;
-       options->printer.text_fields = 1;
        options->printer.image_text_position = 1;
        options->printer.page_text_position = 3;
 
index 9f45ec5..e4da085 100644 (file)
@@ -307,12 +307,12 @@ struct _ConfOptions
        struct {
                gchar *image_font;
                gchar *page_font;
-               gint text_fields;
                gboolean show_image_text;
                gboolean show_page_text;
                gchar *page_text;
                gint image_text_position;
                gint page_text_position;
+               gchar *template_string;
        } printer;
 
        gboolean read_metadata_in_idle;
diff --git a/src/osd.c b/src/osd.c
new file mode 100644 (file)
index 0000000..1f8ccd3
--- /dev/null
+++ b/src/osd.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2018 The Geeqie Team
+ *
+ * Author: Colin Clark
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Routines for creating the Overlay Screen Display text. Also
+ * used for the same purposes by the Print routines
+ */
+
+#include "main.h"
+#include "osd.h"
+
+#include "dnd.h"
+#include "exif.h"
+#include "glua.h"
+#include "metadata.h"
+#include "ui_fileops.h"
+#include "ui_misc.h"
+
+#include <math.h>
+
+static const gchar *predefined_tags[][2] = {
+       {"%name%",                                                      N_("Name")},
+       {"%path:60%",                                           N_("Path")},
+       {"%date%",                                                      N_("Date")},
+       {"%size%",                                                      N_("Size")},
+       {"%zoom%",                                                      N_("Zoom")},
+       {"%dimensions%",                                        N_("Dimensions")},
+       {"%collection%",                                        N_("Collection")},
+       {"%number%",                                            N_("Image index")},
+       {"%total%",                                                     N_("Images total")},
+       {"%comment%",                                           N_("Comment")},
+       {"%keywords%",                                          N_("Keywords")},
+       {"%file.ctime%",                                        N_("File ctime")},
+       {"%file.mode%",                                         N_("File mode")},
+       {"%file.owner%",                                        N_("File owner")},
+       {"%file.group%",                                        N_("File group")},
+       {"%file.link%",                                         N_("File link")},
+       {"%file.class%",                                        N_("File class")},
+       {"%formatted.DateTime%",                        N_("Image date")},
+       {"%formatted.DateTimeDigitized%",       N_("Date digitized")},
+       {"%formatted.ShutterSpeed%",            N_("ShutterSpeed")},
+       {"%formatted.Aperture%",                        N_("Aperture")},
+       {"%formatted.ExposureBias%",            N_("Exposure bias")},
+       {"%formatted.Resolution%",                      N_("Resolution")},
+       {"%formatted.Camera%",                          N_("Camera")},
+       {"%formatted.ISOSpeedRating%",          N_("ISO")},
+       {"%formatted.FocalLength%",                     N_("Focal length")},
+       {"%formatted.FocalLength35mmFilm%",     N_("Focal len. 35mm")},
+       {"%formatted.SubjectDistance%",         N_("Subject distance")},
+       {"%formatted.Flash%",                           N_("Flash")},
+       {"%formatted.ColorProfile%",            N_("Color profile")},
+       {"%formatted.GPSPosition%",                     N_("Lat, Long")},
+       {"%formatted.GPSAltitude%",                     N_("Altitude")},
+       {"%formatted.localtime%",                       N_("Local time")},
+       {"%formatted.timezone%",                        N_("Timezone")},
+       {"%formatted.countryname%",                     N_("Country name")},
+       {"%formatted.countrycode%",                     N_("Country code")},
+       {"%rating%",                                            N_("Rating")},
+       {"%formatted.star_rating%",                     N_("Star rating")},
+       {"%Xmp.dc.creator%",                            N_("© Creator")},
+       {"%Xmp.dc.contributor%",                        N_("© Contributor")},
+       {"%Xmp.dc.rights%",                                     N_("© Rights")},
+       {NULL, NULL}};
+
+static GtkTargetEntry osd_drag_types[] = {
+       { "text/plain", GTK_TARGET_SAME_APP, TARGET_TEXT_PLAIN }
+};
+
+typedef struct _TagData TagData;
+struct _TagData
+{
+       gchar *key;
+       gchar *title;
+};
+
+static void tag_button_cb(GtkWidget *widget, gpointer data)
+{
+       GtkTextView *image_overlay_template_view = data;
+       GtkTextBuffer *buffer;
+       TagData *td;
+
+       buffer = gtk_text_view_get_buffer(image_overlay_template_view);
+       td = g_object_get_data(G_OBJECT(widget), "tag_data");
+       gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(buffer), td->key, -1);
+
+       gtk_widget_grab_focus(GTK_WIDGET(image_overlay_template_view));
+}
+
+static void osd_dnd_get_cb(GtkWidget *btn, GdkDragContext *context,
+                                                               GtkSelectionData *selection_data, guint info,
+                                                               guint time, gpointer data)
+{
+       TagData *td;
+       GtkTextView *image_overlay_template_view = data;
+
+       td = g_object_get_data(G_OBJECT(btn), "tag_data");
+       gtk_selection_data_set_text(selection_data, td->key, -1);
+
+       gtk_widget_grab_focus(GTK_WIDGET(image_overlay_template_view));
+}
+
+static void osd_btn_destroy_cb(GtkWidget *btn, GdkDragContext *context,
+                                                               GtkSelectionData *selection_data, guint info,
+                                                               guint time, gpointer data)
+{
+       TagData *td;
+
+       td = g_object_get_data(G_OBJECT(btn), "tag_data");
+       g_free(td->key);
+       g_free(td->title);
+}
+
+static void set_osd_button(GtkTable *table, const gint rows, const gint cols, const gchar *key, const gchar *title, GtkWidget *template_view)
+{
+       GtkWidget *new_button;
+       TagData *td;
+
+       new_button = gtk_button_new_with_label(title);
+       g_signal_connect(G_OBJECT(new_button), "clicked", G_CALLBACK(tag_button_cb), template_view);
+       gtk_widget_show(new_button);
+
+       td = g_new0(TagData, 1);
+       td->key = g_strdup(key);
+       td->title = g_strdup(title);
+
+       g_object_set_data(G_OBJECT(new_button), "tag_data", td);
+
+       gtk_drag_source_set(new_button, GDK_BUTTON1_MASK, osd_drag_types, 1, GDK_ACTION_COPY);
+       g_signal_connect(G_OBJECT(new_button), "drag_data_get",
+                                                       G_CALLBACK(osd_dnd_get_cb), template_view);
+       g_signal_connect(G_OBJECT(new_button), "destroy",
+                                                       G_CALLBACK(osd_btn_destroy_cb), new_button);
+
+       gtk_table_attach_defaults(table, new_button, cols, cols+1, rows, rows+1);
+
+}
+
+GtkWidget *osd_new(gint max_cols, GtkWidget *template_view)
+{
+       GtkWidget *hbox;
+       GtkWidget *vbox;
+       GtkWidget *vbox_buttons;
+       GtkWidget *group;
+       GtkWidget *button;
+       GtkWidget *scrolled;
+       GtkTextBuffer *buffer;
+       GtkWidget *label;
+       GtkWidget *     subgroup;
+       gint i = 0;
+       gint rows = 0;
+       gint max_rows = 0;
+       gint col = 0;
+       gint cols = 0;
+       gdouble entries;
+       GtkWidget *viewport;
+
+       vbox = gtk_vbox_new(FALSE, 0);
+
+       pref_label_new(vbox, _("To include predefined tags in the template, click a button or drag-and-drop"));
+
+       scrolled = gtk_scrolled_window_new(NULL, NULL);
+       gtk_box_pack_start(GTK_BOX(vbox), scrolled, FALSE, FALSE, 0);
+       gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
+                                      GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+       label = gtk_label_new("title");
+       gtk_widget_show(scrolled);
+       gtk_widget_set_size_request(scrolled, -1, 140);
+
+       viewport = gtk_viewport_new(NULL, NULL);
+       gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
+       gtk_container_add(GTK_CONTAINER(scrolled), viewport);
+       gtk_widget_show(viewport);
+
+       entries = (sizeof(predefined_tags) / sizeof(predefined_tags[0])) - 1;
+       max_rows = ceil(entries / max_cols);
+
+       GtkTable *table;
+       table = GTK_TABLE(gtk_table_new(max_rows, max_cols, FALSE));
+       gtk_container_add(GTK_CONTAINER(viewport), GTK_WIDGET(table));
+       gtk_widget_show(GTK_WIDGET(table));
+
+       for (rows = 0; rows < max_rows; rows++)
+               {
+               cols = 0;
+
+               while (cols < max_cols && predefined_tags[i][0])
+                       {
+                       set_osd_button(table, rows, cols, predefined_tags[i][0], predefined_tags[i][1], template_view);
+                       i = i + 1;
+                       cols++;
+                       }
+               }
+       return vbox;
+}
+static gchar *keywords_to_string(FileData *fd)
+{
+       GList *keywords;
+       GString *kwstr = NULL;
+       gchar *ret = NULL;
+
+       g_assert(fd);
+
+       keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
+
+       if (keywords)
+               {
+               GList *work = keywords;
+
+               while (work)
+                       {
+                       gchar *kw = work->data;
+                       work = work->next;
+
+                       if (!kw) continue;
+                       if (!kwstr)
+                               kwstr = g_string_new("");
+                       else
+                               g_string_append(kwstr, ", ");
+
+                       g_string_append(kwstr, kw);
+                       }
+               string_list_free(keywords);
+               }
+
+       if (kwstr)
+               {
+               ret = kwstr->str;
+               g_string_free(kwstr, FALSE);
+               }
+
+       return ret;
+}
+
+gchar *image_osd_mkinfo(const gchar *str, FileData *fd, GHashTable *vars)
+{
+       gchar delim = '%', imp = '|', sep[] = " - ";
+       gchar *start, *end;
+       guint pos, prev;
+       gboolean want_separator = FALSE;
+       gchar *name, *data;
+       GString *new;
+       gchar *ret;
+
+       if (!str || !*str) return g_strdup("");
+
+       new = g_string_new(str);
+
+       prev = -1;
+
+       while (TRUE)
+               {
+               guint limit = 0;
+               gchar *trunc = NULL;
+               gchar *limpos = NULL;
+               gchar *extra = NULL;
+               gchar *extrapos = NULL;
+               gchar *p;
+
+               start = strchr(new->str + (prev + 1), delim);
+               if (!start)
+                       break;
+               end = strchr(start+1, delim);
+               if (!end)
+                       break;
+
+               /* Search for optionnal modifiers
+                * %name:99:extra% -> name = "name", limit=99, extra = "extra"
+                */
+               for (p = start + 1; p < end; p++)
+                       {
+                       if (p[0] == ':')
+                               {
+                               if (g_ascii_isdigit(p[1]) && !limpos)
+                                       {
+                                       limpos = p + 1;
+                                       if (!trunc) trunc = p;
+                                       }
+                               else
+                                       {
+                                       extrapos = p + 1;
+                                       if (!trunc) trunc = p;
+                                       break;
+                                       }
+                               }
+                       }
+
+               if (limpos)
+                       limit = (guint) atoi(limpos);
+
+               if (extrapos)
+                       extra = g_strndup(extrapos, end - extrapos);
+
+               name = g_strndup(start+1, (trunc ? trunc : end)-start-1);
+               pos = start - new->str;
+               data = NULL;
+
+               if (strcmp(name, "keywords") == 0)
+                       {
+                       data = keywords_to_string(fd);
+                       }
+               else if (strcmp(name, "comment") == 0)
+                       {
+                       data = metadata_read_string(fd, COMMENT_KEY, METADATA_PLAIN);
+                       }
+               else if (strcmp(name, "imagecomment") == 0)
+                       {
+                       data = exif_get_image_comment(fd);
+                       }
+               else if (strcmp(name, "rating") == 0)
+                       {
+                       data = metadata_read_string(fd, RATING_KEY, METADATA_PLAIN);
+                       }
+#ifdef HAVE_LUA
+               else if (strncmp(name, "lua/", 4) == 0)
+                       {
+                       gchar *tmp;
+                       tmp = strchr(name+4, '/');
+                       if (!tmp)
+                               break;
+                       *tmp = '\0';
+                       data = lua_callvalue(fd, name+4, tmp+1);
+                       }
+#endif
+               else
+                       {
+                       data = g_strdup(g_hash_table_lookup(vars, name));
+                       if (!data)
+                               data = metadata_read_string(fd, name, METADATA_FORMATTED);
+                       }
+
+               if (data && *data && limit > 0 && strlen(data) > limit + 3)
+                       {
+                       gchar *new_data = g_strdup_printf("%-*.*s...", limit, limit, data);
+                       g_free(data);
+                       data = new_data;
+                       }
+
+               if (data)
+                       {
+                       /* Since we use pango markup to display, we need to escape here */
+                       gchar *escaped = g_markup_escape_text(data, -1);
+                       g_free(data);
+                       data = escaped;
+                       }
+
+               if (extra)
+                       {
+                       if (data && *data)
+                               {
+                               /* Display data between left and right parts of extra string
+                                * the data is expressed by a '*' character. A '*' may be escaped
+                                * by a \. You should escape all '*' characters, do not rely on the
+                                * current implementation which only replaces the first unescaped '*'.
+                                * If no "*" is present, the extra string is just appended to data string.
+                                * Pango mark up is accepted in left and right parts.
+                                * Any \n is replaced by a newline
+                                * Examples:
+                                * "<i>*</i>\n" -> data is displayed in italics ended with a newline
+                                * "\n"         -> ended with newline
+                                * "ISO *"      -> prefix data with "ISO " (ie. "ISO 100")
+                                * "\**\*"      -> prefix data with a star, and append a star (ie. "*100*")
+                                * "\\*"        -> prefix data with an anti slash (ie "\100")
+                                * "Collection <b>*</b>\n" -> display data in bold prefixed by "Collection " and a newline is appended
+                                *
+                                * FIXME: using background / foreground colors lead to weird results.
+                                */
+                               gchar *new_data;
+                               gchar *left = NULL;
+                               gchar *right = extra;
+                               gchar *p;
+                               guint len = strlen(extra);
+
+                               /* Search for left and right parts and unescape characters */
+                               for (p = extra; *p; p++, len--)
+                                       if (p[0] == '\\')
+                                               {
+                                               if (p[1] == 'n')
+                                                       {
+                                                       memmove(p+1, p+2, --len);
+                                                       p[0] = '\n';
+                                                       }
+                                               else if (p[1] != '\0')
+                                                       memmove(p, p+1, len--); // includes \0
+                                               }
+                                       else if (p[0] == '*' && !left)
+                                               {
+                                               right = p + 1;
+                                               left = extra;
+                                               }
+
+                               if (left) right[-1] = '\0';
+
+                               new_data = g_strdup_printf("%s%s%s", left ? left : "", data, right);
+                               g_free(data);
+                               data = new_data;
+                               }
+                       g_free(extra);
+                       }
+
+               g_string_erase(new, pos, end-start+1);
+               if (data && *data)
+                       {
+                       if (want_separator)
+                               {
+                               /* insert separator */
+                               g_string_insert(new, pos, sep);
+                               pos += strlen(sep);
+                               want_separator = FALSE;
+                               }
+
+                       g_string_insert(new, pos, data);
+                       pos += strlen(data);
+               }
+
+               if (pos-prev >= 1 && new->str[pos] == imp)
+                       {
+                       /* pipe character is replaced by a separator, delete it
+                        * and raise a flag if needed */
+                       g_string_erase(new, pos--, 1);
+                       want_separator |= (data && *data);
+                       }
+
+               if (new->str[pos] == '\n') want_separator = FALSE;
+
+               prev = pos - 1;
+
+               g_free(name);
+               g_free(data);
+               }
+
+       /* search and destroy empty lines */
+       end = new->str;
+       while ((start = strchr(end, '\n')))
+               {
+               end = start;
+               while (*++(end) == '\n')
+                       ;
+               g_string_erase(new, start-new->str, end-start-1);
+               }
+
+       g_strchomp(new->str);
+
+       ret = new->str;
+       g_string_free(new, FALSE);
+
+       return ret;
+}
+
+void osd_template_insert(GHashTable *vars, gchar *keyword, gchar *value, OsdTemplateFlags flags)
+{
+       if (!value)
+               {
+               g_hash_table_insert(vars, keyword, g_strdup(""));
+               return;
+               }
+
+       if (flags & OSDT_NO_DUP)
+               {
+               g_hash_table_insert(vars, keyword, value);
+               return;
+               }
+       else
+               {
+               g_hash_table_insert(vars, keyword, g_strdup(value));
+               }
+
+       if (flags & OSDT_FREE) g_free((gpointer) value);
+}
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
diff --git a/src/osd.h b/src/osd.h
new file mode 100644 (file)
index 0000000..886359e
--- /dev/null
+++ b/src/osd.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Geeqie Team
+ *
+ * Author: Colin Clark
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef OSD_H
+#define OSD_H
+
+typedef enum {
+       OSDT_NONE       = 0,
+       OSDT_FREE       = 1 << 0,
+       OSDT_NO_DUP     = 1 << 1
+} OsdTemplateFlags;
+
+GtkWidget *osd_new(gint max_cols, GtkWidget *template_view);
+gchar *image_osd_mkinfo(const gchar *str, FileData *fd, GHashTable *vars);
+void osd_template_insert(GHashTable *vars, gchar *keyword, gchar *value, OsdTemplateFlags flags);
+#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index ae95955..b89c2c1 100644 (file)
@@ -39,6 +39,7 @@
 #include "layout_config.h"
 #include "layout_util.h"
 #include "metadata.h"
+#include "osd.h"
 #include "pixbuf_util.h"
 #include "slideshow.h"
 #include "toolbar.h"
@@ -52,8 +53,6 @@
 #include "window.h"
 #include "zonedetect.h"
 
-#include <math.h>
-
 #ifdef HAVE_LCMS
 #ifdef HAVE_LCMS2
 #include <lcms2.h>
@@ -2056,116 +2055,7 @@ static void config_tab_windows(GtkWidget *notebook)
                              options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
 }
 
-/* overlay screen display tab */
-static const gchar *predefined_tags[][2] = {
-       {"%name%",                                                      N_("Name")},
-       {"%path:60%*",                                          N_("Path")},
-       {"%date%",                                                      N_("Date")},
-       {"%size%",                                                      N_("Size")},
-       {"%zoom%",                                                      N_("Zoom")},
-       {"%dimensions%",                                        N_("Dimensions")},
-       {"%collection%",                                        N_("Collection")},
-       {"%number%",                                            N_("Collection number")},
-       {"%total%",                                                     N_("Collection total")},
-       {"%file.ctime%",                                        N_("File ctime")},
-       {"%file.mode%",                                         N_("File mode")},
-       {"%file.owner%",                                        N_("File owner")},
-       {"%file.group%",                                        N_("File group")},
-       {"%file.link%",                                         N_("File link")},
-       {"%file.class%",                                        N_("File class")},
-       {"%formatted.DateTime%",                        N_("Image date")},
-       {"%formatted.DateTimeDigitized%",       N_("Date digitized")},
-       {"%formatted.ShutterSpeed%",            N_("ShutterSpeed")},
-       {"%formatted.Aperture%",                        N_("Aperture")},
-       {"%formatted.ExposureBias%",            N_("Exposure bias")},
-       {"%formatted.Resolution%",                      N_("Resolution")},
-       {"%formatted.Camera%",                          N_("Camera")},
-       {"%formatted.ShutterSpeed%",            N_("Shutter speed")},
-       {"%formatted.ISOSpeedRating%",          N_("ISO")},
-       {"%formatted.FocalLength%",                     N_("Focal length")},
-       {"%formatted.FocalLength35mmFilm%",     N_("Focal len. 35mm")},
-       {"%formatted.SubjectDistance%",         N_("Subject distance")},
-       {"%formatted.Flash%",                           N_("Flash")},
-       {"%formatted.ColorProfile%",            N_("Color profile")},
-       {"%formatted.GPSPosition%",                     N_("Lat, Long")},
-       {"%formatted.GPSAltitude%",                     N_("Altitude")},
-       {"%formatted.localtime%",                       N_("Local time")},
-       {"%formatted.timezone%",                        N_("Timezone")},
-       {"%formatted.countryname%",                     N_("Country name")},
-       {"%formatted.countrycode%",                     N_("Country code")},
-       {"%formatted.star_rating%",                     N_("Star rating")},
-       {NULL, NULL}};
-
-static GtkTargetEntry osd_drag_types[] = {
-       { "text/plain", GTK_TARGET_SAME_APP, TARGET_TEXT_PLAIN }
-};
-
-typedef struct _TagData TagData;
-struct _TagData
-{
-       gchar *key;
-       gchar *title;
-};
-
-static void tag_button_cb(GtkWidget *widget, gpointer data)
-{
-       GtkTextView *image_overlay_template_view = data;
-       GtkTextBuffer *buffer;
-       TagData *td;
-
-       buffer = gtk_text_view_get_buffer(image_overlay_template_view);
-       td = g_object_get_data(G_OBJECT(widget), "tag_data");
-       gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(buffer), td->key, -1);
-
-       gtk_widget_grab_focus(GTK_WIDGET(image_overlay_template_view));
-}
-
-static void osd_dnd_get_cb(GtkWidget *btn, GdkDragContext *context,
-                                                               GtkSelectionData *selection_data, guint info,
-                                                               guint time, gpointer data)
-{
-       TagData *td;
-       GtkTextView *image_overlay_template_view = data;
-
-       td = g_object_get_data(G_OBJECT(btn), "tag_data");
-       gtk_selection_data_set_text(selection_data, td->key, -1);
-
-       gtk_widget_grab_focus(GTK_WIDGET(image_overlay_template_view));
-}
-
-static void osd_btn_destroy_cb(GtkWidget *btn, GdkDragContext *context,
-                                                               GtkSelectionData *selection_data, guint info,
-                                                               guint time, gpointer data)
-{
-       TagData *td;
-
-       td = g_object_get_data(G_OBJECT(btn), "tag_data");
-       g_free(td->key);
-       g_free(td->title);
-}
-
-static void set_osd_button(GtkWidget *widget, const gchar *key, const gchar *title,
-                                                                               GtkWidget *image_overlay_template_view)
-{
-       GtkWidget *new_button;
-       TagData *td;
-
-       new_button = pref_button_new(widget, NULL, _(title), TRUE,
-                                                       G_CALLBACK(tag_button_cb), image_overlay_template_view);
-
-       td = g_new0(TagData, 1);
-       td->key = g_strdup(key);
-       td->title = g_strdup(title);
-
-       g_object_set_data(G_OBJECT(new_button), "tag_data", td);
-
-       gtk_drag_source_set(new_button, GDK_BUTTON1_MASK, osd_drag_types, 1, GDK_ACTION_COPY);
-       g_signal_connect(G_OBJECT(new_button), "drag_data_get",
-                                                       G_CALLBACK(osd_dnd_get_cb), image_overlay_template_view);
-       g_signal_connect(G_OBJECT(new_button), "destroy",
-                                                       G_CALLBACK(osd_btn_destroy_cb), new_button);
-}
-
+#define PRE_FORMATTED_COLUMNS 5
 static void config_tab_osd(GtkWidget *notebook)
 {
        GtkWidget *hbox;
@@ -2175,6 +2065,7 @@ static void config_tab_osd(GtkWidget *notebook)
        GtkWidget *button;
        GtkWidget *image_overlay_template_view;
        GtkWidget *scrolled;
+       GtkWidget *scrolled_pre_formatted;
        GtkTextBuffer *buffer;
        GtkWidget *label;
        GtkWidget *     subgroup;
@@ -2188,33 +2079,13 @@ static void config_tab_osd(GtkWidget *notebook)
 
        group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
 
-       hbox = gtk_hbox_new(FALSE, 0);
-
-       gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
-       gtk_widget_show(hbox);
-
-       pref_label_new(hbox, _("To include predefined tags in the template, click a button or drag-and-drop"));
-
        subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
-       hbox = gtk_hbox_new(FALSE, 0);
-       gtk_box_pack_start(GTK_BOX(subgroup), hbox, FALSE, FALSE, 0);
-       gtk_widget_show(hbox);
-
-       for (cols = 0; cols < 6; cols++)
-               {
-               vbox_buttons = gtk_vbox_new(FALSE, 0);
-               rows = 0;
-
-               gtk_box_pack_start(GTK_BOX(hbox), vbox_buttons, FALSE, FALSE, 0);
 
-               while (rows < 6 && predefined_tags[i][0])
-                       {
-                       set_osd_button(vbox_buttons, predefined_tags[i][0], predefined_tags[i][1], image_overlay_template_view);
-                       i = i + 1;
-                       rows++;
-                       }
-               gtk_widget_show(vbox_buttons);
-               }
+       scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
+       gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
+       gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
+       gtk_widget_show(scrolled_pre_formatted);
+       gtk_widget_show(subgroup);
 
        pref_line(group, PREF_PAD_GAP);
 
index 8032ac3..516afa9 100644 (file)
@@ -24,6 +24,7 @@
 #include "exif.h"
 #include "filedata.h"
 #include "image-load.h"
+#include "osd.h"
 #include "pixbuf_util.h"
 #include "ui_misc.h"
 #include "ui_fileops.h"
 /* method to use when scaling down image data */
 #define PRINT_MAX_INTERP GDK_INTERP_HYPER
 
-typedef enum {
-       TEXT_INFO_FILENAME = 1 << 0,
-       TEXT_INFO_FILEDATE = 1 << 1,
-       TEXT_INFO_FILESIZE = 1 << 2,
-       TEXT_INFO_DIMENSIONS = 1 << 3,
-       TEXT_INFO_FILEPATH = 1 << 4
-} TextInfo;
-
 /* reverse order is important */
 typedef enum {
        FOOTER_2,
@@ -59,9 +52,10 @@ struct _PrintWindow
        GtkWidget *vbox;
        GList *source_selection;
 
-       TextInfo        text_fields;
-       gint             job_page;
+       gint job_page;
        GtkTextBuffer *page_text;
+       gchar *template_string;
+       GtkWidget *parent;
        ImageLoader     *job_loader;
 
        GList *print_pixbuf_queue;
@@ -127,63 +121,6 @@ static gboolean print_job_render_image(PrintWindow *pw)
        return TRUE;
 }
 
-static void print_text_field_set(PrintWindow *pw, TextInfo field, gboolean active)
-{
-       if (active)
-               {
-               pw->text_fields |= field;
-               }
-       else
-               {
-               pw->text_fields &= ~field;
-               }
-}
-
-static void print_text_cb_name(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-       gboolean active;
-
-       active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-       print_text_field_set(pw, TEXT_INFO_FILENAME, active);
-}
-
-static void print_text_cb_path(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-       gboolean active;
-
-       active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-       print_text_field_set(pw, TEXT_INFO_FILEPATH, active);
-}
-
-static void print_text_cb_date(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-       gboolean active;
-
-       active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-       print_text_field_set(pw, TEXT_INFO_FILEDATE, active);
-}
-
-static void print_text_cb_size(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-       gboolean active;
-
-       active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-       print_text_field_set(pw, TEXT_INFO_FILESIZE, active);
-}
-
-static void print_text_cb_dims(GtkWidget *widget, gpointer data)
-{
-       PrintWindow *pw = data;
-       gboolean active;
-
-       active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-       print_text_field_set(pw, TEXT_INFO_DIMENSIONS, active);
-}
-
 static void print_set_font_cb(GtkWidget *widget, gpointer data)
 {
        gpointer option;
@@ -371,6 +308,32 @@ static void page_text_position_f2_cb(GtkWidget *widget, gpointer data)
                }
 }
 
+static void set_print_image_text_string(gchar **template_string, const gchar *value)
+{
+       g_assert(template_string);
+
+       g_free(*template_string);
+       *template_string = g_strdup(value);
+}
+
+static void image_text_template_view_changed_cb(GtkWidget *widget, gpointer data)
+{
+       GtkWidget *pTextView;
+       GtkTextBuffer *pTextBuffer;
+       GtkTextIter iStart;
+       GtkTextIter iEnd;
+
+       pTextView = GTK_WIDGET(data);
+
+       pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
+       gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
+       gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
+
+       set_print_image_text_string(&options->printer.template_string,
+                                         gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
+}
+
+#define PRE_FORMATTED_COLUMNS 4
 static void print_text_menu(GtkWidget *box, PrintWindow *pw)
 {
        GtkWidget *group;
@@ -382,6 +345,10 @@ static void print_text_menu(GtkWidget *box, PrintWindow *pw)
        GtkWidget *page_text_button;
        GtkWidget *subgroup;
        GtkWidget *page_text_view;
+       GtkWidget *image_text_template_view;
+       GtkWidget *scrolled;
+       GtkWidget *scrolled_pre_formatted;
+       GtkTextBuffer *buffer;
 
        group = pref_group_new(box, FALSE, _("Image text"), GTK_ORIENTATION_VERTICAL);
 
@@ -411,16 +378,31 @@ static void print_text_menu(GtkWidget *box, PrintWindow *pw)
        gtk_widget_show(hbox);
        pw->image_group = (gtk_radio_button_get_group(GTK_RADIO_BUTTON(button1)));
 
-       pref_checkbox_new(subgroup, _("Name"), (pw->text_fields & TEXT_INFO_FILENAME),
-                         G_CALLBACK(print_text_cb_name), pw);
-       pref_checkbox_new(subgroup, _("Path"), (pw->text_fields & TEXT_INFO_FILEPATH),
-                         G_CALLBACK(print_text_cb_path), pw);
-       pref_checkbox_new(subgroup, _("Date"), (pw->text_fields & TEXT_INFO_FILEDATE),
-                         G_CALLBACK(print_text_cb_date), pw);
-       pref_checkbox_new(subgroup, _("Size"), (pw->text_fields & TEXT_INFO_FILESIZE),
-                         G_CALLBACK(print_text_cb_size), pw);
-       pref_checkbox_new(subgroup, _("Dimensions"), (pw->text_fields & TEXT_INFO_DIMENSIONS),
-                         G_CALLBACK(print_text_cb_dims), pw);
+       image_text_template_view = gtk_text_view_new();
+
+       scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_text_template_view);
+       gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
+       gtk_widget_show(scrolled_pre_formatted);
+       gtk_widget_show(subgroup);
+
+       gtk_widget_set_tooltip_markup(image_text_template_view,
+                                       _("Extensive formatting options are shown in the Help file"));
+
+       scrolled = gtk_scrolled_window_new(NULL, NULL);
+       gtk_widget_set_size_request(scrolled, 200, 50);
+       gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
+                                                                       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_box_pack_start(GTK_BOX(subgroup), scrolled, TRUE, TRUE, 5);
+       gtk_widget_show(scrolled);
+
+       gtk_container_add(GTK_CONTAINER(scrolled), image_text_template_view);
+       gtk_widget_show(image_text_template_view);
+
+       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_text_template_view));
+       if (options->printer.template_string) gtk_text_buffer_set_text(buffer, options->printer.template_string, -1);
+       g_signal_connect(G_OBJECT(buffer), "changed",
+                        G_CALLBACK(image_text_template_view_changed_cb), image_text_template_view);
 
        hbox = pref_box_new(subgroup, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
 
@@ -466,8 +448,6 @@ static void print_text_menu(GtkWidget *box, PrintWindow *pw)
        gtk_widget_show(hbox);
        pw->page_group = (gtk_radio_button_get_group(GTK_RADIO_BUTTON(button2)));
 
-       GtkWidget *scrolled;
-
        scrolled = gtk_scrolled_window_new(NULL, NULL);
        gtk_widget_set_size_request(scrolled, 50, 50);
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
@@ -517,6 +497,69 @@ static gboolean paginate_cb(GtkPrintOperation *operation,
                }
 }
 
+gchar *form_image_text(const gchar *template_string, FileData *fd, PrintWindow *pw, gint page_nr, gint total)
+{
+       const gchar *name;
+       gchar *text = NULL;
+       GHashTable *vars;
+       gchar *window_title;
+       gchar *delimiter;
+       gchar *collection_name;
+
+       if (!fd) return NULL;
+
+       name = fd->name;
+
+       vars = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
+
+       window_title = g_strdup(gtk_window_get_title(GTK_WINDOW(pw->parent)));
+       delimiter = g_strstr_len(window_title, -1, " - Collection - ");
+       if (delimiter)
+               {
+               collection_name = g_strndup(window_title, delimiter - window_title);
+               }
+       else
+               {
+               collection_name = NULL;
+               }
+       g_free(window_title);
+
+       if (collection_name)
+               {
+               osd_template_insert(vars, "collection", collection_name, OSDT_NONE);
+               }
+
+       osd_template_insert(vars, "number", g_strdup_printf("%d", page_nr + 1), OSDT_NO_DUP);
+       osd_template_insert(vars, "total", g_strdup_printf("%d", total), OSDT_NO_DUP);
+       osd_template_insert(vars, "name", (gchar *) name, OSDT_NONE);
+       osd_template_insert(vars, "date", fd ? ((gchar *) text_from_time(fd->date)) : "", OSDT_NONE);
+       osd_template_insert(vars, "size", fd ? (text_from_size_abrev(fd->size)) : g_strdup(""), OSDT_FREE);
+
+       if (fd->pixbuf)
+               {
+               gint w, h;
+               w = gdk_pixbuf_get_width(fd->pixbuf);
+               h = gdk_pixbuf_get_height(fd->pixbuf);
+
+               osd_template_insert(vars, "width", g_strdup_printf("%d", w), OSDT_NO_DUP);
+               osd_template_insert(vars, "height", g_strdup_printf("%d", h), OSDT_NO_DUP);
+               osd_template_insert(vars, "res", g_strdup_printf("%d × %d", w, h), OSDT_FREE);
+               }
+       else
+               {
+               osd_template_insert(vars, "width", NULL, OSDT_NONE);
+               osd_template_insert(vars, "height", NULL, OSDT_NONE);
+               osd_template_insert(vars, "res", NULL, OSDT_NONE);
+               }
+
+       text = image_osd_mkinfo(template_string, fd, vars);
+       g_hash_table_destroy(vars);
+
+       g_free(collection_name);
+
+       return text;
+}
+
 static void draw_page(GtkPrintOperation *operation, GtkPrintContext *context,
                                                                        gint page_nr, gpointer data)
 {
@@ -545,8 +588,10 @@ static void draw_page(GtkPrintOperation *operation, GtkPrintContext *context,
        gdouble pango_page_height;
        GtkTextIter start, end;
        gchar *tmp;
+       gint total;
 
        fd = g_list_nth_data(pw->source_selection, page_nr);
+       total = g_list_length(pw->source_selection);
 
        pixbuf = g_list_nth_data(pw->print_pixbuf_queue, page_nr);
        if (fd->exif_orientation != EXIF_ORIENTATION_TOP_LEFT)
@@ -560,36 +605,7 @@ static void draw_page(GtkPrintOperation *operation, GtkPrintContext *context,
 
        if (options->printer.show_image_text)
                {
-               if (pw->text_fields & TEXT_INFO_FILENAME)
-                       {
-                       image_text = g_string_append(image_text, g_strdup(fd->name));
-                       image_text = g_string_append(image_text, "\n");
-                       }
-               if (pw->text_fields & TEXT_INFO_FILEDATE)
-                       {
-                       image_text = g_string_append(image_text, g_strdup(text_from_time(fd->date)));
-                       image_text = g_string_append(image_text, "\n");
-                       }
-               if (pw->text_fields & TEXT_INFO_FILESIZE)
-                       {
-                       image_text = g_string_append(image_text, g_strdup(text_from_size(fd->size)));
-                       image_text = g_string_append(image_text, "\n");
-                       }
-               if (pw->text_fields & TEXT_INFO_DIMENSIONS)
-                       {
-                       g_string_append_printf(image_text, "%d x %d", (gint)pixbuf_image_width,
-                                                                                               (gint)pixbuf_image_height);
-                       image_text = g_string_append(image_text, "\n");
-                       }
-               if (pw->text_fields & TEXT_INFO_FILEPATH)
-                       {
-                       image_text = g_string_append(image_text, g_strdup(fd->path));
-                       image_text = g_string_append(image_text, "\n");
-                       }
-               if (image_text->len > 0)
-                       {
-                       image_text = g_string_truncate(image_text, image_text->len - 1);
-                       }
+               image_text = g_string_append(image_text, form_image_text(options->printer.template_string, fd, pw, page_nr, total));
                }
 
        if (options->printer.show_page_text)
@@ -789,8 +805,6 @@ static void print_pref_store(PrintWindow *pw)
        gchar *tmp;
        GtkTextIter start, end;
 
-       options->printer.text_fields = pw->text_fields;
-
        gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(pw->page_text), &start, &end);
        tmp = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(pw->page_text), &start, &end, FALSE);
        g_free(options->printer.page_text);
@@ -867,13 +881,14 @@ void print_window_new(FileData *fd, GList *selection, GList *list, GtkWidget *pa
        pw = g_new0(PrintWindow, 1);
 
        pw->source_selection = file_data_process_groups_in_selection(selection, FALSE, NULL);
-       pw->text_fields = options->printer.text_fields;
 
        if (print_layout_page_count(pw) == 0)
                {
                return;
                }
 
+       pw->parent = parent;
+
        vbox = gtk_vbox_new(FALSE, 0);
        gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
        gtk_widget_show(vbox);
index 6dcbae4..99794d5 100644 (file)
@@ -497,15 +497,18 @@ static void write_global_attributes(GString *outstr, gint indent)
        WRITE_NL(); WRITE_CHAR(*options, cp_mv_rn.auto_end);
        WRITE_NL(); WRITE_INT(*options, cp_mv_rn.formatted_start);
 
-       /* printer */
+       WRITE_SEPARATOR();
+
+       /* Print Text */
+       WRITE_NL(); WRITE_CHAR(*options, printer.template_string);
        WRITE_NL(); WRITE_CHAR(*options, printer.image_font);
        WRITE_NL(); WRITE_CHAR(*options, printer.page_font);
        WRITE_NL(); WRITE_CHAR(*options, printer.page_text);
-       WRITE_NL(); WRITE_INT(*options, printer.text_fields);
        WRITE_NL(); WRITE_INT(*options, printer.image_text_position);
        WRITE_NL(); WRITE_INT(*options, printer.page_text_position);
        WRITE_NL(); WRITE_BOOL(*options, printer.show_image_text);
        WRITE_NL(); WRITE_BOOL(*options, printer.show_page_text);
+       WRITE_SEPARATOR();
 }
 
 static void write_color_profile(GString *outstr, gint indent)
@@ -878,11 +881,11 @@ static gboolean load_global_params(const gchar **attribute_names, const gchar **
                if (READ_CHAR(*options, cp_mv_rn.auto_end)) continue;
                if (READ_INT(*options, cp_mv_rn.formatted_start)) continue;
 
-               /* printer */
+               /* Printer text */
+               if (READ_CHAR(*options, printer.template_string)) continue;
                if (READ_CHAR(*options, printer.image_font)) continue;
                if (READ_CHAR(*options, printer.page_font)) continue;
                if (READ_CHAR(*options, printer.page_text)) continue;
-               if (READ_INT(*options, printer.text_fields)) continue;
                if (READ_INT(*options, printer.image_text_position)) continue;
                if (READ_INT(*options, printer.page_text_position)) continue;
                if (READ_BOOL(*options, printer.show_image_text)) continue;