]> git.saurik.com Git - wxWidgets.git/blob - samples/widgets/textctrl.cpp
Workaround for Ctrl-A giving a keycode of 1 in EVT_KEY_DOWN on wxGTK
[wxWidgets.git] / samples / widgets / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Program: wxWindows Widgets Sample
3 // Name: textctrl.cpp
4 // Purpose: part of the widgets sample showing wxTextCtrl
5 // Author: Vadim Zeitlin
6 // Created: 27.03.01
7 // Id: $Id$
8 // Copyright: (c) 2001 Vadim Zeitlin
9 // License: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx/wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 // for all others, include the necessary headers
28 #ifndef WX_PRECOMP
29 #include "wx/log.h"
30 #include "wx/timer.h"
31
32 #include "wx/button.h"
33 #include "wx/checkbox.h"
34 #include "wx/radiobox.h"
35 #include "wx/statbox.h"
36 #include "wx/stattext.h"
37 #include "wx/textctrl.h"
38 #endif
39
40 #include "wx/sizer.h"
41
42 #include "widgets.h"
43
44 #include "icons/text.xpm"
45
46 // ----------------------------------------------------------------------------
47 // constants
48 // ----------------------------------------------------------------------------
49
50 // control ids
51 enum
52 {
53 TextPage_Reset = 100,
54
55 TextPage_Set,
56 TextPage_Add,
57 TextPage_Insert,
58 TextPage_Clear,
59 TextPage_Load,
60
61 TextPage_Password,
62 TextPage_WrapLines,
63 TextPage_Textctrl
64 };
65
66 // textctrl line number radiobox values
67 enum TextLines
68 {
69 TextLines_Single,
70 TextLines_Multi
71 };
72
73 // default values for the controls
74 static const struct ControlValues
75 {
76 TextLines textLines;
77 bool password;
78 bool wraplines;
79 bool readonly;
80 } DEFAULTS =
81 {
82 TextLines_Multi, // multiline
83 FALSE, // not password
84 TRUE, // do wrap lines
85 FALSE // not readonly
86 };
87
88 // ----------------------------------------------------------------------------
89 // TextWidgetsPage
90 // ----------------------------------------------------------------------------
91
92 // Define a new frame type: this is going to be our main frame
93 class TextWidgetsPage : public WidgetsPage
94 {
95 public:
96 // ctor(s) and dtor
97 TextWidgetsPage(wxNotebook *notebook, wxImageList *imaglist);
98 virtual ~TextWidgetsPage();
99
100 protected:
101 // create an info text contorl
102 wxTextCtrl *CreateInfoText();
103
104 // create a horz sizer holding a static text and this text control
105 wxSizer *CreateTextWithLabelSizer(const wxString& label,
106 wxTextCtrl *text,
107 const wxString& label2 = wxEmptyString,
108 wxTextCtrl *text2 = NULL);
109
110 // event handlers
111 void OnButtonReset(wxCommandEvent& event);
112 void OnButtonClearLog(wxCommandEvent& event);
113
114 void OnButtonSet(wxCommandEvent& event);
115 void OnButtonAdd(wxCommandEvent& event);
116 void OnButtonInsert(wxCommandEvent& event);
117 void OnButtonClear(wxCommandEvent& event);
118 void OnButtonLoad(wxCommandEvent& event);
119
120 void OnButtonQuit(wxCommandEvent& event);
121
122 void OnText(wxCommandEvent& event);
123 void OnTextEnter(wxCommandEvent& event);
124
125 void OnCheckOrRadioBox(wxCommandEvent& event);
126
127 void OnUpdateUIClearButton(wxUpdateUIEvent& event);
128
129 void OnUpdateUIPasswordCheckbox(wxUpdateUIEvent& event);
130 void OnUpdateUIWrapLinesCheckbox(wxUpdateUIEvent& event);
131
132 void OnUpdateUIResetButton(wxUpdateUIEvent& event);
133
134 void OnIdle(wxIdleEvent& event);
135
136 // reset the textctrl parameters
137 void Reset();
138
139 // (re)create the textctrl
140 void CreateText();
141
142 // is the control currently single line?
143 bool IsSingleLine() const
144 {
145 return m_radioTextLines->GetSelection() == TextLines_Single;
146 }
147
148 // the controls
149 // ------------
150
151 // the radiobox to choose between single and multi line
152 wxRadioBox *m_radioTextLines;
153
154 // the checkboxes controlling text ctrl styles
155 wxCheckBox *m_chkPassword,
156 *m_chkWrapLines,
157 *m_chkReadonly;
158
159 // the textctrl itself and the sizer it is in
160 wxTextCtrl *m_text;
161 wxSizer *m_sizerText;
162
163 // the information text zones
164 wxTextCtrl *m_textPosCur,
165 *m_textRowCur,
166 *m_textColCur,
167 *m_textPosLast,
168 *m_textLineLast,
169 *m_textSelFrom,
170 *m_textSelTo;
171
172 // and the data to show in them
173 long m_posCur,
174 m_posLast,
175 m_selFrom,
176 m_selTo;
177
178 private:
179 // any class wishing to process wxWindows events must use this macro
180 DECLARE_EVENT_TABLE();
181
182 DECLARE_WIDGETS_PAGE(TextWidgetsPage);
183 };
184
185 // ----------------------------------------------------------------------------
186 // event tables
187 // ----------------------------------------------------------------------------
188
189 BEGIN_EVENT_TABLE(TextWidgetsPage, WidgetsPage)
190 EVT_IDLE(TextWidgetsPage::OnIdle)
191
192 EVT_BUTTON(TextPage_Reset, TextWidgetsPage::OnButtonReset)
193
194 EVT_BUTTON(TextPage_Clear, TextWidgetsPage::OnButtonClear)
195 EVT_BUTTON(TextPage_Set, TextWidgetsPage::OnButtonSet)
196 EVT_BUTTON(TextPage_Add, TextWidgetsPage::OnButtonAdd)
197 EVT_BUTTON(TextPage_Insert, TextWidgetsPage::OnButtonInsert)
198 EVT_BUTTON(TextPage_Load, TextWidgetsPage::OnButtonLoad)
199
200 EVT_UPDATE_UI(TextPage_Clear, TextWidgetsPage::OnUpdateUIClearButton)
201
202 EVT_UPDATE_UI(TextPage_Password, TextWidgetsPage::OnUpdateUIPasswordCheckbox)
203 EVT_UPDATE_UI(TextPage_WrapLines, TextWidgetsPage::OnUpdateUIWrapLinesCheckbox)
204
205 EVT_UPDATE_UI(TextPage_Reset, TextWidgetsPage::OnUpdateUIResetButton)
206
207 EVT_TEXT(TextPage_Textctrl, TextWidgetsPage::OnText)
208 EVT_TEXT_ENTER(TextPage_Textctrl, TextWidgetsPage::OnTextEnter)
209
210 EVT_CHECKBOX(-1, TextWidgetsPage::OnCheckOrRadioBox)
211 EVT_RADIOBOX(-1, TextWidgetsPage::OnCheckOrRadioBox)
212 END_EVENT_TABLE()
213
214 // ============================================================================
215 // implementation
216 // ============================================================================
217
218 IMPLEMENT_WIDGETS_PAGE(TextWidgetsPage, _T("Text"));
219
220 // ----------------------------------------------------------------------------
221 // TextWidgetsPage creation
222 // ----------------------------------------------------------------------------
223
224 TextWidgetsPage::TextWidgetsPage(wxNotebook *notebook, wxImageList *imaglist)
225 : WidgetsPage(notebook)
226 {
227 imaglist->Add(wxBitmap(text_xpm));
228
229 // init everything
230 m_radioTextLines = (wxRadioBox *)NULL;
231
232 m_chkPassword =
233 m_chkWrapLines =
234 m_chkReadonly = (wxCheckBox *)NULL;
235
236 m_text =
237 m_textPosCur =
238 m_textRowCur =
239 m_textColCur =
240 m_textPosLast =
241 m_textLineLast =
242 m_textSelFrom =
243 m_textSelTo = (wxTextCtrl *)NULL;
244 m_sizerText = (wxSizer *)NULL;
245
246 m_posCur =
247 m_posLast =
248 m_selFrom =
249 m_selTo = -2; // not -1 which means "no selection"
250
251 // left pane
252 static const wxString modes[] =
253 {
254 _T("single line"),
255 _T("multi line"),
256 };
257
258 wxStaticBox *box = new wxStaticBox(this, -1, _T("&Set textctrl parameters"));
259 m_radioTextLines = new wxRadioBox(this, -1, _T("&Number of lines:"),
260 wxDefaultPosition, wxDefaultSize,
261 WXSIZEOF(modes), modes,
262 1, wxRA_SPECIFY_COLS);
263
264 wxSizer *sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL);
265
266 sizerLeft->Add(m_radioTextLines, 0, wxGROW | wxALL, 5);
267 sizerLeft->Add(5, 5, 0, wxGROW | wxALL, 5); // spacer
268
269 m_chkPassword = CreateCheckBoxAndAddToSizer(
270 sizerLeft, _T("&Password control"), TextPage_Password
271 );
272 m_chkWrapLines = CreateCheckBoxAndAddToSizer(
273 sizerLeft, _T("Line &wrap"), TextPage_WrapLines
274 );
275 m_chkReadonly = CreateCheckBoxAndAddToSizer(
276 sizerLeft, _T("&Read-only mode")
277 );
278
279 wxButton *btn = new wxButton(this, TextPage_Reset, _T("&Reset"));
280 sizerLeft->Add(btn, 0, wxALIGN_CENTRE_HORIZONTAL | wxALL, 15);
281
282 // middle pane
283 wxStaticBox *box2 = new wxStaticBox(this, -1, _T("&Change contents:"));
284 wxSizer *sizerMiddleUp = new wxStaticBoxSizer(box2, wxVERTICAL);
285
286 btn = new wxButton(this, TextPage_Set, _T("&Set text value"));
287 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
288
289 btn = new wxButton(this, TextPage_Add, _T("&Append text"));
290 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
291
292 btn = new wxButton(this, TextPage_Insert, _T("&Insert text"));
293 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
294
295 btn = new wxButton(this, TextPage_Load, _T("&Load file"));
296 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
297
298 btn = new wxButton(this, TextPage_Clear, _T("&Clear"));
299 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
300
301 wxStaticBox *box4 = new wxStaticBox(this, -1, _T("&Info:"));
302 wxSizer *sizerMiddleDown = new wxStaticBoxSizer(box4, wxVERTICAL);
303
304 m_textPosCur = CreateInfoText();
305 m_textRowCur = CreateInfoText();
306 m_textColCur = CreateInfoText();
307
308 wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
309 sizerRow->Add(CreateTextWithLabelSizer
310 (
311 _T("Current pos:"),
312 m_textPosCur
313 ),
314 0, wxRIGHT, 5);
315 sizerRow->Add(CreateTextWithLabelSizer
316 (
317 _T("Col:"),
318 m_textColCur
319 ),
320 0, wxLEFT | wxRIGHT, 5);
321 sizerRow->Add(CreateTextWithLabelSizer
322 (
323 _T("Row:"),
324 m_textRowCur
325 ),
326 0, wxLEFT, 5);
327 sizerMiddleDown->Add(sizerRow, 0, wxALL, 5);
328
329 m_textLineLast = CreateInfoText();
330 m_textPosLast = CreateInfoText();
331 sizerMiddleDown->Add
332 (
333 CreateTextWithLabelSizer
334 (
335 _T("Number of lines:"),
336 m_textLineLast,
337 _T("Last position:"),
338 m_textPosLast
339 ),
340 0, wxALL, 5
341 );
342
343 m_textSelFrom = CreateInfoText();
344 m_textSelTo = CreateInfoText();
345 sizerMiddleDown->Add
346 (
347 CreateTextWithLabelSizer
348 (
349 _T("Selection: from"),
350 m_textSelFrom,
351 _T("to"),
352 m_textSelTo
353 ),
354 0, wxALL, 5
355 );
356 wxSizer *sizerMiddle = new wxBoxSizer(wxVERTICAL);
357 sizerMiddle->Add(sizerMiddleUp, 0, wxGROW);
358 sizerMiddle->Add(sizerMiddleDown, 1, wxGROW | wxTOP, 5);
359
360 // right pane
361 wxStaticBox *box3 = new wxStaticBox(this, -1, _T("&Text:"));
362 m_sizerText = new wxStaticBoxSizer(box3, wxHORIZONTAL);
363 Reset();
364 CreateText();
365 m_sizerText->SetMinSize(250, 0);
366
367 // the 3 panes panes compose the upper part of the window
368 wxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);
369 sizerTop->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10);
370 sizerTop->Add(sizerMiddle, 0, wxGROW | wxALL, 10);
371 sizerTop->Add(m_sizerText, 1, wxGROW | (wxALL & ~wxRIGHT), 10);
372
373 SetAutoLayout(TRUE);
374 SetSizer(sizerTop);
375
376 sizerTop->Fit(this);
377 }
378
379 TextWidgetsPage::~TextWidgetsPage()
380 {
381 }
382
383 // ----------------------------------------------------------------------------
384 // creation helpers
385 // ----------------------------------------------------------------------------
386
387 wxTextCtrl *TextWidgetsPage::CreateInfoText()
388 {
389 static int s_maxWidth = 0;
390 if ( !s_maxWidth )
391 {
392 // calc it once only
393 GetTextExtent(_T("9999999"), &s_maxWidth, NULL);
394 }
395
396 wxTextCtrl *text = new wxTextCtrl(this, -1, _T(""),
397 wxDefaultPosition,
398 wxSize(s_maxWidth, -1),
399 wxTE_READONLY);
400 return text;
401 }
402
403 wxSizer *TextWidgetsPage::CreateTextWithLabelSizer(const wxString& label,
404 wxTextCtrl *text,
405 const wxString& label2,
406 wxTextCtrl *text2)
407 {
408 wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
409 sizerRow->Add(new wxStaticText(this, -1, label), 0,
410 wxALIGN_CENTRE_VERTICAL | wxRIGHT, 5);
411 sizerRow->Add(text, 0, wxALIGN_CENTRE_VERTICAL);
412 if ( text2 )
413 {
414 sizerRow->Add(new wxStaticText(this, -1, label2), 0,
415 wxALIGN_CENTRE_VERTICAL | wxLEFT | wxRIGHT, 5);
416 sizerRow->Add(text2, 0, wxALIGN_CENTRE_VERTICAL);
417 }
418
419 return sizerRow;
420 }
421
422 // ----------------------------------------------------------------------------
423 // operations
424 // ----------------------------------------------------------------------------
425
426 void TextWidgetsPage::Reset()
427 {
428 m_radioTextLines->SetSelection(DEFAULTS.textLines);
429 m_chkPassword->SetValue(DEFAULTS.password);
430 m_chkWrapLines->SetValue(DEFAULTS.wraplines);
431 m_chkReadonly->SetValue(DEFAULTS.readonly);
432 }
433
434 void TextWidgetsPage::CreateText()
435 {
436 int flags = 0;
437 switch ( m_radioTextLines->GetSelection() )
438 {
439 default:
440 wxFAIL_MSG( _T("unexpected radio box selection") );
441
442 case TextLines_Single:
443 break;
444
445 case TextLines_Multi:
446 flags |= wxTE_MULTILINE;
447 m_chkPassword->SetValue(FALSE);
448 break;
449 }
450
451 if ( m_chkPassword->GetValue() )
452 flags |= wxTE_PASSWORD;
453 if ( m_chkReadonly->GetValue() )
454 flags |= wxTE_READONLY;
455 if ( !m_chkWrapLines->GetValue() )
456 flags |= wxHSCROLL;
457
458 wxString valueOld;
459 if ( m_text )
460 {
461 valueOld = m_text->GetValue();
462
463 m_sizerText->Remove(m_text);
464 delete m_text;
465 }
466 else
467 {
468 valueOld = _T("Hello, Universe!");
469 }
470
471 m_text = new wxTextCtrl(this, TextPage_Textctrl,
472 valueOld,
473 wxDefaultPosition, wxDefaultSize,
474 flags);
475 m_sizerText->Add(m_text, 1, wxALL |
476 (flags & wxTE_MULTILINE ? wxGROW
477 : wxALIGN_TOP), 5);
478 m_sizerText->Layout();
479 }
480
481 // ----------------------------------------------------------------------------
482 // event handlers
483 // ----------------------------------------------------------------------------
484
485 void TextWidgetsPage::OnIdle(wxIdleEvent& WXUNUSED(event))
486 {
487 // update all info texts
488
489 if ( m_textPosCur )
490 {
491 long posCur = m_text->GetInsertionPoint();
492 if ( posCur != m_posCur )
493 {
494 m_textPosCur->Clear();
495 m_textRowCur->Clear();
496 m_textColCur->Clear();
497
498 long col, row;
499 m_text->PositionToXY(posCur, &col, &row);
500
501 *m_textPosCur << posCur;
502 *m_textRowCur << row;
503 *m_textColCur << col;
504
505 m_posCur = posCur;
506 }
507 }
508
509 if ( m_textPosLast )
510 {
511 long posLast = m_text->GetLastPosition();
512 if ( posLast != m_posLast )
513 {
514 m_textPosLast->Clear();
515 *m_textPosLast << posLast;
516
517 m_posLast = posLast;
518 }
519 }
520
521 if ( m_textLineLast )
522 {
523 m_textLineLast->SetValue(
524 wxString::Format(_T("%ld"), m_text->GetNumberOfLines()));
525 }
526
527 if ( m_textSelFrom && m_textSelTo )
528 {
529 long selFrom, selTo;
530 m_text->GetSelection(&selFrom, &selTo);
531 if ( selFrom != m_selFrom )
532 {
533 m_textSelFrom->Clear();
534 *m_textSelFrom << selFrom;
535
536 m_selFrom = selFrom;
537 }
538
539 if ( selTo != m_selTo )
540 {
541 m_textSelTo->Clear();
542 *m_textSelTo << selTo;
543
544 m_selTo = selTo;
545 }
546 }
547 }
548
549 void TextWidgetsPage::OnButtonReset(wxCommandEvent& WXUNUSED(event))
550 {
551 Reset();
552
553 CreateText();
554 }
555
556 void TextWidgetsPage::OnButtonSet(wxCommandEvent& WXUNUSED(event))
557 {
558 m_text->SetValue(_T("Yellow submarine"));
559 m_text->SetFocus();
560 }
561
562 void TextWidgetsPage::OnButtonAdd(wxCommandEvent& WXUNUSED(event))
563 {
564 m_text->AppendText(_T("here, there and everywhere"));
565 m_text->SetFocus();
566 }
567
568 void TextWidgetsPage::OnButtonInsert(wxCommandEvent& WXUNUSED(event))
569 {
570 m_text->WriteText(_T("is there anybody going to listen to my story"));
571 m_text->SetFocus();
572 }
573
574 void TextWidgetsPage::OnButtonClear(wxCommandEvent& WXUNUSED(event))
575 {
576 m_text->Clear();
577 m_text->SetFocus();
578 }
579
580 void TextWidgetsPage::OnButtonLoad(wxCommandEvent& WXUNUSED(event))
581 {
582 // search for the file in several dirs where it's likely to be
583 wxPathList pathlist;
584 pathlist.Add(_T("."));
585 pathlist.Add(_T(".."));
586 pathlist.Add(_T("../../../samples/widgets"));
587
588 wxString filename = pathlist.FindValidPath(_T("textctrl.cpp"));
589 if ( !filename )
590 {
591 wxLogError(_T("File textctrl.cpp not found."));
592 }
593 else // load it
594 {
595 wxStopWatch sw;
596 if ( !m_text->LoadFile(filename) )
597 {
598 // this is not supposed to happen ...
599 wxLogError(_T("Error loading file."));
600 }
601 else
602 {
603 long elapsed = sw.Time();
604 wxLogMessage(_T("Loaded file '%s' in %u.%us"),
605 filename.c_str(), elapsed / 1000, elapsed % 1000);
606 }
607 }
608 }
609
610 void TextWidgetsPage::OnUpdateUIClearButton(wxUpdateUIEvent& event)
611 {
612 event.Enable(!m_text->GetValue().empty());
613 }
614
615 void TextWidgetsPage::OnUpdateUIWrapLinesCheckbox(wxUpdateUIEvent& event)
616 {
617 event.Enable( !IsSingleLine() );
618 }
619
620 void TextWidgetsPage::OnUpdateUIPasswordCheckbox(wxUpdateUIEvent& event)
621 {
622 // can't put multiline control in password mode
623 event.Enable( IsSingleLine() );
624 }
625
626 void TextWidgetsPage::OnUpdateUIResetButton(wxUpdateUIEvent& event)
627 {
628 event.Enable( (m_radioTextLines->GetSelection() != DEFAULTS.textLines) ||
629 (m_chkReadonly->GetValue() != DEFAULTS.readonly) ||
630 (m_chkPassword->GetValue() != DEFAULTS.password) ||
631 (m_chkWrapLines->GetValue() != DEFAULTS.wraplines) );
632 }
633
634 void TextWidgetsPage::OnText(wxCommandEvent& event)
635 {
636 // small hack to suppress the very first message: by then the logging is
637 // not yet redirected and so initial setting of the text value results in
638 // an annoying message box
639 static bool s_firstTime = TRUE;
640 if ( s_firstTime )
641 {
642 s_firstTime = FALSE;
643 return;
644 }
645
646 wxLogMessage(_T("Text ctrl value changed"));
647 }
648
649 void TextWidgetsPage::OnTextEnter(wxCommandEvent& event)
650 {
651 wxLogMessage(_T("Text entered: '%s'"), event.GetString().c_str());
652 }
653
654 void TextWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& event)
655 {
656 CreateText();
657 }
658