}
}
-extern "C" {
+// remove all tags starting with the given prefix from the start..end range
+static void
+wxGtkTextRemoveTagsWithPrefix(GtkTextBuffer *text_buffer,
+ const char *prefix,
+ GtkTextIter *start,
+ GtkTextIter *end)
+{
+ gulong remove_handler_id = g_signal_connect
+ (
+ text_buffer,
+ "remove_tag",
+ G_CALLBACK(wxGtkOnRemoveTag),
+ gpointer(prefix)
+ );
+ gtk_text_buffer_remove_all_tags(text_buffer, start, end);
+ g_signal_handler_disconnect(text_buffer, remove_handler_id);
+}
+
static void wxGtkTextApplyTagsFromAttr(GtkWidget *text,
GtkTextBuffer *text_buffer,
const wxTextAttr& attr,
static gchar buf[1024];
GtkTextTag *tag;
- gulong remove_handler_id = g_signal_connect (text_buffer, "remove_tag",
- G_CALLBACK (wxGtkOnRemoveTag), gpointer("WX"));
- gtk_text_buffer_remove_all_tags(text_buffer, start, end);
- g_signal_handler_disconnect (text_buffer, remove_handler_id);
-
if (attr.HasFont())
{
+ wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXFONT", start, end);
+
PangoFontDescription *font_description = attr.GetFont().GetNativeFontInfo()->description;
wxGtkString font_string(pango_font_description_to_string(font_description));
g_snprintf(buf, sizeof(buf), "WXFONT %s", font_string.c_str());
if (attr.HasTextColour())
{
+ wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXFORECOLOR", start, end);
+
const GdkColor *colFg = attr.GetTextColour().GetColor();
g_snprintf(buf, sizeof(buf), "WXFORECOLOR %d %d %d",
colFg->red, colFg->green, colFg->blue);
if (attr.HasBackgroundColour())
{
+ wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXBACKCOLOR", start, end);
+
const GdkColor *colBg = attr.GetBackgroundColour().GetColor();
g_snprintf(buf, sizeof(buf), "WXBACKCOLOR %d %d %d",
colBg->red, colBg->green, colBg->blue);
gtk_text_iter_get_line(start) );
gtk_text_iter_forward_line(¶_end);
- remove_handler_id = g_signal_connect (text_buffer, "remove_tag",
- G_CALLBACK(wxGtkOnRemoveTag),
- gpointer("WXALIGNMENT"));
- gtk_text_buffer_remove_all_tags( text_buffer, ¶_start, ¶_end );
- g_signal_handler_disconnect (text_buffer, remove_handler_id);
+ wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXALIGNMENT", start, end);
GtkJustification align;
switch (attr.GetAlignment())
gtk_text_iter_get_line(start) );
gtk_text_iter_forward_line(¶_end);
- remove_handler_id = g_signal_connect (text_buffer, "remove_tag",
- G_CALLBACK(wxGtkOnRemoveTag),
- gpointer("WXINDENT"));
- gtk_text_buffer_remove_all_tags( text_buffer, ¶_start, ¶_end );
- g_signal_handler_disconnect (text_buffer, remove_handler_id);
+ wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXINDENT", start, end);
// Convert indent from 1/10th of a mm into pixels
float factor;
gtk_text_iter_get_line(start) );
gtk_text_iter_forward_line(¶_end);
- remove_handler_id = g_signal_connect (text_buffer, "remove_tag",
- G_CALLBACK(wxGtkOnRemoveTag),
- gpointer("WXTABS"));
- gtk_text_buffer_remove_all_tags( text_buffer, ¶_start, ¶_end );
- g_signal_handler_disconnect (text_buffer, remove_handler_id);
+ wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXTABS", start, end);
const wxArrayInt& tabs = attr.GetTabs();
gtk_text_buffer_apply_tag (text_buffer, tag, ¶_start, ¶_end);
}
}
-}
-extern "C" {
static void wxGtkTextInsert(GtkWidget *text,
GtkTextBuffer *text_buffer,
const wxTextAttr& attr,
wxGtkTextApplyTagsFromAttr(text, text_buffer, attr, &start, &iter);
}
-}
// ----------------------------------------------------------------------------
// "insert_text" for GtkEntry
gint *position,
wxTextCtrl *win)
{
- if (g_isIdle)
- wxapp_install_idle_handler();
-
// we should only be called if we have a max len limit at all
GtkEntry *entry = GTK_ENTRY (editable);
if (!win->m_hasVMT) return;
- if (g_isIdle)
- wxapp_install_idle_handler();
-
if ( win->MarkDirtyOnChange() )
win->MarkDirty();
SetUpdateFont(false);
m_text = NULL;
- m_frozenness = 0;
+ m_freezeCount = 0;
+ m_showPositionOnThaw = NULL;
m_gdkHandCursor = NULL;
m_gdkXTermCursor = NULL;
}
const wxValidator& validator,
const wxString &name )
{
- m_needParent = true;
- m_acceptsFocus = true;
-
if (!PreCreation( parent, pos, size ) ||
!CreateBase( parent, id, pos, size, style, validator, name ))
{
m_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
+ // create "ShowPosition" marker
+ GtkTextIter iter;
+ gtk_text_buffer_get_start_iter(m_buffer, &iter);
+ gtk_text_buffer_create_mark(m_buffer, "ShowPosition", &iter, true);
+
// create scrolled window
m_widget = gtk_scrolled_window_new( NULL, NULL );
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( m_widget ),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+ GTK_POLICY_AUTOMATIC,
+ style & wxTE_NO_VSCROLL
+ ? GTK_POLICY_NEVER
+ : GTK_POLICY_AUTOMATIC );
// for ScrollLines/Pages
m_scrollBar[1] = (GtkRange*)((GtkScrolledWindow*)m_widget)->vscrollbar;
// Insert view into scrolled window
gtk_container_add( GTK_CONTAINER(m_widget), m_text );
- // translate wx wrapping style to GTK+
- GtkWrapMode wrap;
- if ( HasFlag( wxTE_DONTWRAP ) )
- wrap = GTK_WRAP_NONE;
- else if ( HasFlag( wxTE_CHARWRAP ) )
- wrap = GTK_WRAP_CHAR;
- else if ( HasFlag( wxTE_WORDWRAP ) )
- wrap = GTK_WRAP_WORD;
- else // HasFlag(wxTE_BESTWRAP) always true as wxTE_BESTWRAP == 0
- {
- // GTK_WRAP_WORD_CHAR seems to be new in GTK+ 2.4
-#ifdef __WXGTK24__
- if ( !gtk_check_version(2,4,0) )
- {
- wrap = GTK_WRAP_WORD_CHAR;
- }
- else
-#endif
- wrap = GTK_WRAP_WORD;
- }
-
- gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text ), wrap );
+ GTKSetWrapMode();
GtkScrolledWindowSetBorder(m_widget, style);
}
if (style & wxTE_PASSWORD)
- {
- if (!multi_line)
- gtk_entry_set_visibility( GTK_ENTRY(m_text), FALSE );
- }
+ GTKSetVisibility();
if (style & wxTE_READONLY)
- {
- if (!multi_line)
- gtk_editable_set_editable( GTK_EDITABLE(m_text), FALSE );
- else
- gtk_text_view_set_editable( GTK_TEXT_VIEW( m_text), FALSE);
- }
+ GTKSetEditable();
- if (multi_line)
- {
- if (style & wxTE_RIGHT)
- gtk_text_view_set_justification( GTK_TEXT_VIEW(m_text), GTK_JUSTIFY_RIGHT );
- else if (style & wxTE_CENTRE)
- gtk_text_view_set_justification( GTK_TEXT_VIEW(m_text), GTK_JUSTIFY_CENTER );
- // Left justify (alignment) is the default and we don't need to apply GTK_JUSTIFY_LEFT
- }
- else
- {
-#ifdef __WXGTK24__
- // gtk_entry_set_alignment was introduced in gtk+-2.3.5
- if (!gtk_check_version(2,4,0))
- {
- if (style & wxTE_RIGHT)
- gtk_entry_set_alignment( GTK_ENTRY(m_text), 1.0 );
- else if (style & wxTE_CENTRE)
- gtk_entry_set_alignment( GTK_ENTRY(m_text), 0.5 );
- }
-#endif
- }
+ // left justification (alignment) is the default anyhow
+ if ( style & (wxTE_RIGHT | wxTE_CENTRE) )
+ GTKSetJustification();
// We want to be notified about text changes.
if (multi_line)
m_cursor = wxCursor( wxCURSOR_IBEAM );
- wxTextAttr attrDef(GetForegroundColour(), GetBackgroundColour(), GetFont());
- SetDefaultStyle( attrDef );
-
return true;
}
+// ----------------------------------------------------------------------------
+// flags handling
+// ----------------------------------------------------------------------------
-void wxTextCtrl::CalculateScrollbar()
+void wxTextCtrl::GTKSetEditable()
{
+ gboolean editable = !HasFlag(wxTE_READONLY);
+ if ( IsSingleLine() )
+ gtk_editable_set_editable(GTK_EDITABLE(m_text), editable);
+ else
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(m_text), editable);
}
+void wxTextCtrl::GTKSetVisibility()
+{
+ // VZ: shouldn't we assert if wxTE_PASSWORD is set for multiline control?
+ if ( IsSingleLine() )
+ gtk_entry_set_visibility(GTK_ENTRY(m_text), !HasFlag(wxTE_PASSWORD));
+}
+
+void wxTextCtrl::GTKSetWrapMode()
+{
+ // no wrapping in single line controls
+ if ( !IsMultiLine() )
+ return;
+
+ // translate wx wrapping style to GTK+
+ GtkWrapMode wrap;
+ if ( HasFlag( wxTE_DONTWRAP ) )
+ wrap = GTK_WRAP_NONE;
+ else if ( HasFlag( wxTE_CHARWRAP ) )
+ wrap = GTK_WRAP_CHAR;
+ else if ( HasFlag( wxTE_WORDWRAP ) )
+ wrap = GTK_WRAP_WORD;
+ else // HasFlag(wxTE_BESTWRAP) always true as wxTE_BESTWRAP == 0
+ {
+ // GTK_WRAP_WORD_CHAR seems to be new in GTK+ 2.4
+#ifdef __WXGTK24__
+ if ( !gtk_check_version(2,4,0) )
+ {
+ wrap = GTK_WRAP_WORD_CHAR;
+ }
+ else
+#endif // __WXGTK24__
+ wrap = GTK_WRAP_WORD;
+ }
+
+ gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text ), wrap );
+}
+
+void wxTextCtrl::GTKSetJustification()
+{
+ if ( IsMultiLine() )
+ {
+ GtkJustification just;
+ if ( HasFlag(wxTE_RIGHT) )
+ just = GTK_JUSTIFY_RIGHT;
+ else if ( HasFlag(wxTE_CENTRE) )
+ just = GTK_JUSTIFY_CENTER;
+ else // wxTE_LEFT == 0
+ just = GTK_JUSTIFY_LEFT;
+
+ gtk_text_view_set_justification(GTK_TEXT_VIEW(m_text), just);
+ }
+ else // single line
+ {
+#ifdef __WXGTK24__
+ // gtk_entry_set_alignment was introduced in gtk+-2.3.5
+ if (!gtk_check_version(2,4,0))
+ {
+ gfloat align;
+ if ( HasFlag(wxTE_RIGHT) )
+ align = 1.0;
+ else if ( HasFlag(wxTE_CENTRE) )
+ align = 0.5;
+ else // single line
+ align = 0.0;
+
+ gtk_entry_set_alignment(GTK_ENTRY(m_text), align);
+ }
+#endif // __WXGTK24__
+ }
+
+}
+
+void wxTextCtrl::SetWindowStyleFlag(long style)
+{
+ long styleOld = GetWindowStyleFlag();
+
+ wxTextCtrlBase::SetWindowStyleFlag(style);
+
+ if ( (style & wxTE_READONLY) != (styleOld & wxTE_READONLY) )
+ GTKSetEditable();
+
+ if ( (style & wxTE_PASSWORD) != (styleOld & wxTE_PASSWORD) )
+ GTKSetVisibility();
+
+ static const long flagsWrap = wxTE_WORDWRAP | wxTE_CHARWRAP | wxTE_DONTWRAP;
+ if ( (style & flagsWrap) != (styleOld & flagsWrap) )
+ GTKSetWrapMode();
+
+ static const long flagsAlign = wxTE_LEFT | wxTE_CENTRE | wxTE_RIGHT;
+ if ( (style & flagsAlign) != (styleOld & flagsAlign) )
+ GTKSetJustification();
+}
+
+// ----------------------------------------------------------------------------
+// control value
+// ----------------------------------------------------------------------------
+
wxString wxTextCtrl::GetValue() const
{
wxCHECK_MSG( m_text != NULL, wxEmptyString, wxT("invalid text ctrl") );
bool wxTextCtrl::IsEmpty() const
{
if ( IsMultiLine() )
- return gtk_text_buffer_get_char_count(m_buffer) != 0;
+ return gtk_text_buffer_get_char_count(m_buffer) == 0;
return wxTextCtrlBase::IsEmpty();
}
m_modified = false;
DontMarkDirtyOnNextChange();
- const wxCharBuffer buffer(wxGTK_CONV_ENC(value, GetTextEncoding()));
+ wxFontEncoding enc = m_defaultStyle.HasFont()
+ ? m_defaultStyle.GetFont().GetEncoding()
+ : wxFONTENCODING_SYSTEM;
+ if ( enc == wxFONTENCODING_SYSTEM )
+ enc = GetTextEncoding();
+
+ const wxCharBuffer buffer(wxGTK_CONV_ENC(value, enc));
if ( !buffer )
{
// see comment in WriteText() as to why we must warn the user about
if ( IsMultiLine() )
{
gtk_text_buffer_set_text( m_buffer, buffer, strlen(buffer) );
+
+ if ( !m_defaultStyle.IsDefault() )
+ {
+ GtkTextIter start, end;
+ gtk_text_buffer_get_bounds( m_buffer, &start, &end );
+ wxGtkTextApplyTagsFromAttr(m_widget, m_buffer, m_defaultStyle,
+ &start, &end);
+ }
}
else // single line
{
gtk_entry_set_text( GTK_ENTRY(m_text), buffer );
}
+ // if, for whatever reason, the callback wasn't called the expected number
+ // of times, still reset the flags to the default values
+ m_dontMarkDirty = false;
+ m_countUpdatesToIgnore = 0;
+
+
// GRG, Jun/2000: Changed this after a lot of discussion in
// the lists. wxWidgets 2.2 will have a set of flags to
// customize this behaviour.
GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW(m_widget) );
// Scroll to cursor, but only if scrollbar thumb is at the very bottom
- if ( wxIsSameDouble(adj->value, adj->upper - adj->page_size) )
+ // won't work when frozen, text view is not using m_buffer then
+ if (!IsFrozen() && wxIsSameDouble(adj->value, adj->upper - adj->page_size))
{
gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW(m_text),
gtk_text_buffer_get_insert( m_buffer ), 0.0, FALSE, 0.0, 1.0 );
{
GtkTextIter line;
gtk_text_buffer_get_iter_at_line(m_buffer,&line,lineNo);
+
GtkTextIter end = line;
- gtk_text_iter_forward_to_line_end(&end);
+ // avoid skipping to the next line end if this one is empty
+ if ( !gtk_text_iter_ends_line(&line) )
+ gtk_text_iter_forward_to_line_end(&end);
+
wxGtkString text(gtk_text_buffer_get_text(m_buffer, &line, &end, true));
result = wxGTK_CONV_BACK(text);
}
{
if ( IsMultiLine() )
{
- GtkTextIter iter;
- gtk_text_buffer_get_iter_at_offset( m_buffer, &iter, 0 );
-
- // move forward by one display line until the end is reached
- int lineCount = 1;
- while ( gtk_text_view_forward_display_line(GTK_TEXT_VIEW(m_text), &iter) )
- {
- lineCount++;
- }
-
- // If the last character in the text buffer is a newline,
- // gtk_text_view_forward_display_line() will return false without that
- // line being counted. Must add one manually in that case.
- GtkTextIter lastCharIter;
- gtk_text_buffer_get_iter_at_offset
- (
- m_buffer,
- &lastCharIter,
- gtk_text_buffer_get_char_count(m_buffer) - 1
- );
- gchar lastChar = gtk_text_iter_get_char( &lastCharIter );
- if ( lastChar == wxT('\n') )
- lineCount++;
-
- return lineCount;
+ return gtk_text_buffer_get_line_count( m_buffer );
}
else // single line
{
GtkTextIter iter;
gtk_text_buffer_get_iter_at_offset( m_buffer, &iter, pos );
gtk_text_buffer_place_cursor( m_buffer, &iter );
- gtk_text_view_scroll_mark_onscreen
- (
- GTK_TEXT_VIEW(m_text),
- gtk_text_buffer_get_insert( m_buffer )
- );
+ GtkTextMark* mark = gtk_text_buffer_get_insert(m_buffer);
+ if (IsFrozen())
+ // defer until Thaw, text view is not using m_buffer now
+ m_showPositionOnThaw = mark;
+ else
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark);
}
else
{
void wxTextCtrl::SetInsertionPointEnd()
{
- wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
-
- if ( IsMultiLine() )
- {
- GtkTextIter end;
- gtk_text_buffer_get_end_iter( m_buffer, &end );
- gtk_text_buffer_place_cursor( m_buffer, &end );
- }
- else
- {
- gtk_editable_set_position( GTK_EDITABLE(m_text), -1 );
- }
+ SetInsertionPoint(-1);
}
void wxTextCtrl::SetEditable( bool editable )
}
// wxGTK-specific: called recursively by Enable,
-// to give widgets an oppprtunity to correct their colours after they
+// to give widgets an opportunity to correct their colours after they
// have been changed by Enable
-void wxTextCtrl::OnParentEnable( bool enable )
+void wxTextCtrl::OnEnabled( bool enable )
{
// If we have a custom background colour, we use this colour in both
// disabled and enabled mode, or we end up with a different colour under the
void wxTextCtrl::ShowPosition( long pos )
{
- if ( IsMultiLine() )
+ if (IsMultiLine())
{
GtkTextIter iter;
- gtk_text_buffer_get_start_iter( m_buffer, &iter );
- gtk_text_iter_set_offset( &iter, pos );
- GtkTextMark *mark = gtk_text_buffer_create_mark( m_buffer, NULL, &iter, TRUE );
- gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW(m_text), mark, 0.0, FALSE, 0.0, 0.0 );
+ gtk_text_buffer_get_iter_at_offset(m_buffer, &iter, int(pos));
+ GtkTextMark* mark = gtk_text_buffer_get_mark(m_buffer, "ShowPosition");
+ gtk_text_buffer_move_mark(m_buffer, mark, &iter);
+ if (IsFrozen())
+ // defer until Thaw, text view is not using m_buffer now
+ m_showPositionOnThaw = mark;
+ else
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark);
}
}
gtk_text_buffer_get_iter_at_offset( m_buffer, &starti, start );
gtk_text_buffer_get_iter_at_offset( m_buffer, &endi, end );
- // use the attributes from style which are set in it and fall back
- // first to the default style and then to the text control default
- // colours for the others
- wxTextAttr attr = wxTextAttr::Combine(style, m_defaultStyle, this);
-
- wxGtkTextApplyTagsFromAttr( m_widget, m_buffer, attr, &starti, &endi );
+ wxGtkTextApplyTagsFromAttr( m_widget, m_buffer, style, &starti, &endi );
return true;
}
+ //else: single line text controls don't support styles
- // else single line
- // cannot do this for GTK+'s Entry widget
return false;
}
void wxTextCtrl::Freeze()
{
+ wxCHECK_RET(m_text != NULL, wxT("invalid text ctrl"));
+
if ( HasFlag(wxTE_MULTILINE) )
{
- if ( !m_frozenness++ )
+ if (m_freezeCount++ == 0)
{
// freeze textview updates and remove buffer
g_signal_connect (m_text, "expose_event",
gtk_widget_set_sensitive(m_widget, false);
g_object_ref(m_buffer);
GtkTextBuffer* buf_new = gtk_text_buffer_new(NULL);
+ GtkTextMark* mark = GTK_TEXT_VIEW(m_text)->first_para_mark;
gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), buf_new);
// gtk_text_view_set_buffer adds its own reference
g_object_unref(buf_new);
+ // This mark should be deleted when the buffer is changed,
+ // but it's not (in GTK+ up to at least 2.10.6).
+ // Otherwise these anonymous marks start to build up in the buffer,
+ // and Freeze takes longer and longer each time it is called.
+ if (GTK_IS_TEXT_MARK(mark) && !gtk_text_mark_get_deleted(mark))
+ gtk_text_buffer_delete_mark(m_buffer, mark);
}
}
}
{
if ( HasFlag(wxTE_MULTILINE) )
{
- wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
+ wxCHECK_RET(m_freezeCount != 0, _T("Thaw() without matching Freeze()"));
- if ( !--m_frozenness )
+ if (--m_freezeCount == 0)
{
// Reattach buffer and thaw textview updates
gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), m_buffer);
(gpointer) gtk_text_exposed_callback, this);
g_signal_handlers_disconnect_by_func (m_text,
(gpointer) gtk_text_exposed_callback, this);
+ if (m_showPositionOnThaw != NULL)
+ {
+ gtk_text_view_scroll_mark_onscreen(
+ GTK_TEXT_VIEW(m_text), m_showPositionOnThaw);
+ m_showPositionOnThaw = NULL;
+ }
}
}
}