1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling, Vadim Zeitlin 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "textctrl.h" 
  14 #include "wx/textctrl.h" 
  17 #include "wx/settings.h" 
  19 #include <sys/types.h> 
  25 #include "gdk/gdkkeysyms.h" 
  27 //----------------------------------------------------------------------------- 
  29 //----------------------------------------------------------------------------- 
  31 extern void wxapp_install_idle_handler(); 
  34 //----------------------------------------------------------------------------- 
  36 //----------------------------------------------------------------------------- 
  38 extern bool       g_blockEventsOnDrag
; 
  39 extern wxCursor   g_globalCursor
; 
  41 //----------------------------------------------------------------------------- 
  43 //----------------------------------------------------------------------------- 
  46 gtk_text_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxTextCtrl 
*win 
) 
  48     if (!win
->m_hasVMT
) return; 
  51         wxapp_install_idle_handler(); 
  55     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, win
->GetId() ); 
  56     event
.SetString( win
->GetValue() ); 
  57     event
.SetEventObject( win 
); 
  58     win
->GetEventHandler()->ProcessEvent( event 
); 
  61 //----------------------------------------------------------------------------- 
  62 // "changed" from vertical scrollbar 
  63 //----------------------------------------------------------------------------- 
  66 gtk_scrollbar_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxTextCtrl 
*win 
) 
  68     if (!win
->m_hasVMT
) return; 
  71         wxapp_install_idle_handler(); 
  73     win
->CalculateScrollbar(); 
  76 //----------------------------------------------------------------------------- 
  78 //----------------------------------------------------------------------------- 
  80 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
,wxControl
) 
  82 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
) 
  83     EVT_CHAR(wxTextCtrl::OnChar
) 
  85     EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
) 
  86     EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
) 
  87     EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
) 
  88     EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
) 
  89     EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
) 
  91     EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
) 
  92     EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
) 
  93     EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
) 
  94     EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
) 
  95     EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
) 
  98 wxTextCtrl::wxTextCtrl() 
 103 wxTextCtrl::wxTextCtrl( wxWindow 
*parent
, 
 105                         const wxString 
&value
, 
 109                         const wxValidator
& validator
, 
 110                         const wxString 
&name 
) 
 113     Create( parent
, id
, value
, pos
, size
, style
, validator
, name 
); 
 116 bool wxTextCtrl::Create( wxWindow 
*parent
, 
 118                          const wxString 
&value
, 
 122                          const wxValidator
& validator
, 
 123                          const wxString 
&name 
) 
 126     m_acceptsFocus 
