* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#include <config.h>
#include <string.h>
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
#include "gtktextview.h"
#include "gtkimmulticontext.h"
#include "gdk/gdkkeysyms.h"
+#include "gtkprivate.h"
#include "gtksizegroup.h" /* FIXME http://bugzilla.gnome.org/show_bug.cgi?id=72258 */
#include "gtktextutil.h"
#include "gtkwindow.h"
PROP_CURSOR_VISIBLE,
PROP_BUFFER,
PROP_OVERWRITE,
+ PROP_ACCEPTS_TAB,
LAST_PROP
};
GtkWidget *child);
static void gtk_text_view_forall (GtkContainer *container,
gboolean include_internals,
- GtkCallback callback,
+ GtkCallback callback,
gpointer callback_data);
/* FIXME probably need the focus methods. */
g_object_class_install_property (gobject_class,
PROP_PIXELS_ABOVE_LINES,
g_param_spec_int ("pixels_above_lines",
- _("Pixels Above Lines"),
- _("Pixels of blank space above paragraphs"),
+ P_("Pixels Above Lines"),
+ P_("Pixels of blank space above paragraphs"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_PIXELS_BELOW_LINES,
g_param_spec_int ("pixels_below_lines",
- _("Pixels Below Lines"),
- _("Pixels of blank space below paragraphs"),
+ P_("Pixels Below Lines"),
+ P_("Pixels of blank space below paragraphs"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_PIXELS_INSIDE_WRAP,
g_param_spec_int ("pixels_inside_wrap",
- _("Pixels Inside Wrap"),
- _("Pixels of blank space between wrapped lines in a paragraph"),
+ P_("Pixels Inside Wrap"),
+ P_("Pixels of blank space between wrapped lines in a paragraph"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_EDITABLE,
g_param_spec_boolean ("editable",
- _("Editable"),
- _("Whether the text can be modified by the user"),
+ P_("Editable"),
+ P_("Whether the text can be modified by the user"),
TRUE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_WRAP_MODE,
g_param_spec_enum ("wrap_mode",
- _("Wrap Mode"),
- _("Whether to wrap lines never, at word boundaries, or at character boundaries"),
+ P_("Wrap Mode"),
+ P_("Whether to wrap lines never, at word boundaries, or at character boundaries"),
GTK_TYPE_WRAP_MODE,
GTK_WRAP_NONE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_JUSTIFICATION,
g_param_spec_enum ("justification",
- _("Justification"),
- _("Left, right, or center justification"),
+ P_("Justification"),
+ P_("Left, right, or center justification"),
GTK_TYPE_JUSTIFICATION,
GTK_JUSTIFY_LEFT,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_LEFT_MARGIN,
g_param_spec_int ("left_margin",
- _("Left Margin"),
- _("Width of the left margin in pixels"),
+ P_("Left Margin"),
+ P_("Width of the left margin in pixels"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_RIGHT_MARGIN,
g_param_spec_int ("right_margin",
- _("Right Margin"),
- _("Width of the right margin in pixels"),
+ P_("Right Margin"),
+ P_("Width of the right margin in pixels"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_INDENT,
g_param_spec_int ("indent",
- _("Indent"),
- _("Amount to indent the paragraph, in pixels"),
+ P_("Indent"),
+ P_("Amount to indent the paragraph, in pixels"),
0,
G_MAXINT,
0,
g_object_class_install_property (gobject_class,
PROP_TABS,
g_param_spec_boxed ("tabs",
- _("Tabs"),
- _("Custom tabs for this text"),
+ P_("Tabs"),
+ P_("Custom tabs for this text"),
PANGO_TYPE_TAB_ARRAY,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_CURSOR_VISIBLE,
g_param_spec_boolean ("cursor_visible",
- _("Cursor Visible"),
- _("If the insertion cursor is shown"),
+ P_("Cursor Visible"),
+ P_("If the insertion cursor is shown"),
TRUE,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_BUFFER,
g_param_spec_object ("buffer",
- _("Buffer"),
- _("The buffer which is displayed"),
+ P_("Buffer"),
+ P_("The buffer which is displayed"),
GTK_TYPE_TEXT_BUFFER,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_OVERWRITE,
g_param_spec_boolean ("overwrite",
- _("Overwrite mode"),
- _("Whether entered text overwrites existing contents"),
+ P_("Overwrite mode"),
+ P_("Whether entered text overwrites existing contents"),
FALSE,
G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
+ PROP_ACCEPTS_TAB,
+ g_param_spec_boolean ("accepts_tab",
+ P_("Accepts tab"),
+ P_("Whether Tab will result in a tab character being entered"),
+ TRUE,
+ G_PARAM_READWRITE));
+
+ /*
+ * Style properties
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_boxed ("error-underline-color",
+ P_("Error underline color"),
+ P_("Color with which to draw error-indication underlines"),
+ GDK_TYPE_COLOR,
+ G_PARAM_READABLE));
/*
* Signals
text_view->cursor_visible = TRUE;
+ text_view->accepts_tab = TRUE;
+
text_view->text_window = text_window_new (GTK_TEXT_WINDOW_TEXT,
widget, 200, 200);
gtk_text_view_set_buffer (text_view, GTK_TEXT_BUFFER (g_value_get_object (value)));
break;
+ case PROP_ACCEPTS_TAB:
+ gtk_text_view_set_accepts_tab (text_view, g_value_get_boolean (value));
+ break;
+
default:
g_assert_not_reached ();
break;
case PROP_OVERWRITE:
g_value_set_boolean (value, text_view->overwrite_mode);
break;
+
+ case PROP_ACCEPTS_TAB:
+ g_value_set_boolean (value, text_view->accepts_tab);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
&child_loc,
child->anchor);
+ /* Since anchored children are only ever allocated from
+ * gtk_text_layout_get_line_display() we have to make sure
+ * that the display line caching in the layout doesn't
+ * get in the way. Invalidating the layout around the anchor
+ * achieves this.
+ */
+ if (GTK_WIDGET_ALLOC_NEEDED (child->widget))
+ {
+ GtkTextIter end = child_loc;
+ gtk_text_iter_forward_char (&end);
+ gtk_text_layout_invalidate (text_view->layout, &child_loc, &end);
+ }
+
gtk_text_layout_validate_yrange (text_view->layout,
&child_loc,
0, 1);
event->keyval == GDK_KP_Tab) &&
!(event->state & GDK_CONTROL_MASK))
{
- /* If the text widget isn't editable overall, move the focus
- * instead
+ /* If the text widget isn't editable overall, or if the application
+ * has turned off "accepts_tab", move the focus instead
*/
- if (text_view->editable)
+ if (text_view->accepts_tab && text_view->editable)
{
gtk_text_view_commit_text (text_view, "\t");
obscure = TRUE;
while (tmp_list != NULL)
{
GtkWidget *child = tmp_list->data;
-
+
gtk_container_propagate_expose (GTK_CONTAINER (text_view),
child,
event);
case GTK_MOVEMENT_WORDS:
if (count < 0)
gtk_text_iter_backward_visible_word_starts (&newplace, -count);
- else if (count > 0)
- gtk_text_iter_forward_visible_word_ends (&newplace, count);
+ else if (count > 0)
+ {
+ if (!gtk_text_iter_forward_visible_word_ends (&newplace, count))
+ gtk_text_iter_forward_to_end (&newplace);
+ }
break;
case GTK_MOVEMENT_DISPLAY_LINES:
}
}
+/**
+ * gtk_text_view_set_accepts_tab:
+ * @text_view: A #GtkTextView
+ * @accepts_tab: %TRUE if pressing the Tab key should insert a tab character, %FALSE, if pressing the Tab key should move the keyboard focus.
+ *
+ * Sets the behavior of the text widget when the Tab key is pressed. If @accepts_tab
+ * is %TRUE a tab character is inserted. If @accepts_tab is %FALSE the keyboard focus
+ * is moved to the next widget in the focus chain.
+ *
+ * Since: 2.4
+ **/
+void
+gtk_text_view_set_accepts_tab (GtkTextView *text_view,
+ gboolean accepts_tab)
+{
+ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+
+ accepts_tab = accepts_tab != FALSE;
+
+ if (text_view->accepts_tab != accepts_tab)
+ {
+ text_view->accepts_tab = accepts_tab;
+
+ g_object_notify (G_OBJECT (text_view), "accepts_tab");
+ }
+}
+
+/**
+ * gtk_text_view_get_accepts_tab:
+ * @text_view: A #GtkTextView
+ *
+ * Returns whether pressing the Tab key inserts a tab characters.
+ * gtk_text_view_set_accepts_tab().
+ *
+ * Return value: %TRUE if pressing the Tab key inserts a tab character, %FALSE if pressing the Tab key moves the keyboard focus.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_text_view_get_accepts_tab (GtkTextView *text_view)
+{
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+
+ return text_view->accepts_tab;
+}
+
static void
gtk_text_view_move_focus (GtkTextView *text_view,
GtkDirectionType direction_type)
gtk_text_iter_backward_visible_word_start (start);
if (!gtk_text_iter_ends_word (end))
- gtk_text_iter_forward_visible_word_end (end);
+ {
+ if (!gtk_text_iter_forward_visible_word_end (end))
+ gtk_text_iter_forward_to_end (end);
+ }
}
else
extend = FALSE;
{
if (text_view->layout)
{
- gboolean split_cursor;
- GtkTextDirection new_dir;
GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
-
+ GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
+ GtkTextDirection new_cursor_dir;
+ GtkTextDirection new_keyboard_dir;
+ gboolean split_cursor;
+
g_object_get (settings,
"gtk-split-cursor", &split_cursor,
NULL);
+
+ if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR)
+ new_keyboard_dir = GTK_TEXT_DIR_LTR;
+ else
+ new_keyboard_dir = GTK_TEXT_DIR_RTL;
+
if (split_cursor)
- {
- new_dir = GTK_TEXT_DIR_NONE;
- }
+ new_cursor_dir = GTK_TEXT_DIR_NONE;
else
- {
- GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
- new_dir = (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ?
- GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
- }
+ new_cursor_dir = new_keyboard_dir;
- if (text_view->layout->cursor_direction != new_dir)
- gtk_text_layout_set_cursor_direction (text_view->layout, new_dir);
+ gtk_text_layout_set_cursor_direction (text_view->layout, new_cursor_dir);
+ gtk_text_layout_set_keyboard_direction (text_view->layout, new_keyboard_dir);
}
}
GtkTextIter drop_point;
GtkTextView *text_view;
gboolean success = FALSE;
+ GtkTextBuffer *buffer = NULL;
text_view = GTK_TEXT_VIEW (widget);
if (!text_view->dnd_mark)
goto done;
- gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
+ buffer = get_buffer (text_view);
+
+ gtk_text_buffer_get_iter_at_mark (buffer,
&drop_point,
text_view->dnd_mark);
if (!gtk_text_iter_can_insert (&drop_point, text_view->editable))
goto done;
+ success = TRUE;
+
+ gtk_text_buffer_begin_user_action (buffer);
+
if (selection_data->target == gdk_atom_intern ("GTK_TEXT_BUFFER_CONTENTS", FALSE))
{
GtkTextBuffer *src_buffer = NULL;
g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
if (gtk_text_buffer_get_tag_table (src_buffer) !=
- gtk_text_buffer_get_tag_table (get_buffer (text_view)))
+ gtk_text_buffer_get_tag_table (buffer))
copy_tags = FALSE;
if (gtk_text_buffer_get_selection_bounds (src_buffer,
&end))
{
if (copy_tags)
- gtk_text_buffer_insert_range_interactive (get_buffer (text_view),
+ gtk_text_buffer_insert_range_interactive (buffer,
&drop_point,
&start,
&end,
gchar *str;
str = gtk_text_iter_get_visible_text (&start, &end);
- gtk_text_buffer_insert_interactive (get_buffer (text_view),
+ gtk_text_buffer_insert_interactive (buffer,
&drop_point, str, -1,
text_view->editable);
g_free (str);
}
else
insert_text_data (text_view, &drop_point, selection_data);
-
- gtk_text_buffer_place_cursor (get_buffer (text_view), &drop_point);
-
- success = TRUE;
-
+
done:
gtk_drag_finish (context, success,
success && context->action == GDK_ACTION_MOVE,
time);
+
+ if (success)
+ {
+ gtk_text_buffer_get_iter_at_mark (buffer,
+ &drop_point,
+ text_view->dnd_mark);
+ gtk_text_buffer_place_cursor (buffer, &drop_point);
+
+ gtk_text_buffer_end_user_action (buffer);
+ }
}
static GtkAdjustment*