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