= TRUE
; 
 128     if (!PreCreation( parent
, pos
, size 
) || 
 129         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 131         wxFAIL_MSG( wxT("wxTextCtrl creation failed") ); 
 136     m_vScrollbarVisible 
= FALSE
; 
 138     bool multi_line 
= (style 
& wxTE_MULTILINE
) != 0; 
 141 #if (GTK_MINOR_VERSION > 2) 
 142         /* a multi-line edit control: create a vertical scrollbar by default and 
 143            horizontal if requested */ 
 144         bool bHasHScrollbar 
= (style 
& wxHSCROLL
) != 0; 
 146         bool bHasHScrollbar 
= FALSE
; 
 149         /* create our control ... */ 
 150         m_text 
= gtk_text_new( (GtkAdjustment 
*) NULL
, (GtkAdjustment 
*) NULL 
); 
 152         /* ... and put into the upper left hand corner of the table */ 
 153         m_widget 
= gtk_table_new(bHasHScrollbar 
? 2 : 1, 2, FALSE
); 
 154         GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
 155         gtk_table_attach( GTK_TABLE(m_widget
), m_text
, 0, 1, 0, 1, 
 156                       (GtkAttachOptions
)(GTK_FILL 
| GTK_EXPAND 
| GTK_SHRINK
), 
 157                       (GtkAttachOptions
)(GTK_FILL 
| GTK_EXPAND 
| GTK_SHRINK
), 
 160         /* always wrap words */ 
 161         gtk_text_set_word_wrap( GTK_TEXT(m_text
), TRUE 
); 
 163 #if (GTK_MINOR_VERSION > 2) 
 164         /* put the horizontal scrollbar in the lower left hand corner */ 
 167             GtkWidget 
*hscrollbar 
= gtk_hscrollbar_new(GTK_TEXT(m_text
)->hadj
); 
 168             GTK_WIDGET_UNSET_FLAGS( hscrollbar
, GTK_CAN_FOCUS 
); 
 169             gtk_table_attach(GTK_TABLE(m_widget
), hscrollbar
, 0, 1, 1, 2, 
 170                        (GtkAttachOptions
)(GTK_EXPAND 
| GTK_FILL 
| GTK_SHRINK
), 
 173             gtk_widget_show(hscrollbar
); 
 175             /* don't wrap lines, otherwise we wouldn't need the scrollbar */ 
 176             gtk_text_set_line_wrap( GTK_TEXT(m_text
), FALSE 
); 
 180         /* finally, put the vertical scrollbar in the upper right corner */ 
 181         m_vScrollbar 
= gtk_vscrollbar_new( GTK_TEXT(m_text
)->vadj 
); 
 182         GTK_WIDGET_UNSET_FLAGS( m_vScrollbar
, GTK_CAN_FOCUS 
); 
 183         gtk_table_attach(GTK_TABLE(m_widget
), m_vScrollbar
, 1, 2, 0, 1, 
 185                      (GtkAttachOptions
)(GTK_EXPAND 
| GTK_FILL 
| GTK_SHRINK
), 
 190         /* a single-line text control: no need for scrollbars */ 
 192           m_text 
= gtk_entry_new(); 
 195     m_parent
->DoAddChild( this ); 
 199     SetFont( parent
->GetFont() ); 
 201     wxSize 
size_best( DoGetBestSize() ); 
 202     wxSize 
new_size( size 
); 
 203     if (new_size
.x 
== -1) 
 204         new_size
.x 
= size_best
.x
; 
 205     if (new_size
.y 
== -1) 
 206         new_size
.y 
= size_best
.y
; 
 207     if ((new_size
.x 
!= size
.x
) || (new_size
.y 
!= size
.y
)) 
 208         SetSize( new_size
.x
, new_size
.y 
); 
 211         gtk_widget_show(m_text
); 
 213     /* we want to be notified about text changes */ 
 214     gtk_signal_connect( GTK_OBJECT(m_text
), "changed", 
 215       GTK_SIGNAL_FUNC(gtk_text_changed_callback
), (gpointer
)this); 
 219         gtk_signal_connect(GTK_OBJECT(GTK_TEXT(m_text
)->vadj
), "changed", 
 220           (GtkSignalFunc
) gtk_scrollbar_changed_callback
, (gpointer
) this ); 
 223     if (!value
.IsEmpty()) 
 227 #if GTK_MINOR_VERSION == 0 
 228         // if we don't realize it, GTK 1.0.6 dies with a SIGSEGV in 
 229         // gtk_editable_insert_text() 
 230         gtk_widget_realize(m_text
); 
 234         wxWX2MBbuf val 
= value
.mbc_str(); 
 235         gtk_editable_insert_text( GTK_EDITABLE(m_text
), val
, strlen(val
), &tmp 
); 
 237         gtk_editable_insert_text( GTK_EDITABLE(m_text
), value
, value
.Length(), &tmp 
); 
 238 #endif // Unicode/!Unicode 
 242             /* bring editable's cursor uptodate. bug in GTK. */ 
 244             GTK_EDITABLE(m_text
)->current_pos 
= gtk_text_get_point( GTK_TEXT(m_text
) ); 
 248     if (style 
& wxTE_PASSWORD
) 
 251             gtk_entry_set_visibility( GTK_ENTRY(m_text
), FALSE 
); 
 254     if (style 
& wxTE_READONLY
) 
 257             gtk_entry_set_editable( GTK_ENTRY(m_text
), FALSE 
); 
 262             gtk_text_set_editable( GTK_TEXT(m_text
), 1 ); 
 265     SetBackgroundColour( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW
) ); 
 266     SetForegroundColour( parent
->GetForegroundColour() ); 
 268     m_cursor 
= wxCursor( wxCURSOR_IBEAM 
); 
 275 void wxTextCtrl::CalculateScrollbar() 
 277     if ((m_windowStyle 
& wxTE_MULTILINE
) == 0) return; 
 279     GtkAdjustment 
*adj 
= GTK_TEXT(m_text
)->vadj
; 
 281     if (adj
->upper 
- adj
->page_size 
< 0.8) 
 283         if (m_vScrollbarVisible
) 
 285             gtk_widget_hide( m_vScrollbar 
); 
 286             m_vScrollbarVisible 
= FALSE
; 
 291         if (!m_vScrollbarVisible
) 
 293             gtk_widget_show( m_vScrollbar 
); 
 294             m_vScrollbarVisible 
= TRUE
; 
 299 wxString 
wxTextCtrl::GetValue() const 
 301     wxCHECK_MSG( m_text 
!= NULL
, wxT(""), wxT("invalid text ctrl") ); 
 304     if (m_windowStyle 
& wxTE_MULTILINE
) 
 306         gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 307         char *text 
= gtk_editable_get_chars( GTK_EDITABLE(m_text
), 0, len 
); 
 308         tmp 
= wxString(text
,*wxConvCurrent
); 
 313         tmp 
= wxString(gtk_entry_get_text( GTK_ENTRY(m_text
) ),*wxConvCurrent
); 
 318 void wxTextCtrl::SetValue( const wxString 
&value 
) 
 320     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 322     wxString tmp 
= wxT(""); 
 323     if (!value
.IsNull()) tmp 
= value
; 
 324     if (m_windowStyle 
& wxTE_MULTILINE
) 
 326         gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 327         gtk_editable_delete_text( GTK_EDITABLE(m_text
), 0, len 
); 
 330         wxWX2MBbuf tmpbuf 
= tmp
.mbc_str(); 
 331         gtk_editable_insert_text( GTK_EDITABLE(m_text
), tmpbuf
, strlen(tmpbuf
), &len 
); 
 333         gtk_editable_insert_text( GTK_EDITABLE(m_text
), tmp
.mbc_str(), tmp
.Length(), &len 
); 
 338         gtk_entry_set_text( GTK_ENTRY(m_text
), tmp
.mbc_str() ); 
 341     // GRG, Jun/2000: Changed this after a lot of discussion in 
 342     //   the lists. wxWindows 2.2 will have a set of flags to 
 343     //   customize this behaviour. 
 344     SetInsertionPoint(0); 
 349 void wxTextCtrl::WriteText( const wxString 
&text 
) 
 351     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 353     if (text
.IsEmpty()) return; 
 355     if (m_windowStyle 
& wxTE_MULTILINE
) 
 357         /* this moves the cursor pos to behind the inserted text */ 
 358         gint len 
= GTK_EDITABLE(m_text
)->current_pos
; 
 361         wxWX2MBbuf buf 
= text
.mbc_str(); 
 362         gtk_editable_insert_text( GTK_EDITABLE(m_text
), buf
, strlen(buf
), &len 
); 
 364         gtk_editable_insert_text( GTK_EDITABLE(m_text
), text
, text
.Length(), &len 
); 
 367         /* bring editable's cursor uptodate. bug in GTK. */ 
 368         GTK_EDITABLE(m_text
)->current_pos 
= gtk_text_get_point( GTK_TEXT(m_text
) ); 
 372         /* this moves the cursor pos to behind the inserted text */ 
 373         gint len 
= GTK_EDITABLE(m_text
)->current_pos
; 
 375         wxWX2MBbuf buf 
= text
.mbc_str(); 
 376         gtk_editable_insert_text( GTK_EDITABLE(m_text
), buf
, strlen(buf
), &len 
); 
 378         gtk_editable_insert_text( GTK_EDITABLE(m_text
), text
, text
.Length(), &len 
); 
 381         /* bring editable's cursor uptodate. bug in GTK. */ 
 382         GTK_EDITABLE(m_text
)->current_pos 
+= text
.Len(); 
 384         /* bring entry's cursor uptodate. bug in GTK. */ 
 385         gtk_entry_set_position( GTK_ENTRY(m_text
), GTK_EDITABLE(m_text
)->current_pos 
); 
 389 void wxTextCtrl::AppendText( const wxString 
&text 
) 
 391     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 393     if (text
.IsEmpty()) return; 
 395     if (m_windowStyle 
& wxTE_MULTILINE
) 
 397         bool hasSpecialAttributes 
= m_font
.Ok() || 
 398                                     m_foregroundColour
.Ok() || 
 399                                     m_backgroundColour
.Ok(); 
 400         if ( hasSpecialAttributes 
) 
 402              gtk_text_insert( GTK_TEXT(m_text
), 
 403                               m_font
.GetInternalFont(), 
 404                               m_foregroundColour
.GetColor(), 
 405                               m_backgroundColour
.GetColor(), 
 406                               text
.mbc_str(), text
.length()); 
 411             /* we'll insert at the last position */ 
 412             gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 414             wxWX2MBbuf buf 
= text
.mbc_str(); 
 415             gtk_editable_insert_text( GTK_EDITABLE(m_text
), buf
, strlen(buf
), &len 
); 
 417             gtk_editable_insert_text( GTK_EDITABLE(m_text
), text
, text
.Length(), &len 
); 
 421         /* bring editable's cursor uptodate. bug in GTK. */ 
 422         GTK_EDITABLE(m_text
)->current_pos 
= gtk_text_get_point( GTK_TEXT(m_text
) ); 
 426         gtk_entry_append_text( GTK_ENTRY(m_text
), text
.mbc_str() ); 
 430 wxString 
wxTextCtrl::GetLineText( long lineNo 
) const 
 432   if (m_windowStyle 
& wxTE_MULTILINE
) 
 434     gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 435     char *text 
= gtk_editable_get_chars( GTK_EDITABLE(m_text
), 0, len 
); 
 439         wxString 
buf(wxT("")); 
 442         for (i 
= 0; currentLine 
!= lineNo 
&& text
[i
]; i
++ ) 
 447         for (j 
= 0; text
[i
] && text
[i
] != '\n'; i
++, j
++ ) 
 454       return wxEmptyString
; 
 458     if (lineNo 
== 0) return GetValue(); 
 459     return wxEmptyString
; 
 463 void wxTextCtrl::OnDropFiles( wxDropFilesEvent 
&WXUNUSED(event
) ) 
 465   /* If you implement this, don't forget to update the documentation! 
 466    * (file docs/latex/wx/text.tex) */ 
 467     wxFAIL_MSG( wxT("wxTextCtrl::OnDropFiles not implemented") ); 
 470 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y 
) const 
 472     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 474         wxString text 
= GetValue(); 
 476         // cast to prevent warning. But pos really should've been unsigned. 
 477         if( (unsigned long)pos 
> text
.Len()  ) 
 483         const wxChar
* stop 
= text
.c_str() + pos
; 
 484         for ( const wxChar 
*p 
= text
.c_str(); p 
< stop
; p
++ ) 
 495     else // single line control 
 497         if ( pos 
<= GTK_ENTRY(m_text
)->text_length 
) 
 504             // index out of bounds 
 512 long wxTextCtrl::XYToPosition(long x
, long y 
) const 
 514     if (!(m_windowStyle 
& wxTE_MULTILINE
)) return 0; 
 517     for( int i
=0; i
<y
; i
++ ) pos 
+= GetLineLength(i
) + 1; // one for '\n' 
 523 int wxTextCtrl::GetLineLength(long lineNo
) const 
 525     wxString str 
= GetLineText (lineNo
); 
 526     return (int) str
.Length(); 
 529 int wxTextCtrl::GetNumberOfLines() const 
 531     if (m_windowStyle 
& wxTE_MULTILINE
) 
 533         gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 534         char *text 
= gtk_editable_get_chars( GTK_EDITABLE(m_text
), 0, len 
); 
 539             for (int i 
= 0; i 
< len
; i
++ ) 
 546             // currentLine is 0 based, add 1 to get number of lines 
 547             return currentLine 
+ 1; 
 560 void wxTextCtrl::SetInsertionPoint( long pos 
) 
 562     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 564     if (m_windowStyle 
& wxTE_MULTILINE
) 
 566         /* seems to be broken in GTK 1.0.X: 
 567            gtk_text_set_point( GTK_TEXT(m_text), (int)pos ); */ 
 569         gtk_signal_disconnect_by_func( GTK_OBJECT(m_text
), 
 570           GTK_SIGNAL_FUNC(gtk_text_changed_callback
), (gpointer
)this); 
 572         /* we fake a set_point by inserting and deleting. as the user 
 573            isn't supposed to get to know about thos non-sense, we 
 574            disconnect so that no events are sent to the user program. */ 
 576         gint tmp 
= (gint
)pos
; 
 577         gtk_editable_insert_text( GTK_EDITABLE(m_text
), " ", 1, &tmp 
); 
 578         gtk_editable_delete_text( GTK_EDITABLE(m_text
), tmp
-1, tmp 
); 
 580         gtk_signal_connect( GTK_OBJECT(m_text
), "changed", 
 581           GTK_SIGNAL_FUNC(gtk_text_changed_callback
), (gpointer
)this); 
 583         /* bring editable's cursor uptodate. another bug in GTK. */ 
 585         GTK_EDITABLE(m_text
)->current_pos 
= gtk_text_get_point( GTK_TEXT(m_text
) ); 
 589         gtk_entry_set_position( GTK_ENTRY(m_text
), (int)pos 
); 
 591         /* bring editable's cursor uptodate. bug in GTK. */ 
 593         GTK_EDITABLE(m_text
)->current_pos 
= (guint32
)pos
; 
 597 void wxTextCtrl::SetInsertionPointEnd() 
 599     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 601     if (m_windowStyle 
& wxTE_MULTILINE
) 
 602         SetInsertionPoint(gtk_text_get_length(GTK_TEXT(m_text
))); 
 604         gtk_entry_set_position( GTK_ENTRY(m_text
), -1 ); 
 607 void wxTextCtrl::SetEditable( bool editable 
) 
 609     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 611     if (m_windowStyle 
& wxTE_MULTILINE
) 
 612         gtk_text_set_editable( GTK_TEXT(m_text
), editable 
); 
 614         gtk_entry_set_editable( GTK_ENTRY(m_text
), editable 
); 
 617 bool wxTextCtrl::Enable( bool enable 
) 
 619     if (!wxWindowBase::Enable(enable
)) 
 625     if (m_windowStyle 
& wxTE_MULTILINE
) 
 627         gtk_text_set_editable( GTK_TEXT(m_text
), enable 
); 
 631         gtk_widget_set_sensitive( m_text
, enable 
); 
 637 void wxTextCtrl::DiscardEdits() 
 642 void wxTextCtrl::SetSelection( long from
, long to 
) 
 644     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 646     gtk_editable_select_region( GTK_EDITABLE(m_text
), (gint
)from
, (gint
)to 
); 
 649 void wxTextCtrl::ShowPosition( long WXUNUSED(pos
) ) 
 651 //    SetInsertionPoint( pos ); 
 654 long wxTextCtrl::GetInsertionPoint() const 
 656     wxCHECK_MSG( m_text 
!= NULL
, 0, wxT("invalid text ctrl") ); 
 658     return (long) GTK_EDITABLE(m_text
)->current_pos
; 
 661 long wxTextCtrl::GetLastPosition() const 
 663     wxCHECK_MSG( m_text 
!= NULL
, 0, wxT("invalid text ctrl") ); 
 666     if (m_windowStyle 
& wxTE_MULTILINE
) 
 667         pos 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 669         pos 
= GTK_ENTRY(m_text
)->text_length
; 
 674 void wxTextCtrl::Remove( long from
, long to 
) 
 676     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 678     gtk_editable_delete_text( GTK_EDITABLE(m_text
), (gint
)from
, (gint
)to 
); 
 681 void wxTextCtrl::Replace( long from
, long to
, const wxString 
&value 
) 
 683     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 685     gtk_editable_delete_text( GTK_EDITABLE(m_text
), (gint
)from
, (gint
)to 
); 
 687     if (!value
.IsEmpty()) 
 689         gint pos 
= (gint
)from
; 
 691         wxWX2MBbuf buf 
= value
.mbc_str(); 
 692         gtk_editable_insert_text( GTK_EDITABLE(m_text
), buf
, strlen(buf
), &pos 
); 
 694         gtk_editable_insert_text( GTK_EDITABLE(m_text
), value
, value
.Length(), &pos 
); 
 699 void wxTextCtrl::Cut() 
 701     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 703 #if (GTK_MINOR_VERSION > 0) 
 704     gtk_editable_cut_clipboard( GTK_EDITABLE(m_text
) ); 
 706     gtk_editable_cut_clipboard( GTK_EDITABLE(m_text
), 0 ); 
 710 void wxTextCtrl::Copy() 
 712     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 714 #if (GTK_MINOR_VERSION > 0) 
 715     gtk_editable_copy_clipboard( GTK_EDITABLE(m_text
) ); 
 717     gtk_editable_copy_clipboard( GTK_EDITABLE(m_text
), 0 ); 
 721 void wxTextCtrl::Paste() 
 723     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 725 #if (GTK_MINOR_VERSION > 0) 
 726     gtk_editable_paste_clipboard( GTK_EDITABLE(m_text
) ); 
 728     gtk_editable_paste_clipboard( GTK_EDITABLE(m_text
), 0 ); 
 732 bool wxTextCtrl::CanCopy() const 
 734     // Can copy if there's a selection 
 736     GetSelection(& from
, & to
); 
 737     return (from 
!= to
) ; 
 740 bool wxTextCtrl::CanCut() const 
 742     // Can cut if there's a selection 
 744     GetSelection(& from
, & to
); 
 745     return (from 
!= to
) ; 
 748 bool wxTextCtrl::CanPaste() const 
 750     return IsEditable() ; 
 754 void wxTextCtrl::Undo() 
 757     wxFAIL_MSG( wxT("wxTextCtrl::Undo not implemented") ); 
 760 void wxTextCtrl::Redo() 
 763     wxFAIL_MSG( wxT("wxTextCtrl::Redo not implemented") ); 
 766 bool wxTextCtrl::CanUndo() const 
 769     wxFAIL_MSG( wxT("wxTextCtrl::CanUndo not implemented") ); 
 773 bool wxTextCtrl::CanRedo() const 
 776     wxFAIL_MSG( wxT("wxTextCtrl::CanRedo not implemented") ); 
 780 // If the return values from and to are the same, there is no 
 782 void wxTextCtrl::GetSelection(long* from
, long* to
) const 
 784     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 786     if (!(GTK_EDITABLE(m_text
)->has_selection
)) 
 788         long i 
= GetInsertionPoint(); 
 794     if (from
) *from 
= (long) GTK_EDITABLE(m_text
)->selection_start_pos
; 
 795     if (to
)   *to 
= (long) GTK_EDITABLE(m_text
)->selection_end_pos
; 
 798 bool wxTextCtrl::IsEditable() const 
 800     wxCHECK_MSG( m_text 
!= NULL
, FALSE
, wxT("invalid text ctrl") ); 
 802     return GTK_EDITABLE(m_text
)->editable
; 
 805 bool wxTextCtrl::IsModified() const 
 810 void wxTextCtrl::Clear() 
 815 void wxTextCtrl::OnChar( wxKeyEvent 
&key_event 
) 
 817     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 819     if ((key_event
.KeyCode() == WXK_RETURN
) && (m_windowStyle 
& wxPROCESS_ENTER
)) 
 821         wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
); 
 822         event
.SetEventObject(this); 
 823         event
.SetString(GetValue()); 
 824         if (GetEventHandler()->ProcessEvent(event
)) return; 
 827     if ((key_event
.KeyCode() == WXK_RETURN
) && !(m_windowStyle 
& wxTE_MULTILINE
)) 
 829         wxWindow 
*top_frame 
= m_parent
; 
 830         while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 831             top_frame 
= top_frame
->GetParent(); 
 832         GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
 834         if (window
->default_widget
) 
 836             gtk_widget_activate (window
->default_widget
); 
 844 GtkWidget
* wxTextCtrl::GetConnectWidget() 
 846     return GTK_WIDGET(m_text
); 
 849 bool wxTextCtrl::IsOwnGtkWindow( GdkWindow 
*window 
) 
 851     if (m_windowStyle 
& wxTE_MULTILINE
) 
 852         return (window 
== GTK_TEXT(m_text
)->text_area
); 
 854         return (window 
== GTK_ENTRY(m_text
)->text_area
); 
 857 // the font will change for subsequent text insertiongs 
 858 bool wxTextCtrl::SetFont( const wxFont 
&font 
) 
 860     wxCHECK_MSG( m_text 
!= NULL
, FALSE
, wxT("invalid text ctrl") ); 
 862     if ( !wxWindowBase::SetFont(font
) ) 
 864         // font didn't change, nothing to do 
 868     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 870         // for compatibility with other ports: the font is a global controls 
 871         // characteristic, so change the font globally 
 872         wxString value 
= GetValue(); 
 873         if ( !value
.IsEmpty() ) 
 884 bool wxTextCtrl::SetForegroundColour( const wxColour 
&WXUNUSED(colour
) ) 
 886     wxCHECK_MSG( m_text 
!= NULL
, FALSE
, wxT("invalid text ctrl") ); 
 892 bool wxTextCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
 894     wxCHECK_MSG( m_text 
!= NULL
, FALSE
, wxT("invalid text ctrl") ); 
 896     wxControl::SetBackgroundColour( colour 
); 
 898     if (!m_widget
->window
) 
 901     wxColour sysbg 
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE 
); 
 902     if (sysbg
.Red() == colour
.Red() && 
 903         sysbg
.Green() == colour
.Green() && 
 904         sysbg
.Blue() == colour
.Blue()) 
 906         return FALSE
