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