2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1997-11-25 06:05:25 +08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2004-03-22 23:19:19 +08:00
|
|
|
* GimpTextTool
|
2010-02-18 04:39:33 +08:00
|
|
|
* Copyright (C) 2002-2010 Sven Neumann <sven@gimp.org>
|
|
|
|
* Daniel Eddeland <danedde@svn.gnome.org>
|
|
|
|
* Michael Natterer <mitch@gimp.org>
|
2004-03-22 23:19:19 +08:00
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1997-11-25 06:05:25 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1997-11-25 06:05:25 +08:00
|
|
|
* (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
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
2000-12-17 05:37:03 +08:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2008-10-10 04:24:04 +08:00
|
|
|
#include <gegl.h>
|
2000-12-29 23:22:01 +08:00
|
|
|
#include <gtk/gtk.h>
|
2000-01-19 07:12:26 +08:00
|
|
|
|
2010-02-22 00:35:04 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2005-01-26 03:11:26 +08:00
|
|
|
#include "libgimpconfig/gimpconfig.h"
|
2001-01-25 06:36:18 +08:00
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
|
2002-05-03 20:45:22 +08:00
|
|
|
#include "tools-types.h"
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2002-11-19 04:50:31 +08:00
|
|
|
#include "core/gimp.h"
|
2018-05-29 22:19:50 +08:00
|
|
|
#include "core/gimpasyncset.h"
|
2003-01-31 17:22:42 +08:00
|
|
|
#include "core/gimpcontext.h"
|
2018-06-03 05:19:51 +08:00
|
|
|
#include "core/gimpdatafactory.h"
|
2018-05-29 22:19:50 +08:00
|
|
|
#include "core/gimperror.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
#include "core/gimpimage.h"
|
2018-03-23 21:19:01 +08:00
|
|
|
#include "core/gimp-palettes.h"
|
2017-06-22 14:16:43 +08:00
|
|
|
#include "core/gimpimage-pick-item.h"
|
2003-02-13 19:23:50 +08:00
|
|
|
#include "core/gimpimage-undo.h"
|
2004-03-20 07:08:24 +08:00
|
|
|
#include "core/gimpimage-undo-push.h"
|
2016-05-20 22:46:26 +08:00
|
|
|
#include "core/gimplayer-floating-selection.h"
|
2009-06-23 05:47:04 +08:00
|
|
|
#include "core/gimpmarshal.h"
|
2001-11-21 07:00:47 +08:00
|
|
|
#include "core/gimptoolinfo.h"
|
2012-02-07 23:57:21 +08:00
|
|
|
#include "core/gimpundostack.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
|
2003-01-30 06:20:09 +08:00
|
|
|
#include "text/gimptext.h"
|
2003-07-24 21:10:27 +08:00
|
|
|
#include "text/gimptext-vectors.h"
|
2003-01-31 17:22:42 +08:00
|
|
|
#include "text/gimptextlayer.h"
|
2008-10-27 01:39:55 +08:00
|
|
|
#include "text/gimptextlayout.h"
|
2004-03-22 07:14:21 +08:00
|
|
|
#include "text/gimptextundo.h"
|
2003-01-30 06:20:09 +08:00
|
|
|
|
2018-09-06 07:37:58 +08:00
|
|
|
#include "vectors/gimpstroke.h"
|
|
|
|
#include "vectors/gimpvectors.h"
|
2007-03-09 19:10:40 +08:00
|
|
|
#include "vectors/gimpvectors-warp.h"
|
|
|
|
|
2003-06-27 22:26:04 +08:00
|
|
|
#include "widgets/gimpdialogfactory.h"
|
2016-11-25 20:26:08 +08:00
|
|
|
#include "widgets/gimpdockcontainer.h"
|
2003-08-22 09:42:57 +08:00
|
|
|
#include "widgets/gimphelp-ids.h"
|
2008-10-27 01:39:55 +08:00
|
|
|
#include "widgets/gimpmenufactory.h"
|
2010-02-26 00:41:10 +08:00
|
|
|
#include "widgets/gimptextbuffer.h"
|
2008-10-31 06:18:16 +08:00
|
|
|
#include "widgets/gimpuimanager.h"
|
2004-03-20 00:29:36 +08:00
|
|
|
#include "widgets/gimpviewabledialog.h"
|
2001-05-26 00:04:54 +08:00
|
|
|
|
2010-09-28 05:04:18 +08:00
|
|
|
#include "display/gimpcanvasgroup.h"
|
2001-09-26 07:23:09 +08:00
|
|
|
#include "display/gimpdisplay.h"
|
2008-10-27 01:39:55 +08:00
|
|
|
#include "display/gimpdisplayshell.h"
|
2017-06-28 21:40:38 +08:00
|
|
|
#include "display/gimptoolrectangle.h"
|
2001-09-26 07:23:09 +08:00
|
|
|
|
2003-02-05 22:39:40 +08:00
|
|
|
#include "gimptextoptions.h"
|
2001-03-08 09:07:03 +08:00
|
|
|
#include "gimptexttool.h"
|
2010-02-18 04:23:15 +08:00
|
|
|
#include "gimptexttool-editor.h"
|
2003-04-16 00:05:52 +08:00
|
|
|
#include "gimptoolcontrol.h"
|
2001-01-23 21:01:48 +08:00
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
Lots of ii8n stuff here and some additions to the de.po. Applied
Wed Oct 14 17:46:15 EDT 1998 Adrian Likins <adrian@gimp.org>
* app/*, po/de.po, de/POTFILES.in, libgimp/gimpintl.h:
Lots of ii8n stuff here and some additions to the de.po.
Applied gimp-egger-981005-1 ,gimp-egger-981006-1,
gimp-egger-981007-1, gimp-egger-981008-1,
gimp-egger-981009-1.patch, gimp-egger-981010-1.patch
* plug-in/guillotine/guillotine.c: added the coordinates
of the split images from the original image to the title.
ie foo.jpg (0,0) for the image in the topleft.
* plug-in/script-fu/scripts/neon-logo.scm,
perspective-shadow.scm, predator.scm,rendermap.scm,
ripply-anim.scm, select_to_image.scm,swirltile.scm,
xach-effect.scm: updated scripts to use new script-fu stuff
wooo boy! a big un!
in testing this, it looks like some of the po files are busted.
but the code stuff seems okay.
-adrian
1998-10-15 07:23:52 +08:00
|
|
|
|
2001-08-12 01:24:47 +08:00
|
|
|
|
2004-03-22 07:14:21 +08:00
|
|
|
#define TEXT_UNDO_TIMEOUT 3
|
|
|
|
|
|
|
|
|
2001-11-21 07:00:47 +08:00
|
|
|
/* local function prototypes */
|
|
|
|
|
2011-01-13 17:06:07 +08:00
|
|
|
static void gimp_text_tool_constructed (GObject *object);
|
2008-10-27 04:46:50 +08:00
|
|
|
static void gimp_text_tool_finalize (GObject *object);
|
|
|
|
|
|
|
|
static void gimp_text_tool_control (GimpTool *tool,
|
|
|
|
GimpToolAction action,
|
|
|
|
GimpDisplay *display);
|
|
|
|
static void gimp_text_tool_button_press (GimpTool *tool,
|
2008-11-01 23:17:36 +08:00
|
|
|
const GimpCoords *coords,
|
2008-10-27 04:46:50 +08:00
|
|
|
guint32 time,
|
|
|
|
GdkModifierType state,
|
2009-06-20 23:37:31 +08:00
|
|
|
GimpButtonPressType press_type,
|
2008-10-27 04:46:50 +08:00
|
|
|
GimpDisplay *display);
|
|
|
|
static void gimp_text_tool_button_release (GimpTool *tool,
|
2008-11-01 23:17:36 +08:00
|
|
|
const GimpCoords *coords,
|
2008-10-27 04:46:50 +08:00
|
|
|
guint32 time,
|
|
|
|
GdkModifierType state,
|
|
|
|
GimpButtonReleaseType release_type,
|
|
|
|
GimpDisplay *display);
|
|
|
|
static void gimp_text_tool_motion (GimpTool *tool,
|
2008-11-01 23:17:36 +08:00
|
|
|
const GimpCoords *coords,
|
2008-10-27 04:46:50 +08:00
|
|
|
guint32 time,
|
|
|
|
GdkModifierType state,
|
|
|
|
GimpDisplay *display);
|
|
|
|
static gboolean gimp_text_tool_key_press (GimpTool *tool,
|
|
|
|
GdkEventKey *kevent,
|
|
|
|
GimpDisplay *display);
|
2010-02-19 03:50:37 +08:00
|
|
|
static gboolean gimp_text_tool_key_release (GimpTool *tool,
|
|
|
|
GdkEventKey *kevent,
|
|
|
|
GimpDisplay *display);
|
2008-11-02 03:05:56 +08:00
|
|
|
static void gimp_text_tool_oper_update (GimpTool *tool,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
GdkModifierType state,
|
|
|
|
gboolean proximity,
|
|
|
|
GimpDisplay *display);
|
2008-10-27 04:46:50 +08:00
|
|
|
static void gimp_text_tool_cursor_update (GimpTool *tool,
|
2008-11-01 23:17:36 +08:00
|
|
|
const GimpCoords *coords,
|
2008-10-27 04:46:50 +08:00
|
|
|
GdkModifierType state,
|
|
|
|
GimpDisplay *display);
|
|
|
|
static GimpUIManager * gimp_text_tool_get_popup (GimpTool *tool,
|
2008-11-01 23:17:36 +08:00
|
|
|
const GimpCoords *coords,
|
2008-10-27 04:46:50 +08:00
|
|
|
GdkModifierType state,
|
|
|
|
GimpDisplay *display,
|
|
|
|
const gchar **ui_path);
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
static void gimp_text_tool_draw (GimpDrawTool *draw_tool);
|
2010-03-07 07:11:05 +08:00
|
|
|
static void gimp_text_tool_draw_selection (GimpDrawTool *draw_tool);
|
2008-10-28 00:21:03 +08:00
|
|
|
|
2018-05-29 22:19:50 +08:00
|
|
|
static gboolean gimp_text_tool_start (GimpTextTool *text_tool,
|
2017-06-28 21:40:38 +08:00
|
|
|
GimpDisplay *display,
|
2018-05-29 22:19:50 +08:00
|
|
|
GimpLayer *layer,
|
|
|
|
GError **error);
|
2017-06-28 21:40:38 +08:00
|
|
|
static void gimp_text_tool_halt (GimpTextTool *text_tool);
|
|
|
|
|
2010-02-18 03:23:58 +08:00
|
|
|
static void gimp_text_tool_frame_item (GimpTextTool *text_tool);
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
static void gimp_text_tool_rectangle_response
|
|
|
|
(GimpToolRectangle *rectangle,
|
|
|
|
gint response_id,
|
|
|
|
GimpTextTool *text_tool);
|
|
|
|
static void gimp_text_tool_rectangle_change_complete
|
|
|
|
(GimpToolRectangle *rectangle,
|
|
|
|
GimpTextTool *text_tool);
|
2008-10-28 00:21:03 +08:00
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
static void gimp_text_tool_connect (GimpTextTool *text_tool,
|
|
|
|
GimpTextLayer *layer,
|
|
|
|
GimpText *text);
|
2010-02-17 23:05:45 +08:00
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
static void gimp_text_tool_layer_notify (GimpTextLayer *layer,
|
2010-11-28 22:28:28 +08:00
|
|
|
const GParamSpec *pspec,
|
2008-10-27 04:46:50 +08:00
|
|
|
GimpTextTool *text_tool);
|
|
|
|
static void gimp_text_tool_proxy_notify (GimpText *text,
|
2010-11-28 22:28:28 +08:00
|
|
|
const GParamSpec *pspec,
|
2008-10-27 04:46:50 +08:00
|
|
|
GimpTextTool *text_tool);
|
2010-03-03 00:44:31 +08:00
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
static void gimp_text_tool_text_notify (GimpText *text,
|
2010-11-28 22:28:28 +08:00
|
|
|
const GParamSpec *pspec,
|
2008-10-27 04:46:50 +08:00
|
|
|
GimpTextTool *text_tool);
|
2010-03-03 00:44:31 +08:00
|
|
|
static void gimp_text_tool_text_changed (GimpText *text,
|
|
|
|
GimpTextTool *text_tool);
|
|
|
|
|
2018-05-29 22:19:50 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_fonts_async_set_empty_notify (GimpAsyncSet *async_set,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
GimpTextTool *text_tool);
|
|
|
|
|
2016-06-05 22:23:50 +08:00
|
|
|
static void gimp_text_tool_apply_list (GimpTextTool *text_tool,
|
|
|
|
GList *pspecs);
|
2004-03-15 01:54:23 +08:00
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
static void gimp_text_tool_create_layer (GimpTextTool *text_tool,
|
|
|
|
GimpText *text);
|
2004-03-15 01:54:23 +08:00
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
static void gimp_text_tool_layer_changed (GimpImage *image,
|
|
|
|
GimpTextTool *text_tool);
|
|
|
|
static void gimp_text_tool_set_image (GimpTextTool *text_tool,
|
|
|
|
GimpImage *image);
|
|
|
|
static gboolean gimp_text_tool_set_drawable (GimpTextTool *text_tool,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
gboolean confirm);
|
2004-03-19 04:55:00 +08:00
|
|
|
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
static void gimp_text_tool_block_drawing (GimpTextTool *text_tool);
|
|
|
|
static void gimp_text_tool_unblock_drawing (GimpTextTool *text_tool);
|
|
|
|
|
|
|
|
static void gimp_text_tool_buffer_begin_edit (GimpTextBuffer *buffer,
|
|
|
|
GimpTextTool *text_tool);
|
|
|
|
static void gimp_text_tool_buffer_end_edit (GimpTextBuffer *buffer,
|
2008-10-27 04:46:50 +08:00
|
|
|
GimpTextTool *text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2018-03-23 21:19:01 +08:00
|
|
|
static void gimp_text_tool_buffer_color_applied
|
|
|
|
(GimpTextBuffer *buffer,
|
|
|
|
const GimpRGB *color,
|
|
|
|
GimpTextTool *text_tool);
|
|
|
|
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
G_DEFINE_TYPE (GimpTextTool, gimp_text_tool, GIMP_TYPE_DRAW_TOOL)
|
2001-02-25 05:06:48 +08:00
|
|
|
|
2005-12-13 17:13:50 +08:00
|
|
|
#define parent_class gimp_text_tool_parent_class
|
1998-10-07 16:59:11 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-02-25 05:06:48 +08:00
|
|
|
void
|
2002-03-29 11:50:29 +08:00
|
|
|
gimp_text_tool_register (GimpToolRegisterCallback callback,
|
2002-05-03 19:31:08 +08:00
|
|
|
gpointer data)
|
2001-02-25 05:06:48 +08:00
|
|
|
{
|
2002-03-29 11:50:29 +08:00
|
|
|
(* callback) (GIMP_TYPE_TEXT_TOOL,
|
2003-02-05 22:39:40 +08:00
|
|
|
GIMP_TYPE_TEXT_OPTIONS,
|
|
|
|
gimp_text_options_gui,
|
2015-09-09 03:18:49 +08:00
|
|
|
GIMP_CONTEXT_PROP_MASK_FOREGROUND |
|
|
|
|
GIMP_CONTEXT_PROP_MASK_FONT |
|
|
|
|
GIMP_CONTEXT_PROP_MASK_PALETTE /* for the color popup's palette tab */,
|
2002-03-21 20:17:17 +08:00
|
|
|
"gimp-text-tool",
|
2002-11-01 07:06:09 +08:00
|
|
|
_("Text"),
|
2006-09-19 02:00:22 +08:00
|
|
|
_("Text Tool: Create or edit text layers"),
|
2004-04-29 21:19:28 +08:00
|
|
|
N_("Te_xt"), "T",
|
2003-08-22 09:42:57 +08:00
|
|
|
NULL, GIMP_HELP_TOOL_TEXT,
|
2017-03-05 23:01:59 +08:00
|
|
|
GIMP_ICON_TOOL_TEXT,
|
2002-05-03 19:31:08 +08:00
|
|
|
data);
|
2001-02-25 05:06:48 +08:00
|
|
|
}
|
|
|
|
|
1999-04-09 06:25:54 +08:00
|
|
|
static void
|
2001-02-25 05:06:48 +08:00
|
|
|
gimp_text_tool_class_init (GimpTextToolClass *klass)
|
1999-04-09 06:25:54 +08:00
|
|
|
{
|
2008-04-03 05:32:32 +08:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
|
|
|
|
GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
|
|
|
|
|
2011-01-13 17:06:07 +08:00
|
|
|
object_class->constructed = gimp_text_tool_constructed;
|
2009-06-22 05:37:18 +08:00
|
|
|
object_class->finalize = gimp_text_tool_finalize;
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2009-06-22 05:37:18 +08:00
|
|
|
tool_class->control = gimp_text_tool_control;
|
|
|
|
tool_class->button_press = gimp_text_tool_button_press;
|
|
|
|
tool_class->motion = gimp_text_tool_motion;
|
|
|
|
tool_class->button_release = gimp_text_tool_button_release;
|
|
|
|
tool_class->key_press = gimp_text_tool_key_press;
|
2010-02-19 03:50:37 +08:00
|
|
|
tool_class->key_release = gimp_text_tool_key_release;
|
2009-06-22 05:37:18 +08:00
|
|
|
tool_class->oper_update = gimp_text_tool_oper_update;
|
|
|
|
tool_class->cursor_update = gimp_text_tool_cursor_update;
|
|
|
|
tool_class->get_popup = gimp_text_tool_get_popup;
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2009-06-22 05:37:18 +08:00
|
|
|
draw_tool_class->draw = gimp_text_tool_draw;
|
2001-02-25 05:06:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_text_tool_init (GimpTextTool *text_tool)
|
|
|
|
{
|
2002-10-11 02:37:12 +08:00
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
2003-02-01 02:57:10 +08:00
|
|
|
|
2010-02-26 00:49:33 +08:00
|
|
|
text_tool->buffer = gimp_text_buffer_new ();
|
2008-10-27 01:39:55 +08:00
|
|
|
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
g_signal_connect (text_tool->buffer, "begin-user-action",
|
|
|
|
G_CALLBACK (gimp_text_tool_buffer_begin_edit),
|
|
|
|
text_tool);
|
2010-03-01 00:15:06 +08:00
|
|
|
g_signal_connect (text_tool->buffer, "end-user-action",
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
G_CALLBACK (gimp_text_tool_buffer_end_edit),
|
2008-10-27 01:39:55 +08:00
|
|
|
text_tool);
|
2018-03-23 21:19:01 +08:00
|
|
|
g_signal_connect (text_tool->buffer, "color-applied",
|
|
|
|
G_CALLBACK (gimp_text_tool_buffer_color_applied),
|
|
|
|
text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-18 18:47:16 +08:00
|
|
|
text_tool->handle_rectangle_change_complete = TRUE;
|
|
|
|
|
2010-02-18 04:23:15 +08:00
|
|
|
gimp_text_tool_editor_init (text_tool);
|
2003-02-01 02:57:10 +08:00
|
|
|
|
2008-10-27 01:39:55 +08:00
|
|
|
gimp_tool_control_set_scroll_lock (tool->control, TRUE);
|
2012-11-07 05:22:02 +08:00
|
|
|
gimp_tool_control_set_handle_empty_image (tool->control, TRUE);
|
2010-03-07 07:53:32 +08:00
|
|
|
gimp_tool_control_set_wants_click (tool->control, TRUE);
|
2009-06-21 22:20:16 +08:00
|
|
|
gimp_tool_control_set_wants_double_click (tool->control, TRUE);
|
|
|
|
gimp_tool_control_set_wants_triple_click (tool->control, TRUE);
|
2008-10-27 01:39:55 +08:00
|
|
|
gimp_tool_control_set_wants_all_key_events (tool->control, TRUE);
|
2017-10-29 23:38:24 +08:00
|
|
|
gimp_tool_control_set_active_modifiers (tool->control,
|
|
|
|
GIMP_TOOL_ACTIVE_MODIFIERS_SEPARATE);
|
2009-02-21 00:57:26 +08:00
|
|
|
gimp_tool_control_set_precision (tool->control,
|
|
|
|
GIMP_CURSOR_PRECISION_PIXEL_BORDER);
|
2008-10-27 01:39:55 +08:00
|
|
|
gimp_tool_control_set_tool_cursor (tool->control,
|
|
|
|
GIMP_TOOL_CURSOR_TEXT);
|
|
|
|
gimp_tool_control_set_action_object_1 (tool->control,
|
|
|
|
"context/context-font-select-set");
|
2001-02-25 05:06:48 +08:00
|
|
|
}
|
|
|
|
|
2011-01-13 17:06:07 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_constructed (GObject *object)
|
2004-03-15 01:54:23 +08:00
|
|
|
{
|
2011-01-13 17:06:07 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (object);
|
|
|
|
GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
|
2018-05-29 22:19:50 +08:00
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
2018-06-03 05:19:51 +08:00
|
|
|
GimpAsyncSet *async_set;
|
2004-03-15 01:54:23 +08:00
|
|
|
|
2012-11-13 04:51:22 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
2004-03-15 01:54:23 +08:00
|
|
|
|
|
|
|
text_tool->proxy = g_object_new (GIMP_TYPE_TEXT, NULL);
|
|
|
|
|
|
|
|
gimp_text_options_connect_text (options, text_tool->proxy);
|
|
|
|
|
2004-03-15 02:48:00 +08:00
|
|
|
g_signal_connect_object (text_tool->proxy, "notify",
|
2004-03-20 21:26:02 +08:00
|
|
|
G_CALLBACK (gimp_text_tool_proxy_notify),
|
|
|
|
text_tool, 0);
|
2018-05-29 22:19:50 +08:00
|
|
|
|
2018-06-03 05:19:51 +08:00
|
|
|
async_set =
|
|
|
|
gimp_data_factory_get_async_set (tool->tool_info->gimp->font_factory);
|
|
|
|
|
|
|
|
g_signal_connect_object (async_set,
|
2018-05-29 22:19:50 +08:00
|
|
|
"notify::empty",
|
|
|
|
G_CALLBACK (gimp_text_tool_fonts_async_set_empty_notify),
|
|
|
|
text_tool, 0);
|
2004-03-15 01:54:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_text_tool_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (object);
|
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&text_tool->proxy);
|
|
|
|
g_clear_object (&text_tool->buffer);
|
2020-05-19 22:05:17 +08:00
|
|
|
g_clear_object (&text_tool->ui_manager);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-18 04:23:15 +08:00
|
|
|
gimp_text_tool_editor_finalize (text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2004-03-15 01:54:23 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2016-06-27 22:48:19 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_remove_empty_text_layer (GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
GimpTextLayer *text_layer = text_tool->layer;
|
|
|
|
|
|
|
|
if (text_layer && text_layer->auto_rename)
|
|
|
|
{
|
|
|
|
GimpText *text = gimp_text_layer_get_text (text_layer);
|
|
|
|
|
2016-11-22 03:42:56 +08:00
|
|
|
if (text && text->box_mode == GIMP_TEXT_BOX_DYNAMIC &&
|
2016-06-27 22:48:19 +08:00
|
|
|
(! text->text || text->text[0] == '\0') &&
|
|
|
|
(! text->markup || text->markup[0] == '\0'))
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (text_layer));
|
|
|
|
|
|
|
|
if (text_tool->image == image)
|
|
|
|
g_signal_handlers_block_by_func (image,
|
|
|
|
gimp_text_tool_layer_changed,
|
|
|
|
text_tool);
|
|
|
|
|
|
|
|
gimp_image_remove_layer (image, GIMP_LAYER (text_layer), TRUE, NULL);
|
|
|
|
gimp_image_flush (image);
|
|
|
|
|
|
|
|
if (text_tool->image == image)
|
|
|
|
g_signal_handlers_unblock_by_func (image,
|
|
|
|
gimp_text_tool_layer_changed,
|
|
|
|
text_tool);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static void
|
2003-03-11 09:22:57 +08:00
|
|
|
gimp_text_tool_control (GimpTool *tool,
|
2006-04-12 20:49:29 +08:00
|
|
|
GimpToolAction action,
|
|
|
|
GimpDisplay *display)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2004-02-05 00:52:35 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
2004-01-20 01:21:53 +08:00
|
|
|
|
2001-02-25 05:06:48 +08:00
|
|
|
switch (action)
|
|
|
|
{
|
2006-05-22 05:12:01 +08:00
|
|
|
case GIMP_TOOL_ACTION_PAUSE:
|
|
|
|
case GIMP_TOOL_ACTION_RESUME:
|
2001-02-25 05:06:48 +08:00
|
|
|
break;
|
|
|
|
|
2006-05-22 05:12:01 +08:00
|
|
|
case GIMP_TOOL_ACTION_HALT:
|
2017-06-28 21:40:38 +08:00
|
|
|
gimp_text_tool_halt (text_tool);
|
2001-02-25 05:06:48 +08:00
|
|
|
break;
|
2014-04-05 04:34:26 +08:00
|
|
|
|
|
|
|
case GIMP_TOOL_ACTION_COMMIT:
|
|
|
|
break;
|
2001-02-25 05:06:48 +08:00
|
|
|
}
|
2001-11-21 07:00:47 +08:00
|
|
|
|
2006-03-29 01:55:52 +08:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->control (tool, action, display);
|
2001-02-25 05:06:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-06-20 23:37:31 +08:00
|
|
|
gimp_text_tool_button_press (GimpTool *tool,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
guint32 time,
|
|
|
|
GdkModifierType state,
|
|
|
|
GimpButtonPressType press_type,
|
|
|
|
GimpDisplay *display)
|
2001-02-25 05:06:48 +08:00
|
|
|
{
|
2008-10-27 04:46:50 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
2010-02-18 16:12:26 +08:00
|
|
|
GimpImage *image = gimp_display_get_image (display);
|
2008-10-27 04:46:50 +08:00
|
|
|
GimpText *text = text_tool->text;
|
2017-06-28 21:40:38 +08:00
|
|
|
GimpToolRectangle *rectangle;
|
2008-04-03 05:32:32 +08:00
|
|
|
|
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
2001-02-25 05:06:48 +08:00
|
|
|
|
2010-02-21 08:39:38 +08:00
|
|
|
if (tool->display && tool->display != display)
|
2011-04-03 06:40:41 +08:00
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
|
2010-02-21 08:39:38 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
if (! text_tool->widget)
|
|
|
|
{
|
2018-05-29 22:19:50 +08:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (! gimp_text_tool_start (text_tool, display, NULL, &error))
|
|
|
|
{
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
|
|
|
|
|
|
|
gimp_tool_message_literal (tool, display, error->message);
|
|
|
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2017-06-28 21:40:38 +08:00
|
|
|
|
|
|
|
gimp_tool_widget_hover (text_tool->widget, coords, state, TRUE);
|
|
|
|
|
|
|
|
/* HACK: force CREATING on a newly created rectangle; otherwise,
|
|
|
|
* the above binding of properties would cause the rectangle to
|
|
|
|
* start with the size from tool options.
|
|
|
|
*/
|
|
|
|
gimp_tool_rectangle_set_function (GIMP_TOOL_RECTANGLE (text_tool->widget),
|
|
|
|
GIMP_TOOL_RECTANGLE_CREATING);
|
|
|
|
}
|
|
|
|
|
|
|
|
rectangle = GIMP_TOOL_RECTANGLE (text_tool->widget);
|
|
|
|
|
2009-06-21 22:20:16 +08:00
|
|
|
if (press_type == GIMP_BUTTON_PRESS_NORMAL)
|
|
|
|
{
|
2011-03-31 04:13:31 +08:00
|
|
|
gimp_tool_control_activate (tool->control);
|
|
|
|
|
2016-06-05 22:23:50 +08:00
|
|
|
/* clicking anywhere while a preedit is going on aborts the
|
|
|
|
* preedit, this is ugly but at least leaves everything in
|
|
|
|
* a consistent state
|
|
|
|
*/
|
|
|
|
if (text_tool->preedit_active)
|
|
|
|
gimp_text_tool_abort_im_context (text_tool);
|
|
|
|
else
|
|
|
|
gimp_text_tool_reset_im_context (text_tool);
|
2010-02-19 23:05:48 +08:00
|
|
|
|
2009-06-21 22:20:16 +08:00
|
|
|
text_tool->selecting = FALSE;
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
if (gimp_tool_rectangle_point_in_rectangle (rectangle,
|
2010-02-17 05:44:38 +08:00
|
|
|
coords->x,
|
|
|
|
coords->y) &&
|
2009-06-21 22:20:16 +08:00
|
|
|
! text_tool->moving)
|
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
gimp_tool_rectangle_set_function (rectangle,
|
|
|
|
GIMP_TOOL_RECTANGLE_DEAD);
|
2009-06-21 22:20:16 +08:00
|
|
|
}
|
2017-06-28 21:40:38 +08:00
|
|
|
else if (gimp_tool_widget_button_press (text_tool->widget, coords,
|
|
|
|
time, state, press_type))
|
2009-06-21 22:20:16 +08:00
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
text_tool->grab_widget = text_tool->widget;
|
2009-06-21 22:20:16 +08:00
|
|
|
}
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2010-02-19 02:44:52 +08:00
|
|
|
/* bail out now if the user user clicked on a handle of an
|
2010-03-07 19:39:50 +08:00
|
|
|
* existing rectangle, but not inside an existing framed layer
|
2009-06-21 22:20:16 +08:00
|
|
|
*/
|
2017-06-28 21:40:38 +08:00
|
|
|
if (gimp_tool_rectangle_get_function (rectangle) !=
|
|
|
|
GIMP_TOOL_RECTANGLE_CREATING)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2010-03-07 19:39:50 +08:00
|
|
|
if (text_tool->layer)
|
|
|
|
{
|
|
|
|
GimpItem *item = GIMP_ITEM (text_tool->layer);
|
|
|
|
gdouble x = coords->x - gimp_item_get_offset_x (item);
|
|
|
|
gdouble y = coords->y - gimp_item_get_offset_y (item);
|
|
|
|
|
|
|
|
if (x < 0 || x >= gimp_item_get_width (item) ||
|
|
|
|
y < 0 || y >= gimp_item_get_height (item))
|
|
|
|
{
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2009-06-21 22:20:16 +08:00
|
|
|
{
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
|
|
|
return;
|
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
2010-03-07 19:39:50 +08:00
|
|
|
|
|
|
|
/* if the the click is not related to the currently edited text
|
|
|
|
* layer in any way, try to pick a text layer
|
|
|
|
*/
|
|
|
|
if (! text_tool->moving &&
|
2017-06-28 21:40:38 +08:00
|
|
|
gimp_tool_rectangle_get_function (rectangle) ==
|
|
|
|
GIMP_TOOL_RECTANGLE_CREATING)
|
2010-03-07 19:39:50 +08:00
|
|
|
{
|
|
|
|
GimpTextLayer *text_layer;
|
|
|
|
|
|
|
|
text_layer = gimp_image_pick_text_layer (image, coords->x, coords->y);
|
|
|
|
|
|
|
|
if (text_layer && text_layer != text_tool->layer)
|
|
|
|
{
|
2020-04-04 08:49:51 +08:00
|
|
|
GList *selection = g_list_prepend (NULL, text_layer);
|
|
|
|
|
2010-03-07 19:39:50 +08:00
|
|
|
if (text_tool->image == image)
|
|
|
|
g_signal_handlers_block_by_func (image,
|
|
|
|
gimp_text_tool_layer_changed,
|
|
|
|
text_tool);
|
|
|
|
|
2020-04-04 08:49:51 +08:00
|
|
|
gimp_image_set_selected_layers (image, selection);
|
|
|
|
g_list_free (selection);
|
2010-03-07 19:39:50 +08:00
|
|
|
|
|
|
|
if (text_tool->image == image)
|
|
|
|
g_signal_handlers_unblock_by_func (image,
|
|
|
|
gimp_text_tool_layer_changed,
|
|
|
|
text_tool);
|
|
|
|
}
|
|
|
|
}
|
2008-04-03 05:32:32 +08:00
|
|
|
}
|
|
|
|
|
2019-09-04 23:10:24 +08:00
|
|
|
if (gimp_image_coords_in_active_pickable (image, coords, FALSE, FALSE, FALSE))
|
2004-03-19 04:55:00 +08:00
|
|
|
{
|
2020-05-18 06:49:21 +08:00
|
|
|
GList *drawables = gimp_image_get_selected_drawables (image);
|
|
|
|
GimpDrawable *drawable = NULL;
|
|
|
|
gdouble x = coords->x;
|
|
|
|
gdouble y = coords->y;
|
|
|
|
|
|
|
|
if (g_list_length (drawables) == 1)
|
|
|
|
{
|
|
|
|
GimpItem *item = GIMP_ITEM (drawables->data);
|
|
|
|
|
|
|
|
x = coords->x - gimp_item_get_offset_x (item);
|
|
|
|
y = coords->y - gimp_item_get_offset_y (item);
|
|
|
|
|
|
|
|
drawable = drawables->data;
|
|
|
|
}
|
|
|
|
g_list_free (drawables);
|
2003-02-01 02:57:10 +08:00
|
|
|
|
2010-02-18 16:12:26 +08:00
|
|
|
/* did the user click on a text layer? */
|
2020-05-18 06:49:21 +08:00
|
|
|
if (drawable &&
|
|
|
|
gimp_text_tool_set_drawable (text_tool, drawable, TRUE))
|
2004-03-20 00:29:36 +08:00
|
|
|
{
|
2010-02-19 02:44:52 +08:00
|
|
|
if (press_type == GIMP_BUTTON_PRESS_NORMAL)
|
2004-03-20 00:29:36 +08:00
|
|
|
{
|
2010-02-19 02:44:52 +08:00
|
|
|
/* if we clicked on a text layer while the tool was idle
|
|
|
|
* (didn't show a rectangle), frame the layer and switch to
|
|
|
|
* selecting instead of drawing a new rectangle
|
|
|
|
*/
|
2017-06-28 21:40:38 +08:00
|
|
|
if (gimp_tool_rectangle_get_function (rectangle) ==
|
|
|
|
GIMP_TOOL_RECTANGLE_CREATING)
|
2010-02-19 02:44:52 +08:00
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
gimp_tool_rectangle_set_function (rectangle,
|
|
|
|
GIMP_TOOL_RECTANGLE_DEAD);
|
2010-02-18 03:23:58 +08:00
|
|
|
|
2010-02-19 02:44:52 +08:00
|
|
|
gimp_text_tool_frame_item (text_tool);
|
|
|
|
}
|
2010-02-17 05:44:38 +08:00
|
|
|
|
2010-02-18 16:12:26 +08:00
|
|
|
if (text_tool->text && text_tool->text != text)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2010-02-18 16:12:26 +08:00
|
|
|
gimp_text_tool_editor_start (text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
2010-02-18 16:12:26 +08:00
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-26 08:57:51 +08:00
|
|
|
if (text_tool->text && ! text_tool->moving)
|
2010-02-18 16:12:26 +08:00
|
|
|
{
|
2010-02-24 06:46:09 +08:00
|
|
|
text_tool->selecting = TRUE;
|
|
|
|
|
2010-02-21 06:19:10 +08:00
|
|
|
gimp_text_tool_editor_button_press (text_tool, x, y, press_type);
|
2010-02-18 16:12:26 +08:00
|
|
|
}
|
2010-02-21 19:04:19 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
text_tool->selecting = FALSE;
|
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-18 16:12:26 +08:00
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
2008-10-27 04:46:50 +08:00
|
|
|
|
2010-02-18 16:12:26 +08:00
|
|
|
return;
|
2004-03-20 00:29:36 +08:00
|
|
|
}
|
2004-03-13 08:47:31 +08:00
|
|
|
}
|
2004-03-20 00:29:36 +08:00
|
|
|
|
2010-02-19 17:53:46 +08:00
|
|
|
if (press_type == GIMP_BUTTON_PRESS_NORMAL)
|
|
|
|
{
|
|
|
|
/* create a new text layer */
|
|
|
|
text_tool->text_box_fixed = FALSE;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2018-05-02 05:00:28 +08:00
|
|
|
/* make sure the text tool has an image, even if the user didn't click
|
|
|
|
* inside the active drawable, in particular, so that the text style
|
|
|
|
* editor picks the correct resolution.
|
|
|
|
*/
|
|
|
|
gimp_text_tool_set_image (text_tool, image);
|
|
|
|
|
2010-02-19 17:53:46 +08:00
|
|
|
gimp_text_tool_connect (text_tool, NULL, NULL);
|
|
|
|
gimp_text_tool_editor_start (text_tool);
|
|
|
|
}
|
2009-06-21 22:20:16 +08:00
|
|
|
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
2003-03-11 09:22:57 +08:00
|
|
|
}
|
|
|
|
|
2008-04-03 05:32:32 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_button_release (GimpTool *tool,
|
2008-11-01 23:17:36 +08:00
|
|
|
const GimpCoords *coords,
|
2008-04-03 05:32:32 +08:00
|
|
|
guint32 time,
|
|
|
|
GdkModifierType state,
|
|
|
|
GimpButtonReleaseType release_type,
|
|
|
|
GimpDisplay *display)
|
|
|
|
{
|
2008-10-27 04:05:11 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
2017-06-28 21:40:38 +08:00
|
|
|
GimpToolRectangle *rectangle = GIMP_TOOL_RECTANGLE (text_tool->widget);
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2011-03-31 04:13:31 +08:00
|
|
|
gimp_tool_control_halt (tool->control);
|
|
|
|
|
2009-06-28 03:31:06 +08:00
|
|
|
if (text_tool->selecting)
|
|
|
|
{
|
2010-02-24 07:03:15 +08:00
|
|
|
/* we are in a selection process (user has initially clicked on
|
|
|
|
* an existing text layer), so finish the selection process and
|
|
|
|
* ignore rectangle-change-complete.
|
2010-02-19 17:50:07 +08:00
|
|
|
*/
|
2010-03-02 20:04:37 +08:00
|
|
|
|
|
|
|
/* need to block "end-user-action" on the text buffer, because
|
|
|
|
* GtkTextBuffer considers copying text to the clipboard an
|
|
|
|
* undo-relevant user action, which is clearly a bug, but what
|
|
|
|
* can we do...
|
|
|
|
*/
|
|
|
|
g_signal_handlers_block_by_func (text_tool->buffer,
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_buffer_begin_edit,
|
|
|
|
text_tool);
|
|
|
|
g_signal_handlers_block_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_end_edit,
|
2010-03-02 20:04:37 +08:00
|
|
|
text_tool);
|
|
|
|
|
2010-02-21 06:19:10 +08:00
|
|
|
gimp_text_tool_editor_button_release (text_tool);
|
2008-10-27 04:46:50 +08:00
|
|
|
|
2010-03-02 20:04:37 +08:00
|
|
|
g_signal_handlers_unblock_by_func (text_tool->buffer,
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_buffer_end_edit,
|
|
|
|
text_tool);
|
|
|
|
g_signal_handlers_unblock_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_begin_edit,
|
2010-03-02 20:04:37 +08:00
|
|
|
text_tool);
|
|
|
|
|
2009-06-28 03:31:06 +08:00
|
|
|
text_tool->selecting = FALSE;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-19 17:50:07 +08:00
|
|
|
text_tool->handle_rectangle_change_complete = FALSE;
|
2010-03-07 07:53:32 +08:00
|
|
|
|
|
|
|
/* there is no cancelling of selections yet */
|
|
|
|
if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
|
|
|
|
release_type = GIMP_BUTTON_RELEASE_NORMAL;
|
2008-04-03 05:32:32 +08:00
|
|
|
}
|
2014-11-29 06:57:06 +08:00
|
|
|
else if (text_tool->moving)
|
|
|
|
{
|
|
|
|
/* the user has moved the text layer with Alt-drag, fall
|
|
|
|
* through and let rectangle-change-complete do its job of
|
|
|
|
* setting text layer's new position.
|
|
|
|
*/
|
|
|
|
}
|
2017-06-28 21:40:38 +08:00
|
|
|
else if (gimp_tool_rectangle_get_function (rectangle) ==
|
|
|
|
GIMP_TOOL_RECTANGLE_DEAD)
|
2008-04-03 05:32:32 +08:00
|
|
|
{
|
2010-02-24 07:03:15 +08:00
|
|
|
/* the user clicked in dead space (like between the corner and
|
2010-03-07 07:53:32 +08:00
|
|
|
* edge handles, so completely ignore that.
|
|
|
|
*/
|
|
|
|
|
|
|
|
text_tool->handle_rectangle_change_complete = FALSE;
|
|
|
|
}
|
|
|
|
else if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
|
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
/* user has canceled the rectangle resizing, fall through
|
|
|
|
* and let the rectangle handle restoring the previous size
|
2010-02-19 17:50:07 +08:00
|
|
|
*/
|
2008-04-03 05:32:32 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
gdouble x1, y1;
|
|
|
|
gdouble x2, y2;
|
2010-02-19 17:50:07 +08:00
|
|
|
|
2010-02-24 07:03:15 +08:00
|
|
|
/* otherwise the user has clicked outside of any text layer in
|
|
|
|
* order to create a new text, fall through and let
|
|
|
|
* rectangle-change-complete do its job of setting the new text
|
|
|
|
* layer's size.
|
2010-02-19 17:50:07 +08:00
|
|
|
*/
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
g_object_get (rectangle,
|
2010-02-19 17:50:07 +08:00
|
|
|
"x1", &x1,
|
|
|
|
"y1", &y1,
|
|
|
|
"x2", &x2,
|
|
|
|
"y2", &y2,
|
|
|
|
NULL);
|
|
|
|
|
2010-03-07 07:53:32 +08:00
|
|
|
if (release_type == GIMP_BUTTON_RELEASE_CLICK ||
|
|
|
|
(x2 - x1) < 3 ||
|
|
|
|
(y2 - y1) < 3)
|
2010-02-19 17:50:07 +08:00
|
|
|
{
|
|
|
|
/* unless the rectangle is unreasonably small to hold any
|
|
|
|
* real text (the user has eitherjust clicked or just made
|
|
|
|
* a rectangle of a few pixels), so set the text box to
|
|
|
|
* dynamic and ignore rectangle-change-complete.
|
|
|
|
*/
|
|
|
|
|
|
|
|
g_object_set (text_tool->proxy,
|
|
|
|
"box-mode", GIMP_TEXT_BOX_DYNAMIC,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
text_tool->handle_rectangle_change_complete = FALSE;
|
|
|
|
}
|
2008-04-03 05:32:32 +08:00
|
|
|
}
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
if (text_tool->grab_widget)
|
|
|
|
{
|
|
|
|
gimp_tool_widget_button_release (text_tool->grab_widget,
|
|
|
|
coords, time, state, release_type);
|
|
|
|
text_tool->grab_widget = NULL;
|
|
|
|
}
|
2008-11-02 03:05:56 +08:00
|
|
|
|
2008-05-02 17:05:13 +08:00
|
|
|
text_tool->handle_rectangle_change_complete = TRUE;
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
2010-02-21 06:19:10 +08:00
|
|
|
static void
|
2008-11-01 23:17:36 +08:00
|
|
|
gimp_text_tool_motion (GimpTool *tool,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
guint32 time,
|
|
|
|
GdkModifierType state,
|
|
|
|
GimpDisplay *display)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
|
|
|
|
2010-02-18 18:34:08 +08:00
|
|
|
if (! text_tool->selecting)
|
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
if (text_tool->grab_widget)
|
|
|
|
{
|
|
|
|
gimp_tool_widget_motion (text_tool->grab_widget,
|
|
|
|
coords, time, state);
|
|
|
|
}
|
2010-02-18 18:34:08 +08:00
|
|
|
}
|
2010-02-24 06:14:09 +08:00
|
|
|
else
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2010-02-21 06:19:10 +08:00
|
|
|
GimpItem *item = GIMP_ITEM (text_tool->layer);
|
|
|
|
gdouble x = coords->x - gimp_item_get_offset_x (item);
|
|
|
|
gdouble y = coords->y - gimp_item_get_offset_y (item);
|
2008-10-27 04:46:50 +08:00
|
|
|
|
2010-02-21 06:19:10 +08:00
|
|
|
gimp_text_tool_editor_motion (text_tool, x, y);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_text_tool_key_press (GimpTool *tool,
|
|
|
|
GdkEventKey *kevent,
|
|
|
|
GimpDisplay *display)
|
|
|
|
{
|
2010-02-18 04:39:33 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-18 04:39:33 +08:00
|
|
|
if (display == tool->display)
|
2010-02-21 06:19:10 +08:00
|
|
|
return gimp_text_tool_editor_key_press (text_tool, kevent);
|
2008-10-31 07:13:24 +08:00
|
|
|
|
2010-02-18 04:39:33 +08:00
|
|
|
return FALSE;
|
2008-04-03 05:32:32 +08:00
|
|
|
}
|
|
|
|
|
2010-02-19 03:50:37 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_text_tool_key_release (GimpTool *tool,
|
|
|
|
GdkEventKey *kevent,
|
|
|
|
GimpDisplay *display)
|
|
|
|
{
|
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
|
|
|
|
|
|
|
if (display == tool->display)
|
2010-02-21 06:19:10 +08:00
|
|
|
return gimp_text_tool_editor_key_release (text_tool, kevent);
|
2010-02-19 03:50:37 +08:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-06-22 05:37:18 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_oper_update (GimpTool *tool,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
GdkModifierType state,
|
|
|
|
gboolean proximity,
|
|
|
|
GimpDisplay *display)
|
|
|
|
{
|
2017-06-29 01:39:52 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
|
|
|
GimpToolRectangle *rectangle = GIMP_TOOL_RECTANGLE (text_tool->widget);
|
2009-06-22 05:37:18 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
|
|
|
|
proximity, display);
|
2009-06-22 05:37:18 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
text_tool->moving = (text_tool->widget &&
|
2017-06-29 01:39:52 +08:00
|
|
|
gimp_tool_rectangle_get_function (rectangle) ==
|
2017-06-28 21:40:38 +08:00
|
|
|
GIMP_TOOL_RECTANGLE_MOVING &&
|
2009-06-22 05:37:18 +08:00
|
|
|
(state & GDK_MOD1_MASK));
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static void
|
2008-11-01 23:17:36 +08:00
|
|
|
gimp_text_tool_cursor_update (GimpTool *tool,
|
|
|
|
const GimpCoords *coords,
|
|
|
|
GdkModifierType state,
|
|
|
|
GimpDisplay *display)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2017-06-29 01:39:52 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
|
|
|
GimpToolRectangle *rectangle = GIMP_TOOL_RECTANGLE (text_tool->widget);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2017-06-29 01:39:52 +08:00
|
|
|
if (rectangle && tool->display == display)
|
2017-06-28 21:40:38 +08:00
|
|
|
{
|
2017-06-29 01:39:52 +08:00
|
|
|
if (gimp_tool_rectangle_point_in_rectangle (rectangle,
|
2010-02-17 05:44:38 +08:00
|
|
|
coords->x,
|
|
|
|
coords->y) &&
|
2008-11-02 03:05:56 +08:00
|
|
|
! text_tool->moving)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
gimp_tool_set_cursor (tool, display,
|
|
|
|
(GimpCursorType) GDK_XTERM,
|
|
|
|
gimp_tool_control_get_tool_cursor (tool->control),
|
|
|
|
GIMP_CURSOR_MODIFIER_NONE);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state,
|
|
|
|
display);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
}
|
2010-02-17 05:44:38 +08:00
|
|
|
else
|
|
|
|
{
|
2018-06-03 05:19:51 +08:00
|
|
|
GimpAsyncSet *async_set;
|
|
|
|
|
|
|
|
async_set =
|
|
|
|
gimp_data_factory_get_async_set (tool->tool_info->gimp->font_factory);
|
|
|
|
|
|
|
|
if (gimp_async_set_is_empty (async_set))
|
2018-05-29 22:19:50 +08:00
|
|
|
{
|
|
|
|
GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state,
|
|
|
|
display);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_tool_set_cursor (tool, display,
|
|
|
|
gimp_tool_control_get_cursor (tool->control),
|
|
|
|
gimp_tool_control_get_tool_cursor (tool->control),
|
|
|
|
GIMP_CURSOR_MODIFIER_BAD);
|
|
|
|
}
|
2010-02-17 05:44:38 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2008-10-27 01:39:55 +08:00
|
|
|
static GimpUIManager *
|
|
|
|
gimp_text_tool_get_popup (GimpTool *tool,
|
2008-11-01 23:17:36 +08:00
|
|
|
const GimpCoords *coords,
|
2008-10-27 01:39:55 +08:00
|
|
|
GdkModifierType state,
|
|
|
|
GimpDisplay *display,
|
|
|
|
const gchar **ui_path)
|
|
|
|
{
|
2017-06-29 01:39:52 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (tool);
|
|
|
|
GimpToolRectangle *rectangle = GIMP_TOOL_RECTANGLE (text_tool->widget);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2017-06-29 01:39:52 +08:00
|
|
|
if (rectangle &&
|
|
|
|
gimp_tool_rectangle_point_in_rectangle (rectangle,
|
2010-02-18 16:12:26 +08:00
|
|
|
coords->x,
|
|
|
|
coords->y))
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2008-10-31 06:18:16 +08:00
|
|
|
if (! text_tool->ui_manager)
|
|
|
|
{
|
2016-11-25 20:26:08 +08:00
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
|
|
|
|
GimpImageWindow *image_window;
|
2008-10-31 06:18:16 +08:00
|
|
|
GimpDialogFactory *dialog_factory;
|
|
|
|
GtkWidget *im_menu;
|
2010-02-20 23:18:41 +08:00
|
|
|
GList *children;
|
2008-10-31 06:18:16 +08:00
|
|
|
|
2016-11-25 20:26:08 +08:00
|
|
|
image_window = gimp_display_shell_get_window (shell);
|
|
|
|
dialog_factory = gimp_dock_container_get_dialog_factory (GIMP_DOCK_CONTAINER (image_window));
|
2008-10-31 06:18:16 +08:00
|
|
|
|
|
|
|
text_tool->ui_manager =
|
2009-12-21 03:19:31 +08:00
|
|
|
gimp_menu_factory_manager_new (gimp_dialog_factory_get_menu_factory (dialog_factory),
|
2008-10-31 06:18:16 +08:00
|
|
|
"<TextTool>",
|
2018-05-14 06:34:16 +08:00
|
|
|
text_tool);
|
2008-10-31 06:18:16 +08:00
|
|
|
|
2019-07-02 09:54:38 +08:00
|
|
|
im_menu = gimp_ui_manager_get_widget (text_tool->ui_manager,
|
|
|
|
"/text-tool-popup/text-tool-input-methods-menu");
|
2008-10-31 06:18:16 +08:00
|
|
|
|
|
|
|
if (GTK_IS_MENU_ITEM (im_menu))
|
|
|
|
im_menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (im_menu));
|
|
|
|
|
2010-02-20 23:18:41 +08:00
|
|
|
/* hide the generated "empty" item */
|
|
|
|
children = gtk_container_get_children (GTK_CONTAINER (im_menu));
|
|
|
|
while (children)
|
|
|
|
{
|
|
|
|
gtk_widget_hide (children->data);
|
|
|
|
children = g_list_remove (children, children->data);
|
|
|
|
}
|
|
|
|
|
2008-10-31 06:18:16 +08:00
|
|
|
gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_tool->im_context),
|
|
|
|
GTK_MENU_SHELL (im_menu));
|
|
|
|
}
|
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
gimp_ui_manager_update (text_tool->ui_manager, text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
*ui_path = "/text-tool-popup";
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
return text_tool->ui_manager;
|
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-27 04:46:50 +08:00
|
|
|
return NULL;
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
2004-03-15 02:48:00 +08:00
|
|
|
static void
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_text_tool_draw (GimpDrawTool *draw_tool)
|
2004-03-15 02:48:00 +08:00
|
|
|
{
|
2010-03-07 07:11:05 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (draw_tool);
|
2004-03-15 02:48:00 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
GIMP_DRAW_TOOL_CLASS (parent_class)->draw (draw_tool);
|
2004-03-15 02:48:00 +08:00
|
|
|
|
2010-02-17 18:57:32 +08:00
|
|
|
if (! text_tool->text ||
|
|
|
|
! text_tool->layer ||
|
2008-10-28 00:21:03 +08:00
|
|
|
! text_tool->layer->text)
|
2014-10-01 06:26:48 +08:00
|
|
|
{
|
2016-04-16 21:12:42 +08:00
|
|
|
gimp_text_tool_editor_update_im_cursor (text_tool);
|
2014-10-01 06:26:48 +08:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2004-03-15 02:48:00 +08:00
|
|
|
|
2010-03-08 00:34:49 +08:00
|
|
|
gimp_text_tool_ensure_layout (text_tool);
|
|
|
|
|
2010-03-07 07:11:05 +08:00
|
|
|
if (gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (text_tool->buffer)))
|
2010-02-18 16:27:08 +08:00
|
|
|
{
|
|
|
|
/* If the text buffer has a selection, highlight the selected letters */
|
|
|
|
|
2010-03-07 07:11:05 +08:00
|
|
|
gimp_text_tool_draw_selection (draw_tool);
|
2010-02-18 16:27:08 +08:00
|
|
|
}
|
|
|
|
else
|
2008-10-28 00:21:03 +08:00
|
|
|
{
|
|
|
|
/* If the text buffer has no selection, draw the text cursor */
|
2004-03-15 02:48:00 +08:00
|
|
|
|
2018-07-29 12:57:38 +08:00
|
|
|
GimpCanvasItem *item;
|
|
|
|
PangoRectangle cursor_rect;
|
|
|
|
gint off_x, off_y;
|
|
|
|
gboolean overwrite;
|
|
|
|
GimpTextDirection direction;
|
2010-03-07 07:11:05 +08:00
|
|
|
|
2010-10-14 08:45:32 +08:00
|
|
|
gimp_text_tool_editor_get_cursor_rect (text_tool,
|
|
|
|
text_tool->overwrite_mode,
|
|
|
|
&cursor_rect);
|
2010-03-07 07:11:05 +08:00
|
|
|
|
2010-09-23 15:45:23 +08:00
|
|
|
gimp_item_get_offset (GIMP_ITEM (text_tool->layer), &off_x, &off_y);
|
|
|
|
cursor_rect.x += off_x;
|
|
|
|
cursor_rect.y += off_y;
|
|
|
|
|
2010-10-14 08:45:32 +08:00
|
|
|
overwrite = text_tool->overwrite_mode && cursor_rect.width != 0;
|
2009-06-25 19:22:25 +08:00
|
|
|
|
2018-07-29 12:57:38 +08:00
|
|
|
direction = gimp_text_tool_get_direction (text_tool);
|
|
|
|
|
2011-03-19 17:11:47 +08:00
|
|
|
item = gimp_draw_tool_add_text_cursor (draw_tool, &cursor_rect,
|
2018-07-29 12:57:38 +08:00
|
|
|
overwrite, direction);
|
2011-03-19 17:11:47 +08:00
|
|
|
gimp_canvas_item_set_highlight (item, TRUE);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
2014-10-01 06:26:48 +08:00
|
|
|
|
2016-04-16 21:12:42 +08:00
|
|
|
gimp_text_tool_editor_update_im_cursor (text_tool);
|
2004-03-22 22:32:47 +08:00
|
|
|
}
|
|
|
|
|
2004-03-15 02:48:00 +08:00
|
|
|
static void
|
2010-03-07 07:11:05 +08:00
|
|
|
gimp_text_tool_draw_selection (GimpDrawTool *draw_tool)
|
2004-03-15 02:48:00 +08:00
|
|
|
{
|
2018-07-29 12:57:38 +08:00
|
|
|
GimpTextTool *text_tool = GIMP_TEXT_TOOL (draw_tool);
|
|
|
|
GtkTextBuffer *buffer = GTK_TEXT_BUFFER (text_tool->buffer);
|
|
|
|
GimpCanvasGroup *group;
|
|
|
|
PangoLayout *layout;
|
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint off_x, off_y;
|
|
|
|
PangoLayoutIter *iter;
|
|
|
|
GtkTextIter sel_start, sel_end;
|
|
|
|
gint min, max;
|
|
|
|
gint i;
|
|
|
|
GimpTextDirection direction;
|
2004-03-15 02:48:00 +08:00
|
|
|
|
2017-07-13 18:34:54 +08:00
|
|
|
group = gimp_draw_tool_add_stroke_group (draw_tool);
|
|
|
|
gimp_canvas_item_set_highlight (GIMP_CANVAS_ITEM (group), TRUE);
|
2010-09-28 05:04:18 +08:00
|
|
|
|
2010-02-21 05:11:06 +08:00
|
|
|
gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end);
|
2004-03-20 07:08:24 +08:00
|
|
|
|
2010-03-01 23:27:34 +08:00
|
|
|
min = gimp_text_buffer_get_iter_index (text_tool->buffer, &sel_start, TRUE);
|
|
|
|
max = gimp_text_buffer_get_iter_index (text_tool->buffer, &sel_end, TRUE);
|
2004-03-21 01:21:48 +08:00
|
|
|
|
2008-11-04 07:44:19 +08:00
|
|
|
layout = gimp_text_layout_get_pango_layout (text_tool->layout);
|
2010-02-19 03:16:11 +08:00
|
|
|
|
2010-03-07 07:11:05 +08:00
|
|
|
gimp_text_layout_get_offsets (text_tool->layout, &offset_x, &offset_y);
|
|
|
|
|
2018-07-29 12:57:38 +08:00
|
|
|
gimp_text_layout_get_size (text_tool->layout, &width, &height);
|
|
|
|
|
2010-09-23 15:45:23 +08:00
|
|
|
gimp_item_get_offset (GIMP_ITEM (text_tool->layer), &off_x, &off_y);
|
|
|
|
offset_x += off_x;
|
|
|
|
offset_y += off_y;
|
|
|
|
|
2018-07-29 12:57:38 +08:00
|
|
|
direction = gimp_text_tool_get_direction (text_tool);
|
|
|
|
|
2010-02-22 03:11:13 +08:00
|
|
|
iter = pango_layout_get_iter (layout);
|
|
|
|
|
2017-07-13 18:34:54 +08:00
|
|
|
gimp_draw_tool_push_group (draw_tool, group);
|
2010-10-04 20:03:37 +08:00
|
|
|
|
2010-02-22 03:11:13 +08:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if (! pango_layout_iter_get_run (iter))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
i = pango_layout_iter_get_index (iter);
|
|
|
|
|
|
|
|
if (i >= min && i < max)
|
|
|
|
{
|
2010-10-04 20:03:37 +08:00
|
|
|
PangoRectangle rect;
|
|
|
|
gint ytop, ybottom;
|
2010-02-22 03:11:13 +08:00
|
|
|
|
|
|
|
pango_layout_iter_get_char_extents (iter, &rect);
|
2010-02-22 03:25:17 +08:00
|
|
|
pango_layout_iter_get_line_yrange (iter, &ytop, &ybottom);
|
|
|
|
|
|
|
|
rect.y = ytop;
|
|
|
|
rect.height = ybottom - ytop;
|
|
|
|
|
2010-02-22 03:11:13 +08:00
|
|
|
pango_extents_to_pixels (&rect, NULL);
|
|
|
|
|
|
|
|
gimp_text_layout_transform_rect (text_tool->layout, &rect);
|
|
|
|
|
2018-07-29 12:57:38 +08:00
|
|
|
switch (direction)
|
|
|
|
{
|
|
|
|
case GIMP_TEXT_DIRECTION_LTR:
|
|
|
|
case GIMP_TEXT_DIRECTION_RTL:
|
|
|
|
rect.x += offset_x;
|
|
|
|
rect.y += offset_y;
|
|
|
|
gimp_draw_tool_add_rectangle (draw_tool, FALSE,
|
|
|
|
rect.x, rect.y,
|
|
|
|
rect.width, rect.height);
|
|
|
|
break;
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_RTL:
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
|
|
|
|
rect.y = offset_x - rect.y + width;
|
|
|
|
rect.x = offset_y + rect.x;
|
|
|
|
gimp_draw_tool_add_rectangle (draw_tool, FALSE,
|
|
|
|
rect.y, rect.x,
|
|
|
|
-rect.height, rect.width);
|
|
|
|
break;
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_LTR:
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
|
|
|
|
rect.y = offset_x + rect.y;
|
|
|
|
rect.x = offset_y - rect.x + height;
|
|
|
|
gimp_draw_tool_add_rectangle (draw_tool, FALSE,
|
|
|
|
rect.y, rect.x,
|
|
|
|
rect.height, -rect.width);
|
|
|
|
break;
|
|
|
|
}
|
2010-02-22 03:11:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
while (pango_layout_iter_next_char (iter));
|
|
|
|
|
2010-10-04 20:03:37 +08:00
|
|
|
gimp_draw_tool_pop_group (draw_tool);
|
|
|
|
|
2010-02-22 03:11:13 +08:00
|
|
|
pango_layout_iter_free (iter);
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
2004-03-20 07:08:24 +08:00
|
|
|
|
2018-05-29 22:19:50 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_text_tool_start (GimpTextTool *text_tool,
|
|
|
|
GimpDisplay *display,
|
|
|
|
GimpLayer *layer,
|
|
|
|
GError **error)
|
2017-06-28 21:40:38 +08:00
|
|
|
{
|
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
|
|
|
GimpToolWidget *widget;
|
2018-06-03 05:19:51 +08:00
|
|
|
GimpAsyncSet *async_set;
|
|
|
|
|
|
|
|
async_set =
|
|
|
|
gimp_data_factory_get_async_set (tool->tool_info->gimp->font_factory);
|
2017-06-28 21:40:38 +08:00
|
|
|
|
2018-06-03 05:19:51 +08:00
|
|
|
if (! gimp_async_set_is_empty (async_set))
|
2018-05-29 22:19:50 +08:00
|
|
|
{
|
|
|
|
g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
|
|
|
|
_("Fonts are still loading"));
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
tool->display = display;
|
|
|
|
|
|
|
|
text_tool->widget = widget = gimp_tool_rectangle_new (shell);
|
|
|
|
|
|
|
|
g_object_set (widget,
|
|
|
|
"force-narrow-mode", TRUE,
|
2017-06-30 02:38:04 +08:00
|
|
|
"status-title", _("Text box: "),
|
2017-06-28 21:40:38 +08:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
gimp_draw_tool_set_widget (GIMP_DRAW_TOOL (tool), widget);
|
|
|
|
|
|
|
|
g_signal_connect (widget, "response",
|
|
|
|
G_CALLBACK (gimp_text_tool_rectangle_response),
|
|
|
|
text_tool);
|
|
|
|
g_signal_connect (widget, "change-complete",
|
|
|
|
G_CALLBACK (gimp_text_tool_rectangle_change_complete),
|
|
|
|
text_tool);
|
|
|
|
|
|
|
|
gimp_draw_tool_start (GIMP_DRAW_TOOL (tool), display);
|
|
|
|
|
|
|
|
if (layer)
|
|
|
|
{
|
|
|
|
gimp_text_tool_frame_item (text_tool);
|
|
|
|
gimp_text_tool_editor_start (text_tool);
|
|
|
|
gimp_text_tool_editor_position (text_tool);
|
|
|
|
}
|
2018-05-29 22:19:50 +08:00
|
|
|
|
|
|
|
return TRUE;
|
2017-06-28 21:40:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_text_tool_halt (GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
|
|
|
|
|
|
|
gimp_text_tool_editor_halt (text_tool);
|
|
|
|
gimp_text_tool_clear_layout (text_tool);
|
|
|
|
gimp_text_tool_set_drawable (text_tool, NULL, FALSE);
|
|
|
|
|
|
|
|
if (gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tool)))
|
|
|
|
gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
|
|
|
|
|
|
|
|
gimp_draw_tool_set_widget (GIMP_DRAW_TOOL (tool), NULL);
|
|
|
|
g_clear_object (&text_tool->widget);
|
|
|
|
|
2020-05-25 17:30:31 +08:00
|
|
|
tool->display = NULL;
|
|
|
|
g_list_free (tool->drawables);
|
|
|
|
tool->drawables = NULL;
|
2017-06-28 21:40:38 +08:00
|
|
|
}
|
|
|
|
|
2010-02-18 03:23:58 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_frame_item (GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LAYER (text_tool->layer));
|
|
|
|
|
|
|
|
text_tool->handle_rectangle_change_complete = FALSE;
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
gimp_tool_rectangle_frame_item (GIMP_TOOL_RECTANGLE (text_tool->widget),
|
2010-02-18 03:23:58 +08:00
|
|
|
GIMP_ITEM (text_tool->layer));
|
|
|
|
|
|
|
|
text_tool->handle_rectangle_change_complete = TRUE;
|
|
|
|
}
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_rectangle_response (GimpToolRectangle *rectangle,
|
|
|
|
gint response_id,
|
|
|
|
GimpTextTool *text_tool)
|
2009-06-24 03:57:59 +08:00
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
2009-06-24 03:57:59 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
/* this happens when a newly created rectangle gets canceled,
|
|
|
|
* we have to shut down the tool
|
|
|
|
*/
|
|
|
|
if (response_id == GIMP_TOOL_WIDGET_RESPONSE_CANCEL)
|
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_text_tool_rectangle_change_complete (GimpToolRectangle *rectangle,
|
|
|
|
GimpTextTool *text_tool)
|
|
|
|
{
|
2010-02-28 01:19:47 +08:00
|
|
|
gimp_text_tool_editor_position (text_tool);
|
|
|
|
|
2009-06-24 03:57:59 +08:00
|
|
|
if (text_tool->handle_rectangle_change_complete)
|
|
|
|
{
|
|
|
|
GimpItem *item = GIMP_ITEM (text_tool->layer);
|
2017-06-28 21:40:38 +08:00
|
|
|
gdouble x1, y1;
|
|
|
|
gdouble x2, y2;
|
2009-06-24 03:57:59 +08:00
|
|
|
|
2010-02-19 18:05:58 +08:00
|
|
|
if (! item)
|
2009-06-24 03:57:59 +08:00
|
|
|
{
|
|
|
|
/* 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
|
|
|
|
*/
|
2010-02-19 18:05:58 +08:00
|
|
|
text_tool->text_box_fixed = TRUE;
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
return;
|
2009-06-24 03:57:59 +08:00
|
|
|
}
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
g_object_get (rectangle,
|
2010-02-19 18:05:58 +08:00
|
|
|
"x1", &x1,
|
|
|
|
"y1", &y1,
|
|
|
|
"x2", &x2,
|
|
|
|
"y2", &y2,
|
2009-06-24 03:57:59 +08:00
|
|
|
NULL);
|
|
|
|
|
2018-09-06 23:43:12 +08:00
|
|
|
if ((x2 - x1) != gimp_item_get_width (item) ||
|
2010-02-19 18:05:58 +08:00
|
|
|
(y2 - y1) != gimp_item_get_height (item))
|
|
|
|
{
|
2012-02-07 23:57:21 +08:00
|
|
|
GimpUnit box_unit = text_tool->proxy->box_unit;
|
|
|
|
gdouble xres, yres;
|
|
|
|
gboolean push_undo = TRUE;
|
|
|
|
GimpUndo *undo;
|
2010-02-21 21:33:33 +08:00
|
|
|
|
|
|
|
gimp_image_get_resolution (text_tool->image, &xres, &yres);
|
|
|
|
|
2010-02-19 18:05:58 +08:00
|
|
|
g_object_set (text_tool->proxy,
|
|
|
|
"box-mode", GIMP_TEXT_BOX_FIXED,
|
2010-02-21 23:46:39 +08:00
|
|
|
"box-width", gimp_pixels_to_units (x2 - x1,
|
2010-03-07 08:19:09 +08:00
|
|
|
box_unit, xres),
|
2010-02-21 23:46:39 +08:00
|
|
|
"box-height", gimp_pixels_to_units (y2 - y1,
|
2010-03-07 08:19:09 +08:00
|
|
|
box_unit, yres),
|
2010-02-19 18:05:58 +08:00
|
|
|
NULL);
|
2009-06-24 03:57:59 +08:00
|
|
|
|
2012-02-07 23:57:21 +08:00
|
|
|
undo = gimp_image_undo_can_compress (text_tool->image,
|
|
|
|
GIMP_TYPE_UNDO_STACK,
|
|
|
|
GIMP_UNDO_GROUP_TEXT);
|
|
|
|
|
|
|
|
if (undo &&
|
|
|
|
gimp_undo_get_age (undo) <= TEXT_UNDO_TIMEOUT &&
|
|
|
|
g_object_get_data (G_OBJECT (undo), "reshape-text-layer") == (gpointer) item)
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
{
|
|
|
|
gimp_image_undo_group_start (text_tool->image, GIMP_UNDO_GROUP_TEXT,
|
|
|
|
_("Reshape Text Layer"));
|
|
|
|
|
|
|
|
undo = gimp_image_undo_can_compress (text_tool->image, GIMP_TYPE_UNDO_STACK,
|
|
|
|
GIMP_UNDO_GROUP_TEXT);
|
|
|
|
|
|
|
|
if (undo)
|
|
|
|
g_object_set_data (G_OBJECT (undo), "reshape-text-layer",
|
|
|
|
(gpointer) item);
|
|
|
|
}
|
2009-06-24 03:57:59 +08:00
|
|
|
|
2018-09-06 23:43:12 +08:00
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
|
|
|
|
2010-02-19 18:05:58 +08:00
|
|
|
gimp_item_translate (item,
|
|
|
|
x1 - gimp_item_get_offset_x (item),
|
|
|
|
y1 - gimp_item_get_offset_y (item),
|
2012-02-07 23:57:21 +08:00
|
|
|
push_undo);
|
|
|
|
gimp_text_tool_apply (text_tool, push_undo);
|
2010-02-19 18:05:58 +08:00
|
|
|
|
2018-09-06 23:43:12 +08:00
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
|
|
|
|
2012-02-07 23:57:21 +08:00
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_group_end (text_tool->image);
|
2010-02-19 18:05:58 +08:00
|
|
|
}
|
2018-09-06 23:43:12 +08:00
|
|
|
else if (x1 != gimp_item_get_offset_x (item) ||
|
|
|
|
y1 != gimp_item_get_offset_y (item))
|
|
|
|
{
|
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
|
|
|
|
|
|
|
gimp_text_tool_apply (text_tool, TRUE);
|
|
|
|
|
|
|
|
gimp_item_translate (item,
|
|
|
|
x1 - gimp_item_get_offset_x (item),
|
|
|
|
y1 - gimp_item_get_offset_y (item),
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
|
|
|
|
|
|
|
gimp_image_flush (text_tool->image);
|
|
|
|
}
|
2009-06-24 03:57:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-10 00:58:54 +08:00
|
|
|
static void
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_text_tool_connect (GimpTextTool *text_tool,
|
|
|
|
GimpTextLayer *layer,
|
|
|
|
GimpText *text)
|
2005-03-10 00:58:54 +08:00
|
|
|
{
|
2010-02-18 03:23:58 +08:00
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
2005-03-10 00:58:54 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_return_if_fail (text == NULL || (layer != NULL && layer->text == text));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text_tool->text != text)
|
2004-03-20 00:29:36 +08:00
|
|
|
{
|
2008-10-28 00:21:03 +08:00
|
|
|
GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (tool);
|
2004-07-13 16:59:10 +08:00
|
|
|
|
2010-02-26 00:49:33 +08:00
|
|
|
g_signal_handlers_block_by_func (text_tool->buffer,
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_buffer_begin_edit,
|
|
|
|
text_tool);
|
|
|
|
g_signal_handlers_block_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_end_edit,
|
2010-02-26 08:36:31 +08:00
|
|
|
text_tool);
|
2010-02-21 09:00:57 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text_tool->text)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (text_tool->text,
|
|
|
|
gimp_text_tool_text_notify,
|
|
|
|
text_tool);
|
2010-03-03 00:44:31 +08:00
|
|
|
g_signal_handlers_disconnect_by_func (text_tool->text,
|
|
|
|
gimp_text_tool_text_changed,
|
|
|
|
text_tool);
|
2003-02-01 02:57:10 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text_tool->pending)
|
2012-02-07 23:57:21 +08:00
|
|
|
gimp_text_tool_apply (text_tool, TRUE);
|
2004-07-13 16:59:10 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&text_tool->text);
|
2001-08-14 21:49:21 +08:00
|
|
|
|
2010-02-26 08:36:31 +08:00
|
|
|
g_object_set (text_tool->proxy,
|
|
|
|
"text", NULL,
|
|
|
|
"markup", NULL,
|
|
|
|
NULL);
|
2010-03-03 08:15:27 +08:00
|
|
|
gimp_text_buffer_set_text (text_tool->buffer, NULL);
|
2010-02-24 06:14:09 +08:00
|
|
|
|
|
|
|
gimp_text_tool_clear_layout (text_tool);
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
2004-03-15 01:54:23 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_context_define_property (GIMP_CONTEXT (options),
|
|
|
|
GIMP_CONTEXT_PROP_FOREGROUND,
|
|
|
|
text != NULL);
|
2002-10-11 01:07:46 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text)
|
|
|
|
{
|
2012-03-10 02:21:44 +08:00
|
|
|
if (text->unit != text_tool->proxy->unit)
|
|
|
|
gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (options->size_entry),
|
|
|
|
text->unit);
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_config_sync (G_OBJECT (text), G_OBJECT (text_tool->proxy), 0);
|
2010-03-03 08:15:27 +08:00
|
|
|
|
|
|
|
if (text->markup)
|
|
|
|
gimp_text_buffer_set_markup (text_tool->buffer, text->markup);
|
|
|
|
else
|
|
|
|
gimp_text_buffer_set_text (text_tool->buffer, text->text);
|
2001-08-14 21:49:21 +08:00
|
|
|
|
2010-02-24 06:14:09 +08:00
|
|
|
gimp_text_tool_clear_layout (text_tool);
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
text_tool->text = g_object_ref (text);
|
2004-01-20 01:21:53 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_signal_connect (text, "notify",
|
|
|
|
G_CALLBACK (gimp_text_tool_text_notify),
|
|
|
|
text_tool);
|
2010-03-03 00:44:31 +08:00
|
|
|
g_signal_connect (text, "changed",
|
|
|
|
G_CALLBACK (gimp_text_tool_text_changed),
|
|
|
|
text_tool);
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
2010-02-21 09:00:57 +08:00
|
|
|
|
2010-02-26 08:36:31 +08:00
|
|
|
g_signal_handlers_unblock_by_func (text_tool->buffer,
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_buffer_end_edit,
|
|
|
|
text_tool);
|
|
|
|
g_signal_handlers_unblock_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_begin_edit,
|
2010-02-21 09:00:57 +08:00
|
|
|
text_tool);
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
1998-02-22 18:45:12 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text_tool->layer != layer)
|
2005-02-20 03:10:33 +08:00
|
|
|
{
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text_tool->layer)
|
2018-04-24 08:49:03 +08:00
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (text_tool->layer,
|
|
|
|
gimp_text_tool_layer_notify,
|
|
|
|
text_tool);
|
2005-02-20 03:10:33 +08:00
|
|
|
|
2018-04-24 08:49:03 +08:00
|
|
|
/* don't try to remove the layer if it is not attached,
|
|
|
|
* which can happen if we got here because the layer was
|
|
|
|
* somehow deleted from the image (like by the user in the
|
|
|
|
* layers dialog).
|
|
|
|
*/
|
|
|
|
if (gimp_item_is_attached (GIMP_ITEM (text_tool->layer)))
|
|
|
|
gimp_text_tool_remove_empty_text_layer (text_tool);
|
|
|
|
}
|
2016-06-27 22:48:19 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
text_tool->layer = layer;
|
2005-02-20 03:10:33 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (layer)
|
2018-04-24 08:49:03 +08:00
|
|
|
{
|
|
|
|
g_signal_connect_object (text_tool->layer, "notify",
|
|
|
|
G_CALLBACK (gimp_text_tool_layer_notify),
|
|
|
|
text_tool, 0);
|
|
|
|
}
|
2005-02-20 03:10:33 +08:00
|
|
|
}
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
2004-01-20 01:21:53 +08:00
|
|
|
|
2008-10-27 01:39:55 +08:00
|
|
|
static void
|
2010-11-28 22:28:28 +08:00
|
|
|
gimp_text_tool_layer_notify (GimpTextLayer *layer,
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
GimpTextTool *text_tool)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2011-04-03 06:40:41 +08:00
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
|
|
|
|
2010-11-28 22:28:28 +08:00
|
|
|
if (! strcmp (pspec->name, "modified"))
|
|
|
|
{
|
|
|
|
if (layer->modified)
|
2011-04-03 06:40:41 +08:00
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
|
2010-11-28 22:28:28 +08:00
|
|
|
}
|
|
|
|
else if (! strcmp (pspec->name, "text"))
|
|
|
|
{
|
|
|
|
if (! layer->text)
|
2011-04-03 06:40:41 +08:00
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
|
2010-11-28 22:28:28 +08:00
|
|
|
}
|
2018-09-06 23:16:50 +08:00
|
|
|
else if (! strcmp (pspec->name, "offset-x") ||
|
|
|
|
! strcmp (pspec->name, "offset-y"))
|
|
|
|
{
|
|
|
|
if (gimp_item_is_attached (GIMP_ITEM (layer)))
|
|
|
|
{
|
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
|
|
|
|
|
|
|
gimp_text_tool_frame_item (text_tool);
|
|
|
|
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
|
|
|
}
|
|
|
|
}
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2012-02-07 23:57:21 +08:00
|
|
|
static gboolean
|
2018-09-06 23:09:01 +08:00
|
|
|
gimp_text_tool_apply_idle (GimpTextTool *text_tool)
|
2012-02-07 23:57:21 +08:00
|
|
|
{
|
2018-09-06 23:09:01 +08:00
|
|
|
text_tool->idle_id = 0;
|
|
|
|
|
|
|
|
gimp_text_tool_apply (text_tool, TRUE);
|
|
|
|
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
2012-02-07 23:57:21 +08:00
|
|
|
}
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
static void
|
2010-11-28 22:28:28 +08:00
|
|
|
gimp_text_tool_proxy_notify (GimpText *text,
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
GimpTextTool *text_tool)
|
2008-10-28 00:21:03 +08:00
|
|
|
{
|
|
|
|
if (! text_tool->text)
|
|
|
|
return;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2013-02-17 03:38:15 +08:00
|
|
|
if ((pspec->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE &&
|
|
|
|
pspec->owner_type == GIMP_TYPE_TEXT)
|
2008-10-28 00:21:03 +08:00
|
|
|
{
|
2016-06-05 22:23:50 +08:00
|
|
|
if (text_tool->preedit_active)
|
|
|
|
{
|
|
|
|
/* if there is a preedit going on, don't queue pending
|
|
|
|
* changes to be idle-applied with undo; instead, flush the
|
|
|
|
* pending queue (happens only when preedit starts), and
|
|
|
|
* apply the changes to text_tool->text directly. Preedit
|
|
|
|
* will *always* end by removing the preedit string, and if
|
|
|
|
* the preedit was committed, it will insert the resulting
|
|
|
|
* text, which will not trigger this if() any more.
|
|
|
|
*/
|
|
|
|
|
|
|
|
GList *list = NULL;
|
2010-03-07 07:15:32 +08:00
|
|
|
|
2016-06-05 22:23:50 +08:00
|
|
|
/* if there are pending changes, apply them before applying
|
|
|
|
* preedit stuff directly (bypassing undo)
|
|
|
|
*/
|
|
|
|
if (text_tool->pending)
|
|
|
|
{
|
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
|
|
|
gimp_text_tool_apply (text_tool, TRUE);
|
2018-09-06 23:09:01 +08:00
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
2016-06-05 22:23:50 +08:00
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2016-06-05 22:23:50 +08:00
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
|
|
|
|
|
|
|
list = g_list_append (list, (gpointer) pspec);
|
|
|
|
gimp_text_tool_apply_list (text_tool, list);
|
|
|
|
g_list_free (list);
|
|
|
|
|
|
|
|
gimp_text_tool_frame_item (text_tool);
|
|
|
|
|
|
|
|
gimp_image_flush (gimp_item_get_image (GIMP_ITEM (text_tool->layer)));
|
|
|
|
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* else queue the property change for normal processing,
|
|
|
|
* including undo
|
|
|
|
*/
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2016-06-05 22:23:50 +08:00
|
|
|
text_tool->pending = g_list_append (text_tool->pending,
|
|
|
|
(gpointer) pspec);
|
|
|
|
|
2018-09-06 23:09:01 +08:00
|
|
|
if (! text_tool->idle_id)
|
|
|
|
{
|
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
2016-06-05 22:23:50 +08:00
|
|
|
|
2018-09-06 23:09:01 +08:00
|
|
|
text_tool->idle_id =
|
|
|
|
g_idle_add_full (G_PRIORITY_LOW,
|
|
|
|
(GSourceFunc) gimp_text_tool_apply_idle,
|
|
|
|
text_tool,
|
|
|
|
NULL);
|
|
|
|
}
|
2016-06-05 22:23:50 +08:00
|
|
|
}
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
2002-10-11 02:37:12 +08:00
|
|
|
static void
|
2010-11-28 22:28:28 +08:00
|
|
|
gimp_text_tool_text_notify (GimpText *text,
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
GimpTextTool *text_tool)
|
2002-10-11 02:37:12 +08:00
|
|
|
{
|
2008-10-28 00:21:03 +08:00
|
|
|
g_return_if_fail (text == text_tool->text);
|
2002-10-11 02:37:12 +08:00
|
|
|
|
2016-06-05 22:23:50 +08:00
|
|
|
/* an undo cancels all preedit operations */
|
|
|
|
if (text_tool->preedit_active)
|
|
|
|
gimp_text_tool_abort_im_context (text_tool);
|
|
|
|
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
2010-02-24 06:14:09 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if ((pspec->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE)
|
2002-10-11 02:37:12 +08:00
|
|
|
{
|
2016-03-26 22:59:26 +08:00
|
|
|
GValue value = G_VALUE_INIT;
|
2002-10-11 02:37:12 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_value_init (&value, pspec->value_type);
|
2004-11-23 00:03:54 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_object_get_property (G_OBJECT (text), pspec->name, &value);
|
2006-08-28 23:26:25 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_signal_handlers_block_by_func (text_tool->proxy,
|
|
|
|
gimp_text_tool_proxy_notify,
|
|
|
|
text_tool);
|
2002-10-12 01:42:26 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_object_set_property (G_OBJECT (text_tool->proxy), pspec->name, &value);
|
2002-10-11 02:37:12 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_signal_handlers_unblock_by_func (text_tool->proxy,
|
|
|
|
gimp_text_tool_proxy_notify,
|
|
|
|
text_tool);
|
2003-06-27 22:26:04 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_value_unset (&value);
|
|
|
|
}
|
2002-10-11 02:37:12 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
/* if the text has changed, (probably because of an undo), we put
|
|
|
|
* the new text into the text buffer
|
|
|
|
*/
|
2010-02-26 08:36:31 +08:00
|
|
|
if (strcmp (pspec->name, "text") == 0 ||
|
|
|
|
strcmp (pspec->name, "markup") == 0)
|
2008-10-28 00:21:03 +08:00
|
|
|
{
|
2010-02-26 00:49:33 +08:00
|
|
|
g_signal_handlers_block_by_func (text_tool->buffer,
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_buffer_begin_edit,
|
|
|
|
text_tool);
|
|
|
|
g_signal_handlers_block_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_end_edit,
|
2010-02-26 08:36:31 +08:00
|
|
|
text_tool);
|
2018-03-23 21:19:01 +08:00
|
|
|
|
2012-10-20 22:24:56 +08:00
|
|
|
if (text->markup)
|
2010-02-26 08:36:31 +08:00
|
|
|
gimp_text_buffer_set_markup (text_tool->buffer, text->markup);
|
2012-10-20 22:24:56 +08:00
|
|
|
else
|
|
|
|
gimp_text_buffer_set_text (text_tool->buffer, text->text);
|
2004-03-12 02:47:37 +08:00
|
|
|
|
2010-02-26 08:36:31 +08:00
|
|
|
g_signal_handlers_unblock_by_func (text_tool->buffer,
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_buffer_end_edit,
|
|
|
|
text_tool);
|
|
|
|
g_signal_handlers_unblock_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_begin_edit,
|
2008-10-28 00:21:03 +08:00
|
|
|
text_tool);
|
2004-03-20 00:29:36 +08:00
|
|
|
}
|
2018-09-06 23:09:01 +08:00
|
|
|
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
2010-03-03 00:44:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_text_tool_text_changed (GimpText *text,
|
|
|
|
GimpTextTool *text_tool)
|
|
|
|
{
|
2018-09-06 23:09:01 +08:00
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
|
|
|
|
2010-03-03 00:44:31 +08:00
|
|
|
/* we need to redraw the rectangle in any case because whatever
|
|
|
|
* changes to the text can change its size
|
|
|
|
*/
|
|
|
|
gimp_text_tool_frame_item (text_tool);
|
|
|
|
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
2004-03-20 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
2018-05-29 22:19:50 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_fonts_async_set_empty_notify (GimpAsyncSet *async_set,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
|
|
|
|
|
|
|
if (! gimp_async_set_is_empty (async_set) && tool->display)
|
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
|
|
|
|
}
|
|
|
|
|
2016-06-05 22:23:50 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_apply_list (GimpTextTool *text_tool,
|
|
|
|
GList *pspecs)
|
|
|
|
{
|
|
|
|
GObject *src = G_OBJECT (text_tool->proxy);
|
|
|
|
GObject *dest = G_OBJECT (text_tool->text);
|
|
|
|
GList *list;
|
2004-02-09 06:09:57 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_signal_handlers_block_by_func (dest,
|
2008-11-02 03:05:56 +08:00
|
|
|
gimp_text_tool_text_notify,
|
|
|
|
text_tool);
|
2010-03-03 00:44:31 +08:00
|
|
|
g_signal_handlers_block_by_func (dest,
|
|
|
|
gimp_text_tool_text_changed,
|
|
|
|
text_tool);
|
2004-03-13 08:47:31 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_object_freeze_notify (dest);
|
2004-02-09 06:09:57 +08:00
|
|
|
|
2016-06-05 22:23:50 +08:00
|
|
|
for (list = pspecs; list; list = g_list_next (list))
|
2004-03-19 04:55:00 +08:00
|
|
|
{
|
2016-06-05 22:23:50 +08:00
|
|
|
const GParamSpec *pspec;
|
|
|
|
GValue value = G_VALUE_INIT;
|
2007-12-27 01:33:41 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
/* look ahead and compress changes */
|
|
|
|
if (list->next && list->next->data == list->data)
|
|
|
|
continue;
|
2004-02-09 06:09:57 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
pspec = list->data;
|
2004-03-13 11:57:01 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_value_init (&value, pspec->value_type);
|
2004-03-19 04:55:00 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_object_get_property (src, pspec->name, &value);
|
|
|
|
g_object_set_property (dest, pspec->name, &value);
|
2004-03-19 04:55:00 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_value_unset (&value);
|
|
|
|
}
|
2004-03-13 08:47:31 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_object_thaw_notify (dest);
|
2004-03-13 11:19:53 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_signal_handlers_unblock_by_func (dest,
|
2008-11-02 03:05:56 +08:00
|
|
|
gimp_text_tool_text_notify,
|
|
|
|
text_tool);
|
2010-03-03 00:44:31 +08:00
|
|
|
g_signal_handlers_unblock_by_func (dest,
|
|
|
|
gimp_text_tool_text_changed,
|
|
|
|
text_tool);
|
2004-03-20 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_create_layer (GimpTextTool *text_tool,
|
|
|
|
GimpText *text)
|
2004-03-20 00:29:36 +08:00
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
|
|
|
GimpImage *image = gimp_display_get_image (tool->display);
|
|
|
|
GimpLayer *layer;
|
|
|
|
gdouble x1, y1;
|
|
|
|
gdouble x2, y2;
|
2008-10-28 00:21:03 +08:00
|
|
|
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text)
|
|
|
|
{
|
|
|
|
text = gimp_config_duplicate (GIMP_CONFIG (text));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-03 04:54:24 +08:00
|
|
|
gchar *string;
|
2008-10-28 00:21:03 +08:00
|
|
|
|
2010-03-03 04:54:24 +08:00
|
|
|
if (gimp_text_buffer_has_markup (text_tool->buffer))
|
|
|
|
{
|
|
|
|
string = gimp_text_buffer_get_markup (text_tool->buffer);
|
|
|
|
|
|
|
|
g_object_set (text_tool->proxy,
|
|
|
|
"markup", string,
|
|
|
|
"box-mode", GIMP_TEXT_BOX_DYNAMIC,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
string = gimp_text_buffer_get_text (text_tool->buffer);
|
|
|
|
|
|
|
|
g_object_set (text_tool->proxy,
|
|
|
|
"text", string,
|
|
|
|
"box-mode", GIMP_TEXT_BOX_DYNAMIC,
|
|
|
|
NULL);
|
|
|
|
}
|
2004-03-20 00:29:36 +08:00
|
|
|
|
2010-02-20 22:13:14 +08:00
|
|
|
g_free (string);
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
text = gimp_config_duplicate (GIMP_CONFIG (text_tool->proxy));
|
|
|
|
}
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
layer = gimp_text_layer_new (image, text);
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_object_unref (text);
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (! layer)
|
2010-03-05 17:50:50 +08:00
|
|
|
{
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
|
|
|
return;
|
|
|
|
}
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_text_tool_connect (text_tool, GIMP_TEXT_LAYER (layer), text);
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT,
|
|
|
|
_("Add Text Layer"));
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-11-14 23:01:44 +08:00
|
|
|
if (gimp_image_get_floating_selection (image))
|
2008-10-28 00:21:03 +08:00
|
|
|
{
|
|
|
|
g_signal_handlers_block_by_func (image,
|
|
|
|
gimp_text_tool_layer_changed,
|
|
|
|
text_tool);
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-11-14 23:01:44 +08:00
|
|
|
floating_sel_anchor (gimp_image_get_floating_selection (image));
|
2006-05-14 06:55:22 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_signal_handlers_unblock_by_func (image,
|
|
|
|
gimp_text_tool_layer_changed,
|
|
|
|
text_tool);
|
2006-05-14 06:55:22 +08:00
|
|
|
}
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
g_object_get (text_tool->widget,
|
2008-11-02 03:05:56 +08:00
|
|
|
"x1", &x1,
|
|
|
|
"y1", &y1,
|
|
|
|
"x2", &x2,
|
|
|
|
"y2", &y2,
|
|
|
|
NULL);
|
|
|
|
|
2018-07-31 15:27:33 +08:00
|
|
|
if (text_tool->text_box_fixed == FALSE)
|
|
|
|
{
|
|
|
|
if (text_tool->text &&
|
|
|
|
(text_tool->text->base_dir == GIMP_TEXT_DIRECTION_TTB_RTL ||
|
|
|
|
text_tool->text->base_dir == GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT))
|
|
|
|
{
|
2018-08-02 18:55:00 +08:00
|
|
|
x1 -= gimp_item_get_width (GIMP_ITEM (layer));
|
2018-07-31 15:27:33 +08:00
|
|
|
}
|
|
|
|
}
|
2008-12-28 20:43:07 +08:00
|
|
|
gimp_item_set_offset (GIMP_ITEM (layer), x1, y1);
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2009-08-04 04:30:36 +08:00
|
|
|
gimp_image_add_layer (image, layer,
|
|
|
|
GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
2008-10-28 00:21:03 +08:00
|
|
|
|
|
|
|
if (text_tool->text_box_fixed)
|
2008-04-03 05:32:32 +08:00
|
|
|
{
|
2010-03-07 08:19:09 +08:00
|
|
|
GimpUnit box_unit = text_tool->proxy->box_unit;
|
|
|
|
gdouble xres, yres;
|
2010-02-21 21:33:33 +08:00
|
|
|
|
|
|
|
gimp_image_get_resolution (image, &xres, &yres);
|
|
|
|
|
2008-04-03 05:32:32 +08:00
|
|
|
g_object_set (text_tool->proxy,
|
2008-08-11 17:44:38 +08:00
|
|
|
"box-mode", GIMP_TEXT_BOX_FIXED,
|
2010-02-21 23:46:39 +08:00
|
|
|
"box-width", gimp_pixels_to_units (x2 - x1,
|
2010-03-07 08:19:09 +08:00
|
|
|
box_unit, xres),
|
2010-02-21 23:46:39 +08:00
|
|
|
"box-height", gimp_pixels_to_units (y2 - y1,
|
2010-03-07 08:19:09 +08:00
|
|
|
box_unit, yres),
|
2008-04-03 05:32:32 +08:00
|
|
|
NULL);
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
|
2012-02-07 23:57:21 +08:00
|
|
|
gimp_text_tool_apply (text_tool, TRUE); /* unblocks drawing */
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-02-18 03:23:58 +08:00
|
|
|
gimp_text_tool_frame_item (text_tool);
|
2008-04-03 05:32:32 +08:00
|
|
|
}
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_image_undo_group_end (image);
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_image_flush (image);
|
2008-04-03 05:32:32 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), FALSE);
|
2018-09-06 23:09:01 +08:00
|
|
|
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define RESPONSE_NEW 1
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_confirm_response (GtkWidget *widget,
|
|
|
|
gint response_id,
|
|
|
|
GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
GimpTextLayer *layer = text_tool->layer;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gtk_widget_destroy (widget);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
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 */
|
2010-02-26 08:36:31 +08:00
|
|
|
g_object_notify (G_OBJECT (text_tool->proxy), "markup");
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-18 04:23:15 +08:00
|
|
|
gimp_text_tool_editor_start (text_tool);
|
2008-10-28 00:21:03 +08:00
|
|
|
break;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
default:
|
|
|
|
break;
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_text_tool_confirm_dialog (GimpTextTool *text_tool)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2009-10-06 01:58:03 +08:00
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
|
|
|
GimpDisplayShell *shell = gimp_display_get_shell (tool->display);
|
|
|
|
GtkWidget *dialog;
|
|
|
|
GtkWidget *vbox;
|
|
|
|
GtkWidget *label;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_return_if_fail (text_tool->layer != NULL);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text_tool->confirm_dialog)
|
|
|
|
{
|
|
|
|
gtk_window_present (GTK_WINDOW (text_tool->confirm_dialog));
|
|
|
|
return;
|
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2020-05-02 07:42:04 +08:00
|
|
|
dialog = gimp_viewable_dialog_new (g_list_prepend (NULL, text_tool->layer),
|
2008-10-28 00:21:03 +08:00
|
|
|
GIMP_CONTEXT (gimp_tool_get_options (tool)),
|
|
|
|
_("Confirm Text Editing"),
|
|
|
|
"gimp-text-tool-confirm",
|
2017-03-05 23:01:59 +08:00
|
|
|
GIMP_ICON_LAYER_TEXT_LAYER,
|
2008-10-28 00:21:03 +08:00
|
|
|
_("Confirm Text Editing"),
|
2009-10-06 01:58:03 +08:00
|
|
|
GTK_WIDGET (shell),
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_standard_help_func, NULL,
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
_("Create _New Layer"), RESPONSE_NEW,
|
2017-02-12 23:06:34 +08:00
|
|
|
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
|
|
|
_("_Edit"), GTK_RESPONSE_ACCEPT,
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
NULL);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2018-05-10 23:04:37 +08:00
|
|
|
gimp_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
|
2008-10-28 00:21:03 +08:00
|
|
|
RESPONSE_NEW,
|
2010-09-08 02:39:45 +08:00
|
|
|
GTK_RESPONSE_ACCEPT,
|
2008-10-28 00:21:03 +08:00
|
|
|
GTK_RESPONSE_CANCEL,
|
|
|
|
-1);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_signal_connect (dialog, "response",
|
|
|
|
G_CALLBACK (gimp_text_tool_confirm_response),
|
|
|
|
text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2011-09-30 17:29:11 +08:00
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
2008-10-28 00:21:03 +08:00
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
|
2009-07-15 22:19:32 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
|
2008-10-28 00:21:03 +08:00
|
|
|
vbox, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (vbox);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
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."));
|
2016-09-09 01:11:20 +08:00
|
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
2008-10-28 00:21:03 +08:00
|
|
|
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (label);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gtk_widget_show (dialog);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
text_tool->confirm_dialog = dialog;
|
|
|
|
g_signal_connect_swapped (dialog, "destroy",
|
|
|
|
G_CALLBACK (g_nullify_pointer),
|
|
|
|
&text_tool->confirm_dialog);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_text_tool_layer_changed (GimpImage *image,
|
|
|
|
GimpTextTool *text_tool)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2020-04-04 08:49:51 +08:00
|
|
|
GList *layers = gimp_image_get_selected_layers (image);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2020-04-04 08:49:51 +08:00
|
|
|
if (g_list_length (layers) != 1 || layers->data != text_tool->layer)
|
2008-10-28 00:21:03 +08:00
|
|
|
{
|
2017-06-28 21:40:38 +08:00
|
|
|
GimpTool *tool = GIMP_TOOL (text_tool);
|
|
|
|
GimpDisplay *display = tool->display;
|
2010-02-27 04:22:10 +08:00
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
if (display)
|
|
|
|
{
|
2020-04-04 08:49:51 +08:00
|
|
|
GimpLayer *layer = NULL;
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
|
2010-02-27 04:22:10 +08:00
|
|
|
|
2020-04-04 08:49:51 +08:00
|
|
|
if (g_list_length (layers) == 1)
|
|
|
|
layer = layers->data;
|
|
|
|
|
|
|
|
/* The tool can only be started when a single layer is
|
|
|
|
* selected and this is a text layer.
|
|
|
|
*/
|
|
|
|
if (layer &&
|
|
|
|
gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer),
|
2017-06-28 21:40:38 +08:00
|
|
|
FALSE) &&
|
|
|
|
GIMP_LAYER (text_tool->layer) == layer)
|
|
|
|
{
|
2018-05-29 22:19:50 +08:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (! gimp_text_tool_start (text_tool, display, layer, &error))
|
|
|
|
{
|
|
|
|
gimp_text_tool_set_drawable (text_tool, NULL, FALSE);
|
|
|
|
|
|
|
|
gimp_tool_message_literal (tool, display, error->message);
|
|
|
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2017-06-28 21:40:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_set_image (GimpTextTool *text_tool,
|
|
|
|
GimpImage *image)
|
|
|
|
{
|
|
|
|
if (text_tool->image == image)
|
2008-10-27 03:54:27 +08:00
|
|
|
return;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text_tool->image)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2008-10-28 00:21:03 +08:00
|
|
|
g_signal_handlers_disconnect_by_func (text_tool->image,
|
|
|
|
gimp_text_tool_layer_changed,
|
|
|
|
text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_object_remove_weak_pointer (G_OBJECT (text_tool->image),
|
|
|
|
(gpointer) &text_tool->image);
|
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-18 16:12:26 +08:00
|
|
|
text_tool->image = image;
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (image)
|
|
|
|
{
|
|
|
|
GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
|
|
|
|
gdouble xres;
|
|
|
|
gdouble yres;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
g_object_add_weak_pointer (G_OBJECT (text_tool->image),
|
|
|
|
(gpointer) &text_tool->image);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2020-03-26 07:33:11 +08:00
|
|
|
g_signal_connect_object (text_tool->image, "selected-layers-changed",
|
2008-10-28 00:21:03 +08:00
|
|
|
G_CALLBACK (gimp_text_tool_layer_changed),
|
|
|
|
text_tool, 0);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-18 16:12:26 +08:00
|
|
|
gimp_image_get_resolution (image, &xres, &yres);
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (options->size_entry), 0,
|
|
|
|
yres, FALSE);
|
|
|
|
}
|
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_text_tool_set_drawable (GimpTextTool *text_tool,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
gboolean confirm)
|
|
|
|
{
|
|
|
|
GimpImage *image = NULL;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (text_tool->confirm_dialog)
|
|
|
|
gtk_widget_destroy (text_tool->confirm_dialog);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
if (drawable)
|
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_text_tool_set_image (text_tool, image);
|
|
|
|
|
|
|
|
if (GIMP_IS_TEXT_LAYER (drawable) && GIMP_TEXT_LAYER (drawable)->text)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2008-10-28 00:21:03 +08:00
|
|
|
GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable);
|
|
|
|
|
|
|
|
if (layer == text_tool->layer && layer->text == text_tool->text)
|
|
|
|
return TRUE;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
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;
|
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_text_tool_connect (text_tool, NULL, NULL);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
return FALSE;
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
2010-02-18 04:39:33 +08:00
|
|
|
static void
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
gimp_text_tool_block_drawing (GimpTextTool *text_tool)
|
|
|
|
{
|
2018-09-06 23:09:01 +08:00
|
|
|
if (text_tool->drawing_blocked == 0)
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
{
|
|
|
|
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
|
|
|
|
|
|
|
|
gimp_text_tool_clear_layout (text_tool);
|
|
|
|
}
|
2018-09-06 23:09:01 +08:00
|
|
|
|
|
|
|
text_tool->drawing_blocked++;
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_text_tool_unblock_drawing (GimpTextTool *text_tool)
|
|
|
|
{
|
2018-09-06 23:09:01 +08:00
|
|
|
g_return_if_fail (text_tool->drawing_blocked > 0);
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
|
2018-09-06 23:09:01 +08:00
|
|
|
text_tool->drawing_blocked--;
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
|
2018-09-06 23:09:01 +08:00
|
|
|
if (text_tool->drawing_blocked == 0)
|
|
|
|
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
|
app: fix text tool drawing for good this time (hopefully)
Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).
Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.
Therefore:
- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
can be called as many times as needed, and a single unblock()
enables drawing again. block() also clears the layout, because it
served its purpose (it was just used to pause drawing, and we know
the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
the callback, so we undraw stuff and kill the cached layout before
any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
the text and the buffer are in sync again, the tool is undrawn and
we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
2010-03-05 06:47:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_text_tool_buffer_begin_edit (GimpTextBuffer *buffer,
|
|
|
|
GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
gimp_text_tool_block_drawing (text_tool);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_text_tool_buffer_end_edit (GimpTextBuffer *buffer,
|
|
|
|
GimpTextTool *text_tool)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
|
|
|
if (text_tool->text)
|
|
|
|
{
|
2010-03-03 04:54:24 +08:00
|
|
|
gchar *string;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-03-03 04:54:24 +08:00
|
|
|
if (gimp_text_buffer_has_markup (buffer))
|
|
|
|
{
|
|
|
|
string = gimp_text_buffer_get_markup (buffer);
|
|
|
|
|
|
|
|
g_object_set (text_tool->proxy,
|
|
|
|
"markup", string,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
string = gimp_text_buffer_get_text (buffer);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-03-03 04:54:24 +08:00
|
|
|
g_object_set (text_tool->proxy,
|
|
|
|
"text", string,
|
|
|
|
NULL);
|
|
|
|
}
|
2010-03-01 00:15:06 +08:00
|
|
|
|
2010-03-03 04:54:24 +08:00
|
|
|
g_free (string);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_text_tool_create_layer (text_tool, NULL);
|
|
|
|
}
|
2018-09-06 23:09:01 +08:00
|
|
|
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
2018-03-23 21:19:01 +08:00
|
|
|
static void
|
|
|
|
gimp_text_tool_buffer_color_applied (GimpTextBuffer *buffer,
|
|
|
|
const GimpRGB *color,
|
|
|
|
GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
gimp_palettes_add_color_history (GIMP_TOOL (text_tool)->tool_info->gimp,
|
|
|
|
color);
|
|
|
|
}
|
|
|
|
|
2010-02-26 08:36:31 +08:00
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
2010-02-18 04:23:15 +08:00
|
|
|
void
|
2010-02-24 06:14:09 +08:00
|
|
|
gimp_text_tool_clear_layout (GimpTextTool *text_tool)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&text_tool->layout);
|
2010-02-24 06:14:09 +08:00
|
|
|
}
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-10-14 17:01:16 +08:00
|
|
|
gboolean
|
2010-02-24 06:14:09 +08:00
|
|
|
gimp_text_tool_ensure_layout (GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
if (! text_tool->layout && text_tool->text)
|
|
|
|
{
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (text_tool->layer));
|
2011-03-18 09:31:20 +08:00
|
|
|
gdouble xres;
|
|
|
|
gdouble yres;
|
2013-08-30 23:16:44 +08:00
|
|
|
GError *error = NULL;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2011-03-18 09:31:20 +08:00
|
|
|
gimp_image_get_resolution (image, &xres, &yres);
|
|
|
|
|
|
|
|
text_tool->layout = gimp_text_layout_new (text_tool->layer->text,
|
2013-08-30 23:16:44 +08:00
|
|
|
xres, yres, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
}
|
2010-02-19 19:21:03 +08:00
|
|
|
}
|
2010-10-14 17:01:16 +08:00
|
|
|
|
|
|
|
return text_tool->layout != NULL;
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
2018-09-06 23:09:01 +08:00
|
|
|
void
|
2016-06-06 03:06:29 +08:00
|
|
|
gimp_text_tool_apply (GimpTextTool *text_tool,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
const GParamSpec *pspec = NULL;
|
|
|
|
GimpImage *image;
|
|
|
|
GimpTextLayer *layer;
|
|
|
|
GList *list;
|
|
|
|
gboolean undo_group = FALSE;
|
|
|
|
|
|
|
|
if (text_tool->idle_id)
|
|
|
|
{
|
|
|
|
g_source_remove (text_tool->idle_id);
|
|
|
|
text_tool->idle_id = 0;
|
2018-09-06 23:09:01 +08:00
|
|
|
|
|
|
|
gimp_text_tool_unblock_drawing (text_tool);
|
2016-06-06 03:06:29 +08:00
|
|
|
}
|
|
|
|
|
2018-09-06 23:09:01 +08:00
|
|
|
g_return_if_fail (text_tool->text != NULL);
|
|
|
|
g_return_if_fail (text_tool->layer != NULL);
|
2016-06-06 03:06:29 +08:00
|
|
|
|
|
|
|
layer = text_tool->layer;
|
|
|
|
image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
|
2018-09-06 23:09:01 +08:00
|
|
|
g_return_if_fail (layer->text == text_tool->text);
|
2016-06-06 03:06:29 +08:00
|
|
|
|
|
|
|
/* 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 */;
|
|
|
|
|
|
|
|
if (g_list_length (list) == 1)
|
|
|
|
pspec = list->data;
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
GimpContext *context;
|
|
|
|
|
|
|
|
context = GIMP_CONTEXT (gimp_tool_get_options (tool));
|
|
|
|
|
|
|
|
push_undo = FALSE;
|
|
|
|
gimp_undo_reset_age (undo);
|
|
|
|
gimp_undo_refresh_preview (undo, context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
{
|
|
|
|
if (layer->modified)
|
|
|
|
{
|
|
|
|
undo_group = TRUE;
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_TEXT, NULL);
|
|
|
|
|
|
|
|
gimp_image_undo_push_text_layer_modified (image, NULL, layer);
|
|
|
|
|
|
|
|
/* see comment in gimp_text_layer_set() */
|
|
|
|
gimp_image_undo_push_drawable_mod (image, NULL,
|
|
|
|
GIMP_DRAWABLE (layer), TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_image_undo_push_text_layer (image, NULL, layer, pspec);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_text_tool_apply_list (text_tool, list);
|
|
|
|
|
|
|
|
g_list_free (text_tool->pending);
|
|
|
|
text_tool->pending = NULL;
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
{
|
|
|
|
g_object_set (layer, "modified", FALSE, NULL);
|
|
|
|
|
|
|
|
if (undo_group)
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_text_tool_frame_item (text_tool);
|
|
|
|
|
|
|
|
gimp_image_flush (image);
|
|
|
|
}
|
|
|
|
|
2018-05-29 22:19:50 +08:00
|
|
|
gboolean
|
2010-02-17 20:08:53 +08:00
|
|
|
gimp_text_tool_set_layer (GimpTextTool *text_tool,
|
|
|
|
GimpLayer *layer)
|
|
|
|
{
|
2018-05-29 22:19:50 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_TEXT_TOOL (text_tool), FALSE);
|
|
|
|
g_return_val_if_fail (layer == NULL || GIMP_IS_LAYER (layer), FALSE);
|
2010-02-17 20:08:53 +08:00
|
|
|
|
2018-07-19 14:19:40 +08:00
|
|
|
if (layer == GIMP_LAYER (text_tool->layer))
|
|
|
|
return TRUE;
|
|
|
|
|
2017-06-28 21:40:38 +08:00
|
|
|
/* FIXME this function works, and I have no clue why: first we set
|
|
|
|
* the drawable, then we HALT the tool and start() it without
|
|
|
|
* re-setting the drawable. Why this works perfectly anyway when
|
|
|
|
* double clicking a text layer in the layers dialog... no idea.
|
|
|
|
*/
|
2010-02-17 20:08:53 +08:00
|
|
|
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;
|
|
|
|
|
|
|
|
context = gimp_get_user_context (tool->tool_info->gimp);
|
|
|
|
display = gimp_context_get_display (context);
|
|
|
|
|
|
|
|
if (! display ||
|
|
|
|
gimp_display_get_image (display) != gimp_item_get_image (item))
|
|
|
|
{
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
display = NULL;
|
|
|
|
|
|
|
|
for (list = gimp_get_display_iter (tool->tool_info->gimp);
|
|
|
|
list;
|
|
|
|
list = g_list_next (list))
|
|
|
|
{
|
|
|
|
display = list->data;
|
|
|
|
|
|
|
|
if (gimp_display_get_image (display) == gimp_item_get_image (item))
|
|
|
|
{
|
|
|
|
gimp_context_set_display (context, display);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
display = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tool->display)
|
2017-06-28 21:40:38 +08:00
|
|
|
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, tool->display);
|
|
|
|
|
|
|
|
if (display)
|
2010-02-17 20:08:53 +08:00
|
|
|
{
|
2018-05-29 22:19:50 +08:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (! gimp_text_tool_start (text_tool, display, layer, &error))
|
|
|
|
{
|
|
|
|
gimp_text_tool_set_drawable (text_tool, NULL, FALSE);
|
|
|
|
|
|
|
|
gimp_tool_message_literal (tool, display, error->message);
|
|
|
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2010-02-17 20:08:53 +08:00
|
|
|
|
2020-05-25 17:30:31 +08:00
|
|
|
g_list_free (tool->drawables);
|
|
|
|
tool->drawables = g_list_prepend (NULL, GIMP_DRAWABLE (layer));
|
2010-02-17 20:08:53 +08:00
|
|
|
}
|
|
|
|
}
|
2018-05-29 22:19:50 +08:00
|
|
|
|
|
|
|
return TRUE;
|
2010-02-17 20:08:53 +08:00
|
|
|
}
|
|
|
|
|
2008-10-27 01:39:55 +08:00
|
|
|
gboolean
|
|
|
|
gimp_text_tool_get_has_text_selection (GimpTextTool *text_tool)
|
|
|
|
{
|
2010-02-26 00:49:33 +08:00
|
|
|
GtkTextBuffer *buffer = GTK_TEXT_BUFFER (text_tool->buffer);
|
2010-02-26 00:41:10 +08:00
|
|
|
|
|
|
|
return gtk_text_buffer_get_has_selection (buffer);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
2008-10-28 00:21:03 +08:00
|
|
|
void
|
2009-06-24 19:51:25 +08:00
|
|
|
gimp_text_tool_delete_selection (GimpTextTool *text_tool)
|
2008-10-28 00:21:03 +08:00
|
|
|
{
|
2010-02-26 00:49:33 +08:00
|
|
|
GtkTextBuffer *buffer = GTK_TEXT_BUFFER (text_tool->buffer);
|
2010-02-26 00:41:10 +08:00
|
|
|
|
|
|
|
if (gtk_text_buffer_get_has_selection (buffer))
|
2008-10-28 00:21:03 +08:00
|
|
|
{
|
2010-02-26 00:41:10 +08:00
|
|
|
gtk_text_buffer_delete_selection (buffer, TRUE, TRUE);
|
2008-10-28 00:21:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-27 01:39:55 +08:00
|
|
|
void
|
2009-06-28 03:51:52 +08:00
|
|
|
gimp_text_tool_cut_clipboard (GimpTextTool *text_tool)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2009-10-06 01:58:03 +08:00
|
|
|
GimpDisplayShell *shell;
|
|
|
|
GtkClipboard *clipboard;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2009-06-28 03:51:52 +08:00
|
|
|
g_return_if_fail (GIMP_IS_TEXT_TOOL (text_tool));
|
|
|
|
|
2009-10-06 01:58:03 +08:00
|
|
|
shell = gimp_display_get_shell (GIMP_TOOL (text_tool)->display);
|
|
|
|
|
|
|
|
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (shell),
|
2008-10-27 01:39:55 +08:00
|
|
|
GDK_SELECTION_CLIPBOARD);
|
2010-02-20 23:18:41 +08:00
|
|
|
|
2010-02-26 00:49:33 +08:00
|
|
|
gtk_text_buffer_cut_clipboard (GTK_TEXT_BUFFER (text_tool->buffer),
|
2010-02-26 00:41:10 +08:00
|
|
|
clipboard, TRUE);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-06-28 03:51:52 +08:00
|
|
|
gimp_text_tool_copy_clipboard (GimpTextTool *text_tool)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2009-10-06 01:58:03 +08:00
|
|
|
GimpDisplayShell *shell;
|
|
|
|
GtkClipboard *clipboard;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2009-06-28 03:51:52 +08:00
|
|
|
g_return_if_fail (GIMP_IS_TEXT_TOOL (text_tool));
|
|
|
|
|
2009-10-06 01:58:03 +08:00
|
|
|
shell = gimp_display_get_shell (GIMP_TOOL (text_tool)->display);
|
|
|
|
|
|
|
|
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (shell),
|
2009-06-28 03:51:52 +08:00
|
|
|
GDK_SELECTION_CLIPBOARD);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-03-05 17:53:09 +08:00
|
|
|
/* need to block "end-user-action" on the text buffer, because
|
|
|
|
* GtkTextBuffer considers copying text to the clipboard an
|
|
|
|
* undo-relevant user action, which is clearly a bug, but what
|
|
|
|
* can we do...
|
|
|
|
*/
|
|
|
|
g_signal_handlers_block_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_begin_edit,
|
|
|
|
text_tool);
|
|
|
|
g_signal_handlers_block_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_end_edit,
|
|
|
|
text_tool);
|
|
|
|
|
2010-02-26 00:49:33 +08:00
|
|
|
gtk_text_buffer_copy_clipboard (GTK_TEXT_BUFFER (text_tool->buffer),
|
2010-02-26 00:41:10 +08:00
|
|
|
clipboard);
|
2010-03-05 17:53:09 +08:00
|
|
|
|
|
|
|
g_signal_handlers_unblock_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_end_edit,
|
|
|
|
text_tool);
|
|
|
|
g_signal_handlers_unblock_by_func (text_tool->buffer,
|
|
|
|
gimp_text_tool_buffer_begin_edit,
|
|
|
|
text_tool);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-06-28 03:51:52 +08:00
|
|
|
gimp_text_tool_paste_clipboard (GimpTextTool *text_tool)
|
2008-10-27 01:39:55 +08:00
|
|
|
{
|
2009-10-06 01:58:03 +08:00
|
|
|
GimpDisplayShell *shell;
|
|
|
|
GtkClipboard *clipboard;
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2009-06-28 03:51:52 +08:00
|
|
|
g_return_if_fail (GIMP_IS_TEXT_TOOL (text_tool));
|
|
|
|
|
2009-10-06 01:58:03 +08:00
|
|
|
shell = gimp_display_get_shell (GIMP_TOOL (text_tool)->display);
|
|
|
|
|
|
|
|
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (shell),
|
2009-06-28 03:51:52 +08:00
|
|
|
GDK_SELECTION_CLIPBOARD);
|
2008-10-27 01:39:55 +08:00
|
|
|
|
2010-02-26 00:49:33 +08:00
|
|
|
gtk_text_buffer_paste_clipboard (GTK_TEXT_BUFFER (text_tool->buffer),
|
2010-02-26 00:41:10 +08:00
|
|
|
clipboard, NULL, TRUE);
|
2008-10-27 01:39:55 +08:00
|
|
|
}
|
2008-10-28 00:21:03 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-11-03 07:03:29 +08:00
|
|
|
gimp_item_get_offset (GIMP_ITEM (text_tool->layer), &x, &y);
|
2008-10-28 00:21:03 +08:00
|
|
|
gimp_item_translate (GIMP_ITEM (vectors), x, y, FALSE);
|
|
|
|
}
|
|
|
|
|
2009-08-04 04:30:36 +08:00
|
|
|
gimp_image_add_vectors (text_tool->image, vectors,
|
|
|
|
GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
2008-10-28 00:21:03 +08:00
|
|
|
|
|
|
|
gimp_image_flush (text_tool->image);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_text_tool_create_vectors_warped (GimpTextTool *text_tool)
|
|
|
|
{
|
2018-09-03 11:19:05 +08:00
|
|
|
GimpVectors *vectors0;
|
|
|
|
GimpVectors *vectors;
|
|
|
|
gdouble box_width;
|
|
|
|
gdouble box_height;
|
|
|
|
GimpTextDirection dir;
|
2018-09-06 22:59:44 +08:00
|
|
|
gdouble offset = 0.0;
|
2008-10-28 00:21:03 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_TEXT_TOOL (text_tool));
|
|
|
|
|
|
|
|
if (! text_tool->text || ! text_tool->image || ! text_tool->layer)
|
|
|
|
return;
|
|
|
|
|
2018-09-03 11:19:05 +08:00
|
|
|
box_width = gimp_item_get_width (GIMP_ITEM (text_tool->layer));
|
2008-11-03 08:09:01 +08:00
|
|
|
box_height = gimp_item_get_height (GIMP_ITEM (text_tool->layer));
|
2008-10-28 00:21:03 +08:00
|
|
|
|
|
|
|
vectors0 = gimp_image_get_active_vectors (text_tool->image);
|
|
|
|
if (! vectors0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
vectors = gimp_text_vectors_new (text_tool->image, text_tool->text);
|
|
|
|
|
2018-09-06 07:37:58 +08:00
|
|
|
offset = 0;
|
2018-09-03 11:19:05 +08:00
|
|
|
dir = gimp_text_tool_get_direction (text_tool);
|
|
|
|
switch (dir)
|
|
|
|
{
|
|
|
|
case GIMP_TEXT_DIRECTION_LTR:
|
|
|
|
case GIMP_TEXT_DIRECTION_RTL:
|
|
|
|
offset = 0.5 * box_height;
|
|
|
|
break;
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_RTL:
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_LTR:
|
|
|
|
case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
|
|
|
|
{
|
2018-09-06 07:37:58 +08:00
|
|
|
GimpStroke *stroke = NULL;
|
|
|
|
|
|
|
|
while ((stroke = gimp_vectors_stroke_get_next (vectors, stroke)))
|
|
|
|
{
|
|
|
|
gimp_stroke_rotate (stroke, 0, 0, 270);
|
|
|
|
gimp_stroke_translate (stroke, 0, box_width);
|
|
|
|
}
|
2018-09-03 11:19:05 +08:00
|
|
|
}
|
|
|
|
offset = 0.5 * box_width;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_vectors_warp_vectors (vectors0, vectors, offset);
|
2008-10-28 00:21:03 +08:00
|
|
|
|
2010-02-18 16:12:26 +08:00
|
|
|
gimp_item_set_visible (GIMP_ITEM (vectors), TRUE, FALSE);
|
|
|
|
|
2009-08-04 04:30:36 +08:00
|
|
|
gimp_image_add_vectors (text_tool->image, vectors,
|
|
|
|
GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
|
2008-10-28 00:21:03 +08:00
|
|
|
|
|
|
|
gimp_image_flush (text_tool->image);
|
|
|
|
}
|
2018-07-29 12:57:38 +08:00
|
|
|
|
|
|
|
GimpTextDirection
|
|
|
|
gimp_text_tool_get_direction (GimpTextTool *text_tool)
|
|
|
|
{
|
|
|
|
GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (text_tool);
|
|
|
|
return options->base_dir;
|
|
|
|
}
|