[libadwaita/wip/exalm/tabs: 82/88] Add AdwFadingLabel
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libadwaita/wip/exalm/tabs: 82/88] Add AdwFadingLabel
- Date: Fri, 7 May 2021 21:07:53 +0000 (UTC)
commit 029fb6dbba282053ac0f6564102f59094f4468a7
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Tue Jan 26 21:00:05 2021 +0500
Add AdwFadingLabel
Add a helper widget for showing fading ellipsized titles in tabs.
doc/meson.build | 1 +
src/adw-fading-label-private.h | 31 ++++
src/adw-fading-label.c | 328 +++++++++++++++++++++++++++++++++++++++++
src/adwaita.gresources.xml | 1 +
src/glsl/fade.glsl | 25 ++++
src/meson.build | 1 +
6 files changed, 387 insertions(+)
---
diff --git a/doc/meson.build b/doc/meson.build
index 468e0af..cd2ea0e 100644
--- a/doc/meson.build
+++ b/doc/meson.build
@@ -11,6 +11,7 @@ private_headers = [
'adw-enums.h',
'adw-enums-private.h',
'adw-enum-value-object-private.h',
+ 'adw-fading-label-private.h',
'adw-focus-private.h',
'adw-gizmo-private.h',
'adw-indicator-bin-private.h',
diff --git a/src/adw-fading-label-private.h b/src/adw-fading-label-private.h
new file mode 100644
index 0000000..630d291
--- /dev/null
+++ b/src/adw-fading-label-private.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#pragma once
+
+#if !defined(_ADWAITA_INSIDE) && !defined(ADWAITA_COMPILATION)
+#error "Only <adwaita.h> can be included directly."
+#endif
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_FADING_LABEL (adw_fading_label_get_type())
+
+G_DECLARE_FINAL_TYPE (AdwFadingLabel, adw_fading_label, ADW, FADING_LABEL, GtkWidget)
+
+const char *adw_fading_label_get_label (AdwFadingLabel *self);
+void adw_fading_label_set_label (AdwFadingLabel *self,
+ const char *label);
+
+float adw_fading_label_get_align (AdwFadingLabel *self);
+void adw_fading_label_set_align (AdwFadingLabel *self,
+ float align);
+
+G_END_DECLS
diff --git a/src/adw-fading-label.c b/src/adw-fading-label.c
new file mode 100644
index 0000000..d9ad95a
--- /dev/null
+++ b/src/adw-fading-label.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#include "config.h"
+#include "adw-fading-label-private.h"
+
+#include <glib/gi18n-lib.h>
+#include "adw-bidi-private.h"
+
+/**
+ * PRIVATE:adw-fading-label
+ * @short_description: A helper object for #AdwTab
+ * @title: AdwFadingLabel
+ * @stability: Private
+ *
+ * The AdwFadingLabel widget allows to ellipsize a label with a fading effect.
+ *
+ * Since: 1.0
+ */
+
+#define FADE_WIDTH 18
+
+struct _AdwFadingLabel
+{
+ GtkWidget parent_instance;
+
+ GtkWidget *label;
+ float align;
+
+ GskGLShader *shader;
+ gboolean shader_compiled;
+};
+
+G_DEFINE_TYPE (AdwFadingLabel, adw_fading_label, GTK_TYPE_WIDGET)
+
+enum {
+ PROP_0,
+ PROP_LABEL,
+ PROP_ALIGN,
+ LAST_PROP
+};
+
+static GParamSpec *props[LAST_PROP];
+
+static gboolean
+is_rtl (AdwFadingLabel *self)
+{
+ PangoDirection pango_direction = PANGO_DIRECTION_NEUTRAL;
+ const char *label = adw_fading_label_get_label (self);
+
+ if (label)
+ pango_direction = adw_find_base_dir (label, -1);
+
+ if (pango_direction == PANGO_DIRECTION_RTL)
+ return TRUE;
+
+ if (pango_direction == PANGO_DIRECTION_LTR)
+ return FALSE;
+
+ return gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL;
+}
+
+static void
+ensure_shader (AdwFadingLabel *self)
+{
+ GtkNative *native;
+ GskRenderer *renderer;
+ g_autoptr (GError) error = NULL;
+
+ if (self->shader)
+ return;
+
+ self->shader = gsk_gl_shader_new_from_resource ("/org/gnome/Adwaita/glsl/fade.glsl");
+
+ native = gtk_widget_get_native (GTK_WIDGET (self));
+ renderer = gtk_native_get_renderer (native);
+
+ self->shader_compiled = gsk_gl_shader_compile (self->shader, renderer, &error);
+
+ if (error) {
+ /* If shaders aren't supported, the error doesn't matter and we just
+ * silently fall back */
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
+ g_critical ("Couldn't compile shader: %s\n", error->message);
+
+ self->shader_compiled = FALSE;
+ }
+}
+
+static void
+adw_fading_label_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *min,
+ int *nat,
+ int *min_baseline,
+ int *nat_baseline)
+{
+ AdwFadingLabel *self = ADW_FADING_LABEL (widget);
+
+ gtk_widget_measure (self->label, orientation, for_size,
+ min, nat, min_baseline, nat_baseline);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL && min)
+ *min = 0;
+}
+
+static void
+adw_fading_label_size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ AdwFadingLabel *self = ADW_FADING_LABEL (widget);
+ float align = is_rtl (self) ? 1 - self->align : self->align;
+ int child_width;
+ float offset;
+ GskTransform *transform;
+
+ gtk_widget_measure (self->label, GTK_ORIENTATION_HORIZONTAL, height,
+ NULL, &child_width, NULL, NULL);
+
+ offset = (width - child_width) * align;
+ transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (offset, 0));
+
+ gtk_widget_allocate (self->label, child_width, height, baseline, transform);
+}
+
+static void
+adw_fading_label_snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
+{
+ AdwFadingLabel *self = ADW_FADING_LABEL (widget);
+ float align = is_rtl (self) ? 1 - self->align : self->align;
+ int width = gtk_widget_get_width (widget);
+ int clipped_size;
+ GtkSnapshot *child_snapshot;
+ g_autoptr (GskRenderNode) node = NULL;
+ graphene_rect_t bounds;
+
+ if (width <= 0)
+ return;
+
+ clipped_size = gtk_widget_get_allocated_width (self->label) - width;
+
+ if (clipped_size <= 0) {
+ gtk_widget_snapshot_child (widget, self->label, snapshot);
+
+ return;
+ }
+
+ child_snapshot = gtk_snapshot_new ();
+ gtk_widget_snapshot_child (widget, self->label, child_snapshot);
+ node = gtk_snapshot_free_to_node (child_snapshot);
+
+ gsk_render_node_get_bounds (node, &bounds);
+ bounds.origin.x = 0;
+ bounds.size.width = width;
+
+ ensure_shader (self);
+
+ if (self->shader_compiled) {
+ gtk_snapshot_push_gl_shader (snapshot, self->shader, &bounds,
+ gsk_gl_shader_format_args (self->shader,
+ "offsetLeft", 0.0f,
+ "offsetRight", 0.0f,
+ "strengthLeft", align > 0 ? 1.0f : 0.0f,
+ "strengthRight", align < 1 ? 1.0f : 0.0f,
+ NULL));
+ } else {
+ gtk_snapshot_push_clip (snapshot, &bounds);
+ }
+
+ gtk_snapshot_append_node (snapshot, node);
+
+ if (self->shader_compiled)
+ gtk_snapshot_gl_shader_pop_texture (snapshot);
+
+ gtk_snapshot_pop (snapshot);
+}
+
+static void
+adw_fading_label_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AdwFadingLabel *self = ADW_FADING_LABEL (object);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ g_value_set_string (value, adw_fading_label_get_label (self));
+ break;
+
+ case PROP_ALIGN:
+ g_value_set_float (value, adw_fading_label_get_align (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+adw_fading_label_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AdwFadingLabel *self = ADW_FADING_LABEL (object);
+
+ switch (prop_id) {
+ case PROP_LABEL:
+ adw_fading_label_set_label (self, g_value_get_string (value));
+ break;
+
+ case PROP_ALIGN:
+ adw_fading_label_set_align (self, g_value_get_float (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+adw_fading_label_dispose (GObject *object)
+{
+ AdwFadingLabel *self = ADW_FADING_LABEL (object);
+
+ g_clear_object (&self->shader);
+ g_clear_pointer (&self->label, gtk_widget_unparent);
+
+ G_OBJECT_CLASS (adw_fading_label_parent_class)->dispose (object);
+}
+
+static void
+adw_fading_label_class_init (AdwFadingLabelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->get_property = adw_fading_label_get_property;
+ object_class->set_property = adw_fading_label_set_property;
+ object_class->dispose = adw_fading_label_dispose;
+
+ widget_class->measure = adw_fading_label_measure;
+ widget_class->size_allocate = adw_fading_label_size_allocate;
+ widget_class->snapshot = adw_fading_label_snapshot;
+
+ props[PROP_LABEL] =
+ g_param_spec_string ("label",
+ "Label",
+ "Label",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ props[PROP_ALIGN] =
+ g_param_spec_float ("align",
+ "Align",
+ "Align",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+}
+
+static void
+adw_fading_label_init (AdwFadingLabel *self)
+{
+ self->label = gtk_label_new (NULL);
+ gtk_label_set_single_line_mode (GTK_LABEL (self->label), TRUE);
+
+ gtk_widget_set_parent (self->label, GTK_WIDGET (self));
+}
+
+const char *
+adw_fading_label_get_label (AdwFadingLabel *self)
+{
+ g_return_val_if_fail (ADW_IS_FADING_LABEL (self), NULL);
+
+ return gtk_label_get_label (GTK_LABEL (self->label));
+}
+
+void
+adw_fading_label_set_label (AdwFadingLabel *self,
+ const char *label)
+{
+ g_return_if_fail (ADW_IS_FADING_LABEL (self));
+
+ if (!g_strcmp0 (label, adw_fading_label_get_label (self)))
+ return;
+
+ gtk_label_set_label (GTK_LABEL (self->label), label);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LABEL]);
+}
+
+float
+adw_fading_label_get_align (AdwFadingLabel *self)
+{
+ g_return_val_if_fail (ADW_IS_FADING_LABEL (self), 0.0f);
+
+ return self->align;
+}
+
+void
+adw_fading_label_set_align (AdwFadingLabel *self,
+ float align)
+{
+ g_return_if_fail (ADW_IS_FADING_LABEL (self));
+
+ align = CLAMP (align, 0.0, 1.0);
+
+ if (self->align == align)
+ return;
+
+ self->align = align;
+
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ALIGN]);
+}
diff --git a/src/adwaita.gresources.xml b/src/adwaita.gresources.xml
index 64de095..1bee5f8 100644
--- a/src/adwaita.gresources.xml
+++ b/src/adwaita.gresources.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Adwaita">
+ <file>glsl/fade.glsl</file>
<file>glsl/mask.glsl</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/adw-expander-arrow-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/status/avatar-default-symbolic.svg</file>
diff --git a/src/glsl/fade.glsl b/src/glsl/fade.glsl
new file mode 100644
index 0000000..64dc111
--- /dev/null
+++ b/src/glsl/fade.glsl
@@ -0,0 +1,25 @@
+uniform float offsetLeft;
+uniform float offsetRight;
+uniform float strengthLeft;
+uniform float strengthRight;
+
+uniform sampler2D u_texture1;
+
+#define FADE_WIDTH 18
+
+void mainImage(out vec4 fragColor,
+ in vec2 fragCoord,
+ in vec2 resolution,
+ in vec2 uv) {
+ float progress;
+
+ fragColor = GskTexture(u_texture1, uv);
+
+ progress = fragCoord.x - offsetLeft;
+ progress = min(max(progress / FADE_WIDTH, 0), 1);
+ fragColor *= (1 + strengthLeft * (progress - 1));
+
+ progress = resolution.x - offsetRight - fragCoord.x;
+ progress = min(max(progress / FADE_WIDTH, 0), 1);
+ fragColor *= (1 + strengthRight * (progress - 1));
+}
diff --git a/src/meson.build b/src/meson.build
index 08eced1..8390098 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -129,6 +129,7 @@ src_sources = [
'adw-enum-list-model.c',
'adw-enum-value-object.c',
'adw-expander-row.c',
+ 'adw-fading-label.c',
'adw-flap.c',
'adw-focus.c',
'adw-gizmo.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]