aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2022-01-09 10:09:06 +0100
committerPřemysl Eric Janouch <p@janouch.name>2022-01-10 11:53:15 +0100
commit1a190001fc541c645166e8997f4bb3408835dd1f (patch)
tree60e6ee2aec0142ec0ac05d9d0641aef8d2c5a93a
parent3bf41993a3d099ba33a2cdc30a15693fddc7722f (diff)
downloadfiv-1a190001fc541c645166e8997f4bb3408835dd1f.tar.gz
fiv-1a190001fc541c645166e8997f4bb3408835dd1f.tar.xz
fiv-1a190001fc541c645166e8997f4bb3408835dd1f.zip
Make the browser implement its own scrollable
It's quite rough around the edges so far.
-rw-r--r--fiv-browser.c119
-rw-r--r--fiv.c5
2 files changed, 114 insertions, 10 deletions
diff --git a/fiv-browser.c b/fiv-browser.c
index 175f364..e184fa8 100644
--- a/fiv-browser.c
+++ b/fiv-browser.c
@@ -54,6 +54,10 @@ typedef struct _Thumbnailer {
struct _FivBrowser {
GtkWidget parent_instance;
+ GtkAdjustment *hadjustment; ///< GtkScrollable boilerplate
+ GtkAdjustment *vadjustment; ///< GtkScrollable boilerplate
+ GtkScrollablePolicy hscroll_policy; ///< GtkScrollable boilerplate
+ GtkScrollablePolicy vscroll_policy; ///< GtkScrollable boilerplate
FivThumbnailSize item_size; ///< Thumbnail size
int item_height; ///< Thumbnail height in pixels
@@ -170,7 +174,21 @@ relayout(FivBrowser *self, int width)
}
g_array_free(items, TRUE);
- return y + padding.bottom;
+ int total_height = y + padding.bottom;
+ if (self->hadjustment) {
+ // TODO(p): Set it to the width. Ideally, bump it to the minimum width.
+ }
+ if (self->vadjustment) {
+ gtk_adjustment_set_lower(self->vadjustment, 0);
+ gtk_adjustment_set_upper(self->vadjustment, total_height);
+ gtk_adjustment_set_page_size(
+ self->vadjustment, gtk_widget_get_allocated_height(widget));
+ gtk_adjustment_set_page_increment(
+ self->vadjustment, gtk_widget_get_allocated_height(widget));
+ gtk_adjustment_set_step_increment(self->vadjustment,
+ self->item_height + self->item_spacing + 2 * self->item_border_y);
+ }
+ return total_height;
}
static void
@@ -225,6 +243,9 @@ item_extents(FivBrowser *self, const Item *item, const Row *row)
static const Entry *
entry_at(FivBrowser *self, int x, int y)
{
+ if (self->vadjustment)
+ y += gtk_adjustment_get_value(self->vadjustment);
+
for (guint i = 0; i < self->layouted_rows->len; i++) {
const Row *row = &g_array_index(self->layouted_rows, Row, i);
for (Item *item = row->items; item->entry; item++) {
@@ -748,14 +769,18 @@ show_context_menu(GtkWidget *widget, GFile *file)
// --- Boilerplate -------------------------------------------------------------
-// TODO(p): For proper navigation, we need to implement GtkScrollable.
G_DEFINE_TYPE_EXTENDED(FivBrowser, fiv_browser, GTK_TYPE_WIDGET, 0,
- /* G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE,
- fiv_browser_scrollable_init) */)
+ G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE, NULL))
enum {
PROP_THUMBNAIL_SIZE = 1,
- N_PROPERTIES
+ N_PROPERTIES,
+
+ // These are overriden, we do not register them.
+ PROP_HADJUSTMENT,
+ PROP_VADJUSTMENT,
+ PROP_HSCROLL_POLICY,
+ PROP_VSCROLL_POLICY,
};
static GParamSpec *browser_properties[N_PROPERTIES];
@@ -769,6 +794,35 @@ enum {
static guint browser_signals[LAST_SIGNAL];
static void
+on_adjustment_value_changed(
+ G_GNUC_UNUSED GtkAdjustment *adjustment, gpointer user_data)
+{
+ FivBrowser *self = FIV_BROWSER(user_data);
+ gtk_widget_queue_draw(GTK_WIDGET(self));
+}
+
+static gboolean
+replace_adjustment(
+ FivBrowser *self, GtkAdjustment **adjustment, GtkAdjustment *replacement)
+{
+ if (*adjustment == replacement)
+ return FALSE;
+
+ if (*adjustment) {
+ g_signal_handlers_disconnect_by_func(
+ *adjustment, on_adjustment_value_changed, self);
+ g_clear_object(adjustment);
+ }
+ if (replacement) {
+ *adjustment = g_object_ref(replacement);
+ g_signal_connect(*adjustment, "value-changed",
+ G_CALLBACK(on_adjustment_value_changed), self);
+ // TODO(p): We should set it up, as it is done in relayout().
+ }
+ return TRUE;
+}
+
+static void
fiv_browser_finalize(GObject *gobject)
{
FivBrowser *self = FIV_BROWSER(gobject);
@@ -783,6 +837,9 @@ fiv_browser_finalize(GObject *gobject)
cairo_surface_destroy(self->glow);
g_clear_object(&self->pointer);
+ replace_adjustment(self, &self->hadjustment, NULL);
+ replace_adjustment(self, &self->vadjustment, NULL);
+
G_OBJECT_CLASS(fiv_browser_parent_class)->finalize(gobject);
}
@@ -795,6 +852,18 @@ fiv_browser_get_property(
case PROP_THUMBNAIL_SIZE:
g_value_set_enum(value, self->item_size);
break;
+ case PROP_HADJUSTMENT:
+ g_value_set_object(value, self->hadjustment);
+ break;
+ case PROP_VADJUSTMENT:
+ g_value_set_object(value, self->vadjustment);
+ break;
+ case PROP_HSCROLL_POLICY:
+ g_value_set_enum(value, self->hscroll_policy);
+ break;
+ case PROP_VSCROLL_POLICY:
+ g_value_set_enum(value, self->vscroll_policy);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
@@ -825,6 +894,30 @@ fiv_browser_set_property(
case PROP_THUMBNAIL_SIZE:
set_item_size(self, g_value_get_enum(value));
break;
+ case PROP_HADJUSTMENT:
+ if (replace_adjustment(
+ self, &self->hadjustment, g_value_get_object(value)))
+ g_object_notify_by_pspec(object, pspec);
+ break;
+ case PROP_VADJUSTMENT:
+ if (replace_adjustment(
+ self, &self->vadjustment, g_value_get_object(value)))
+ g_object_notify_by_pspec(object, pspec);
+ break;
+ case PROP_HSCROLL_POLICY:
+ if ((gint) self->hscroll_policy != g_value_get_enum(value)) {
+ self->hscroll_policy = g_value_get_enum(value);
+ gtk_widget_queue_resize(GTK_WIDGET(self));
+ g_object_notify_by_pspec(object, pspec);
+ }
+ break;
+ case PROP_VSCROLL_POLICY:
+ if ((gint) self->vscroll_policy != g_value_get_enum(value)) {
+ self->vscroll_policy = g_value_get_enum(value);
+ gtk_widget_queue_resize(GTK_WIDGET(self));
+ g_object_notify_by_pspec(object, pspec);
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
@@ -899,6 +992,7 @@ fiv_browser_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
GTK_WIDGET_CLASS(fiv_browser_parent_class)
->size_allocate(widget, allocation);
+ // TODO(p): Update adjustments so that blank space is avoided.
relayout(FIV_BROWSER(widget), allocation->width);
}
@@ -914,6 +1008,12 @@ fiv_browser_draw(GtkWidget *widget, cairo_t *cr)
gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0,
allocation.width, allocation.height);
+ // TODO(p): self->hadjustment as well, and test it.
+ if (self->vadjustment) {
+ gdouble y = gtk_adjustment_get_value(self->vadjustment);
+ cairo_translate(cr, 0, -y);
+ }
+
GdkRectangle clip = {};
gboolean have_clip = gdk_cairo_get_clip_rectangle(cr, &clip);
@@ -1129,6 +1229,15 @@ fiv_browser_class_init(FivBrowserClass *klass)
g_object_class_install_properties(
object_class, N_PROPERTIES, browser_properties);
+ g_object_class_override_property(
+ object_class, PROP_HADJUSTMENT, "hadjustment");
+ g_object_class_override_property(
+ object_class, PROP_VADJUSTMENT, "vadjustment");
+ g_object_class_override_property(
+ object_class, PROP_HSCROLL_POLICY, "hscroll-policy");
+ g_object_class_override_property(
+ object_class, PROP_VSCROLL_POLICY, "vscroll-policy");
+
browser_signals[ITEM_ACTIVATED] = g_signal_new("item-activated",
G_TYPE_FROM_CLASS(klass), 0, 0, NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_FILE, GTK_TYPE_PLACES_OPEN_FLAGS);
diff --git a/fiv.c b/fiv.c
index 749340b..c326fdf 100644
--- a/fiv.c
+++ b/fiv.c
@@ -1709,11 +1709,6 @@ main(int argc, char *argv[])
G_CALLBACK(on_item_activated), NULL);
gtk_container_add(GTK_CONTAINER(g.browser_scroller), g.browser);
- // Christ, no, do not scroll all the way to the top on focus.
- GtkWidget *browser_port = gtk_bin_get_child(GTK_BIN(g.browser_scroller));
- gtk_container_set_focus_hadjustment(GTK_CONTAINER(browser_port), NULL);
- gtk_container_set_focus_vadjustment(GTK_CONTAINER(browser_port), NULL);
-
g.browser_sidebar = make_browser_sidebar(g.model);
g.browser_paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
gtk_paned_add1(GTK_PANED(g.browser_paned), g.browser_sidebar);