// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "textctrl.h"
#endif
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
#include "wx/textctrl.h"
#include "wx/utils.h"
#include "wx/intl.h"
// ----------------------------------------------------------------------------
#ifdef __WXGTK20__
+static void wxGtkTextApplyTagsFromAttr(GtkTextBuffer *text_buffer,
+ const wxTextAttr& attr,
+ GtkTextIter *start,
+ GtkTextIter *end)
+{
+ static gchar buf[1024];
+ GtkTextTag *tag;
+
+ if (attr.HasFont())
+ {
+ char *font_string;
+ PangoFontDescription *font_description = attr.GetFont().GetNativeFontInfo()->description;
+ font_string = pango_font_description_to_string(font_description);
+ g_snprintf(buf, sizeof(buf), "WXFONT %s", font_string);
+ tag = gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer ),
+ buf );
+ if (!tag)
+ tag = gtk_text_buffer_create_tag( text_buffer, buf,
+ "font-desc", font_description,
+ NULL );
+ gtk_text_buffer_apply_tag (text_buffer, tag, start, end);
+ g_free (font_string);
+ }
+
+ if (attr.HasTextColour())
+ {
+ GdkColor *colFg = attr.GetTextColour().GetColor();
+ g_snprintf(buf, sizeof(buf), "WXFORECOLOR %d %d %d",
+ colFg->red, colFg->green, colFg->blue);
+ tag = gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer ),
+ buf );
+ if (!tag)
+ tag = gtk_text_buffer_create_tag( text_buffer, buf,
+ "foreground-gdk", colFg, NULL );
+ gtk_text_buffer_apply_tag (text_buffer, tag, start, end);
+ }
+
+ if (attr.HasBackgroundColour())
+ {
+ GdkColor *colBg = attr.GetBackgroundColour().GetColor();
+ g_snprintf(buf, sizeof(buf), "WXBACKCOLOR %d %d %d",
+ colBg->red, colBg->green, colBg->blue);
+ tag = gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer ),
+ buf );
+ if (!tag)
+ tag = gtk_text_buffer_create_tag( text_buffer, buf,
+ "background-gdk", colBg, NULL );
+ gtk_text_buffer_apply_tag (text_buffer, tag, start, end);
+ }
+}
+
static void wxGtkTextInsert(GtkWidget *text,
GtkTextBuffer *text_buffer,
const wxTextAttr& attr,
wxCharBuffer buffer)
{
- PangoFontDescription *font_description = attr.HasFont()
- ? attr.GetFont().GetNativeFontInfo()->description
- : NULL;
-
- GdkColor *colFg = attr.HasTextColour() ? attr.GetTextColour().GetColor()
- : NULL;
-
- GdkColor *colBg = attr.HasBackgroundColour()
- ? attr.GetBackgroundColour().GetColor()
- : NULL;
-
- GtkTextIter start, end;
- GtkTextMark *mark;
- // iterators are invalidated by any mutation that affects 'indexable' buffer contents,
- // so we save current position in a mark
- // we need a mark of left gravity, so we cannot use
- // mark = gtk_text_buffer_get_insert (text_buffer)
+ gint start_offset;
+ GtkTextIter iter, start;
- gtk_text_buffer_get_iter_at_mark( text_buffer, &start,
+ gtk_text_buffer_get_iter_at_mark( text_buffer, &iter,
gtk_text_buffer_get_insert (text_buffer) );
- mark = gtk_text_buffer_create_mark( text_buffer, NULL, &start, TRUE/*left gravity*/ );
+ start_offset = gtk_text_iter_get_offset (&iter);
+ gtk_text_buffer_insert( text_buffer, &iter, buffer, strlen(buffer) );
- gtk_text_buffer_insert_at_cursor( text_buffer, buffer, strlen(buffer) );
+ gtk_text_buffer_get_iter_at_offset (text_buffer, &start, start_offset);
- gtk_text_buffer_get_iter_at_mark( text_buffer, &end,
- gtk_text_buffer_get_insert (text_buffer) );
- gtk_text_buffer_get_iter_at_mark( text_buffer, &start, mark );
-
- GtkTextTag *tag;
- tag = gtk_text_buffer_create_tag( text_buffer, NULL, "font-desc", font_description,
- "foreground-gdk", colFg,
- "background-gdk", colBg, NULL );
- gtk_text_buffer_apply_tag( text_buffer, tag, &start, &end );
+ wxGtkTextApplyTagsFromAttr(text_buffer, attr, &start, &iter);
}
#else
static void wxGtkTextInsert(GtkWidget *text,
wxapp_install_idle_handler();
win->SetModified();
+#ifndef __WXGTK20__
win->UpdateFontIfNeeded();
+#endif // !__WXGTK20__
wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
event.SetEventObject( win );
win->GetEventHandler()->ProcessEvent( event );
}
+//-----------------------------------------------------------------------------
+// "expose_event" from scrolled window and textview
+//-----------------------------------------------------------------------------
+
+#ifdef __WXGTK20__
+static gboolean
+gtk_text_exposed_callback( GtkWidget *widget, GdkEventExpose *event, wxTextCtrl *win )
+{
+ return TRUE;
+}
+#endif
+
//-----------------------------------------------------------------------------
// "changed" from vertical scrollbar
//-----------------------------------------------------------------------------
{
m_ignoreNextUpdate =
m_modified = FALSE;
- m_updateFont = FALSE;
+ SetUpdateFont(FALSE);
m_text =
m_vScrollbar = (GtkWidget *)NULL;
+#ifdef __WXGTK20__
+ m_frozenness = 0;
+#endif
}
wxTextCtrl::wxTextCtrl( wxWindow *parent,
bool multi_line = (style & wxTE_MULTILINE) != 0;
-#ifdef __WXGTK20__
- GtkTextBuffer *buffer = NULL;
-#endif
-
if (multi_line)
{
#ifdef __WXGTK20__
// Create view
m_text = gtk_text_view_new();
- buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
+ m_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
// create scrolled window
m_widget = gtk_scrolled_window_new( NULL, NULL );
gtk_container_add( GTK_CONTAINER(m_widget), m_text );
// Global settings which can be overridden by tags, I guess.
- if (HasFlag( wxHSCROLL ))
+ if (HasFlag( wxHSCROLL ) || HasFlag( wxTE_DONTWRAP ))
gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text ), GTK_WRAP_NONE );
else
gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text ), GTK_WRAP_WORD );
if (!HasFlag(wxNO_BORDER))
gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(m_widget), GTK_SHADOW_IN );
+
+ GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
#else
// create our control ...
m_text = gtk_text_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
m_focusWidget = m_text;
- PostCreation();
-
- SetFont( parent->GetFont() );
-
- wxSize size_best( DoGetBestSize() );
- wxSize new_size( size );
- if (new_size.x == -1)
- new_size.x = size_best.x;
- if (new_size.y == -1)
- new_size.y = size_best.y;
- if ((new_size.x != size.x) || (new_size.y != size.y))
- SetSize( new_size.x, new_size.y );
+ PostCreation(size);
if (multi_line)
gtk_widget_show(m_text);
#ifdef __WXGTK20__
else
gtk_text_view_set_editable( GTK_TEXT_VIEW( m_text), FALSE);
- }
#else
}
else
{
if (multi_line)
gtk_text_set_editable( GTK_TEXT(m_text), 1 );
- }
#endif
+ }
+#ifdef __WXGTK20__
+ 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
+ }
+#endif // __WXGTK20__
+
// We want to be notified about text changes.
#ifdef __WXGTK20__
if (multi_line)
{
- g_signal_connect( G_OBJECT(buffer), "changed",
+ g_signal_connect( G_OBJECT(m_buffer), "changed",
GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
}
else
#endif
+
{
- gtk_signal_connect( GTK_OBJECT(m_text), "changed",
- GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
+ gtk_signal_connect( GTK_OBJECT(m_text), "changed",
+ GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
}
- // we don't set a valid background colour, because the window
- // manager should use a default one
- m_backgroundColour = wxColour();
-
- wxColour colFg = parent->GetForegroundColour();
- SetForegroundColour( colFg );
-
m_cursor = wxCursor( wxCURSOR_IBEAM );
- wxTextAttr attrDef( colFg, m_backgroundColour, parent->GetFont() );
+ wxTextAttr attrDef(GetForegroundColour(), GetBackgroundColour(), GetFont());
SetDefaultStyle( attrDef );
- Show( TRUE );
-
return TRUE;
}
+
void wxTextCtrl::CalculateScrollbar()
{
#ifndef __WXGTK20__
if (m_windowStyle & wxTE_MULTILINE)
{
#ifdef __WXGTK20__
- GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
-
GtkTextIter start;
- gtk_text_buffer_get_start_iter( text_buffer, &start );
+ gtk_text_buffer_get_start_iter( m_buffer, &start );
GtkTextIter end;
- gtk_text_buffer_get_end_iter( text_buffer, &end );
- gchar *text = gtk_text_buffer_get_text( text_buffer, &start, &end, TRUE );
-
+ gtk_text_buffer_get_end_iter( m_buffer, &end );
+ gchar *text = gtk_text_buffer_get_text( m_buffer, &start, &end, TRUE );
+
#if wxUSE_UNICODE
wxWCharBuffer buffer( wxConvUTF8.cMB2WX( text ) );
#else
wxCharBuffer buffer( wxConvLocal.cWC2WX( wxConvUTF8.cMB2WC( text ) ) );
#endif
- tmp = buffer;
+ if ( buffer )
+ tmp = buffer;
g_free( text );
#else
#else
wxCharBuffer buffer( wxConvUTF8.cWC2MB( wxConvLocal.cWX2WC( value ) ) );
#endif
- GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
- gtk_text_buffer_set_text( text_buffer, buffer, strlen(buffer) );
+ if (gtk_text_buffer_get_char_count(m_buffer) != 0)
+ IgnoreNextTextUpdate();
+
+ gtk_text_buffer_set_text( m_buffer, buffer, strlen(buffer) );
#else
gint len = gtk_text_get_length( GTK_TEXT(m_text) );
}
// GRG, Jun/2000: Changed this after a lot of discussion in
- // the lists. wxWindows 2.2 will have a set of flags to
+ // the lists. wxWidgets 2.2 will have a set of flags to
// customize this behaviour.
SetInsertionPoint(0);
if ( text.empty() )
return;
+ // gtk_text_changed_callback() will set m_modified to true but m_modified
+ // shouldn't be changed by the program writing to the text control itself,
+ // so save the old value and restore when we're done
+ bool oldModified = m_modified;
+
if ( m_windowStyle & wxTE_MULTILINE )
{
#ifdef __WXGTK20__
#else
wxCharBuffer buffer( wxConvUTF8.cWC2MB( wxConvLocal.cWX2WC( text ) ) );
#endif
- GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
-
+ if ( !buffer )
+ {
+ // what else can we do? at least don't crash...
+ return;
+ }
+
// TODO: Call whatever is needed to delete the selection.
- wxGtkTextInsert( m_text, text_buffer, m_defaultStyle, buffer );
+ wxGtkTextInsert( m_text, m_buffer, m_defaultStyle, buffer );
- // Scroll to cursor.
- GtkTextIter iter;
- gtk_text_buffer_get_iter_at_mark( text_buffer, &iter, gtk_text_buffer_get_insert( text_buffer ) );
- gtk_text_view_scroll_to_iter( GTK_TEXT_VIEW(m_text), &iter, 0.0, FALSE, 0.0, 1.0 );
+ 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 ( 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 );
+ }
#else // GTK 1.x
// After cursor movements, gtk_text_get_point() is wrong by one.
gtk_text_set_point( GTK_TEXT(m_text), GET_EDITABLE_POS(m_text) );
gtk_editable_delete_selection( GTK_EDITABLE(m_text) );
wxGtkTextInsert(m_text, m_defaultStyle, text.c_str(), text.Len());
+ // we called wxGtkTextInsert with correct font, no need to do anything
+ // in UpdateFontIfNeeded() any longer
+ if ( !text.empty() )
+ {
+ SetUpdateFont(FALSE);
+ }
+
// Bring editable's cursor back uptodate.
SET_EDITABLE_POS(m_text, gtk_text_get_point( GTK_TEXT(m_text) ));
#endif // GTK 1.x/2.0
gtk_entry_set_position( GTK_ENTRY(m_text), len );
}
- m_modified = TRUE;
+ m_modified = oldModified;
}
void wxTextCtrl::AppendText( const wxString &text )
return buf;
}
else
-#endif
{
return wxEmptyString;
}
+#else
+ GtkTextIter line;
+ gtk_text_buffer_get_iter_at_line(m_buffer,&line,lineNo);
+ GtkTextIter end;
+ gtk_text_buffer_get_end_iter(m_buffer,&end );
+ gchar *text = gtk_text_buffer_get_text(m_buffer,&line,&end,TRUE);
+ wxString result(wxGTK_CONV_BACK(text));
+ g_free(text);
+ return result.BeforeFirst(wxT('\n'));
+#endif
}
else
{
if (m_windowStyle & wxTE_MULTILINE)
{
#ifdef __WXGTK20__
- GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
-
- return gtk_text_buffer_get_line_count( buffer );
+ return gtk_text_buffer_get_line_count( m_buffer );
#else
gint len = gtk_text_get_length( GTK_TEXT(m_text) );
char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
{
wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
- if (m_windowStyle & wxTE_MULTILINE)
+ if ( IsMultiLine() )
{
#ifdef __WXGTK20__
- GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
GtkTextIter iter;
- gtk_text_buffer_get_iter_at_offset( text_buffer, &iter, pos );
- gtk_text_buffer_place_cursor( text_buffer, &iter );
-#else
+ 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 )
+ );
+#else // GTK+ 1.x
gtk_signal_disconnect_by_func( GTK_OBJECT(m_text),
GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
// bring editable's cursor uptodate. Bug in GTK.
SET_EDITABLE_POS(m_text, gtk_text_get_point( GTK_TEXT(m_text) ));
-#endif
+#endif // GTK+ 2/1
}
else
{
if (m_windowStyle & wxTE_MULTILINE)
{
#ifdef __WXGTK20__
- GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
GtkTextIter end;
- gtk_text_buffer_get_end_iter( text_buffer, &end );
- gtk_text_buffer_place_cursor( text_buffer, &end );
+ gtk_text_buffer_get_end_iter( m_buffer, &end );
+ gtk_text_buffer_place_cursor( m_buffer, &end );
#else
SetInsertionPoint(gtk_text_get_length(GTK_TEXT(m_text)));
#endif
}
}
+void wxTextCtrl::MarkDirty()
+{
+ m_modified = TRUE;
+}
+
void wxTextCtrl::DiscardEdits()
{
m_modified = FALSE;
if (m_windowStyle & wxTE_MULTILINE)
{
#ifdef __WXGTK20__
- GtkTextBuffer *buf = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
-
GtkTextIter fromi, toi;
- gtk_text_buffer_get_iter_at_offset( buf, &fromi, from );
- gtk_text_buffer_get_iter_at_offset( buf, &toi, to );
+ gtk_text_buffer_get_iter_at_offset( m_buffer, &fromi, from );
+ gtk_text_buffer_get_iter_at_offset( m_buffer, &toi, to );
- gtk_text_buffer_place_cursor( buf, &toi );
- gtk_text_buffer_move_mark_by_name( buf, "selection_bound", &fromi );
+ gtk_text_buffer_place_cursor( m_buffer, &toi );
+ gtk_text_buffer_move_mark_by_name( m_buffer, "selection_bound", &fromi );
#else
gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
#endif
void wxTextCtrl::ShowPosition( long pos )
{
-#ifndef __WXGTK20__
if (m_windowStyle & wxTE_MULTILINE)
{
+#ifdef __WXGTK20__
+ 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 );
+#else // GTK 1.x
GtkAdjustment *vp = GTK_TEXT(m_text)->vadj;
float totalLines = (float) GetNumberOfLines();
long posX;
float posLine = (float) posY;
float p = (posLine/totalLines)*(vp->upper - vp->lower) + vp->lower;
gtk_adjustment_set_value(GTK_TEXT(m_text)->vadj, p);
+#endif // GTK 1.x/2.x
}
-#endif
}
+#ifdef __WXGTK20__
+
+wxTextCtrlHitTestResult
+wxTextCtrl::HitTest(const wxPoint& pt, long *pos) const
+{
+ if ( !IsMultiLine() )
+ {
+ // not supported
+ return wxTE_HT_UNKNOWN;
+ }
+
+ int x, y;
+ gtk_text_view_window_to_buffer_coords
+ (
+ GTK_TEXT_VIEW(m_text),
+ GTK_TEXT_WINDOW_TEXT,
+ pt.x, pt.y,
+ &x, &y
+ );
+
+ GtkTextIter iter;
+ gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(m_text), &iter, x, y);
+ if ( pos )
+ *pos = gtk_text_iter_get_offset(&iter);
+
+ return wxTE_HT_ON_TEXT;
+}
+
+#endif // __WXGTK20__
+
long wxTextCtrl::GetInsertionPoint() const
{
wxCHECK_MSG( m_text != NULL, 0, wxT("invalid text ctrl") );
#ifdef __WXGTK20__
if (m_windowStyle & wxTE_MULTILINE)
{
- GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
-
// There is no direct accessor for the cursor, but
// internally, the cursor is the "mark" called
// "insert" in the text view's btree structure.
- GtkTextMark *mark = gtk_text_buffer_get_insert( text_buffer );
+ GtkTextMark *mark = gtk_text_buffer_get_insert( m_buffer );
GtkTextIter cursor;
- gtk_text_buffer_get_iter_at_mark( text_buffer, &cursor, mark );
+ gtk_text_buffer_get_iter_at_mark( m_buffer, &cursor, mark );
return gtk_text_iter_get_offset( &cursor );
}
if (m_windowStyle & wxTE_MULTILINE)
{
#ifdef __WXGTK20__
- GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
GtkTextIter end;
- gtk_text_buffer_get_end_iter( text_buffer, &end );
+ gtk_text_buffer_get_end_iter( m_buffer, &end );
pos = gtk_text_iter_get_offset( &end );
#else
#ifdef __WXGTK20__
if (m_windowStyle & wxTE_MULTILINE)
{
- GtkTextBuffer *
- text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
-
GtkTextIter fromi, toi;
- gtk_text_buffer_get_iter_at_offset( text_buffer, &fromi, from );
- gtk_text_buffer_get_iter_at_offset( text_buffer, &toi, to );
+ gtk_text_buffer_get_iter_at_offset( m_buffer, &fromi, from );
+ gtk_text_buffer_get_iter_at_offset( m_buffer, &toi, to );
- gtk_text_buffer_delete( text_buffer, &fromi, &toi );
+ gtk_text_buffer_delete( m_buffer, &fromi, &toi );
}
else // single line
#endif
{
wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
-#ifndef __WXGTK20__
- gtk_editable_cut_clipboard( GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG );
+#ifdef __WXGTK20__
+ if (m_windowStyle & wxTE_MULTILINE)
+ g_signal_emit_by_name(m_text, "cut-clipboard");
+ else
#endif
+ gtk_editable_cut_clipboard(GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG);
}
void wxTextCtrl::Copy()
{
wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
-#ifndef __WXGTK20__
- gtk_editable_copy_clipboard( GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG );
+#ifdef __WXGTK20__
+ if (m_windowStyle & wxTE_MULTILINE)
+ g_signal_emit_by_name(m_text, "copy-clipboard");
+ else
#endif
+ gtk_editable_copy_clipboard(GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG);
}
void wxTextCtrl::Paste()
{
wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
-#ifndef __WXGTK20__
- gtk_editable_paste_clipboard( GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG );
+#ifdef __WXGTK20__
+ if (m_windowStyle & wxTE_MULTILINE)
+ g_signal_emit_by_name(m_text, "paste-clipboard");
+ else
#endif
+ gtk_editable_paste_clipboard(GTK_EDITABLE(m_text) DUMMY_CLIPBOARD_ARG);
}
// Undo/redo
{
wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
- gint from, to;
-#ifdef __WXGTK20__
- GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (m_text));
- GtkTextIter ifrom, ito;
- if (!gtk_text_buffer_get_selection_bounds(buffer, &ifrom, &ito))
-#else
- if ( !(GTK_EDITABLE(m_text)->has_selection) )
-#endif
- {
- from =
- to = GetInsertionPoint();
- }
- else // got selection
- {
+ gint from = -1;
+ gint to = -1;
+ bool haveSelection = FALSE;
+
#ifdef __WXGTK20__
- from = gtk_text_iter_get_offset(&ifrom);
- to = gtk_text_iter_get_offset(&ito);
-#else
- from = (long) GTK_EDITABLE(m_text)->selection_start_pos;
- to = (long) GTK_EDITABLE(m_text)->selection_end_pos;
+ if (m_windowStyle & wxTE_MULTILINE)
+ {
+ GtkTextIter ifrom, ito;
+ if ( gtk_text_buffer_get_selection_bounds(m_buffer, &ifrom, &ito) )
+ {
+ haveSelection = TRUE;
+ from = gtk_text_iter_get_offset(&ifrom);
+ to = gtk_text_iter_get_offset(&ito);
+ }
+ }
+ else // not multi-line
+ {
+ if ( gtk_editable_get_selection_bounds( GTK_EDITABLE(m_text),
+ &from, &to) )
+ {
+ haveSelection = TRUE;
+ }
+ }
+#else // not GTK2
+ if ( (GTK_EDITABLE(m_text)->has_selection) )
+ {
+ haveSelection = TRUE;
+ from = (long) GTK_EDITABLE(m_text)->selection_start_pos;
+ to = (long) GTK_EDITABLE(m_text)->selection_end_pos;
+ }
#endif
- if ( from > to )
- {
- // exchange them to be compatible with wxMSW
- gint tmp = from;
- from = to;
- to = tmp;
- }
- }
+ if (! haveSelection )
+ from = to = GetInsertionPoint();
+
+ if ( from > to )
+ {
+ // exchange them to be compatible with wxMSW
+ gint tmp = from;
+ from = to;
+ to = tmp;
+ }
if ( fromOut )
*fromOut = from;
*toOut = to;
}
+
bool wxTextCtrl::IsEditable() const
{
wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
if ( m_windowStyle & wxTE_MULTILINE )
{
- m_updateFont = TRUE;
+ SetUpdateFont(TRUE);
m_defaultStyle.SetFont(font);
{
// this method is very inefficient and hence should be called as rarely as
// possible!
+ //
+ // TODO: it can be implemented much more efficiently for GTK2
+#ifndef __WXGTK20__
wxASSERT_MSG( (m_windowStyle & wxTE_MULTILINE) && m_updateFont,
+
_T("shouldn't be called for single line controls") );
+#else
+ wxASSERT_MSG( (m_windowStyle & wxTE_MULTILINE),
+ _T("shouldn't be called for single line controls") );
+#endif
wxString value = GetValue();
if ( !value.IsEmpty() )
{
- m_updateFont = FALSE;
+ SetUpdateFont(FALSE);
Clear();
AppendText(value);
}
}
+#ifndef __WXGTK20__
+
void wxTextCtrl::UpdateFontIfNeeded()
{
if ( m_updateFont )
ChangeFontGlobally();
}
+#endif // GTK+ 1.x
+
bool wxTextCtrl::SetForegroundColour(const wxColour& colour)
{
if ( !wxControl::SetForegroundColour(colour) )
if ( !wxControl::SetBackgroundColour( colour ) )
return FALSE;
+#ifndef __WXGTK20__
if (!m_widget->window)
return FALSE;
-
- wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
- if (sysbg.Red() == colour.Red() &&
- sysbg.Green() == colour.Green() &&
- sysbg.Blue() == colour.Blue())
- {
- return FALSE; // FIXME or TRUE?
- }
+#endif
if (!m_backgroundColour.Ok())
return FALSE;
return TRUE;
}
#ifdef __WXGTK20__
- GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
- gint l = gtk_text_buffer_get_char_count( text_buffer );
+ gint l = gtk_text_buffer_get_char_count( m_buffer );
wxCHECK_MSG( start >= 0 && end <= l, FALSE,
_T("invalid range in wxTextCtrl::SetStyle") );
GtkTextIter starti, endi;
- gtk_text_buffer_get_iter_at_offset( text_buffer, &starti, start );
- gtk_text_buffer_get_iter_at_offset( text_buffer, &endi, end );
+ 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);
- PangoFontDescription *font_description = attr.HasFont()
- ? attr.GetFont().GetNativeFontInfo()->description
- : NULL;
-
- GdkColor *colFg = attr.HasTextColour() ? attr.GetTextColour().GetColor()
- : NULL;
-
- GdkColor *colBg = attr.HasBackgroundColour()
- ? attr.GetBackgroundColour().GetColor()
- : NULL;
-
- GtkTextTag *tag;
- tag = gtk_text_buffer_create_tag( text_buffer, NULL, "font-desc", font_description,
- "foreground-gdk", colFg,
- "background-gdk", colBg, NULL );
- gtk_text_buffer_apply_tag( text_buffer, tag, &starti, &endi );
+ wxGtkTextApplyTagsFromAttr( m_buffer, attr, &starti, &endi );
return TRUE;
#else
// VERY dirty way to do that - removes the required text and re-adds it
// with styling (FIXME)
-
+
gint l = gtk_text_get_length( GTK_TEXT(m_text) );
wxCHECK_MSG( start >= 0 && end <= l, FALSE,
}
}
-void wxTextCtrl::ApplyWidgetStyle()
+void wxTextCtrl::DoApplyWidgetStyle(GtkRcStyle *style)
{
- if (m_windowStyle & wxTE_MULTILINE)
- {
- // how ?
- }
- else
- {
- SetWidgetStyle();
- gtk_widget_set_style( m_text, m_widgetStyle );
- }
+ gtk_widget_modify_style(m_text, style);
}
void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
}
}
- if (wxUpdateUIEvent::CanUpdate())
- UpdateWindowUI();
+ if (wxUpdateUIEvent::CanUpdate(this))
+ UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
}
wxSize wxTextCtrl::DoGetBestSize() const
{
// FIXME should be different for multi-line controls...
wxSize ret( wxControl::DoGetBestSize() );
- return wxSize(80, ret.y);
+ wxSize best(80, ret.y);
+ CacheBestSize(best);
+ return best;
}
// ----------------------------------------------------------------------------
void wxTextCtrl::Freeze()
{
-#ifndef __WXGTK20__
if ( HasFlag(wxTE_MULTILINE) )
{
- gtk_text_freeze(GTK_TEXT(m_text));
+#ifdef __WXGTK20__
+ if ( !m_frozenness++ )
+ {
+ // freeze textview updates and remove buffer
+ g_signal_connect( G_OBJECT(m_text), "expose_event",
+ GTK_SIGNAL_FUNC(gtk_text_exposed_callback), (gpointer)this);
+ g_signal_connect( G_OBJECT(m_widget), "expose_event",
+ GTK_SIGNAL_FUNC(gtk_text_exposed_callback), (gpointer)this);
+ gtk_widget_set_sensitive(m_widget, false);
+ g_object_ref(m_buffer);
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), gtk_text_buffer_new(NULL));
}
+#else
+ gtk_text_freeze(GTK_TEXT(m_text));
#endif
+ }
}
void wxTextCtrl::Thaw()
{
-#ifndef __WXGTK20__
if ( HasFlag(wxTE_MULTILINE) )
{
+#ifdef __WXGTK20__
+ wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
+
+ if ( !--m_frozenness )
+ {
+ // Reattach buffer and thaw textview updates
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), m_buffer);
+ g_object_unref(m_buffer);
+ gtk_widget_set_sensitive(m_widget, true);
+ g_signal_handlers_disconnect_by_func(m_widget, (gpointer)gtk_text_exposed_callback, this);
+ g_signal_handlers_disconnect_by_func(m_text, (gpointer)gtk_text_exposed_callback, this);
+ }
+#else
GTK_TEXT(m_text)->vadj->value = 0.0;
gtk_text_thaw(GTK_TEXT(m_text));
- }
#endif
+ }
}
// ----------------------------------------------------------------------------
GtkAdjustment *wxTextCtrl::GetVAdj() const
{
+ if ( !IsMultiLine() )
+ return NULL;
+
#ifdef __WXGTK20__
- return NULL;
+ return gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_widget));
#else
- return HasFlag(wxTE_MULTILINE) ? GTK_TEXT(m_text)->vadj : NULL;
+ return GTK_TEXT(m_text)->vadj;
#endif
}
bool wxTextCtrl::DoScroll(GtkAdjustment *adj, int diff)
{
-#ifndef __WXGTK20__
float value = adj->value + diff;
if ( value < 0 )
adj->value = value;
+#ifdef __WXGTK20__
+ gtk_adjustment_value_changed(GTK_ADJUSTMENT(adj));
+#else
gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
-
#endif
+
return TRUE;
}
bool wxTextCtrl::ScrollLines(int lines)
{
-#ifdef __WXGTK20__
- return FALSE;
-#else
GtkAdjustment *adj = GetVAdj();
if ( !adj )
return FALSE;
+#ifdef __WXGTK20__
+ int diff = (int)ceil(lines*adj->step_increment);
+#else
// this is hardcoded to 10 in GTK+ 1.2 (great idea)
- static const int KEY_SCROLL_PIXELS = 10;
-
- return DoScroll(adj, lines*KEY_SCROLL_PIXELS);
+ int diff = 10*lines;
#endif
+
+ return DoScroll(adj, diff);
}
bool wxTextCtrl::ScrollPages(int pages)
{
-#ifdef __WXGTK20__
- return FALSE;
-#else
GtkAdjustment *adj = GetVAdj();
if ( !adj )
return FALSE;
return DoScroll(adj, (int)ceil(pages*adj->page_increment));
-#endif
}
+
+// static
+wxVisualAttributes
+wxTextCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
+{
+ return GetDefaultAttributesFromGTKWidget(gtk_entry_new, true);
+}