1 /////////////////////////////////////////////////////////////////////////////
2 // Program:     wxWidgets Widgets Sample
3 // Name:        samples/widgets/widgets.cpp
4 // Purpose:     Sample showing most of the simple wxWidgets widgets
5 // Author:      Vadim Zeitlin
6 // Created:     27.03.01
7 // Id:          $Id: widgets.cpp 58192 2009-01-18 12:29:22Z JS $
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/app.h"
30     #include "wx/log.h"
31     #include "wx/frame.h"
32     #include "wx/menu.h"
33 
34     #include "wx/button.h"
35     #include "wx/checkbox.h"
36     #include "wx/listbox.h"
37     #include "wx/statbox.h"
38     #include "wx/stattext.h"
39     #include "wx/textctrl.h"
40     #include "wx/msgdlg.h"
41 #endif
42 
43 #include "wx/sysopt.h"
44 #include "wx/bookctrl.h"
45 #include "wx/treebook.h"
46 #include "wx/sizer.h"
47 #include "wx/colordlg.h"
48 #include "wx/fontdlg.h"
49 #include "wx/textdlg.h"
50 #include "wx/imaglist.h"
51 #include "wx/wupdlock.h"
52 
53 #include "widgets.h"
54 
55 #include "../sample.xpm"
56 
57 // ----------------------------------------------------------------------------
58 // constants
59 // ----------------------------------------------------------------------------
60 
61 // control ids
62 enum
63 {
64     Widgets_ClearLog = 100,
65     Widgets_Quit,
66 
67     Widgets_BookCtrl,
68 
69 #if wxUSE_TOOLTIPS
70     Widgets_SetTooltip,
71 #endif // wxUSE_TOOLTIPS
72     Widgets_SetFgColour,
73     Widgets_SetBgColour,
74     Widgets_SetFont,
75     Widgets_Enable,
76 
77     Widgets_BorderNone,
78     Widgets_BorderStatic,
79     Widgets_BorderSimple,
80     Widgets_BorderRaised,
81     Widgets_BorderSunken,
82     Widgets_BorderDouble,
83     Widgets_BorderDefault,
84 
85     Widgets_GlobalBusyCursor,
86     Widgets_BusyCursor,
87 
88     Widgets_GoToPage,
89     Widgets_GoToPageLast = Widgets_GoToPage + 100
90 };
91 
92 const wxChar *WidgetsCategories[MAX_PAGES] = {
93 #if defined(__WXUNIVERSAL__)
94     wxT("Universal"),
95 #else
96     wxT("Native"),
97 #endif
98     wxT("Generic"),
99     wxT("Pickers"),
100     wxT("Comboboxes"),
101     wxT("With items"),
102     wxT("Editable"),
103     wxT("Books"),
104     wxT("All controls")
105 };
106 
107 // ----------------------------------------------------------------------------
108 // our classes
109 // ----------------------------------------------------------------------------
110 
111 // Define a new application type, each program should derive a class from wxApp
112 class WidgetsApp : public wxApp
113 {
114 public:
115     // override base class virtuals
116     // ----------------------------
117 
118     // this one is called on application startup and is a good place for the app
119     // initialization (doing it here and not in the ctor allows to have an error
120     // return: if OnInit() returns false, the application terminates)
121     virtual bool OnInit();
122 };
123 
124 // Define a new frame type: this is going to be our main frame
125 class WidgetsFrame : public wxFrame
126 {
127 public:
128     // ctor(s) and dtor
129     WidgetsFrame(const wxString& title);
130     virtual ~WidgetsFrame();
131 
132 protected:
133     // event handlers
134 #if USE_LOG
135     void OnButtonClearLog(wxCommandEvent& event);
136 #endif // USE_LOG
137     void OnExit(wxCommandEvent& event);
138 
139 #if wxUSE_MENUS
140     void OnPageChanging(WidgetsBookCtrlEvent& event);
141     void OnPageChanged(WidgetsBookCtrlEvent& event);
142     void OnGoToPage(wxCommandEvent& event);
143 
144 #if wxUSE_TOOLTIPS
145     void OnSetTooltip(wxCommandEvent& event);
146 #endif // wxUSE_TOOLTIPS
147     void OnSetFgCol(wxCommandEvent& event);
148     void OnSetBgCol(wxCommandEvent& event);
149     void OnSetFont(wxCommandEvent& event);
150     void OnEnable(wxCommandEvent& event);
151     void OnSetBorder(wxCommandEvent& event);
152 
153     void OnToggleGlobalBusyCursor(wxCommandEvent& event);
154     void OnToggleBusyCursor(wxCommandEvent& event);
155 #endif // wxUSE_MENUS
156 
157     // initialize the book: add all pages to it
158     void InitBook();
159 
160     // return the currently selected page (never NULL)
161     WidgetsPage *CurrentPage();
162 
163 private:
164     // the panel containing everything
165     wxPanel *m_panel;
166 
167 #if USE_LOG
168     // the listbox for logging messages
169     wxListBox *m_lboxLog;
170 
171     // the log target we use to redirect messages to the listbox
172     wxLog *m_logTarget;
173 #endif // USE_LOG
174 
175     // the book containing the test pages
176     WidgetsBookCtrl *m_book;
177 
178 #if wxUSE_MENUS
179     // last chosen fg/bg colours and font
180     wxColour m_colFg,
181              m_colBg;
182     wxFont   m_font;
183 #endif // wxUSE_MENUS
184 
185     // any class wishing to process wxWidgets events must use this macro
186     DECLARE_EVENT_TABLE()
187 };
188 
189 #if USE_LOG
190 // A log target which just redirects the messages to a listbox
191 class LboxLogger : public wxLog
192 {
193 public:
LboxLogger(wxListBox * lbox,wxLog * logOld)194     LboxLogger(wxListBox *lbox, wxLog *logOld)
195     {
196         m_lbox = lbox;
197         //m_lbox->Disable(); -- looks ugly under MSW
198         m_logOld = logOld;
199     }
200 
~LboxLogger()201     virtual ~LboxLogger()
202     {
203         wxLog::SetActiveTarget(m_logOld);
204     }
205 
206 private:
207     // implement sink functions
DoLog(wxLogLevel level,const wxChar * szString,time_t t)208     virtual void DoLog(wxLogLevel level, const wxChar *szString, time_t t)
209     {
210         // don't put trace messages into listbox or we can get into infinite
211         // recursion
212         if ( level == wxLOG_Trace )
213         {
214             if ( m_logOld )
215             {
216                 // cast is needed to call protected method
217                 ((LboxLogger *)m_logOld)->DoLog(level, szString, t);
218             }
219         }
220         else
221         {
222             wxLog::DoLog(level, szString, t);
223         }
224     }
225 
DoLogString(const wxChar * szString,time_t WXUNUSED (t))226     virtual void DoLogString(const wxChar *szString, time_t WXUNUSED(t))
227     {
228         wxString msg;
229         TimeStamp(&msg);
230         msg += szString;
231 
232         #ifdef __WXUNIVERSAL__
233             m_lbox->AppendAndEnsureVisible(msg);
234         #else // other ports don't have this method yet
235             m_lbox->Append(msg);
236             m_lbox->SetFirstItem(m_lbox->GetCount() - 1);
237         #endif
238     }
239 
240     // the control we use
241     wxListBox *m_lbox;
242 
243     // the old log target
244     wxLog *m_logOld;
245 };
246 #endif // USE_LOG
247 
248 // array of pages
249 WX_DEFINE_ARRAY_PTR(WidgetsPage *, ArrayWidgetsPage);
250 
251 // ----------------------------------------------------------------------------
252 // misc macros
253 // ----------------------------------------------------------------------------
254 
255 IMPLEMENT_APP(WidgetsApp)
256 
257 // ----------------------------------------------------------------------------
258 // event tables
259 // ----------------------------------------------------------------------------
260 
BEGIN_EVENT_TABLE(WidgetsFrame,wxFrame)261 BEGIN_EVENT_TABLE(WidgetsFrame, wxFrame)
262 #if USE_LOG
263     EVT_BUTTON(Widgets_ClearLog, WidgetsFrame::OnButtonClearLog)
264 #endif // USE_LOG
265     EVT_BUTTON(Widgets_Quit, WidgetsFrame::OnExit)
266 
267 #if wxUSE_TOOLTIPS
268     EVT_MENU(Widgets_SetTooltip, WidgetsFrame::OnSetTooltip)
269 #endif // wxUSE_TOOLTIPS
270 
271 #if wxUSE_MENUS
272     EVT_WIDGETS_PAGE_CHANGING(wxID_ANY, WidgetsFrame::OnPageChanging)
273     EVT_MENU_RANGE(Widgets_GoToPage, Widgets_GoToPageLast,
274                    WidgetsFrame::OnGoToPage)
275 
276     EVT_MENU(Widgets_SetFgColour, WidgetsFrame::OnSetFgCol)
277     EVT_MENU(Widgets_SetBgColour, WidgetsFrame::OnSetBgCol)
278     EVT_MENU(Widgets_SetFont,     WidgetsFrame::OnSetFont)
279     EVT_MENU(Widgets_Enable,      WidgetsFrame::OnEnable)
280 
281     EVT_MENU_RANGE(Widgets_BorderNone, Widgets_BorderDefault,
282                    WidgetsFrame::OnSetBorder)
283 
284     EVT_MENU(Widgets_GlobalBusyCursor,  WidgetsFrame::OnToggleGlobalBusyCursor)
285     EVT_MENU(Widgets_BusyCursor,        WidgetsFrame::OnToggleBusyCursor)
286 
287     EVT_MENU(wxID_EXIT, WidgetsFrame::OnExit)
288 #endif // wxUSE_MENUS
289 END_EVENT_TABLE()
290 
291 // ============================================================================
292 // implementation
293 // ============================================================================
294 
295 // ----------------------------------------------------------------------------
296 // app class
297 // ----------------------------------------------------------------------------
298 
299 bool WidgetsApp::OnInit()
300 {
301     if ( !wxApp::OnInit() )
302         return false;
303 
304     // the reason for having these ifdef's is that I often run two copies of
305     // this sample side by side and it is useful to see which one is which
306     wxString title;
307 #if defined(__WXUNIVERSAL__)
308     title = _T("wxUniv/");
309 #endif
310 
311 #if defined(__WXMSW__)
312     title += _T("wxMSW");
313 #elif defined(__WXGTK__)
314     title += _T("wxGTK");
315 #elif defined(__WXMAC__)
316     title += _T("wxMAC");
317 #elif defined(__WXMOTIF__)
318     title += _T("wxMOTIF");
319 #else
320     title += _T("wxWidgets");
321 #endif
322 
323     wxFrame *frame = new WidgetsFrame(title + _T(" widgets demo"));
324     frame->Show();
325 
326     //wxLog::AddTraceMask(_T("listbox"));
327     //wxLog::AddTraceMask(_T("scrollbar"));
328     //wxLog::AddTraceMask(_T("focus"));
329 
330     return true;
331 }
332 
333 // ----------------------------------------------------------------------------
334 // WidgetsFrame construction
335 // ----------------------------------------------------------------------------
336 
WidgetsFrame(const wxString & title)337 WidgetsFrame::WidgetsFrame(const wxString& title)
338             : wxFrame(NULL, wxID_ANY, title)
339 {
340     // set the frame icon
341     SetIcon(wxICON(sample));
342 
343     // init everything
344 #if USE_LOG
345     m_lboxLog = (wxListBox *)NULL;
346     m_logTarget = (wxLog *)NULL;
347 #endif // USE_LOG
348     m_book = (WidgetsBookCtrl *)NULL;
349 
350 #if wxUSE_MENUS
351     // create the menubar
352     wxMenuBar *mbar = new wxMenuBar;
353     wxMenu *menuWidget = new wxMenu;
354 #if wxUSE_TOOLTIPS
355     menuWidget->Append(Widgets_SetTooltip, _T("Set &tooltip...\tCtrl-T"));
356     menuWidget->AppendSeparator();
357 #endif // wxUSE_TOOLTIPS
358     menuWidget->Append(Widgets_SetFgColour, _T("Set &foreground...\tCtrl-F"));
359     menuWidget->Append(Widgets_SetBgColour, _T("Set &background...\tCtrl-B"));
360     menuWidget->Append(Widgets_SetFont,     _T("Set f&ont...\tCtrl-O"));
361     menuWidget->AppendCheckItem(Widgets_Enable,  _T("&Enable/disable\tCtrl-E"));
362 
363     wxMenu *menuBorders = new wxMenu;
364     menuBorders->AppendRadioItem(Widgets_BorderDefault, _T("De&fault\tCtrl-Shift-9"));
365     menuBorders->AppendRadioItem(Widgets_BorderNone,   _T("&None\tCtrl-Shift-0"));
366     menuBorders->AppendRadioItem(Widgets_BorderSimple, _T("&Simple\tCtrl-Shift-1"));
367     menuBorders->AppendRadioItem(Widgets_BorderDouble, _T("&Double\tCtrl-Shift-2"));
368     menuBorders->AppendRadioItem(Widgets_BorderStatic, _T("Stati&c\tCtrl-Shift-3"));
369     menuBorders->AppendRadioItem(Widgets_BorderRaised, _T("&Raised\tCtrl-Shift-4"));
370     menuBorders->AppendRadioItem(Widgets_BorderSunken, _T("S&unken\tCtrl-Shift-5"));
371     menuWidget->AppendSubMenu(menuBorders, _T("Set &border"));
372 
373     menuWidget->AppendSeparator();
374     menuWidget->AppendCheckItem(Widgets_GlobalBusyCursor,
375                                 _T("Toggle &global busy cursor\tCtrl-Shift-U"));
376     menuWidget->AppendCheckItem(Widgets_BusyCursor,
377                                 _T("Toggle b&usy cursor\tCtrl-U"));
378 
379     menuWidget->AppendSeparator();
380     menuWidget->Append(wxID_EXIT, _T("&Quit\tCtrl-Q"));
381     mbar->Append(menuWidget, _T("&Widget"));
382     SetMenuBar(mbar);
383 
384     mbar->Check(Widgets_Enable, true);
385 #endif // wxUSE_MENUS
386 
387     // create controls
388     m_panel = new wxPanel(this, wxID_ANY);
389 
390     wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
391 
392     // we have 2 panes: book with pages demonstrating the controls in the
393     // upper one and the log window with some buttons in the lower
394 
395     int style = wxBK_DEFAULT;
396     // Uncomment to suppress page theme (draw in solid colour)
397     //style |= wxNB_NOPAGETHEME;
398 
399     m_book = new WidgetsBookCtrl(m_panel, Widgets_BookCtrl, wxDefaultPosition,
400 #ifdef __WXMOTIF__
401         wxSize(500, wxDefaultCoord), // under Motif, height is a function of the width...
402 #else
403         wxDefaultSize,
404 #endif
405         style);
406     InitBook();
407 
408 #ifndef __WXHANDHELD__
409     // the lower one only has the log listbox and a button to clear it
410 #if USE_LOG
411     wxSizer *sizerDown = new wxStaticBoxSizer(
412         new wxStaticBox( m_panel, wxID_ANY, _T("&Log window") ),
413         wxVERTICAL);
414 
415     m_lboxLog = new wxListBox(m_panel, wxID_ANY);
416     sizerDown->Add(m_lboxLog, 1, wxGROW | wxALL, 5);
417     sizerDown->SetMinSize(100, 150);
418 #else
419     wxSizer *sizerDown = new wxBoxSizer(wxVERTICAL);
420 #endif // USE_LOG
421 
422     wxBoxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
423     wxButton *btn;
424 #if USE_LOG
425     btn = new wxButton(m_panel, Widgets_ClearLog, _T("Clear &log"));
426     sizerBtns->Add(btn);
427     sizerBtns->Add(10, 0); // spacer
428 #endif // USE_LOG
429     btn = new wxButton(m_panel, Widgets_Quit, _T("E&xit"));
430     sizerBtns->Add(btn);
431     sizerDown->Add(sizerBtns, 0, wxALL | wxALIGN_RIGHT, 5);
432 
433     // put everything together
434     sizerTop->Add(m_book, 1, wxGROW | (wxALL & ~(wxTOP | wxBOTTOM)), 10);
435     sizerTop->Add(0, 5, 0, wxGROW); // spacer in between
436     sizerTop->Add(sizerDown, 0,  wxGROW | (wxALL & ~wxTOP), 10);
437 
438 #else // !__WXHANDHELD__/__WXHANDHELD__
439 
440     sizerTop->Add(m_book, 1, wxGROW | wxALL );
441 
442 #endif // __WXHANDHELD__
443 
444     m_panel->SetSizer(sizerTop);
445 
446     sizerTop->Fit(this);
447     sizerTop->SetSizeHints(this);
448 
449 #if USE_LOG && !defined(__WXCOCOA__)
450     // wxCocoa's listbox is too flakey to use for logging right now
451     // now that everything is created we can redirect the log messages to the
452     // listbox
453     m_logTarget = new LboxLogger(m_lboxLog, wxLog::GetActiveTarget());
454     wxLog::SetActiveTarget(m_logTarget);
455 #endif
456 }
457 
InitBook()458 void WidgetsFrame::InitBook()
459 {
460 #if USE_ICONS_IN_BOOK
461     wxImageList *imageList = new wxImageList(32, 32);
462 
463     imageList->Add(wxBitmap(sample_xpm));
464 #else
465     wxImageList *imageList = NULL;
466 #endif
467 
468 #if !USE_TREEBOOK
469     WidgetsBookCtrl *books[MAX_PAGES];
470 #endif
471 
472     ArrayWidgetsPage pages[MAX_PAGES];
473     wxArrayString labels[MAX_PAGES];
474 
475     wxMenu *menuPages = new wxMenu;
476     unsigned int nPage = 0, nFKey = 0;
477     int cat, imageId = 1;
478 
479     // we need to first create all pages and only then add them to the book
480     // as we need the image list first
481     //
482     // we also construct the pages menu during this first iteration
483     for ( cat = 0; cat < MAX_PAGES; cat++ )
484     {
485 #if USE_TREEBOOK
486         nPage++; // increase for parent page
487 #else
488         books[cat] = new WidgetsBookCtrl(m_book,
489                                          wxID_ANY,
490                                          wxDefaultPosition,
491                                          wxDefaultSize,
492                                          wxBK_DEFAULT);
493 #endif
494 
495         for ( WidgetsPageInfo *info = WidgetsPage::ms_widgetPages;
496               info;
497               info = info->GetNext() )
498         {
499             if( (info->GetCategories() & ( 1 << cat )) == 0)
500                 continue;
501 
502             WidgetsPage *page = (*info->GetCtor())(
503 #if USE_TREEBOOK
504                                  m_book
505 #else
506                                  books[cat]
507 #endif
508                                  , imageList);
509             pages[cat].Add(page);
510 
511             labels[cat].Add(info->GetLabel());
512             if ( cat == ALL_PAGE )
513             {
514                 wxString radioLabel(info->GetLabel());
515                 nFKey++;
516                 if ( nFKey <= 12 )
517                 {
518                     radioLabel << wxT("\tF" ) << nFKey;
519                 }
520 
521                 menuPages->AppendRadioItem(
522                             Widgets_GoToPage + nPage,
523                             radioLabel
524                            );
525 #if !USE_TREEBOOK
526                 // consider only for book in book architecture
527                 nPage++;
528 #endif
529             }
530 
531 #if USE_TREEBOOK
532             // consider only for treebook architecture (with subpages)
533             nPage++;
534 #endif
535         }
536     }
537 
538     GetMenuBar()->Append(menuPages, _T("&Page"));
539 
540 #if USE_ICONS_IN_BOOK
541     m_book->AssignImageList(imageList);
542 #endif
543 
544     for ( cat = 0; cat < MAX_PAGES; cat++ )
545     {
546 #if USE_TREEBOOK
547         m_book->AddPage(NULL,WidgetsCategories[cat],false,0);
548 #else
549         m_book->AddPage(books[cat],WidgetsCategories[cat],false,0);
550 #if USE_ICONS_IN_BOOK
551         books[cat]->SetImageList(imageList);
552 #endif
553 #endif
554 
555         // now do add them
556         size_t count = pages[cat].GetCount();
557         for ( size_t n = 0; n < count; n++ )
558         {
559 #if USE_TREEBOOK
560             m_book->AddSubPage
561 #else
562             books[cat]->AddPage
563 #endif
564                            (
565                             pages[cat][n],
566                             labels[cat][n],
567                             false, // don't select
568                             imageId++
569                            );
570         }
571     }
572 
573     Connect( wxID_ANY,
574              wxEVT_COMMAND_WIDGETS_PAGE_CHANGED,
575              wxWidgetsbookEventHandler(WidgetsFrame::OnPageChanged) );
576 
577 #if USE_TREEBOOK
578     // for treebook page #0 is empty parent page only so select the first page
579     // with some contents
580     m_book->SetSelection(1);
581 
582     // but ensure that the top of the tree is shown nevertheless
583     wxTreeCtrl * const tree = m_book->GetTreeCtrl();
584 
585     wxTreeItemIdValue cookie;
586     tree->EnsureVisible(tree->GetFirstChild(tree->GetRootItem(), cookie));
587 #else
588     // for other books set selection twice to force connected event handler
589     // to force lazy creation of initial visible content
590     m_book->SetSelection(1);
591     m_book->SetSelection(0);
592 #endif // USE_TREEBOOK
593 }
594 
CurrentPage()595 WidgetsPage *WidgetsFrame::CurrentPage()
596 {
597     wxWindow *page = m_book->GetCurrentPage();
598 
599 #if !USE_TREEBOOK
600     WidgetsBookCtrl *subBook = wxStaticCast(page, WidgetsBookCtrl);
601     wxCHECK_MSG( subBook, NULL, _T("no WidgetsBookCtrl?") );
602 
603     page = subBook->GetCurrentPage();
604 #endif // !USE_TREEBOOK
605 
606     return wxStaticCast(page, WidgetsPage);
607 }
608 
~WidgetsFrame()609 WidgetsFrame::~WidgetsFrame()
610 {
611 #if USE_LOG
612     delete m_logTarget;
613 #endif // USE_LOG
614 }
615 
616 // ----------------------------------------------------------------------------
617 // WidgetsFrame event handlers
618 // ----------------------------------------------------------------------------
619 
OnExit(wxCommandEvent & WXUNUSED (event))620 void WidgetsFrame::OnExit(wxCommandEvent& WXUNUSED(event))
621 {
622     Close();
623 }
624 
625 #if USE_LOG
OnButtonClearLog(wxCommandEvent & WXUNUSED (event))626 void WidgetsFrame::OnButtonClearLog(wxCommandEvent& WXUNUSED(event))
627 {
628     m_lboxLog->Clear();
629 }
630 #endif // USE_LOG
631 
632 #if wxUSE_MENUS
633 
OnPageChanging(WidgetsBookCtrlEvent & event)634 void WidgetsFrame::OnPageChanging(WidgetsBookCtrlEvent& event)
635 {
636 #if USE_TREEBOOK
637     // don't allow selection of entries without pages (categories)
638     if ( !m_book->GetPage(event.GetSelection()) )
639         event.Veto();
640 #else
641     wxUnusedVar(event);
642 #endif
643 }
644 
OnPageChanged(WidgetsBookCtrlEvent & event)645 void WidgetsFrame::OnPageChanged(WidgetsBookCtrlEvent& event)
646 {
647     const int sel = event.GetSelection();
648 
649     // adjust "Page" menu selection
650     wxMenuItem *item = GetMenuBar()->FindItem(Widgets_GoToPage + sel);
651     if ( item )
652         item->Check();
653 
654     GetMenuBar()->Check(Widgets_BusyCursor, false);
655 
656     // create the pages on demand, otherwise the sample startup is too slow as
657     // it creates hundreds of controls
658     WidgetsPage *page = CurrentPage();
659     if ( page->GetChildren().empty() )
660     {
661         wxWindowUpdateLocker noUpdates(page);
662         page->CreateContent();
663         //page->Layout();
664         page->GetSizer()->Fit(page);
665 
666         WidgetsBookCtrl *book = wxStaticCast(page->GetParent(), WidgetsBookCtrl);
667         wxSize size;
668         for ( size_t i = 0; i < book->GetPageCount(); ++i )
669         {
670             wxWindow *page = book->GetPage(i);
671             if ( page )
672             {
673                 size.IncTo(page->GetSize());
674             }
675         }
676         page->SetSize(size);
677     }
678 
679     event.Skip();
680 }
681 
OnGoToPage(wxCommandEvent & event)682 void WidgetsFrame::OnGoToPage(wxCommandEvent& event)
683 {
684 #if USE_TREEBOOK
685     m_book->SetSelection(event.GetId() - Widgets_GoToPage);
686 #else
687     m_book->SetSelection(m_book->GetPageCount()-1);
688     WidgetsBookCtrl *book = wxStaticCast(m_book->GetCurrentPage(), WidgetsBookCtrl);
689     book->SetSelection(event.GetId() - Widgets_GoToPage);
690 #endif
691 }
692 
693 #if wxUSE_TOOLTIPS
694 
OnSetTooltip(wxCommandEvent & WXUNUSED (event))695 void WidgetsFrame::OnSetTooltip(wxCommandEvent& WXUNUSED(event))
696 {
697     static wxString s_tip = _T("This is a tooltip");
698 
699     wxTextEntryDialog dialog
700                       (
701                         this,
702                         _T("Tooltip text (may use \\n, leave empty to remove): "),
703                         _T("Widgets sample"),
704                         s_tip
705                       );
706 
707     if ( dialog.ShowModal() != wxID_OK )
708         return;
709 
710     s_tip = dialog.GetValue();
711     s_tip.Replace(_T("\\n"), _T("\n"));
712 
713     WidgetsPage *page = CurrentPage();
714 
715     page->GetWidget()->SetToolTip(s_tip);
716 
717     wxControl *ctrl2 = page->GetWidget2();
718     if ( ctrl2 )
719         ctrl2->SetToolTip(s_tip);
720 }
721 
722 #endif // wxUSE_TOOLTIPS
723 
OnSetFgCol(wxCommandEvent & WXUNUSED (event))724 void WidgetsFrame::OnSetFgCol(wxCommandEvent& WXUNUSED(event))
725 {
726 #if wxUSE_COLOURDLG
727     // allow for debugging the default colour the first time this is called
728     WidgetsPage *page = CurrentPage();
729 
730     if (!m_colFg.Ok())
731         m_colFg = page->GetForegroundColour();
732 
733     wxColour col = wxGetColourFromUser(this, m_colFg);
734     if ( !col.Ok() )
735         return;
736 
737     m_colFg = col;
738 
739     page->GetWidget()->SetForegroundColour(m_colFg);
740     page->GetWidget()->Refresh();
741 
742     wxControl *ctrl2 = page->GetWidget2();
743     if ( ctrl2 )
744     {
745         ctrl2->SetForegroundColour(m_colFg);
746         ctrl2->Refresh();
747     }
748 #else
749     wxLogMessage(_T("Colour selection dialog not available in current build."));
750 #endif
751 }
752 
OnSetBgCol(wxCommandEvent & WXUNUSED (event))753 void WidgetsFrame::OnSetBgCol(wxCommandEvent& WXUNUSED(event))
754 {
755 #if wxUSE_COLOURDLG
756     WidgetsPage *page = CurrentPage();
757 
758     if ( !m_colBg.Ok() )
759         m_colBg = page->GetBackgroundColour();
760 
761     wxColour col = wxGetColourFromUser(this, m_colBg);
762     if ( !col.Ok() )
763         return;
764 
765     m_colBg = col;
766 
767     page->GetWidget()->SetBackgroundColour(m_colBg);
768     page->GetWidget()->Refresh();
769 
770     wxControl *ctrl2 = page->GetWidget2();
771     if ( ctrl2 )
772     {
773         ctrl2->SetBackgroundColour(m_colFg);
774         ctrl2->Refresh();
775     }
776 #else
777     wxLogMessage(_T("Colour selection dialog not available in current build."));
778 #endif
779 }
780 
OnSetFont(wxCommandEvent & WXUNUSED (event))781 void WidgetsFrame::OnSetFont(wxCommandEvent& WXUNUSED(event))
782 {
783 #if wxUSE_FONTDLG
784     WidgetsPage *page = CurrentPage();
785 
786     if (!m_font.Ok())
787         m_font = page->GetFont();
788 
789     wxFont font = wxGetFontFromUser(this, m_font);
790     if ( !font.Ok() )
791         return;
792 
793     m_font = font;
794 
795     page->GetWidget()->SetFont(m_font);
796     page->GetWidget()->Refresh();
797 
798     wxControl *ctrl2 = page->GetWidget2();
799     if ( ctrl2 )
800     {
801         ctrl2->SetFont(m_font);
802         ctrl2->Refresh();
803     }
804 #else
805     wxLogMessage(_T("Font selection dialog not available in current build."));
806 #endif
807 }
808 
OnEnable(wxCommandEvent & event)809 void WidgetsFrame::OnEnable(wxCommandEvent& event)
810 {
811     CurrentPage()->GetWidget()->Enable(event.IsChecked());
812     if (CurrentPage()->GetWidget2())
813         CurrentPage()->GetWidget2()->Enable(event.IsChecked());
814 }
815 
OnSetBorder(wxCommandEvent & event)816 void WidgetsFrame::OnSetBorder(wxCommandEvent& event)
817 {
818     int border;
819     switch ( event.GetId() )
820     {
821         case Widgets_BorderNone:   border = wxBORDER_NONE;   break;
822         case Widgets_BorderStatic: border = wxBORDER_STATIC; break;
823         case Widgets_BorderSimple: border = wxBORDER_SIMPLE; break;
824         case Widgets_BorderRaised: border = wxBORDER_RAISED; break;
825         case Widgets_BorderSunken: border = wxBORDER_SUNKEN; break;
826         case Widgets_BorderDouble: border = wxBORDER_DOUBLE; break;
827 
828         default:
829             wxFAIL_MSG( _T("unknown border style") );
830             // fall through
831 
832         case Widgets_BorderDefault: border = wxBORDER_DEFAULT; break;
833     }
834 
835     WidgetsPage::ms_defaultFlags &= ~wxBORDER_MASK;
836     WidgetsPage::ms_defaultFlags |= border;
837 
838     WidgetsPage *page = CurrentPage();
839 
840     page->RecreateWidget();
841 }
842 
OnToggleGlobalBusyCursor(wxCommandEvent & event)843 void WidgetsFrame::OnToggleGlobalBusyCursor(wxCommandEvent& event)
844 {
845     if ( event.IsChecked() )
846         wxBeginBusyCursor();
847     else
848         wxEndBusyCursor();
849 }
850 
OnToggleBusyCursor(wxCommandEvent & event)851 void WidgetsFrame::OnToggleBusyCursor(wxCommandEvent& event)
852 {
853     CurrentPage()->GetWidget()->SetCursor(*(event.IsChecked()
854                                                 ? wxHOURGLASS_CURSOR
855                                                 : wxSTANDARD_CURSOR));
856 }
857 
858 #endif // wxUSE_MENUS
859 
860 // ----------------------------------------------------------------------------
861 // WidgetsPageInfo
862 // ----------------------------------------------------------------------------
863 
WidgetsPageInfo(Constructor ctor,const wxChar * label,int categories)864 WidgetsPageInfo::WidgetsPageInfo(Constructor ctor, const wxChar *label, int categories)
865                : m_label(label)
866                , m_categories(categories)
867 {
868     m_ctor = ctor;
869 
870     m_next = NULL;
871 
872     // dummy sorting: add and immediately sort in the list according to label
873     if ( WidgetsPage::ms_widgetPages )
874     {
875         WidgetsPageInfo *node_prev = WidgetsPage::ms_widgetPages;
876         if ( wxStrcmp(label, node_prev->GetLabel().c_str()) < 0 )
877         {
878             // add as first
879             m_next = node_prev;
880             WidgetsPage::ms_widgetPages = this;
881         }
882         else
883         {
884             WidgetsPageInfo *node_next;
885             do
886             {
887                 node_next = node_prev->GetNext();
888                 if ( node_next )
889                 {
890                     // add if between two
891                     if ( wxStrcmp(label, node_next->GetLabel().c_str()) < 0 )
892                     {
893                         node_prev->SetNext(this);
894                         m_next = node_next;
895                         // force to break loop
896                         node_next = NULL;
897                     }
898                 }
899                 else
900                 {
901                     // add as last
902                     node_prev->SetNext(this);
903                     m_next = node_next;
904                 }
905                 node_prev = node_next;
906             }
907             while ( node_next );
908         }
909     }
910     else
911     {
912         // add when first
913         WidgetsPage::ms_widgetPages = this;
914     }
915 }
916 
917 // ----------------------------------------------------------------------------
918 // WidgetsPage
919 // ----------------------------------------------------------------------------
920 
921 int WidgetsPage::ms_defaultFlags = wxBORDER_DEFAULT;
922 WidgetsPageInfo *WidgetsPage::ms_widgetPages = NULL;
923 
WidgetsPage(WidgetsBookCtrl * book,wxImageList * imaglist,const char * icon[])924 WidgetsPage::WidgetsPage(WidgetsBookCtrl *book,
925                          wxImageList *imaglist,
926                          const char* icon[])
927            : wxPanel(book, wxID_ANY,
928                      wxDefaultPosition, wxDefaultSize,
929                      wxNO_FULL_REPAINT_ON_RESIZE |
930                      wxCLIP_CHILDREN |
931                      wxTAB_TRAVERSAL)
932 {
933 #if USE_ICONS_IN_BOOK
934     imaglist->Add(wxBitmap(icon));
935 #else
936     wxUnusedVar(imaglist);
937     wxUnusedVar(icon);
938 #endif
939 }
940 
CreateSizerWithText(wxControl * control,wxWindowID id,wxTextCtrl ** ppText)941 wxSizer *WidgetsPage::CreateSizerWithText(wxControl *control,
942                                           wxWindowID id,
943                                           wxTextCtrl **ppText)
944 {
945     wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
946     wxTextCtrl *text = new wxTextCtrl(this, id, wxEmptyString,
947         wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
948 
949     sizerRow->Add(control, 0, wxRIGHT | wxALIGN_CENTRE_VERTICAL, 5);
950     sizerRow->Add(text, 1, wxLEFT | wxALIGN_CENTRE_VERTICAL, 5);
951 
952     if ( ppText )
953         *ppText = text;
954 
955     return sizerRow;
956 }
957 
958 // create a sizer containing a label and a text ctrl
CreateSizerWithTextAndLabel(const wxString & label,wxWindowID id,wxTextCtrl ** ppText)959 wxSizer *WidgetsPage::CreateSizerWithTextAndLabel(const wxString& label,
960                                                   wxWindowID id,
961                                                   wxTextCtrl **ppText)
962 {
963     return CreateSizerWithText(new wxStaticText(this, wxID_ANY, label),
964         id, ppText);
965 }
966 
967 // create a sizer containing a button and a text ctrl
CreateSizerWithTextAndButton(wxWindowID idBtn,const wxString & label,wxWindowID id,wxTextCtrl ** ppText)968 wxSizer *WidgetsPage::CreateSizerWithTextAndButton(wxWindowID idBtn,
969                                                    const wxString& label,
970                                                    wxWindowID id,
971                                                    wxTextCtrl **ppText)
972 {
973     return CreateSizerWithText(new wxButton(this, idBtn, label), id, ppText);
974 }
975 
CreateCheckBoxAndAddToSizer(wxSizer * sizer,const wxString & label,wxWindowID id)976 wxCheckBox *WidgetsPage::CreateCheckBoxAndAddToSizer(wxSizer *sizer,
977                                                      const wxString& label,
978                                                      wxWindowID id)
979 {
980     wxCheckBox *checkbox = new wxCheckBox(this, id, label);
981     sizer->Add(checkbox, 0, wxLEFT | wxRIGHT, 5);
982     sizer->Add(0, 2, 0, wxGROW); // spacer
983 
984     return checkbox;
985 }
986