<guilabel>File date</guilabel>\r
</term>\r
<listitem>\r
- The search will match if the file modification time on disk is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The\r
+ The search will match if the file date is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The\r
<emphasis>between</emphasis>\r
test is inclusive, for example a file with date of 10/04/2003 will match if the date parameters are between 10/04/2003 and 12/31/2003.\r
<para />\r
</code>\r
button displays a pop up calendar to enter the date.\r
<para />\r
- The\r
- <emphasis role="strong">Exif date</emphasis>\r
- checkbox permits searches to be made on the exif date of images. If an image does not have an exif date, it will default to 01 January 1970.\r
+ One of four date types may be selected. They are described in the\r
+ <link linkend="GuideReferenceFileDates">Reference section</link>\r
+ .\r
+ <note>If an image does not have an exif date, it will default to 01 January 1970.</note>\r
</listitem>\r
</varlistentry>\r
<varlistentry>\r
</note>\r
</listitem>\r
</varlistentry>\r
+ <varlistentry>\r
+ <term>\r
+ <guilabel>Class</guilabel>\r
+ </term>\r
+ <listitem>\r
+ The search will match if the file's class is, or is not, one of the following types.\r
+ <itemizedlist>\r
+ <listitem>Unknown</listitem>\r
+ <listitem>Image</listitem>\r
+ <listitem>Raw Image</listitem>\r
+ <listitem>Video</listitem>\r
+ <listitem>Metadata</listitem>\r
+ </itemizedlist>\r
+ </listitem>\r
+ </varlistentry>\r
</variablelist>\r
<para />\r
<para />\r
</varlistentry>\r
<varlistentry>\r
<term>\r
- <guilabel>File Creation Date</guilabel>\r
+ <guilabel>File Date</guilabel>\r
</term>\r
<listitem>\r
- <para>Images are sorted by file creation date.</para>\r
+ <para>\r
+ Images are sorted by one of four types of file date. They are described in the\r
+ <link linkend="GuideReferenceFileDates">Reference section</link>\r
+ .\r
+ </para>\r
</listitem>\r
</varlistentry>\r
<varlistentry>\r
<term>\r
- <guilabel>Exif Date</guilabel>\r
+ <guilabel>Size</guilabel>\r
</term>\r
<listitem>\r
- <para>Images are sorted by file Exif date.</para>\r
+ <para>Images are sorted by file size on disk.</para>\r
</listitem>\r
</varlistentry>\r
<varlistentry>\r
<term>\r
- <guilabel>Size</guilabel>\r
+ <guilabel>Rating</guilabel>\r
</term>\r
<listitem>\r
- <para>Image are sorted by file size on disk.</para>\r
+ <para>Image are sorted by Xmp.xmp.Rating.</para>\r
+ </listitem>\r
+ </varlistentry>\r
+ <varlistentry>\r
+ <term>\r
+ <guilabel>Class</guilabel>\r
+ </term>\r
+ <listitem>\r
+ <para>Image are sorted by class. The class types, and sort order, is:</para>\r
+ <itemizedlist>\r
+ <listitem>Unknown</listitem>\r
+ <listitem>Image</listitem>\r
+ <listitem>Raw Image</listitem>\r
+ <listitem>Video</listitem>\r
+ <listitem>Metadata</listitem>\r
+ </itemizedlist>\r
</listitem>\r
</varlistentry>\r
<varlistentry>\r
</listitem>\r
</varlistentry>\r
</variablelist>\r
- <para />\r
+ <note>When images have equal rank, for example in rating or class sorts, within each section images will be sorted by filename.</note>\r
</section>\r
<section id="Filelist">\r
<title>File list</title>\r
You can pan the view as you pan an image in normal view mode, using left mouse button and drag.\r
</para>\r
<para>A primary mouse button click on any image will display informations about the image. Secondary mouse button will show a context menu.</para>\r
+ <para>\r
+ The\r
+ <link linkend="GuideReferenceKeyboardShortcuts" endterm="titleGuideReferenceKeyboardShortcuts" />\r
+ available are listed in the Reference section.\r
+ </para>\r
<note>\r
<para>Pan view recursively visits each folder under the specified folder. This can consume considerable computer resources.</para>\r
</note>\r
</varlistentry>\r
</variablelist>\r
</section>\r
-</section>
+</section>\r
[ "x$ext" = "x" ] && return 1 #no extension
gq_metadata="$GQ_METADATA_DIR/$1.gq.xmp"
- if [ -f "$gq_metadata" ]; then
- gq_orientation=`exiv2 -PXkv "$gq_metadata"|grep Xmp.tiff.Orientation|sed -e "s|Xmp.tiff.Orientation *||"`
+ if [ -f "$gq_metadata" ] ; then
+ gq_orientation=`exiv2 -PXkv "$gq_metadata"|grep Xmp.tiff.Orientation|sed -e "s|Xmp.tiff.Orientation *||"`
+ [ $? != 0 ] && exit 1
else
- gq_orientation=
+ gq_orientation=
fi
case "$ext" in
jpg|jpeg)
- [ -n "$gq_orientation" ] && exiv2 -M "set Exif.Image.Orientation $gq_orientation" "$1"
+ if [ -n "$gq_orientaqtion" ] ; then
+ exiv2 -M "set Exif.Image.Orientation $gq_orientation" "$1"
+ [ $? != 0 ] && exit 1
+ fi
if exiftran -aip "$1" ; then
# exiftran ignores xmp, set it manually
exiv2 -M "set Xmp.tiff.Orientation 1" "$1"
+ [ $? != 0 ] && exit 1
#http://dev.exiv2.org/issues/show/639
- [ -n "$gq_orientation" ] && exiv2 -M "set Xmp.tiff.Orientation 1" \
- -M "set Exif.Image.Orientation 1" "$gq_metadata"
+ if [ -n "$gq_orientation" ] ; then
+ exiv2 -M "set Xmp.tiff.Orientation 1" \
+ -M "set Exif.Image.Orientation 1" "$gq_metadata"
+ [ $? != 0 ] && exit 1
+ fi
return 0
+ else
+ exit 1
fi
;;
tif|tiff|png)
- [ -n "$gq_orientation" ] && exiv2 -M "set Exif.Image.Orientation $gq_orientation" "$1"
+ if [ -n "$gq_orientation" ] ; then
+ exiv2 -M "set Exif.Image.Orientation $gq_orientation" "$1"
+ [ $? != 0 ] && exit 1
+ fi
if mogrify -auto-orient "$1" ; then
# mogrify ignores xmp, set it manually
exiv2 -M "set Xmp.tiff.Orientation 1" "$1"
+ [ $? != 0 ] && exit 1
#http://dev.exiv2.org/issues/show/639
- [ -n "$gq_orientation" ] && exiv2 -M "set Xmp.tiff.Orientation 1" \
- -M "set Exif.Image.Orientation 1" "$gq_metadata"
+ if [ -n "$gq_orientation" ] ; then
+ exiv2 -M "set Xmp.tiff.Orientation 1" \
+ -M "set Exif.Image.Orientation 1" "$gq_metadata"
+ [ $? != 0 ] && exit 1
+ fi
return 0
+ else
+ exit 1
fi
;;
*) #not supported
- return 0
+ return 4
;;
esac
}
rotate_image_file()
{
ext=`echo "${3##*.}" |tr "[:upper:]" "[:lower:]"`
- [ "x$ext" = "x" ] && return 4 #no extension
+ [ "x$ext" = "x" ] && return 1 #no extension
case "$ext" in
jpg|jpeg)
exiftran -i "$1" "$3"
- return 0
+ [ $? != 0 ] && return 6
+ return 0;
;;
tif|tiff|png)
mogrify $2 "$3"
- return 0
+ [ $? != 0 ] && return 7
+ return 0;
;;
*) #not supported
# get the sidecars:
geeqie -r --get-sidecars:"$file" |while read sidecar ; do
# the main file is included in the sidecar file list, no special handling is required
+ [ ! -w "$sidecar" ] && exit 5
rotate "$sidecar"
+ ret=$?
done
+ # Bourne shell runs DO loops in a sub-shell
+ ret=$?
+ [ $ret != 0 ] && exit $ret
else
+ [ ! -w "$file" ] && exit 5
if [ -n "$rotate_image_file" ] ; then
if [ -n "$preserve_mtime" ] ; then
mtime=`mktemp /tmp/geeqie-rotate.XXXXXXXXXX` || exit 3
touch --reference="$mtime" "$file"
rm "$mtime"
fi
- if [ $ret -eq 4 ] ; then
- exit 4
- fi
+ [ $ret != 0 ] && exit $ret
else
rotate "$file"
+ ret=$?
+ [ $ret != 0 ] && exit $ret
fi
fi
done
+exit 0
echo '#ifndef UI_ICONS_H'; \
echo '#define UI_ICONS_H'; echo; \
$(GDK_PIXBUF_CSOURCE) --raw --extern --build-list $(ICON_PAIRS); \
- echo '#endif /* UI_ICONS_H */'" > $@ || echo "!!! Failed to generate $@ !!!"
+ echo '#endif /* UI_ICONS_H */'" > $@ || { echo "!!! Failed to generate $@ !!!"; exit 1; }
ClayRGB1998_icc.h: ClayRGB1998.icc
echo "/*" > $@
#include "metadata.h"
#include "filedata.h"
#include "history_list.h"
+#include "layout_util.h"
#include "misc.h"
#include "ui_misc.h"
#include "window.h"
break;
}
} // if (event->state & GDK_CONTROL...
+ if (!stop_signal && is_help_key(event))
+ {
+ help_window_show("GuideOtherWindowsExif.html");
+ stop_signal = TRUE;
+ }
return stop_signal;
} // static gboolean advanced_exif_...
#include "img-view.h"
#include "layout.h"
#include "layout_image.h"
+#include "layout_util.h"
#include "misc.h"
#include "pixbuf_util.h"
#include "print.h"
if (cia->fd->cdate > cib->fd->cdate) return 1;
return 0;
break;
+ case SORT_EXIFTIME:
+ if (cia->fd->exifdate < cib->fd->exifdate) return -1;
+ if (cia->fd->exifdate > cib->fd->exifdate) return 1;
+ break;
+ case SORT_EXIFTIMEDIGITIZED:
+ if (cia->fd->exifdate_digitized < cib->fd->exifdate_digitized) return -1;
+ if (cia->fd->exifdate_digitized > cib->fd->exifdate_digitized) return 1;
+ break;
+ case SORT_RATING:
+ if (cia->fd->rating < cib->fd->rating) return -1;
+ if (cia->fd->rating > cib->fd->rating) return 1;
+ break;
case SORT_PATH:
return utf8_compare(cia->fd->path, cib->fd->path, options->file_sort.case_sensitive);
break;
+ case SORT_CLASS:
+ if (cia->fd->format_class < cib->fd->format_class) return -1;
+ if (cia->fd->format_class > cib->fd->format_class) return 1;
+ break;
#ifdef HAVE_STRVERSCMP
case SORT_NUMBER:
return strverscmp(cia->fd->name, cib->fd->name);
collection_remove_by_info(cw->cd, collection_table_get_focus_info(cw->table));
}
break;
- case GDK_KEY_F1:
- help_window_show("GuideReferenceKeyboardShortcuts.html#CollectionsKeyboardShortcuts");
- break;
default:
stop_signal = FALSE;
break;
}
}
+ if (!stop_signal && is_help_key(event))
+ {
+ help_window_show("GuideCollections.html");
+ stop_signal = TRUE;
+ }
+
return stop_signal;
}
cmsUInt32Number r;
char buffer[20];
buffer[0] = '\0';
- r = cmsGetProfileInfoASCII(profile, cmsInfoDescription, "en", "US", buffer, 20);
+ cmsGetProfileInfoASCII(profile, cmsInfoDescription, "en", "US", buffer, 20);
buffer[19] = '\0'; /* Just to be sure */
return g_strdup(buffer);
#else
#include "img-view.h"
#include "layout.h"
#include "layout_image.h"
+#include "layout_util.h"
#include "md5-util.h"
#include "menu.h"
#include "misc.h"
submenu_add_edit(menu, &item, G_CALLBACK(dupe_menu_edit_cb), dw, editmenu_fd_list);
if (!on_row) gtk_widget_set_sensitive(item, FALSE);
- submenu = submenu_add_collections(menu, &item,
+ submenu_add_collections(menu, &item,
G_CALLBACK(dupe_pop_menu_collections_cb), dw);
gtk_widget_set_sensitive(item, on_row);
dupe_popup_menu_pos_cb, listview, 0, GDK_CURRENT_TIME);
}
break;
- case GDK_KEY_F1:
- help_window_show("GuideReferenceKeyboardShortcuts.html#DuplicatesKeyboardShortcuts");
- break;
default:
stop_signal = FALSE;
break;
}
}
+ if (!stop_signal && is_help_key(event))
+ {
+ help_window_show("GuideImageSearchFindingDuplicates.html");
+ stop_signal = TRUE;
+ }
return stop_signal;
}
return text;
}
+static gchar *exif_build_formatted_DateTimeDigitized(ExifData *exif)
+{
+ gchar *text = exif_get_data_as_text(exif, "Exif.Photo.DateTimeDigitized");
+ gchar *subsec = NULL;
+ gchar buf[128];
+ gchar *tmp;
+ gint buflen;
+ struct tm tm;
+ GError *error = NULL;
+
+ if (text)
+ {
+ subsec = exif_get_data_as_text(exif, "Exif.Photo.SubSecTimeDigitized");
+ }
+ else
+ {
+ text = exif_get_data_as_text(exif, "Exif.Image.DateTime");
+ if (text) subsec = exif_get_data_as_text(exif, "Exif.Photo.SubSecTime");
+ }
+
+ /* Convert the stuff into a tm struct */
+ memset(&tm, 0, sizeof(tm)); /* Uh, strptime could let garbage in tm! */
+ if (text && strptime(text, "%Y:%m:%d %H:%M:%S", &tm))
+ {
+ buflen = strftime(buf, sizeof(buf), "%x %X", &tm);
+ if (buflen > 0)
+ {
+ tmp = g_locale_to_utf8(buf, buflen, NULL, NULL, &error);
+ if (error)
+ {
+ log_printf("Error converting locale strftime to UTF-8: %s\n", error->message);
+ g_error_free(error);
+ }
+ else
+ {
+ g_free(text);
+ text = g_strdup(tmp);
+ }
+ }
+ }
+
+ if (subsec)
+ {
+ tmp = text;
+ text = g_strconcat(tmp, ".", subsec, NULL);
+ g_free(tmp);
+ g_free(subsec);
+ }
+ return text;
+}
+
static gchar *exif_build_formatted_ShutterSpeed(ExifData *exif)
{
ExifRational *r;
ExifFormattedText ExifFormattedList[] = {
EXIF_FORMATTED_TAG(Camera, N_("Camera")),
EXIF_FORMATTED_TAG(DateTime, N_("Date")),
+ EXIF_FORMATTED_TAG(DateTimeDigitized, N_("DateDigitized")),
EXIF_FORMATTED_TAG(ShutterSpeed, N_("Shutter speed")),
EXIF_FORMATTED_TAG(Aperture, N_("Aperture")),
EXIF_FORMATTED_TAG(ExposureBias, N_("Exposure bias")),
}
}
+void read_exif_time_digitized_data(FileData *file)
+{
+ if (file->exifdate > 0)
+ {
+ DEBUG_1("%s set_exif_time_digitized_data: Already exists for %s", get_exec_time(), file->path);
+ return;
+ }
+
+ file->exif = exif_read_fd(file);
+
+ if (file->exif)
+ {
+ gchar *tmp = exif_get_data_as_text(file->exif, "Exif.Photo.DateTimeDigitized");
+ DEBUG_2("%s set_exif_time_digitized_data: reading %p %s", get_exec_time(), file, file->path);
+
+ if (tmp)
+ {
+ struct tm time_str;
+ uint year, month, day, hour, min, sec;
+
+ sscanf(tmp, "%4d:%2d:%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
+ time_str.tm_year = year - 1900;
+ time_str.tm_mon = month - 1;
+ time_str.tm_mday = day;
+ time_str.tm_hour = hour;
+ time_str.tm_min = min;
+ time_str.tm_sec = sec;
+ time_str.tm_isdst = 0;
+
+ file->exifdate_digitized = mktime(&time_str);
+ g_free(tmp);
+ }
+ }
+}
+
void set_exif_time_data(GList *files)
{
DEBUG_1("%s set_exif_time_data: ...", get_exec_time());
}
}
+void set_exif_time_digitized_data(GList *files)
+{
+ DEBUG_1("%s set_exif_time_digitized_data: ...", get_exec_time());
+
+ while (files)
+ {
+ FileData *file = files->data;
+
+ read_exif_time_digitized_data(file);
+ files = files->next;
+ }
+}
+
void set_rating_data(GList *files)
{
gchar *rating_str;
if (fa->exifdate > fb->exifdate) return 1;
/* fall back to name */
break;
+ case SORT_EXIFTIMEDIGITIZED:
+ if (fa->exifdate_digitized < fb->exifdate_digitized) return -1;
+ if (fa->exifdate_digitized > fb->exifdate_digitized) return 1;
+ /* fall back to name */
+ break;
case SORT_RATING:
if (fa->rating < fb->rating) return -1;
if (fa->rating > fb->rating) return 1;
/* fall back to name */
break;
+ case SORT_CLASS:
+ if (fa->format_class < fb->format_class) return -1;
+ if (fa->format_class > fb->format_class) return 1;
+ /* fall back to name */
+ break;
#ifdef HAVE_STRVERSCMP
case SORT_NUMBER:
ret = strverscmp(fa->name, fb->name);
{
set_exif_time_data(list);
}
+ if (method == SORT_EXIFTIMEDIGITIZED)
+ {
+ set_exif_time_digitized_data(list);
+ }
if (method == SORT_RATING)
{
set_rating_data(list);
gboolean file_data_unregister_real_time_monitor(FileData *fd);
void read_exif_time_data(FileData *file);
+void read_exif_time_digitized_data(FileData *file);
#endif
/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
#include "image-overlay.h"
#include "layout.h"
#include "layout_image.h"
+#include "layout_util.h"
#include "menu.h"
#include "misc.h"
#include "pixbuf_util.h"
break;
}
}
+ if (!stop_signal && is_help_key(event))
+ {
+ help_window_show("GuideOtherWindowsImageWindow.html");
+ stop_signal = TRUE;
+ }
return stop_signal;
}
menu_item_add_divider(menu);
- submenu = submenu_add_collections(menu, &item,
+ submenu_add_collections(menu, &item,
G_CALLBACK(image_pop_menu_collections_cb), vw);
gtk_widget_set_sensitive(item, TRUE);
menu_item_add_divider(menu);
{
if (!layout_valid(&lw)) return FALSE;
- if(!lw->options.animate || lw->image->image_fd == NULL)
+ if(!lw->options.animate || lw->image->image_fd == NULL || lw->image->image_fd->extension == NULL || g_ascii_strcasecmp(lw->image->image_fd->extension,".GIF")!=0)
{
if(lw->animation)
{
rotation = g_strdup_printf("%d", fd_n->user_orientation);
command = g_strconcat(GQ_BIN_DIR, "/geeqie-rotate -r ", rotation,
- keep_date ? " -t " : " ", fd_n->path, NULL);
-
+ keep_date ? " -t \"" : " \"", fd_n->path, "\"", NULL);
run_result = WEXITSTATUS(runcmd(command));
if (!run_result)
{
message = g_string_new("");
message = g_string_append(message, _("Operation failed:\n"));
- if (run_result == 3)
- message = g_string_append(message, _("Cannot create tmp file"));
- else
- {
- message = g_string_append(message, _("File: "));
- message = g_string_append(message, fd_n->name);
- }
+ if (run_result == 1)
+ message = g_string_append(message, _("No file extension\n"));
+ else if (run_result == 3)
+ message = g_string_append(message, _("Cannot create tmp file\n"));
+ else if (run_result == 4)
+ message = g_string_append(message, _("Operation not supported for filetype\n"));
+ else if (run_result == 5)
+ message = g_string_append(message, _("File is not writable\n"));
+ else if (run_result == 6)
+ message = g_string_append(message, _("Exiftran error\n"));
+ else if (run_result == 7)
+ message = g_string_append(message, _("Mogrify error\n"));
+
+ message = g_string_append(message, fd_n->name);
gd = generic_dialog_new(_("Image orientation"),
"Image orientation", NULL, TRUE, NULL, NULL);
// layout_menu_edit_update(lw);
}
+/**
+ * @brief Checks if event key is mapped to Help
+ * @param event
+ * @returns
+ *
+ * Used to check if the user has re-mapped the Help key
+ * in Preferences/Keyboard
+ *
+ * Note: help_key.accel_mods and event->state
+ * differ in the higher bits
+ */
+gboolean is_help_key(GdkEventKey *event)
+{
+ GtkAccelKey help_key;
+ gboolean ret = FALSE;
+ guint mask = GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK;
+
+ if (gtk_accel_map_lookup_entry("<Actions>/MenuActions/HelpContents", &help_key))
+ {
+ if (help_key.accel_key == event->keyval &&
+ (help_key.accel_mods & mask) == (event->state & mask))
+ {
+ ret = TRUE;
+ }
+ }
+
+ return ret;
+}
/*
*-----------------------------------------------------------------------------
void layout_exif_window_new(LayoutWindow *lw);
+gboolean is_help_key(GdkEventKey *event);
+
#endif
/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
lua_pushnil(L);
return 1;
}
- } // if (strcmp(key, "Exif.Photo.Da...
+ }
+ else if (strcmp(key, "Exif.Photo.DateTimeDigitized") == 0)
+ {
+ memset(&tm, 0, sizeof(tm));
+ if (value && strptime(value, "%Y:%m:%d %H:%M:%S", &tm))
+ {
+ datetime = mktime(&tm);
+ lua_pushnumber(L, datetime);
+ return 1;
+ }
+ else
+ {
+ lua_pushnil(L);
+ return 1;
+ }
+ }
lua_pushstring(L, value);
return 1;
}
return _("Sort by file creation date");
break;
case SORT_EXIFTIME:
- return _("Sort by Exif-date");
+ return _("Sort by Exif date original");
+ break;
+ case SORT_EXIFTIMEDIGITIZED:
+ return _("Sort by Exif date digitized");
break;
case SORT_NONE:
return _("Unsorted");
case SORT_RATING:
return _("Sort by rating");
break;
+ case SORT_CLASS:
+ return _("Sort by class");
+ break;
case SORT_NAME:
default:
return _("Sort by name");
submenu_add_sort_item(submenu, func, SORT_TIME, show_current, type);
submenu_add_sort_item(submenu, func, SORT_CTIME, show_current, type);
submenu_add_sort_item(submenu, func, SORT_EXIFTIME, show_current, type);
+ submenu_add_sort_item(submenu, func, SORT_EXIFTIMEDIGITIZED, show_current, type);
submenu_add_sort_item(submenu, func, SORT_SIZE, show_current, type);
submenu_add_sort_item(submenu, func, SORT_RATING, show_current, type);
+ submenu_add_sort_item(submenu, func, SORT_CLASS, show_current, type);
if (include_path) submenu_add_sort_item(submenu, func, SORT_PATH, show_current, type);
if (include_none) submenu_add_sort_item(submenu, func, SORT_NONE, show_current, type);
{
const gchar *collection_name = work->data;
- item = menu_item_add(menu, collection_name, func,
+ menu_item_add(menu, collection_name, func,
GINT_TO_POINTER(index));
work = work->next;
index++;
#include "history_list.h"
#include "image.h"
#include "img-view.h"
+#include "layout_util.h"
#include "menu.h"
#include "metadata.h"
#include "misc.h"
case '/':
pan_search_toggle_visible(pw, TRUE);
break;
- case GDK_KEY_F1:
- help_window_show("GuideReferenceKeyboardShortcuts.html#PanViewKeyboardShortcuts");
- break;
- default:
stop_signal = FALSE;
break;
}
}
}
+ if (!stop_signal && is_help_key(event))
+ {
+ help_window_show("GuideOtherWindowsPanView.html");
+ stop_signal = TRUE;
+ }
return stop_signal;
}
gint x_scroll; /* allow local adjustment and mirroring */
gint y_scroll;
+ gint hidpi_scale;
};
return PR_TILE_SIZE * PR_TILE_SIZE * 4 / 8;
}
+static void rt_hidpi_aware_draw(
+ RendererTiles *rt,
+ cairo_t *cr,
+ GdkPixbuf *pixbuf,
+ double x,
+ double y)
+{
+#if GTK_CHECK_VERSION(3, 10, 0)
+ cairo_surface_t *surface;
+ surface = gdk_cairo_surface_create_from_pixbuf(pixbuf, rt->hidpi_scale, NULL);
+ cairo_set_source_surface(cr, surface, x, y);
+ cairo_fill(cr);
+ cairo_surface_destroy(surface);
+#else
+ gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
+ cairo_fill(cr);
+#endif
+}
+
static void rt_tile_prepare(RendererTiles *rt, ImageTile *it)
{
PixbufRenderer *pr = rt->pr;
CAIRO_CONTENT_COLOR,
rt->tile_width, rt->tile_height);
- size = pixmap_calc_size(surface);
+ size = pixmap_calc_size(surface) * rt->hidpi_scale * rt->hidpi_scale;
rt_tile_free_space(rt, size, it);
it->surface = surface;
{
GdkPixbuf *pixbuf;
guint size;
- pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width, rt->tile_height);
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->hidpi_scale * rt->tile_width, rt->hidpi_scale * rt->tile_height);
- size = gdk_pixbuf_get_rowstride(pixbuf) * rt->tile_height;
+ size = gdk_pixbuf_get_rowstride(pixbuf) * rt->tile_height * rt->hidpi_scale;
rt_tile_free_space(rt, size, it);
it->pixbuf = pixbuf;
cairo_fill_preserve(cr);
gdk_cairo_set_source_pixbuf(cr, od->pixbuf, px - rx, py - ry);
- cairo_fill (cr);
+ cairo_fill(cr);
cairo_destroy (cr);
cr = gdk_cairo_create(od->window);
static GdkPixbuf *rt_get_spare_tile(RendererTiles *rt)
{
- if (!rt->spare_tile) rt->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width, rt->tile_height);
+ if (!rt->spare_tile) rt->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width * rt->hidpi_scale, rt->tile_height * rt->hidpi_scale);
return rt->spare_tile;
}
guchar *sp, *dp;
guchar *ip, *spi, *dpi;
gint i, j;
- gint tw = rt->tile_width;
+ gint tw = rt->tile_width * rt->hidpi_scale;
srs = gdk_pixbuf_get_rowstride(src);
s_pix = gdk_pixbuf_get_pixels(src);
guchar *sp, *dp;
guchar *ip, *spi, *dpi;
gint i, j;
- gint th = rt->tile_height;
+ gint th = rt->tile_height * rt->hidpi_scale;
srs = gdk_pixbuf_get_rowstride(src);
s_pix = gdk_pixbuf_get_pixels(src);
guchar *spi, *dpi;
gint i, j;
- gint tw = rt->tile_width;
+ gint tw = rt->tile_width * rt->hidpi_scale;
srs = gdk_pixbuf_get_rowstride(src);
s_pix = gdk_pixbuf_get_pixels(src);
guchar *sp, *dp;
guchar *dpi;
gint i, j;
- gint tw = rt->tile_width;
- gint th = rt->tile_height;
+ gint tw = rt->tile_width * rt->hidpi_scale;
+ gint th = rt->tile_height * rt->hidpi_scale;
srs = gdk_pixbuf_get_rowstride(src);
s_pix = gdk_pixbuf_get_pixels(src);
guchar *sp, *dp;
guchar *spi, *dpi;
gint i;
- gint th = rt->tile_height;
+ gint th = rt->tile_height * rt->hidpi_scale;
srs = gdk_pixbuf_get_rowstride(src);
s_pix = gdk_pixbuf_get_pixels(src);
if (st->blank)
{
cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_fill (cr);
}
else /* (pr->zoom == 1.0 || pr->scale == 1.0) */
{
- gdk_cairo_set_source_pixbuf(cr, st->pixbuf, -it->x + st->x, -it->y + st->y);
+ rt_hidpi_aware_draw(rt, cr, st->pixbuf, -it->x + st->x, -it->y + st->y);
}
- cairo_fill (cr);
cairo_destroy (cr);
}
}
if (pr->image_width == 0 || pr->image_height == 0) return;
- scale_x = (gdouble)pr->width / pr->image_width;
- scale_y = (gdouble)pr->height / pr->image_height;
+ scale_x = rt->hidpi_scale * (gdouble)pr->width / pr->image_width;
+ scale_y = rt->hidpi_scale * (gdouble)pr->height / pr->image_height;
pr_tile_coords_map_orientation(orientation, it->x, it->y,
pr->width, pr->height,
&pb_x, &pb_y,
&pb_w, &pb_h);
+ src_x *= rt->hidpi_scale;
+ src_y *= rt->hidpi_scale;
+ pb_x *= rt->hidpi_scale;
+ pb_y *= rt->hidpi_scale;
+ pb_w *= rt->hidpi_scale;
+ pb_h *= rt->hidpi_scale;
+
switch (orientation)
{
gdouble tmp;
cr = cairo_create(it->surface);
cairo_rectangle (cr, x, y, w, h);
- gdk_cairo_set_source_pixbuf(cr, it->pixbuf, 0, 0);
- cairo_fill (cr);
+ rt_hidpi_aware_draw(rt, cr, it->pixbuf, 0, 0);
cairo_destroy (cr);
}
}
rt->stereo_off_x = 0;
rt->stereo_off_y = 0;
+#if GTK_CHECK_VERSION(3, 10, 0)
+ rt->hidpi_scale = gtk_widget_get_scale_factor(GTK_WIDGET(rt->pr));
+#else
+ rt->hidpi_scale = 1;
+#endif
+
g_signal_connect(G_OBJECT(pr), "hierarchy-changed",
G_CALLBACK(rt_hierarchy_changed_cb), rt);
g_signal_connect(G_OBJECT(pr), "expose_event",
G_CALLBACK(rt_expose_cb), rt);
#endif
+
return (RendererFuncs *) rt;
}
#include "image-load.h"
#include "img-view.h"
#include "layout.h"
+#include "layout_util.h"
#include "math.h"
#include "menu.h"
#include "metadata.h"
GtkWidget *menu_date;
GtkWidget *date_sel;
GtkWidget *date_sel_end;
+ GtkWidget *date_type;
GtkWidget *check_dimensions;
GtkWidget *menu_dimensions;
GtkWidget *spin_rating;
GtkWidget *spin_rating_end;
+ GtkWidget *check_class;
+ GtkWidget *menu_class;
+ GtkWidget *class_type;
+
FileData *search_dir_fd;
gboolean search_path_recurse;
gchar *search_name;
gint search_rating;
gint search_rating_end;
gboolean search_comment_match_case;
- gboolean search_date_exif;
MatchType search_type;
MatchType match_comment;
MatchType match_rating;
MatchType match_gps;
+ MatchType match_class;
gboolean match_name_enable;
gboolean match_size_enable;
gboolean match_keywords_enable;
gboolean match_comment_enable;
gboolean match_rating_enable;
+ gboolean match_class_enable;
GList *search_folder_list;
GList *search_done_list;
{ N_("greater than"), SEARCH_MATCH_OVER }
};
+static const MatchList text_search_menu_class[] = {
+ { N_("is"), SEARCH_MATCH_EQUAL },
+ { N_("is not"), SEARCH_MATCH_NONE }
+};
+
static GList *search_window_list = NULL;
submenu_add_edit(menu, &item, G_CALLBACK(sr_menu_edit_cb), sd, editmenu_fd_list);
if (!on_row) gtk_widget_set_sensitive(item, FALSE);
- submenu = submenu_add_collections(menu, &item,
+ submenu_add_collections(menu, &item,
G_CALLBACK(search_pop_menu_collections_cb), sd);
gtk_widget_set_sensitive(item, on_row);
search_result_menu_pos_cb, sd, 0, GDK_CURRENT_TIME);
}
break;
- case GDK_KEY_F1:
- help_window_show("GuideReferenceKeyboardShortcuts.html#SearchKeyboardShortcuts");
- break;
default:
stop_signal = FALSE;
break;
break;
}
}
+ if (!stop_signal && is_help_key(event))
+ {
+ help_window_show("GuideImageSearchSearch.html");
+ stop_signal = TRUE;
+ }
return stop_signal;
}
tested = TRUE;
match = FALSE;
- if (sd->search_date_exif)
+ if (g_strcmp0(gtk_combo_box_text_get_active_text(
+ GTK_COMBO_BOX_TEXT(sd->date_type)), _("Changed")) == 0)
+ {
+ file_date = fd->cdate;
+ }
+ else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+ GTK_COMBO_BOX_TEXT(sd->date_type)), _("Original")) == 0)
{
read_exif_time_data(fd);
file_date = fd->exifdate;
}
+ else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+ GTK_COMBO_BOX_TEXT(sd->date_type)), _("Digitized")) == 0)
+ {
+ read_exif_time_digitized_data(fd);
+ file_date = fd->exifdate_digitized;
+ }
else
{
file_date = fd->date;
}
}
+ if (match && sd->match_class_enable)
+ {
+ tested = TRUE;
+ match = FALSE;
+ gint class;
+ FileFormatClass search_class;
+
+ if (g_strcmp0(gtk_combo_box_text_get_active_text(
+ GTK_COMBO_BOX_TEXT(sd->class_type)), _("Image")) == 0)
+ {
+ search_class = FORMAT_CLASS_IMAGE;
+ }
+ else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+ GTK_COMBO_BOX_TEXT(sd->class_type)), _("Raw Image")) == 0)
+ {
+ search_class = FORMAT_CLASS_RAWIMAGE;
+ }
+ else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+ GTK_COMBO_BOX_TEXT(sd->class_type)), _("Video")) == 0)
+ {
+ search_class = FORMAT_CLASS_VIDEO;
+ }
+ else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+ GTK_COMBO_BOX_TEXT(sd->class_type)), _("Metadata")) == 0)
+ {
+ search_class = FORMAT_CLASS_META;
+ }
+ else
+ {
+ search_class = FORMAT_CLASS_UNKNOWN;
+ }
+
+ class = fd->format_class;
+ if (sd->match_class == SEARCH_MATCH_EQUAL)
+ {
+ match = (class == search_class);
+ }
+ else if (sd->match_class == SEARCH_MATCH_NONE)
+ {
+ match = (class != search_class);
+ }
+ }
+
if (match && sd->match_gps_enable)
{
/* Calculate the distance the image is from the specified origin.
(sd->match_rating == SEARCH_MATCH_BETWEEN));
}
+static void menu_choice_class_cb(GtkWidget *combo, gpointer data)
+{
+ SearchData *sd = data;
+
+ if (!menu_choice_get_match_type(combo, &sd->match_class)) return;
+}
+
static void menu_choice_date_cb(GtkWidget *combo, gpointer data)
{
SearchData *sd = data;
sd->match_keywords = SEARCH_MATCH_ALL;
sd->match_comment = SEARCH_MATCH_CONTAINS;
sd->match_rating = SEARCH_MATCH_EQUAL;
+ sd->match_class = SEARCH_MATCH_EQUAL;
sd->match_name_enable = TRUE;
_("File date is"), &sd->match_date_enable,
text_search_menu_date, sizeof(text_search_menu_date) / sizeof(MatchList),
G_CALLBACK(menu_choice_date_cb), sd);
+
sd->date_sel = date_selection_new();
date_selection_time_set(sd->date_sel, time(NULL));
gtk_box_pack_start(GTK_BOX(hbox), sd->date_sel, FALSE, FALSE, 0);
date_selection_time_set(sd->date_sel_end, time(NULL));
gtk_box_pack_start(GTK_BOX(hbox2), sd->date_sel_end, FALSE, FALSE, 0);
gtk_widget_show(sd->date_sel_end);
- pref_checkbox_new_int(hbox, _("Exif date"),
- sd->search_date_exif, &sd->search_date_exif);
+
+ sd->date_type = gtk_combo_box_text_new();
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Modified"));
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Status Changed"));
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Original"));
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Digitized"));
+ gtk_box_pack_start(GTK_BOX(hbox), sd->date_type, FALSE, FALSE, 0);
+ gtk_combo_box_set_active(GTK_COMBO_BOX(sd->date_type), 0);
+ gtk_widget_set_tooltip_text(sd->date_type, "Modified (mtime)\nStatus Changed (ctime)\nOriginal (Exif.Photo.DateTimeOriginal)\nDigitized (Exif.Photo.DateTimeDigitized)");
+ gtk_widget_show(sd->date_type);
/* Search for image dimensions */
hbox = menu_choice(sd->box_search, &sd->check_dimensions, &sd->menu_dimensions,
gtk_widget_show(sd->entry_gps_coord);
+ /* Search for image class */
+ hbox = menu_choice(sd->box_search, &sd->check_class, &sd->menu_class,
+ _("Image class"), &sd->match_class_enable,
+ text_search_menu_class, sizeof(text_search_menu_class) / sizeof(MatchList),
+ G_CALLBACK(menu_choice_class_cb), sd);
+
+ sd->class_type = gtk_combo_box_text_new();
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Image"));
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Raw Image"));
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Video"));
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Metadata"));
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Unknown"));
+ gtk_box_pack_start(GTK_BOX(hbox), sd->class_type, FALSE, FALSE, 0);
+ gtk_combo_box_set_active(GTK_COMBO_BOX(sd->class_type), 0);
+ gtk_widget_show(sd->class_type);
+
/* Done the types of searches */
scrolled = gtk_scrolled_window_new(NULL, NULL);
SORT_PATH,
SORT_NUMBER,
SORT_EXIFTIME,
- SORT_RATING
+ SORT_EXIFTIMEDIGITIZED,
+ SORT_RATING,
+ SORT_CLASS
} SortType;
typedef enum {
ExifData *exif;
time_t exifdate;
+ time_t exifdate_digitized;
GHashTable *modified_xmp; // hash table which contains unwritten xmp metadata in format: key->list of string values
GList *cached_metadata;
gint rating;
if (event->keyval == GDK_KEY_Escape)
{
- if (gd->cancel_cb) gd->cancel_cb(gd, gd->data);
- else if (auto_close) generic_dialog_click_cb(widget, data);
+ if (gd->cancel_cb)
+ {
+ gd->cancel_cb(gd, gd->data);
+ if (auto_close) generic_dialog_close(gd);
+ }
+ else
+ {
+ if (auto_close) generic_dialog_click_cb(widget, data);
+ }
return TRUE;
}
return FALSE;
<span class="guilabel">File date</span>
</dt>
<dd>
- The search will match if the file modification time on disk is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
+ The search will match if the file date is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
<span class="emphasis">between</span>
test is inclusive, for example a file with date of 10/04/2003 will match if the date parameters are between 10/04/2003 and 12/31/2003.
<p class="para block"></p>
</span>
button displays a pop up calendar to enter the date.
<p class="para block"></p>
- The
- <span class="emphasis emphasis-bold">Exif date</span>
- checkbox permits searches to be made on the exif date of images. If an image does not have an exif date, it will default to 01 January 1970.
+ One of four date types may be selected. They are described in the
+ <a class="link" href=".html#GuideReferenceFileDates" title="">Reference section</a>
+ .
+ <div class="admonition block note block-indent"><div class="note-inner">If an image does not have an exif date, it will default to 01 January 1970.</div></div>
</dd>
<dt class="term">
<span class="guilabel">Image dimensions</span>
for details on how to create this file.
</div></div>
</dd>
+<dt class="term">
+ <span class="guilabel">Class</span>
+ </dt>
+<dd>
+ The search will match if the file's class is, or is not, one of the following types.
+ <div class="block list itemizedlist"><ul class="itemizedlist">
+<li class="li-first">Unknown</li>
+<li>Image</li>
+<li>Raw Image</li>
+<li>Video</li>
+<li>Metadata</li>
+</ul></div>
+ </dd>
</dl></div>
<p class="para block"></p>
<p class="para block"></p>
<p class="para block block-first">Images are sorted by file modification date.</p>
</dd>
<dt class="term">
- <span class="guilabel">File Creation Date</span>
+ <span class="guilabel">File Date</span>
</dt>
<dd>
- <p class="para block block-first">Images are sorted by file creation date.</p>
+ <p class="para block block-first">
+ Images are sorted by one of four types of file date. They are described in the
+ <a class="link" href=".html#GuideReferenceFileDates" title="">Reference section</a>
+ .
+ </p>
</dd>
<dt class="term">
- <span class="guilabel">Exif Date</span>
+ <span class="guilabel">Size</span>
</dt>
<dd>
- <p class="para block block-first">Images are sorted by file Exif date.</p>
+ <p class="para block block-first">Images are sorted by file size on disk.</p>
</dd>
<dt class="term">
- <span class="guilabel">Size</span>
+ <span class="guilabel">Rating</span>
+ </dt>
+<dd>
+ <p class="para block block-first">Image are sorted by Xmp.xmp.Rating.</p>
+ </dd>
+<dt class="term">
+ <span class="guilabel">Class</span>
</dt>
<dd>
- <p class="para block block-first">Image are sorted by file size on disk.</p>
+ <p class="para block block-first">Image are sorted by class. The class types, and sort order, is:</p>
+ <div class="block list itemizedlist"><ul class="itemizedlist">
+<li class="li-first">Unknown</li>
+<li>Image</li>
+<li>Raw Image</li>
+<li>Video</li>
+<li>Metadata</li>
+</ul></div>
</dd>
<dt class="term">
<span class="guilabel">Ascending</span>
<p class="para block block-first">Toggles between increasing and decreasing sort order. A check will appear next to this entry to indicate ascending sort order.</p>
</dd>
</dl></div>
-<p class="para block"></p>
+<div class="admonition block note block-indent"><div class="note-inner">When images have equal rank, for example in rating or class sorts, within each section images will be sorted by filename.</div></div>
</div>
<div class="division section">
<a name="Filelist"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.6.3. </span>File list</span></h2></div>
You can pan the view as you pan an image in normal view mode, using left mouse button and drag.
</p>
<p class="para block">A primary mouse button click on any image will display informations about the image. Secondary mouse button will show a context menu.</p>
+<p class="para block">
+ The
+ <a class="link" href="GuideReferenceKeyboardShortcuts.html" title="Keyboard and Mouse Shortcuts">Keyboard and Mouse Shortcuts</a>
+ available are listed in the Reference section.
+ </p>
<div class="admonition block note block-indent"><div class="note-inner">
<p class="para block block-first">Pan view recursively visits each folder under the specified folder. This can consume considerable computer resources.</p>
</div></div>