]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/textctrl.cpp
More colour finetuning
[wxWidgets.git] / src / gtk / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "textctrl.h"
12 #endif
13
14 #include "wx/textctrl.h"
15 #include "wx/utils.h"
16 #include "wx/intl.h"
17 #include "wx/settings.h"
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <ctype.h>
22
23 //-----------------------------------------------------------------------------
24 // "changed"
25 //-----------------------------------------------------------------------------
26
27 static void gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
28 {
29 win->SetModified();
30
31 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->m_windowId );
32 wxString val( win->GetValue() );
33 if (!val.IsNull()) event.m_commandString = WXSTRINGCAST val;
34 event.SetEventObject( win );
35 win->GetEventHandler()->ProcessEvent( event );
36 }
37
38 //-----------------------------------------------------------------------------
39 // wxTextCtrl
40 //-----------------------------------------------------------------------------
41
42 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl,wxControl)
43
44 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
45 EVT_CHAR(wxTextCtrl::OnChar)
46 END_EVENT_TABLE()
47
48 wxTextCtrl::wxTextCtrl() : streambuf()
49 {
50 if (allocate()) setp(base(),ebuf());
51
52 m_modified = FALSE;
53 }
54
55 wxTextCtrl::wxTextCtrl( wxWindow *parent, wxWindowID id, const wxString &value,
56 const wxPoint &pos, const wxSize &size,
57 int style, const wxValidator& validator, const wxString &name ) : streambuf()
58 {
59 if (allocate()) setp(base(),ebuf());
60
61 m_modified = FALSE;
62 Create( parent, id, value, pos, size, style, validator, name );
63 }
64
65 bool wxTextCtrl::Create( wxWindow *parent, wxWindowID id, const wxString &value,
66 const wxPoint &pos, const wxSize &size,
67 int style, const wxValidator& validator, const wxString &name )
68 {
69 m_needParent = TRUE;
70
71 PreCreation( parent, id, pos, size, style, name );
72
73 SetValidator( validator );
74
75 bool multi_line = (style & wxTE_MULTILINE) != 0;
76 if ( multi_line )
77 {
78 // a multi-line edit control: create a vertical scrollbar by default and
79 // horizontal if requested
80 bool bHasHScrollbar = (style & wxHSCROLL) != 0;
81
82 // create our control...
83 m_text = gtk_text_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
84
85 // ... and put into the upper left hand corner of the table
86 m_widget = gtk_table_new(bHasHScrollbar ? 2 : 1, 2, FALSE);
87 gtk_table_attach( GTK_TABLE(m_widget), m_text, 0, 1, 0, 1,
88 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK),
89 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND | GTK_SHRINK),
90 0, 0);
91
92 // put the horizontal scrollbar in the lower left hand corner
93 if (bHasHScrollbar)
94 {
95 GtkWidget *hscrollbar = gtk_hscrollbar_new(GTK_TEXT(m_text)->hadj);
96 gtk_table_attach(GTK_TABLE(m_widget), hscrollbar, 0, 1, 1, 2,
97 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
98 GTK_FILL,
99 0, 0);
100 gtk_widget_show(hscrollbar);
101 }
102
103 // finally, put the vertical scrollbar in the upper right corner
104 GtkWidget *vscrollbar = gtk_vscrollbar_new(GTK_TEXT(m_text)->vadj);
105 gtk_table_attach(GTK_TABLE(m_widget), vscrollbar, 1, 2, 0, 1,
106 GTK_FILL,
107 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK),
108 0, 0);
109 gtk_widget_show( vscrollbar );
110 }
111 else
112 {
113 // a single-line text control: no need for scrollbars
114 m_widget =
115 m_text = gtk_entry_new();
116 }
117
118 wxSize newSize = size;
119 if (newSize.x == -1) newSize.x = 80;
120 if (newSize.y == -1) newSize.y = 26;
121 SetSize( newSize.x, newSize.y );
122
123 m_parent->AddChild( this );
124
125 (m_parent->m_insertCallback)( m_parent, this );
126
127 PostCreation();
128
129 if (multi_line)
130 {
131 gtk_widget_realize(m_text);
132 gtk_widget_show(m_text);
133 }
134
135 // we want to be notified about text changes
136 gtk_signal_connect(GTK_OBJECT(m_text), "changed",
137 GTK_SIGNAL_FUNC(gtk_text_changed_callback),
138 (gpointer)this);
139
140 if (!value.IsNull())
141 {
142 gint tmp = 0;
143 gtk_editable_insert_text( GTK_EDITABLE(m_text), value, value.Length(), &tmp );
144 SetInsertionPointEnd();
145 }
146
147 if (style & wxTE_PASSWORD)
148 {
149 if (!multi_line)
150 gtk_entry_set_visibility( GTK_ENTRY(m_text), FALSE );
151 }
152
153 if (style & wxTE_READONLY)
154 {
155 if (!multi_line)
156 gtk_entry_set_editable( GTK_ENTRY(m_text), FALSE );
157 }
158 else
159 {
160 if (multi_line)
161 gtk_text_set_editable( GTK_TEXT(m_text), 1 );
162 }
163
164 Show( TRUE );
165
166 SetBackgroundColour( parent->GetBackgroundColour() );
167 SetForegroundColour( parent->GetForegroundColour() );
168
169 return TRUE;
170 }
171
172 wxString wxTextCtrl::GetValue() const
173 {
174 wxCHECK_MSG( m_text != NULL, "", "invalid text ctrl" );
175
176 wxString tmp;
177 if (m_windowStyle & wxTE_MULTILINE)
178 {
179 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
180 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
181 tmp = text;
182 g_free( text );
183 }
184 else
185 {
186 tmp = gtk_entry_get_text( GTK_ENTRY(m_text) );
187 }
188 return tmp;
189 }
190
191 void wxTextCtrl::SetValue( const wxString &value )
192 {
193 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
194
195 wxString tmp = "";
196 if (!value.IsNull()) tmp = value;
197 if (m_windowStyle & wxTE_MULTILINE)
198 {
199 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
200 gtk_editable_delete_text( GTK_EDITABLE(m_text), 0, len );
201 len = 0;
202 gtk_editable_insert_text( GTK_EDITABLE(m_text), tmp, tmp.Length(), &len );
203 }
204 else
205 {
206 gtk_entry_set_text( GTK_ENTRY(m_text), tmp );
207 }
208 }
209
210 void wxTextCtrl::WriteText( const wxString &text )
211 {
212 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
213
214 if (text.IsNull()) return;
215
216 if (m_windowStyle & wxTE_MULTILINE)
217 {
218 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
219 gtk_editable_insert_text( GTK_EDITABLE(m_text), text, text.Length(), &len );
220 }
221 else
222 {
223 gtk_entry_append_text( GTK_ENTRY(m_text), text );
224 }
225 }
226
227 bool wxTextCtrl::LoadFile( const wxString &file )
228 {
229 wxCHECK_MSG( m_text != NULL, FALSE, "invalid text ctrl" );
230
231 if (!wxFileExists(file)) return FALSE;
232
233 Clear();
234
235 FILE *fp = NULL;
236 struct stat statb;
237
238 if ((stat ((char*) (const char*) file, &statb) == -1) || (statb.st_mode & S_IFMT) != S_IFREG ||
239 !(fp = fopen ((char*) (const char*) file, "r")))
240 {
241 return FALSE;
242 }
243 else
244 {
245 gint len = statb.st_size;
246 char *text;
247 if (!(text = (char*)malloc ((unsigned) (len + 1))))
248 {
249 fclose (fp);
250 return FALSE;
251 }
252 if (fread (text, sizeof (char), len, fp) != (size_t) len)
253 {
254 }
255 fclose (fp);
256
257 text[len] = 0;
258
259 if (m_windowStyle & wxTE_MULTILINE)
260 {
261 gtk_editable_insert_text( GTK_EDITABLE(m_text), text, 0, &len );
262 }
263 else
264 {
265 gtk_entry_set_text( GTK_ENTRY(m_text), text );
266 }
267
268 free (text);
269 m_modified = FALSE;
270 return TRUE;
271 }
272 return FALSE;
273 }
274
275 bool wxTextCtrl::SaveFile( const wxString &file )
276 {
277 wxCHECK_MSG( m_text != NULL, FALSE, "invalid text ctrl" );
278
279 if (file == "") return FALSE;
280
281 FILE *fp;
282
283 if (!(fp = fopen ((char*) (const char*) file, "w")))
284 {
285 return FALSE;
286 }
287 else
288 {
289 char *text = NULL;
290 gint len = 0;
291
292 if (m_windowStyle & wxTE_MULTILINE)
293 {
294 len = gtk_text_get_length( GTK_TEXT(m_text) );
295 text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
296 }
297 else
298 {
299 text = gtk_entry_get_text( GTK_ENTRY(m_text) );
300 }
301
302 if (fwrite (text, sizeof (char), len, fp) != (size_t) len)
303 {
304 // Did not write whole file
305 }
306
307 // Make sure newline terminates the file
308 if (text[len - 1] != '\n')
309 fputc ('\n', fp);
310
311 fclose (fp);
312
313 if (m_windowStyle & wxTE_MULTILINE) g_free( text );
314
315 m_modified = FALSE;
316 return TRUE;
317 }
318
319 return TRUE;
320 }
321
322 wxString wxTextCtrl::GetLineText( long lineNo ) const
323 {
324 if (m_windowStyle & wxTE_MULTILINE)
325 {
326 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
327 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
328
329 if (text)
330 {
331 wxString buf("");
332 long i;
333 int currentLine = 0;
334 for (i = 0; currentLine != lineNo && text[i]; i++ )
335 if (text[i] == '\n')
336 currentLine++;
337 // Now get the text
338 int j;
339 for (j = 0; text[i] && text[i] != '\n'; i++, j++ )
340 buf += text[i];
341
342 g_free( text );
343 return buf;
344 }
345 else
346 return wxEmptyString;
347 }
348 else
349 {
350 if (lineNo == 0) return GetValue();
351 return wxEmptyString;
352 }
353 }
354
355 void wxTextCtrl::OnDropFiles( wxDropFilesEvent &WXUNUSED(event) )
356 {
357 wxFAIL_MSG( "wxTextCtrl::OnDropFiles not implemented" );
358 }
359
360 long wxTextCtrl::PositionToXY(long pos, long *x, long *y ) const
361 {
362 if (!(m_windowStyle & wxTE_MULTILINE))
363 return 0;
364 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
365 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
366 if(!text)
367 return 0;
368 if( pos >= len)
369 return pos=len-1;
370
371 *x=1; // Col 1
372 *y=1; // Line 1
373 for (int i = 0; i < pos; i++ )
374 {
375 if (text[i] == '\n')
376 {
377 (*y)++;
378 *x=1;
379 }
380 else
381 (*x)++;
382 }
383 g_free( text );
384 return 1;
385 }
386
387 long wxTextCtrl::XYToPosition(long x, long y ) const
388 {
389 if (!(m_windowStyle & wxTE_MULTILINE))
390 return 0;
391 long pos=0;
392
393 for(int i=1;i<y;i++)
394 pos +=GetLineLength(i);
395 pos +=x-1; // Pos start with 0
396 return pos;
397 }
398
399 int wxTextCtrl::GetLineLength(long lineNo) const
400 {
401 wxString str = GetLineText (lineNo);
402 return (int) str.Length();
403 }
404
405 int wxTextCtrl::GetNumberOfLines() const
406 {
407 if (m_windowStyle & wxTE_MULTILINE)
408 {
409 gint len = gtk_text_get_length( GTK_TEXT(m_text) );
410 char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
411
412 if (text)
413 {
414 int currentLine = 0;
415 for (int i = 0; i < len; i++ )
416 if (text[i] == '\n')
417 currentLine++;
418
419 g_free( text );
420 return currentLine;
421 }
422 else
423 return 0;
424 }
425 else
426 {
427 return 1;
428 }
429 }
430
431 void wxTextCtrl::SetInsertionPoint( long pos )
432 {
433 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
434
435 int tmp = (int) pos;
436 if (m_windowStyle & wxTE_MULTILINE)
437 gtk_text_set_point( GTK_TEXT(m_text), tmp );
438 else
439 gtk_entry_set_position( GTK_ENTRY(m_text), tmp );
440 }
441
442 void wxTextCtrl::SetInsertionPointEnd()
443 {
444 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
445
446 int pos = 0;
447 if (m_windowStyle & wxTE_MULTILINE)
448 pos = gtk_text_get_length( GTK_TEXT(m_text) );
449 else
450 pos = GTK_ENTRY(m_text)->text_length;
451 SetInsertionPoint((pos-1)>0 ? (pos-1):0);
452 }
453
454 void wxTextCtrl::SetEditable( bool editable )
455 {
456 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
457
458 if (m_windowStyle & wxTE_MULTILINE)
459 gtk_text_set_editable( GTK_TEXT(m_text), editable );
460 else
461 gtk_entry_set_editable( GTK_ENTRY(m_text), editable );
462 }
463
464 void wxTextCtrl::SetSelection( long from, long to )
465 {
466 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
467
468 gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
469 }
470
471 void wxTextCtrl::ShowPosition( long WXUNUSED(pos) )
472 {
473 wxFAIL_MSG( "wxTextCtrl::ShowPosition not implemented" );
474 }
475
476 long wxTextCtrl::GetInsertionPoint() const
477 {
478 wxCHECK_MSG( m_text != NULL, 0, "invalid text ctrl" );
479
480 return (long) GTK_EDITABLE(m_text)->current_pos;
481 }
482
483 long wxTextCtrl::GetLastPosition() const
484 {
485 wxCHECK_MSG( m_text != NULL, 0, "invalid text ctrl" );
486
487 int pos = 0;
488 if (m_windowStyle & wxTE_MULTILINE)
489 pos = gtk_text_get_length( GTK_TEXT(m_text) );
490 else
491 pos = GTK_ENTRY(m_text)->text_length;
492 return (long)pos-1;
493 }
494
495 void wxTextCtrl::Remove( long from, long to )
496 {
497 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
498
499 gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
500 }
501
502 void wxTextCtrl::Replace( long from, long to, const wxString &value )
503 {
504 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
505
506 gtk_editable_delete_text( GTK_EDITABLE(m_text), (gint)from, (gint)to );
507 if (value.IsNull()) return;
508 gint pos = (gint)to;
509 gtk_editable_insert_text( GTK_EDITABLE(m_text), value, value.Length(), &pos );
510 }
511
512 void wxTextCtrl::Cut()
513 {
514 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
515
516 #if (GTK_MINOR_VERSION == 1)
517 gtk_editable_cut_clipboard( GTK_EDITABLE(m_text) );
518 #else
519 gtk_editable_cut_clipboard( GTK_EDITABLE(m_text), 0 );
520 #endif
521 }
522
523 void wxTextCtrl::Copy()
524 {
525 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
526
527 #if (GTK_MINOR_VERSION == 1)
528 gtk_editable_copy_clipboard( GTK_EDITABLE(m_text) );
529 #else
530 gtk_editable_copy_clipboard( GTK_EDITABLE(m_text), 0 );
531 #endif
532 }
533
534 void wxTextCtrl::Paste()
535 {
536 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
537
538 #if (GTK_MINOR_VERSION == 1)
539 gtk_editable_paste_clipboard( GTK_EDITABLE(m_text) );
540 #else
541 gtk_editable_paste_clipboard( GTK_EDITABLE(m_text), 0 );
542 #endif
543 }
544
545 void wxTextCtrl::Clear()
546 {
547 SetValue( "" );
548 }
549
550 void wxTextCtrl::OnChar( wxKeyEvent &key_event )
551 {
552 if ((key_event.KeyCode() == WXK_RETURN) && (m_windowStyle & wxPROCESS_ENTER))
553 {
554 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
555 event.SetEventObject(this);
556 if (GetEventHandler()->ProcessEvent(event)) return;
557 }
558 else if (key_event.KeyCode() == WXK_TAB)
559 {
560 wxNavigationKeyEvent event;
561 event.SetDirection( key_event.m_shiftDown );
562 event.SetWindowChange(FALSE);
563 event.SetEventObject(this);
564
565 if (GetEventHandler()->ProcessEvent(event)) return;
566 }
567 key_event.Skip();
568 }
569
570 int wxTextCtrl::overflow( int WXUNUSED(c) )
571 {
572 int len = pptr() - pbase();
573 char *txt = new char[len+1];
574 strncpy(txt, pbase(), len);
575 txt[len] = '\0';
576 (*this) << txt;
577 setp(pbase(), epptr());
578 delete[] txt;
579 return EOF;
580 }
581
582 int wxTextCtrl::sync()
583 {
584 int len = pptr() - pbase();
585 char *txt = new char[len+1];
586 strncpy(txt, pbase(), len);
587 txt[len] = '\0';
588 (*this) << txt;
589 setp(pbase(), epptr());
590 delete[] txt;
591 return 0;
592 }
593
594 int wxTextCtrl::underflow()
595 {
596 return EOF;
597 }
598
599 wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
600 {
601 WriteText(s);
602 return *this;
603 }
604
605 wxTextCtrl& wxTextCtrl::operator<<(float f)
606 {
607 static char buf[100];
608 sprintf(buf, "%.2f", f);
609 WriteText(buf);
610 return *this;
611 }
612
613 wxTextCtrl& wxTextCtrl::operator<<(double d)
614 {
615 static char buf[100];
616 sprintf(buf, "%.2f", d);
617 WriteText(buf);
618 return *this;
619 }
620
621 wxTextCtrl& wxTextCtrl::operator<<(int i)
622 {
623 static char buf[100];
624 sprintf(buf, "%i", i);
625 WriteText(buf);
626 return *this;
627 }
628
629 wxTextCtrl& wxTextCtrl::operator<<(long i)
630 {
631 static char buf[100];
632 sprintf(buf, "%ld", i);
633 WriteText(buf);
634 return *this;
635 }
636
637 wxTextCtrl& wxTextCtrl::operator<<(const char c)
638 {
639 char buf[2];
640
641 buf[0] = c;
642 buf[1] = 0;
643 WriteText(buf);
644 return *this;
645 }
646
647 GtkWidget* wxTextCtrl::GetConnectWidget()
648 {
649 return GTK_WIDGET(m_text);
650 }
651
652 bool wxTextCtrl::IsOwnGtkWindow( GdkWindow *window )
653 {
654 if (m_windowStyle & wxTE_MULTILINE)
655 return (window == GTK_TEXT(m_text)->text_area);
656 else
657 return (window == GTK_ENTRY(m_text)->text_area);
658 }
659
660 void wxTextCtrl::SetFont( const wxFont &WXUNUSED(font) )
661 {
662 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
663
664 // doesn't work
665 }
666
667 void wxTextCtrl::SetForegroundColour( const wxColour &WXUNUSED(colour) )
668 {
669 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
670
671 // doesn't work
672 }
673
674 void wxTextCtrl::SetBackgroundColour( const wxColour &colour )
675 {
676 wxCHECK_RET( m_text != NULL, "invalid text ctrl" );
677
678 wxControl::SetBackgroundColour( colour );
679
680 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
681 if (sysbg.Red() == colour.Red() &&
682 sysbg.Green() == colour.Green() &&
683 sysbg.Blue() == colour.Blue())
684 {
685 return;
686 }
687
688 if (!m_backgroundColour.Ok()) return;
689
690 if (m_windowStyle & wxTE_MULTILINE)
691 {
692 GdkWindow *window = GTK_TEXT(m_text)->text_area;
693 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
694 gdk_window_set_background( window, m_backgroundColour.GetColor() );
695 gdk_window_clear( window );
696 }
697 }
698
699 void wxTextCtrl::ApplyWidgetStyle()
700 {
701 if (m_windowStyle & wxTE_MULTILINE)
702 {
703 }
704 else
705 {
706 SetWidgetStyle();
707 gtk_widget_set_style( m_text, m_widgetStyle );
708 }
709 }
710