removed trailing ; after DECLARE_ macros
[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 DECLARE_WIDGETS_PAGE(TextWidgetsPage)
182 };
183
184 // ----------------------------------------------------------------------------
185 // event tables
186 // ----------------------------------------------------------------------------
187
188 BEGIN_EVENT_TABLE(TextWidgetsPage, WidgetsPage)
189 EVT_IDLE(TextWidgetsPage::OnIdle)
190
191 EVT_BUTTON(TextPage_Reset, TextWidgetsPage::OnButtonReset)
192
193 EVT_BUTTON(TextPage_Clear, TextWidgetsPage::OnButtonClear)
194 EVT_BUTTON(TextPage_Set, TextWidgetsPage::OnButtonSet)
195 EVT_BUTTON(TextPage_Add, TextWidgetsPage::OnButtonAdd)
196 EVT_BUTTON(TextPage_Insert, TextWidgetsPage::OnButtonInsert)
197 EVT_BUTTON(TextPage_Load, TextWidgetsPage::OnButtonLoad)
198
199 EVT_UPDATE_UI(TextPage_Clear, TextWidgetsPage::OnUpdateUIClearButton)
200
201 EVT_UPDATE_UI(TextPage_Password, TextWidgetsPage::OnUpdateUIPasswordCheckbox)
202 EVT_UPDATE_UI(TextPage_WrapLines, TextWidgetsPage::OnUpdateUIWrapLinesCheckbox)
203
204 EVT_UPDATE_UI(TextPage_Reset, TextWidgetsPage::OnUpdateUIResetButton)
205
206 EVT_TEXT(TextPage_Textctrl, TextWidgetsPage::OnText)
207 EVT_TEXT_ENTER(TextPage_Textctrl, TextWidgetsPage::OnTextEnter)
208
209 EVT_CHECKBOX(-1, TextWidgetsPage::OnCheckOrRadioBox)
210 EVT_RADIOBOX(-1, TextWidgetsPage::OnCheckOrRadioBox)
211 END_EVENT_TABLE()
212
213 // ============================================================================
214 // implementation
215 // ============================================================================
216
217 IMPLEMENT_WIDGETS_PAGE(TextWidgetsPage, _T("Text"));
218
219 // ----------------------------------------------------------------------------
220 // TextWidgetsPage creation
221 // ----------------------------------------------------------------------------
222
223 TextWidgetsPage::TextWidgetsPage(wxNotebook *notebook, wxImageList *imaglist)
224 : WidgetsPage(notebook)
225 {
226 imaglist->Add(wxBitmap(text_xpm));
227
228 // init everything
229 m_radioTextLines = (wxRadioBox *)NULL;
230
231 m_chkPassword =
232 m_chkWrapLines =
233 m_chkReadonly = (wxCheckBox *)NULL;
234
235 m_text =
236 m_textPosCur =
237 m_textRowCur =
238 m_textColCur =
239 m_textPosLast =
240 m_textLineLast =
241 m_textSelFrom =
242 m_textSelTo = (wxTextCtrl *)NULL;
243 m_sizerText = (wxSizer *)NULL;
244
245 m_posCur =
246 m_posLast =
247 m_selFrom =
248 m_selTo = -2; // not -1 which means "no selection"
249
250 // left pane
251 static const wxString modes[] =
252 {
253 _T("single line"),
254 _T("multi line"),
255 };
256
257 wxStaticBox *box = new wxStaticBox(this, -1, _T("&Set textctrl parameters"));
258 m_radioTextLines = new wxRadioBox(this, -1, _T("&Number of lines:"),
259 wxDefaultPosition, wxDefaultSize,
260 WXSIZEOF(modes), modes,
261 1, wxRA_SPECIFY_COLS);
262
263 wxSizer *sizerLeft = new wxStaticBoxSizer(box, wxVERTICAL);
264
265 sizerLeft->Add(m_radioTextLines, 0, wxGROW | wxALL, 5);
266 sizerLeft->Add(5, 5, 0, wxGROW | wxALL, 5); // spacer
267
268 m_chkPassword = CreateCheckBoxAndAddToSizer(
269 sizerLeft, _T("&Password control"), TextPage_Password
270 );
271 m_chkWrapLines = CreateCheckBoxAndAddToSizer(
272 sizerLeft, _T("Line &wrap"), TextPage_WrapLines
273 );
274 m_chkReadonly = CreateCheckBoxAndAddToSizer(
275 sizerLeft, _T("&Read-only mode")
276 );
277
278 wxButton *btn = new wxButton(this, TextPage_Reset, _T("&Reset"));
279 sizerLeft->Add(btn, 0, wxALIGN_CENTRE_HORIZONTAL | wxALL, 15);
280
281 // middle pane
282 wxStaticBox *box2 = new wxStaticBox(this, -1, _T("&Change contents:"));
283 wxSizer *sizerMiddleUp = new wxStaticBoxSizer(box2, wxVERTICAL);
284
285 btn = new wxButton(this, TextPage_Set, _T("&Set text value"));
286 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
287
288 btn = new wxButton(this, TextPage_Add, _T("&Append text"));
289 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
290
291 btn = new wxButton(this, TextPage_Insert, _T("&Insert text"));
292 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
293
294 btn = new wxButton(this, TextPage_Load, _T("&Load file"));
295 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
296
297 btn = new wxButton(this, TextPage_Clear, _T("&Clear"));
298 sizerMiddleUp->Add(btn, 0, wxALL | wxGROW, 5);
299
300 wxStaticBox *box4 = new wxStaticBox(this, -1, _T("&Info:"));
301 wxSizer *sizerMiddleDown = new wxStaticBoxSizer(box4, wxVERTICAL);
302
303 m_textPosCur = CreateInfoText();
304 m_textRowCur = CreateInfoText();
305 m_textColCur = CreateInfoText();
306
307 wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
308 sizerRow->Add(CreateTextWithLabelSizer
309 (
310 _T("Current pos:"),
311 m_textPosCur
312 ),
313 0, wxRIGHT, 5);
314 sizerRow->Add(CreateTextWithLabelSizer
315 (
316 _T("Col:"),
317 m_textColCur
318 ),
319 0, wxLEFT | wxRIGHT, 5);
320 sizerRow->Add(CreateTextWithLabelSizer
321 (
322 _T("Row:"),
323 m_textRowCur
324 ),
325 0, wxLEFT, 5);
326 sizerMiddleDown->Add(sizerRow, 0, wxALL, 5);
327
328 m_textLineLast = CreateInfoText();
329 m_textPosLast = CreateInfoText();
330 sizerMiddleDown->Add
331 (
332 CreateTextWithLabelSizer
333 (
334 _T("Number of lines:"),
335 m_textLineLast,
336 _T("Last position:"),
337 m_textPosLast
338 ),
339 0, wxALL, 5
340 );
341
342 m_textSelFrom = CreateInfoText();
343 m_textSelTo = CreateInfoText();
344 sizerMiddleDown->Add
345 (
346 CreateTextWithLabelSizer
347 (
348 _T("Selection: from"),
349 m_textSelFrom,
350 _T("to"),
351 m_textSelTo
352 ),
353 0, wxALL, 5
354 );
355 wxSizer *sizerMiddle = new wxBoxSizer(wxVERTICAL);
356 sizerMiddle->Add(sizerMiddleUp, 0, wxGROW);
357 sizerMiddle->Add(sizerMiddleDown, 1, wxGROW | wxTOP, 5);
358
359 // right pane
360 wxStaticBox *box3 = new wxStaticBox(this, -1, _T("&Text:"));
361 m_sizerText = new wxStaticBoxSizer(box3, wxHORIZONTAL);
362 Reset();
363 CreateText();
364 m_sizerText->SetMinSize(250, 0);
365
366 // the 3 panes panes compose the upper part of the window
367 wxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);
368 sizerTop->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10);
369 sizerTop->Add(sizerMiddle, 0, wxGROW | wxALL, 10);
370 sizerTop->Add(m_sizerText, 1, wxGROW | (wxALL & ~wxRIGHT), 10);
371
372 SetAutoLayout(TRUE);
373 SetSizer(sizerTop);
374
375 sizerTop->Fit(this);
376 }
377
378 TextWidgetsPage::~TextWidgetsPage()
379 {
380 }
381
382 // ----------------------------------------------------------------------------
383 // creation helpers
384 // ----------------------------------------------------------------------------
385
386 wxTextCtrl *TextWidgetsPage::CreateInfoText()
387 {
388 static int s_maxWidth = 0;
389 if ( !s_maxWidth )
390 {
391 // calc it once only
392 GetTextExtent(_T("9999999"), &s_maxWidth, NULL);
393 }
394
395 wxTextCtrl *text = new wxTextCtrl(this, -1, _T(""),
396 wxDefaultPosition,
397 wxSize(s_maxWidth, -1),
398 wxTE_READONLY);
399 return text;
400 }
401
402 wxSizer *TextWidgetsPage::CreateTextWithLabelSizer(const wxString& label,
403 wxTextCtrl *text,
404 const wxString& label2,
405 wxTextCtrl *text2)
406 {
407 wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
408 sizerRow->Add(new wxStaticText(this, -1, label), 0,
409 wxALIGN_CENTRE_VERTICAL | wxRIGHT, 5);
410 sizerRow->Add(text, 0, wxALIGN_CENTRE_VERTICAL);
411 if ( text2 )
412 {
413 sizerRow->Add(new wxStaticText(this, -1, label2), 0,
414 wxALIGN_CENTRE_VERTICAL | wxLEFT | wxRIGHT, 5);
415 sizerRow->Add(text2, 0, wxALIGN_CENTRE_VERTICAL);
416 }
417
418 return sizerRow;
419 }
420
421 // ----------------------------------------------------------------------------
422 // operations
423 // ----------------------------------------------------------------------------
424
425 void TextWidgetsPage::Reset()
426 {
427 m_radioTextLines->SetSelection(DEFAULTS.textLines);
428 m_chkPassword->SetValue(DEFAULTS.password);
429 m_chkWrapLines->SetValue(DEFAULTS.wraplines);
430 m_chkReadonly->SetValue(DEFAULTS.readonly);
431 }
432
433 void TextWidgetsPage::CreateText()
434 {
435 int flags = 0;
436 switch ( m_radioTextLines->GetSelection() )
437 {
438 default:
439 wxFAIL_MSG( _T("unexpected radio box selection") );
440
441 case TextLines_Single:
442 break;
443
444 case TextLines_Multi:
445 flags |= wxTE_MULTILINE;
446 m_chkPassword->SetValue(FALSE);
447 break;
448 }
449
450 if ( m_chkPassword->GetValue() )
451 flags |= wxTE_PASSWORD;
452 if ( m_chkReadonly->GetValue() )
453 flags |= wxTE_READONLY;
454 if ( !m_chkWrapLines->GetValue() )
455 flags |= wxHSCROLL;
456
457 wxString valueOld;
458 if ( m_text )
459 {
460 valueOld = m_text->GetValue();
461
462 m_sizerText->Remove(m_text);
463 delete m_text;
464 }
465 else
466 {
467 valueOld = _T("Hello, Universe!");
468 }
469
470 m_text = new wxTextCtrl(this, TextPage_Textctrl,
471 valueOld,
472 wxDefaultPosition, wxDefaultSize,
473 flags);
474 m_sizerText->Add(m_text, 1, wxALL |
475 (flags & wxTE_MULTILINE ? wxGROW
476 : wxALIGN_TOP), 5);
477 m_sizerText->Layout();
478 }
479
480 // ----------------------------------------------------------------------------
481 // event handlers
482 // ----------------------------------------------------------------------------
483
484 void TextWidgetsPage::OnIdle(wxIdleEvent& WXUNUSED(event))
485 {
486 // update all info texts
487
488 if ( m_textPosCur )
489 {
490 long posCur = m_text->GetInsertionPoint();
491 if ( posCur != m_posCur )
492 {
493 m_textPosCur->Clear();
494 m_textRowCur->Clear();
495 m_textColCur->Clear();
496
497 long col, row;
498 m_text->PositionToXY(posCur, &col, &row);
499
500 *m_textPosCur << posCur;
501 *m_textRowCur << row;
502 *m_textColCur << col;
503
504 m_posCur = posCur;
505 }
506 }
507
508 if ( m_textPosLast )
509 {
510 long posLast = m_text->GetLastPosition();
511 if ( posLast != m_posLast )
512 {
513 m_textPosLast->Clear();
514 *m_textPosLast << posLast;
515
516 m_posLast = posLast;
517 }
518 }
519
520 if ( m_textLineLast )
521 {
522 m_textLineLast->SetValue(
523 wxString::Format(_T("%ld"), m_text->GetNumberOfLines()));
524 }
525
526 if ( m_textSelFrom && m_textSelTo )
527 {
528 long selFrom, selTo;
529 m_text->GetSelection(&selFrom, &selTo);
530 if ( selFrom != m_selFrom )
531 {
532 m_textSelFrom->Clear();
533 *m_textSelFrom << selFrom;
534
535 m_selFrom = selFrom;
536 }
537
538 if ( selTo != m_selTo )
539 {
540 m_textSelTo->Clear();
541 *m_textSelTo << selTo;
542
543 m_selTo = selTo;
544 }
545 }
546 }
547
548 void TextWidgetsPage::OnButtonReset(wxCommandEvent& WXUNUSED(event))
549 {
550 Reset();
551
552 CreateText();
553 }
554
555 void TextWidgetsPage::OnButtonSet(wxCommandEvent& WXUNUSED(event))
556 {
557 m_text->SetValue(_T("Yellow submarine"));
558 m_text->SetFocus();
559 }
560
561 void TextWidgetsPage::OnButtonAdd(wxCommandEvent& WXUNUSED(event))
562 {
563 m_text->AppendText(_T("here, there and everywhere"));
564 m_text->SetFocus();
565 }
566
567 void TextWidgetsPage::OnButtonInsert(wxCommandEvent& WXUNUSED(event))
568 {
569 m_text->WriteText(_T("is there anybody going to listen to my story"));
570 m_text->SetFocus();
571 }
572
573 void TextWidgetsPage::OnButtonClear(wxCommandEvent& WXUNUSED(event))
574 {
575 m_text->Clear();
576 m_text->SetFocus();
577 }
578
579 void TextWidgetsPage::OnButtonLoad(wxCommandEvent& WXUNUSED(event))
580 {
581 // search for the file in several dirs where it's likely to be
582 wxPathList pathlist;
583 pathlist.Add(_T("."));
584 pathlist.Add(_T(".."));
585 pathlist.Add(_T("../../../samples/widgets"));
586
587 wxString filename = pathlist.FindValidPath(_T("textctrl.cpp"));
588 if ( !filename )
589 {
590 wxLogError(_T("File textctrl.cpp not found."));
591 }
592 else // load it
593 {
594 wxStopWatch sw;
595 if ( !m_text->LoadFile(filename) )
596 {
597 // this is not supposed to happen ...
598 wxLogError(_T("Error loading file."));
599 }
600 else
601 {
602 long elapsed = sw.Time();
603 wxLogMessage(_T("Loaded file '%s' in %u.%us"),
604 filename.c_str(), elapsed / 1000, elapsed % 1000);
605 }
606 }
607 }
608
609 void TextWidgetsPage::OnUpdateUIClearButton(wxUpdateUIEvent& event)
610 {
611 event.Enable(!m_text->GetValue().empty());
612 }
613
614 void TextWidgetsPage::OnUpdateUIWrapLinesCheckbox(wxUpdateUIEvent& event)
615 {
616 event.Enable( !IsSingleLine() );
617 }
618
619 void TextWidgetsPage::OnUpdateUIPasswordCheckbox(wxUpdateUIEvent& event)
620 {
621 // can't put multiline control in password mode
622 event.Enable( IsSingleLine() );
623 }
624
625 void TextWidgetsPage::OnUpdateUIResetButton(wxUpdateUIEvent& event)
626 {
627 event.Enable( (m_radioTextLines->GetSelection() != DEFAULTS.textLines) ||
628 (m_chkReadonly->GetValue() != DEFAULTS.readonly) ||
629 (m_chkPassword->GetValue() != DEFAULTS.password) ||
630 (m_chkWrapLines->GetValue() != DEFAULTS.wraplines) );
631 }
632
633 void TextWidgetsPage::OnText(wxCommandEvent& event)
634 {
635 // small hack to suppress the very first message: by then the logging is
636 // not yet redirected and so initial setting of the text value results in
637 // an annoying message box
638 static bool s_firstTime = TRUE;
639 if ( s_firstTime )
640 {
641 s_firstTime = FALSE;
642 return;
643 }
644
645 wxLogMessage(_T("Text ctrl value changed"));
646 }
647
648 void TextWidgetsPage::OnTextEnter(wxCommandEvent& event)
649 {
650 wxLogMessage(_T("Text entered: '%s'"), event.GetString().c_str());
651 }
652
653 void TextWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& event)
654 {
655 CreateText();
656 }
657