]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/textctrl.cpp
compilation fix
[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 16#include "wx/intl.h"
a1f79c1e 17#include "wx/log.h"
ae0bdb01 18#include "wx/settings.h"
fc71ef6e 19#include "wx/panel.h"
c801d85f 20
a81258be
RR
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <ctype.h>
817ec43a 24#include <math.h> // for fabs
a81258be 25
83624f79
RR
26#include "gdk/gdk.h"
27#include "gtk/gtk.h"
b292e2f5
RR
28#include "gdk/gdkkeysyms.h"
29
acfd422a
RR
30//-----------------------------------------------------------------------------
31// idle system
32//-----------------------------------------------------------------------------
33
34extern void wxapp_install_idle_handler();
35extern bool g_isIdle;
36
b292e2f5
RR
37//-----------------------------------------------------------------------------
38// data
39//-----------------------------------------------------------------------------
40
65045edd
RR
41extern bool g_blockEventsOnDrag;
42extern wxCursor g_globalCursor;
b292e2f5 43
c801d85f 44//-----------------------------------------------------------------------------
2f2aa628 45// "changed"
c801d85f
KB
46//-----------------------------------------------------------------------------
47
805dd538 48static void
2830bf19 49gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
484e45bf 50{
a2053b27 51 if (!win->m_hasVMT) return;
805dd538 52
bb69661b 53 if (g_isIdle)
3c679789
RR
54 wxapp_install_idle_handler();
55
034be888 56 win->SetModified();
01041145 57 win->UpdateFontIfNeeded();
8bbe427f 58
f03fc89f 59 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
8a85884a 60 event.SetString( win->GetValue() );
2830bf19
RR
61 event.SetEventObject( win );
62 win->GetEventHandler()->ProcessEvent( event );
6de97a3b 63}
112892b9 64
2830bf19 65//-----------------------------------------------------------------------------
034be888 66// "changed" from vertical scrollbar
2830bf19
RR
67//-----------------------------------------------------------------------------
68
805dd538 69static void
034be888 70gtk_scrollbar_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
2830bf19 71{
3c679789 72 if (!win->m_hasVMT) return;
bb69661b
VZ
73
74 if (g_isIdle)
3c679789 75 wxapp_install_idle_handler();
acfd422a 76
2830bf19
RR
77 win->CalculateScrollbar();
78}
79
fc71ef6e
JS
80//-----------------------------------------------------------------------------
81// "focus_in_event"
82//-----------------------------------------------------------------------------
83
fc71ef6e
JS
84extern wxWindow *g_focusWindow;
85extern bool g_blockEventsOnDrag;
86// extern bool g_isIdle;
87
88static gint gtk_text_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
89{
90 // Necessary?
91#if 0
92 if (g_isIdle)
93 wxapp_install_idle_handler();
94#endif
95 if (!win->m_hasVMT) return FALSE;
96 if (g_blockEventsOnDrag) return FALSE;
97
98 g_focusWindow = win;
99
5314ac16
VZ
100 // notify the parent that we got the focus
101 wxChildFocusEvent eventFocus(win);
102 (void)win->GetEventHandler()->ProcessEvent(eventFocus);
fc71ef6e
JS
103
104#ifdef HAVE_XIM
105 if (win->m_ic)
106 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
107#endif
108
109#if 0
110#ifdef wxUSE_CARET
111 // caret needs to be informed about focus change
112 wxCaret *caret = win->GetCaret();
113 if ( caret )
114 {
115 caret->OnSetFocus();
116 }
117#endif // wxUSE_CARET
118#endif
119
120 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
121 event.SetEventObject( win );
122
123 if (win->GetEventHandler()->ProcessEvent( event ))
124 {
fc71ef6e
JS
125 return TRUE;
126 }
127
128 return FALSE;
129}
130
131//-----------------------------------------------------------------------------
132// "focus_out_event"
133//-----------------------------------------------------------------------------
134
135static gint gtk_text_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
136{
137#if 0
138 if (g_isIdle)
139 wxapp_install_idle_handler();
140#endif
141
142 if (!win->m_hasVMT) return FALSE;
143 if (g_blockEventsOnDrag) return FALSE;
144
145#if 0
146 // if the focus goes out of our app alltogether, OnIdle() will send
147 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
148 // g_sendActivateEvent to -1
149 g_sendActivateEvent = 0;
150#endif
151
3379ed37 152 wxWindow *winFocus = wxFindFocusedChild(win);
fc71ef6e
JS
153 if ( winFocus )
154 win = winFocus;
155
156 g_focusWindow = (wxWindow *)NULL;
157
158#ifdef HAVE_XIM
159 if (win->m_ic)
160 gdk_im_end();
161#endif
162
163#if 0
164#ifdef wxUSE_CARET
165 // caret needs to be informed about focus change
166 wxCaret *caret = win->GetCaret();
167 if ( caret )
168 {
169 caret->OnKillFocus();
170 }
171#endif // wxUSE_CARET
172#endif
173
174 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
175 event.SetEventObject( win );
176
177 if (win->GetEventHandler()->ProcessEvent( event ))
178 {
fc71ef6e
JS
179 return TRUE;
180 }
181
182 return FALSE;
183}
184
2f2aa628
RR
185//-----------------------------------------------------------------------------
186// wxTextCtrl
187//-----------------------------------------------------------------------------
188
189IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl,wxControl)
190
c801d85f 191BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
2830bf19 192 EVT_CHAR(wxTextCtrl::OnChar)
e702ff0f
JS
193
194 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
195 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
196 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
197 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
198 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
199
200 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
201 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
202 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
203 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
204 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
c801d85f
KB
205END_EVENT_TABLE()
206
01041145 207void wxTextCtrl::Init()
f5abe911
RR
208{
209 m_modified = FALSE;
01041145 210 m_updateFont = FALSE;
3ca6a5f0
BP
211 m_text =
212 m_vScrollbar = (GtkWidget *)NULL;
f5abe911 213}
13289f04 214
13111b2a
VZ
215wxTextCtrl::wxTextCtrl( wxWindow *parent,
216 wxWindowID id,
217 const wxString &value,
218 const wxPoint &pos,
219 const wxSize &size,
220 long style,
221 const wxValidator& validator,
222 const wxString &name )
f5abe911 223{
01041145
VZ
224 Init();
225
f5abe911
RR
226 Create( parent, id, value, pos, size, style, validator, name );
227}
c801d85f 228
13111b2a
VZ
229bool wxTextCtrl::Create( wxWindow *parent,
230 wxWindowID id,
231 const wxString &value,
232 const wxPoint &pos,
233 const wxSize &size,
234 long style,
235 const wxValidator& validator,
236 const wxString &name )
c801d85f 237{
2830bf19 238 m_needParent = TRUE;
b292e2f5 239 m_acceptsFocus = TRUE;
484e45bf 240
4dcaf11a
RR
241 if (!PreCreation( parent, pos, size ) ||
242 !CreateBase( parent, id, pos, size, style, validator, name ))
243 {
223d09f6 244 wxFAIL_MSG( wxT("wxTextCtrl creation failed") );
13111b2a 245 return FALSE;
4dcaf11a 246 }
6de97a3b 247
805dd538 248
034be888 249 m_vScrollbarVisible = FALSE;
13289f04 250
2830bf19 251 bool multi_line = (style & wxTE_MULTILINE) != 0;
ab46dc18 252 if (multi_line)
2830bf19 253 {
7d6d2cd4 254#if (GTK_MINOR_VERSION > 2)
034be888
RR
255 /* a multi-line edit control: create a vertical scrollbar by default and
256 horizontal if requested */
2830bf19 257 bool bHasHScrollbar = (style & wxHSCROLL) != 0;
7d6d2cd4
RR
258#else
259 bool bHasHScrollbar = FALSE;
260#endif
805dd538 261
034be888 262 /* create our control ... */
2830bf19
RR
263 m_text = gtk_text_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
264
034be888 265 /* ... and put into the upper left hand corner of the table */
2830bf19 266 m_widget = gtk_table_new(bHasHScrollbar ? 2 : 1, 2, FALSE);
5664fc32 267 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2830bf19 268 gtk_table_attach( GTK_TABLE(m_widget), m_text, 0, 1, 0, 1,
41dee9d0 269 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK),
f5368809
RR
270 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK),
271 0, 0);
bb69661b 272
5c387335
RR
273 /* always wrap words */
274 gtk_text_set_word_wrap( GTK_TEXT(m_text), TRUE );
bb69661b 275
7d6d2cd4 276#if (GTK_MINOR_VERSION > 2)
034be888 277 /* put the horizontal scrollbar in the lower left hand corner */
2830bf19
RR
278 if (bHasHScrollbar)
279 {
280 GtkWidget *hscrollbar = gtk_hscrollbar_new(GTK_TEXT(m_text)->hadj);
5664fc32 281 GTK_WIDGET_UNSET_FLAGS( hscrollbar, GTK_CAN_FOCUS );
2830bf19 282 gtk_table_attach(GTK_TABLE(m_widget), hscrollbar, 0, 1, 1, 2,
8ce63e9d 283 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK),
13289f04
VZ
284 GTK_FILL,
285 0, 0);
2830bf19 286 gtk_widget_show(hscrollbar);
13289f04 287
3358d36e
VZ
288 /* don't wrap lines, otherwise we wouldn't need the scrollbar */
289 gtk_text_set_line_wrap( GTK_TEXT(m_text), FALSE );
5c387335 290 }
7d6d2cd4 291#endif
bb69661b 292
ab46dc18
RR
293 /* finally, put the vertical scrollbar in the upper right corner */
294 m_vScrollbar = gtk_vscrollbar_new( GTK_TEXT(m_text)->vadj );
295 GTK_WIDGET_UNSET_FLAGS( m_vScrollbar, GTK_CAN_FOCUS );
ab46dc18
RR
296 gtk_table_attach(GTK_TABLE(m_widget), m_vScrollbar, 1, 2, 0, 1,
297 GTK_FILL,
298 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK),
299 0, 0);
2830bf19
RR
300 }
301 else
302 {
034be888 303 /* a single-line text control: no need for scrollbars */
2830bf19
RR
304 m_widget =
305 m_text = gtk_entry_new();
306 }
484e45bf 307
db434467
RR
308 m_parent->DoAddChild( this );
309
310 PostCreation();
311
312 SetFont( parent->GetFont() );
313
314 wxSize size_best( DoGetBestSize() );
315 wxSize new_size( size );
0279e844 316 if (new_size.x == -1)
db434467 317 new_size.x = size_best.x;
0279e844 318 if (new_size.y == -1)
db434467 319 new_size.y = size_best.y;
0279e844
RR
320 if ((new_size.x != size.x) || (new_size.y != size.y))
321 SetSize( new_size.x, new_size.y );
484e45bf 322
2830bf19 323 if (multi_line)
2830bf19 324 gtk_widget_show(m_text);
13289f04 325
ab46dc18
RR
326 if (multi_line)
327 {
328 gtk_signal_connect(GTK_OBJECT(GTK_TEXT(m_text)->vadj), "changed",
329 (GtkSignalFunc) gtk_scrollbar_changed_callback, (gpointer) this );
fc71ef6e
JS
330
331 gtk_signal_connect( GTK_OBJECT(GTK_TEXT(m_text)), "focus_in_event",
332 GTK_SIGNAL_FUNC(gtk_text_focus_in_callback), (gpointer)this );
333
334 gtk_signal_connect( GTK_OBJECT(GTK_TEXT(m_text)), "focus_out_event",
335 GTK_SIGNAL_FUNC(gtk_text_focus_out_callback), (gpointer)this );
336 }
337 else
338 {
339 gtk_signal_connect( GTK_OBJECT(m_text), "focus_in_event",
340 GTK_SIGNAL_FUNC(gtk_text_focus_in_callback), (gpointer)this );
341
342 gtk_signal_connect( GTK_OBJECT(m_text), "focus_out_event",
343 GTK_SIGNAL_FUNC(gtk_text_focus_out_callback), (gpointer)this );
ab46dc18 344 }
3358d36e 345
291a8f20 346 if (!value.IsEmpty())
2830bf19
RR
347 {
348 gint tmp = 0;
3358d36e
VZ
349
350#if GTK_MINOR_VERSION == 0
351 // if we don't realize it, GTK 1.0.6 dies with a SIGSEGV in
352 // gtk_editable_insert_text()
353 gtk_widget_realize(m_text);
354#endif // GTK 1.0
355
05939a81 356#if wxUSE_UNICODE
3358d36e 357 wxWX2MBbuf val = value.mbc_str();
05939a81 358 gtk_editable_insert_text( GTK_EDITABLE(m_text), val, strlen(val), &tmp );
3358d36e 359#else // !Unicode
2830bf19 360 gtk_editable_insert_text( GTK_EDITABLE(m_text), value, value.Length(), &tmp );
3358d36e
VZ
361#endif // Unicode/!Unicode
362
291a8f20
RR
363 if (multi_line)
364 {
3358d36e
VZ
365 /* bring editable's cursor uptodate. bug in GTK. */
366
367 GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
368 }
2830bf19 369 }
484e45bf 370
2830bf19
RR
371 if (style & wxTE_PASSWORD)
372 {
373 if (!multi_line)
374 gtk_entry_set_visibility( GTK_ENTRY(m_text), FALSE );
375 }
8bbe427f 376
2830bf19
RR
377 if (style & wxTE_READONLY)
378 {
379 if (!multi_line)
380 gtk_entry_set_editable( GTK_ENTRY(m_text), FALSE );
381 }
382 else
383 {
384 if (multi_line)
385 gtk_text_set_editable( GTK_TEXT(m_text), 1 );
386 }
3358d36e 387
ce16e5d7
RR
388 /* we want to be notified about text changes */
389 gtk_signal_connect( GTK_OBJECT(m_text), "changed",
390 GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
391
a88acabd
JS
392 /* we don't set a valid background colour, because the window
393 manager should use a default one */
394 m_backgroundColour = wxColour();
17665a2b
VZ
395
396 wxColour colFg = parent->GetForegroundColour();
397 SetForegroundColour( colFg );
805dd538 398
65045edd 399 m_cursor = wxCursor( wxCURSOR_IBEAM );
13111b2a 400
17665a2b
VZ
401 // FIXME: is the bg colour correct here?
402 wxTextAttr attrDef( colFg,
403 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW),
404 parent->GetFont() );
405 SetDefaultStyle( attrDef );
406
2830bf19 407 Show( TRUE );
805dd538 408
2830bf19
RR
409 return TRUE;
410}
484e45bf 411
2830bf19
RR
412void wxTextCtrl::CalculateScrollbar()
413{
414 if ((m_windowStyle & wxTE_MULTILINE) == 0) return;
f96aa4d9 415
2830bf19 416 GtkAdjustment *adj = GTK_TEXT(m_text)->vadj;
805dd538 417
2830bf19
RR
418 if (adj->upper - adj->page_size < 0.8)
419 {
420 if (m_vScrollbarVisible)
421 {
034be888 422 gtk_widget_hide( m_vScrollbar );
034be888 423 m_vScrollbarVisible = FALSE;
2830bf19
RR
424 }
425 }
426 else
427 {
428 if (!m_vScrollbarVisible)
429 {
034be888 430 gtk_widget_show( m_vScrollbar );
034be888 431 m_vScrollbarVisible = TRUE;
2830bf19
RR
432 }
433 }
6de97a3b 434}
c801d85f 435
03f38c58 436wxString wxTextCtrl::GetValue() const
c801d85f 437{
223d09f6 438 wxCHECK_MSG( m_text != NULL, wxT(""), wxT("invalid text ctrl") );
8bbe427f 439
2830bf19
RR
440 wxString tmp;
441 if (m_windowStyle & wxTE_MULTILINE)
442 {
443 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
444 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
dcf924a3 445 tmp = wxString(text,*wxConvCurrent);
2830bf19
RR
446 g_free( text );
447 }
448 else
449 {
dcf924a3 450 tmp = wxString(gtk_entry_get_text( GTK_ENTRY(m_text) ),*wxConvCurrent);
2830bf19
RR
451 }
452 return tmp;
6de97a3b 453}
c801d85f
KB
454
455void wxTextCtrl::SetValue( const wxString &value )
456{
223d09f6 457 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 458
2830bf19
RR
459 if (m_windowStyle & wxTE_MULTILINE)
460 {
461 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
462 gtk_editable_delete_text( GTK_EDITABLE(m_text), 0, len );
463 len = 0;
05939a81 464#if wxUSE_UNICODE
01041145 465 wxWX2MBbuf tmpbuf = value.mbc_str();
05939a81
OK
466 gtk_editable_insert_text( GTK_EDITABLE(m_text), tmpbuf, strlen(tmpbuf), &len );
467#else
01041145 468 gtk_editable_insert_text( GTK_EDITABLE(m_text), value.mbc_str(), value.Length(), &len );
05939a81 469#endif
2830bf19
RR
470 }
471 else
472 {
01041145 473 gtk_entry_set_text( GTK_ENTRY(m_text), value.mbc_str() );
2830bf19 474 }
f6bcfd97
BP
475
476 // GRG, Jun/2000: Changed this after a lot of discussion in
477 // the lists. wxWindows 2.2 will have a set of flags to
478 // customize this behaviour.
479 SetInsertionPoint(0);
480
481 m_modified = FALSE;
6de97a3b 482}
c801d85f
KB
483
484void wxTextCtrl::WriteText( const wxString &text )
485{
223d09f6 486 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 487
17665a2b
VZ
488 if ( text.empty() )
489 return;
484e45bf 490
17665a2b
VZ
491#if wxUSE_UNICODE
492 wxWX2MBbuf buf = text.mbc_str();
493 const char *txt = buf;
494 size_t txtlen = strlen(buf);
495#else
496 const char *txt = text;
497 size_t txtlen = text.length();
498#endif
499
500 if ( m_windowStyle & wxTE_MULTILINE )
2830bf19 501 {
291a8f20 502 /* this moves the cursor pos to behind the inserted text */
3358d36e 503 gint len = GTK_EDITABLE(m_text)->current_pos;
13111b2a 504
17665a2b
VZ
505 // if we have any special style, use it
506 if ( !m_defaultStyle.IsDefault() )
507 {
508 GdkFont *font = m_defaultStyle.HasFont()
509 ? m_defaultStyle.GetFont().GetInternalFont()
510 : NULL;
511
512 GdkColor *colFg = m_defaultStyle.HasTextColour()
513 ? m_defaultStyle.GetTextColour().GetColor()
514 : NULL;
515
516 GdkColor *colBg = m_defaultStyle.HasBackgroundColour()
517 ? m_defaultStyle.GetBackgroundColour().GetColor()
518 : NULL;
519
520 gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, txtlen );
521 }
522 else // no style
523 {
524 gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len );
525 }
3358d36e
VZ
526
527 /* bring editable's cursor uptodate. bug in GTK. */
528 GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
2830bf19 529 }
17665a2b 530 else // single line
2830bf19 531 {
c46554be 532 /* this moves the cursor pos to behind the inserted text */
3358d36e 533 gint len = GTK_EDITABLE(m_text)->current_pos;
17665a2b 534 gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len );
3358d36e
VZ
535
536 /* bring editable's cursor uptodate. bug in GTK. */
537 GTK_EDITABLE(m_text)->current_pos += text.Len();
538
539 /* bring entry's cursor uptodate. bug in GTK. */
540 gtk_entry_set_position( GTK_ENTRY(m_text), GTK_EDITABLE(m_text)->current_pos );
2830bf19 541 }
6de97a3b 542}
c801d85f 543
a6e21573
HH
544void wxTextCtrl::AppendText( const wxString &text )
545{
223d09f6 546 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
a6e21573 547
17665a2b
VZ
548 if ( text.empty() )
549 return;
550
551#if wxUSE_UNICODE
552 wxWX2MBbuf buf = text.mbc_str();
553 const char *txt = buf;
554 size_t txtlen = strlen(buf);
555#else
556 const char *txt = text;
557 size_t txtlen = text.length();
558#endif
2df7be7f 559
a6e21573
HH
560 if (m_windowStyle & wxTE_MULTILINE)
561 {
17665a2b 562 if ( !m_defaultStyle.IsDefault() )
bb69661b 563 {
1ff4714d
VZ
564 wxFont font = m_defaultStyle.HasFont() ? m_defaultStyle.GetFont()
565 : m_font;
566 GdkFont *fnt = font.Ok() ? font.GetInternalFont() : NULL;
17665a2b 567
1ff4714d
VZ
568 wxColour col = m_defaultStyle.HasTextColour()
569 ? m_defaultStyle.GetTextColour()
570 : m_foregroundColour;
571 GdkColor *colFg = col.Ok() ? col.GetColor() : NULL;
bb69661b 572
1ff4714d
VZ
573 col = m_defaultStyle.HasBackgroundColour()
574 ? m_defaultStyle.GetBackgroundColour()
575 : m_backgroundColour;
576 GdkColor *colBg = col.Ok() ? col.GetColor() : NULL;
17665a2b 577
1ff4714d 578 gtk_text_insert( GTK_TEXT(m_text), fnt, colFg, colBg, txt, txtlen );
bb69661b 579 }
17665a2b 580 else // no style
bb69661b
VZ
581 {
582 /* we'll insert at the last position */
583 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
17665a2b 584 gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len );
bb69661b 585 }
3358d36e
VZ
586
587 /* bring editable's cursor uptodate. bug in GTK. */
588 GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
a6e21573 589 }
17665a2b 590 else // single line
a6e21573 591 {
17665a2b 592 gtk_entry_append_text( GTK_ENTRY(m_text), txt );
a6e21573
HH
593 }
594}
595
debe6624 596wxString wxTextCtrl::GetLineText( long lineNo ) const
c801d85f 597{
a81258be
RR
598 if (m_windowStyle & wxTE_MULTILINE)
599 {
600 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
601 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
602
603 if (text)
604 {
223d09f6 605 wxString buf(wxT(""));
a81258be
RR
606 long i;
607 int currentLine = 0;
608 for (i = 0; currentLine != lineNo && text[i]; i++ )
609 if (text[i] == '\n')
610 currentLine++;
611 // Now get the text
612 int j;
613 for (j = 0; text[i] && text[i] != '\n'; i++, j++ )
614 buf += text[i];
8bbe427f 615
a81258be
RR
616 g_free( text );
617 return buf;
618 }
619 else
620 return wxEmptyString;
621 }
622 else
623 {
624 if (lineNo == 0) return GetValue();
625 return wxEmptyString;
626 }
6de97a3b 627}
c801d85f 628
a81258be
RR
629void wxTextCtrl::OnDropFiles( wxDropFilesEvent &WXUNUSED(event) )
630{
ac0d36b5
HH
631 /* If you implement this, don't forget to update the documentation!
632 * (file docs/latex/wx/text.tex) */
223d09f6 633 wxFAIL_MSG( wxT("wxTextCtrl::OnDropFiles not implemented") );
a81258be 634}
112892b9 635
0efe5ba7 636bool wxTextCtrl::PositionToXY(long pos, long *x, long *y ) const
c801d85f 637{
96385642 638 if ( m_windowStyle & wxTE_MULTILINE )
805dd538 639 {
96385642
VZ
640 wxString text = GetValue();
641
6085b116 642 // cast to prevent warning. But pos really should've been unsigned.
2829d9e3 643 if( (unsigned long)pos > text.Len() )
96385642
VZ
644 return FALSE;
645
ac0d36b5
HH
646 *x=0; // First Col
647 *y=0; // First Line
2829d9e3 648
05939a81
OK
649 const wxChar* stop = text.c_str() + pos;
650 for ( const wxChar *p = text.c_str(); p < stop; p++ )
96385642 651 {
223d09f6 652 if (*p == wxT('\n'))
96385642
VZ
653 {
654 (*y)++;
ac0d36b5 655 *x=0;
96385642
VZ
656 }
657 else
658 (*x)++;
659 }
805dd538 660 }
96385642
VZ
661 else // single line control
662 {
2829d9e3 663 if ( pos <= GTK_ENTRY(m_text)->text_length )
96385642 664 {
ac0d36b5 665 *y = 0;
96385642
VZ
666 *x = pos;
667 }
668 else
669 {
670 // index out of bounds
671 return FALSE;
672 }
8bbe427f 673 }
96385642
VZ
674
675 return TRUE;
6de97a3b 676}
c801d85f 677
e3ca08dd 678long wxTextCtrl::XYToPosition(long x, long y ) const
c801d85f 679{
2830bf19 680 if (!(m_windowStyle & wxTE_MULTILINE)) return 0;
805dd538 681
2830bf19 682 long pos=0;
ac0d36b5 683 for( int i=0; i<y; i++ ) pos += GetLineLength(i) + 1; // one for '\n'
8bbe427f 684
3358d36e 685 pos += x;
2830bf19 686 return pos;
6de97a3b 687}
c801d85f 688
a81258be 689int wxTextCtrl::GetLineLength(long lineNo) const
c801d85f 690{
a81258be
RR
691 wxString str = GetLineText (lineNo);
692 return (int) str.Length();
6de97a3b 693}
c801d85f 694
a81258be 695int wxTextCtrl::GetNumberOfLines() const
c801d85f 696{
2830bf19 697 if (m_windowStyle & wxTE_MULTILINE)
a81258be 698 {
2830bf19
RR
699 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
700 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
701
702 if (text)
703 {
704 int currentLine = 0;
705 for (int i = 0; i < len; i++ )
96385642 706 {
2830bf19 707 if (text[i] == '\n')
96385642
VZ
708 currentLine++;
709 }
2830bf19 710 g_free( text );
2829d9e3
VZ
711
712 // currentLine is 0 based, add 1 to get number of lines
713 return currentLine + 1;
2830bf19
RR
714 }
715 else
96385642 716 {
2830bf19 717 return 0;
96385642 718 }
a81258be
RR
719 }
720 else
2830bf19 721 {
96385642 722 return 1;
2830bf19 723 }
6de97a3b 724}
c801d85f 725
debe6624 726void wxTextCtrl::SetInsertionPoint( long pos )
c801d85f 727{
223d09f6 728 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
3358d36e
VZ
729
730 if (m_windowStyle & wxTE_MULTILINE)
291a8f20
RR
731 {
732 /* seems to be broken in GTK 1.0.X:
3358d36e
VZ
733 gtk_text_set_point( GTK_TEXT(m_text), (int)pos ); */
734
291a8f20
RR
735 gtk_signal_disconnect_by_func( GTK_OBJECT(m_text),
736 GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
3358d36e 737
291a8f20 738 /* we fake a set_point by inserting and deleting. as the user
3358d36e
VZ
739 isn't supposed to get to know about thos non-sense, we
740 disconnect so that no events are sent to the user program. */
741
291a8f20
RR
742 gint tmp = (gint)pos;
743 gtk_editable_insert_text( GTK_EDITABLE(m_text), " ", 1, &tmp );
3358d36e
VZ
744 gtk_editable_delete_text( GTK_EDITABLE(m_text), tmp-1, tmp );
745
291a8f20
RR
746 gtk_signal_connect( GTK_OBJECT(m_text), "changed",
747 GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
3358d36e
VZ
748
749 /* bring editable's cursor uptodate. another bug in GTK. */
750
751 GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) );
ac0d36b5 752 }
2830bf19 753 else
291a8f20 754 {
d59051dd 755 gtk_entry_set_position( GTK_ENTRY(m_text), (int)pos );
3358d36e
VZ
756
757 /* bring editable's cursor uptodate. bug in GTK. */
758
b02da6b1 759 GTK_EDITABLE(m_text)->current_pos = (guint32)pos;
291a8f20 760 }
6de97a3b 761}
c801d85f 762
03f38c58 763void wxTextCtrl::SetInsertionPointEnd()
c801d85f 764{
223d09f6 765 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 766
d59051dd
VZ
767 if (m_windowStyle & wxTE_MULTILINE)
768 SetInsertionPoint(gtk_text_get_length(GTK_TEXT(m_text)));
769 else
770 gtk_entry_set_position( GTK_ENTRY(m_text), -1 );
6de97a3b 771}
c801d85f 772
debe6624 773void wxTextCtrl::SetEditable( bool editable )
c801d85f 774{
223d09f6 775 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 776
2830bf19
RR
777 if (m_windowStyle & wxTE_MULTILINE)
778 gtk_text_set_editable( GTK_TEXT(m_text), editable );
779 else
780 gtk_entry_set_editable( GTK_ENTRY(m_text), editable );
6de97a3b 781}
c801d85f 782
68df5777
RR
783bool wxTextCtrl::Enable( bool enable )
784{
785 if (!wxWindowBase::Enable(enable))
786 {
787 // nothing to do
788 return FALSE;
789 }
f6bcfd97 790
68df5777
RR
791 if (m_windowStyle & wxTE_MULTILINE)
792 {
793 gtk_text_set_editable( GTK_TEXT(m_text), enable );
5abf8c9d 794 OnParentEnable(enable);
68df5777
RR
795 }
796 else
797 {
798 gtk_widget_set_sensitive( m_text, enable );
799 }
800
801 return TRUE;
802}
803
fdca68a6
JS
804// wxGTK-specific: called recursively by Enable,
805// to give widgets an oppprtunity to correct their colours after they
806// have been changed by Enable
807void wxTextCtrl::OnParentEnable( bool enable )
808{
809 // If we have a custom background colour, we use this colour in both
810 // disabled and enabled mode, or we end up with a different colour under the
811 // text.
812 wxColour oldColour = GetBackgroundColour();
813 if (oldColour.Ok())
814 {
815 // Need to set twice or it'll optimize the useful stuff out
816 if (oldColour == * wxWHITE)
817 SetBackgroundColour(*wxBLACK);
818 else
819 SetBackgroundColour(*wxWHITE);
820 SetBackgroundColour(oldColour);
821 }
822}
823
0efe5ba7
VZ
824void wxTextCtrl::DiscardEdits()
825{
826 m_modified = FALSE;
827}
828
d7eee191
VZ
829void wxTextCtrl::SetMaxLength(unsigned long len)
830{
831 if ( !HasFlag(wxTE_MULTILINE) )
832 {
833 gtk_entry_set_max_length(GTK_ENTRY(m_text), len);
834 }
835}
836
debe6624 837void wxTextCtrl::SetSelection( long from, long to )
c801d85f 838{
223d09f6 839 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 840
a1f79c1e
VZ
841 if ( (m_windowStyle & wxTE_MULTILINE) &&
842 !GTK_TEXT(m_text)->line_start_cache )
843 {
844 // tell the programmer that it didn't work
845 wxLogDebug(_T("Can't call SetSelection() before realizing the control"));
846 return;
847 }
848
2830bf19 849 gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
6de97a3b 850}
c801d85f 851
910f1f8c 852void wxTextCtrl::ShowPosition( long WXUNUSED(pos) )
c801d85f 853{
910f1f8c 854// SetInsertionPoint( pos );
6de97a3b 855}
c801d85f 856
03f38c58 857long wxTextCtrl::GetInsertionPoint() const
c801d85f 858{
223d09f6 859 wxCHECK_MSG( m_text != NULL, 0, wxT("invalid text ctrl") );
8bbe427f 860
2830bf19 861 return (long) GTK_EDITABLE(m_text)->current_pos;
6de97a3b 862}
c801d85f 863
03f38c58 864long wxTextCtrl::GetLastPosition() const
c801d85f 865{
223d09f6 866 wxCHECK_MSG( m_text != NULL, 0, wxT("invalid text ctrl") );
8bbe427f 867
2830bf19
RR
868 int pos = 0;
869 if (m_windowStyle & wxTE_MULTILINE)
870 pos = gtk_text_get_length( GTK_TEXT(m_text) );
871 else
872 pos = GTK_ENTRY(m_text)->text_length;
805dd538 873
ac0d36b5 874 return (long)pos;
6de97a3b 875}
c801d85f 876
debe6624 877void wxTextCtrl::Remove( long from, long to )
c801d85f 878{
223d09f6 879 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 880
2830bf19 881 gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
6de97a3b 882}
c801d85f 883
debe6624 884void wxTextCtrl::Replace( long from, long to, const wxString &value )
c801d85f 885{
223d09f6 886 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 887
2830bf19 888 gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
bb69661b 889
2df7be7f
RR
890 if (!value.IsEmpty())
891 {
892 gint pos = (gint)from;
05939a81 893#if wxUSE_UNICODE
2df7be7f
RR
894 wxWX2MBbuf buf = value.mbc_str();
895 gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &pos );
05939a81 896#else
2df7be7f 897 gtk_editable_insert_text( GTK_EDITABLE(m_text), value, value.Length(), &pos );
05939a81 898#endif
2df7be7f 899 }
6de97a3b 900}
c801d85f 901
03f38c58 902void wxTextCtrl::Cut()
c801d85f 903{
223d09f6 904 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 905
d345e841 906#if (GTK_MINOR_VERSION > 0)
2830bf19 907 gtk_editable_cut_clipboard( GTK_EDITABLE(m_text) );
75ed1d15 908#else
2830bf19 909 gtk_editable_cut_clipboard( GTK_EDITABLE(m_text), 0 );
75ed1d15 910#endif
6de97a3b 911}
c801d85f 912
03f38c58 913void wxTextCtrl::Copy()
c801d85f 914{
223d09f6 915 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 916
d345e841 917#if (GTK_MINOR_VERSION > 0)
2830bf19 918 gtk_editable_copy_clipboard( GTK_EDITABLE(m_text) );
75ed1d15 919#else
2830bf19 920 gtk_editable_copy_clipboard( GTK_EDITABLE(m_text), 0 );
75ed1d15 921#endif
6de97a3b 922}
c801d85f 923
03f38c58 924void wxTextCtrl::Paste()
c801d85f 925{
223d09f6 926 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 927
d345e841 928#if (GTK_MINOR_VERSION > 0)
2830bf19 929 gtk_editable_paste_clipboard( GTK_EDITABLE(m_text) );
75ed1d15 930#else
2830bf19 931 gtk_editable_paste_clipboard( GTK_EDITABLE(m_text), 0 );
75ed1d15 932#endif
6de97a3b 933}
c801d85f 934
ca8b28f2
JS
935// Undo/redo
936void wxTextCtrl::Undo()
937{
938 // TODO
223d09f6 939 wxFAIL_MSG( wxT("wxTextCtrl::Undo not implemented") );
ca8b28f2
JS
940}
941
942void wxTextCtrl::Redo()
943{
944 // TODO
223d09f6 945 wxFAIL_MSG( wxT("wxTextCtrl::Redo not implemented") );
ca8b28f2
JS
946}
947
948bool wxTextCtrl::CanUndo() const
949{
950 // TODO
223d09f6 951 wxFAIL_MSG( wxT("wxTextCtrl::CanUndo not implemented") );
ca8b28f2
JS
952 return FALSE;
953}
954
955bool wxTextCtrl::CanRedo() const
956{
957 // TODO
223d09f6 958 wxFAIL_MSG( wxT("wxTextCtrl::CanRedo not implemented") );
ca8b28f2
JS
959 return FALSE;
960}
961
962// If the return values from and to are the same, there is no
963// selection.
2d4cc5b6 964void wxTextCtrl::GetSelection(long* fromOut, long* toOut) const
ca8b28f2 965{
223d09f6 966 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
bb69661b 967
2d4cc5b6
VZ
968 long from, to;
969 if ( !(GTK_EDITABLE(m_text)->has_selection) )
05060eeb 970 {
2d4cc5b6
VZ
971 from =
972 to = GetInsertionPoint();
973 }
974 else // got selection
975 {
976 from = (long) GTK_EDITABLE(m_text)->selection_start_pos;
977 to = (long) GTK_EDITABLE(m_text)->selection_end_pos;
978
979 if ( from > to )
980 {
981 // exchange them to be compatible with wxMSW
982 long tmp = from;
983 from = to;
984 to = tmp;
985 }
05060eeb 986 }
bb69661b 987
2d4cc5b6
VZ
988 if ( fromOut )
989 *fromOut = from;
990 if ( toOut )
991 *toOut = to;
ca8b28f2
JS
992}
993
994bool wxTextCtrl::IsEditable() const
995{
223d09f6 996 wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
05060eeb
RR
997
998 return GTK_EDITABLE(m_text)->editable;
ca8b28f2
JS
999}
1000
0efe5ba7
VZ
1001bool wxTextCtrl::IsModified() const
1002{
1003 return m_modified;
1004}
1005
03f38c58 1006void wxTextCtrl::Clear()
c801d85f 1007{
223d09f6 1008 SetValue( wxT("") );
6de97a3b 1009}
c801d85f 1010
903f689b 1011void wxTextCtrl::OnChar( wxKeyEvent &key_event )
c801d85f 1012{
223d09f6 1013 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
805dd538 1014
2830bf19
RR
1015 if ((key_event.KeyCode() == WXK_RETURN) && (m_windowStyle & wxPROCESS_ENTER))
1016 {
1017 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1018 event.SetEventObject(this);
f6bcfd97 1019 event.SetString(GetValue());
2830bf19
RR
1020 if (GetEventHandler()->ProcessEvent(event)) return;
1021 }
903f689b 1022
da048e3d
RR
1023 if ((key_event.KeyCode() == WXK_RETURN) && !(m_windowStyle & wxTE_MULTILINE))
1024 {
1025 wxWindow *top_frame = m_parent;
8487f887 1026 while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
da048e3d 1027 top_frame = top_frame->GetParent();
13111b2a
VZ
1028 GtkWindow *window = GTK_WINDOW(top_frame->m_widget);
1029
1030 if (window->default_widget)
da048e3d
RR
1031 {
1032 gtk_widget_activate (window->default_widget);
13111b2a
VZ
1033 return;
1034 }
da048e3d
RR
1035 }
1036
2830bf19 1037 key_event.Skip();
6de97a3b 1038}
c801d85f 1039
03f38c58 1040GtkWidget* wxTextCtrl::GetConnectWidget()
e3e65dac 1041{
ae0bdb01 1042 return GTK_WIDGET(m_text);
6de97a3b 1043}
e3e65dac 1044
903f689b
RR
1045bool wxTextCtrl::IsOwnGtkWindow( GdkWindow *window )
1046{
ae0bdb01
RR
1047 if (m_windowStyle & wxTE_MULTILINE)
1048 return (window == GTK_TEXT(m_text)->text_area);
1049 else
1050 return (window == GTK_ENTRY(m_text)->text_area);
903f689b 1051}
e3e65dac 1052
bb69661b
VZ
1053// the font will change for subsequent text insertiongs
1054bool wxTextCtrl::SetFont( const wxFont &font )
868a2826 1055{
223d09f6 1056 wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
8bbe427f 1057
bb69661b
VZ
1058 if ( !wxWindowBase::SetFont(font) )
1059 {
1060 // font didn't change, nothing to do
1061 return FALSE;
1062 }
1063
1064 if ( m_windowStyle & wxTE_MULTILINE )
1065 {
01041145 1066 m_updateFont = TRUE;
bb69661b 1067
1ff4714d
VZ
1068 m_defaultStyle.SetFont(font);
1069
01041145 1070 ChangeFontGlobally();
bb69661b
VZ
1071 }
1072
1073 return TRUE;
58614078
RR
1074}
1075
01041145
VZ
1076void wxTextCtrl::ChangeFontGlobally()
1077{
1078 // this method is very inefficient and hence should be called as rarely as
1079 // possible!
1080 wxASSERT_MSG( (m_windowStyle & wxTE_MULTILINE) && m_updateFont,
1081 _T("shouldn't be called for single line controls") );
1082
1083 wxString value = GetValue();
1084 if ( !value.IsEmpty() )
1085 {
572aeb77
VZ
1086 m_updateFont = FALSE;
1087
01041145
VZ
1088 Clear();
1089 AppendText(value);
01041145
VZ
1090 }
1091}
1092
1093void wxTextCtrl::UpdateFontIfNeeded()
1094{
1095 if ( m_updateFont )
1096 ChangeFontGlobally();
1097}
1098
17665a2b
VZ
1099bool wxTextCtrl::SetForegroundColour(const wxColour& colour)
1100{
1101 if ( !wxControl::SetForegroundColour(colour) )
1102 return FALSE;
1103
1104 // update default fg colour too
1105 m_defaultStyle.SetTextColour(colour);
1106
1107 return TRUE;
1108}
1109
f03fc89f 1110bool wxTextCtrl::SetBackgroundColour( const wxColour &colour )
68dda785 1111{
223d09f6 1112 wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
a81258be 1113
1f477433
VZ
1114 if ( !wxControl::SetBackgroundColour( colour ) )
1115 return FALSE;
3358d36e 1116
f03fc89f
VZ
1117 if (!m_widget->window)
1118 return FALSE;
8bbe427f 1119
ae0bdb01 1120 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
805dd538
VZ
1121 if (sysbg.Red() == colour.Red() &&
1122 sysbg.Green() == colour.Green() &&
ae0bdb01
RR
1123 sysbg.Blue() == colour.Blue())
1124 {
f03fc89f 1125 return FALSE; // FIXME or TRUE?
805dd538
VZ
1126 }
1127
f03fc89f
VZ
1128 if (!m_backgroundColour.Ok())
1129 return FALSE;
8bbe427f 1130
ae0bdb01
RR
1131 if (m_windowStyle & wxTE_MULTILINE)
1132 {
1133 GdkWindow *window = GTK_TEXT(m_text)->text_area;
f03fc89f
VZ
1134 if (!window)
1135 return FALSE;
ae0bdb01
RR
1136 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
1137 gdk_window_set_background( window, m_backgroundColour.GetColor() );
1138 gdk_window_clear( window );
1139 }
f03fc89f 1140
17665a2b
VZ
1141 // change active background color too
1142 m_defaultStyle.SetBackgroundColour( colour );
1143
f03fc89f 1144 return TRUE;
58614078
RR
1145}
1146
17665a2b
VZ
1147bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr &style )
1148{
1149 /* VERY dirty way to do that - removes the required text and re-adds it
1150 with styling (FIXME) */
1151 if ( m_windowStyle & wxTE_MULTILINE )
1152 {
1153 if ( style.IsDefault() )
1154 {
1155 // nothing to do
1156 return TRUE;
1157 }
1158
1159 gint l = gtk_text_get_length( GTK_TEXT(m_text) );
1160
1161 wxCHECK_MSG( start >= 0 && end <= l, FALSE,
1162 _T("invalid range in wxTextCtrl::SetStyle") );
1163
1164 gint old_pos = gtk_editable_get_position( GTK_EDITABLE(m_text) );
1165 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), start, end );
1166 wxString tmp(text,*wxConvCurrent);
1167 g_free( text );
1168
1169 gtk_editable_delete_text( GTK_EDITABLE(m_text), start, end );
1170 gtk_editable_set_position( GTK_EDITABLE(m_text), start );
1171
1172#if wxUSE_UNICODE
1173 wxWX2MBbuf buf = tmp.mbc_str();
1174 const char *txt = buf;
1175 size_t txtlen = strlen(buf);
1176#else
1177 const char *txt = tmp;
1178 size_t txtlen = tmp.length();
1179#endif
1180
1181 GdkFont *font = style.HasFont()
1182 ? style.GetFont().GetInternalFont()
1183 : NULL;
1184
1185 GdkColor *colFg = style.HasTextColour()
1186 ? style.GetTextColour().GetColor()
1187 : NULL;
1188
1189 GdkColor *colBg = style.HasBackgroundColour()
1190 ? style.GetBackgroundColour().GetColor()
1191 : NULL;
1192
1193 gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, txtlen );
1194
1195 /* does not seem to help under GTK+ 1.2 !!!
1196 gtk_editable_set_position( GTK_EDITABLE(m_text), old_pos ); */
1197 SetInsertionPoint( old_pos );
1198 return TRUE;
1199 }
1200 else // singe line
1201 {
1202 // cannot do this for GTK+'s Entry widget
1203 return FALSE;
1204 }
1205}
1206
58614078
RR
1207void wxTextCtrl::ApplyWidgetStyle()
1208{
ae0bdb01
RR
1209 if (m_windowStyle & wxTE_MULTILINE)
1210 {
2830bf19 1211 // how ?
805dd538 1212 }
ae0bdb01
RR
1213 else
1214 {
1215 SetWidgetStyle();
1216 gtk_widget_set_style( m_text, m_widgetStyle );
1217 }
68dda785 1218}
f96aa4d9 1219
e702ff0f
JS
1220void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1221{
1222 Cut();
1223}
1224
1225void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1226{
1227 Copy();
1228}
1229
1230void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1231{
1232 Paste();
1233}
1234
1235void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1236{
1237 Undo();
1238}
1239
1240void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1241{
1242 Redo();
1243}
1244
1245void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1246{
1247 event.Enable( CanCut() );
1248}
1249
1250void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1251{
1252 event.Enable( CanCopy() );
1253}
1254
1255void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1256{
1257 event.Enable( CanPaste() );
1258}
1259
1260void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1261{
1262 event.Enable( CanUndo() );
1263}
1264
1265void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1266{
1267 event.Enable( CanRedo() );
1268}
65045edd
RR
1269
1270void wxTextCtrl::OnInternalIdle()
1271{
1272 wxCursor cursor = m_cursor;
1273 if (g_globalCursor.Ok()) cursor = g_globalCursor;
1274
307f16e8 1275 if (cursor.Ok())
65045edd 1276 {
65045edd 1277 GdkWindow *window = (GdkWindow*) NULL;
13111b2a 1278 if (HasFlag(wxTE_MULTILINE))
65045edd
RR
1279 window = GTK_TEXT(m_text)->text_area;
1280 else
1281 window = GTK_ENTRY(m_text)->text_area;
13111b2a 1282
65045edd
RR
1283 if (window)
1284 gdk_window_set_cursor( window, cursor.GetCursor() );
1285
1286 if (!g_globalCursor.Ok())
1287 cursor = *wxSTANDARD_CURSOR;
1288
1289 window = m_widget->window;
247e5b16 1290 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
65045edd
RR
1291 gdk_window_set_cursor( window, cursor.GetCursor() );
1292 }
26bf1ce0
VZ
1293
1294 UpdateWindowUI();
65045edd 1295}
f68586e5
VZ
1296
1297wxSize wxTextCtrl::DoGetBestSize() const
1298{
1299 // FIXME should be different for multi-line controls...
0279e844
RR
1300 wxSize ret( wxControl::DoGetBestSize() );
1301 return wxSize(80, ret.y);
f68586e5 1302}
0cc7251e 1303
9cd6d737
VZ
1304// ----------------------------------------------------------------------------
1305// freeze/thaw
1306// ----------------------------------------------------------------------------
1307
0cc7251e
VZ
1308void wxTextCtrl::Freeze()
1309{
1310 if ( HasFlag(wxTE_MULTILINE) )
1311 {
1312 gtk_text_freeze(GTK_TEXT(m_text));
1313 }
1314}
1315
1316void wxTextCtrl::Thaw()
1317{
1318 if ( HasFlag(wxTE_MULTILINE) )
1319 {
817ec43a
VZ
1320 GTK_TEXT(m_text)->vadj->value = 0.0;
1321
0cc7251e
VZ
1322 gtk_text_thaw(GTK_TEXT(m_text));
1323 }
1324}
9cd6d737
VZ
1325
1326// ----------------------------------------------------------------------------
1327// scrolling
1328// ----------------------------------------------------------------------------
1329
1330GtkAdjustment *wxTextCtrl::GetVAdj() const
1331{
1332 return HasFlag(wxTE_MULTILINE) ? GTK_TEXT(m_text)->vadj : NULL;
1333}
1334
1335bool wxTextCtrl::DoScroll(GtkAdjustment *adj, int diff)
1336{
1337 float value = adj->value + diff;
1338
1339 if ( value < 0 )
1340 value = 0;
1341
1342 float upper = adj->upper - adj->page_size;
1343 if ( value > upper )
1344 value = upper;
1345
1346 // did we noticeably change the scroll position?
1347 if ( fabs(adj->value - value) < 0.2 )
1348 {
1349 // well, this is what Robert does in wxScrollBar, so it must be good...
1350 return FALSE;
1351 }
1352
1353 adj->value = value;
1354
1355 gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
1356
1357 return TRUE;
1358}
1359
1360bool wxTextCtrl::ScrollLines(int lines)
1361{
1362 GtkAdjustment *adj = GetVAdj();
1363 if ( !adj )
1364 return FALSE;
1365
1366 // this is hardcoded to 10 in GTK+ 1.2 (great idea)
1367 static const int KEY_SCROLL_PIXELS = 10;
1368
1369 return DoScroll(adj, lines*KEY_SCROLL_PIXELS);
1370}
1371
1372bool wxTextCtrl::ScrollPages(int pages)
1373{
1374 GtkAdjustment *adj = GetVAdj();
1375 if ( !adj )
1376 return FALSE;
1377
817ec43a 1378 return DoScroll(adj, (int)ceil(pages*adj->page_increment));
9cd6d737
VZ
1379}
1380