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