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