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