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