]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/textctrl.cpp
e5c9c881a2c0f36065a13388557e600f15853ad8
[wxWidgets.git] / src / gtk / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "textctrl.h"
12 #endif
13
14 #include "wx/textctrl.h"
15 #include "wx/utils.h"
16 #include "wx/intl.h"
17 #include "wx/settings.h"
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <ctype.h>
22
23 #include "gdk/gdk.h"
24 #include "gtk/gtk.h"
25 #include "gdk/gdkkeysyms.h"
26
27 //-----------------------------------------------------------------------------
28 // idle system
29 //-----------------------------------------------------------------------------
30
31 extern void wxapp_install_idle_handler();
32 extern bool g_isIdle;
33
34 //-----------------------------------------------------------------------------
35 // data
36 //-----------------------------------------------------------------------------
37
38 extern bool g_blockEventsOnDrag;
39
40 //-----------------------------------------------------------------------------
41 // "changed"
42 //-----------------------------------------------------------------------------
43
44 static void
45 gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
46 {
47 if (!win->m_hasVMT) return;
48
49 if (g_isIdle)
50 wxapp_install_idle_handler();
51
52 win->SetModified();
53
54 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
55 event.SetString( win->GetValue() );
56 event.SetEventObject( win );
57 win->GetEventHandler()->ProcessEvent( event );
58 }
59
60 //-----------------------------------------------------------------------------
61 // "changed" from vertical scrollbar
62 //-----------------------------------------------------------------------------
63
64 static void
65 gtk_scrollbar_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
66 {
67 if (!win->m_hasVMT) return;
68
69 if (g_isIdle)
70 wxapp_install_idle_handler();
71
72 win->CalculateScrollbar();
73 }
74
75 //-----------------------------------------------------------------------------
76 // wxTextCtrl
77 //-----------------------------------------------------------------------------
78
79 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl,wxControl)
80
81 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
82 EVT_CHAR(wxTextCtrl::OnChar)
83
84 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
85 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
86 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
87 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
88 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
89
90 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
91 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
92 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
93 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
94 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
95 END_EVENT_TABLE()
96
97 #ifndef NO_TEXT_WINDOW_STREAM
98 wxTextCtrl::wxTextCtrl() : streambuf()
99 {
100 if (allocate()) setp(base(),ebuf());
101
102 m_modified = FALSE;
103 }
104 #else
105 wxTextCtrl::wxTextCtrl()
106 {
107 m_modified = FALSE;
108 }
109 #endif
110
111 #ifndef NO_TEXT_WINDOW_STREAM
112 wxTextCtrl::wxTextCtrl( wxWindow *parent, wxWindowID id, const wxString &value,
113 const wxPoint &pos, const wxSize &size,
114 int style, const wxValidator& validator, const wxString &name ) : streambuf()
115 {
116 if (allocate()) setp(base(),ebuf());
117
118 m_modified = FALSE;
119 Create( parent, id, value, pos, size, style, validator, name );
120 }
121 #else
122 wxTextCtrl::wxTextCtrl( wxWindow *parent, wxWindowID id, const wxString &value,
123 const wxPoint &pos, const wxSize &size,
124 int style, const wxValidator& validator, const wxString &name )
125 {
126 m_modified = FALSE;
127 Create( parent, id, value, pos, size, style, validator, name );
128 }
129 #endif
130
131 bool wxTextCtrl::Create( wxWindow *parent, wxWindowID id, const wxString &value,
132 const wxPoint &pos, const wxSize &size,
133 int style, const wxValidator& validator, const wxString &name )
134 {
135 m_needParent = TRUE;
136 m_acceptsFocus = TRUE;
137
138 PreCreation( parent, id, pos, size, style, name );
139
140 SetValidator( validator );
141
142 m_vScrollbarVisible = FALSE;
143
144 bool multi_line = (style & wxTE_MULTILINE) != 0;
145 if (multi_line)
146 {
147 /* a multi-line edit control: create a vertical scrollbar by default and
148 horizontal if requested */
149 bool bHasHScrollbar = (style & wxHSCROLL) != 0;
150
151 /* create our control ... */
152 m_text = gtk_text_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
153
154 /* ... and put into the upper left hand corner of the table */
155 m_widget = gtk_table_new(bHasHScrollbar ? 2 : 1, 2, FALSE);
156 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
157 gtk_table_attach( GTK_TABLE(m_widget), m_text, 0, 1, 0, 1,
158 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK),
159 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK),
160 0, 0);
161
162 /* always wrap words */
163 gtk_text_set_word_wrap( GTK_TEXT(m_text), TRUE );
164 /* put the horizontal scrollbar in the lower left hand corner */
165 if (bHasHScrollbar)
166 {
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),
171 GTK_FILL,
172 0, 0);
173 gtk_widget_show(hscrollbar);
174
175 #if (GTK_MINOR_VERSION > 0)
176 /* don't wrap lines, otherwise we wouldn't need the scrollbar */
177 gtk_text_set_line_wrap( GTK_TEXT(m_text), FALSE );
178 #endif
179 }
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,
184 GTK_FILL,
185 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK),
186 0, 0);
187 }
188 else
189 {
190 /* a single-line text control: no need for scrollbars */
191 m_widget =
192 m_text = gtk_entry_new();
193 }
194
195 wxSize newSize = size;
196 if (newSize.x == -1) newSize.x = 80;
197 if (newSize.y == -1) newSize.y = 26;
198 SetSize( newSize.x, newSize.y );
199
200 m_parent->DoAddChild( this );
201
202 PostCreation();
203
204 if (multi_line)
205 gtk_widget_show(m_text);
206
207 /* we want to be notified about text changes */
208 gtk_signal_connect( GTK_OBJECT(m_text), "changed",
209 GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
210
211 if (multi_line)
212 {
213 gtk_signal_connect(GTK_OBJECT(GTK_TEXT(m_text)->vadj), "changed",
214 (GtkSignalFunc) gtk_scrollbar_changed_callback, (gpointer) this );
215 }
216
217 if (!value.IsEmpty())
218 {
219 gint tmp = 0;
220
221 #if GTK_MINOR_VERSION == 0
222 // if we don't realize it, GTK 1.0.6 dies with a SIGSEGV in
223 // gtk_editable_insert_text()
224 gtk_widget_realize(m_text);
225 #endif // GTK 1.0
226
227 #if wxUSE_UNICODE
228 wxWX2MBbuf val = value.mbc_str();
229 gtk_editable_insert_text( GTK_EDITABLE(m_text), val, strlen(val), &tmp );
230 #else // !Unicode
231 gtk_editable_insert_text( GTK_EDITABLE(m_text), value, value.Length(), &tmp );
232 #endif // Unicode/!Unicode
233
234 if (multi_line)
235 {
236 /* bring editable's cursor uptodate. bug in GTK. */
237
238 GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
239 }
240 }
241
242 if (style & wxTE_PASSWORD)
243 {
244 if (!multi_line)
245 gtk_entry_set_visibility( GTK_ENTRY(m_text), FALSE );
246 }
247
248 if (style & wxTE_READONLY)
249 {
250 if (!multi_line)
251 gtk_entry_set_editable( GTK_ENTRY(m_text), FALSE );
252 }
253 else
254 {
255 if (multi_line)
256 gtk_text_set_editable( GTK_TEXT(m_text), 1 );
257 }
258
259 SetBackgroundColour( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW) );
260 SetForegroundColour( parent->GetForegroundColour() );
261
262 Show( TRUE );
263
264 return TRUE;
265 }
266
267 void wxTextCtrl::CalculateScrollbar()
268 {
269 if ((m_windowStyle & wxTE_MULTILINE) == 0) return;
270
271 GtkAdjustment *adj = GTK_TEXT(m_text)->vadj;
272
273 if (adj->upper - adj->page_size < 0.8)
274 {
275 if (m_vScrollbarVisible)
276 {
277 gtk_widget_hide( m_vScrollbar );
278 m_vScrollbarVisible = FALSE;
279 }
280 }
281 else
282 {
283 if (!m_vScrollbarVisible)
284 {
285 gtk_widget_show( m_vScrollbar );
286 m_vScrollbarVisible = TRUE;
287 }
288 }
289 }
290
291 wxString wxTextCtrl::GetValue() const
292 {
293 wxCHECK_MSG( m_text != NULL, _T(""), _T("invalid text ctrl") );
294
295 wxString tmp;
296 if (m_windowStyle & wxTE_MULTILINE)
297 {
298 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
299 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
300 tmp = wxString(text,*wxConv_current);
301 g_free( text );
302 }
303 else
304 {
305 tmp = wxString(gtk_entry_get_text( GTK_ENTRY(m_text) ),*wxConv_current);
306 }
307 return tmp;
308 }
309
310 void wxTextCtrl::SetValue( const wxString &value )
311 {
312 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
313
314 gtk_signal_disconnect_by_func( GTK_OBJECT(m_text),
315 GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
316
317 wxString tmp = _T("");
318 if (!value.IsNull()) tmp = value;
319 if (m_windowStyle & wxTE_MULTILINE)
320 {
321 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
322 gtk_editable_delete_text( GTK_EDITABLE(m_text), 0, len );
323 len = 0;
324 #if wxUSE_UNICODE
325 wxWX2MBbuf tmpbuf = tmp.mbc_str();
326 gtk_editable_insert_text( GTK_EDITABLE(m_text), tmpbuf, strlen(tmpbuf), &len );
327 #else
328 gtk_editable_insert_text( GTK_EDITABLE(m_text), tmp.mbc_str(), tmp.Length(), &len );
329 #endif
330 }
331 else
332 {
333 gtk_entry_set_text( GTK_ENTRY(m_text), tmp.mbc_str() );
334 }
335
336 gtk_signal_connect( GTK_OBJECT(m_text), "changed",
337 GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
338 }
339
340 void wxTextCtrl::WriteText( const wxString &text )
341 {
342 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
343
344 if (text.IsNull()) return;
345
346 if (m_windowStyle & wxTE_MULTILINE)
347 {
348 /* this moves the cursor pos to behind the inserted text */
349 gint len = GTK_EDITABLE(m_text)->current_pos;
350
351 #if wxUSE_UNICODE
352 wxWX2MBbuf buf = text.mbc_str();
353 gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &len );
354 #else
355 gtk_editable_insert_text( GTK_EDITABLE(m_text), text, text.Length(), &len );
356 #endif
357
358 /* bring editable's cursor uptodate. bug in GTK. */
359 GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
360 }
361 else
362 {
363 /* this moves the cursor pos to behind the inserted text */
364 gint len = GTK_EDITABLE(m_text)->current_pos;
365 #if wxUSE_UNICODE
366 wxWX2MBbuf buf = text.mbc_str();
367 gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &len );
368 #else
369 gtk_editable_insert_text( GTK_EDITABLE(m_text), text, text.Length(), &len );
370 #endif
371
372 /* bring editable's cursor uptodate. bug in GTK. */
373 GTK_EDITABLE(m_text)->current_pos += text.Len();
374
375 /* bring entry's cursor uptodate. bug in GTK. */
376 gtk_entry_set_position( GTK_ENTRY(m_text), GTK_EDITABLE(m_text)->current_pos );
377 }
378 }
379
380 void wxTextCtrl::AppendText( const wxString &text )
381 {
382 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
383
384 if (m_windowStyle & wxTE_MULTILINE)
385 {
386 /* we'll insert at the last position */
387 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
388 #if wxUSE_UNICODE
389 wxWX2MBbuf buf = text.mbc_str();
390 gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &len );
391 #else
392 gtk_editable_insert_text( GTK_EDITABLE(m_text), text, text.Length(), &len );
393 #endif
394
395 /* bring editable's cursor uptodate. bug in GTK. */
396 GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
397 }
398 else
399 {
400 gtk_entry_append_text( GTK_ENTRY(m_text), text.mbc_str() );
401 }
402 }
403
404 bool wxTextCtrl::LoadFile( const wxString &file )
405 {
406 wxCHECK_MSG( m_text != NULL, FALSE, _T("invalid text ctrl") );
407
408 if (!wxFileExists(file)) return FALSE;
409
410 Clear();
411
412 FILE *fp = (FILE*) NULL;
413 struct stat statb;
414
415 if ((stat (FNSTRINGCAST file.fn_str(), &statb) == -1) || (statb.st_mode & S_IFMT) != S_IFREG ||
416 !(fp = fopen (FNSTRINGCAST file.fn_str(), "r")))
417 {
418 return FALSE;
419 }
420 else
421 {
422 gint len = statb.st_size;
423 char *text;
424 if (!(text = (char*)malloc ((unsigned) (len + 1))))
425 {
426 fclose (fp);
427 return FALSE;
428 }
429 if (fread (text, sizeof (char), len, fp) != (size_t) len)
430 {
431 }
432 fclose (fp);
433
434 text[len] = 0;
435
436 if (m_windowStyle & wxTE_MULTILINE)
437 {
438 gint pos = 0;
439 gtk_editable_insert_text( GTK_EDITABLE(m_text), text, len, &pos );
440 }
441 else
442 {
443 gtk_entry_set_text( GTK_ENTRY(m_text), text );
444 }
445
446 free (text);
447 m_modified = FALSE;
448 return TRUE;
449 }
450 return FALSE;
451 }
452
453 bool wxTextCtrl::SaveFile( const wxString &file )
454 {
455 wxCHECK_MSG( m_text != NULL, FALSE, _T("invalid text ctrl") );
456
457 if (file == _T("")) return FALSE;
458
459 FILE *fp;
460
461 if (!(fp = fopen (FNSTRINGCAST file.fn_str(), "w")))
462 {
463 return FALSE;
464 }
465 else
466 {
467 char *text = (char*) NULL;
468 gint len = 0;
469
470 if (m_windowStyle & wxTE_MULTILINE)
471 {
472 len = gtk_text_get_length( GTK_TEXT(m_text) );
473 text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
474 }
475 else
476 {
477 text = gtk_entry_get_text( GTK_ENTRY(m_text) );
478 }
479
480 if (fwrite (text, sizeof (char), len, fp) != (size_t) len)
481 {
482 // Did not write whole file
483 }
484
485 // Make sure newline terminates the file
486 if (text[len - 1] != '\n')
487 fputc ('\n', fp);
488
489 fclose (fp);
490
491 if (m_windowStyle & wxTE_MULTILINE) g_free( text );
492
493 m_modified = FALSE;
494 return TRUE;
495 }
496
497 return TRUE;
498 }
499
500 wxString wxTextCtrl::GetLineText( long lineNo ) const
501 {
502 if (m_windowStyle & wxTE_MULTILINE)
503 {
504 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
505 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
506
507 if (text)
508 {
509 wxString buf(_T(""));
510 long i;
511 int currentLine = 0;
512 for (i = 0; currentLine != lineNo && text[i]; i++ )
513 if (text[i] == '\n')
514 currentLine++;
515 // Now get the text
516 int j;
517 for (j = 0; text[i] && text[i] != '\n'; i++, j++ )
518 buf += text[i];
519
520 g_free( text );
521 return buf;
522 }
523 else
524 return wxEmptyString;
525 }
526 else
527 {
528 if (lineNo == 0) return GetValue();
529 return wxEmptyString;
530 }
531 }
532
533 void wxTextCtrl::OnDropFiles( wxDropFilesEvent &WXUNUSED(event) )
534 {
535 /* If you implement this, don't forget to update the documentation!
536 * (file docs/latex/wx/text.tex) */
537 wxFAIL_MSG( _T("wxTextCtrl::OnDropFiles not implemented") );
538 }
539
540 long wxTextCtrl::PositionToXY(long pos, long *x, long *y ) const
541 {
542 if ( m_windowStyle & wxTE_MULTILINE )
543 {
544 wxString text = GetValue();
545
546 // cast to prevent warning. But pos really should've been unsigned.
547 if( (unsigned long)pos > text.Len() )
548 return FALSE;
549
550 *x=0; // First Col
551 *y=0; // First Line
552
553 const wxChar* stop = text.c_str() + pos;
554 for ( const wxChar *p = text.c_str(); p < stop; p++ )
555 {
556 if (*p == _T('\n'))
557 {
558 (*y)++;
559 *x=0;
560 }
561 else
562 (*x)++;
563 }
564 }
565 else // single line control
566 {
567 if ( pos <= GTK_ENTRY(m_text)->text_length )
568 {
569 *y = 0;
570 *x = pos;
571 }
572 else
573 {
574 // index out of bounds
575 return FALSE;
576 }
577 }
578
579 return TRUE;
580 }
581
582 long wxTextCtrl::XYToPosition(long x, long y ) const
583 {
584 if (!(m_windowStyle & wxTE_MULTILINE)) return 0;
585
586 long pos=0;
587 for( int i=0; i<y; i++ ) pos += GetLineLength(i) + 1; // one for '\n'
588
589 pos += x;
590 return pos;
591 }
592
593 int wxTextCtrl::GetLineLength(long lineNo) const
594 {
595 wxString str = GetLineText (lineNo);
596 return (int) str.Length();
597 }
598
599 int wxTextCtrl::GetNumberOfLines() const
600 {
601 if (m_windowStyle & wxTE_MULTILINE)
602 {
603 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
604 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
605
606 if (text)
607 {
608 int currentLine = 0;
609 for (int i = 0; i < len; i++ )
610 {
611 if (text[i] == '\n')
612 currentLine++;
613 }
614 g_free( text );
615
616 // currentLine is 0 based, add 1 to get number of lines
617 return currentLine + 1;
618 }
619 else
620 {
621 return 0;
622 }
623 }
624 else
625 {
626 return 1;
627 }
628 }
629
630 void wxTextCtrl::SetInsertionPoint( long pos )
631 {
632 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
633
634 if (m_windowStyle & wxTE_MULTILINE)
635 {
636 /* seems to be broken in GTK 1.0.X:
637 gtk_text_set_point( GTK_TEXT(m_text), (int)pos ); */
638
639 gtk_signal_disconnect_by_func( GTK_OBJECT(m_text),
640 GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
641
642 /* we fake a set_point by inserting and deleting. as the user
643 isn't supposed to get to know about thos non-sense, we
644 disconnect so that no events are sent to the user program. */
645
646 gint tmp = (gint)pos;
647 gtk_editable_insert_text( GTK_EDITABLE(m_text), " ", 1, &tmp );
648 gtk_editable_delete_text( GTK_EDITABLE(m_text), tmp-1, tmp );
649
650 gtk_signal_connect( GTK_OBJECT(m_text), "changed",
651 GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
652
653 /* bring editable's cursor uptodate. another bug in GTK. */
654
655 GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
656 }
657 else
658 {
659 gtk_entry_set_position( GTK_ENTRY(m_text), (int)pos );
660
661 /* bring editable's cursor uptodate. bug in GTK. */
662
663 GTK_EDITABLE(m_text)->current_pos = pos;
664 }
665 }
666
667 void wxTextCtrl::SetInsertionPointEnd()
668 {
669 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
670
671 if (m_windowStyle & wxTE_MULTILINE)
672 SetInsertionPoint(gtk_text_get_length(GTK_TEXT(m_text)));
673 else
674 gtk_entry_set_position( GTK_ENTRY(m_text), -1 );
675 }
676
677 void wxTextCtrl::SetEditable( bool editable )
678 {
679 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
680
681 if (m_windowStyle & wxTE_MULTILINE)
682 gtk_text_set_editable( GTK_TEXT(m_text), editable );
683 else
684 gtk_entry_set_editable( GTK_ENTRY(m_text), editable );
685 }
686
687 void wxTextCtrl::SetSelection( long from, long to )
688 {
689 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
690
691 gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
692 }
693
694 void wxTextCtrl::ShowPosition( long WXUNUSED(pos) )
695 {
696 wxFAIL_MSG( _T("wxTextCtrl::ShowPosition not implemented") );
697 }
698
699 long wxTextCtrl::GetInsertionPoint() const
700 {
701 wxCHECK_MSG( m_text != NULL, 0, _T("invalid text ctrl") );
702
703 return (long) GTK_EDITABLE(m_text)->current_pos;
704 }
705
706 long wxTextCtrl::GetLastPosition() const
707 {
708 wxCHECK_MSG( m_text != NULL, 0, _T("invalid text ctrl") );
709
710 int pos = 0;
711 if (m_windowStyle & wxTE_MULTILINE)
712 pos = gtk_text_get_length( GTK_TEXT(m_text) );
713 else
714 pos = GTK_ENTRY(m_text)->text_length;
715
716 return (long)pos;
717 }
718
719 void wxTextCtrl::Remove( long from, long to )
720 {
721 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
722
723 gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
724 }
725
726 void wxTextCtrl::Replace( long from, long to, const wxString &value )
727 {
728 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
729
730 gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
731 if (value.IsNull()) return;
732 gint pos = (gint)from;
733 #if wxUSE_UNICODE
734 wxWX2MBbuf buf = value.mbc_str();
735 gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &pos );
736 #else
737 gtk_editable_insert_text( GTK_EDITABLE(m_text), value, value.Length(), &pos );
738 #endif
739 }
740
741 void wxTextCtrl::Cut()
742 {
743 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
744
745 #if (GTK_MINOR_VERSION > 0)
746 gtk_editable_cut_clipboard( GTK_EDITABLE(m_text) );
747 #else
748 gtk_editable_cut_clipboard( GTK_EDITABLE(m_text), 0 );
749 #endif
750 }
751
752 void wxTextCtrl::Copy()
753 {
754 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
755
756 #if (GTK_MINOR_VERSION > 0)
757 gtk_editable_copy_clipboard( GTK_EDITABLE(m_text) );
758 #else
759 gtk_editable_copy_clipboard( GTK_EDITABLE(m_text), 0 );
760 #endif
761 }
762
763 void wxTextCtrl::Paste()
764 {
765 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
766
767 #if (GTK_MINOR_VERSION > 0)
768 gtk_editable_paste_clipboard( GTK_EDITABLE(m_text) );
769 #else
770 gtk_editable_paste_clipboard( GTK_EDITABLE(m_text), 0 );
771 #endif
772 }
773
774 bool wxTextCtrl::CanCopy() const
775 {
776 // Can copy if there's a selection
777 long from, to;
778 GetSelection(& from, & to);
779 return (from != to) ;
780 }
781
782 bool wxTextCtrl::CanCut() const
783 {
784 // Can cut if there's a selection
785 long from, to;
786 GetSelection(& from, & to);
787 return (from != to) ;
788 }
789
790 bool wxTextCtrl::CanPaste() const
791 {
792 return IsEditable() ;
793 }
794
795 // Undo/redo
796 void wxTextCtrl::Undo()
797 {
798 // TODO
799 wxFAIL_MSG( _T("wxTextCtrl::Undo not implemented") );
800 }
801
802 void wxTextCtrl::Redo()
803 {
804 // TODO
805 wxFAIL_MSG( _T("wxTextCtrl::Redo not implemented") );
806 }
807
808 bool wxTextCtrl::CanUndo() const
809 {
810 // TODO
811 wxFAIL_MSG( _T("wxTextCtrl::CanUndo not implemented") );
812 return FALSE;
813 }
814
815 bool wxTextCtrl::CanRedo() const
816 {
817 // TODO
818 wxFAIL_MSG( _T("wxTextCtrl::CanRedo not implemented") );
819 return FALSE;
820 }
821
822 // If the return values from and to are the same, there is no
823 // selection.
824 void wxTextCtrl::GetSelection(long* from, long* to) const
825 {
826 // TODO
827 *from = 0;
828 *to = 0;
829 wxFAIL_MSG( _T("wxTextCtrl::GetSelection not implemented") );
830 }
831
832 bool wxTextCtrl::IsEditable() const
833 {
834 // TODO
835 wxFAIL_MSG( _T("wxTextCtrl::IsEditable not implemented") );
836 return FALSE;
837 }
838
839 void wxTextCtrl::Clear()
840 {
841 SetValue( _T("") );
842 }
843
844 void wxTextCtrl::OnChar( wxKeyEvent &key_event )
845 {
846 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
847
848 if ((key_event.KeyCode() == WXK_RETURN) && (m_windowStyle & wxPROCESS_ENTER))
849 {
850 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
851 event.SetEventObject(this);
852 if (GetEventHandler()->ProcessEvent(event)) return;
853 }
854
855 key_event.Skip();
856 }
857
858 #ifndef NO_TEXT_WINDOW_STREAM
859 int wxTextCtrl::overflow( int WXUNUSED(c) )
860 {
861 int len = pptr() - pbase();
862 char *txt = new char[len+1];
863 strncpy(txt, pbase(), len);
864 txt[len] = '\0';
865 (*this) << txt;
866 setp(pbase(), epptr());
867 delete[] txt;
868 return EOF;
869 }
870
871 int wxTextCtrl::sync()
872 {
873 int len = pptr() - pbase();
874 char *txt = new char[len+1];
875 strncpy(txt, pbase(), len);
876 txt[len] = '\0';
877 (*this) << txt;
878 setp(pbase(), epptr());
879 delete[] txt;
880 return 0;
881 }
882
883 int wxTextCtrl::underflow()
884 {
885 return EOF;
886 }
887
888 wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
889 {
890 AppendText(s);
891 return *this;
892 }
893
894 wxTextCtrl& wxTextCtrl::operator<<(float f)
895 {
896 static char buf[100];
897 sprintf(buf, "%.2f", f);
898 AppendText(buf);
899 return *this;
900 }
901
902 wxTextCtrl& wxTextCtrl::operator<<(double d)
903 {
904 static char buf[100];
905 sprintf(buf, "%.2f", d);
906 AppendText(buf);
907 return *this;
908 }
909
910 wxTextCtrl& wxTextCtrl::operator<<(int i)
911 {
912 static char buf[100];
913 sprintf(buf, "%i", i);
914 AppendText(buf);
915 return *this;
916 }
917
918 wxTextCtrl& wxTextCtrl::operator<<(long i)
919 {
920 static char buf[100];
921 sprintf(buf, "%ld", i);
922 AppendText(buf);
923 return *this;
924 }
925
926 wxTextCtrl& wxTextCtrl::operator<<(const char c)
927 {
928 char buf[2];
929
930 buf[0] = c;
931 buf[1] = 0;
932 AppendText(buf);
933 return *this;
934 }
935 #endif
936
937 GtkWidget* wxTextCtrl::GetConnectWidget()
938 {
939 return GTK_WIDGET(m_text);
940 }
941
942 bool wxTextCtrl::IsOwnGtkWindow( GdkWindow *window )
943 {
944 if (m_windowStyle & wxTE_MULTILINE)
945 return (window == GTK_TEXT(m_text)->text_area);
946 else
947 return (window == GTK_ENTRY(m_text)->text_area);
948 }
949
950 bool wxTextCtrl::SetFont( const wxFont &WXUNUSED(font) )
951 {
952 wxCHECK_MSG( m_text != NULL, FALSE, _T("invalid text ctrl") );
953
954 // doesn't work
955 return FALSE;
956 }
957
958 bool wxTextCtrl::SetForegroundColour( const wxColour &WXUNUSED(colour) )
959 {
960 wxCHECK_MSG( m_text != NULL, FALSE, _T("invalid text ctrl") );
961
962 // doesn't work
963 return FALSE;
964 }
965
966 bool wxTextCtrl::SetBackgroundColour( const wxColour &colour )
967 {
968 wxCHECK_MSG( m_text != NULL, FALSE, _T("invalid text ctrl") );
969
970 wxControl::SetBackgroundColour( colour );
971
972 if (!m_widget->window)
973 return FALSE;
974
975 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
976 if (sysbg.Red() == colour.Red() &&
977 sysbg.Green() == colour.Green() &&
978 sysbg.Blue() == colour.Blue())
979 {
980 return FALSE; // FIXME or TRUE?
981 }
982
983 if (!m_backgroundColour.Ok())
984 return FALSE;
985
986 if (m_windowStyle & wxTE_MULTILINE)
987 {
988 GdkWindow *window = GTK_TEXT(m_text)->text_area;
989 if (!window)
990 return FALSE;
991 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
992 gdk_window_set_background( window, m_backgroundColour.GetColor() );
993 gdk_window_clear( window );
994 }
995
996 return TRUE;
997 }
998
999 void wxTextCtrl::ApplyWidgetStyle()
1000 {
1001 if (m_windowStyle & wxTE_MULTILINE)
1002 {
1003 // how ?
1004 }
1005 else
1006 {
1007 SetWidgetStyle();
1008 gtk_widget_set_style( m_text, m_widgetStyle );
1009 }
1010 }
1011
1012 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1013 {
1014 Cut();
1015 }
1016
1017 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1018 {
1019 Copy();
1020 }
1021
1022 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1023 {
1024 Paste();
1025 }
1026
1027 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1028 {
1029 Undo();
1030 }
1031
1032 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1033 {
1034 Redo();
1035 }
1036
1037 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1038 {
1039 event.Enable( CanCut() );
1040 }
1041
1042 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1043 {
1044 event.Enable( CanCopy() );
1045 }
1046
1047 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1048 {
1049 event.Enable( CanPaste() );
1050 }
1051
1052 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1053 {
1054 event.Enable( CanUndo() );
1055 }
1056
1057 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1058 {
1059 event.Enable( CanRedo() );
1060 }