gimp r27444 - in trunk: . app/actions app/tools menus
- From: mitch svn gnome org
- To: svn-commits-list gnome org
- Subject: gimp r27444 - in trunk: . app/actions app/tools menus
- Date: Mon, 27 Oct 2008 16:21:03 +0000 (UTC)
Author: mitch
Date: Mon Oct 27 16:21:03 2008
New Revision: 27444
URL: http://svn.gnome.org/viewvc/gimp?rev=27444&view=rev
Log:
2008-10-27 Michael Natterer <mitch gimp org>
* menus/text-tool-menu.xml
* app/actions/text-tool-actions.c
* app/actions/text-tool-commands.[ch]: add "Text along Path" to the
text tool context menu.
* app/tools/gimptextoptions.[ch]: remove the text along path
button here.
* app/tools/gimptexttool.c: changed accordingly.
* app/tools/gimptexttool.[ch]: move public functions together,
move all virtual function implementations together and put them in
order, made the text along path function public, factor out
gimp_text_tool_xy_to_offset() instead of duplicaing this code
three times, remove gimp_rectangle_tool_frame_item() because it
doesn't belong here.
* app/tools/gimprectangletool.[ch]: add
gimp_rectangle_tool_frame_item() here. Enselic, please process ;)
Modified:
trunk/ChangeLog
trunk/app/actions/text-tool-actions.c
trunk/app/actions/text-tool-commands.c
trunk/app/actions/text-tool-commands.h
trunk/app/tools/gimprectangletool.c
trunk/app/tools/gimprectangletool.h
trunk/app/tools/gimptextoptions.c
trunk/app/tools/gimptextoptions.h
trunk/app/tools/gimptexttool.c
trunk/app/tools/gimptexttool.h
trunk/menus/text-tool-menu.xml
Modified: trunk/app/actions/text-tool-actions.c
==============================================================================
--- trunk/app/actions/text-tool-actions.c (original)
+++ trunk/app/actions/text-tool-actions.c Mon Oct 27 16:21:03 2008
@@ -83,7 +83,13 @@
{ "text-tool-path-from-text", GIMP_STOCK_PATH,
N_("_Path from Text"), "",
N_("Create a path from the outlines of the current text"),
- G_CALLBACK (text_tool_path_from_text_callback),
+ G_CALLBACK (text_tool_path_from_text_cmd_callback),
+ NULL },
+
+ { "text-tool-text-along-path", GIMP_STOCK_PATH,
+ N_("Text along Path"), "",
+ N_("Bend the text along the currently active path"),
+ G_CALLBACK (text_tool_text_along_path_cmd_callback),
NULL },
{ "text-tool-input-methods", NULL,
@@ -134,6 +140,7 @@
GimpTextTool *text_tool = GIMP_TEXT_TOOL (data);
GimpImage *image = GIMP_TOOL (text_tool)->display->image;
GimpLayer *layer;
+ GimpVectors *vectors;
GtkClipboard *clipboard;
gboolean text_layer = FALSE;
gboolean text_sel = FALSE; /* some text is selected */
@@ -144,6 +151,8 @@
if (layer)
text_layer = gimp_drawable_is_text_layer (GIMP_DRAWABLE (layer));
+ vectors = gimp_image_get_active_vectors (image);
+
text_sel = gimp_text_tool_get_has_text_selection (text_tool);
/*
@@ -167,4 +176,5 @@
SET_SENSITIVE ("text-tool-clear", text_layer);
SET_SENSITIVE ("text-tool-load", image);
SET_SENSITIVE ("text-tool-path-from-text", text_layer);
+ SET_SENSITIVE ("text-tool-text-along-path", text_layer && vectors);
}
Modified: trunk/app/actions/text-tool-commands.c
==============================================================================
--- trunk/app/actions/text-tool-commands.c (original)
+++ trunk/app/actions/text-tool-commands.c Mon Oct 27 16:21:03 2008
@@ -158,8 +158,8 @@
}
void
-text_tool_path_from_text_callback (GtkAction *action,
- gpointer data)
+text_tool_path_from_text_cmd_callback (GtkAction *action,
+ gpointer data)
{
GimpTextTool *text_tool = GIMP_TEXT_TOOL (data);
@@ -167,6 +167,15 @@
}
void
+text_tool_text_along_path_cmd_callback (GtkAction *action,
+ gpointer data)
+{
+ GimpTextTool *text_tool = GIMP_TEXT_TOOL (data);
+
+ gimp_text_tool_create_vectors_warped (text_tool);
+}
+
+void
text_tool_direction_cmd_callback (GtkAction *action,
GtkAction *current,
gpointer data)
Modified: trunk/app/actions/text-tool-commands.h
==============================================================================
--- trunk/app/actions/text-tool-commands.h (original)
+++ trunk/app/actions/text-tool-commands.h Mon Oct 27 16:21:03 2008
@@ -20,23 +20,25 @@
#define __TEXT_TOOL_COMMANDS_H__
-void text_tool_cut_cmd_callback (GtkAction *action,
- gpointer data);
-void text_tool_copy_cmd_callback (GtkAction *action,
- gpointer data);
-void text_tool_paste_cmd_callback (GtkAction *action,
- gpointer data);
-void text_tool_delete_cmd_callback (GtkAction *action,
- gpointer data);
-void text_tool_load_cmd_callback (GtkAction *action,
- gpointer data);
-void text_tool_clear_cmd_callback (GtkAction *action,
- gpointer data);
-void text_tool_path_from_text_callback (GtkAction *action,
- gpointer data);
-void text_tool_direction_cmd_callback (GtkAction *action,
- GtkAction *current,
- gpointer data);
+void text_tool_cut_cmd_callback (GtkAction *action,
+ gpointer data);
+void text_tool_copy_cmd_callback (GtkAction *action,
+ gpointer data);
+void text_tool_paste_cmd_callback (GtkAction *action,
+ gpointer data);
+void text_tool_delete_cmd_callback (GtkAction *action,
+ gpointer data);
+void text_tool_load_cmd_callback (GtkAction *action,
+ gpointer data);
+void text_tool_clear_cmd_callback (GtkAction *action,
+ gpointer data);
+void text_tool_path_from_text_cmd_callback (GtkAction *action,
+ gpointer data);
+void text_tool_text_along_path_cmd_callback (GtkAction *action,
+ gpointer data);
+void text_tool_direction_cmd_callback (GtkAction *action,
+ GtkAction *current,
+ gpointer data);
#endif /* __TEXT_TOOL_COMMANDS_H__ */
Modified: trunk/app/tools/gimprectangletool.c
==============================================================================
--- trunk/app/tools/gimprectangletool.c (original)
+++ trunk/app/tools/gimprectangletool.c Mon Oct 27 16:21:03 2008
@@ -695,6 +695,58 @@
return inside;
}
+/**
+ * gimp_rectangle_tool_frame_item:
+ * @rect_tool: a #GimpRectangleTool interface
+ * @item: a #GimpItem attached to the image on which a
+ * rectangle is being shown.
+ *
+ * Convenience function to set the corners of the rectangle to
+ * match the bounds of the specified item. The rectangle interface
+ * must be active (i.e., showing a rectangle), and the item must be
+ * attached to the image on which the rectangle is active.
+ **/
+void
+gimp_rectangle_tool_frame_item (GimpRectangleTool *rect_tool,
+ GimpItem *item)
+{
+ GimpDisplay *display = GIMP_TOOL (rect_tool)->display;
+ gint offset_x;
+ gint offset_y;
+ gint width;
+ gint height;
+
+ g_return_if_fail (GIMP_IS_ITEM (item));
+ g_return_if_fail (gimp_item_is_attached (item));
+ g_return_if_fail (display != NULL);
+ g_return_if_fail (display->image == item->image);
+
+ width = gimp_item_width (item);
+ height = gimp_item_height (item);
+
+ gimp_item_offsets (item, &offset_x, &offset_y);
+
+ gimp_draw_tool_pause (GIMP_DRAW_TOOL (rect_tool));
+
+ gimp_rectangle_tool_set_function (rect_tool,
+ GIMP_RECTANGLE_TOOL_CREATING);
+
+ g_object_set (rect_tool,
+ "x1", offset_x,
+ "y1", offset_y,
+ "x2", offset_x + width,
+ "y2", offset_y + height,
+ NULL);
+
+ /* kludge to force handle sizes to update. This call may be
+ * harmful if this function is ever moved out of the text tool code.
+ */
+ gimp_rectangle_tool_set_constraint (rect_tool,
+ GIMP_RECTANGLE_CONSTRAIN_NONE);
+
+ gimp_draw_tool_resume (GIMP_DRAW_TOOL (rect_tool));
+}
+
void
gimp_rectangle_tool_set_property (GObject *object,
guint property_id,
Modified: trunk/app/tools/gimprectangletool.h
==============================================================================
--- trunk/app/tools/gimprectangletool.h (original)
+++ trunk/app/tools/gimprectangletool.h Mon Oct 27 16:21:03 2008
@@ -143,6 +143,10 @@
gboolean gimp_rectangle_tool_point_in_rectangle (GimpRectangleTool *rect_tool,
gdouble x,
gdouble y);
+void gimp_rectangle_tool_frame_item (GimpRectangleTool *rect_tool,
+ GimpItem *item);
+
+
/* convenience functions */
void gimp_rectangle_tool_install_properties (GObjectClass *klass);
Modified: trunk/app/tools/gimptextoptions.c
==============================================================================
--- trunk/app/tools/gimptextoptions.c (original)
+++ trunk/app/tools/gimptextoptions.c Mon Oct 27 16:21:03 2008
@@ -193,8 +193,7 @@
static void
gimp_text_options_init (GimpTextOptions *options)
{
- options->size_entry = NULL;
- options->along_vectors_button = NULL;
+ options->size_entry = NULL;
}
static void
@@ -516,13 +515,6 @@
gimp_table_attach_stock (GTK_TABLE (table), row++,
GIMP_STOCK_LETTER_SPACING, spinbutton, 1, TRUE);
- button = gtk_button_new_with_label (_("Text along Path"));
- gtk_box_pack_end (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
- gtk_widget_set_sensitive (button, FALSE);
- gtk_widget_show (button);
-
- options->along_vectors_button = button;
-
return main_vbox;
}
Modified: trunk/app/tools/gimptextoptions.h
==============================================================================
--- trunk/app/tools/gimptextoptions.h (original)
+++ trunk/app/tools/gimptextoptions.h Mon Oct 27 16:21:03 2008
@@ -56,7 +56,6 @@
/* options gui */
GtkWidget *size_entry;
- GtkWidget *along_vectors_button;
};
Modified: trunk/app/tools/gimptexttool.c
==============================================================================
--- trunk/app/tools/gimptexttool.c (original)
+++ trunk/app/tools/gimptexttool.c Mon Oct 27 16:21:03 2008
@@ -114,6 +114,13 @@
GimpDisplay *display,
const gchar **ui_path);
+static void gimp_text_tool_draw (GimpDrawTool *draw_tool);
+static void gimp_text_tool_draw_preedit (GimpDrawTool *draw_tool);
+static void gimp_text_tool_draw_selection (GimpDrawTool *draw_tool);
+
+static gboolean gimp_text_tool_rectangle_change_complete
+ (GimpRectangleTool *rect_tool);
+
static void gimp_text_tool_connect (GimpTextTool *text_tool,
GimpTextLayer *layer,
GimpText *text);
@@ -129,8 +136,6 @@
static gboolean gimp_text_tool_idle_apply (GimpTextTool *text_tool);
static void gimp_text_tool_apply (GimpTextTool *text_tool);
-static void gimp_text_tool_create_vectors_warped
- (GimpTextTool *text_tool);
static void gimp_text_tool_create_layer (GimpTextTool *text_tool,
GimpText *text);
@@ -147,19 +152,9 @@
GimpDrawable *drawable,
gboolean confirm);
-static gboolean gimp_text_tool_rectangle_change_complete
- (GimpRectangleTool *rect_tool);
-void gimp_rectangle_tool_frame_item (GimpRectangleTool *rect_tool,
- GimpItem *item);
-
-static void gimp_text_tool_draw (GimpDrawTool *draw_tool);
-static void gimp_text_tool_draw_preedit_lines (GimpDrawTool *draw_tool);
-static void gimp_text_tool_draw_text_selection (GimpDrawTool *draw_tool);
-
static void gimp_text_tool_update_layout (GimpTextTool *text_tool);
static void gimp_text_tool_update_proxy (GimpTextTool *text_tool);
-static void gimp_text_tool_reset_im_context (GimpTextTool *text_tool);
static void gimp_text_tool_enter_text (GimpTextTool *text_tool,
const gchar *str);
static void gimp_text_tool_text_buffer_changed (GtkTextBuffer *text_buffer,
@@ -172,8 +167,12 @@
GParamSpec *pspec,
GimpTextTool *text_tool);
-/* IM Context Callbacks
- */
+static gint gimp_text_tool_xy_to_offset (GimpTextTool *text_tool,
+ gdouble x,
+ gdouble y);
+
+/* IM context utilities and callbacks */
+static void gimp_text_tool_reset_im_context (GimpTextTool *text_tool);
static void gimp_text_tool_commit_cb (GtkIMContext *context,
const gchar *str,
GimpTextTool *text_tool);
@@ -496,23 +495,10 @@
if (text_tool->layout)
{
- GtkTextIter cursor, start, end;
+ GtkTextIter cursor;
gint offset;
- gint trailing;
- gchar *string;
- gtk_text_buffer_get_bounds (text_tool->text_buffer,
- &start, &end);
- string = gtk_text_buffer_get_text (text_tool->text_buffer,
- &start, &end, TRUE);
- pango_layout_xy_to_index (text_tool->layout->layout,
- x * PANGO_SCALE,
- y * PANGO_SCALE,
- &offset, &trailing);
- offset = g_utf8_pointer_to_offset (string, string + offset);
- offset += trailing;
-
- g_free (string);
+ offset = gimp_text_tool_xy_to_offset (text_tool, x, y);
gtk_text_buffer_get_iter_at_offset (text_tool->text_buffer,
&cursor, offset);
@@ -618,24 +604,10 @@
GimpItem *item = GIMP_ITEM (text_tool->layer);
gdouble x = coords->x - item->offset_x;
gdouble y = coords->y - item->offset_y;
- GtkTextIter cursor, start, end;
- gint offset, trailing;
- gchar *string;
-
- gtk_text_buffer_get_bounds (text_tool->text_buffer, &start, &end);
-
- string = gtk_text_buffer_get_text (text_tool->text_buffer,
- &start, &end, TRUE);
-
- pango_layout_xy_to_index (text_tool->layout->layout,
- x * PANGO_SCALE,
- y * PANGO_SCALE,
- &offset, &trailing);
+ GtkTextIter cursor;
+ gint offset;
- offset = g_utf8_pointer_to_offset (string, string + offset);
- offset += trailing;
-
- g_free (string);
+ offset = gimp_text_tool_xy_to_offset (text_tool, x, y);
gtk_text_buffer_get_iter_at_offset (text_tool->text_buffer,
&cursor, offset);
@@ -691,26 +663,12 @@
gdouble x = coords->x - item->offset_x;
gdouble y = coords->y - item->offset_y;
GtkTextIter cursor;
- GtkTextIter start, end;
GtkTextIter old_selection_bound;
GtkTextMark *selection_mark;
- gint offset, trailing;
+ gint offset;
gint old_cursor_offset;
- gchar *string;
-
- gtk_text_buffer_get_bounds (text_tool->text_buffer, &start, &end);
- string = gtk_text_buffer_get_text (text_tool->text_buffer,
- &start, &end, TRUE);
-
- pango_layout_xy_to_index (text_tool->layout->layout,
- x * PANGO_SCALE,
- y * PANGO_SCALE,
- &offset, &trailing);
-
- offset = g_utf8_pointer_to_offset (string, string + offset);
- offset += trailing;
- g_free (string);
+ offset = gimp_text_tool_xy_to_offset (text_tool, x, y);
selection_mark = gtk_text_buffer_get_selection_bound (text_tool->text_buffer);
@@ -1051,456 +1009,278 @@
}
static void
-gimp_text_tool_connect (GimpTextTool *text_tool,
- GimpTextLayer *layer,
- GimpText *text)
+gimp_text_tool_draw (GimpDrawTool *draw_tool)
{
- GimpTool *tool = GIMP_TOOL (text_tool);
+ GimpTextTool *text_tool = GIMP_TEXT_TOOL (draw_tool);
+ GimpTool *tool = GIMP_TOOL (draw_tool);
+ GdkRectangle cliprect;
+ gint width, height;
+ gint x1, x2;
+ gint y1, y2;
+ GtkTextIter start;
- g_return_if_fail (text == NULL || (layer != NULL && layer->text == text));
+ g_object_set (text_tool,
+ "narrow-mode", TRUE,
+ NULL);
- if (text_tool->text != text)
- {
- GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (tool);
+ gimp_rectangle_tool_draw (draw_tool);
- if (text_tool->text)
- {
- g_signal_handlers_disconnect_by_func (text_tool->text,
- gimp_text_tool_text_notify,
- text_tool);
+ if (! text_tool->layer ||
+ ! text_tool->layer->text)
+ return;
- if (text_tool->pending)
- gimp_text_tool_apply (text_tool);
+ /* There will be no layout if the function is called from the wrong place */
+ if (! text_tool->layout)
+ gimp_text_tool_update_layout (text_tool);
- if (options->along_vectors_button)
- {
- gtk_widget_set_sensitive (options->along_vectors_button,
- FALSE);
- g_signal_handlers_disconnect_by_func (options->along_vectors_button,
- gimp_text_tool_create_vectors_warped,
- text_tool);
- }
+ g_object_get (text_tool,
+ "x1", &x1,
+ "y1", &y1,
+ "x2", &x2,
+ "y2", &y2,
+ NULL);
- g_object_unref (text_tool->text);
- text_tool->text = NULL;
+ /* Turn on clipping for text-cursor and selections */
+ cliprect.x = x1;
+ cliprect.width = x2 - x1;
+ cliprect.y = y1;
+ cliprect.height = y2 - y1;
+ gimp_draw_tool_set_clip_rect (draw_tool, &cliprect, FALSE);
- g_object_set (text_tool->proxy, "text", NULL, NULL);
- }
+ gtk_text_buffer_get_start_iter (text_tool->text_buffer, &start);
- gimp_context_define_property (GIMP_CONTEXT (options),
- GIMP_CONTEXT_PROP_FOREGROUND,
- text != NULL);
+ if (! gtk_text_buffer_get_has_selection (text_tool->text_buffer))
+ {
+ /* If the text buffer has no selection, draw the text cursor */
- if (text)
- {
- gimp_config_sync (G_OBJECT (text), G_OBJECT (text_tool->proxy), 0);
+ gint cursorx;
+ GtkTextIter cursor;
+ PangoRectangle crect;
+ gchar *string;
- text_tool->text = g_object_ref (text);
+ gtk_text_buffer_get_iter_at_mark (text_tool->text_buffer, &cursor,
+ gtk_text_buffer_get_insert (text_tool->text_buffer));
- g_signal_connect (text, "notify",
- G_CALLBACK (gimp_text_tool_text_notify),
- text_tool);
+ string = gtk_text_buffer_get_text (text_tool->text_buffer,
+ &start, &cursor, FALSE);
- if (options->along_vectors_button)
- {
- g_signal_connect_swapped (options->along_vectors_button, "clicked",
- G_CALLBACK (gimp_text_tool_create_vectors_warped),
- text_tool);
- gtk_widget_set_sensitive (options->along_vectors_button, TRUE);
- }
- }
- }
+ /* Using strlen to get the byte index, not the character offset */
+ cursorx = strlen (string);
- if (text_tool->layer != layer)
- {
- if (text_tool->layer)
- g_signal_handlers_disconnect_by_func (text_tool->layer,
- gimp_text_tool_layer_notify,
- text_tool);
+ /* TODO: make cursor position itself even inside preedits! */
+ if (text_tool->preedit_len > 0)
+ cursorx += text_tool->preedit_len;
- text_tool->layer = layer;
+ g_free (string);
- if (layer)
- g_signal_connect_object (text_tool->layer, "notify::modified",
- G_CALLBACK (gimp_text_tool_layer_notify),
- text_tool, 0);
- }
-}
+ pango_layout_index_to_pos (text_tool->layout->layout, cursorx, &crect);
-static void
-gimp_text_tool_use_editor_notify (GimpTextOptions *options,
- GParamSpec *pspec,
- GimpTextTool *text_tool)
-{
- if (options->use_editor)
- {
- if (text_tool->text && text_tool->text_buffer)
- gimp_text_tool_editor (text_tool);
+ crect.x = PANGO_PIXELS (crect.x);
+ crect.y = PANGO_PIXELS (crect.y);
+ crect.height = PANGO_PIXELS (crect.height);
+
+ gimp_draw_tool_draw_rectangle (draw_tool, TRUE,
+ crect.x, crect.y,
+ 4, crect.height,
+ TRUE);
+
+ if (text_tool->preedit_string && text_tool->preedit_len > 0)
+ gimp_text_tool_draw_preedit (draw_tool);
}
else
{
- if (text_tool->editor)
- gtk_widget_destroy (text_tool->editor);
+ /* If the text buffer has a selection, highlight the
+ * selected letters*/
+
+ gimp_text_tool_draw_selection (draw_tool);
}
-}
-static void
-gimp_text_tool_layer_notify (GimpTextLayer *layer,
- GParamSpec *pspec,
- GimpTextTool *text_tool)
-{
- if (layer->modified)
- gimp_text_tool_connect (text_tool, NULL, NULL);
+ /* Turn off clipping when done */
+ gimp_draw_tool_set_clip_rect (draw_tool, NULL, FALSE);
}
static void
-gimp_text_tool_proxy_notify (GimpText *text,
- GParamSpec *pspec,
- GimpTextTool *text_tool)
+gimp_text_tool_draw_preedit (GimpDrawTool *draw_tool)
{
- if (! text_tool->text)
- return;
+ GimpTextTool *text_tool = GIMP_TEXT_TOOL (draw_tool);
+ PangoLayout *layout;
+ PangoLayoutIter *line_iter;
+ GtkTextIter cursor, start;
+ gint i;
+ gint min, max;
+ gchar *string;
- if ((pspec->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE)
- {
- text_tool->pending = g_list_append (text_tool->pending, pspec);
+ gtk_text_buffer_get_selection_bounds (text_tool->text_buffer, &cursor, NULL);
+ gtk_text_buffer_get_start_iter (text_tool->text_buffer, &start);
- if (text_tool->idle_id)
- g_source_remove (text_tool->idle_id);
+ string = gtk_text_buffer_get_text (text_tool->text_buffer,
+ &start, &cursor, FALSE);
+ min = strlen (string);
+ g_free (string);
- text_tool->idle_id =
- g_idle_add_full (G_PRIORITY_LOW,
- (GSourceFunc) gimp_text_tool_idle_apply, text_tool,
- NULL);
- }
-}
+ max = min + text_tool->preedit_len;
-static void
-gimp_text_tool_text_notify (GimpText *text,
- GParamSpec *pspec,
- GimpTextTool *text_tool)
-{
- g_return_if_fail (text == text_tool->text);
+ layout = text_tool->layout->layout;
+ line_iter = pango_layout_get_iter (layout);
+ i = 0;
- if ((pspec->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE)
+ do
{
- GValue value = { 0, };
+ gint firstline, lastline;
+ gint first_x, last_x;
- g_value_init (&value, pspec->value_type);
+ pango_layout_index_to_line_x (layout, min, 0, &firstline, &first_x);
+ pango_layout_index_to_line_x (layout, max, 0, &lastline, &last_x);
- g_object_get_property (G_OBJECT (text), pspec->name, &value);
+ if (i >= firstline && i <= lastline)
+ {
+ PangoRectangle crect;
- g_signal_handlers_block_by_func (text_tool->proxy,
- gimp_text_tool_proxy_notify,
- text_tool);
+ pango_layout_iter_get_line_extents (line_iter, NULL, &crect);
+ pango_extents_to_pixels (&crect, NULL);
- g_object_set_property (G_OBJECT (text_tool->proxy), pspec->name, &value);
+ gimp_draw_tool_draw_line (draw_tool,
+ crect.x, crect.y + crect.height,
+ crect.x + crect.width,
+ crect.y + crect.height,
+ TRUE);
+ if (i == firstline)
+ {
+ PangoRectangle crect2 = crect;
- g_signal_handlers_unblock_by_func (text_tool->proxy,
- gimp_text_tool_proxy_notify,
- text_tool);
+ crect2.width = PANGO_PIXELS (first_x) - crect.x;
+ crect2.x = crect.x;
- g_value_unset (&value);
- }
+ gimp_draw_tool_draw_line (draw_tool,
+ crect2.x, crect2.y + crect2.height,
+ crect2.width,
+ crect2.y + crect2.height,
+ TRUE);
+ }
- /* we need to redraw the rectangle if it is visible and the shape of
- the layer has changed, because of an undo for example. */
- if (strcmp (pspec->name, "box-width") == 0 ||
- strcmp (pspec->name, "box-height") == 0 ||
- text->box_mode == GIMP_TEXT_BOX_DYNAMIC)
- {
- GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (text_tool);
+ if (i == lastline)
+ {
+ PangoRectangle crect2 = crect;
- text_tool->handle_rectangle_change_complete = FALSE;
- gimp_rectangle_tool_frame_item (rect_tool,
- GIMP_ITEM (text_tool->layer));
- text_tool->handle_rectangle_change_complete = TRUE;
+ crect2.width = crect.x + crect.width - PANGO_PIXELS (last_x);
+ crect2.x = PANGO_PIXELS (last_x);
+
+ gimp_draw_tool_draw_line (draw_tool,
+ crect2.x, crect2.y + crect2.height,
+ crect2.x + crect2.width,
+ crect2.y + crect2.height,
+ TRUE);
+ }
+ }
+
+ i++;
}
+ while (pango_layout_iter_next_line (line_iter));
- /* if the text has changed, (probably because of an undo), we put
- * the new text into the text buffer
- */
- if (strcmp (pspec->name, "text") == 0)
- {
- g_signal_handlers_block_by_func (text_tool->proxy,
- gimp_text_tool_text_buffer_changed,
- text_tool);
-
- gtk_text_buffer_set_text (text_tool->text_buffer, text->text, -1);
-
- g_signal_handlers_unblock_by_func (text_tool->proxy,
- gimp_text_tool_text_buffer_changed,
- text_tool);
-
- /* force change of cursor and selection display */
- gimp_text_tool_update_layout (text_tool);
-/* gimp_text_tool_update_proxy (text_tool); */
- return;
- }
-}
-
-static gboolean
-gimp_text_tool_idle_apply (GimpTextTool *text_tool)
-{
- text_tool->idle_id = 0;
-
- gimp_text_tool_apply (text_tool);
-
- return FALSE;
+ pango_layout_iter_free (line_iter);
}
static void
-gimp_text_tool_apply (GimpTextTool *text_tool)
+gimp_text_tool_draw_selection (GimpDrawTool *draw_tool)
{
- const GParamSpec *pspec = NULL;
- GimpImage *image;
- GimpTextLayer *layer;
- GObject *src;
- GObject *dest;
- GList *list;
- gboolean push_undo = TRUE;
- gboolean undo_group = FALSE;
-
- if (text_tool->idle_id)
- {
- g_source_remove (text_tool->idle_id);
- text_tool->idle_id = 0;
- }
-
- g_return_if_fail (text_tool->text != NULL);
- g_return_if_fail (text_tool->layer != NULL);
+ GimpTextTool *text_tool = GIMP_TEXT_TOOL (draw_tool);
+ PangoLayout *layout;
+ PangoLayoutIter *line_iter;
+ GtkTextIter start;
+ GtkTextIter sel_start, sel_end;
+ gint i;
+ gint min, max;
+ gchar *string;
- layer = text_tool->layer;
- image = gimp_item_get_image (GIMP_ITEM (layer));
+ gtk_text_buffer_get_selection_bounds (text_tool->text_buffer,
+ &sel_start, &sel_end);
+ gtk_text_buffer_get_start_iter (text_tool->text_buffer, &start);
- g_return_if_fail (layer->text == text_tool->text);
+ string = gtk_text_buffer_get_text (text_tool->text_buffer,
+ &start, &sel_start, FALSE);
+ min = strlen (string);
+ g_free (string);
- /* Walk over the list of changes and figure out if we are changing
- * a single property or need to push a full text undo.
- */
- for (list = text_tool->pending;
- list && list->next && list->next->data == list->data;
- list = list->next)
- /* do nothing */;
+ string = gtk_text_buffer_get_text (text_tool->text_buffer,
+ &start, &sel_end, FALSE);
+ max = strlen (string);
+ g_free (string);
- if (g_list_length (list) == 1)
- pspec = list->data;
+ layout = text_tool->layout->layout;
+ line_iter = pango_layout_get_iter (layout);
+ i = 0;
- /* If we are changing a single property, we don't need to push
- * an undo if all of the following is true:
- * - the redo stack is empty
- * - the last item on the undo stack is a text undo
- * - the last undo changed the same text property on the same layer
- * - the last undo happened less than TEXT_UNDO_TIMEOUT seconds ago
+ /* Invert the selected letters by inverting all
+ * lines containing selected letters, then
+ * invert the unselected letters on these lines
+ * a second time to make them look normal
*/
- if (pspec)
+ do
{
- GimpUndo *undo = gimp_image_undo_can_compress (image, GIMP_TYPE_TEXT_UNDO,
- GIMP_UNDO_TEXT_LAYER);
-
- if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer))
- {
- GimpTextUndo *text_undo = GIMP_TEXT_UNDO (undo);
-
- if (text_undo->pspec == pspec)
- {
- if (gimp_undo_get_age (undo) < TEXT_UNDO_TIMEOUT)
- {
- GimpTool *tool = GIMP_TOOL (text_tool);
+ gint firstline, lastline;
+ gint first_x, last_x;
- push_undo = FALSE;
- gimp_undo_reset_age (undo);
- gimp_undo_refresh_preview (undo,
- GIMP_CONTEXT (gimp_tool_get_options (tool)));
- }
- }
- }
- }
+ pango_layout_index_to_line_x (layout, min, 0, &firstline, &first_x);
+ pango_layout_index_to_line_x (layout, max, 0, &lastline, &last_x);
- if (push_undo)
- {
- if (layer->modified)
+ if (i >= firstline && i <= lastline)
{
- undo_group = TRUE;
- gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, NULL);
-
- gimp_image_undo_push_text_layer_modified (image, NULL, layer);
- gimp_image_undo_push_drawable_mod (image,
- NULL, GIMP_DRAWABLE (layer));
- }
-
- gimp_image_undo_push_text_layer (image, NULL, layer, pspec);
- }
-
- src = G_OBJECT (text_tool->proxy);
- dest = G_OBJECT (text_tool->text);
-
- g_signal_handlers_block_by_func (dest,
- gimp_text_tool_text_notify, text_tool);
-
- g_object_freeze_notify (dest);
-
- for (; list; list = list->next)
- {
- GValue value = { 0, };
-
- /* look ahead and compress changes */
- if (list->next && list->next->data == list->data)
- continue;
-
- pspec = list->data;
-
- g_value_init (&value, pspec->value_type);
-
- g_object_get_property (src, pspec->name, &value);
- g_object_set_property (dest, pspec->name, &value);
-
- g_value_unset (&value);
- }
-
- g_list_free (text_tool->pending);
- text_tool->pending = NULL;
-
- g_object_thaw_notify (dest);
-
- g_signal_handlers_unblock_by_func (dest,
- gimp_text_tool_text_notify, text_tool);
-
- if (push_undo)
- {
- g_object_set (layer, "modified", FALSE, NULL);
-
- if (undo_group)
- gimp_image_undo_group_end (image);
- }
-
- /* if we're doing dynamic text, we want to update the
- * shape of the rectangle */
- if (layer->text->box_mode == GIMP_TEXT_BOX_DYNAMIC)
- {
- text_tool->handle_rectangle_change_complete = FALSE;
- gimp_rectangle_tool_frame_item (GIMP_RECTANGLE_TOOL (text_tool),
- GIMP_ITEM (layer));
- text_tool->handle_rectangle_change_complete = TRUE;
- }
+ PangoRectangle crect;
- gimp_image_flush (image);
- gimp_text_tool_update_layout (text_tool);
-}
+ pango_layout_iter_get_line_extents (line_iter, NULL, &crect);
+ pango_extents_to_pixels (&crect, NULL);
-void
-gimp_text_tool_create_vectors (GimpTextTool *text_tool)
-{
- GimpVectors *vectors;
+ gimp_draw_tool_draw_rectangle (draw_tool, TRUE,
+ crect.x, crect.y,
+ crect.width, crect.height,
+ TRUE);
+ if (i == firstline)
+ {
+ /* Twice invert all letters before the selection,
+ * making them look normal
+ */
+ PangoRectangle crect2 = crect;
- if (! text_tool->text || ! text_tool->image)
- return;
+ crect2.width = PANGO_PIXELS (first_x) - crect.x;
+ crect2.x = crect.x;
- vectors = gimp_text_vectors_new (text_tool->image, text_tool->text);
+ gimp_draw_tool_draw_rectangle (draw_tool, TRUE,
+ crect2.x, crect2.y,
+ crect2.width, crect2.height,
+ TRUE);
+ }
+ if (i == lastline)
+ {
+ /* Twice invert all letters after the selection,
+ * making them look normal
+ */
+ PangoRectangle crect2 = crect;
- if (text_tool->layer)
- {
- gint x, y;
+ crect2.width = crect.x + crect.width - PANGO_PIXELS (last_x);
+ crect2.x = PANGO_PIXELS (last_x);
- gimp_item_offsets (GIMP_ITEM (text_tool->layer), &x, &y);
- gimp_item_translate (GIMP_ITEM (vectors), x, y, FALSE);
+ gimp_draw_tool_draw_rectangle (draw_tool, TRUE,
+ crect2.x, crect2.y,
+ crect2.width, crect2.height,
+ TRUE);
+ }
+ }
+ i++;
}
-
- gimp_image_add_vectors (text_tool->image, vectors, -1, TRUE);
-
- gimp_image_flush (text_tool->image);
-}
-
-static void
-gimp_text_tool_create_vectors_warped (GimpTextTool *text_tool)
-{
- GimpVectors *vectors0;
- GimpVectors *vectors;
- GimpText *text = text_tool->text;
- gdouble box_height;
-
- if (! text || ! text_tool->image || ! text_tool->layer)
- return;
-
- box_height = gimp_item_height (GIMP_ITEM (text_tool->layer));
-
- vectors0 = gimp_image_get_active_vectors (text_tool->image);
- if (! vectors0)
- return;
-
- vectors = gimp_text_vectors_new (text_tool->image, text_tool->text);
-
- gimp_vectors_warp_vectors (vectors0, vectors, 0.5 * box_height);
-
- gimp_image_add_vectors (text_tool->image, vectors, -1, TRUE);
- gimp_image_set_active_vectors (text_tool->image, vectors);
- gimp_item_set_visible (GIMP_ITEM (vectors), TRUE, FALSE);
-
- gimp_image_flush (text_tool->image);
+ while (pango_layout_iter_next_line (line_iter));
+ pango_layout_iter_free (line_iter);
}
-static void
-gimp_text_tool_create_layer (GimpTextTool *text_tool,
- GimpText *text)
+static gboolean
+gimp_text_tool_rectangle_change_complete (GimpRectangleTool *rect_tool)
{
- GimpTool *tool = GIMP_TOOL (text_tool);
- GimpImage *image;
- GimpLayer *layer;
-
- if (text)
- {
- text = gimp_config_duplicate (GIMP_CONFIG (text));
- }
- else
- {
- gchar *str = gimp_text_tool_canvas_editor_get_text (text_tool);
-
- g_object_set (text_tool->proxy,
- "text", str,
- "box-mode", GIMP_TEXT_BOX_DYNAMIC,
- NULL);
-
- g_free (str);
-
- text = gimp_config_duplicate (GIMP_CONFIG (text_tool->proxy));
- }
-
- image = tool->display->image;
- layer = gimp_text_layer_new (image, text);
-
- g_object_unref (text);
-
- if (! layer)
- return;
-
- gimp_text_tool_connect (text_tool, GIMP_TEXT_LAYER (layer), text);
-
- gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT,
- _("Add Text Layer"));
-
- if (gimp_image_floating_sel (image))
- {
- g_signal_handlers_block_by_func (image,
- gimp_text_tool_layer_changed,
- text_tool);
-
- floating_sel_anchor (gimp_image_floating_sel (image));
-
- g_signal_handlers_unblock_by_func (image,
- gimp_text_tool_layer_changed,
- text_tool);
- }
-
- GIMP_ITEM (layer)->offset_x = text_tool->x1;
- GIMP_ITEM (layer)->offset_y = text_tool->y1;
-
- gimp_image_add_layer (image, layer, -1, TRUE);
+ GimpTextTool *text_tool = GIMP_TEXT_TOOL (rect_tool);
- if (text_tool->text_box_fixed)
+ if (text_tool->handle_rectangle_change_complete)
{
- GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (text_tool);
- GimpItem *item = GIMP_ITEM (layer);
- gint x1, y1, x2, y2;
+ GimpText *text = text_tool->text;
+ GimpItem *item;
+ gint x1, y1, x2, y2;
g_object_get (rect_tool,
"x1", &x1,
@@ -1508,395 +1288,428 @@
"x2", &x2,
"y2", &y2,
NULL);
+
+ text_tool->text_box_fixed = TRUE;
+
+ if (! text || ! text->text || (text->text[0] == 0))
+ {
+ /*
+ * we can't set properties for the text layer, because
+ * it isn't created until some text has been inserted,
+ * so we need to make a special note that will remind
+ * us what to do when we actually create the layer
+ */
+ return TRUE;
+ }
+
g_object_set (text_tool->proxy,
"box-mode", GIMP_TEXT_BOX_FIXED,
"box-width", (gdouble) (x2 - x1),
"box-height", (gdouble) (y2 - y1),
NULL);
+
+ gimp_image_undo_group_start (text_tool->image, GIMP_UNDO_GROUP_TEXT,
+ _("Reshape Text Layer"));
+
+ item = GIMP_ITEM (text_tool->layer);
gimp_item_translate (item,
x1 - item->offset_x,
y1 - item->offset_y,
TRUE);
- }
- else
- {
- text_tool->handle_rectangle_change_complete = FALSE;
- gimp_rectangle_tool_frame_item (GIMP_RECTANGLE_TOOL (text_tool),
- GIMP_ITEM (layer));
- text_tool->handle_rectangle_change_complete = TRUE;
+ gimp_text_tool_apply (text_tool);
+
+ gimp_image_undo_group_end (text_tool->image);
}
- gimp_image_undo_group_end (image);
+ return TRUE;
+}
- gimp_image_flush (image);
- gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), FALSE);
-}
+/* private functions */
static void
-gimp_text_tool_canvas_editor (GimpTextTool *text_tool)
+gimp_text_tool_connect (GimpTextTool *text_tool,
+ GimpTextLayer *layer,
+ GimpText *text)
{
- GimpTool *tool = GIMP_TOOL (text_tool);
- GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
+ GimpTool *tool = GIMP_TOOL (text_tool);
- gtk_im_context_set_client_window (text_tool->im_context,
- GIMP_DISPLAY_SHELL (tool->display->shell)->canvas->window);
+ g_return_if_fail (text == NULL || (layer != NULL && layer->text == text));
- gtk_im_context_focus_in (text_tool->im_context);
+ if (text_tool->text != text)
+ {
+ GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (tool);
- gimp_text_tool_update_layout (text_tool);
+ if (text_tool->text)
+ {
+ g_signal_handlers_disconnect_by_func (text_tool->text,
+ gimp_text_tool_text_notify,
+ text_tool);
- if (options->use_editor)
- gimp_text_tool_editor (text_tool);
-}
+ if (text_tool->pending)
+ gimp_text_tool_apply (text_tool);
-static void
-gimp_text_tool_editor (GimpTextTool *text_tool)
-{
- GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
- GimpDialogFactory *dialog_factory;
- GtkWindow *parent = NULL;
+ g_object_unref (text_tool->text);
+ text_tool->text = NULL;
- if (text_tool->editor)
- {
- gtk_window_present (GTK_WINDOW (text_tool->editor));
- return;
- }
+ g_object_set (text_tool->proxy, "text", NULL, NULL);
+ }
- dialog_factory = gimp_dialog_factory_from_name ("toplevel");
+ gimp_context_define_property (GIMP_CONTEXT (options),
+ GIMP_CONTEXT_PROP_FOREGROUND,
+ text != NULL);
- if (GIMP_TOOL (text_tool)->display)
- parent = GTK_WINDOW (GIMP_TOOL (text_tool)->display->shell);
+ if (text)
+ {
+ gimp_config_sync (G_OBJECT (text), G_OBJECT (text_tool->proxy), 0);
- text_tool->editor = gimp_text_options_editor_new (parent, options,
- dialog_factory->menu_factory,
- _("GIMP Text Editor"),
- text_tool->text_buffer);
+ text_tool->text = g_object_ref (text);
- g_object_add_weak_pointer (G_OBJECT (text_tool->editor),
- (gpointer) &text_tool->editor);
+ g_signal_connect (text, "notify",
+ G_CALLBACK (gimp_text_tool_text_notify),
+ text_tool);
+ }
+ }
- gimp_dialog_factory_add_foreign (dialog_factory,
- "gimp-text-tool-dialog",
- text_tool->editor);
+ if (text_tool->layer != layer)
+ {
+ if (text_tool->layer)
+ g_signal_handlers_disconnect_by_func (text_tool->layer,
+ gimp_text_tool_layer_notify,
+ text_tool);
- gtk_widget_show (text_tool->editor);
+ text_tool->layer = layer;
+
+ if (layer)
+ g_signal_connect_object (text_tool->layer, "notify::modified",
+ G_CALLBACK (gimp_text_tool_layer_notify),
+ text_tool, 0);
+ }
}
-static gchar *
-gimp_text_tool_canvas_editor_get_text (GimpTextTool *text_tool)
+static void
+gimp_text_tool_use_editor_notify (GimpTextOptions *options,
+ GParamSpec *pspec,
+ GimpTextTool *text_tool)
{
- if (text_tool->text_buffer)
+ if (options->use_editor)
{
- GtkTextIter start, end;
- GtkTextIter selstart, selend;
- gchar *string;
- gchar *fb;
- gchar *lb;
+ if (text_tool->text && text_tool->text_buffer)
+ gimp_text_tool_editor (text_tool);
+ }
+ else
+ {
+ if (text_tool->editor)
+ gtk_widget_destroy (text_tool->editor);
+ }
+}
- gtk_text_buffer_get_bounds (text_tool->text_buffer, &start, &end);
- gtk_text_buffer_get_selection_bounds (text_tool->text_buffer,
- &selstart, &selend);
+static void
+gimp_text_tool_layer_notify (GimpTextLayer *layer,
+ GParamSpec *pspec,
+ GimpTextTool *text_tool)
+{
+ if (layer->modified)
+ gimp_text_tool_connect (text_tool, NULL, NULL);
+}
- fb = gtk_text_buffer_get_text (text_tool->text_buffer,
- &start, &selstart, TRUE);
- lb = gtk_text_buffer_get_text (text_tool->text_buffer,
- &selstart, &end, TRUE);
+static void
+gimp_text_tool_proxy_notify (GimpText *text,
+ GParamSpec *pspec,
+ GimpTextTool *text_tool)
+{
+ if (! text_tool->text)
+ return;
- if (text_tool->preedit_string)
- {
- if (fb == NULL)
- {
- string = g_strconcat (text_tool->preedit_string, lb, NULL);
- }
- else
- {
- string = g_strconcat (fb, text_tool->preedit_string, lb, NULL);
- }
- }
- else
- {
- string = g_strconcat (fb, lb, NULL);
- }
+ if ((pspec->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE)
+ {
+ text_tool->pending = g_list_append (text_tool->pending, pspec);
- g_free (fb);
- g_free (lb);
+ if (text_tool->idle_id)
+ g_source_remove (text_tool->idle_id);
- return string;
+ text_tool->idle_id =
+ g_idle_add_full (G_PRIORITY_LOW,
+ (GSourceFunc) gimp_text_tool_idle_apply, text_tool,
+ NULL);
}
-
- return NULL;
}
-
-#define RESPONSE_NEW 1
-
static void
-gimp_text_tool_confirm_response (GtkWidget *widget,
- gint response_id,
- GimpTextTool *text_tool)
+gimp_text_tool_text_notify (GimpText *text,
+ GParamSpec *pspec,
+ GimpTextTool *text_tool)
{
- GimpTextLayer *layer = text_tool->layer;
+ g_return_if_fail (text == text_tool->text);
- gtk_widget_destroy (widget);
+ if ((pspec->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE)
+ {
+ GValue value = { 0, };
- if (layer && layer->text)
+ g_value_init (&value, pspec->value_type);
+
+ g_object_get_property (G_OBJECT (text), pspec->name, &value);
+
+ g_signal_handlers_block_by_func (text_tool->proxy,
+ gimp_text_tool_proxy_notify,
+ text_tool);
+
+ g_object_set_property (G_OBJECT (text_tool->proxy), pspec->name, &value);
+
+ g_signal_handlers_unblock_by_func (text_tool->proxy,
+ gimp_text_tool_proxy_notify,
+ text_tool);
+
+ g_value_unset (&value);
+ }
+
+ /* we need to redraw the rectangle if it is visible and the shape of
+ the layer has changed, because of an undo for example. */
+ if (strcmp (pspec->name, "box-width") == 0 ||
+ strcmp (pspec->name, "box-height") == 0 ||
+ text->box_mode == GIMP_TEXT_BOX_DYNAMIC)
{
- switch (response_id)
- {
- case RESPONSE_NEW:
- gimp_text_tool_create_layer (text_tool, layer->text);
- break;
+ GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (text_tool);
- case GTK_RESPONSE_ACCEPT:
- gimp_text_tool_connect (text_tool, layer, layer->text);
+ text_tool->handle_rectangle_change_complete = FALSE;
+ gimp_rectangle_tool_frame_item (rect_tool,
+ GIMP_ITEM (text_tool->layer));
+ text_tool->handle_rectangle_change_complete = TRUE;
+ }
- /* cause the text layer to be rerendered */
- if (text_tool->proxy)
- g_object_notify (G_OBJECT (text_tool->proxy), "text");
+ /* if the text has changed, (probably because of an undo), we put
+ * the new text into the text buffer
+ */
+ if (strcmp (pspec->name, "text") == 0)
+ {
+ g_signal_handlers_block_by_func (text_tool->proxy,
+ gimp_text_tool_text_buffer_changed,
+ text_tool);
- gimp_text_tool_canvas_editor (text_tool);
- break;
+ gtk_text_buffer_set_text (text_tool->text_buffer, text->text, -1);
- default:
- break;
- }
+ g_signal_handlers_unblock_by_func (text_tool->proxy,
+ gimp_text_tool_text_buffer_changed,
+ text_tool);
+
+ /* force change of cursor and selection display */
+ gimp_text_tool_update_layout (text_tool);
+/* gimp_text_tool_update_proxy (text_tool); */
+ return;
}
}
+static gboolean
+gimp_text_tool_idle_apply (GimpTextTool *text_tool)
+{
+ text_tool->idle_id = 0;
+
+ gimp_text_tool_apply (text_tool);
+
+ return FALSE;
+}
+
static void
-gimp_text_tool_confirm_dialog (GimpTextTool *text_tool)
+gimp_text_tool_apply (GimpTextTool *text_tool)
{
- GimpTool *tool = GIMP_TOOL (text_tool);
- GtkWidget *dialog;
- GtkWidget *vbox;
- GtkWidget *label;
-
- g_return_if_fail (text_tool->layer != NULL);
+ const GParamSpec *pspec = NULL;
+ GimpImage *image;
+ GimpTextLayer *layer;
+ GObject *src;
+ GObject *dest;
+ GList *list;
+ gboolean push_undo = TRUE;
+ gboolean undo_group = FALSE;
- if (text_tool->confirm_dialog)
+ if (text_tool->idle_id)
{
- gtk_window_present (GTK_WINDOW (text_tool->confirm_dialog));
- return;
+ g_source_remove (text_tool->idle_id);
+ text_tool->idle_id = 0;
}
- dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (text_tool->layer),
- GIMP_CONTEXT (gimp_tool_get_options (tool)),
- _("Confirm Text Editing"),
- "gimp-text-tool-confirm",
- GIMP_STOCK_TEXT_LAYER,
- _("Confirm Text Editing"),
- tool->display->shell,
- gimp_standard_help_func, NULL,
-
- _("Create _New Layer"), RESPONSE_NEW,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_EDIT, GTK_RESPONSE_ACCEPT,
-
- NULL);
-
- gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
- RESPONSE_NEW,
- GTK_RESPONSE_OK,
- GTK_RESPONSE_CANCEL,
- -1);
+ g_return_if_fail (text_tool->text != NULL);
+ g_return_if_fail (text_tool->layer != NULL);
- gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ layer = text_tool->layer;
+ image = gimp_item_get_image (GIMP_ITEM (layer));
- g_signal_connect (dialog, "response",
- G_CALLBACK (gimp_text_tool_confirm_response),
- text_tool);
+ g_return_if_fail (layer->text == text_tool->text);
- vbox = gtk_vbox_new (FALSE, 6);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
- vbox, FALSE, FALSE, 0);
- gtk_widget_show (vbox);
+ /* Walk over the list of changes and figure out if we are changing
+ * a single property or need to push a full text undo.
+ */
+ for (list = text_tool->pending;
+ list && list->next && list->next->data == list->data;
+ list = list->next)
+ /* do nothing */;
- label = gtk_label_new (_("The layer you selected is a text layer but "
- "it has been modified using other tools. "
- "Editing the layer with the text tool will "
- "discard these modifications."
- "\n\n"
- "You can edit the layer or create a new "
- "text layer from its text attributes."));
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
- gtk_widget_show (label);
+ if (g_list_length (list) == 1)
+ pspec = list->data;
- gtk_widget_show (dialog);
+ /* If we are changing a single property, we don't need to push
+ * an undo if all of the following is true:
+ * - the redo stack is empty
+ * - the last item on the undo stack is a text undo
+ * - the last undo changed the same text property on the same layer
+ * - the last undo happened less than TEXT_UNDO_TIMEOUT seconds ago
+ */
+ if (pspec)
+ {
+ GimpUndo *undo = gimp_image_undo_can_compress (image, GIMP_TYPE_TEXT_UNDO,
+ GIMP_UNDO_TEXT_LAYER);
- text_tool->confirm_dialog = dialog;
- g_signal_connect_swapped (dialog, "destroy",
- G_CALLBACK (g_nullify_pointer),
- &text_tool->confirm_dialog);
-}
+ if (undo && GIMP_ITEM_UNDO (undo)->item == GIMP_ITEM (layer))
+ {
+ GimpTextUndo *text_undo = GIMP_TEXT_UNDO (undo);
-static void
-gimp_text_tool_layer_changed (GimpImage *image,
- GimpTextTool *text_tool)
-{
- GimpLayer *layer = gimp_image_get_active_layer (image);
- GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (text_tool);
+ if (text_undo->pspec == pspec)
+ {
+ if (gimp_undo_get_age (undo) < TEXT_UNDO_TIMEOUT)
+ {
+ GimpTool *tool = GIMP_TOOL (text_tool);
- gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), FALSE);
+ push_undo = FALSE;
+ gimp_undo_reset_age (undo);
+ gimp_undo_refresh_preview (undo,
+ GIMP_CONTEXT (gimp_tool_get_options (tool)));
+ }
+ }
+ }
+ }
- if (text_tool->layer)
+ if (push_undo)
{
- if (! gimp_rectangle_tool_rectangle_is_new (rect_tool))
+ if (layer->modified)
{
- text_tool->handle_rectangle_change_complete = FALSE;
- gimp_rectangle_tool_frame_item (rect_tool,
- GIMP_ITEM (text_tool->layer));
- text_tool->handle_rectangle_change_complete = TRUE;
+ undo_group = TRUE;
+ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, NULL);
+
+ gimp_image_undo_push_text_layer_modified (image, NULL, layer);
+ gimp_image_undo_push_drawable_mod (image,
+ NULL, GIMP_DRAWABLE (layer));
}
+
+ gimp_image_undo_push_text_layer (image, NULL, layer, pspec);
}
-}
-static void
-gimp_text_tool_set_image (GimpTextTool *text_tool,
- GimpImage *image)
-{
- if (text_tool->image == image)
- return;
+ src = G_OBJECT (text_tool->proxy);
+ dest = G_OBJECT (text_tool->text);
- if (text_tool->image)
- {
- g_signal_handlers_disconnect_by_func (text_tool->image,
- gimp_text_tool_layer_changed,
- text_tool);
+ g_signal_handlers_block_by_func (dest,
+ gimp_text_tool_text_notify, text_tool);
- g_object_remove_weak_pointer (G_OBJECT (text_tool->image),
- (gpointer) &text_tool->image);
- text_tool->image = NULL;
- }
+ g_object_freeze_notify (dest);
- if (image)
+ for (; list; list = list->next)
{
- GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
- gdouble xres;
- gdouble yres;
+ GValue value = { 0, };
- gimp_image_get_resolution (image, &xres, &yres);
+ /* look ahead and compress changes */
+ if (list->next && list->next->data == list->data)
+ continue;
- text_tool->image = image;
- g_object_add_weak_pointer (G_OBJECT (text_tool->image),
- (gpointer) &text_tool->image);
+ pspec = list->data;
- g_signal_connect_object (text_tool->image, "active-layer-changed",
- G_CALLBACK (gimp_text_tool_layer_changed),
- text_tool, 0);
+ g_value_init (&value, pspec->value_type);
- gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (options->size_entry), 0,
- yres, FALSE);
- }
-}
+ g_object_get_property (src, pspec->name, &value);
+ g_object_set_property (dest, pspec->name, &value);
-static gboolean
-gimp_text_tool_set_drawable (GimpTextTool *text_tool,
- GimpDrawable *drawable,
- gboolean confirm)
-{
- GimpImage *image = NULL;
+ g_value_unset (&value);
+ }
- if (text_tool->confirm_dialog)
- gtk_widget_destroy (text_tool->confirm_dialog);
+ g_list_free (text_tool->pending);
+ text_tool->pending = NULL;
- if (drawable)
- image = gimp_item_get_image (GIMP_ITEM (drawable));
+ g_object_thaw_notify (dest);
- gimp_text_tool_set_image (text_tool, image);
+ g_signal_handlers_unblock_by_func (dest,
+ gimp_text_tool_text_notify, text_tool);
- if (GIMP_IS_TEXT_LAYER (drawable) && GIMP_TEXT_LAYER (drawable)->text)
+ if (push_undo)
{
- GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable);
-
- if (layer == text_tool->layer && layer->text == text_tool->text)
- return TRUE;
+ g_object_set (layer, "modified", FALSE, NULL);
- if (layer->modified)
- {
- if (confirm)
- {
- gimp_text_tool_connect (text_tool, layer, NULL);
- gimp_text_tool_confirm_dialog (text_tool);
- return TRUE;
- }
- }
- else
- {
- gimp_text_tool_connect (text_tool, layer, layer->text);
- return TRUE;
- }
+ if (undo_group)
+ gimp_image_undo_group_end (image);
}
- gimp_text_tool_connect (text_tool, NULL, NULL);
- text_tool->layer = NULL;
+ /* if we're doing dynamic text, we want to update the
+ * shape of the rectangle */
+ if (layer->text->box_mode == GIMP_TEXT_BOX_DYNAMIC)
+ {
+ text_tool->handle_rectangle_change_complete = FALSE;
+ gimp_rectangle_tool_frame_item (GIMP_RECTANGLE_TOOL (text_tool),
+ GIMP_ITEM (layer));
+ text_tool->handle_rectangle_change_complete = TRUE;
+ }
- return FALSE;
+ gimp_image_flush (image);
+ gimp_text_tool_update_layout (text_tool);
}
-void
-gimp_text_tool_set_layer (GimpTextTool *text_tool,
- GimpLayer *layer)
+static void
+gimp_text_tool_create_layer (GimpTextTool *text_tool,
+ GimpText *text)
{
- g_return_if_fail (GIMP_IS_TEXT_TOOL (text_tool));
- g_return_if_fail (layer == NULL || GIMP_IS_LAYER (layer));
+ GimpTool *tool = GIMP_TOOL (text_tool);
+ GimpImage *image;
+ GimpLayer *layer;
+
+ if (text)
+ {
+ text = gimp_config_duplicate (GIMP_CONFIG (text));
+ }
+ else
+ {
+ gchar *str = gimp_text_tool_canvas_editor_get_text (text_tool);
+
+ g_object_set (text_tool->proxy,
+ "text", str,
+ "box-mode", GIMP_TEXT_BOX_DYNAMIC,
+ NULL);
- if (gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), TRUE))
- {
- GimpTool *tool = GIMP_TOOL (text_tool);
- GimpItem *item = GIMP_ITEM (layer);
- GimpContext *context;
- GimpDisplay *display;
+ g_free (str);
- context = gimp_get_user_context (tool->tool_info->gimp);
- display = gimp_context_get_display (context);
+ text = gimp_config_duplicate (GIMP_CONFIG (text_tool->proxy));
+ }
- if (! display || display->image != item->image)
- {
- GList *list;
+ image = tool->display->image;
+ layer = gimp_text_layer_new (image, text);
- display = NULL;
+ g_object_unref (text);
- for (list = GIMP_LIST (tool->tool_info->gimp->displays)->list;
- list;
- list = g_list_next (list))
- {
- display = list->data;
+ if (! layer)
+ return;
- if (display->image == item->image)
- {
- gimp_context_set_display (context, display);
- break;
- }
+ gimp_text_tool_connect (text_tool, GIMP_TEXT_LAYER (layer), text);
- display = NULL;
- }
- }
+ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT,
+ _("Add Text Layer"));
- tool->display = display;
+ if (gimp_image_floating_sel (image))
+ {
+ g_signal_handlers_block_by_func (image,
+ gimp_text_tool_layer_changed,
+ text_tool);
- if (tool->display)
- {
- tool->drawable = GIMP_DRAWABLE (layer);
+ floating_sel_anchor (gimp_image_floating_sel (image));
- gimp_text_tool_canvas_editor (text_tool);
- }
+ g_signal_handlers_unblock_by_func (image,
+ gimp_text_tool_layer_changed,
+ text_tool);
}
-}
-static gboolean
-gimp_text_tool_rectangle_change_complete (GimpRectangleTool *rect_tool)
-{
- GimpTextTool *text_tool = GIMP_TEXT_TOOL (rect_tool);
+ GIMP_ITEM (layer)->offset_x = text_tool->x1;
+ GIMP_ITEM (layer)->offset_y = text_tool->y1;
- if (text_tool->handle_rectangle_change_complete)
+ gimp_image_add_layer (image, layer, -1, TRUE);
+
+ if (text_tool->text_box_fixed)
{
- GimpText *text = text_tool->text;
- GimpItem *item;
- gint x1, y1, x2, y2;
+ GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (text_tool);
+ GimpItem *item = GIMP_ITEM (layer);
+ gint x1, y1, x2, y2;
g_object_get (rect_tool,
"x1", &x1,
@@ -1904,392 +1717,383 @@
"x2", &x2,
"y2", &y2,
NULL);
-
- text_tool->text_box_fixed = TRUE;
-
- if (! text || ! text->text || (text->text[0] == 0))
- {
- /*
- * we can't set properties for the text layer, because
- * it isn't created until some text has been inserted,
- * so we need to make a special note that will remind
- * us what to do when we actually create the layer
- */
- return TRUE;
- }
-
g_object_set (text_tool->proxy,
"box-mode", GIMP_TEXT_BOX_FIXED,
"box-width", (gdouble) (x2 - x1),
"box-height", (gdouble) (y2 - y1),
NULL);
-
- gimp_image_undo_group_start (text_tool->image, GIMP_UNDO_GROUP_TEXT,
- _("Reshape Text Layer"));
-
- item = GIMP_ITEM (text_tool->layer);
gimp_item_translate (item,
x1 - item->offset_x,
y1 - item->offset_y,
TRUE);
- gimp_text_tool_apply (text_tool);
-
- gimp_image_undo_group_end (text_tool->image);
+ }
+ else
+ {
+ text_tool->handle_rectangle_change_complete = FALSE;
+ gimp_rectangle_tool_frame_item (GIMP_RECTANGLE_TOOL (text_tool),
+ GIMP_ITEM (layer));
+ text_tool->handle_rectangle_change_complete = TRUE;
}
- return TRUE;
+ gimp_image_undo_group_end (image);
+
+ gimp_image_flush (image);
+
+ gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), FALSE);
}
-/* this doesn't belong here but this is the only place
- it is used at the moment -- Bill
-*/
-
-/**
- * gimp_rectangle_tool_frame_item:
- * @rect_tool: a #GimpRectangleTool interface
- * @item: a #GimpItem attached to the image on which a
- * rectangle is being shown.
- *
- * Convenience function to set the corners of the rectangle to
- * match the bounds of the specified item. The rectangle interface
- * must be active (i.e., showing a rectangle), and the item must be
- * attached to the image on which the rectangle is active.
- */
-void
-gimp_rectangle_tool_frame_item (GimpRectangleTool *rect_tool,
- GimpItem *item)
+static void
+gimp_text_tool_canvas_editor (GimpTextTool *text_tool)
{
- GimpDisplay *display = GIMP_TOOL (rect_tool)->display;
- gint offset_x;
- gint offset_y;
- gint width;
- gint height;
-
- g_return_if_fail (GIMP_IS_ITEM (item));
- g_return_if_fail (gimp_item_is_attached (item));
- g_return_if_fail (display != NULL);
- g_return_if_fail (display->image == item->image);
-
- width = gimp_item_width (item);
- height = gimp_item_height (item);
-
- gimp_item_offsets (item, &offset_x, &offset_y);
-
- gimp_draw_tool_pause (GIMP_DRAW_TOOL (rect_tool));
-
- gimp_rectangle_tool_set_function (rect_tool,
- GIMP_RECTANGLE_TOOL_CREATING);
-
- g_object_set (rect_tool,
- "x1", offset_x,
- "y1", offset_y,
- "x2", offset_x + width,
- "y2", offset_y + height,
- NULL);
+ GimpTool *tool = GIMP_TOOL (text_tool);
+ GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
- /* kludge to force handle sizes to update. This call may be
- * harmful if this function is ever moved out of the text tool code.
- */
- gimp_rectangle_tool_set_constraint (rect_tool,
- GIMP_RECTANGLE_CONSTRAIN_NONE);
+ gtk_im_context_set_client_window (text_tool->im_context,
+ GIMP_DISPLAY_SHELL (tool->display->shell)->canvas->window);
+
+ gtk_im_context_focus_in (text_tool->im_context);
+
+ gimp_text_tool_update_layout (text_tool);
- gimp_draw_tool_resume (GIMP_DRAW_TOOL (rect_tool));
+ if (options->use_editor)
+ gimp_text_tool_editor (text_tool);
}
static void
-gimp_text_tool_draw_preedit_lines (GimpDrawTool *draw_tool)
+gimp_text_tool_editor (GimpTextTool *text_tool)
{
- GimpTextTool *text_tool = GIMP_TEXT_TOOL (draw_tool);
- PangoLayout *layout;
- PangoLayoutIter *line_iter;
- GtkTextIter cursor, start;
- gint i;
- gint min, max;
- gchar *string;
+ GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
+ GimpDialogFactory *dialog_factory;
+ GtkWindow *parent = NULL;
- gtk_text_buffer_get_selection_bounds (text_tool->text_buffer, &cursor, NULL);
- gtk_text_buffer_get_start_iter (text_tool->text_buffer, &start);
+ if (text_tool->editor)
+ {
+ gtk_window_present (GTK_WINDOW (text_tool->editor));
+ return;
+ }
- string = gtk_text_buffer_get_text (text_tool->text_buffer,
- &start, &cursor, FALSE);
- min = strlen (string);
- g_free (string);
+ dialog_factory = gimp_dialog_factory_from_name ("toplevel");
- max = min + text_tool->preedit_len;
+ if (GIMP_TOOL (text_tool)->display)
+ parent = GTK_WINDOW (GIMP_TOOL (text_tool)->display->shell);
- layout = text_tool->layout->layout;
- line_iter = pango_layout_get_iter (layout);
- i = 0;
+ text_tool->editor = gimp_text_options_editor_new (parent, options,
+ dialog_factory->menu_factory,
+ _("GIMP Text Editor"),
+ text_tool->text_buffer);
- do
- {
- gint firstline, lastline;
- gint first_x, last_x;
+ g_object_add_weak_pointer (G_OBJECT (text_tool->editor),
+ (gpointer) &text_tool->editor);
- pango_layout_index_to_line_x (layout, min, 0, &firstline, &first_x);
- pango_layout_index_to_line_x (layout, max, 0, &lastline, &last_x);
+ gimp_dialog_factory_add_foreign (dialog_factory,
+ "gimp-text-tool-dialog",
+ text_tool->editor);
- if (i >= firstline && i <= lastline)
- {
- PangoRectangle crect;
+ gtk_widget_show (text_tool->editor);
+}
- pango_layout_iter_get_line_extents (line_iter, NULL, &crect);
- pango_extents_to_pixels (&crect, NULL);
+static gchar *
+gimp_text_tool_canvas_editor_get_text (GimpTextTool *text_tool)
+{
+ if (text_tool->text_buffer)
+ {
+ GtkTextIter start, end;
+ GtkTextIter selstart, selend;
+ gchar *string;
+ gchar *fb;
+ gchar *lb;
- gimp_draw_tool_draw_line (draw_tool,
- crect.x, crect.y + crect.height,
- crect.x + crect.width,
- crect.y + crect.height,
- TRUE);
- if (i == firstline)
- {
- PangoRectangle crect2 = crect;
+ gtk_text_buffer_get_bounds (text_tool->text_buffer, &start, &end);
+ gtk_text_buffer_get_selection_bounds (text_tool->text_buffer,
+ &selstart, &selend);
- crect2.width = PANGO_PIXELS (first_x) - crect.x;
- crect2.x = crect.x;
+ fb = gtk_text_buffer_get_text (text_tool->text_buffer,
+ &start, &selstart, TRUE);
+ lb = gtk_text_buffer_get_text (text_tool->text_buffer,
+ &selstart, &end, TRUE);
- gimp_draw_tool_draw_line (draw_tool,
- crect2.x, crect2.y + crect2.height,
- crect2.width,
- crect2.y + crect2.height,
- TRUE);
+ if (text_tool->preedit_string)
+ {
+ if (fb == NULL)
+ {
+ string = g_strconcat (text_tool->preedit_string, lb, NULL);
}
- if (i == lastline)
+ else
{
- PangoRectangle crect2 = crect;
+ string = g_strconcat (fb, text_tool->preedit_string, lb, NULL);
+ }
+ }
+ else
+ {
+ string = g_strconcat (fb, lb, NULL);
+ }
+
+ g_free (fb);
+ g_free (lb);
+
+ return string;
+ }
+
+ return NULL;
+}
+
+
+#define RESPONSE_NEW 1
+
+static void
+gimp_text_tool_confirm_response (GtkWidget *widget,
+ gint response_id,
+ GimpTextTool *text_tool)
+{
+ GimpTextLayer *layer = text_tool->layer;
+
+ gtk_widget_destroy (widget);
+
+ if (layer && layer->text)
+ {
+ switch (response_id)
+ {
+ case RESPONSE_NEW:
+ gimp_text_tool_create_layer (text_tool, layer->text);
+ break;
+
+ case GTK_RESPONSE_ACCEPT:
+ gimp_text_tool_connect (text_tool, layer, layer->text);
+
+ /* cause the text layer to be rerendered */
+ if (text_tool->proxy)
+ g_object_notify (G_OBJECT (text_tool->proxy), "text");
- crect2.width = crect.x + crect.width - PANGO_PIXELS (last_x);
- crect2.x = PANGO_PIXELS (last_x);
+ gimp_text_tool_canvas_editor (text_tool);
+ break;
- gimp_draw_tool_draw_line (draw_tool,
- crect2.x, crect2.y + crect2.height,
- crect2.x + crect2.width,
- crect2.y + crect2.height,
- TRUE);
- }
+ default:
+ break;
}
-
- i++;
}
- while (pango_layout_iter_next_line (line_iter));
-
- pango_layout_iter_free (line_iter);
}
static void
-gimp_text_tool_draw_text_selection (GimpDrawTool *draw_tool)
+gimp_text_tool_confirm_dialog (GimpTextTool *text_tool)
{
- GimpTextTool *text_tool = GIMP_TEXT_TOOL (draw_tool);
- PangoLayout *layout;
- PangoLayoutIter *line_iter;
- GtkTextIter start;
- GtkTextIter sel_start, sel_end;
- gint i;
- gint min, max;
- gchar *string;
-
- gtk_text_buffer_get_selection_bounds (text_tool->text_buffer,
- &sel_start, &sel_end);
- gtk_text_buffer_get_start_iter (text_tool->text_buffer, &start);
+ GimpTool *tool = GIMP_TOOL (text_tool);
+ GtkWidget *dialog;
+ GtkWidget *vbox;
+ GtkWidget *label;
- string = gtk_text_buffer_get_text (text_tool->text_buffer,
- &start, &sel_start, FALSE);
- min = strlen (string);
- g_free (string);
+ g_return_if_fail (text_tool->layer != NULL);
- string = gtk_text_buffer_get_text (text_tool->text_buffer,
- &start, &sel_end, FALSE);
- max = strlen (string);
- g_free (string);
+ if (text_tool->confirm_dialog)
+ {
+ gtk_window_present (GTK_WINDOW (text_tool->confirm_dialog));
+ return;
+ }
- layout = text_tool->layout->layout;
- line_iter = pango_layout_get_iter (layout);
- i = 0;
+ dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (text_tool->layer),
+ GIMP_CONTEXT (gimp_tool_get_options (tool)),
+ _("Confirm Text Editing"),
+ "gimp-text-tool-confirm",
+ GIMP_STOCK_TEXT_LAYER,
+ _("Confirm Text Editing"),
+ tool->display->shell,
+ gimp_standard_help_func, NULL,
- /* Invert the selected letters by inverting all
- * lines containing selected letters, then
- * invert the unselected letters on these lines
- * a second time to make them look normal
- */
- do
- {
- gint firstline, lastline;
- gint first_x, last_x;
+ _("Create _New Layer"), RESPONSE_NEW,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_EDIT, GTK_RESPONSE_ACCEPT,
- pango_layout_index_to_line_x (layout, min, 0, &firstline, &first_x);
- pango_layout_index_to_line_x (layout, max, 0, &lastline, &last_x);
+ NULL);
- if (i >= firstline && i <= lastline)
- {
- PangoRectangle crect;
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ RESPONSE_NEW,
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
- pango_layout_iter_get_line_extents (line_iter, NULL, &crect);
- pango_extents_to_pixels (&crect, NULL);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
- gimp_draw_tool_draw_rectangle (draw_tool, TRUE,
- crect.x, crect.y,
- crect.width, crect.height,
- TRUE);
- if (i == firstline)
- {
- /* Twice invert all letters before the selection,
- * making them look normal
- */
- PangoRectangle crect2 = crect;
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gimp_text_tool_confirm_response),
+ text_tool);
- crect2.width = PANGO_PIXELS (first_x) - crect.x;
- crect2.x = crect.x;
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+ vbox, FALSE, FALSE, 0);
+ gtk_widget_show (vbox);
- gimp_draw_tool_draw_rectangle (draw_tool, TRUE,
- crect2.x, crect2.y,
- crect2.width, crect2.height,
- TRUE);
- }
- if (i == lastline)
- {
- /* Twice invert all letters after the selection,
- * making them look normal
- */
- PangoRectangle crect2 = crect;
+ label = gtk_label_new (_("The layer you selected is a text layer but "
+ "it has been modified using other tools. "
+ "Editing the layer with the text tool will "
+ "discard these modifications."
+ "\n\n"
+ "You can edit the layer or create a new "
+ "text layer from its text attributes."));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
- crect2.width = crect.x + crect.width - PANGO_PIXELS (last_x);
- crect2.x = PANGO_PIXELS (last_x);
+ gtk_widget_show (dialog);
- gimp_draw_tool_draw_rectangle (draw_tool, TRUE,
- crect2.x, crect2.y,
- crect2.width, crect2.height,
- TRUE);
- }
- }
- i++;
- }
- while (pango_layout_iter_next_line (line_iter));
- pango_layout_iter_free (line_iter);
+ text_tool->confirm_dialog = dialog;
+ g_signal_connect_swapped (dialog, "destroy",
+ G_CALLBACK (g_nullify_pointer),
+ &text_tool->confirm_dialog);
}
static void
-gimp_text_tool_draw (GimpDrawTool *draw_tool)
+gimp_text_tool_layer_changed (GimpImage *image,
+ GimpTextTool *text_tool)
{
- GimpTextTool *text_tool = GIMP_TEXT_TOOL (draw_tool);
- GimpTool *tool = GIMP_TOOL (draw_tool);
- GdkRectangle cliprect;
- gint width, height;
- gint x1, x2;
- gint y1, y2;
- GtkTextIter start;
+ GimpLayer *layer = gimp_image_get_active_layer (image);
+ GimpRectangleTool *rect_tool = GIMP_RECTANGLE_TOOL (text_tool);
- g_object_set (text_tool,
- "narrow-mode", TRUE,
- NULL);
+ gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), FALSE);
- gimp_rectangle_tool_draw (draw_tool);
+ if (text_tool->layer)
+ {
+ if (! gimp_rectangle_tool_rectangle_is_new (rect_tool))
+ {
+ text_tool->handle_rectangle_change_complete = FALSE;
+ gimp_rectangle_tool_frame_item (rect_tool,
+ GIMP_ITEM (text_tool->layer));
+ text_tool->handle_rectangle_change_complete = TRUE;
+ }
+ }
+}
- if (! text_tool->layer ||
- ! text_tool->layer->text)
+static void
+gimp_text_tool_set_image (GimpTextTool *text_tool,
+ GimpImage *image)
+{
+ if (text_tool->image == image)
return;
- /* There will be no layout if the function is called from the wrong place */
- if (! text_tool->layout)
- gimp_text_tool_update_layout (text_tool);
-
- g_object_get (text_tool,
- "x1", &x1,
- "y1", &y1,
- "x2", &x2,
- "y2", &y2,
- NULL);
-
- /* Turn on clipping for text-cursor and selections */
- cliprect.x = x1;
- cliprect.width = x2 - x1;
- cliprect.y = y1;
- cliprect.height = y2 - y1;
- gimp_draw_tool_set_clip_rect (draw_tool, &cliprect, FALSE);
-
- gtk_text_buffer_get_start_iter (text_tool->text_buffer, &start);
-
- if (! gtk_text_buffer_get_has_selection (text_tool->text_buffer))
+ if (text_tool->image)
{
- /* If the text buffer has no selection, draw the text cursor */
+ g_signal_handlers_disconnect_by_func (text_tool->image,
+ gimp_text_tool_layer_changed,
+ text_tool);
- gint cursorx;
- GtkTextIter cursor;
- PangoRectangle crect;
- gchar *string;
+ g_object_remove_weak_pointer (G_OBJECT (text_tool->image),
+ (gpointer) &text_tool->image);
+ text_tool->image = NULL;
+ }
- gtk_text_buffer_get_iter_at_mark (text_tool->text_buffer, &cursor,
- gtk_text_buffer_get_insert (text_tool->text_buffer));
+ if (image)
+ {
+ GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
+ gdouble xres;
+ gdouble yres;
- string = gtk_text_buffer_get_text (text_tool->text_buffer,
- &start, &cursor, FALSE);
+ gimp_image_get_resolution (image, &xres, &yres);
- /* Using strlen to get the byte index, not the character offset */
- cursorx = strlen (string);
+ text_tool->image = image;
+ g_object_add_weak_pointer (G_OBJECT (text_tool->image),
+ (gpointer) &text_tool->image);
- /* TODO: make cursor position itself even inside preedits! */
- if (text_tool->preedit_len > 0)
- cursorx += text_tool->preedit_len;
+ g_signal_connect_object (text_tool->image, "active-layer-changed",
+ G_CALLBACK (gimp_text_tool_layer_changed),
+ text_tool, 0);
- g_free (string);
+ gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (options->size_entry), 0,
+ yres, FALSE);
+ }
+}
- pango_layout_index_to_pos (text_tool->layout->layout, cursorx, &crect);
+static gboolean
+gimp_text_tool_set_drawable (GimpTextTool *text_tool,
+ GimpDrawable *drawable,
+ gboolean confirm)
+{
+ GimpImage *image = NULL;
- crect.x = PANGO_PIXELS (crect.x);
- crect.y = PANGO_PIXELS (crect.y);
- crect.height = PANGO_PIXELS (crect.height);
+ if (text_tool->confirm_dialog)
+ gtk_widget_destroy (text_tool->confirm_dialog);
- gimp_draw_tool_draw_rectangle (draw_tool, TRUE,
- crect.x, crect.y,
- 4, crect.height,
- TRUE);
+ if (drawable)
+ image = gimp_item_get_image (GIMP_ITEM (drawable));
- if (text_tool->preedit_string && text_tool->preedit_len > 0)
- gimp_text_tool_draw_preedit_lines (draw_tool);
- }
- else
+ gimp_text_tool_set_image (text_tool, image);
+
+ if (GIMP_IS_TEXT_LAYER (drawable) && GIMP_TEXT_LAYER (drawable)->text)
{
- /* If the text buffer has a selection, highlight the
- * selected letters*/
+ GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable);
+
+ if (layer == text_tool->layer && layer->text == text_tool->text)
+ return TRUE;
- gimp_text_tool_draw_text_selection (draw_tool);
+ if (layer->modified)
+ {
+ if (confirm)
+ {
+ gimp_text_tool_connect (text_tool, layer, NULL);
+ gimp_text_tool_confirm_dialog (text_tool);
+ return TRUE;
+ }
+ }
+ else
+ {
+ gimp_text_tool_connect (text_tool, layer, layer->text);
+ return TRUE;
+ }
}
- /* Turn off clipping when done */
- gimp_draw_tool_set_clip_rect (draw_tool, NULL, FALSE);
-}
+ gimp_text_tool_connect (text_tool, NULL, NULL);
+ text_tool->layer = NULL;
-static void
-gimp_text_tool_commit_cb (GtkIMContext *context,
- const gchar *str,
- GimpTextTool *text_tool)
-{
- gimp_text_tool_enter_text (text_tool, str);
+ return FALSE;
}
-static void
-gimp_text_tool_reset_im_context (GimpTextTool *text_tool)
+void
+gimp_text_tool_set_layer (GimpTextTool *text_tool,
+ GimpLayer *layer)
{
- if (text_tool->needs_im_reset)
+ g_return_if_fail (GIMP_IS_TEXT_TOOL (text_tool));
+ g_return_if_fail (layer == NULL || GIMP_IS_LAYER (layer));
+
+ if (gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), TRUE))
{
- text_tool->needs_im_reset = FALSE;
- gtk_im_context_reset (text_tool->im_context);
- }
-}
+ GimpTool *tool = GIMP_TOOL (text_tool);
+ GimpItem *item = GIMP_ITEM (layer);
+ GimpContext *context;
+ GimpDisplay *display;
-static void
-gimp_text_tool_preedit_changed_cb (GtkIMContext *context,
- GimpTextTool *text_tool)
-{
- if (text_tool->preedit_string)
- g_free (text_tool->preedit_string);
+ context = gimp_get_user_context (tool->tool_info->gimp);
+ display = gimp_context_get_display (context);
- gtk_im_context_get_preedit_string (context,
- &text_tool->preedit_string, NULL,
- &text_tool->preedit_cursor);
+ if (! display || display->image != item->image)
+ {
+ GList *list;
- text_tool->preedit_len = strlen (text_tool->preedit_string);
+ display = NULL;
- gimp_text_tool_update_proxy (text_tool);
+ for (list = GIMP_LIST (tool->tool_info->gimp->displays)->list;
+ list;
+ list = g_list_next (list))
+ {
+ display = list->data;
+
+ if (display->image == item->image)
+ {
+ gimp_context_set_display (context, display);
+ break;
+ }
+
+ display = NULL;
+ }
+ }
+
+ tool->display = display;
+
+ if (tool->display)
+ {
+ tool->drawable = GIMP_DRAWABLE (layer);
+
+ gimp_text_tool_canvas_editor (text_tool);
+ }
+ }
}
static void
@@ -2311,34 +2115,6 @@
}
}
-void
-gimp_text_tool_delete_text (GimpTextTool *text_tool,
- gboolean backspace)
-{
- GtkTextIter cursor;
-
- gtk_text_buffer_get_iter_at_mark (text_tool->text_buffer,
- &cursor,
- gtk_text_buffer_get_insert (text_tool->text_buffer));
-
- if (gtk_text_buffer_get_has_selection (text_tool->text_buffer))
- {
- gtk_text_buffer_delete_selection (text_tool->text_buffer, TRUE, TRUE);
- }
- else if (backspace)
- {
- gtk_text_buffer_backspace (text_tool->text_buffer, &cursor, TRUE, TRUE);
- }
- else
- {
- GtkTextIter end = cursor;
-
- gtk_text_iter_forward_cursor_positions (&end, 1);
- gtk_text_buffer_delete_interactive (text_tool->text_buffer,
- &cursor, &end, TRUE);
- }
-}
-
static void
gimp_text_tool_enter_text (GimpTextTool *text_tool,
const gchar *str)
@@ -2387,6 +2163,73 @@
text_tool->layout = gimp_text_layout_new (text_tool->layer->text, image);
}
+static gint
+gimp_text_tool_xy_to_offset (GimpTextTool *text_tool,
+ gdouble x,
+ gdouble y)
+{
+ GtkTextIter start, end;
+ gchar *string;
+ gint offset;
+ gint trailing;
+
+ gtk_text_buffer_get_bounds (text_tool->text_buffer, &start, &end);
+ string = gtk_text_buffer_get_text (text_tool->text_buffer,
+ &start, &end, TRUE);
+
+ pango_layout_xy_to_index (text_tool->layout->layout,
+ x * PANGO_SCALE,
+ y * PANGO_SCALE,
+ &offset, &trailing);
+
+ offset = g_utf8_pointer_to_offset (string, string + offset);
+ offset += trailing;
+
+ g_free (string);
+
+ return offset;
+}
+
+
+/* IM context utilities and callbacks */
+
+static void
+gimp_text_tool_reset_im_context (GimpTextTool *text_tool)
+{
+ if (text_tool->needs_im_reset)
+ {
+ text_tool->needs_im_reset = FALSE;
+ gtk_im_context_reset (text_tool->im_context);
+ }
+}
+
+static void
+gimp_text_tool_commit_cb (GtkIMContext *context,
+ const gchar *str,
+ GimpTextTool *text_tool)
+{
+ gimp_text_tool_enter_text (text_tool, str);
+}
+
+static void
+gimp_text_tool_preedit_changed_cb (GtkIMContext *context,
+ GimpTextTool *text_tool)
+{
+ if (text_tool->preedit_string)
+ g_free (text_tool->preedit_string);
+
+ gtk_im_context_get_preedit_string (context,
+ &text_tool->preedit_string, NULL,
+ &text_tool->preedit_cursor);
+
+ text_tool->preedit_len = strlen (text_tool->preedit_string);
+
+ gimp_text_tool_update_proxy (text_tool);
+}
+
+
+/* public functions */
+
gboolean
gimp_text_tool_get_has_text_selection (GimpTextTool *text_tool)
{
@@ -2397,6 +2240,34 @@
}
void
+gimp_text_tool_delete_text (GimpTextTool *text_tool,
+ gboolean backspace)
+{
+ GtkTextIter cursor;
+
+ gtk_text_buffer_get_iter_at_mark (text_tool->text_buffer,
+ &cursor,
+ gtk_text_buffer_get_insert (text_tool->text_buffer));
+
+ if (gtk_text_buffer_get_has_selection (text_tool->text_buffer))
+ {
+ gtk_text_buffer_delete_selection (text_tool->text_buffer, TRUE, TRUE);
+ }
+ else if (backspace)
+ {
+ gtk_text_buffer_backspace (text_tool->text_buffer, &cursor, TRUE, TRUE);
+ }
+ else
+ {
+ GtkTextIter end = cursor;
+
+ gtk_text_iter_forward_cursor_positions (&end, 1);
+ gtk_text_buffer_delete_interactive (text_tool->text_buffer,
+ &cursor, &end, TRUE);
+ }
+}
+
+void
gimp_text_tool_clipboard_cut (GimpTextTool *text_tool)
{
GimpTool *tool = GIMP_TOOL (text_tool);
@@ -2436,3 +2307,57 @@
gtk_text_buffer_paste_clipboard (text_tool->text_buffer, clipboard, NULL, TRUE);
}
+
+void
+gimp_text_tool_create_vectors (GimpTextTool *text_tool)
+{
+ GimpVectors *vectors;
+
+ g_return_if_fail (GIMP_IS_TEXT_TOOL (text_tool));
+
+ if (! text_tool->text || ! text_tool->image)
+ return;
+
+ vectors = gimp_text_vectors_new (text_tool->image, text_tool->text);
+
+ if (text_tool->layer)
+ {
+ gint x, y;
+
+ gimp_item_offsets (GIMP_ITEM (text_tool->layer), &x, &y);
+ gimp_item_translate (GIMP_ITEM (vectors), x, y, FALSE);
+ }
+
+ gimp_image_add_vectors (text_tool->image, vectors, -1, TRUE);
+
+ gimp_image_flush (text_tool->image);
+}
+
+void
+gimp_text_tool_create_vectors_warped (GimpTextTool *text_tool)
+{
+ GimpVectors *vectors0;
+ GimpVectors *vectors;
+ gdouble box_height;
+
+ g_return_if_fail (GIMP_IS_TEXT_TOOL (text_tool));
+
+ if (! text_tool->text || ! text_tool->image || ! text_tool->layer)
+ return;
+
+ box_height = gimp_item_height (GIMP_ITEM (text_tool->layer));
+
+ vectors0 = gimp_image_get_active_vectors (text_tool->image);
+ if (! vectors0)
+ return;
+
+ vectors = gimp_text_vectors_new (text_tool->image, text_tool->text);
+
+ gimp_vectors_warp_vectors (vectors0, vectors, 0.5 * box_height);
+
+ gimp_image_add_vectors (text_tool->image, vectors, -1, TRUE);
+ gimp_image_set_active_vectors (text_tool->image, vectors);
+ gimp_item_set_visible (GIMP_ITEM (vectors), TRUE, FALSE);
+
+ gimp_image_flush (text_tool->image);
+}
Modified: trunk/app/tools/gimptexttool.h
==============================================================================
--- trunk/app/tools/gimptexttool.h (original)
+++ trunk/app/tools/gimptexttool.h Mon Oct 27 16:21:03 2008
@@ -86,6 +86,8 @@
void gimp_text_tool_set_layer (GimpTextTool *text_tool,
GimpLayer *layer);
+gboolean gimp_text_tool_get_has_text_selection (GimpTextTool *text_tool);
+
void gimp_text_tool_delete_text (GimpTextTool *text_tool,
gboolean backspace);
void gimp_text_tool_clipboard_cut (GimpTextTool *text_tool);
@@ -94,8 +96,7 @@
void gimp_text_tool_clipboard_paste (GimpTextTool *text_tool,
gboolean use_clipboard);
-gboolean gimp_text_tool_get_has_text_selection (GimpTextTool *text_tool);
void gimp_text_tool_create_vectors (GimpTextTool *text_tool);
-
+void gimp_text_tool_create_vectors_warped (GimpTextTool *text_tool);
#endif /* __GIMP_TEXT_TOOL_H__ */
Modified: trunk/menus/text-tool-menu.xml
==============================================================================
--- trunk/menus/text-tool-menu.xml (original)
+++ trunk/menus/text-tool-menu.xml Mon Oct 27 16:21:03 2008
@@ -12,6 +12,7 @@
<menuitem action="text-tool-clear" />
<separator />
<menuitem action="text-tool-path-from-text" />
+ <menuitem action="text-tool-text-along-path" />
<separator />
<menuitem action="text-tool-direction-ltr" />
<menuitem action="text-tool-direction-rtl" />
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]