diff --git a/projectorganizer/src/Makefile.am b/projectorganizer/src/Makefile.am index 91960801c..9ec5fd1b7 100644 --- a/projectorganizer/src/Makefile.am +++ b/projectorganizer/src/Makefile.am @@ -16,7 +16,9 @@ projectorganizer_la_SOURCES = \ prjorg-goto-panel.h \ prjorg-goto-panel.c \ prjorg-goto-anywhere.h \ - prjorg-goto-anywhere.c + prjorg-goto-anywhere.c \ + prjorg-wraplabel.h \ + prjorg-wraplabel.c projectorganizer_la_CPPFLAGS = $(AM_CPPFLAGS) \ -DG_LOG_DOMAIN=\"ProjectOrganizer\" diff --git a/projectorganizer/src/prjorg-project.c b/projectorganizer/src/prjorg-project.c index b21d36436..6fb9fd71f 100644 --- a/projectorganizer/src/prjorg-project.c +++ b/projectorganizer/src/prjorg-project.c @@ -28,6 +28,7 @@ #include "prjorg-utils.h" #include "prjorg-project.h" #include "prjorg-sidebar.h" +#include "prjorg-wraplabel.h" extern GeanyPlugin *geany_plugin; extern GeanyData *geany_data; @@ -736,10 +737,10 @@ GtkWidget *prjorg_project_add_properties_tab(GtkWidget *notebook) gtk_box_pack_start(GTK_BOX(vbox), table_box, FALSE, FALSE, 6); hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - label = gtk_label_new(_("The patterns above affect only sidebar and indexing and are not used in the Find in Files\n" - "dialog. You can further restrict the files belonging to the project by setting the\n" + label = prjorg_wrap_label_new(_("The patterns above affect only sidebar and indexing and are not used in the Find in Files " + "dialog. You can further restrict the files belonging to the project by setting the" "File Patterns under the Project tab (these are also used for the Find in Files dialog).")); - gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 12); + gtk_box_pack_start(GTK_BOX(hbox1), label, TRUE, TRUE, 12); gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 0); hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); diff --git a/projectorganizer/src/prjorg-wraplabel.c b/projectorganizer/src/prjorg-wraplabel.c new file mode 100644 index 000000000..8dca2372c --- /dev/null +++ b/projectorganizer/src/prjorg-wraplabel.c @@ -0,0 +1,212 @@ +/* + * prjorg-wraplabel.c - renamed copy of geanywraplabel.c from Geany + * + * Copyright 2009 The Geany contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * A GtkLabel subclass that can wrap to any width, unlike GtkLabel which has a fixed wrap point. + * (inspired by libview's WrapLabel, https://view.sourceforge.net/) + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "prjorg-wraplabel.h" + + +struct _PrjorgWrapLabelClass +{ + GtkLabelClass parent_class; +}; + +typedef struct +{ + gint wrap_width; + gint wrap_height; +} PrjorgWrapLabelPrivate; + +struct _PrjorgWrapLabel +{ + GtkLabel parent; + PrjorgWrapLabelPrivate *priv; +}; + + +static gboolean prjorg_wrap_label_draw(GtkWidget *widget, cairo_t *cr); +static void prjorg_wrap_label_get_preferred_width (GtkWidget *widget, + gint *minimal_width, gint *natural_width); +static void prjorg_wrap_label_get_preferred_height (GtkWidget *widget, + gint *minimal_height, gint *natural_height); +static void prjorg_wrap_label_get_preferred_width_for_height (GtkWidget *widget, + gint height, gint *minimal_width, gint *natural_width); +static void prjorg_wrap_label_get_preferred_height_for_width (GtkWidget *widget, + gint width, gint *minimal_height, gint *natural_height); +static GtkSizeRequestMode prjorg_wrap_label_get_request_mode(GtkWidget *widget); +static void prjorg_wrap_label_size_allocate (GtkWidget *widget, GtkAllocation *alloc); +static void prjorg_wrap_label_set_wrap_width (GtkWidget *widget, gint width); +static void prjorg_wrap_label_label_notify (GObject *object, GParamSpec *pspec, gpointer data); + +G_DEFINE_TYPE(PrjorgWrapLabel, prjorg_wrap_label, GTK_TYPE_LABEL) + + +static void prjorg_wrap_label_class_init(PrjorgWrapLabelClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + + widget_class->size_allocate = prjorg_wrap_label_size_allocate; + widget_class->draw = prjorg_wrap_label_draw; + widget_class->get_preferred_width = prjorg_wrap_label_get_preferred_width; + widget_class->get_preferred_width_for_height = prjorg_wrap_label_get_preferred_width_for_height; + widget_class->get_preferred_height = prjorg_wrap_label_get_preferred_height; + widget_class->get_preferred_height_for_width = prjorg_wrap_label_get_preferred_height_for_width; + widget_class->get_request_mode = prjorg_wrap_label_get_request_mode; + + g_type_class_add_private(klass, sizeof (PrjorgWrapLabelPrivate)); +} + + +static void prjorg_wrap_label_init(PrjorgWrapLabel *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, + PRJORG_WRAP_LABEL_TYPE, PrjorgWrapLabelPrivate); + + self->priv->wrap_width = 0; + self->priv->wrap_height = 0; + + g_signal_connect(self, "notify::label", G_CALLBACK(prjorg_wrap_label_label_notify), NULL); + gtk_misc_set_alignment(GTK_MISC(self), 0.0, 0.0); +} + + +/* Sets the point at which the text should wrap. */ +static void prjorg_wrap_label_set_wrap_width(GtkWidget *widget, gint width) +{ + PrjorgWrapLabel *self = PRJORG_WRAP_LABEL(widget); + PangoLayout *layout; + + if (width <= 0) + return; + + layout = gtk_label_get_layout(GTK_LABEL(widget)); + + /* + * We may need to reset the wrap width, so do this regardless of whether + * or not we've changed the width. + */ + pango_layout_set_width(layout, width * PANGO_SCALE); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); + pango_layout_get_pixel_size(layout, NULL, &self->priv->wrap_height); + + if (self->priv->wrap_width != width) + { + self->priv->wrap_width = width; + gtk_widget_queue_resize(widget); + } +} + + +/* updates the wrap width when the label text changes */ +static void prjorg_wrap_label_label_notify(GObject *object, GParamSpec *pspec, gpointer data) +{ + PrjorgWrapLabel *self = PRJORG_WRAP_LABEL(object); + + prjorg_wrap_label_set_wrap_width(GTK_WIDGET(object), self->priv->wrap_width); +} + + +/* makes sure the layout is setup for rendering and chains to parent renderer */ +static gboolean prjorg_wrap_label_draw(GtkWidget *widget, cairo_t *cr) +{ + PrjorgWrapLabel *self = PRJORG_WRAP_LABEL(widget); + PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(widget)); + + pango_layout_set_width(layout, self->priv->wrap_width * PANGO_SCALE); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); + + return (* GTK_WIDGET_CLASS(prjorg_wrap_label_parent_class)->draw)(widget, cr); +} + + +static void prjorg_wrap_label_get_preferred_width (GtkWidget *widget, + gint *minimal_width, gint *natural_width) +{ + *minimal_width = *natural_width = 0; +} + + +static void prjorg_wrap_label_get_preferred_width_for_height (GtkWidget *widget, + gint height, gint *minimal_width, gint *natural_width) +{ + PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(widget));; + + pango_layout_set_height(layout, height * PANGO_SCALE); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); + pango_layout_get_pixel_size(layout, natural_width, NULL); + + *minimal_width = 0; +} + + +static void prjorg_wrap_label_get_preferred_height (GtkWidget *widget, + gint *minimal_height, gint *natural_height) +{ + *minimal_height = *natural_height = PRJORG_WRAP_LABEL(widget)->priv->wrap_height; +} + + +static void prjorg_wrap_label_get_preferred_height_for_width (GtkWidget *widget, + gint width, gint *minimal_height, gint *natural_height) +{ + PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(widget)); + + pango_layout_set_width(layout, width * PANGO_SCALE); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); + pango_layout_get_pixel_size(layout, NULL, natural_height); + + *minimal_height = *natural_height; +} + + +static GtkSizeRequestMode prjorg_wrap_label_get_request_mode(GtkWidget *widget) +{ + return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT; +} + + +/* Sets the wrap width to the width allocated to us. */ +static void prjorg_wrap_label_size_allocate(GtkWidget *widget, GtkAllocation *alloc) +{ + GtkWidget *parent; + + (* GTK_WIDGET_CLASS(prjorg_wrap_label_parent_class)->size_allocate)(widget, alloc); + + prjorg_wrap_label_set_wrap_width(widget, alloc->width); + + /* ask the parent to recompute our size, because it seems GTK size + * caching is too aggressive */ + parent = gtk_widget_get_parent(widget); + if (GTK_IS_CONTAINER(parent)) + gtk_container_check_resize(GTK_CONTAINER(parent)); +} + + +GtkWidget *prjorg_wrap_label_new(const gchar *text) +{ + return g_object_new(PRJORG_WRAP_LABEL_TYPE, "label", text, NULL); +} diff --git a/projectorganizer/src/prjorg-wraplabel.h b/projectorganizer/src/prjorg-wraplabel.h new file mode 100644 index 000000000..efd22fdef --- /dev/null +++ b/projectorganizer/src/prjorg-wraplabel.h @@ -0,0 +1,49 @@ +/* + * prjorg- wraplabel.h - renamed copy of geanywraplabel.h from Geany + * + * Copyright 2009 The Geany contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PRJORG_WRAP_LABEL_H +#define PRJORG_WRAP_LABEL_H 1 + +#include "gtkcompat.h" + +G_BEGIN_DECLS + + +#define PRJORG_WRAP_LABEL_TYPE (prjorg_wrap_label_get_type()) +#define PRJORG_WRAP_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + PRJORG_WRAP_LABEL_TYPE, PrjorgWrapLabel)) +#define PRJORG_WRAP_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ + PRJORG_WRAP_LABEL_TYPE, PrjorgWrapLabelClass)) +#define IS_PRJORG_WRAP_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ + PRJORG_WRAP_LABEL_TYPE)) +#define IS_PRJORG_WRAP_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ + PRJORG_WRAP_LABEL_TYPE)) + + +typedef struct _PrjorgWrapLabel PrjorgWrapLabel; +typedef struct _PrjorgWrapLabelClass PrjorgWrapLabelClass; + +GType prjorg_wrap_label_get_type (void); +GtkWidget* prjorg_wrap_label_new (const gchar *text); + + +G_END_DECLS + +#endif /* PRJORG_WRAP_LABEL_H */