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