]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/textctrl.cpp
Fixed the drawing of the HRules so they don't try to iterate over all
[wxWidgets.git] / src / gtk / 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
debe6624 829void wxTextCtrl::SetSelection( long from, long to )
c801d85f 830{
223d09f6 831 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 832
a1f79c1e
VZ
833 if ( (m_windowStyle & wxTE_MULTILINE) &&
834 !GTK_TEXT(m_text)->line_start_cache )
835 {
836 // tell the programmer that it didn't work
837 wxLogDebug(_T("Can't call SetSelection() before realizing the control"));
838 return;
839 }
840
2830bf19 841 gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
6de97a3b 842}
c801d85f 843
910f1f8c 844void wxTextCtrl::ShowPosition( long WXUNUSED(pos) )
c801d85f 845{
910f1f8c 846// SetInsertionPoint( pos );
6de97a3b 847}
c801d85f 848
03f38c58 849long wxTextCtrl::GetInsertionPoint() const
c801d85f 850{
223d09f6 851 wxCHECK_MSG( m_text != NULL, 0, wxT("invalid text ctrl") );
8bbe427f 852
2830bf19 853 return (long) GTK_EDITABLE(m_text)->current_pos;
6de97a3b 854}
c801d85f 855
03f38c58 856long wxTextCtrl::GetLastPosition() const
c801d85f 857{
223d09f6 858 wxCHECK_MSG( m_text != NULL, 0, wxT("invalid text ctrl") );
8bbe427f 859
2830bf19
RR
860 int pos = 0;
861 if (m_windowStyle & wxTE_MULTILINE)
862 pos = gtk_text_get_length( GTK_TEXT(m_text) );
863 else
864 pos = GTK_ENTRY(m_text)->text_length;
805dd538 865
ac0d36b5 866 return (long)pos;
6de97a3b 867}
c801d85f 868
debe6624 869void wxTextCtrl::Remove( long from, long to )
c801d85f 870{
223d09f6 871 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 872
2830bf19 873 gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
6de97a3b 874}
c801d85f 875
debe6624 876void wxTextCtrl::Replace( long from, long to, const wxString &value )
c801d85f 877{
223d09f6 878 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 879
2830bf19 880 gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
bb69661b 881
2df7be7f
RR
882 if (!value.IsEmpty())
883 {
884 gint pos = (gint)from;
05939a81 885#if wxUSE_UNICODE
2df7be7f
RR
886 wxWX2MBbuf buf = value.mbc_str();
887 gtk_editable_insert_text( GTK_EDITABLE(m_text), buf, strlen(buf), &pos );
05939a81 888#else
2df7be7f 889 gtk_editable_insert_text( GTK_EDITABLE(m_text), value, value.Length(), &pos );
05939a81 890#endif
2df7be7f 891 }
6de97a3b 892}
c801d85f 893
03f38c58 894void wxTextCtrl::Cut()
c801d85f 895{
223d09f6 896 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 897
d345e841 898#if (GTK_MINOR_VERSION > 0)
2830bf19 899 gtk_editable_cut_clipboard( GTK_EDITABLE(m_text) );
75ed1d15 900#else
2830bf19 901 gtk_editable_cut_clipboard( GTK_EDITABLE(m_text), 0 );
75ed1d15 902#endif
6de97a3b 903}
c801d85f 904
03f38c58 905void wxTextCtrl::Copy()
c801d85f 906{
223d09f6 907 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 908
d345e841 909#if (GTK_MINOR_VERSION > 0)
2830bf19 910 gtk_editable_copy_clipboard( GTK_EDITABLE(m_text) );
75ed1d15 911#else
2830bf19 912 gtk_editable_copy_clipboard( GTK_EDITABLE(m_text), 0 );
75ed1d15 913#endif
6de97a3b 914}
c801d85f 915
03f38c58 916void wxTextCtrl::Paste()
c801d85f 917{
223d09f6 918 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
8bbe427f 919
d345e841 920#if (GTK_MINOR_VERSION > 0)
2830bf19 921 gtk_editable_paste_clipboard( GTK_EDITABLE(m_text) );
75ed1d15 922#else
2830bf19 923 gtk_editable_paste_clipboard( GTK_EDITABLE(m_text), 0 );
75ed1d15 924#endif
6de97a3b 925}
c801d85f 926
ca8b28f2
JS
927// Undo/redo
928void wxTextCtrl::Undo()
929{
930 // TODO
223d09f6 931 wxFAIL_MSG( wxT("wxTextCtrl::Undo not implemented") );
ca8b28f2
JS
932}
933
934void wxTextCtrl::Redo()
935{
936 // TODO
223d09f6 937 wxFAIL_MSG( wxT("wxTextCtrl::Redo not implemented") );
ca8b28f2
JS
938}
939
940bool wxTextCtrl::CanUndo() const
941{
942 // TODO
223d09f6 943 wxFAIL_MSG( wxT("wxTextCtrl::CanUndo not implemented") );
ca8b28f2
JS
944 return FALSE;
945}
946
947bool wxTextCtrl::CanRedo() const
948{
949 // TODO
223d09f6 950 wxFAIL_MSG( wxT("wxTextCtrl::CanRedo not implemented") );
ca8b28f2
JS
951 return FALSE;
952}
953
954// If the return values from and to are the same, there is no
955// selection.
2d4cc5b6 956void wxTextCtrl::GetSelection(long* fromOut, long* toOut) const
ca8b28f2 957{
223d09f6 958 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
bb69661b 959
2d4cc5b6
VZ
960 long from, to;
961 if ( !(GTK_EDITABLE(m_text)->has_selection) )
05060eeb 962 {
2d4cc5b6
VZ
963 from =
964 to = GetInsertionPoint();
965 }
966 else // got selection
967 {
968 from = (long) GTK_EDITABLE(m_text)->selection_start_pos;
969 to = (long) GTK_EDITABLE(m_text)->selection_end_pos;
970
971 if ( from > to )
972 {
973 // exchange them to be compatible with wxMSW
974 long tmp = from;
975 from = to;
976 to = tmp;
977 }
05060eeb 978 }
bb69661b 979
2d4cc5b6
VZ
980 if ( fromOut )
981 *fromOut = from;
982 if ( toOut )
983 *toOut = to;
ca8b28f2
JS
984}
985
986bool wxTextCtrl::IsEditable() const
987{
223d09f6 988 wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
05060eeb
RR
989
990 return GTK_EDITABLE(m_text)->editable;
ca8b28f2
JS
991}
992
0efe5ba7
VZ
993bool wxTextCtrl::IsModified() const
994{
995 return m_modified;
996}
997
03f38c58 998void wxTextCtrl::Clear()
c801d85f 999{
223d09f6 1000 SetValue( wxT("") );
6de97a3b 1001}
c801d85f 1002
903f689b 1003void wxTextCtrl::OnChar( wxKeyEvent &key_event )
c801d85f 1004{
223d09f6 1005 wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
805dd538 1006
2830bf19
RR
1007 if ((key_event.KeyCode() == WXK_RETURN) && (m_windowStyle & wxPROCESS_ENTER))
1008 {
1009 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1010 event.SetEventObject(this);
f6bcfd97 1011 event.SetString(GetValue());
2830bf19
RR
1012 if (GetEventHandler()->ProcessEvent(event)) return;
1013 }
903f689b 1014
da048e3d
RR
1015 if ((key_event.KeyCode() == WXK_RETURN) && !(m_windowStyle & wxTE_MULTILINE))
1016 {
1017 wxWindow *top_frame = m_parent;
8487f887 1018 while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
da048e3d 1019 top_frame = top_frame->GetParent();
13111b2a
VZ
1020 GtkWindow *window = GTK_WINDOW(top_frame->m_widget);
1021
1022 if (window->default_widget)
da048e3d
RR
1023 {
1024 gtk_widget_activate (window->default_widget);
13111b2a
VZ
1025 return;
1026 }
da048e3d
RR
1027 }
1028
2830bf19 1029 key_event.Skip();
6de97a3b 1030}
c801d85f 1031
03f38c58 1032GtkWidget* wxTextCtrl::GetConnectWidget()
e3e65dac 1033{
ae0bdb01 1034 return GTK_WIDGET(m_text);
6de97a3b 1035}
e3e65dac 1036
903f689b
RR
1037bool wxTextCtrl::IsOwnGtkWindow( GdkWindow *window )
1038{
ae0bdb01
RR
1039 if (m_windowStyle & wxTE_MULTILINE)
1040 return (window == GTK_TEXT(m_text)->text_area);
1041 else
1042 return (window == GTK_ENTRY(m_text)->text_area);
903f689b 1043}
e3e65dac 1044
bb69661b
VZ
1045// the font will change for subsequent text insertiongs
1046bool wxTextCtrl::SetFont( const wxFont &font )
868a2826 1047{
223d09f6 1048 wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
8bbe427f 1049
bb69661b
VZ
1050 if ( !wxWindowBase::SetFont(font) )
1051 {
1052 // font didn't change, nothing to do
1053 return FALSE;
1054 }
1055
1056 if ( m_windowStyle & wxTE_MULTILINE )
1057 {
01041145 1058 m_updateFont = TRUE;
bb69661b 1059
1ff4714d
VZ
1060 m_defaultStyle.SetFont(font);
1061
01041145 1062 ChangeFontGlobally();
bb69661b
VZ
1063 }
1064
1065 return TRUE;
58614078
RR
1066}
1067
01041145
VZ
1068void wxTextCtrl::ChangeFontGlobally()
1069{
1070 // this method is very inefficient and hence should be called as rarely as
1071 // possible!
1072 wxASSERT_MSG( (m_windowStyle & wxTE_MULTILINE) && m_updateFont,
1073 _T("shouldn't be called for single line controls") );
1074
1075 wxString value = GetValue();
1076 if ( !value.IsEmpty() )
1077 {
572aeb77
VZ
1078 m_updateFont = FALSE;
1079
01041145
VZ
1080 Clear();
1081 AppendText(value);
01041145
VZ
1082 }
1083}
1084
1085void wxTextCtrl::UpdateFontIfNeeded()
1086{
1087 if ( m_updateFont )
1088 ChangeFontGlobally();
1089}
1090
17665a2b
VZ
1091bool wxTextCtrl::SetForegroundColour(const wxColour& colour)
1092{
1093 if ( !wxControl::SetForegroundColour(colour) )
1094 return FALSE;
1095
1096 // update default fg colour too
1097 m_defaultStyle.SetTextColour(colour);
1098
1099 return TRUE;
1100}
1101
f03fc89f 1102bool wxTextCtrl::SetBackgroundColour( const wxColour &colour )
68dda785 1103{
223d09f6 1104 wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
a81258be 1105
1f477433
VZ
1106 if ( !wxControl::SetBackgroundColour( colour ) )
1107 return FALSE;
3358d36e 1108
f03fc89f
VZ
1109 if (!m_widget->window)
1110 return FALSE;
8bbe427f 1111
ae0bdb01 1112 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
805dd538
VZ
1113 if (sysbg.Red() == colour.Red() &&
1114 sysbg.Green() == colour.Green() &&
ae0bdb01
RR
1115 sysbg.Blue() == colour.Blue())
1116 {
f03fc89f 1117 return FALSE; // FIXME or TRUE?
805dd538
VZ
1118 }
1119
f03fc89f
VZ
1120 if (!m_backgroundColour.Ok())
1121 return FALSE;
8bbe427f 1122
ae0bdb01
RR
1123 if (m_windowStyle & wxTE_MULTILINE)
1124 {
1125 GdkWindow *window = GTK_TEXT(m_text)->text_area;
f03fc89f
VZ
1126 if (!window)
1127 return FALSE;
ae0bdb01
RR
1128 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
1129 gdk_window_set_background( window, m_backgroundColour.GetColor() );
1130 gdk_window_clear( window );
1131 }
f03fc89f 1132
17665a2b
VZ
1133 // change active background color too
1134 m_defaultStyle.SetBackgroundColour( colour );
1135
f03fc89f 1136 return TRUE;
58614078
RR
1137}
1138
17665a2b
VZ
1139bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr &style )
1140{
1141 /* VERY dirty way to do that - removes the required text and re-adds it
1142 with styling (FIXME) */
1143 if ( m_windowStyle & wxTE_MULTILINE )
1144 {
1145 if ( style.IsDefault() )
1146 {
1147 // nothing to do
1148 return TRUE;
1149 }
1150
1151 gint l = gtk_text_get_length( GTK_TEXT(m_text) );
1152
1153 wxCHECK_MSG( start >= 0 && end <= l, FALSE,
1154 _T("invalid range in wxTextCtrl::SetStyle") );
1155
1156 gint old_pos = gtk_editable_get_position( GTK_EDITABLE(m_text) );
1157 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), start, end );
1158 wxString tmp(text,*wxConvCurrent);
1159 g_free( text );
1160
1161 gtk_editable_delete_text( GTK_EDITABLE(m_text), start, end );
1162 gtk_editable_set_position( GTK_EDITABLE(m_text), start );
1163
1164#if wxUSE_UNICODE
1165 wxWX2MBbuf buf = tmp.mbc_str();
1166 const char *txt = buf;
1167 size_t txtlen = strlen(buf);
1168#else
1169 const char *txt = tmp;
1170 size_t txtlen = tmp.length();
1171#endif
1172
1173 GdkFont *font = style.HasFont()
1174 ? style.GetFont().GetInternalFont()
1175 : NULL;
1176
1177 GdkColor *colFg = style.HasTextColour()
1178 ? style.GetTextColour().GetColor()
1179 : NULL;
1180
1181 GdkColor *colBg = style.HasBackgroundColour()
1182 ? style.GetBackgroundColour().GetColor()
1183 : NULL;
1184
1185 gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, txtlen );
1186
1187 /* does not seem to help under GTK+ 1.2 !!!
1188 gtk_editable_set_position( GTK_EDITABLE(m_text), old_pos ); */
1189 SetInsertionPoint( old_pos );
1190 return TRUE;
1191 }
1192 else // singe line
1193 {
1194 // cannot do this for GTK+'s Entry widget
1195 return FALSE;
1196 }
1197}
1198
58614078
RR
1199void wxTextCtrl::ApplyWidgetStyle()
1200{
ae0bdb01
RR
1201 if (m_windowStyle & wxTE_MULTILINE)
1202 {
2830bf19 1203 // how ?
805dd538 1204 }
ae0bdb01
RR
1205 else
1206 {
1207 SetWidgetStyle();
1208 gtk_widget_set_style( m_text, m_widgetStyle );
1209 }
68dda785 1210}
f96aa4d9 1211
e702ff0f
JS
1212void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1213{
1214 Cut();
1215}
1216
1217void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1218{
1219 Copy();
1220}
1221
1222void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1223{
1224 Paste();
1225}
1226
1227void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1228{
1229 Undo();
1230}
1231
1232void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1233{
1234 Redo();
1235}
1236
1237void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1238{
1239 event.Enable( CanCut() );
1240}
1241
1242void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1243{
1244 event.Enable( CanCopy() );
1245}
1246
1247void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1248{
1249 event.Enable( CanPaste() );
1250}
1251
1252void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1253{
1254 event.Enable( CanUndo() );
1255}
1256
1257void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1258{
1259 event.Enable( CanRedo() );
1260}
65045edd
RR
1261
1262void wxTextCtrl::OnInternalIdle()
1263{
1264 wxCursor cursor = m_cursor;
1265 if (g_globalCursor.Ok()) cursor = g_globalCursor;
1266
307f16e8 1267 if (cursor.Ok())
65045edd 1268 {
65045edd 1269 GdkWindow *window = (GdkWindow*) NULL;
13111b2a 1270 if (HasFlag(wxTE_MULTILINE))
65045edd
RR
1271 window = GTK_TEXT(m_text)->text_area;
1272 else
1273 window = GTK_ENTRY(m_text)->text_area;
13111b2a 1274
65045edd
RR
1275 if (window)
1276 gdk_window_set_cursor( window, cursor.GetCursor() );
1277
1278 if (!g_globalCursor.Ok())
1279 cursor = *wxSTANDARD_CURSOR;
1280
1281 window = m_widget->window;
247e5b16 1282 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
65045edd
RR
1283 gdk_window_set_cursor( window, cursor.GetCursor() );
1284 }
26bf1ce0
VZ
1285
1286 UpdateWindowUI();
65045edd 1287}
f68586e5
VZ
1288
1289wxSize wxTextCtrl::DoGetBestSize() const
1290{
1291 // FIXME should be different for multi-line controls...
0279e844
RR
1292 wxSize ret( wxControl::DoGetBestSize() );
1293 return wxSize(80, ret.y);
f68586e5 1294}
0cc7251e 1295
9cd6d737
VZ
1296// ----------------------------------------------------------------------------
1297// freeze/thaw
1298// ----------------------------------------------------------------------------
1299
0cc7251e
VZ
1300void wxTextCtrl::Freeze()
1301{
1302 if ( HasFlag(wxTE_MULTILINE) )
1303 {
1304 gtk_text_freeze(GTK_TEXT(m_text));
1305 }
1306}
1307
1308void wxTextCtrl::Thaw()
1309{
1310 if ( HasFlag(wxTE_MULTILINE) )
1311 {
817ec43a
VZ
1312 GTK_TEXT(m_text)->vadj->value = 0.0;
1313
0cc7251e
VZ
1314 gtk_text_thaw(GTK_TEXT(m_text));
1315 }
1316}
9cd6d737
VZ
1317
1318// ----------------------------------------------------------------------------
1319// scrolling
1320// ----------------------------------------------------------------------------
1321
1322GtkAdjustment *wxTextCtrl::GetVAdj() const
1323{
1324 return HasFlag(wxTE_MULTILINE) ? GTK_TEXT(m_text)->vadj : NULL;
1325}
1326
1327bool wxTextCtrl::DoScroll(GtkAdjustment *adj, int diff)
1328{
1329 float value = adj->value + diff;
1330
1331 if ( value < 0 )
1332 value = 0;
1333
1334 float upper = adj->upper - adj->page_size;
1335 if ( value > upper )
1336 value = upper;
1337
1338 // did we noticeably change the scroll position?
1339 if ( fabs(adj->value - value) < 0.2 )
1340 {
1341 // well, this is what Robert does in wxScrollBar, so it must be good...
1342 return FALSE;
1343 }
1344
1345 adj->value = value;
1346
1347 gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
1348
1349 return TRUE;
1350}
1351
1352bool wxTextCtrl::ScrollLines(int lines)
1353{
1354 GtkAdjustment *adj = GetVAdj();
1355 if ( !adj )
1356 return FALSE;
1357
1358 // this is hardcoded to 10 in GTK+ 1.2 (great idea)
1359 static const int KEY_SCROLL_PIXELS = 10;
1360
1361 return DoScroll(adj, lines*KEY_SCROLL_PIXELS);
1362}
1363
1364bool wxTextCtrl::ScrollPages(int pages)
1365{
1366 GtkAdjustment *adj = GetVAdj();
1367 if ( !adj )
1368 return FALSE;
1369
817ec43a 1370 return DoScroll(adj, (int)ceil(pages*adj->page_increment));
9cd6d737
VZ
1371}
1372