src: Add fading label class
Co-Authored-By: Titouan Real <titouan.real@gmail.com> Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/657>
This commit is contained in:
committed by
Georges Basile Stavracas Neto
co-authored by
Titouan Real
parent
32f44b160e
commit
bd4d503080
@@ -165,6 +165,7 @@ libedataserver_dep = dependency('libedataserver-1.2', version: '>= 3.45.1')
|
||||
libecal_dep = dependency('libecal-2.0', version: '>= 3.45.1')
|
||||
libsoup_dep = dependency('libsoup-3.0')
|
||||
libadwaita_dep = dependency('libadwaita-1', version: '>= 1.8.alpha')
|
||||
fribidi_dep = dependency('fribidi')
|
||||
glib_dep = dependency('glib-2.0', version: '>= 2.80.0')
|
||||
gtk_dep = dependency('gtk4', version: '>= 4.21.2')
|
||||
gio_dep = dependency('gio-2.0', version: '>= 2.58.0')
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/..
|
||||
*/
|
||||
|
||||
/* Bits taken from GTK 4.0.2 and tweaked to be used by libadwaita. */
|
||||
/* Copied from libadwaita 1.8 and adapted for use in gnome-calendar. */
|
||||
|
||||
#include "gcal-bidi.h"
|
||||
|
||||
#include <fribidi.h>
|
||||
|
||||
static PangoDirection
|
||||
gcal_unichar_direction (gunichar ch)
|
||||
{
|
||||
FriBidiCharType fribidi_ch_type;
|
||||
|
||||
G_STATIC_ASSERT (sizeof (FriBidiChar) == sizeof (gunichar));
|
||||
|
||||
fribidi_ch_type = fribidi_get_bidi_type (ch);
|
||||
|
||||
if (!FRIBIDI_IS_STRONG (fribidi_ch_type))
|
||||
return PANGO_DIRECTION_NEUTRAL;
|
||||
else if (FRIBIDI_IS_RTL (fribidi_ch_type))
|
||||
return PANGO_DIRECTION_RTL;
|
||||
else
|
||||
return PANGO_DIRECTION_LTR;
|
||||
}
|
||||
|
||||
PangoDirection
|
||||
gcal_find_base_dir (const gchar *text,
|
||||
gint length)
|
||||
{
|
||||
PangoDirection dir = PANGO_DIRECTION_NEUTRAL;
|
||||
const char *p;
|
||||
|
||||
g_return_val_if_fail (text != NULL || length == 0, PANGO_DIRECTION_NEUTRAL);
|
||||
|
||||
p = text;
|
||||
while ((length < 0 || p < text + length) && *p) {
|
||||
gunichar wc = g_utf8_get_char (p);
|
||||
|
||||
dir = gcal_unichar_direction (wc);
|
||||
|
||||
if (dir != PANGO_DIRECTION_NEUTRAL)
|
||||
break;
|
||||
|
||||
p = g_utf8_next_char (p);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Purism SPC
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
/* Copied from libadwaita 1.8 and adapted for use in gnome-calendar. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
#include <pango/pango.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
PangoDirection gcal_find_base_dir (const gchar *text,
|
||||
gint length);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Purism SPC
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* Author: Alice Mikhaylenko <alice.mikhaylenko@puri.sm>
|
||||
*/
|
||||
|
||||
/* Copied from libadwaita 1.8 and adapted for use in gnome-calendar. */
|
||||
|
||||
#include "config.h"
|
||||
#include "gcal-fading-label.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include "gcal-bidi.h"
|
||||
|
||||
#define FADE_WIDTH 18.0f
|
||||
|
||||
struct _GcalFadingLabel
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *label;
|
||||
gfloat align;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (GcalFadingLabel, gcal_fading_label, GTK_TYPE_WIDGET)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_LABEL,
|
||||
PROP_ALIGN,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *props[LAST_PROP];
|
||||
|
||||
static gboolean
|
||||
is_rtl (GcalFadingLabel *self)
|
||||
{
|
||||
PangoDirection pango_direction = PANGO_DIRECTION_NEUTRAL;
|
||||
const gchar *label = gcal_fading_label_get_label (self);
|
||||
|
||||
if (label)
|
||||
pango_direction = gcal_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
|
||||
gcal_fading_label_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *min,
|
||||
gint *nat,
|
||||
gint *min_baseline,
|
||||
gint *nat_baseline)
|
||||
{
|
||||
GcalFadingLabel *self = GCAL_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
|
||||
gcal_fading_label_size_allocate (GtkWidget *widget,
|
||||
gint width,
|
||||
gint height,
|
||||
gint baseline)
|
||||
{
|
||||
GcalFadingLabel *self = GCAL_FADING_LABEL (widget);
|
||||
GskTransform *transform;
|
||||
gfloat align = is_rtl (self) ? 1 - self->align : self->align;
|
||||
gint child_width;
|
||||
gfloat offset;
|
||||
|
||||
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
|
||||
gcal_fading_label_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GcalFadingLabel *self = GCAL_FADING_LABEL (widget);
|
||||
g_autoptr (GskRenderNode) node = NULL;
|
||||
g_autoptr (GtkSnapshot) child_snapshot = NULL;
|
||||
graphene_rect_t bounds;
|
||||
gfloat align = is_rtl (self) ? 1 - self->align : self->align;
|
||||
gint width = gtk_widget_get_width (widget);
|
||||
gint clipped_size;
|
||||
|
||||
if (width <= 0)
|
||||
return;
|
||||
|
||||
clipped_size = gtk_widget_get_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 (g_steal_pointer (&child_snapshot));
|
||||
|
||||
gsk_render_node_get_bounds (node, &bounds);
|
||||
bounds.origin.x = 0;
|
||||
bounds.origin.y = floor (bounds.origin.y);
|
||||
bounds.size.width = width;
|
||||
bounds.size.height = ceil (bounds.size.height) + 1;
|
||||
|
||||
gtk_snapshot_push_mask (snapshot, GSK_MASK_MODE_INVERTED_ALPHA);
|
||||
|
||||
if (align > 0)
|
||||
{
|
||||
gtk_snapshot_append_linear_gradient (snapshot,
|
||||
&GRAPHENE_RECT_INIT (0, bounds.origin.y,
|
||||
FADE_WIDTH, bounds.size.height),
|
||||
&GRAPHENE_POINT_INIT (0, 0),
|
||||
&GRAPHENE_POINT_INIT (FADE_WIDTH, 0),
|
||||
(GskColorStop[2]) {
|
||||
{ 0, { 0, 0, 0, 1 } },
|
||||
{ 1, { 0, 0, 0, 0 } },
|
||||
},
|
||||
2);
|
||||
}
|
||||
|
||||
if (align < 1)
|
||||
{
|
||||
gtk_snapshot_append_linear_gradient (snapshot,
|
||||
&GRAPHENE_RECT_INIT (width - FADE_WIDTH, bounds.origin.y,
|
||||
FADE_WIDTH, bounds.size.height),
|
||||
&GRAPHENE_POINT_INIT (width, 0),
|
||||
&GRAPHENE_POINT_INIT (width - FADE_WIDTH, 0),
|
||||
(GskColorStop[2]) {
|
||||
{ 0, { 0, 0, 0, 1 } },
|
||||
{ 1, { 0, 0, 0, 0 } },
|
||||
},
|
||||
2);
|
||||
}
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gtk_snapshot_push_clip (snapshot, &bounds);
|
||||
gtk_snapshot_append_node (snapshot, node);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_fading_label_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GcalFadingLabel *self = GCAL_FADING_LABEL (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_LABEL:
|
||||
g_value_set_string (value, gcal_fading_label_get_label (self));
|
||||
break;
|
||||
|
||||
case PROP_ALIGN:
|
||||
g_value_set_float (value, gcal_fading_label_get_align (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_fading_label_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GcalFadingLabel *self = GCAL_FADING_LABEL (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_LABEL:
|
||||
gcal_fading_label_set_label (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_ALIGN:
|
||||
gcal_fading_label_set_align (self, g_value_get_float (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_fading_label_dispose (GObject *object)
|
||||
{
|
||||
GcalFadingLabel *self = GCAL_FADING_LABEL (object);
|
||||
|
||||
g_clear_pointer (&self->label, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (gcal_fading_label_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_fading_label_class_init (GcalFadingLabelClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->get_property = gcal_fading_label_get_property;
|
||||
object_class->set_property = gcal_fading_label_set_property;
|
||||
object_class->dispose = gcal_fading_label_dispose;
|
||||
|
||||
widget_class->measure = gcal_fading_label_measure;
|
||||
widget_class->size_allocate = gcal_fading_label_size_allocate;
|
||||
widget_class->snapshot = gcal_fading_label_snapshot;
|
||||
|
||||
props[PROP_LABEL] =
|
||||
g_param_spec_string ("label", NULL, NULL,
|
||||
NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
props[PROP_ALIGN] =
|
||||
g_param_spec_float ("align", NULL, NULL,
|
||||
0.0, 1.0, 0.0,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, props);
|
||||
}
|
||||
|
||||
static void
|
||||
gcal_fading_label_init (GcalFadingLabel *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 gchar *
|
||||
gcal_fading_label_get_label (GcalFadingLabel *self)
|
||||
{
|
||||
g_return_val_if_fail (GCAL_IS_FADING_LABEL (self), NULL);
|
||||
|
||||
return gtk_label_get_label (GTK_LABEL (self->label));
|
||||
}
|
||||
|
||||
void
|
||||
gcal_fading_label_set_label (GcalFadingLabel *self,
|
||||
const gchar *label)
|
||||
{
|
||||
g_return_if_fail (GCAL_IS_FADING_LABEL (self));
|
||||
|
||||
if (!g_strcmp0 (label, gcal_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
|
||||
gcal_fading_label_get_align (GcalFadingLabel *self)
|
||||
{
|
||||
g_return_val_if_fail (GCAL_IS_FADING_LABEL (self), 0.0f);
|
||||
|
||||
return self->align;
|
||||
}
|
||||
|
||||
void
|
||||
gcal_fading_label_set_align (GcalFadingLabel *self,
|
||||
gfloat align)
|
||||
{
|
||||
g_return_if_fail (GCAL_IS_FADING_LABEL (self));
|
||||
|
||||
align = CLAMP (align, 0.0, 1.0);
|
||||
|
||||
if (G_APPROX_VALUE (self->align, align, FLT_EPSILON))
|
||||
return;
|
||||
|
||||
self->align = align;
|
||||
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ALIGN]);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Purism SPC
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* Author: Alice Mikhaylenko <alice.mikhaylenko@puri.sm>
|
||||
*/
|
||||
|
||||
/* Copied from libadwaita 1.8 and adapted for use in gnome-calendar. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GCAL_TYPE_FADING_LABEL (gcal_fading_label_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GcalFadingLabel, gcal_fading_label, GCAL, FADING_LABEL, GtkWidget)
|
||||
|
||||
const gchar *gcal_fading_label_get_label (GcalFadingLabel *self);
|
||||
void gcal_fading_label_set_label (GcalFadingLabel *self,
|
||||
const gchar *label);
|
||||
gfloat gcal_fading_label_get_align (GcalFadingLabel *self);
|
||||
void gcal_fading_label_set_align (GcalFadingLabel *self,
|
||||
gfloat align);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -41,11 +41,13 @@ built_sources += gnome.compile_resources(
|
||||
|
||||
sources += files(
|
||||
'gcal-application.c',
|
||||
'gcal-bidi.c',
|
||||
'gcal-calendar-list.c',
|
||||
'gcal-calendar-navigation-button.c',
|
||||
'gcal-drop-overlay.c',
|
||||
'gcal-event-popover.c',
|
||||
'gcal-event-widget.c',
|
||||
'gcal-fading-label.c',
|
||||
'gcal-meeting-row.c',
|
||||
'gcal-overflow-bin.c',
|
||||
'gcal-overflow-bin-layout.c',
|
||||
|
||||
@@ -8,6 +8,7 @@ gcal_deps = [
|
||||
libecal_dep,
|
||||
libsoup_dep,
|
||||
libical_dep,
|
||||
fribidi_dep,
|
||||
glib_dep,
|
||||
gtk_dep,
|
||||
gio_dep,
|
||||
|
||||
Reference in New Issue
Block a user