]> git.saurik.com Git - wxWidgets.git/blame_incremental - samples/widgets/textctrl.cpp
added workaround for GTK+ focus_out bug (and removed Vaclav's mouse capture stack...
[wxWidgets.git] / samples / widgets / textctrl.cpp
... / ...
CommitLineData
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
51enum
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
67enum TextLines
68{
69 TextLines_Single,
70 TextLines_Multi
71};
72
73// default values for the controls
74static 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
93class TextWidgetsPage : public WidgetsPage
94{
95public:
96 // ctor(s) and dtor
97 TextWidgetsPage(wxNotebook *notebook, wxImageList *imaglist);
98 virtual ~TextWidgetsPage();
99
100protected:
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
178private:
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
189BEGIN_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)
212END_EVENT_TABLE()
213
214// ============================================================================
215// implementation
216// ============================================================================
217
218IMPLEMENT_WIDGETS_PAGE(TextWidgetsPage, _T("Text"));
219
220// ----------------------------------------------------------------------------
221// TextWidgetsPage creation
222// ----------------------------------------------------------------------------
223
224TextWidgetsPage::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
379TextWidgetsPage::~TextWidgetsPage()
380{
381}
382
383// ----------------------------------------------------------------------------
384// creation helpers
385// ----------------------------------------------------------------------------
386
387wxTextCtrl *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
403wxSizer *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
426void 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
434void 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
485void 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
549void TextWidgetsPage::OnButtonReset(wxCommandEvent& WXUNUSED(event))
550{
551 Reset();
552
553 CreateText();
554}
555
556void TextWidgetsPage::OnButtonSet(wxCommandEvent& WXUNUSED(event))
557{
558 m_text->SetValue(_T("Yellow submarine"));
559 m_text->SetFocus();
560}
561
562void TextWidgetsPage::OnButtonAdd(wxCommandEvent& WXUNUSED(event))
563{
564 m_text->AppendText(_T("here, there and everywhere"));
565 m_text->SetFocus();
566}
567
568void 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
574void TextWidgetsPage::OnButtonClear(wxCommandEvent& WXUNUSED(event))
575{
576 m_text->Clear();
577 m_text->SetFocus();
578}
579
580void 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
610void TextWidgetsPage::OnUpdateUIClearButton(wxUpdateUIEvent& event)
611{
612 event.Enable(!m_text->GetValue().empty());
613}
614
615void TextWidgetsPage::OnUpdateUIWrapLinesCheckbox(wxUpdateUIEvent& event)
616{
617 event.Enable( !IsSingleLine() );
618}
619
620void TextWidgetsPage::OnUpdateUIPasswordCheckbox(wxUpdateUIEvent& event)
621{
622 // can't put multiline control in password mode
623 event.Enable( IsSingleLine() );
624}
625
626void 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
634void 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
649void TextWidgetsPage::OnTextEnter(wxCommandEvent& event)
650{
651 wxLogMessage(_T("Text entered: '%s'"), event.GetString().c_str());
652}
653
654void TextWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& event)
655{
656 CreateText();
657}
658