]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/textctrl.cpp
73293accf3b0cdc0ed4c7c22f6f39f572c2c104c
[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
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 WXUNUSED(pos) )
697 {
698 wxFAIL_MSG( _T("wxTextCtrl::ShowPosition not implemented") );
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 // TODO
829 *from = 0;
830 *to = 0;
831 wxFAIL_MSG( _T("wxTextCtrl::GetSelection not implemented") );
832 }
833
834 bool wxTextCtrl::IsEditable() const
835 {
836 // TODO
837 wxFAIL_MSG( _T("wxTextCtrl::IsEditable not implemented") );
838 return FALSE;
839 }
840
841 void wxTextCtrl::Clear()
842 {
843 SetValue( _T("") );
844 }
845
846 void wxTextCtrl::OnChar( wxKeyEvent &key_event )
847 {
848 wxCHECK_RET( m_text != NULL, _T("invalid text ctrl") );
849
850 if ((key_event.KeyCode() == WXK_RETURN) && (m_windowStyle & wxPROCESS_ENTER))
851 {
852 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
853 event.SetEventObject(this);
854 if (GetEventHandler()->ProcessEvent(event)) return;
855 }
856
857 key_event.Skip();
858 }
859
860 #ifndef NO_TEXT_WINDOW_STREAM
861 int wxTextCtrl::overflow( int WXUNUSED(c) )
862 {
863 int len = pptr() - pbase();
864 char *txt = new char[len+1];
865 strncpy(txt, pbase(), len);
866 txt[len] = '\0';
867 (*this) << txt;
868 setp(pbase(), epptr());
869 delete[] txt;
870 return EOF;
871 }
872
873 int wxTextCtrl::sync()
874 {
875 int len = pptr() - pbase();
876 char *txt = new char[len+1];
877 strncpy(txt, pbase(), len);
878 txt[len] = '\0';
879 (*this) << txt;
880 setp(pbase(), epptr());
881 delete[] txt;
882 return 0;
883 }
884
885 int wxTextCtrl::underflow()
886 {
887 return EOF;
888 }
889
890 wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
891 {
892 AppendText(s);
893 return *this;
894 }
895
896 wxTextCtrl& wxTextCtrl::operator<<(float f)
897 {
898 static char buf[100];
899 sprintf(buf, "%.2f", f);
900 AppendText(buf);
901 return *this;
902 }
903
904 wxTextCtrl& wxTextCtrl::operator<<(double d)
905 {
906 static char buf[100];
907 sprintf(buf, "%.2f", d);
908 AppendText(buf);
909 return *this;
910 }
911
912 wxTextCtrl& wxTextCtrl::operator<<(int i)
913 {
914 static char buf[100];
915 sprintf(buf, "%i", i);
916 AppendText(buf);
917 return *this;
918 }
919
920 wxTextCtrl& wxTextCtrl::operator<<(long i)
921 {
922 static char buf[100];
923 sprintf(buf, "%ld", i);
924 AppendText(buf);
925 return *this;
926 }
927
928 wxTextCtrl& wxTextCtrl::operator<<(const char c)
929 {
930 char buf[2];
931
932 buf[0] = c;
933 buf[1] = 0;
934 AppendText(buf);
935 return *this;
936 }
937 #endif
938
939 GtkWidget* wxTextCtrl::GetConnectWidget()
940 {
941 return GTK_WIDGET(m_text);
942 }
943
944 bool wxTextCtrl::IsOwnGtkWindow( GdkWindow *window )
945 {
946 if (m_windowStyle & wxTE_MULTILINE)
947 return (window == GTK_TEXT(m_text)->text_area);
948 else
949 return (window == GTK_ENTRY(m_text)->text_area);
950 }
951
952 bool wxTextCtrl::SetFont( const wxFont &WXUNUSED(font) )
953 {
954 wxCHECK_MSG( m_text != NULL, FALSE, _T("invalid text ctrl") );
955
956 // doesn't work
957 return FALSE;
958 }
959
960 bool wxTextCtrl::SetForegroundColour( const wxColour &WXUNUSED(colour) )
961 {
962 wxCHECK_MSG( m_text != NULL, FALSE, _T("invalid text ctrl") );
963
964 // doesn't work
965 return FALSE;
966 }
967
968 bool wxTextCtrl::SetBackgroundColour( const wxColour &colour )
969 {
970 wxCHECK_MSG( m_text != NULL, FALSE, _T("invalid text ctrl") );
971
972 wxControl::SetBackgroundColour( colour );
973
974 if (!m_widget->window)
975 return FALSE;
976
977 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
978 if (sysbg.Red() == colour.Red() &&
979 sysbg.Green() == colour.Green() &&
980 sysbg.Blue() == colour.Blue())
981 {
982 return FALSE; // FIXME or TRUE?
983 }
984
985 if (!m_backgroundColour.Ok())
986 return FALSE;
987
988 if (m_windowStyle & wxTE_MULTILINE)
989 {
990 GdkWindow *window = GTK_TEXT(m_text)->text_area;
991 if (!window)
992 return FALSE;
993 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
994 gdk_window_set_background( window, m_backgroundColour.GetColor() );
995 gdk_window_clear( window );
996 }
997
998 return TRUE;
999 }
1000
1001 void wxTextCtrl::ApplyWidgetStyle()
1002 {
1003 if (m_windowStyle & wxTE_MULTILINE)
1004 {
1005 // how ?
1006 }
1007 else
1008 {
1009 SetWidgetStyle();
1010 gtk_widget_set_style( m_text, m_widgetStyle );
1011 }
1012 }
1013
1014 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1015 {
1016 Cut();
1017 }
1018
1019 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1020 {
1021 Copy();
1022 }
1023
1024 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1025 {
1026 Paste();
1027 }
1028
1029 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1030 {
1031 Undo();
1032 }
1033
1034 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1035 {
1036 Redo();
1037 }
1038
1039 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1040 {
1041 event.Enable( CanCut() );
1042 }
1043
1044 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1045 {
1046 event.Enable( CanCopy() );
1047 }
1048
1049 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1050 {
1051 event.Enable( CanPaste() );
1052 }
1053
1054 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1055 {
1056 event.Enable( CanUndo() );
1057 }
1058
1059 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1060 {
1061 event.Enable( CanRedo() );
1062 }