Compare commits
5 Commits
0bec06b55d
...
8efd11d4e5
Author | SHA1 | Date | |
---|---|---|---|
8efd11d4e5 | |||
a3855e8f12 | |||
e239aca6f4 | |||
e663368ee4 | |||
8070c7f9ee |
@ -2,12 +2,16 @@ fastiv
|
||||
======
|
||||
|
||||
'fastiv' is a fast image viewer, supporting BMP, PNG, GIF, JPEG, and optionally
|
||||
RAW and SVG pictures, or whatever gdk-pixbuf loads. Currently, it's very basic.
|
||||
RAW, SVG and X11 cursors, or whatever gdk-pixbuf loads.
|
||||
|
||||
It still has some road to go, but it's already become quite usable,
|
||||
and it has received basic polishing.
|
||||
|
||||
Non-goals
|
||||
---------
|
||||
- fancy UI--the focus is on speed of use first, colour accuracy second
|
||||
- editing--that's what _editors_ are for, be it GIMP or Rawtherapee
|
||||
- editing--that's what _editors_ are for, be it GIMP or Rawtherapee;
|
||||
nothing beyond the most basic of adjustments is desired
|
||||
- memory efficiency, though preloading can cause some pressure
|
||||
- portability to non-UNIXy systems
|
||||
|
||||
|
@ -43,6 +43,7 @@ struct _FastivBrowser {
|
||||
|
||||
FastivIoThumbnailSize item_size; ///< Thumbnail size
|
||||
int item_height; ///< Thumbnail height in pixels
|
||||
int item_spacing; ///< Space between items in pixels
|
||||
|
||||
GArray *entries; ///< [Entry]
|
||||
GArray *layouted_rows; ///< [Row]
|
||||
@ -60,10 +61,6 @@ typedef struct row Row;
|
||||
|
||||
static const double g_permitted_width_multiplier = 2;
|
||||
|
||||
// Could be split out to also-idiomatic row-spacing/column-spacing properties.
|
||||
// TODO(p): Make a property for this.
|
||||
static const int g_item_spacing = 1;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct entry {
|
||||
@ -106,7 +103,7 @@ static void
|
||||
append_row(FastivBrowser *self, int *y, int x, GArray *items_array)
|
||||
{
|
||||
if (self->layouted_rows->len)
|
||||
*y += g_item_spacing;
|
||||
*y += self->item_spacing;
|
||||
|
||||
*y += self->item_border_y;
|
||||
g_array_append_val(self->layouted_rows, ((Row) {
|
||||
@ -143,8 +140,8 @@ relayout(FastivBrowser *self, int width)
|
||||
2 * self->item_border_x;
|
||||
if (!items->len) {
|
||||
// Just insert it, whether or not there's any space.
|
||||
} else if (x + g_item_spacing + width <= available_width) {
|
||||
x += g_item_spacing;
|
||||
} else if (x + self->item_spacing + width <= available_width) {
|
||||
x += self->item_spacing;
|
||||
} else {
|
||||
append_row(self, &y,
|
||||
padding.left + MAX(0, available_width - x) / 2, items);
|
||||
@ -485,6 +482,23 @@ fastiv_browser_get_property(
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_item_size(FastivBrowser *self, FastivIoThumbnailSize size)
|
||||
{
|
||||
if (size < FASTIV_IO_THUMBNAIL_SIZE_MIN ||
|
||||
size > FASTIV_IO_THUMBNAIL_SIZE_MAX)
|
||||
return;
|
||||
|
||||
if (size != self->item_size) {
|
||||
self->item_size = size;
|
||||
self->item_height = fastiv_io_thumbnail_sizes[self->item_size].size;
|
||||
reload_thumbnails(self);
|
||||
|
||||
g_object_notify_by_pspec(
|
||||
G_OBJECT(self), browser_properties[PROP_THUMBNAIL_SIZE]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fastiv_browser_set_property(
|
||||
GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
||||
@ -492,11 +506,7 @@ fastiv_browser_set_property(
|
||||
FastivBrowser *self = FASTIV_BROWSER(object);
|
||||
switch (property_id) {
|
||||
case PROP_THUMBNAIL_SIZE:
|
||||
if (g_value_get_enum(value) != (int) self->item_size) {
|
||||
self->item_size = g_value_get_enum(value);
|
||||
self->item_height = fastiv_io_thumbnail_sizes[self->item_size].size;
|
||||
reload_thumbnails(self);
|
||||
}
|
||||
set_item_size(self, g_value_get_enum(value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
@ -550,7 +560,8 @@ fastiv_browser_realize(GtkWidget *widget)
|
||||
|
||||
.visual = gtk_widget_get_visual(widget),
|
||||
.event_mask = gtk_widget_get_events(widget) | GDK_KEY_PRESS_MASK |
|
||||
GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK,
|
||||
GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
|
||||
GDK_SCROLL_MASK,
|
||||
};
|
||||
|
||||
// We need this window to receive input events at all.
|
||||
@ -652,6 +663,51 @@ fastiv_browser_motion_notify_event(GtkWidget *widget, GdkEventMotion *event)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fastiv_browser_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
||||
{
|
||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
||||
if ((event->state & gtk_accelerator_get_default_mod_mask()) !=
|
||||
GDK_CONTROL_MASK)
|
||||
return FALSE;
|
||||
|
||||
switch (event->direction) {
|
||||
case GDK_SCROLL_UP:
|
||||
set_item_size(self, self->item_size + 1);
|
||||
return TRUE;
|
||||
case GDK_SCROLL_DOWN:
|
||||
set_item_size(self, self->item_size - 1);
|
||||
return TRUE;
|
||||
default:
|
||||
// For some reason, we can also get GDK_SCROLL_SMOOTH.
|
||||
// Left/right are good to steal from GtkScrolledWindow for consistency.
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fastiv_browser_query_tooltip(GtkWidget *widget, gint x, gint y,
|
||||
G_GNUC_UNUSED gboolean keyboard_tooltip, GtkTooltip *tooltip)
|
||||
{
|
||||
FastivBrowser *self = FASTIV_BROWSER(widget);
|
||||
const Entry *entry = entry_at(self, x, y);
|
||||
if (!entry)
|
||||
return FALSE;
|
||||
|
||||
GFile *file = g_file_new_for_path(entry->filename);
|
||||
GFileInfo *info = g_file_query_info(file,
|
||||
G_FILE_ATTRIBUTE_STANDARD_NAME
|
||||
"," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
|
||||
G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
||||
g_object_unref(file);
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
gtk_tooltip_set_text(tooltip, g_file_info_get_display_name(info));
|
||||
g_object_unref(info);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fastiv_browser_style_updated(GtkWidget *widget)
|
||||
{
|
||||
@ -661,6 +717,11 @@ fastiv_browser_style_updated(GtkWidget *widget)
|
||||
GtkStyleContext *style = gtk_widget_get_style_context(widget);
|
||||
GtkBorder border = {}, margin = {};
|
||||
|
||||
int item_spacing = self->item_spacing;
|
||||
gtk_widget_style_get(widget, "spacing", &self->item_spacing, NULL);
|
||||
if (item_spacing != self->item_spacing)
|
||||
gtk_widget_queue_resize(widget);
|
||||
|
||||
// Using a pseudo-class, because GTK+ regions are deprecated.
|
||||
gtk_style_context_save(style);
|
||||
gtk_style_context_add_class(style, "item");
|
||||
@ -741,8 +802,16 @@ fastiv_browser_class_init(FastivBrowserClass *klass)
|
||||
widget_class->size_allocate = fastiv_browser_size_allocate;
|
||||
widget_class->button_press_event = fastiv_browser_button_press_event;
|
||||
widget_class->motion_notify_event = fastiv_browser_motion_notify_event;
|
||||
widget_class->scroll_event = fastiv_browser_scroll_event;
|
||||
widget_class->query_tooltip = fastiv_browser_query_tooltip;
|
||||
widget_class->style_updated = fastiv_browser_style_updated;
|
||||
|
||||
// Could be split to also-idiomatic row-spacing/column-spacing properties.
|
||||
// The GParamSpec is sinked by this call.
|
||||
gtk_widget_class_install_style_property(widget_class,
|
||||
g_param_spec_int("spacing", "Spacing", "Space between items",
|
||||
0, G_MAXINT, 1, G_PARAM_READWRITE));
|
||||
|
||||
// TODO(p): Later override "screen_changed", recreate Pango layouts there,
|
||||
// if we get to have any, or otherwise reflect DPI changes.
|
||||
gtk_widget_class_set_css_name(widget_class, "fastiv-browser");
|
||||
@ -752,14 +821,14 @@ static void
|
||||
fastiv_browser_init(FastivBrowser *self)
|
||||
{
|
||||
gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE);
|
||||
gtk_widget_set_has_tooltip(GTK_WIDGET(self), TRUE);
|
||||
|
||||
self->entries = g_array_new(FALSE, TRUE, sizeof(Entry));
|
||||
g_array_set_clear_func(self->entries, (GDestroyNotify) entry_free);
|
||||
self->layouted_rows = g_array_new(FALSE, TRUE, sizeof(Row));
|
||||
g_array_set_clear_func(self->layouted_rows, (GDestroyNotify) row_free);
|
||||
|
||||
self->item_size = FASTIV_IO_THUMBNAIL_SIZE_NORMAL;
|
||||
self->item_height = fastiv_io_thumbnail_sizes[self->item_size].size;
|
||||
set_item_size(self, FASTIV_IO_THUMBNAIL_SIZE_NORMAL);
|
||||
self->selected = -1;
|
||||
self->glow = cairo_image_surface_create(CAIRO_FORMAT_A1, 0, 0);
|
||||
|
||||
|
@ -67,6 +67,19 @@ fastiv_sidebar_class_init(FastivSidebarClass *klass)
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_FILE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_rowlabel_query_tooltip(GtkWidget *widget,
|
||||
G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y,
|
||||
G_GNUC_UNUSED gboolean keyboard_tooltip, GtkTooltip *tooltip)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL(widget);
|
||||
if (!pango_layout_is_ellipsized(gtk_label_get_layout(label)))
|
||||
return FALSE;
|
||||
|
||||
gtk_tooltip_set_text(tooltip, gtk_label_get_text(label));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_row(GFile *file, const char *icon_name)
|
||||
{
|
||||
@ -88,6 +101,9 @@ create_row(GFile *file, const char *icon_name)
|
||||
|
||||
GtkWidget *rowlabel = gtk_label_new(name);
|
||||
gtk_label_set_ellipsize(GTK_LABEL(rowlabel), PANGO_ELLIPSIZE_END);
|
||||
gtk_widget_set_has_tooltip(rowlabel, TRUE);
|
||||
g_signal_connect(rowlabel, "query-tooltip",
|
||||
G_CALLBACK(on_rowlabel_query_tooltip), NULL);
|
||||
gtk_style_context_add_class(
|
||||
gtk_widget_get_style_context(rowlabel), "sidebar-label");
|
||||
gtk_container_add(GTK_CONTAINER(rowbox), rowlabel);
|
||||
|
Loading…
x
Reference in New Issue
Block a user