; // FIXME or TRUE? 
 909     if (!m_backgroundColour
.Ok()) 
 912     if (m_windowStyle 
& wxTE_MULTILINE
) 
 914         GdkWindow 
*window 
= GTK_TEXT(m_text
)->text_area
; 
 917         m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window 
) ); 
 918         gdk_window_set_background( window
, m_backgroundColour
.GetColor() ); 
 919         gdk_window_clear( window 
); 
 925 void wxTextCtrl::ApplyWidgetStyle() 
 927     if (m_windowStyle 
& wxTE_MULTILINE
) 
 934         gtk_widget_set_style( m_text
, m_widgetStyle 
); 
 938 void wxTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
 943 void wxTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
 948 void wxTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
 953 void wxTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
 958 void wxTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
 963 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
 965     event
.Enable( CanCut() ); 
 968 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
 970     event
.Enable( CanCopy() ); 
 973 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
 975     event
.Enable( CanPaste() ); 
 978 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
 980     event
.Enable( CanUndo() ); 
 983 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
 985     event
.Enable( CanRedo() ); 
 988 void wxTextCtrl::OnInternalIdle() 
 990     wxCursor cursor 
= m_cursor
; 
 991     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
 995         GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
 996         if (HasFlag(wxTE_MULTILINE
)) 
 997             window 
= GTK_TEXT(m_text
)->text_area
; 
 999             window 
= GTK_ENTRY(m_text
)->text_area
; 
1002             gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
1004         if (!g_globalCursor
.Ok()) 
1005             cursor 
= *wxSTANDARD_CURSOR
; 
1007         window 
= m_widget
->window
; 
1008         if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
1009             gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
1015 wxSize 
wxTextCtrl::DoGetBestSize() const 
1017     // FIXME should be different for multi-line controls... 
1018     wxSize 
ret( wxControl::DoGetBestSize() ); 
1019     return wxSize(80, ret
.y
);