diff --git a/gtk/gtktextbtree.c b/gtk/gtktextbtree.c index 82369f6a4c..691d77e26e 100644 --- a/gtk/gtktextbtree.c +++ b/gtk/gtktextbtree.c @@ -2532,6 +2532,10 @@ gtk_text_btree_remove_mark (GtkTextBTree *tree, if (segment->body.mark.name) g_hash_table_remove(tree->mark_table, segment->body.mark.name); mark_segment_unref(segment); + + segment->body.mark.tree = NULL; + segment->body.mark.line = NULL; + segments_changed(tree); } diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 860c598028..0726863b56 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -385,6 +385,44 @@ gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer, gtk_text_buffer_insert(buffer, &iter, text, len); } +gboolean +gtk_text_buffer_insert_interactive(GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + gboolean editable_by_default) +{ + g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE); + g_return_val_if_fail(text != NULL, FALSE); + + if (gtk_text_iter_editable (iter, editable_by_default)) + { + gtk_text_buffer_insert (buffer, iter, text, len); + return TRUE; + } + else + return FALSE; +} + +gboolean +gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer, + const gchar *text, + gint len, + gboolean default_editable) +{ + GtkTextIter iter; + + g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE); + g_return_val_if_fail(text != NULL, FALSE); + + gtk_text_buffer_get_iter_at_mark(buffer, &iter, + gtk_text_buffer_get_mark (buffer, + "insert")); + + return gtk_text_buffer_insert_interactive (buffer, &iter, text, len, + default_editable); +} + /* * Deletion */ @@ -397,7 +435,7 @@ gtk_text_buffer_real_delete_text(GtkTextBuffer *buffer, g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); g_return_if_fail(start != NULL); g_return_if_fail(end != NULL); - + gtk_text_btree_delete(start, end); /* may have deleted the selection... */ @@ -420,6 +458,8 @@ gtk_text_buffer_emit_delete(GtkTextBuffer *buffer, if (gtk_text_iter_equal(start, end)) return; + gtk_text_iter_reorder (start, end); + gtk_signal_emit(GTK_OBJECT(buffer), signals[DELETE_TEXT], start, end); @@ -437,6 +477,109 @@ gtk_text_buffer_delete (GtkTextBuffer *buffer, gtk_text_buffer_emit_delete(buffer, start, end); } +gboolean +gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer, + GtkTextIter *start_iter, + GtkTextIter *end_iter, + gboolean default_editable) +{ + GtkTextMark *end_mark; + GtkTextMark *start_mark; + GtkTextIter iter; + gboolean current_state; + gboolean deleted_stuff = FALSE; + + /* Delete all editable text in the range start_iter, end_iter */ + + g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), FALSE); + g_return_val_if_fail (start_iter != NULL, FALSE); + g_return_val_if_fail (end_iter != NULL, FALSE); + + gtk_text_iter_reorder (start_iter, end_iter); + + start_mark = gtk_text_buffer_create_mark (buffer, NULL, + start_iter, TRUE); + end_mark = gtk_text_buffer_create_mark (buffer, NULL, + end_iter, FALSE); + iter = *start_iter; + + current_state = gtk_text_iter_editable (&iter, default_editable); + + while (gtk_text_iter_forward_find_tag_toggle (&iter, NULL)) + { + gboolean new_state; + gboolean done = FALSE; + GtkTextIter end; + + gtk_text_buffer_get_iter_at_mark (buffer, &end, end_mark); + + if (gtk_text_iter_compare (&iter, &end) >= 0) + { + done = TRUE; + iter = end; /* clamp to the last boundary */ + } + + new_state = gtk_text_iter_editable (&iter, default_editable); + + if (current_state == new_state) + { + if (done) + { + if (current_state) + { + /* We're ending an editable region. Delete said region. */ + GtkTextIter start; + + gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark); + + gtk_text_buffer_delete (buffer, &start, &iter); + + deleted_stuff = TRUE; + } + + break; + } + else + continue; + } + + if (current_state && !new_state) + { + /* End of an editable region. Delete it. */ + GtkTextIter start; + + gtk_text_buffer_get_iter_at_mark (buffer, &start, start_mark); + + gtk_text_buffer_delete (buffer, &start, &iter); + + current_state = FALSE; + deleted_stuff = TRUE; + } + else + { + /* We are at the start of an editable region. We won't be deleting + * the previous region. Move start mark to start of this region. + */ + + g_assert (!current_state && new_state); + + gtk_text_buffer_move_mark (buffer, start_mark, + &iter); + + + current_state = TRUE; + } + + if (done) + break; + } + + gtk_text_buffer_delete_mark (buffer, start_mark); + gtk_text_buffer_delete_mark (buffer, end_mark); + + return deleted_stuff; +} + /* * Extracting textual buffer contents */ @@ -546,8 +689,6 @@ gtk_text_buffer_set_mark(GtkTextBuffer *buffer, GtkTextIter location; GtkTextMark *mark; - g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); - mark = gtk_text_btree_set_mark(buffer->tree, existing_mark, mark_name, @@ -576,6 +717,8 @@ gtk_text_buffer_create_mark(GtkTextBuffer *buffer, const GtkTextIter *where, gboolean left_gravity) { + g_return_val_if_fail(GTK_IS_TEXT_BUFFER(buffer), NULL); + return gtk_text_buffer_set_mark(buffer, NULL, mark_name, where, left_gravity, FALSE); } @@ -586,6 +729,8 @@ gtk_text_buffer_move_mark(GtkTextBuffer *buffer, const GtkTextIter *where) { g_return_if_fail (mark != NULL); + g_return_if_fail (!gtk_text_mark_deleted (mark)); + g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); gtk_text_buffer_set_mark(buffer, mark, NULL, where, FALSE, TRUE); } @@ -595,6 +740,8 @@ gtk_text_buffer_get_iter_at_mark(GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextMark *mark) { + g_return_if_fail (mark != NULL); + g_return_if_fail (!gtk_text_mark_deleted (mark)); g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); gtk_text_btree_get_iter_at_mark(buffer->tree, @@ -606,6 +753,8 @@ void gtk_text_buffer_delete_mark(GtkTextBuffer *buffer, GtkTextMark *mark) { + g_return_if_fail (mark != NULL); + g_return_if_fail (!gtk_text_mark_deleted (mark)); g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); gtk_text_btree_remove_mark (buffer->tree, mark); @@ -1186,8 +1335,12 @@ selection_received (GtkWidget *widget, utf = gtk_text_latin1_to_utf((const gchar*)selection_data->data, selection_data->length); - gtk_text_buffer_insert (buffer, &insert_point, - utf, -1); + if (buffer->paste_interactive) + gtk_text_buffer_insert_interactive (buffer, &insert_point, + utf, -1, buffer->paste_default_editable); + else + gtk_text_buffer_insert (buffer, &insert_point, + utf, -1); g_free(utf); } break; @@ -1216,8 +1369,13 @@ selection_received (GtkWidget *widget, gchar *utf; utf = gtk_text_latin1_to_utf(list[i], strlen(list[i])); - - gtk_text_buffer_insert(buffer, &insert_point, utf, -1); + + if (buffer->paste_interactive) + gtk_text_buffer_insert_interactive (buffer, &insert_point, + utf, -1, buffer->paste_default_editable); + else + gtk_text_buffer_insert (buffer, &insert_point, + utf, -1); g_free(utf); } @@ -1306,9 +1464,14 @@ gtk_text_buffer_update_clipboard_selection(GtkTextBuffer *buffer) } static void -paste(GtkTextBuffer *buffer, GdkAtom selection, guint32 time) +paste (GtkTextBuffer *buffer, GdkAtom selection, guint32 time, + gboolean interactive, + gboolean default_editable) { ensure_handlers(buffer); + + buffer->paste_interactive = interactive; + buffer->paste_default_editable = default_editable; gtk_selection_convert (buffer->selection_widget, selection, utf8_atom, time); @@ -1317,25 +1480,31 @@ paste(GtkTextBuffer *buffer, GdkAtom selection, guint32 time) void gtk_text_buffer_paste_primary_selection(GtkTextBuffer *buffer, GtkTextIter *override_location, - guint32 time) + guint32 time, + gboolean interactive, + gboolean default_editable) { if (override_location != NULL) gtk_text_buffer_create_mark(buffer, "__paste_point_override", override_location, FALSE); - paste(buffer, GDK_SELECTION_PRIMARY, time); + paste(buffer, GDK_SELECTION_PRIMARY, time, interactive, default_editable); } void gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer, - guint32 time) + guint32 time, + gboolean interactive, + gboolean default_editable) { - paste(buffer, clipboard_atom, time); + paste(buffer, clipboard_atom, time, interactive, default_editable); } gboolean -gtk_text_buffer_delete_selection (GtkTextBuffer *buffer) +gtk_text_buffer_delete_selection (GtkTextBuffer *buffer, + gboolean interactive, + gboolean default_editable) { GtkTextIter start; GtkTextIter end; @@ -1346,7 +1515,11 @@ gtk_text_buffer_delete_selection (GtkTextBuffer *buffer) } else { - gtk_text_buffer_delete(buffer, &start, &end); + if (interactive) + gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable); + else + gtk_text_buffer_delete (buffer, &start, &end); + gtk_text_buffer_update_primary_selection(buffer); return TRUE; /* We deleted stuff */ } @@ -1355,7 +1528,9 @@ gtk_text_buffer_delete_selection (GtkTextBuffer *buffer) static void cut_or_copy(GtkTextBuffer *buffer, guint32 time, - gboolean delete_region_after) + gboolean delete_region_after, + gboolean interactive, + gboolean default_editable) { /* We prefer to cut the selected region between selection_bound and insertion point. If that region is empty, then we cut the region @@ -1389,22 +1564,29 @@ cut_or_copy(GtkTextBuffer *buffer, set_clipboard_contents_nocopy(buffer, text); if (delete_region_after) - gtk_text_buffer_delete(buffer, &start, &end); + { + if (interactive) + gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable); + else + gtk_text_buffer_delete (buffer, &start, &end); + } } } void gtk_text_buffer_cut (GtkTextBuffer *buffer, - guint32 time) + guint32 time, + gboolean interactive, + gboolean default_editable) { - cut_or_copy(buffer, time, TRUE); + cut_or_copy(buffer, time, TRUE, interactive, default_editable); } void gtk_text_buffer_copy (GtkTextBuffer *buffer, guint32 time) { - cut_or_copy(buffer, time, FALSE); + cut_or_copy(buffer, time, FALSE, FALSE, TRUE); } diff --git a/gtk/gtktextbuffer.h b/gtk/gtktextbuffer.h index 27c2822cb0..7dcf1c929f 100644 --- a/gtk/gtktextbuffer.h +++ b/gtk/gtktextbuffer.h @@ -42,6 +42,8 @@ struct _GtkTextBuffer { GtkWidget *selection_widget; gboolean have_selection; gboolean selection_handlers_installed; + gboolean paste_interactive; + gboolean paste_default_editable; }; struct _GtkTextBufferClass { @@ -105,11 +107,27 @@ void gtk_text_buffer_insert_at_cursor (GtkTextBuffer *buffer, const gchar *text, gint len); -/* Delete from the buffer */ +gboolean gtk_text_buffer_insert_interactive (GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + gboolean default_editable); +gboolean gtk_text_buffer_insert_interactive_at_cursor (GtkTextBuffer *buffer, + const gchar *text, + gint len, + gboolean default_editable); + + +/* Delete from the buffer */ +void gtk_text_buffer_delete (GtkTextBuffer *buffer, + GtkTextIter *start_iter, + GtkTextIter *end_iter); +gboolean gtk_text_buffer_delete_interactive (GtkTextBuffer *buffer, + GtkTextIter *start_iter, + GtkTextIter *end_iter, + gboolean default_editable); + -void gtk_text_buffer_delete (GtkTextBuffer *buffer, - GtkTextIter *start_iter, - GtkTextIter *end_iter); /* Obtain strings from the buffer */ gchar *gtk_text_buffer_get_text (GtkTextBuffer *buffer, @@ -207,16 +225,26 @@ void gtk_text_buffer_set_modified (GtkTextBuffer *buffer, void gtk_text_buffer_set_clipboard_contents (GtkTextBuffer *buffer, const gchar *text); const gchar *gtk_text_buffer_get_clipboard_contents (GtkTextBuffer *buffer); + + void gtk_text_buffer_paste_primary_selection (GtkTextBuffer *buffer, GtkTextIter *override_location, - guint32 time); -gboolean gtk_text_buffer_delete_selection (GtkTextBuffer *buffer); + guint32 time, + gboolean interactive, + gboolean default_editable); +gboolean gtk_text_buffer_delete_selection (GtkTextBuffer *buffer, + gboolean interactive, + gboolean default_editable); void gtk_text_buffer_cut (GtkTextBuffer *buffer, - guint32 time); + guint32 time, + gboolean interactive, + gboolean default_editable); void gtk_text_buffer_copy (GtkTextBuffer *buffer, guint32 time); void gtk_text_buffer_paste_clipboard (GtkTextBuffer *buffer, - guint32 time); + guint32 time, + gboolean interactive, + gboolean default_editable); gboolean gtk_text_buffer_get_selection_bounds (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end); diff --git a/gtk/gtktextiter.c b/gtk/gtktextiter.c index c0c7386452..e5b5e09e7a 100644 --- a/gtk/gtktextiter.c +++ b/gtk/gtktextiter.c @@ -858,6 +858,26 @@ gtk_text_iter_has_tag (const GtkTextIter *iter, } } +gboolean +gtk_text_iter_editable (const GtkTextIter *iter, + gboolean default_setting) +{ + GtkTextStyleValues *values; + gboolean retval; + + values = gtk_text_style_values_new (); + + values->editable = default_setting; + + gtk_text_iter_get_style_values (iter, values); + + retval = values->editable; + + gtk_text_style_values_unref (values); + + return retval; +} + gboolean gtk_text_iter_starts_line (const GtkTextIter *iter) { @@ -933,6 +953,37 @@ gtk_text_iter_get_chars_in_line (const GtkTextIter *iter) return count; } +gboolean +gtk_text_iter_get_style_values (const GtkTextIter *iter, + GtkTextStyleValues *values) +{ + GtkTextTag** tags; + gint tag_count = 0; + + /* Get the tags at this spot */ + tags = gtk_text_btree_get_tags (iter, &tag_count); + + /* No tags, use default style */ + if (tags == NULL || tag_count == 0) + { + if (tags) + g_free (tags); + + return FALSE; + } + + /* Sort tags in ascending order of priority */ + gtk_text_tag_array_sort (tags, tag_count); + + gtk_text_style_values_fill_from_tags (values, + tags, + tag_count); + + g_free (tags); + + return TRUE; +} + /* * Increments/decrements */ diff --git a/gtk/gtktextiter.h b/gtk/gtktextiter.h index 8aa06f6765..45d14ca44e 100644 --- a/gtk/gtktextiter.h +++ b/gtk/gtktextiter.h @@ -46,10 +46,12 @@ void gtk_text_iter_free (GtkTextIter *iter); /* * Convert to different kinds of index */ -gint gtk_text_buffer_get_offset (const GtkTextIter *iter); -gint gtk_text_iter_get_line (const GtkTextIter *iter); -gint gtk_text_iter_get_line_offset (const GtkTextIter *iter); -gint gtk_text_iter_get_line_index (const GtkTextIter *iter); + +gint gtk_text_buffer_get_offset (const GtkTextIter *iter); +gint gtk_text_iter_get_line (const GtkTextIter *iter); +gint gtk_text_iter_get_line_offset (const GtkTextIter *iter); +gint gtk_text_iter_get_line_index (const GtkTextIter *iter); + /* * "Dereference" operators @@ -72,19 +74,19 @@ gchar *gtk_text_iter_get_visible_text (const GtkTextIter *start, /* Returns TRUE if the iterator pointed at a pixmap */ gboolean gtk_text_iter_get_pixmap (const GtkTextIter *iter, - GdkPixmap **pixmap, - GdkBitmap **mask); + GdkPixmap **pixmap, + GdkBitmap **mask); /* Return list of tags toggled at this point (toggled_on determines whether the list is of on-toggles or off-toggles) */ GSList *gtk_text_iter_get_toggled_tags (const GtkTextIter *iter, - gboolean toggled_on); + gboolean toggled_on); gboolean gtk_text_iter_begins_tag (const GtkTextIter *iter, - GtkTextTag *tag); + GtkTextTag *tag); gboolean gtk_text_iter_ends_tag (const GtkTextIter *iter, - GtkTextTag *tag); + GtkTextTag *tag); gboolean gtk_text_iter_toggles_tag (const GtkTextIter *iter, GtkTextTag *tag); @@ -92,11 +94,17 @@ gboolean gtk_text_iter_toggles_tag (const GtkTextIter *iter, gboolean gtk_text_iter_has_tag (const GtkTextIter *iter, GtkTextTag *tag); +gboolean gtk_text_iter_editable (const GtkTextIter *iter, + gboolean default_setting); + gboolean gtk_text_iter_starts_line (const GtkTextIter *iter); gboolean gtk_text_iter_ends_line (const GtkTextIter *iter); gint gtk_text_iter_get_chars_in_line (const GtkTextIter *iter); +gboolean gtk_text_iter_get_style_values (const GtkTextIter *iter, + GtkTextStyleValues *values); + /* * Moving around the buffer */ @@ -120,25 +128,24 @@ gboolean gtk_text_iter_backward_word_starts (GtkTextIter *iter, gboolean gtk_text_iter_forward_word_end (GtkTextIter *iter); gboolean gtk_text_iter_backward_word_start (GtkTextIter *iter); +void gtk_text_iter_set_offset (GtkTextIter *iter, + gint char_index); +void gtk_text_iter_set_line (GtkTextIter *iter, + gint line_number); +void gtk_text_iter_set_line_offset (GtkTextIter *iter, + gint char_on_line); +void gtk_text_iter_forward_to_end (GtkTextIter *iter); +gboolean gtk_text_iter_forward_to_newline (GtkTextIter *iter); -void gtk_text_iter_set_offset (GtkTextIter *iter, - gint char_index); -void gtk_text_iter_set_line (GtkTextIter *iter, - gint line_number); -void gtk_text_iter_set_line_offset (GtkTextIter *iter, - gint char_on_line); - -void gtk_text_iter_forward_to_end (GtkTextIter *iter); -gboolean gtk_text_iter_forward_to_newline(GtkTextIter *iter); /* returns TRUE if a toggle was found; NULL for the tag pointer means "any tag toggle", otherwise the next toggle of the specified tag is located. */ gboolean gtk_text_iter_forward_find_tag_toggle (GtkTextIter *iter, - GtkTextTag *tag); + GtkTextTag *tag); gboolean gtk_text_iter_backward_find_tag_toggle (GtkTextIter *iter, - GtkTextTag *tag); + GtkTextTag *tag); typedef gboolean (* GtkTextCharPredicate) (gunichar ch, gpointer user_data); diff --git a/gtk/gtktextmark.c b/gtk/gtktextmark.c index 72cb4f1bab..f85ef0a6ba 100644 --- a/gtk/gtktextmark.c +++ b/gtk/gtktextmark.c @@ -35,6 +35,41 @@ gtk_text_mark_get_name (GtkTextMark *mark) return g_strdup (seg->body.mark.name); } + +GtkTextMark * +gtk_text_mark_ref (GtkTextMark *mark) +{ + GtkTextLineSegment *seg; + + seg = (GtkTextLineSegment*)mark; + + mark_segment_ref (seg); + + return mark; +} + +void +gtk_text_mark_unref (GtkTextMark *mark) +{ + GtkTextLineSegment *seg; + + seg = (GtkTextLineSegment*)mark; + + mark_segment_unref (seg); +} + +gboolean +gtk_text_mark_deleted (GtkTextMark *mark) +{ + GtkTextLineSegment *seg; + + g_return_val_if_fail (mark != NULL, FALSE); + + seg = (GtkTextLineSegment*)mark; + + return seg->body.mark.tree == NULL; +} + /* * Macro that determines the size of a mark segment: */ diff --git a/gtk/gtktextmark.h b/gtk/gtktextmark.h index 0fa2f0dd52..6a0e09224c 100644 --- a/gtk/gtktextmark.h +++ b/gtk/gtktextmark.h @@ -10,11 +10,16 @@ extern "C" { typedef struct _GtkTextMark GtkTextMark; void gtk_text_mark_set_visible (GtkTextMark *mark, - gboolean setting); + gboolean setting); gboolean gtk_text_mark_is_visible (GtkTextMark *mark); char * gtk_text_mark_get_name (GtkTextMark *mark); +GtkTextMark *gtk_text_mark_ref (GtkTextMark *mark); +void gtk_text_mark_unref (GtkTextMark *mark); + +gboolean gtk_text_mark_deleted (GtkTextMark *mark); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtktexttag.h b/gtk/gtktexttag.h index cbea91ecf5..30f43c2be2 100644 --- a/gtk/gtktexttag.h +++ b/gtk/gtktexttag.h @@ -103,6 +103,100 @@ gint gtk_text_tag_event (GtkTextTag *tag, GdkEvent *event, const GtkTextIter *iter); +/* + * Style object created by folding a set of tags together + */ + +typedef struct _GtkTextAppearance GtkTextAppearance; + +struct _GtkTextAppearance +{ + GdkColor bg_color; + GdkColor fg_color; + GdkBitmap *bg_stipple; + GdkBitmap *fg_stipple; + + guint underline : 4; /* PangoUnderline */ + guint overstrike : 1; + + /* Whether to use background-related values; this is irrelevant for + * the values struct when in a tag, but is used for the composite + * values struct; it's true if any of the tags being composited + * had background stuff set. */ + guint draw_bg : 1; + + /* This is only used when we are actually laying out and rendering + * a paragraph; not when a GtkTextAppearance is part of a + * GtkTextStyleValues. + */ + guint inside_selection : 1; +}; + +struct _GtkTextStyleValues +{ + guint refcount; + + GtkTextAppearance appearance; + + gint border_width; + GtkShadowType relief; + GtkJustification justify; + GtkTextDirection direction; + + PangoFontDescription *font_desc; + + /* lMargin1 */ + gint left_margin; + + /* lMargin2 */ + gint left_wrapped_line_margin; + + /* super/subscript offset, can be negative */ + gint offset; + + gint right_margin; + + gint pixels_above_lines; + + gint pixels_below_lines; + + gint pixels_inside_wrap; + + GtkTextTabArray *tab_array; + + GtkWrapMode wrap_mode; /* How to handle wrap-around for this tag. + * Must be GTK_WRAPMODE_CHAR, + * GTK_WRAPMODE_NONE, GTK_WRAPMODE_WORD + */ + + gchar *language; + + /* hide the text */ + guint invisible : 1; + + /* Background is fit to full line height rather than + * baseline +/- ascent/descent (font height) */ + guint bg_full_height : 1; + + /* can edit this text */ + guint editable : 1; + + /* colors are allocated etc. */ + guint realized : 1; + + guint pad1 : 1; + guint pad2 : 1; + guint pad3 : 1; + guint pad4 : 1; +}; + +GtkTextStyleValues *gtk_text_style_values_new (void); +void gtk_text_style_values_copy (GtkTextStyleValues *src, + GtkTextStyleValues *dest); +void gtk_text_style_values_unref (GtkTextStyleValues *values); +void gtk_text_style_values_ref (GtkTextStyleValues *values); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtktexttagprivate.h b/gtk/gtktexttagprivate.h index eee3f1951b..d8ec06fe8a 100644 --- a/gtk/gtktexttagprivate.h +++ b/gtk/gtktexttagprivate.h @@ -13,99 +13,6 @@ void gtk_text_style_values_fill_from_tags (GtkTextStyleValues *values, void gtk_text_tag_array_sort (GtkTextTag **tag_array_p, guint len); -/* - * Style object created by folding a set of tags together - */ - -typedef struct _GtkTextAppearance GtkTextAppearance; - -struct _GtkTextAppearance -{ - GdkColor bg_color; - GdkColor fg_color; - GdkBitmap *bg_stipple; - GdkBitmap *fg_stipple; - - guint underline : 4; /* PangoUnderline */ - guint overstrike : 1; - - /* Whether to use background-related values; this is irrelevant for - * the values struct when in a tag, but is used for the composite - * values struct; it's true if any of the tags being composited - * had background stuff set. */ - guint draw_bg : 1; - - /* This is only used when we are actually laying out and rendering - * a paragraph; not when a GtkTextAppearance is part of a - * GtkTextStyleValues. - */ - guint inside_selection : 1; -}; - -struct _GtkTextStyleValues -{ - guint refcount; - - GtkTextAppearance appearance; - - gint border_width; - GtkShadowType relief; - GtkJustification justify; - GtkTextDirection direction; - - PangoFontDescription *font_desc; - - /* lMargin1 */ - gint left_margin; - - /* lMargin2 */ - gint left_wrapped_line_margin; - - /* super/subscript offset, can be negative */ - gint offset; - - gint right_margin; - - gint pixels_above_lines; - - gint pixels_below_lines; - - gint pixels_inside_wrap; - - GtkTextTabArray *tab_array; - - GtkWrapMode wrap_mode; /* How to handle wrap-around for this tag. - * Must be GTK_WRAPMODE_CHAR, - * GTK_WRAPMODE_NONE, GTK_WRAPMODE_WORD - */ - - gchar *language; - - /* hide the text */ - guint invisible : 1; - - /* Background is fit to full line height rather than - * baseline +/- ascent/descent (font height) */ - guint bg_full_height : 1; - - /* can edit this text */ - guint editable : 1; - - /* colors are allocated etc. */ - guint realized : 1; - - guint pad1 : 1; - guint pad2 : 1; - guint pad3 : 1; - guint pad4 : 1; -}; - -GtkTextStyleValues *gtk_text_style_values_new (void); -void gtk_text_style_values_copy (GtkTextStyleValues *src, - GtkTextStyleValues *dest); -void gtk_text_style_values_unref (GtkTextStyleValues *values); -void gtk_text_style_values_ref (GtkTextStyleValues *values); - /* ensure colors are allocated, etc. for drawing */ void gtk_text_style_values_realize (GtkTextStyleValues *values, GdkColormap *cmap, diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index b80831465c..3005673704 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -610,6 +610,9 @@ gtk_text_view_init (GtkTextView *text_view) gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit", GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view); + + text_view->editable = TRUE; + text_view->cursor_visible = TRUE; } GtkWidget* @@ -932,6 +935,62 @@ gtk_text_view_get_wrap_mode (GtkTextView *text_view) return text_view->wrap_mode; } +void +gtk_text_view_set_editable (GtkTextView *text_view, + gboolean setting) +{ + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + + if (text_view->editable != setting) + { + text_view->editable = setting; + + if (text_view->layout) + { + text_view->layout->default_style->editable = text_view->editable; + gtk_text_layout_default_style_changed (text_view->layout); + } + } +} + +gboolean +gtk_text_view_get_editable (GtkTextView *text_view) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + + return text_view->editable; +} + +void +gtk_text_view_set_cursor_visible (GtkTextView *text_view, + gboolean setting) +{ + g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); + + if (text_view->cursor_visible != setting) + { + text_view->cursor_visible = setting; + + if (GTK_WIDGET_HAS_FOCUS (text_view)) + { + GtkTextMark *insert; + + insert = gtk_text_buffer_get_mark (text_view->buffer, + "insert"); + gtk_text_mark_set_visible (insert, text_view->cursor_visible); + } + } +} + +gboolean +gtk_text_view_get_cursor_visible (GtkTextView *text_view) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + + return text_view->cursor_visible; +} + + gboolean gtk_text_view_place_cursor_onscreen (GtkTextView *text_view) { @@ -1483,7 +1542,8 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event) return TRUE; else if (event->keyval == GDK_Return) { - gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1); + gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\n", 1, + text_view->editable); gtk_text_view_scroll_to_mark (text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), @@ -1553,7 +1613,9 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event) gtk_text_buffer_paste_primary_selection (text_view->buffer, &iter, - event->time); + event->time, + TRUE, + text_view->editable); return TRUE; } else if (event->button == 3) @@ -1589,7 +1651,7 @@ gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event) insert = gtk_text_buffer_get_mark (GTK_TEXT_VIEW (widget)->buffer, "insert"); - gtk_text_mark_set_visible (insert, TRUE); + gtk_text_mark_set_visible (insert, GTK_TEXT_VIEW (widget)->cursor_visible); gtk_text_view_start_cursor_blink (GTK_TEXT_VIEW (widget)); @@ -1968,7 +2030,8 @@ gtk_text_view_delete_text (GtkTextView *text_view, if (type == GTK_TEXT_DELETE_CHAR) { /* Char delete deletes the selection, if one exists */ - if (gtk_text_buffer_delete_selection (text_view->buffer)) + if (gtk_text_buffer_delete_selection (text_view->buffer, TRUE, + text_view->editable)) return; } @@ -2048,10 +2111,14 @@ gtk_text_view_delete_text (GtkTextView *text_view, if (!gtk_text_iter_equal (&start, &end)) { - gtk_text_buffer_delete (text_view->buffer, &start, &end); - - if (leave_one) - gtk_text_buffer_insert_at_cursor (text_view->buffer, " ", 1); + if (gtk_text_buffer_delete_interactive (text_view->buffer, &start, &end, + text_view->editable)) + { + if (leave_one) + gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, + " ", 1, + text_view->editable); + } gtk_text_view_scroll_to_mark (text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), @@ -2062,7 +2129,7 @@ gtk_text_view_delete_text (GtkTextView *text_view, static void gtk_text_view_cut_text (GtkTextView *text_view) { - gtk_text_buffer_cut (text_view->buffer, GDK_CURRENT_TIME); + gtk_text_buffer_cut (text_view->buffer, GDK_CURRENT_TIME, TRUE, text_view->editable); gtk_text_view_scroll_to_mark (text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), @@ -2082,7 +2149,7 @@ gtk_text_view_copy_text (GtkTextView *text_view) static void gtk_text_view_paste_text (GtkTextView *text_view) { - gtk_text_buffer_paste_clipboard (text_view->buffer, GDK_CURRENT_TIME); + gtk_text_buffer_paste_clipboard (text_view->buffer, GDK_CURRENT_TIME, TRUE, text_view->editable); gtk_text_view_scroll_to_mark (text_view, gtk_text_buffer_get_mark (text_view->buffer, "insert"), @@ -2561,9 +2628,10 @@ gtk_text_view_drag_data_get (GtkWidget *widget, static void gtk_text_view_drag_data_delete (GtkWidget *widget, - GdkDragContext *context) + GdkDragContext *context) { - gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer); + gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->buffer, + TRUE, GTK_TEXT_VIEW (widget)->editable); } static void @@ -2604,9 +2672,18 @@ gtk_text_view_drag_motion (GtkWidget *widget, } else { - gtk_text_mark_set_visible (text_view->dnd_mark, TRUE); - - gdk_drag_status (context, context->suggested_action, time); + if (gtk_text_iter_editable (&newplace, text_view->editable)) + { + gtk_text_mark_set_visible (text_view->dnd_mark, text_view->cursor_visible); + + gdk_drag_status (context, context->suggested_action, time); + } + else + { + /* Can't drop here. */ + gdk_drag_status (context, 0, time); + gtk_text_mark_set_visible (text_view->dnd_mark, FALSE); + } } gtk_text_buffer_move_mark (text_view->buffer, @@ -2706,16 +2783,18 @@ gtk_text_view_drag_data_received (GtkWidget *widget, utf = gtk_text_latin1_to_utf ((const gchar*)selection_data->data, selection_data->length); - gtk_text_buffer_insert (text_view->buffer, &drop_point, - utf, -1); + gtk_text_buffer_insert_interactive (text_view->buffer, &drop_point, + utf, -1, + text_view->editable); g_free (utf); } break; case UTF8: - gtk_text_buffer_insert (text_view->buffer, &drop_point, - (const gchar *)selection_data->data, - selection_data->length); + gtk_text_buffer_insert_interactive (text_view->buffer, &drop_point, + (const gchar *)selection_data->data, + selection_data->length, + text_view->editable); break; case CTEXT: @@ -2737,7 +2816,9 @@ gtk_text_view_drag_data_received (GtkWidget *widget, utf = gtk_text_latin1_to_utf (list[i], strlen (list[i])); - gtk_text_buffer_insert (text_view->buffer, &drop_point, utf, -1); + gtk_text_buffer_insert_interactive (text_view->buffer, + &drop_point, utf, -1, + text_view->editable); g_free (utf); } @@ -2852,17 +2933,20 @@ gtk_text_view_commit_handler (GtkIMContext *context, const gchar *str, GtkTextView *text_view) { - gtk_text_buffer_delete_selection (text_view->buffer); + gtk_text_buffer_delete_selection (text_view->buffer, TRUE, + text_view->editable); if (!strcmp (str, "\n")) { - gtk_text_buffer_insert_at_cursor (text_view->buffer, "\n", 1); + gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, "\n", 1, + text_view->editable); } else { if (text_view->overwrite_mode) gtk_text_view_delete_text (text_view, GTK_TEXT_DELETE_CHAR, 1); - gtk_text_buffer_insert_at_cursor (text_view->buffer, str, strlen (str)); + gtk_text_buffer_insert_interactive_at_cursor (text_view->buffer, str, -1, + text_view->editable); } gtk_text_view_scroll_to_mark (text_view, diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h index 95b1b1b561..7871f611c1 100644 --- a/gtk/gtktextview.h +++ b/gtk/gtktextview.h @@ -64,6 +64,10 @@ struct _GtkTextView { GtkWrapMode wrap_mode; /* Default wrap mode */ + gboolean editable; /* default editability */ + + gboolean cursor_visible; + GdkWindow *bin_window; GtkAdjustment *hadjustment; GtkAdjustment *vadjustment; @@ -144,6 +148,15 @@ void gtk_text_view_set_wrap_mode (GtkTextView *text_view, GtkWrapMode wrap_mode); GtkWrapMode gtk_text_view_get_wrap_mode (GtkTextView *text_view); +void gtk_text_view_set_editable (GtkTextView *text_view, + gboolean setting); +gboolean gtk_text_view_get_editable (GtkTextView *text_view); + +void gtk_text_view_set_cursor_visible (GtkTextView *text_view, + gboolean setting); +gboolean gtk_text_view_get_cursor_visible (GtkTextView *text_view); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/testtext.c b/gtk/testtext.c index da1708e1d3..9f56fe3889 100644 --- a/gtk/testtext.c +++ b/gtk/testtext.c @@ -20,6 +20,7 @@ struct _Buffer GtkTextBuffer *buffer; char *filename; gint untitled_serial; + GtkTextTag *not_editable_tag; }; struct _View @@ -839,6 +840,53 @@ do_direction_changed (gpointer callback_data, gtk_widget_queue_resize (view->text_view); } +static void +do_editable_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action); +} + +static void +do_cursor_visible_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action); +} + +static void +do_apply_editable (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + GtkTextIter start; + GtkTextIter end; + + if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer, + &start, &end)) + { + if (callback_action) + { + gtk_text_buffer_remove_tag (view->buffer->buffer, + "ineditable", + &start, &end); + } + else + { + gtk_text_buffer_apply_tag (view->buffer->buffer, + "ineditable", + &start, &end); + } + } +} + static void view_init_menus (View *view) { @@ -893,9 +941,19 @@ static GtkItemFactoryEntry menu_items[] = { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "" }, { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/Settings/Wrap Off" }, { "/Settings/sep1", NULL, 0, 0, "" }, + { "/Settings/Editable", NULL, do_editable_changed, TRUE, "" }, + { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" }, + { "/Settings/sep1", NULL, 0, 0, "" }, + + { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "" }, + { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" }, + { "/Settings/sep1", NULL, 0, 0, "" }, + { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "" }, { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" }, - + { "/_Attributes", NULL, 0, 0, "" }, + { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL }, + { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL }, { "/_Test", NULL, 0, 0, "" }, { "/Test/_Example", NULL, do_example, 0, NULL }, }; @@ -1061,6 +1119,12 @@ create_buffer (void) buffer->filename = NULL; buffer->untitled_serial = -1; + buffer->not_editable_tag = gtk_text_buffer_create_tag (buffer->buffer, + "ineditable"); + gtk_object_set (GTK_OBJECT (buffer->not_editable_tag), + "editable", FALSE, + "foreground", "purple", NULL); + buffers = g_slist_prepend (buffers, buffer); return buffer; diff --git a/tests/testtext.c b/tests/testtext.c index da1708e1d3..9f56fe3889 100644 --- a/tests/testtext.c +++ b/tests/testtext.c @@ -20,6 +20,7 @@ struct _Buffer GtkTextBuffer *buffer; char *filename; gint untitled_serial; + GtkTextTag *not_editable_tag; }; struct _View @@ -839,6 +840,53 @@ do_direction_changed (gpointer callback_data, gtk_widget_queue_resize (view->text_view); } +static void +do_editable_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action); +} + +static void +do_cursor_visible_changed (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + + gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action); +} + +static void +do_apply_editable (gpointer callback_data, + guint callback_action, + GtkWidget *widget) +{ + View *view = view_from_widget (widget); + GtkTextIter start; + GtkTextIter end; + + if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer, + &start, &end)) + { + if (callback_action) + { + gtk_text_buffer_remove_tag (view->buffer->buffer, + "ineditable", + &start, &end); + } + else + { + gtk_text_buffer_apply_tag (view->buffer->buffer, + "ineditable", + &start, &end); + } + } +} + static void view_init_menus (View *view) { @@ -893,9 +941,19 @@ static GtkItemFactoryEntry menu_items[] = { "/Settings/Wrap _Off", NULL, do_wrap_changed, GTK_WRAPMODE_NONE, "" }, { "/Settings/Wrap _Words", NULL, do_wrap_changed, GTK_WRAPMODE_WORD, "/Settings/Wrap Off" }, { "/Settings/sep1", NULL, 0, 0, "" }, + { "/Settings/Editable", NULL, do_editable_changed, TRUE, "" }, + { "/Settings/Not editable", NULL, do_editable_changed, FALSE, "/Settings/Editable" }, + { "/Settings/sep1", NULL, 0, 0, "" }, + + { "/Settings/Cursor visible", NULL, do_cursor_visible_changed, TRUE, "" }, + { "/Settings/Cursor not visible", NULL, do_cursor_visible_changed, FALSE, "/Settings/Cursor visible" }, + { "/Settings/sep1", NULL, 0, 0, "" }, + { "/Settings/Left-to-Right", NULL, do_direction_changed, GTK_TEXT_DIR_LTR, "" }, { "/Settings/Right-to-Left", NULL, do_direction_changed, GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" }, - + { "/_Attributes", NULL, 0, 0, "" }, + { "/Attributes/Editable", NULL, do_apply_editable, TRUE, NULL }, + { "/Attributes/Not editable", NULL, do_apply_editable, FALSE, NULL }, { "/_Test", NULL, 0, 0, "" }, { "/Test/_Example", NULL, do_example, 0, NULL }, }; @@ -1061,6 +1119,12 @@ create_buffer (void) buffer->filename = NULL; buffer->untitled_serial = -1; + buffer->not_editable_tag = gtk_text_buffer_create_tag (buffer->buffer, + "ineditable"); + gtk_object_set (GTK_OBJECT (buffer->not_editable_tag), + "editable", FALSE, + "foreground", "purple", NULL); + buffers = g_slist_prepend (buffers, buffer); return buffer;