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
62enum
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
92const 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
112class WidgetsApp : public wxApp
113{
114public:
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
125class WidgetsFrame : public wxFrame
126{
127public:
128    // ctor(s) and dtor
129    WidgetsFrame(const wxString& title);
130    virtual ~WidgetsFrame();
131
132protected:
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
163private:
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
191class LboxLogger : public wxLog
192{
193public:
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
201    virtual ~LboxLogger()
202    {
203        wxLog::SetActiveTarget(m_logOld);
204    }
205
206private:
207    // implement sink functions
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
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
249WX_DEFINE_ARRAY_PTR(WidgetsPage *, ArrayWidgetsPage);
250
251// ----------------------------------------------------------------------------
252// misc macros
253// ----------------------------------------------------------------------------
254
255IMPLEMENT_APP(WidgetsApp)
256
257// ----------------------------------------------------------------------------
258// event tables
259// ----------------------------------------------------------------------------
260
261BEGIN_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
289END_EVENT_TABLE()
290
291// ============================================================================
292// implementation
293// ============================================================================
294
295// ----------------------------------------------------------------------------
296// app class
297// ----------------------------------------------------------------------------
298
299bool 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
337WidgetsFrame::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
458void 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
595WidgetsPage *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
609WidgetsFrame::~WidgetsFrame()
610{
611#if USE_LOG
612    delete m_logTarget;
613#endif // USE_LOG
614}
615
616// ----------------------------------------------------------------------------
617// WidgetsFrame event handlers
618// ----------------------------------------------------------------------------
619
620void WidgetsFrame::OnExit(wxCommandEvent& WXUNUSED(event))
621{
622    Close();
623}
624
625#if USE_LOG
626void WidgetsFrame::OnButtonClearLog(wxCommandEvent& WXUNUSED(event))
627{
628    m_lboxLog->Clear();
629}
630#endif // USE_LOG
631
632#if wxUSE_MENUS
633
634void 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
645void 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
682void 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
695void 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
724void 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
753void 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
781void 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
809void WidgetsFrame::OnEnable(wxCommandEvent& event)
810{
811    CurrentPage()->GetWidget()->Enable(event.IsChecked());
812    if (CurrentPage()->GetWidget2())
813        CurrentPage()->GetWidget2()->Enable(event.IsChecked());
814}
815
816void 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
843void WidgetsFrame::OnToggleGlobalBusyCursor(wxCommandEvent& event)
844{
845    if ( event.IsChecked() )
846        wxBeginBusyCursor();
847    else
848        wxEndBusyCursor();
849}
850
851void 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
864WidgetsPageInfo::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
921int WidgetsPage::ms_defaultFlags = wxBORDER_DEFAULT;
922WidgetsPageInfo *WidgetsPage::ms_widgetPages = NULL;
923
924WidgetsPage::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
941wxSizer *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
959wxSizer *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
968wxSizer *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
976wxCheckBox *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