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')
|
libecal_dep = dependency('libecal-2.0', version: '>= 3.45.1')
|
||||||
libsoup_dep = dependency('libsoup-3.0')
|
libsoup_dep = dependency('libsoup-3.0')
|
||||||
libadwaita_dep = dependency('libadwaita-1', version: '>= 1.8.alpha')
|
libadwaita_dep = dependency('libadwaita-1', version: '>= 1.8.alpha')
|
||||||
|
fribidi_dep = dependency('fribidi')
|
||||||
glib_dep = dependency('glib-2.0', version: '>= 2.80.0')
|
glib_dep = dependency('glib-2.0', version: '>= 2.80.0')
|
||||||
gtk_dep = dependency('gtk4', version: '>= 4.21.2')
|
gtk_dep = dependency('gtk4', version: '>= 4.21.2')
|
||||||
gio_dep = dependency('gio-2.0', version: '>= 2.58.0')
|
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(
|
sources += files(
|
||||||
'gcal-application.c',
|
'gcal-application.c',
|
||||||
|
'gcal-bidi.c',
|
||||||
'gcal-calendar-list.c',
|
'gcal-calendar-list.c',
|
||||||
'gcal-calendar-navigation-button.c',
|
'gcal-calendar-navigation-button.c',
|
||||||
'gcal-drop-overlay.c',
|
'gcal-drop-overlay.c',
|
||||||
'gcal-event-popover.c',
|
'gcal-event-popover.c',
|
||||||
'gcal-event-widget.c',
|
'gcal-event-widget.c',
|
||||||
|
'gcal-fading-label.c',
|
||||||
'gcal-meeting-row.c',
|
'gcal-meeting-row.c',
|
||||||
'gcal-overflow-bin.c',
|
'gcal-overflow-bin.c',
|
||||||
'gcal-overflow-bin-layout.c',
|
'gcal-overflow-bin-layout.c',
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ gcal_deps = [
|
|||||||
libecal_dep,
|
libecal_dep,
|
||||||
libsoup_dep,
|
libsoup_dep,
|
||||||
libical_dep,
|
libical_dep,
|
||||||
|
fribidi_dep,
|
||||||
glib_dep,
|
glib_dep,
|
||||||
gtk_dep,
|
gtk_dep,
|
||||||
gio_dep,
|
gio_dep,
|
||||||
|
|||||||
Reference in New Issue
Block a user