Merge branch 'wip/otte/inscription' into 'main'

More inscription work

See merge request GNOME/gtk!4808
This commit is contained in:
Matthias Clasen
2022-06-12 01:38:40 +00:00
10 changed files with 524 additions and 0 deletions

View File

@@ -329,6 +329,7 @@
<file>pickers.c</file>
<file>printing.c</file>
<file>revealer.c</file>
<file>read_more.c</file>
<file>rotated_text.c</file>
<file>scale.c</file>
<file>search_entry.c</file>

View File

@@ -73,6 +73,7 @@ demos = files([
'peg_solitaire.c',
'pickers.c',
'printing.c',
'read_more.c',
'revealer.c',
'rotated_text.c',
'scale.c',

238
demos/gtk-demo/read_more.c Normal file
View File

@@ -0,0 +1,238 @@
/* Read More
*
* A simple implementation of a widget that can either
* display a lot of text or just the first few lines with a
* "Read More" button.
*/
#include <gtk/gtk.h>
#define READ_TYPE_MORE (read_more_get_type ())
G_DECLARE_FINAL_TYPE(ReadMore, read_more, READ, MORE, GtkWidget)
struct _ReadMore {
GtkWidget parent_instance;
GtkWidget *label;
GtkWidget *inscription;
GtkWidget *box;
gboolean show_more;
};
G_DEFINE_TYPE (ReadMore, read_more, GTK_TYPE_WIDGET)
static GtkSizeRequestMode
read_more_get_request_mode (GtkWidget *widget)
{
return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
}
static void
read_more_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
ReadMore *self = READ_MORE (widget);
int label_min, label_nat, label_min_baseline, label_nat_baseline;
int box_min, box_nat, box_min_baseline, box_nat_baseline;
int min_check;
if (self->show_more)
min_check = G_MAXINT;
else if (for_size >= 0)
gtk_widget_measure (self->box, 1 - orientation, -1, &min_check, NULL, NULL, NULL);
else
min_check = -1;
if (min_check > for_size)
{
gtk_widget_measure (self->label,
orientation,
for_size,
minimum, natural,
minimum_baseline, natural_baseline);
return;
}
else if (for_size >= 0)
gtk_widget_measure (self->label, 1 - orientation, -1, &min_check, NULL, NULL, NULL);
else
min_check = -1;
if (min_check > for_size)
{
gtk_widget_measure (self->box,
orientation,
for_size,
minimum, natural,
minimum_baseline, natural_baseline);
return;
}
gtk_widget_measure (self->label,
orientation,
for_size,
&label_min, &label_nat,
&label_min_baseline, &label_nat_baseline);
gtk_widget_measure (self->box,
orientation,
for_size,
&box_min, &box_nat,
&box_min_baseline, &box_nat_baseline);
*minimum = MIN (label_min, box_min);
*natural = MIN (label_nat, box_nat);
/* FIXME: Figure out baselines! */
}
static void
read_more_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
ReadMore *self = READ_MORE (widget);
gboolean show_more;
if (self->show_more)
{
show_more = TRUE;
}
else
{
int needed;
/* check to see if we have enough space to show all text */
gtk_widget_measure (self->label,
GTK_ORIENTATION_VERTICAL,
width,
&needed, NULL, NULL, NULL);
show_more = needed <= height;
}
gtk_widget_set_child_visible (self->label, show_more);
gtk_widget_set_child_visible (self->box, !show_more);
if (show_more)
gtk_widget_size_allocate (self->label, &(GtkAllocation) { 0, 0, width, height }, baseline);
else
gtk_widget_size_allocate (self->box, &(GtkAllocation) { 0, 0, width, height }, baseline);
}
static void
read_more_dispose (GObject *object)
{
ReadMore *self = READ_MORE (object);
g_clear_pointer (&self->label, gtk_widget_unparent);
g_clear_pointer (&self->box, gtk_widget_unparent);
G_OBJECT_CLASS (read_more_parent_class)->dispose (object);
}
static void
read_more_class_init (ReadMoreClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
widget_class->get_request_mode = read_more_get_request_mode;
widget_class->measure = read_more_measure;
widget_class->size_allocate = read_more_allocate;
object_class->dispose = read_more_dispose;
}
static void
read_more_clicked (GtkButton *button,
ReadMore *self)
{
self->show_more = TRUE;
gtk_widget_queue_resize (GTK_WIDGET (self));
}
static void
read_more_init (ReadMore *self)
{
GtkWidget *button;
self->label = gtk_label_new (NULL);
gtk_label_set_xalign (GTK_LABEL (self->label), 0.0);
gtk_label_set_yalign (GTK_LABEL (self->label), 0.0);
gtk_label_set_wrap (GTK_LABEL (self->label), TRUE);
gtk_label_set_width_chars (GTK_LABEL (self->label), 3);
gtk_label_set_max_width_chars (GTK_LABEL (self->label), 30);
gtk_widget_set_parent (self->label, GTK_WIDGET (self));
self->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_vexpand (self->box, FALSE);
gtk_widget_set_parent (self->box, GTK_WIDGET (self));
self->inscription = gtk_inscription_new (NULL);
gtk_inscription_set_xalign (GTK_INSCRIPTION (self->inscription), 0.0);
gtk_inscription_set_yalign (GTK_INSCRIPTION (self->inscription), 0.0);
gtk_inscription_set_min_lines (GTK_INSCRIPTION (self->inscription), 3);
gtk_inscription_set_nat_chars (GTK_INSCRIPTION (self->inscription), 30);
gtk_widget_set_vexpand (self->inscription, TRUE);
gtk_box_append (GTK_BOX (self->box), self->inscription);
button = gtk_button_new_with_label ("Read More");
g_signal_connect (button, "clicked", G_CALLBACK (read_more_clicked), self);
gtk_box_append (GTK_BOX (self->box), button);
}
static void
read_more_set_text (ReadMore *self,
const char *text)
{
gtk_label_set_label (GTK_LABEL (self->label), text);
gtk_inscription_set_text (GTK_INSCRIPTION (self->inscription), text);
}
static GtkWidget *
read_more_new (const char *text)
{
ReadMore *self = g_object_new (READ_TYPE_MORE, NULL);
read_more_set_text (self, text);
return GTK_WIDGET (self);
}
GtkWidget *
do_read_more (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *readmore;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Read More");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
readmore = read_more_new (
"I'd just like to interject for a moment. What you're referring to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.\n"
"\n"
"Many computer users run a modified version of the GNU system every day, without realizing it. Through a peculiar turn of events, the version of GNU which is widely used today is often called \"Linux\", and many of its users are not aware that it is basically the GNU system, developed by the GNU Project.\n"
"\n"
"There really is a Linux, and these people are using it, but it is just a part of the system they use. Linux is the kernel: the program in the system that allocates the machine's resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. Linux is normally used in combination with the GNU operating system: the whole system is basically GNU with Linux added, or GNU/Linux. All the so-called \"Linux\" distributions are really distributions of GNU/Linux.");
gtk_window_set_child (GTK_WINDOW (window), readmore);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -86,6 +86,7 @@ enum
PROP_NAT_LINES,
PROP_TEXT,
PROP_TEXT_OVERFLOW,
PROP_WRAP_MODE,
PROP_XALIGN,
PROP_YALIGN,
@@ -154,6 +155,10 @@ gtk_inscription_get_property (GObject *object,
g_value_set_enum (value, self->overflow);
break;
case PROP_WRAP_MODE:
g_value_set_enum (value, pango_layout_get_wrap (self->layout));
break;
case PROP_XALIGN:
g_value_set_float (value, self->xalign);
break;
@@ -210,6 +215,10 @@ gtk_inscription_set_property (GObject *object,
gtk_inscription_set_text_overflow (self, g_value_get_enum (value));
break;
case PROP_WRAP_MODE:
gtk_inscription_set_wrap_mode (self, g_value_get_enum (value));
break;
case PROP_XALIGN:
gtk_inscription_set_xalign (self, g_value_get_float (value));
break;
@@ -395,9 +404,15 @@ gtk_inscription_get_layout_location (GtkInscription *self,
/* yalign is 0 because we can't support yalign while baseline aligning */
y = baseline - layout_baseline;
}
else if (pango_layout_is_ellipsized (self->layout))
{
y = 0.f;
}
else
{
y = floor ((widget_height - logical.height) * self->yalign);
if (y < 0)
y = 0.f;
}
*x_out = x;
@@ -620,6 +635,21 @@ gtk_inscription_class_init (GtkInscriptionClass *klass)
GTK_INSCRIPTION_OVERFLOW_CLIP,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GtkInscription:wrap-mode: (attributes org.gtk.Property.get=gtk_inscription_get_wrap_mode org.gtk.Property.set=gtk_inscription_set_wrap_mode)
*
* Controls how the line wrapping is done.
*
* Note that unlike `GtkLabel`, the default here is %PANGO_WRAP_WORD_CHAR.
*
* Since: 4.8
*/
properties[PROP_WRAP_MODE] =
g_param_spec_enum ("wrap-mode", NULL, NULL,
PANGO_TYPE_WRAP_MODE,
PANGO_WRAP_WORD_CHAR,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GtkInscription:xalign: (attributes org.gtk.Property.get=gtk_inscription_get_xalign org.gtk.Property.set=gtk_inscription_set_xalign)
*
@@ -1146,6 +1176,51 @@ gtk_inscription_get_text_overflow (GtkInscription *self)
return self->overflow;
}
/**
* gtk_inscription_set_wrap_mode: (attributes org.gtk.Method.set_property=wrap-mode)
* @self: a `GtkInscription`
* @wrap_mode: the line wrapping mode
*
* Controls how line wrapping is done.
*
* Since:4.8
*/
void
gtk_inscription_set_wrap_mode (GtkInscription *self,
PangoWrapMode wrap_mode)
{
g_return_if_fail (GTK_IS_INSCRIPTION (self));
if (pango_layout_get_wrap (self->layout) == wrap_mode)
return;
pango_layout_set_wrap (self->layout, wrap_mode);
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WRAP_MODE]);
}
/**
* gtk_inscription_get_wrap_mode: (attributes org.gtk.Method.get_property=wrap-mode)
* @self: a `GtkInscription`
*
* Returns line wrap mode used by the inscription.
*
* See [method@Gtk.Inscription.set_wrap_mode].
*
* Returns: the line wrap mode
*
* Since:4.8
*/
PangoWrapMode
gtk_inscription_get_wrap_mode (GtkInscription *self)
{
g_return_val_if_fail (GTK_IS_INSCRIPTION (self), PANGO_WRAP_WORD_CHAR);
return pango_layout_get_wrap (self->layout);
}
/**
* gtk_inscription_set_markup: (attributes org.gtk.Method.set_property=markup)
* @self: a `GtkInscription`

View File

@@ -71,6 +71,11 @@ GtkInscriptionOverflow gtk_inscription_get_text_overflow (GtkInscription
GDK_AVAILABLE_IN_4_8
void gtk_inscription_set_text_overflow (GtkInscription *self,
GtkInscriptionOverflow overflow);
GDK_AVAILABLE_IN_4_8
PangoWrapMode gtk_inscription_get_wrap_mode (GtkInscription *self);
GDK_AVAILABLE_IN_4_8
void gtk_inscription_set_wrap_mode (GtkInscription *self,
PangoWrapMode wrap_mode);
GDK_AVAILABLE_IN_4_8
guint gtk_inscription_get_min_chars (GtkInscription *self);

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow">
<property name="default-width">200</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkOverlay">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">
</property>
</object>
</child>
<child type="overlay">
<object class="GtkLabel">
<property name="label" translatable="yes">We wrap supercalifragilisticexpialidocious into 3 lines</property>
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<layout>
<property name="clip-overlay">1</property>
</layout>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">We wrap supercalifragilisticexpialidocious into 3 lines</property>
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="lines">2</property>
<property name="ellipsize">start</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">We wrap supercalifragilisticexpialidocious into 3 lines</property>
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="lines">2</property>
<property name="ellipsize">middle</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">We wrap supercalifragilisticexpialidocious into 3 lines</property>
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="lines">2</property>
<property name="ellipsize">end</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow">
<property name="default-width">200</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">We wrap supercalifragilisticexpialidocious into 3 lines</property>
<property name="text-overflow">clip</property>
<property name="yalign">0</property>
<property name="nat-lines">2</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">We wrap supercalifragilisticexpialidocious into 3 lines</property>
<property name="text-overflow">ellipsize-start</property>
<property name="nat-lines">2</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">We wrap supercalifragilisticexpialidocious into 3 lines</property>
<property name="text-overflow">ellipsize-middle</property>
<property name="nat-lines">2</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">We wrap supercalifragilisticexpialidocious into 3 lines</property>
<property name="text-overflow">ellipsize-end</property>
<property name="nat-lines">2</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow">
<property name="default-width">200</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="homogeneous">1</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">THIS
HIGH</property>
<attributes>
<attribute name="line-height" value="1.25" />
</attributes>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</property>
<property name="text-overflow">clip</property>
<property name="yalign">0.0</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</property>
<property name="text-overflow">ellipsize-start</property>
<property name="yalign">0.0</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</property>
<property name="text-overflow">ellipsize-middle</property>
<property name="yalign">0.0</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</property>
<property name="text-overflow">ellipsize-end</property>
<property name="yalign">0.0</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow">
<property name="default-width">200</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="homogeneous">1</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">THIS
HIGH</property>
<attributes>
<attribute name="line-height" value="1.25" />
</attributes>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</property>
<property name="text-overflow">clip</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</property>
<property name="text-overflow">ellipsize-start</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</property>
<property name="text-overflow">ellipsize-middle</property>
</object>
</child>
<child>
<object class="GtkInscription">
<property name="text" translatable="yes">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</property>
<property name="text-overflow">ellipsize-end</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -371,6 +371,10 @@ testdata = [
'inscription-markup.ui',
'inscription-overflow.ref.ui',
'inscription-overflow.ui',
'inscription-overflow-multiline.ref.ui',
'inscription-overflow-multiline.ui',
'inscription-overflow-yalign.ref.ui',
'inscription-overflow-yalign.ui',
'label-attribute-preference.css',
'label-attribute-preference.ref.ui',
'label-attribute-preference.ui',