summaryrefslogtreecommitdiffstats
path: root/app/widgets/gimptextstyleeditor.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/widgets/gimptextstyleeditor.c')
-rw-r--r--app/widgets/gimptextstyleeditor.c1302
1 files changed, 1302 insertions, 0 deletions
diff --git a/app/widgets/gimptextstyleeditor.c b/app/widgets/gimptextstyleeditor.c
new file mode 100644
index 0000000..3f942d4
--- /dev/null
+++ b/app/widgets/gimptextstyleeditor.c
@@ -0,0 +1,1302 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * GimpTextStyleEditor
+ * Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
+ *
+ * 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 3 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpcontainer.h"
+#include "core/gimpcontext.h"
+
+#include "text/gimptext.h"
+
+#include "gimpcolorpanel.h"
+#include "gimpcontainerentry.h"
+#include "gimpcontainerview.h"
+#include "gimptextbuffer.h"
+#include "gimptextstyleeditor.h"
+#include "gimptexttag.h"
+#include "gimpwidgets-utils.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+ PROP_0,
+ PROP_GIMP,
+ PROP_TEXT,
+ PROP_BUFFER,
+ PROP_FONTS,
+ PROP_RESOLUTION_X,
+ PROP_RESOLUTION_Y
+};
+
+
+static void gimp_text_style_editor_constructed (GObject *object);
+static void gimp_text_style_editor_dispose (GObject *object);
+static void gimp_text_style_editor_finalize (GObject *object);
+static void gimp_text_style_editor_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_text_style_editor_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static GtkWidget * gimp_text_style_editor_create_toggle (GimpTextStyleEditor *editor,
+ GtkTextTag *tag,
+ const gchar *icon_name,
+ const gchar *tooltip);
+
+static void gimp_text_style_editor_clear_tags (GtkButton *button,
+ GimpTextStyleEditor *editor);
+
+static void gimp_text_style_editor_font_changed (GimpContext *context,
+ GimpFont *font,
+ GimpTextStyleEditor *editor);
+static void gimp_text_style_editor_set_font (GimpTextStyleEditor *editor,
+ GtkTextTag *font_tag);
+static void gimp_text_style_editor_set_default_font (GimpTextStyleEditor *editor);
+
+static void gimp_text_style_editor_color_changed (GimpColorButton *button,
+ GimpTextStyleEditor *editor);
+static void gimp_text_style_editor_set_color (GimpTextStyleEditor *editor,
+ GtkTextTag *color_tag);
+static void gimp_text_style_editor_set_default_color (GimpTextStyleEditor *editor);
+
+static void gimp_text_style_editor_tag_toggled (GtkToggleButton *toggle,
+ GimpTextStyleEditor *editor);
+static void gimp_text_style_editor_set_toggle (GimpTextStyleEditor *editor,
+ GtkToggleButton *toggle,
+ gboolean active);
+
+static void gimp_text_style_editor_size_changed (GimpSizeEntry *entry,
+ GimpTextStyleEditor *editor);
+static void gimp_text_style_editor_set_size (GimpTextStyleEditor *editor,
+ GtkTextTag *size_tag);
+static void gimp_text_style_editor_set_default_size (GimpTextStyleEditor *editor);
+
+static void gimp_text_style_editor_baseline_changed (GtkAdjustment *adjustment,
+ GimpTextStyleEditor *editor);
+static void gimp_text_style_editor_set_baseline (GimpTextStyleEditor *editor,
+ GtkTextTag *baseline_tag);
+
+static void gimp_text_style_editor_kerning_changed (GtkAdjustment *adjustment,
+ GimpTextStyleEditor *editor);
+static void gimp_text_style_editor_set_kerning (GimpTextStyleEditor *editor,
+ GtkTextTag *kerning_tag);
+
+static void gimp_text_style_editor_update (GimpTextStyleEditor *editor);
+static gboolean gimp_text_style_editor_update_idle (GimpTextStyleEditor *editor);
+
+
+G_DEFINE_TYPE (GimpTextStyleEditor, gimp_text_style_editor,
+ GTK_TYPE_BOX)
+
+#define parent_class gimp_text_style_editor_parent_class
+
+
+static void
+gimp_text_style_editor_class_init (GimpTextStyleEditorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = gimp_text_style_editor_constructed;
+ object_class->dispose = gimp_text_style_editor_dispose;
+ object_class->finalize = gimp_text_style_editor_finalize;
+ object_class->set_property = gimp_text_style_editor_set_property;
+ object_class->get_property = gimp_text_style_editor_get_property;
+
+ g_object_class_install_property (object_class, PROP_GIMP,
+ g_param_spec_object ("gimp",
+ NULL, NULL,
+ GIMP_TYPE_GIMP,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class, PROP_TEXT,
+ g_param_spec_object ("text",
+ NULL, NULL,
+ GIMP_TYPE_TEXT,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class, PROP_BUFFER,
+ g_param_spec_object ("buffer",
+ NULL, NULL,
+ GIMP_TYPE_TEXT_BUFFER,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class, PROP_FONTS,
+ g_param_spec_object ("fonts",
+ NULL, NULL,
+ GIMP_TYPE_CONTAINER,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class, PROP_RESOLUTION_X,
+ g_param_spec_double ("resolution-x",
+ NULL, NULL,
+ GIMP_MIN_RESOLUTION,
+ GIMP_MAX_RESOLUTION,
+ 1.0,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_RESOLUTION_Y,
+ g_param_spec_double ("resolution-y",
+ NULL, NULL,
+ GIMP_MIN_RESOLUTION,
+ GIMP_MAX_RESOLUTION,
+ 1.0,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+gimp_text_style_editor_init (GimpTextStyleEditor *editor)
+{
+ GtkWidget *image;
+ GimpRGB color;
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (editor),
+ GTK_ORIENTATION_VERTICAL);
+ gtk_box_set_spacing (GTK_BOX (editor), 2);
+
+ /* upper row */
+
+ editor->upper_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+ gtk_box_pack_start (GTK_BOX (editor), editor->upper_hbox, FALSE, FALSE, 0);
+ gtk_widget_show (editor->upper_hbox);
+
+ editor->font_entry = gimp_container_entry_new (NULL, NULL,
+ GIMP_VIEW_SIZE_SMALL, 1);
+ gtk_box_pack_start (GTK_BOX (editor->upper_hbox), editor->font_entry,
+ FALSE, FALSE, 0);
+ gtk_widget_show (editor->font_entry);
+
+ gimp_help_set_help_data (editor->font_entry,
+ _("Change font of selected text"), NULL);
+
+ editor->size_entry =
+ gimp_size_entry_new (1, 0, "%a", TRUE, FALSE, FALSE, 10,
+ GIMP_SIZE_ENTRY_UPDATE_SIZE);
+ gtk_table_set_col_spacing (GTK_TABLE (editor->size_entry), 1, 0);
+ gtk_box_pack_start (GTK_BOX (editor->upper_hbox), editor->size_entry,
+ FALSE, FALSE, 0);
+ gtk_widget_show (editor->size_entry);
+
+ gimp_help_set_help_data (editor->size_entry,
+ _("Change size of selected text"), NULL);
+
+ g_signal_connect (editor->size_entry, "value-changed",
+ G_CALLBACK (gimp_text_style_editor_size_changed),
+ editor);
+
+ /* lower row */
+
+ editor->lower_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+ gtk_box_pack_start (GTK_BOX (editor), editor->lower_hbox, FALSE, FALSE, 0);
+ gtk_widget_show (editor->lower_hbox);
+
+ editor->clear_button = gtk_button_new ();
+ gtk_widget_set_can_focus (editor->clear_button, FALSE);
+ gtk_box_pack_start (GTK_BOX (editor->lower_hbox), editor->clear_button,
+ FALSE, FALSE, 0);
+ gtk_widget_show (editor->clear_button);
+
+ gimp_help_set_help_data (editor->clear_button,
+ _("Clear style of selected text"), NULL);
+
+ g_signal_connect (editor->clear_button, "clicked",
+ G_CALLBACK (gimp_text_style_editor_clear_tags),
+ editor);
+
+ image = gtk_image_new_from_icon_name ("edit-clear", GTK_ICON_SIZE_MENU);
+ gtk_container_add (GTK_CONTAINER (editor->clear_button), image);
+ gtk_widget_show (image);
+
+ gimp_rgba_set (&color, 0.0, 0.0, 0.0, 1.0);
+ editor->color_button = gimp_color_panel_new (_("Change color of selected text"),
+ &color,
+ GIMP_COLOR_AREA_FLAT, 20, 20);
+ gimp_widget_set_fully_opaque (editor->color_button, TRUE);
+
+ gtk_box_pack_end (GTK_BOX (editor->lower_hbox), editor->color_button,
+ FALSE, FALSE, 0);
+ gtk_widget_show (editor->color_button);
+
+ gimp_help_set_help_data (editor->color_button,
+ _("Change color of selected text"), NULL);
+
+ g_signal_connect (editor->color_button, "color-changed",
+ G_CALLBACK (gimp_text_style_editor_color_changed),
+ editor);
+
+ editor->kerning_adjustment =
+ GTK_ADJUSTMENT (gtk_adjustment_new (0.0, -1000.0, 1000.0, 1.0, 10.0, 0.0));
+ editor->kerning_spinbutton =
+ gimp_spin_button_new (editor->kerning_adjustment, 1.0, 1);
+ gtk_entry_set_width_chars (GTK_ENTRY (editor->kerning_spinbutton), 5);
+ gtk_box_pack_end (GTK_BOX (editor->lower_hbox), editor->kerning_spinbutton,
+ FALSE, FALSE, 0);
+ gtk_widget_show (editor->kerning_spinbutton);
+
+ gimp_help_set_help_data (editor->kerning_spinbutton,
+ _("Change kerning of selected text"), NULL);
+
+ g_signal_connect (editor->kerning_adjustment, "value-changed",
+ G_CALLBACK (gimp_text_style_editor_kerning_changed),
+ editor);
+
+ editor->baseline_adjustment =
+ GTK_ADJUSTMENT (gtk_adjustment_new (0.0, -1000.0, 1000.0, 1.0, 10.0, 0.0));
+ editor->baseline_spinbutton =
+ gimp_spin_button_new (editor->baseline_adjustment, 1.0, 1);
+ gtk_entry_set_width_chars (GTK_ENTRY (editor->baseline_spinbutton), 5);
+ gtk_box_pack_end (GTK_BOX (editor->lower_hbox), editor->baseline_spinbutton,
+ FALSE, FALSE, 0);
+ gtk_widget_show (editor->baseline_spinbutton);
+
+ gimp_help_set_help_data (editor->baseline_spinbutton,
+ _("Change baseline of selected text"), NULL);
+
+ g_signal_connect (editor->baseline_adjustment, "value-changed",
+ G_CALLBACK (gimp_text_style_editor_baseline_changed),
+ editor);
+}
+
+static void
+gimp_text_style_editor_constructed (GObject *object)
+{
+ GimpTextStyleEditor *editor = GIMP_TEXT_STYLE_EDITOR (object);
+
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ gimp_assert (GIMP_IS_GIMP (editor->gimp));
+ gimp_assert (GIMP_IS_CONTAINER (editor->fonts));
+ gimp_assert (GIMP_IS_TEXT (editor->text));
+ gimp_assert (GIMP_IS_TEXT_BUFFER (editor->buffer));
+
+ editor->context = gimp_context_new (editor->gimp, "text style editor", NULL);
+
+ g_signal_connect (editor->context, "font-changed",
+ G_CALLBACK (gimp_text_style_editor_font_changed),
+ editor);
+
+ gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (editor->size_entry), 0,
+ editor->resolution_y, TRUE);
+
+ /* use the global user context so we get the global FG/BG colors */
+ gimp_color_panel_set_context (GIMP_COLOR_PANEL (editor->color_button),
+ gimp_get_user_context (editor->gimp));
+
+ gimp_container_view_set_container (GIMP_CONTAINER_VIEW (editor->font_entry),
+ editor->fonts);
+ gimp_container_view_set_context (GIMP_CONTAINER_VIEW (editor->font_entry),
+ editor->context);
+
+ gimp_text_style_editor_create_toggle (editor, editor->buffer->bold_tag,
+ GIMP_ICON_FORMAT_TEXT_BOLD,
+ _("Bold"));
+ gimp_text_style_editor_create_toggle (editor, editor->buffer->italic_tag,
+ GIMP_ICON_FORMAT_TEXT_ITALIC,
+ _("Italic"));
+ gimp_text_style_editor_create_toggle (editor, editor->buffer->underline_tag,
+ GIMP_ICON_FORMAT_TEXT_UNDERLINE,
+ _("Underline"));
+ gimp_text_style_editor_create_toggle (editor, editor->buffer->strikethrough_tag,
+ GIMP_ICON_FORMAT_TEXT_STRIKETHROUGH,
+ _("Strikethrough"));
+
+ g_signal_connect_swapped (editor->text, "notify::font",
+ G_CALLBACK (gimp_text_style_editor_update),
+ editor);
+ g_signal_connect_swapped (editor->text, "notify::font-size",
+ G_CALLBACK (gimp_text_style_editor_update),
+ editor);
+ g_signal_connect_swapped (editor->text, "notify::font-size-unit",
+ G_CALLBACK (gimp_text_style_editor_update),
+ editor);
+ g_signal_connect_swapped (editor->text, "notify::color",
+ G_CALLBACK (gimp_text_style_editor_update),
+ editor);
+
+ g_signal_connect_data (editor->buffer, "changed",
+ G_CALLBACK (gimp_text_style_editor_update),
+ editor, 0,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+ g_signal_connect_data (editor->buffer, "apply-tag",
+ G_CALLBACK (gimp_text_style_editor_update),
+ editor, 0,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+ g_signal_connect_data (editor->buffer, "remove-tag",
+ G_CALLBACK (gimp_text_style_editor_update),
+ editor, 0,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+ g_signal_connect_data (editor->buffer, "mark-set",
+ G_CALLBACK (gimp_text_style_editor_update),
+ editor, 0,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+
+ gimp_text_style_editor_update (editor);
+}
+
+static void
+gimp_text_style_editor_dispose (GObject *object)
+{
+ GimpTextStyleEditor *editor = GIMP_TEXT_STYLE_EDITOR (object);
+
+ if (editor->text)
+ {
+ g_signal_handlers_disconnect_by_func (editor->text,
+ gimp_text_style_editor_update,
+ editor);
+ }
+
+ if (editor->buffer)
+ {
+ g_signal_handlers_disconnect_by_func (editor->buffer,
+ gimp_text_style_editor_update,
+ editor);
+ }
+
+ if (editor->update_idle_id)
+ {
+ g_source_remove (editor->update_idle_id);
+ editor->update_idle_id = 0;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gimp_text_style_editor_finalize (GObject *object)
+{
+ GimpTextStyleEditor *editor = GIMP_TEXT_STYLE_EDITOR (object);
+
+ g_clear_object (&editor->context);
+ g_clear_object (&editor->text);
+ g_clear_object (&editor->buffer);
+ g_clear_object (&editor->fonts);
+
+ if (editor->toggles)
+ {
+ g_list_free (editor->toggles);
+ editor->toggles = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_text_style_editor_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpTextStyleEditor *editor = GIMP_TEXT_STYLE_EDITOR (object);
+
+ switch (property_id)
+ {
+ case PROP_GIMP:
+ editor->gimp = g_value_get_object (value); /* don't ref */
+ break;
+ case PROP_TEXT:
+ editor->text = g_value_dup_object (value);
+ break;
+ case PROP_BUFFER:
+ editor->buffer = g_value_dup_object (value);
+ break;
+ case PROP_FONTS:
+ editor->fonts = g_value_dup_object (value);
+ break;
+ case PROP_RESOLUTION_X:
+ editor->resolution_x = g_value_get_double (value);
+ break;
+ case PROP_RESOLUTION_Y:
+ editor->resolution_y = g_value_get_double (value);
+ if (editor->size_entry)
+ gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (editor->size_entry), 0,
+ editor->resolution_y, TRUE);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_text_style_editor_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpTextStyleEditor *editor = GIMP_TEXT_STYLE_EDITOR (object);
+
+ switch (property_id)
+ {
+ case PROP_GIMP:
+ g_value_set_object (value, editor->gimp);
+ break;
+ case PROP_TEXT:
+ g_value_set_object (value, editor->text);
+ break;
+ case PROP_BUFFER:
+ g_value_set_object (value, editor->buffer);
+ break;
+ case PROP_FONTS:
+ g_value_set_object (value, editor->fonts);
+ break;
+ case PROP_RESOLUTION_X:
+ g_value_set_double (value, editor->resolution_x);
+ break;
+ case PROP_RESOLUTION_Y:
+ g_value_set_double (value, editor->resolution_y);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+/* public functions */
+
+GtkWidget *
+gimp_text_style_editor_new (Gimp *gimp,
+ GimpText *text,
+ GimpTextBuffer *buffer,
+ GimpContainer *fonts,
+ gdouble resolution_x,
+ gdouble resolution_y)
+{
+ g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
+ g_return_val_if_fail (GIMP_IS_TEXT (text), NULL);
+ g_return_val_if_fail (GIMP_IS_TEXT_BUFFER (buffer), NULL);
+ g_return_val_if_fail (resolution_x > 0.0, NULL);
+ g_return_val_if_fail (resolution_y > 0.0, NULL);
+
+ return g_object_new (GIMP_TYPE_TEXT_STYLE_EDITOR,
+ "gimp", gimp,
+ "text", text,
+ "buffer", buffer,
+ "fonts", fonts,
+ "resolution-x", resolution_x,
+ "resolution-y", resolution_y,
+ NULL);
+}
+
+GList *
+gimp_text_style_editor_list_tags (GimpTextStyleEditor *editor,
+ GList **remove_tags)
+{
+ GList *toggles;
+ GList *tags = NULL;
+
+ g_return_val_if_fail (GIMP_IS_TEXT_STYLE_EDITOR (editor), NULL);
+ g_return_val_if_fail (remove_tags != NULL, NULL);
+
+ *remove_tags = NULL;
+
+ for (toggles = editor->toggles; toggles; toggles = g_list_next (toggles))
+ {
+ GtkTextTag *tag = g_object_get_data (toggles->data, "tag");
+
+ if (gtk_toggle_button_get_active (toggles->data))
+ {
+ tags = g_list_prepend (tags, tag);
+ }
+ else
+ {
+ *remove_tags = g_list_prepend (*remove_tags, tag);
+ }
+ }
+
+ {
+ GList *list;
+ gdouble pixels;
+
+ for (list = editor->buffer->size_tags; list; list = g_list_next (list))
+ *remove_tags = g_list_prepend (*remove_tags, list->data);
+
+ pixels = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (editor->size_entry), 0);
+
+ if (pixels != 0.0)
+ {
+ GtkTextTag *tag;
+ gdouble points;
+
+ points = gimp_units_to_points (pixels,
+ GIMP_UNIT_PIXEL,
+ editor->resolution_y);
+ tag = gimp_text_buffer_get_size_tag (editor->buffer,
+ PANGO_SCALE * points);
+ tags = g_list_prepend (tags, tag);
+ }
+ }
+
+ {
+ GList *list;
+ const gchar *font_name;
+
+ for (list = editor->buffer->font_tags; list; list = g_list_next (list))
+ *remove_tags = g_list_prepend (*remove_tags, list->data);
+
+ font_name = gimp_context_get_font_name (editor->context);
+
+ if (font_name)
+ {
+ GtkTextTag *tag;
+
+ tag = gimp_text_buffer_get_font_tag (editor->buffer, font_name);
+ tags = g_list_prepend (tags, tag);
+ }
+ }
+
+ {
+ GList *list;
+ GimpRGB color;
+
+ for (list = editor->buffer->color_tags; list; list = g_list_next (list))
+ *remove_tags = g_list_prepend (*remove_tags, list->data);
+
+ gimp_color_button_get_color (GIMP_COLOR_BUTTON (editor->color_button),
+ &color);
+
+ if (TRUE) /* FIXME should have "inconsistent" state as for font and size */
+ {
+ GtkTextTag *tag;
+
+ tag = gimp_text_buffer_get_color_tag (editor->buffer, &color);
+ tags = g_list_prepend (tags, tag);
+ }
+ }
+
+ *remove_tags = g_list_reverse (*remove_tags);
+
+ return g_list_reverse (tags);
+}
+
+
+/* private functions */
+
+static GtkWidget *
+gimp_text_style_editor_create_toggle (GimpTextStyleEditor *editor,
+ GtkTextTag *tag,
+ const gchar *icon_name,
+ const gchar *tooltip)
+{
+ GtkWidget *toggle;
+ GtkWidget *image;
+
+ toggle = gtk_toggle_button_new ();
+ gtk_widget_set_can_focus (toggle, FALSE);
+ gtk_box_pack_start (GTK_BOX (editor->lower_hbox), toggle, FALSE, FALSE, 0);
+ gtk_widget_show (toggle);
+
+ gimp_help_set_help_data (toggle, tooltip, NULL);
+
+ editor->toggles = g_list_append (editor->toggles, toggle);
+ g_object_set_data (G_OBJECT (toggle), "tag", tag);
+
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (gimp_text_style_editor_tag_toggled),
+ editor);
+
+ image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
+ gtk_container_add (GTK_CONTAINER (toggle), image);
+ gtk_widget_show (image);
+
+ return toggle;
+}
+
+static void
+gimp_text_style_editor_clear_tags (GtkButton *button,
+ GimpTextStyleEditor *editor)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->buffer);
+
+ if (gtk_text_buffer_get_has_selection (buffer))
+ {
+ GtkTextIter start, end;
+
+ gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+
+ gtk_text_buffer_begin_user_action (buffer);
+
+ gtk_text_buffer_remove_all_tags (buffer, &start, &end);
+
+ gtk_text_buffer_end_user_action (buffer);
+ }
+}
+
+static void
+gimp_text_style_editor_font_changed (GimpContext *context,
+ GimpFont *font,
+ GimpTextStyleEditor *editor)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->buffer);
+ GList *insert_tags;
+ GList *remove_tags;
+
+ if (gtk_text_buffer_get_has_selection (buffer))
+ {
+ GtkTextIter start, end;
+
+ gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+
+ gimp_text_buffer_set_font (editor->buffer, &start, &end,
+ gimp_context_get_font_name (context));
+ }
+
+ insert_tags = gimp_text_style_editor_list_tags (editor, &remove_tags);
+ gimp_text_buffer_set_insert_tags (editor->buffer, insert_tags, remove_tags);
+}
+
+static void
+gimp_text_style_editor_set_font (GimpTextStyleEditor *editor,
+ GtkTextTag *font_tag)
+{
+ gchar *font = NULL;
+
+ if (font_tag)
+ font = gimp_text_tag_get_font (font_tag);
+
+ g_signal_handlers_block_by_func (editor->context,
+ gimp_text_style_editor_font_changed,
+ editor);
+
+ gimp_context_set_font_name (editor->context, font);
+
+ g_signal_handlers_unblock_by_func (editor->context,
+ gimp_text_style_editor_font_changed,
+ editor);
+
+ g_free (font);
+}
+
+static void
+gimp_text_style_editor_set_default_font (GimpTextStyleEditor *editor)
+{
+ g_signal_handlers_block_by_func (editor->context,
+ gimp_text_style_editor_font_changed,
+ editor);
+
+ gimp_context_set_font_name (editor->context, editor->text->font);
+
+ g_signal_handlers_unblock_by_func (editor->context,
+ gimp_text_style_editor_font_changed,
+ editor);
+}
+
+static void
+gimp_text_style_editor_color_changed (GimpColorButton *button,
+ GimpTextStyleEditor *editor)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->buffer);
+ GList *insert_tags;
+ GList *remove_tags;
+
+ if (gtk_text_buffer_get_has_selection (buffer))
+ {
+ GtkTextIter start, end;
+ GimpRGB color;
+
+ gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+
+ gimp_color_button_get_color (button, &color);
+ gimp_text_buffer_set_color (editor->buffer, &start, &end, &color);
+ }
+
+ insert_tags = gimp_text_style_editor_list_tags (editor, &remove_tags);
+ gimp_text_buffer_set_insert_tags (editor->buffer, insert_tags, remove_tags);
+}
+
+static void
+gimp_text_style_editor_set_color (GimpTextStyleEditor *editor,
+ GtkTextTag *color_tag)
+{
+ GimpRGB color;
+
+ gimp_rgba_set (&color, 0.0, 0.0, 0.0, 1.0);
+
+ if (color_tag)
+ gimp_text_tag_get_fg_color (color_tag, &color);
+
+ g_signal_handlers_block_by_func (editor->color_button,
+ gimp_text_style_editor_color_changed,
+ editor);
+
+ gimp_color_button_set_color (GIMP_COLOR_BUTTON (editor->color_button),
+ &color);
+
+ /* FIXME should have "inconsistent" state as for font and size */
+
+ g_signal_handlers_unblock_by_func (editor->color_button,
+ gimp_text_style_editor_color_changed,
+ editor);
+}
+
+static void
+gimp_text_style_editor_set_default_color (GimpTextStyleEditor *editor)
+{
+ g_signal_handlers_block_by_func (editor->color_button,
+ gimp_text_style_editor_color_changed,
+ editor);
+
+ gimp_color_button_set_color (GIMP_COLOR_BUTTON (editor->color_button),
+ &editor->text->color);
+
+ g_signal_handlers_unblock_by_func (editor->color_button,
+ gimp_text_style_editor_color_changed,
+ editor);
+}
+
+static void
+gimp_text_style_editor_tag_toggled (GtkToggleButton *toggle,
+ GimpTextStyleEditor *editor)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->buffer);
+ GtkTextTag *tag = g_object_get_data (G_OBJECT (toggle), "tag");
+ GList *insert_tags;
+ GList *remove_tags;
+
+ if (gtk_text_buffer_get_has_selection (buffer))
+ {
+ GtkTextIter start, end;
+
+ gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+
+ gtk_text_buffer_begin_user_action (buffer);
+
+ if (gtk_toggle_button_get_active (toggle))
+ {
+ gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
+ }
+ else
+ {
+ gtk_text_buffer_remove_tag (buffer, tag, &start, &end);
+ }
+
+ gtk_text_buffer_end_user_action (buffer);
+ }
+
+ insert_tags = gimp_text_style_editor_list_tags (editor, &remove_tags);
+ gimp_text_buffer_set_insert_tags (editor->buffer, insert_tags, remove_tags);
+}
+
+static void
+gimp_text_style_editor_set_toggle (GimpTextStyleEditor *editor,
+ GtkToggleButton *toggle,
+ gboolean active)
+{
+ g_signal_handlers_block_by_func (toggle,
+ gimp_text_style_editor_tag_toggled,
+ editor);
+
+ gtk_toggle_button_set_active (toggle, active);
+
+ g_signal_handlers_unblock_by_func (toggle,
+ gimp_text_style_editor_tag_toggled,
+ editor);
+}
+
+static void
+gimp_text_style_editor_size_changed (GimpSizeEntry *entry,
+ GimpTextStyleEditor *editor)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->buffer);
+ GList *insert_tags;
+ GList *remove_tags;
+
+ if (gtk_text_buffer_get_has_selection (buffer))
+ {
+ GtkTextIter start, end;
+ gdouble points;
+
+ gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+
+ points = gimp_units_to_points (gimp_size_entry_get_refval (entry, 0),
+ GIMP_UNIT_PIXEL,
+ editor->resolution_y);
+
+ gimp_text_buffer_set_size (editor->buffer, &start, &end,
+ PANGO_SCALE * points);
+ }
+
+ insert_tags = gimp_text_style_editor_list_tags (editor, &remove_tags);
+ gimp_text_buffer_set_insert_tags (editor->buffer, insert_tags, remove_tags);
+}
+
+static void
+gimp_text_style_editor_set_size (GimpTextStyleEditor *editor,
+ GtkTextTag *size_tag)
+{
+ gint size = 0;
+ gdouble pixels;
+
+ if (size_tag)
+ size = gimp_text_tag_get_size (size_tag);
+
+ g_signal_handlers_block_by_func (editor->size_entry,
+ gimp_text_style_editor_size_changed,
+ editor);
+
+ pixels = gimp_units_to_pixels ((gdouble) size / PANGO_SCALE,
+ GIMP_UNIT_POINT,
+ editor->resolution_y);
+ gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (editor->size_entry), 0, pixels);
+
+ if (size == 0)
+ {
+ GtkWidget *spinbutton;
+
+ spinbutton = gimp_size_entry_get_help_widget (GIMP_SIZE_ENTRY (editor->size_entry), 0);
+
+ gtk_entry_set_text (GTK_ENTRY (spinbutton), "");
+ }
+
+ g_signal_handlers_unblock_by_func (editor->size_entry,
+ gimp_text_style_editor_size_changed,
+ editor);
+}
+
+static void
+gimp_text_style_editor_set_default_size (GimpTextStyleEditor *editor)
+{
+ gdouble pixels = gimp_units_to_pixels (editor->text->font_size,
+ editor->text->unit,
+ editor->resolution_y);
+
+ g_signal_handlers_block_by_func (editor->size_entry,
+ gimp_text_style_editor_size_changed,
+ editor);
+
+ gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (editor->size_entry), 0, pixels);
+
+ g_signal_handlers_unblock_by_func (editor->size_entry,
+ gimp_text_style_editor_size_changed,
+ editor);
+}
+
+static void
+gimp_text_style_editor_baseline_changed (GtkAdjustment *adjustment,
+ GimpTextStyleEditor *editor)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->buffer);
+ GtkTextIter start, end;
+
+ if (! gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+ {
+ gtk_text_buffer_get_iter_at_mark (buffer, &start,
+ gtk_text_buffer_get_insert (buffer));
+ gtk_text_buffer_get_end_iter (buffer, &end);
+ }
+
+ gimp_text_buffer_set_baseline (editor->buffer, &start, &end,
+ gtk_adjustment_get_value (adjustment) *
+ PANGO_SCALE);
+}
+
+static void
+gimp_text_style_editor_set_baseline (GimpTextStyleEditor *editor,
+ GtkTextTag *baseline_tag)
+{
+ gint baseline = 0;
+
+ if (baseline_tag)
+ baseline = gimp_text_tag_get_baseline (baseline_tag);
+
+ g_signal_handlers_block_by_func (editor->baseline_adjustment,
+ gimp_text_style_editor_baseline_changed,
+ editor);
+
+ gtk_adjustment_set_value (editor->baseline_adjustment,
+ (gdouble) baseline / PANGO_SCALE);
+ /* make sure the "" really gets replaced */
+ gtk_adjustment_value_changed (editor->baseline_adjustment);
+
+ g_signal_handlers_unblock_by_func (editor->baseline_adjustment,
+ gimp_text_style_editor_baseline_changed,
+ editor);
+}
+
+static void
+gimp_text_style_editor_kerning_changed (GtkAdjustment *adjustment,
+ GimpTextStyleEditor *editor)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->buffer);
+ GtkTextIter start, end;
+
+ if (! gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+ {
+ gtk_text_buffer_get_iter_at_mark (buffer, &start,
+ gtk_text_buffer_get_insert (buffer));
+ end = start;
+ gtk_text_iter_forward_char (&end);
+ }
+
+ gimp_text_buffer_set_kerning (editor->buffer, &start, &end,
+ gtk_adjustment_get_value (adjustment) *
+ PANGO_SCALE);
+}
+
+static void
+gimp_text_style_editor_set_kerning (GimpTextStyleEditor *editor,
+ GtkTextTag *kerning_tag)
+{
+ gint kerning = 0;
+
+ if (kerning_tag)
+ kerning = gimp_text_tag_get_kerning (kerning_tag);
+
+ g_signal_handlers_block_by_func (editor->kerning_adjustment,
+ gimp_text_style_editor_kerning_changed,
+ editor);
+
+ gtk_adjustment_set_value (editor->kerning_adjustment,
+ (gdouble) kerning / PANGO_SCALE);
+ /* make sure the "" really gets replaced */
+ gtk_adjustment_value_changed (editor->kerning_adjustment);
+
+ g_signal_handlers_unblock_by_func (editor->kerning_adjustment,
+ gimp_text_style_editor_kerning_changed,
+ editor);
+}
+
+static void
+gimp_text_style_editor_update (GimpTextStyleEditor *editor)
+{
+ if (editor->update_idle_id)
+ g_source_remove (editor->update_idle_id);
+
+ editor->update_idle_id =
+ gdk_threads_add_idle ((GSourceFunc) gimp_text_style_editor_update_idle,
+ editor);
+}
+
+static gboolean
+gimp_text_style_editor_update_idle (GimpTextStyleEditor *editor)
+{
+ GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->buffer);
+
+ if (editor->update_idle_id)
+ {
+ g_source_remove (editor->update_idle_id);
+ editor->update_idle_id = 0;
+ }
+
+ if (gtk_text_buffer_get_has_selection (buffer))
+ {
+ GtkTextIter start, end;
+ GtkTextIter iter;
+ GList *list;
+ gboolean any_toggle_active = TRUE;
+ gboolean font_differs = FALSE;
+ gboolean color_differs = FALSE;
+ gboolean size_differs = FALSE;
+ gboolean baseline_differs = FALSE;
+ gboolean kerning_differs = FALSE;
+ GtkTextTag *font_tag = NULL;
+ GtkTextTag *color_tag = NULL;
+ GtkTextTag *size_tag = NULL;
+ GtkTextTag *baseline_tag = NULL;
+ GtkTextTag *kerning_tag = NULL;
+
+ gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+ gtk_text_iter_order (&start, &end);
+
+ /* first, switch all toggles on */
+ for (list = editor->toggles; list; list = g_list_next (list))
+ {
+ GtkToggleButton *toggle = list->data;
+
+ gimp_text_style_editor_set_toggle (editor, toggle, TRUE);
+ }
+
+ /* and get some initial values */
+ font_tag = gimp_text_buffer_get_iter_font (editor->buffer,
+ &start, NULL);
+ color_tag = gimp_text_buffer_get_iter_color (editor->buffer,
+ &start, NULL);
+ size_tag = gimp_text_buffer_get_iter_size (editor->buffer,
+ &start, NULL);
+ baseline_tag = gimp_text_buffer_get_iter_baseline (editor->buffer,
+ &start, NULL);
+ kerning_tag = gimp_text_buffer_get_iter_kerning (editor->buffer,
+ &start, NULL);
+
+ for (iter = start;
+ gtk_text_iter_in_range (&iter, &start, &end);
+ gtk_text_iter_forward_cursor_position (&iter))
+ {
+ if (any_toggle_active)
+ {
+ any_toggle_active = FALSE;
+
+ for (list = editor->toggles; list; list = g_list_next (list))
+ {
+ GtkToggleButton *toggle = list->data;
+ GtkTextTag *tag = g_object_get_data (G_OBJECT (toggle),
+ "tag");
+
+ if (! gtk_text_iter_has_tag (&iter, tag))
+ {
+ gimp_text_style_editor_set_toggle (editor, toggle, FALSE);
+ }
+ else
+ {
+ any_toggle_active = TRUE;
+ }
+ }
+ }
+
+ if (! font_differs)
+ {
+ GtkTextTag *tag;
+
+ tag = gimp_text_buffer_get_iter_font (editor->buffer, &iter,
+ NULL);
+
+ if (tag != font_tag)
+ font_differs = TRUE;
+ }
+
+ if (! color_differs)
+ {
+ GtkTextTag *tag;
+
+ tag = gimp_text_buffer_get_iter_color (editor->buffer, &iter,
+ NULL);
+
+ if (tag != color_tag)
+ color_differs = TRUE;
+ }
+
+ if (! size_differs)
+ {
+ GtkTextTag *tag;
+
+ tag = gimp_text_buffer_get_iter_size (editor->buffer, &iter,
+ NULL);
+
+ if (tag != size_tag)
+ size_differs = TRUE;
+ }
+
+ if (! baseline_differs)
+ {
+ GtkTextTag *tag;
+
+ tag = gimp_text_buffer_get_iter_baseline (editor->buffer, &iter,
+ NULL);
+
+ if (tag != baseline_tag)
+ baseline_differs = TRUE;
+ }
+
+ if (! kerning_differs)
+ {
+ GtkTextTag *tag;
+
+ tag = gimp_text_buffer_get_iter_kerning (editor->buffer, &iter,
+ NULL);
+
+ if (tag != kerning_tag)
+ kerning_differs = TRUE;
+ }
+
+ if (! any_toggle_active &&
+ color_differs &&
+ font_differs &&
+ size_differs &&
+ baseline_differs &&
+ kerning_differs)
+ break;
+ }
+
+ if (font_differs)
+ gimp_text_style_editor_set_font (editor, NULL);
+ else if (font_tag)
+ gimp_text_style_editor_set_font (editor, font_tag);
+ else
+ gimp_text_style_editor_set_default_font (editor);
+
+ if (color_differs)
+ gimp_text_style_editor_set_color (editor, NULL);
+ else if (color_tag)
+ gimp_text_style_editor_set_color (editor, color_tag);
+ else
+ gimp_text_style_editor_set_default_color (editor);
+
+ if (size_differs)
+ gimp_text_style_editor_set_size (editor, NULL);
+ else if (size_tag)
+ gimp_text_style_editor_set_size (editor, size_tag);
+ else
+ gimp_text_style_editor_set_default_size (editor);
+
+ if (baseline_differs)
+ gtk_entry_set_text (GTK_ENTRY (editor->baseline_spinbutton), "");
+ else
+ gimp_text_style_editor_set_baseline (editor, baseline_tag);
+
+ if (kerning_differs)
+ gtk_entry_set_text (GTK_ENTRY (editor->kerning_spinbutton), "");
+ else
+ gimp_text_style_editor_set_kerning (editor, kerning_tag);
+ }
+ else /* no selection */
+ {
+ GtkTextIter cursor;
+ GSList *tags;
+ GSList *tags_on;
+ GSList *tags_off;
+ GList *list;
+
+ gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
+ gtk_text_buffer_get_insert (buffer));
+
+ tags = gtk_text_iter_get_tags (&cursor);
+ tags_on = gtk_text_iter_get_toggled_tags (&cursor, TRUE);
+ tags_off = gtk_text_iter_get_toggled_tags (&cursor, FALSE);
+
+ for (list = editor->buffer->font_tags; list; list = g_list_next (list))
+ {
+ GtkTextTag *tag = list->data;
+
+ if ((g_slist_find (tags, tag) &&
+ ! g_slist_find (tags_on, tag)) ||
+ g_slist_find (tags_off, tag))
+ {
+ gimp_text_style_editor_set_font (editor, tag);
+ break;
+ }
+ }
+
+ if (! list)
+ gimp_text_style_editor_set_default_font (editor);
+
+ for (list = editor->buffer->color_tags; list; list = g_list_next (list))
+ {
+ GtkTextTag *tag = list->data;
+
+ if ((g_slist_find (tags, tag) &&
+ ! g_slist_find (tags_on, tag)) ||
+ g_slist_find (tags_off, tag))
+ {
+ gimp_text_style_editor_set_color (editor, tag);
+ break;
+ }
+ }
+
+ if (! list)
+ gimp_text_style_editor_set_default_color (editor);
+
+ for (list = editor->buffer->size_tags; list; list = g_list_next (list))
+ {
+ GtkTextTag *tag = list->data;
+
+ if ((g_slist_find (tags, tag) &&
+ ! g_slist_find (tags_on, tag)) ||
+ g_slist_find (tags_off, tag))
+ {
+ gimp_text_style_editor_set_size (editor, tag);
+ break;
+ }
+ }
+
+ if (! list)
+ gimp_text_style_editor_set_default_size (editor);
+
+ for (list = editor->buffer->baseline_tags; list; list = g_list_next (list))
+ {
+ GtkTextTag *tag = list->data;
+
+ if ((g_slist_find (tags, tag) &&
+ ! g_slist_find (tags_on, tag)) ||
+ g_slist_find (tags_off, tag))
+ {
+ gimp_text_style_editor_set_baseline (editor, tag);
+ break;
+ }
+ }
+
+ if (! list)
+ gimp_text_style_editor_set_baseline (editor, NULL);
+
+ for (list = editor->toggles; list; list = g_list_next (list))
+ {
+ GtkToggleButton *toggle = list->data;
+ GtkTextTag *tag = g_object_get_data (G_OBJECT (toggle),
+ "tag");
+
+ gimp_text_style_editor_set_toggle (editor, toggle,
+ (g_slist_find (tags, tag) &&
+ ! g_slist_find (tags_on, tag)) ||
+ g_slist_find (tags_off, tag));
+ }
+
+ {
+ GtkTextTag *tag;
+
+ tag = gimp_text_buffer_get_iter_kerning (editor->buffer, &cursor, NULL);
+ gimp_text_style_editor_set_kerning (editor, tag);
+ }
+
+ g_slist_free (tags);
+ g_slist_free (tags_on);
+ g_slist_free (tags_off);
+ }
+
+ if (editor->context->font_name &&
+ g_strcmp0 (editor->context->font_name,
+ gimp_object_get_name (gimp_context_get_font (editor->context))))
+ {
+ /* A font is set, but is unavailable; change the help text. */
+ gchar *help_text;
+
+ help_text = g_strdup_printf (_("Font \"%s\" unavailable on this system"),
+ editor->context->font_name);
+ gimp_help_set_help_data (editor->font_entry, help_text, NULL);
+ g_free (help_text);
+ }
+ else
+ {
+ gimp_help_set_help_data (editor->font_entry,
+ _("Change font of selected text"), NULL);
+ }
+
+ return FALSE;
+}