wxWidgets/samples/widgets/widgets.cpp
Vadim Zeitlin 40aa1a7e60 Implement GetSizeFromTextSize() for wxSpinCtrl.
Implement it for the native MSW and GTK versions and the generic one used in
the other ports and also for wxSpinCtrlDouble under MSW.

Also test this function in the spin page of the widgets sample.

Closes #14840.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72995 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2012-11-20 12:49:53 +00:00

1275 lines
37 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Program: wxWidgets Widgets Sample
// Name: samples/widgets/widgets.cpp
// Purpose: Sample showing most of the simple wxWidgets widgets
// Author: Vadim Zeitlin
// Created: 27.03.01
// Id: $Id$
// Copyright: (c) 2001 Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// for compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/log.h"
#include "wx/frame.h"
#include "wx/menu.h"
#include "wx/image.h"
#include "wx/button.h"
#include "wx/checkbox.h"
#include "wx/listbox.h"
#include "wx/statbox.h"
#include "wx/stattext.h"
#include "wx/textctrl.h"
#include "wx/msgdlg.h"
#endif
#include "wx/sysopt.h"
#include "wx/bookctrl.h"
#include "wx/treebook.h"
#include "wx/sizer.h"
#include "wx/colordlg.h"
#include "wx/fontdlg.h"
#include "wx/textdlg.h"
#include "wx/imaglist.h"
#include "wx/wupdlock.h"
#include "wx/textcompleter.h"
#include "wx/persist/toplevel.h"
#include "wx/persist/treebook.h"
#include "widgets.h"
#include "../sample.xpm"
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// control ids
enum
{
Widgets_ClearLog = 100,
Widgets_Quit,
Widgets_BookCtrl,
#if wxUSE_TOOLTIPS
Widgets_SetTooltip,
#endif // wxUSE_TOOLTIPS
Widgets_SetFgColour,
Widgets_SetBgColour,
Widgets_SetPageBg,
Widgets_SetFont,
Widgets_Enable,
Widgets_BorderNone,
Widgets_BorderStatic,
Widgets_BorderSimple,
Widgets_BorderRaised,
Widgets_BorderSunken,
Widgets_BorderDouble,
Widgets_BorderDefault,
Widgets_GlobalBusyCursor,
Widgets_BusyCursor,
Widgets_GoToPage,
Widgets_GoToPageLast = Widgets_GoToPage + 100,
TextEntry_Begin,
TextEntry_DisableAutoComplete = TextEntry_Begin,
TextEntry_AutoCompleteFixed,
TextEntry_AutoCompleteFilenames,
TextEntry_AutoCompleteDirectories,
TextEntry_AutoCompleteCustom,
TextEntry_SetHint,
TextEntry_End
};
const wxChar *WidgetsCategories[MAX_PAGES] = {
#if defined(__WXUNIVERSAL__)
wxT("Universal"),
#else
wxT("Native"),
#endif
wxT("Generic"),
wxT("Pickers"),
wxT("Comboboxes"),
wxT("With items"),
wxT("Editable"),
wxT("Books"),
wxT("All controls")
};
// ----------------------------------------------------------------------------
// our classes
// ----------------------------------------------------------------------------
// Define a new application type, each program should derive a class from wxApp
class WidgetsApp : public wxApp
{
public:
// override base class virtuals
// ----------------------------
// this one is called on application startup and is a good place for the app
// initialization (doing it here and not in the ctor allows to have an error
// return: if OnInit() returns false, the application terminates)
virtual bool OnInit();
};
// Define a new frame type: this is going to be our main frame
class WidgetsFrame : public wxFrame
{
public:
// ctor(s) and dtor
WidgetsFrame(const wxString& title);
virtual ~WidgetsFrame();
protected:
// event handlers
#if USE_LOG
void OnButtonClearLog(wxCommandEvent& event);
#endif // USE_LOG
void OnExit(wxCommandEvent& event);
#if wxUSE_MENUS
void OnPageChanging(WidgetsBookCtrlEvent& event);
void OnPageChanged(WidgetsBookCtrlEvent& event);
void OnGoToPage(wxCommandEvent& event);
#if wxUSE_TOOLTIPS
void OnSetTooltip(wxCommandEvent& event);
#endif // wxUSE_TOOLTIPS
void OnSetFgCol(wxCommandEvent& event);
void OnSetBgCol(wxCommandEvent& event);
void OnSetPageBg(wxCommandEvent& event);
void OnSetFont(wxCommandEvent& event);
void OnEnable(wxCommandEvent& event);
void OnSetBorder(wxCommandEvent& event);
void OnToggleGlobalBusyCursor(wxCommandEvent& event);
void OnToggleBusyCursor(wxCommandEvent& event);
// wxTextEntry-specific tests
void OnDisableAutoComplete(wxCommandEvent& event);
void OnAutoCompleteFixed(wxCommandEvent& event);
void OnAutoCompleteFilenames(wxCommandEvent& event);
void OnAutoCompleteDirectories(wxCommandEvent& event);
void OnAutoCompleteCustom(wxCommandEvent& event);
void OnSetHint(wxCommandEvent& event);
void OnUpdateTextUI(wxUpdateUIEvent& event)
{
event.Enable( CurrentPage()->GetTextEntry() != NULL );
}
#endif // wxUSE_MENUS
// initialize the book: add all pages to it
void InitBook();
// return the currently selected page (never NULL)
WidgetsPage *CurrentPage();
private:
// the panel containing everything
wxPanel *m_panel;
#if USE_LOG
// the listbox for logging messages
wxListBox *m_lboxLog;
// the log target we use to redirect messages to the listbox
wxLog *m_logTarget;
#endif // USE_LOG
// the book containing the test pages
WidgetsBookCtrl *m_book;
#if wxUSE_MENUS
// last chosen fg/bg colours and font
wxColour m_colFg,
m_colBg;
wxFont m_font;
#endif // wxUSE_MENUS
// any class wishing to process wxWidgets events must use this macro
DECLARE_EVENT_TABLE()
};
#if USE_LOG
// A log target which just redirects the messages to a listbox
class LboxLogger : public wxLog
{
public:
LboxLogger(wxListBox *lbox, wxLog *logOld)
{
m_lbox = lbox;
//m_lbox->Disable(); -- looks ugly under MSW
m_logOld = logOld;
}
virtual ~LboxLogger()
{
wxLog::SetActiveTarget(m_logOld);
}
private:
// implement sink functions
virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
{
if ( level == wxLOG_Trace )
{
if ( m_logOld )
m_logOld->LogTextAtLevel(level, msg);
return;
}
#ifdef __WXUNIVERSAL__
m_lbox->AppendAndEnsureVisible(msg);
#else // other ports don't have this method yet
m_lbox->Append(msg);
m_lbox->SetFirstItem(m_lbox->GetCount() - 1);
#endif
}
// the control we use
wxListBox *m_lbox;
// the old log target
wxLog *m_logOld;
};
#endif // USE_LOG
// array of pages
WX_DEFINE_ARRAY_PTR(WidgetsPage *, ArrayWidgetsPage);
// ----------------------------------------------------------------------------
// misc macros
// ----------------------------------------------------------------------------
IMPLEMENT_APP(WidgetsApp)
// ----------------------------------------------------------------------------
// event tables
// ----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(WidgetsFrame, wxFrame)
#if USE_LOG
EVT_BUTTON(Widgets_ClearLog, WidgetsFrame::OnButtonClearLog)
#endif // USE_LOG
EVT_BUTTON(Widgets_Quit, WidgetsFrame::OnExit)
#if wxUSE_TOOLTIPS
EVT_MENU(Widgets_SetTooltip, WidgetsFrame::OnSetTooltip)
#endif // wxUSE_TOOLTIPS
#if wxUSE_MENUS
EVT_WIDGETS_PAGE_CHANGING(wxID_ANY, WidgetsFrame::OnPageChanging)
EVT_MENU_RANGE(Widgets_GoToPage, Widgets_GoToPageLast,
WidgetsFrame::OnGoToPage)
EVT_MENU(Widgets_SetFgColour, WidgetsFrame::OnSetFgCol)
EVT_MENU(Widgets_SetBgColour, WidgetsFrame::OnSetBgCol)
EVT_MENU(Widgets_SetPageBg, WidgetsFrame::OnSetPageBg)
EVT_MENU(Widgets_SetFont, WidgetsFrame::OnSetFont)
EVT_MENU(Widgets_Enable, WidgetsFrame::OnEnable)
EVT_MENU_RANGE(Widgets_BorderNone, Widgets_BorderDefault,
WidgetsFrame::OnSetBorder)
EVT_MENU(Widgets_GlobalBusyCursor, WidgetsFrame::OnToggleGlobalBusyCursor)
EVT_MENU(Widgets_BusyCursor, WidgetsFrame::OnToggleBusyCursor)
EVT_MENU(TextEntry_DisableAutoComplete, WidgetsFrame::OnDisableAutoComplete)
EVT_MENU(TextEntry_AutoCompleteFixed, WidgetsFrame::OnAutoCompleteFixed)
EVT_MENU(TextEntry_AutoCompleteFilenames, WidgetsFrame::OnAutoCompleteFilenames)
EVT_MENU(TextEntry_AutoCompleteDirectories, WidgetsFrame::OnAutoCompleteDirectories)
EVT_MENU(TextEntry_AutoCompleteCustom, WidgetsFrame::OnAutoCompleteCustom)
EVT_MENU(TextEntry_SetHint, WidgetsFrame::OnSetHint)
EVT_UPDATE_UI_RANGE(TextEntry_Begin, TextEntry_End - 1,
WidgetsFrame::OnUpdateTextUI)
EVT_MENU(wxID_EXIT, WidgetsFrame::OnExit)
#endif // wxUSE_MENUS
END_EVENT_TABLE()
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// app class
// ----------------------------------------------------------------------------
bool WidgetsApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
SetVendorName("wxWidgets_Samples");
// the reason for having these ifdef's is that I often run two copies of
// this sample side by side and it is useful to see which one is which
wxString title;
#if defined(__WXUNIVERSAL__)
title = wxT("wxUniv/");
#endif
#if defined(__WXMSW__)
title += wxT("wxMSW");
#elif defined(__WXGTK__)
title += wxT("wxGTK");
#elif defined(__WXMAC__)
title += wxT("wxMAC");
#elif defined(__WXMOTIF__)
title += wxT("wxMOTIF");
#else
title += wxT("wxWidgets");
#endif
wxFrame *frame = new WidgetsFrame(title + wxT(" widgets demo"));
frame->Show();
return true;
}
// ----------------------------------------------------------------------------
// WidgetsFrame construction
// ----------------------------------------------------------------------------
WidgetsFrame::WidgetsFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title)
{
const bool sizeSet = wxPersistentRegisterAndRestore(this, "Main");
// set the frame icon
SetIcon(wxICON(sample));
// init everything
#if USE_LOG
m_lboxLog = NULL;
m_logTarget = NULL;
#endif // USE_LOG
m_book = NULL;
#if wxUSE_MENUS
// create the menubar
wxMenuBar *mbar = new wxMenuBar;
wxMenu *menuWidget = new wxMenu;
#if wxUSE_TOOLTIPS
menuWidget->Append(Widgets_SetTooltip, wxT("Set &tooltip...\tCtrl-T"));
menuWidget->AppendSeparator();
#endif // wxUSE_TOOLTIPS
menuWidget->Append(Widgets_SetFgColour, wxT("Set &foreground...\tCtrl-F"));
menuWidget->Append(Widgets_SetBgColour, wxT("Set &background...\tCtrl-B"));
menuWidget->Append(Widgets_SetPageBg, wxT("Set &page background...\tShift-Ctrl-B"));
menuWidget->Append(Widgets_SetFont, wxT("Set f&ont...\tCtrl-O"));
menuWidget->AppendCheckItem(Widgets_Enable, wxT("&Enable/disable\tCtrl-E"));
wxMenu *menuBorders = new wxMenu;
menuBorders->AppendRadioItem(Widgets_BorderDefault, wxT("De&fault\tCtrl-Shift-9"));
menuBorders->AppendRadioItem(Widgets_BorderNone, wxT("&None\tCtrl-Shift-0"));
menuBorders->AppendRadioItem(Widgets_BorderSimple, wxT("&Simple\tCtrl-Shift-1"));
menuBorders->AppendRadioItem(Widgets_BorderDouble, wxT("&Double\tCtrl-Shift-2"));
menuBorders->AppendRadioItem(Widgets_BorderStatic, wxT("Stati&c\tCtrl-Shift-3"));
menuBorders->AppendRadioItem(Widgets_BorderRaised, wxT("&Raised\tCtrl-Shift-4"));
menuBorders->AppendRadioItem(Widgets_BorderSunken, wxT("S&unken\tCtrl-Shift-5"));
menuWidget->AppendSubMenu(menuBorders, wxT("Set &border"));
menuWidget->AppendSeparator();
menuWidget->AppendCheckItem(Widgets_GlobalBusyCursor,
wxT("Toggle &global busy cursor\tCtrl-Shift-U"));
menuWidget->AppendCheckItem(Widgets_BusyCursor,
wxT("Toggle b&usy cursor\tCtrl-U"));
menuWidget->AppendSeparator();
menuWidget->Append(wxID_EXIT, wxT("&Quit\tCtrl-Q"));
mbar->Append(menuWidget, wxT("&Widget"));
wxMenu *menuTextEntry = new wxMenu;
menuTextEntry->AppendRadioItem(TextEntry_DisableAutoComplete,
wxT("&Disable auto-completion"));
menuTextEntry->AppendRadioItem(TextEntry_AutoCompleteFixed,
wxT("Fixed-&list auto-completion"));
menuTextEntry->AppendRadioItem(TextEntry_AutoCompleteFilenames,
wxT("&Files names auto-completion"));
menuTextEntry->AppendRadioItem(TextEntry_AutoCompleteDirectories,
wxT("&Directories names auto-completion"));
menuTextEntry->AppendRadioItem(TextEntry_AutoCompleteCustom,
wxT("&Custom auto-completion"));
menuTextEntry->AppendSeparator();
menuTextEntry->Append(TextEntry_SetHint, "Set help &hint");
mbar->Append(menuTextEntry, wxT("&Text"));
SetMenuBar(mbar);
mbar->Check(Widgets_Enable, true);
#endif // wxUSE_MENUS
// create controls
m_panel = new wxPanel(this, wxID_ANY);
wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL);
// we have 2 panes: book with pages demonstrating the controls in the
// upper one and the log window with some buttons in the lower
int style = wxBK_DEFAULT;
// Uncomment to suppress page theme (draw in solid colour)
//style |= wxNB_NOPAGETHEME;
m_book = new WidgetsBookCtrl(m_panel, Widgets_BookCtrl,
wxDefaultPosition, wxDefaultSize,
style, "Widgets");
InitBook();
#ifndef __WXHANDHELD__
// the lower one only has the log listbox and a button to clear it
#if USE_LOG
wxSizer *sizerDown = new wxStaticBoxSizer(
new wxStaticBox( m_panel, wxID_ANY, wxT("&Log window") ),
wxVERTICAL);
m_lboxLog = new wxListBox(m_panel, wxID_ANY);
sizerDown->Add(m_lboxLog, 1, wxGROW | wxALL, 5);
sizerDown->SetMinSize(100, 150);
#else
wxSizer *sizerDown = new wxBoxSizer(wxVERTICAL);
#endif // USE_LOG
wxBoxSizer *sizerBtns = new wxBoxSizer(wxHORIZONTAL);
wxButton *btn;
#if USE_LOG
btn = new wxButton(m_panel, Widgets_ClearLog, wxT("Clear &log"));
sizerBtns->Add(btn);
sizerBtns->Add(10, 0); // spacer
#endif // USE_LOG
btn = new wxButton(m_panel, Widgets_Quit, wxT("E&xit"));
sizerBtns->Add(btn);
sizerDown->Add(sizerBtns, 0, wxALL | wxALIGN_RIGHT, 5);
// put everything together
sizerTop->Add(m_book, 1, wxGROW | (wxALL & ~(wxTOP | wxBOTTOM)), 10);
sizerTop->Add(0, 5, 0, wxGROW); // spacer in between
sizerTop->Add(sizerDown, 0, wxGROW | (wxALL & ~wxTOP), 10);
#else // !__WXHANDHELD__/__WXHANDHELD__
sizerTop->Add(m_book, 1, wxGROW | wxALL );
#endif // __WXHANDHELD__
m_panel->SetSizer(sizerTop);
const wxSize sizeMin = m_panel->GetBestSize();
if ( !sizeSet )
SetClientSize(sizeMin);
SetMinClientSize(sizeMin);
#if USE_LOG && !defined(__WXCOCOA__)
// wxCocoa's listbox is too flakey to use for logging right now
// now that everything is created we can redirect the log messages to the
// listbox
m_logTarget = new LboxLogger(m_lboxLog, wxLog::GetActiveTarget());
wxLog::SetActiveTarget(m_logTarget);
#endif
}
void WidgetsFrame::InitBook()
{
#if USE_ICONS_IN_BOOK
wxImageList *imageList = new wxImageList(ICON_SIZE, ICON_SIZE);
wxImage img(sample_xpm);
imageList->Add(wxBitmap(img.Scale(ICON_SIZE, ICON_SIZE)));
#else
wxImageList *imageList = NULL;
#endif
#if !USE_TREEBOOK
WidgetsBookCtrl *books[MAX_PAGES];
#endif
ArrayWidgetsPage pages[MAX_PAGES];
wxArrayString labels[MAX_PAGES];
wxMenu *menuPages = new wxMenu;
unsigned int nPage = 0, nFKey = 0;
int cat, imageId = 1;
// we need to first create all pages and only then add them to the book
// as we need the image list first
//
// we also construct the pages menu during this first iteration
for ( cat = 0; cat < MAX_PAGES; cat++ )
{
#if USE_TREEBOOK
nPage++; // increase for parent page
#else
books[cat] = new WidgetsBookCtrl(m_book,
wxID_ANY,
wxDefaultPosition,
wxDefaultSize,
wxBK_DEFAULT);
#endif
for ( WidgetsPageInfo *info = WidgetsPage::ms_widgetPages;
info;
info = info->GetNext() )
{
if( (info->GetCategories() & ( 1 << cat )) == 0)
continue;
WidgetsPage *page = (*info->GetCtor())(
#if USE_TREEBOOK
m_book
#else
books[cat]
#endif
, imageList);
pages[cat].Add(page);
labels[cat].Add(info->GetLabel());
if ( cat == ALL_PAGE )
{
wxString radioLabel(info->GetLabel());
nFKey++;
if ( nFKey <= 12 )
{
radioLabel << wxT("\tF" ) << nFKey;
}
menuPages->AppendRadioItem(
Widgets_GoToPage + nPage,
radioLabel
);
#if !USE_TREEBOOK
// consider only for book in book architecture
nPage++;
#endif
}
#if USE_TREEBOOK
// consider only for treebook architecture (with subpages)
nPage++;
#endif
}
}
GetMenuBar()->Append(menuPages, wxT("&Page"));
#if USE_ICONS_IN_BOOK
m_book->AssignImageList(imageList);
#endif
for ( cat = 0; cat < MAX_PAGES; cat++ )
{
#if USE_TREEBOOK
m_book->AddPage(NULL,WidgetsCategories[cat],false,0);
#else
m_book->AddPage(books[cat],WidgetsCategories[cat],false,0);
#if USE_ICONS_IN_BOOK
books[cat]->SetImageList(imageList);
#endif
#endif
// now do add them
size_t count = pages[cat].GetCount();
for ( size_t n = 0; n < count; n++ )
{
#if USE_TREEBOOK
m_book->AddSubPage
#else
books[cat]->AddPage
#endif
(
pages[cat][n],
labels[cat][n],
false, // don't select
imageId++
);
}
}
Connect( wxID_ANY,
wxEVT_COMMAND_WIDGETS_PAGE_CHANGED,
wxWidgetsbookEventHandler(WidgetsFrame::OnPageChanged) );
const bool pageSet = wxPersistentRegisterAndRestore(m_book);
#if USE_TREEBOOK
// for treebook page #0 is empty parent page only so select the first page
// with some contents
if ( !pageSet )
m_book->SetSelection(1);
// but ensure that the top of the tree is shown nevertheless
wxTreeCtrl * const tree = m_book->GetTreeCtrl();
wxTreeItemIdValue cookie;
tree->EnsureVisible(tree->GetFirstChild(tree->GetRootItem(), cookie));
#else
if ( !pageSet )
{
// for other books set selection twice to force connected event handler
// to force lazy creation of initial visible content
m_book->SetSelection(1);
m_book->SetSelection(0);
}
#endif // USE_TREEBOOK
}
WidgetsPage *WidgetsFrame::CurrentPage()
{
wxWindow *page = m_book->GetCurrentPage();
#if !USE_TREEBOOK
WidgetsBookCtrl *subBook = wxStaticCast(page, WidgetsBookCtrl);
wxCHECK_MSG( subBook, NULL, wxT("no WidgetsBookCtrl?") );
page = subBook->GetCurrentPage();
#endif // !USE_TREEBOOK
return wxStaticCast(page, WidgetsPage);
}
WidgetsFrame::~WidgetsFrame()
{
#if USE_LOG
delete m_logTarget;
#endif // USE_LOG
}
// ----------------------------------------------------------------------------
// WidgetsFrame event handlers
// ----------------------------------------------------------------------------
void WidgetsFrame::OnExit(wxCommandEvent& WXUNUSED(event))
{
Close();
}
#if USE_LOG
void WidgetsFrame::OnButtonClearLog(wxCommandEvent& WXUNUSED(event))
{
m_lboxLog->Clear();
}
#endif // USE_LOG
#if wxUSE_MENUS
void WidgetsFrame::OnPageChanging(WidgetsBookCtrlEvent& event)
{
#if USE_TREEBOOK
// don't allow selection of entries without pages (categories)
if ( !m_book->GetPage(event.GetSelection()) )
event.Veto();
#else
wxUnusedVar(event);
#endif
}
void WidgetsFrame::OnPageChanged(WidgetsBookCtrlEvent& event)
{
const int sel = event.GetSelection();
// adjust "Page" menu selection
wxMenuItem *item = GetMenuBar()->FindItem(Widgets_GoToPage + sel);
if ( item )
item->Check();
GetMenuBar()->Check(Widgets_BusyCursor, false);
// create the pages on demand, otherwise the sample startup is too slow as
// it creates hundreds of controls
WidgetsPage *page = CurrentPage();
if ( page->GetChildren().empty() )
{
wxWindowUpdateLocker noUpdates(page);
page->CreateContent();
//page->Layout();
page->GetSizer()->Fit(page);
WidgetsBookCtrl *book = wxStaticCast(page->GetParent(), WidgetsBookCtrl);
wxSize size;
for ( size_t i = 0; i < book->GetPageCount(); ++i )
{
wxWindow *page = book->GetPage(i);
if ( page )
{
size.IncTo(page->GetSize());
}
}
page->SetSize(size);
}
event.Skip();
}
void WidgetsFrame::OnGoToPage(wxCommandEvent& event)
{
#if USE_TREEBOOK
m_book->SetSelection(event.GetId() - Widgets_GoToPage);
#else
m_book->SetSelection(m_book->GetPageCount()-1);
WidgetsBookCtrl *book = wxStaticCast(m_book->GetCurrentPage(), WidgetsBookCtrl);
book->SetSelection(event.GetId() - Widgets_GoToPage);
#endif
}
#if wxUSE_TOOLTIPS
void WidgetsFrame::OnSetTooltip(wxCommandEvent& WXUNUSED(event))
{
static wxString s_tip = wxT("This is a tooltip");
wxTextEntryDialog dialog
(
this,
wxT("Tooltip text (may use \\n, leave empty to remove): "),
wxT("Widgets sample"),
s_tip
);
if ( dialog.ShowModal() != wxID_OK )
return;
s_tip = dialog.GetValue();
s_tip.Replace(wxT("\\n"), wxT("\n"));
WidgetsPage *page = CurrentPage();
const Widgets widgets = page->GetWidgets();
for ( Widgets::const_iterator it = widgets.begin();
it != widgets.end();
++it )
{
(*it)->SetToolTip(s_tip);
}
}
#endif // wxUSE_TOOLTIPS
namespace
{
// Trivial wrapper for wxGetColourFromUser() which also does something even if
// the colour dialog is not available in the current build (which may happen
// for the ports in development and it is still useful to see how colours work)
wxColour GetColourFromUser(wxWindow *parent, const wxColour& colDefault)
{
#if wxUSE_COLOURDLG
return wxGetColourFromUser(parent, colDefault);
#else // !wxUSE_COLOURDLG
if ( colDefault == *wxBLACK )
return *wxWHITE;
else
return *wxBLACK;
#endif // wxUSE_COLOURDLG/!wxUSE_COLOURDLG
}
} // anonymous namespace
void WidgetsFrame::OnSetFgCol(wxCommandEvent& WXUNUSED(event))
{
// allow for debugging the default colour the first time this is called
WidgetsPage *page = CurrentPage();
if (!m_colFg.IsOk())
m_colFg = page->GetForegroundColour();
wxColour col = GetColourFromUser(this, m_colFg);
if ( !col.IsOk() )
return;
m_colFg = col;
const Widgets widgets = page->GetWidgets();
for ( Widgets::const_iterator it = widgets.begin();
it != widgets.end();
++it )
{
(*it)->SetForegroundColour(m_colFg);
(*it)->Refresh();
}
}
void WidgetsFrame::OnSetBgCol(wxCommandEvent& WXUNUSED(event))
{
WidgetsPage *page = CurrentPage();
if ( !m_colBg.IsOk() )
m_colBg = page->GetBackgroundColour();
wxColour col = GetColourFromUser(this, m_colBg);
if ( !col.IsOk() )
return;
m_colBg = col;
const Widgets widgets = page->GetWidgets();
for ( Widgets::const_iterator it = widgets.begin();
it != widgets.end();
++it )
{
(*it)->SetBackgroundColour(m_colBg);
(*it)->Refresh();
}
}
void WidgetsFrame::OnSetPageBg(wxCommandEvent& WXUNUSED(event))
{
wxColour col = GetColourFromUser(this, GetBackgroundColour());
if ( !col.IsOk() )
return;
CurrentPage()->SetBackgroundColour(col);
CurrentPage()->Refresh();
}
void WidgetsFrame::OnSetFont(wxCommandEvent& WXUNUSED(event))
{
#if wxUSE_FONTDLG
WidgetsPage *page = CurrentPage();
if (!m_font.IsOk())
m_font = page->GetFont();
wxFont font = wxGetFontFromUser(this, m_font);
if ( !font.IsOk() )
return;
m_font = font;
const Widgets widgets = page->GetWidgets();
for ( Widgets::const_iterator it = widgets.begin();
it != widgets.end();
++it )
{
(*it)->SetFont(m_font);
(*it)->Refresh();
}
// The best size of the widget could have changed after changing its font,
// so re-layout to show it correctly.
page->Layout();
#else
wxLogMessage(wxT("Font selection dialog not available in current build."));
#endif
}
void WidgetsFrame::OnEnable(wxCommandEvent& event)
{
const Widgets widgets = CurrentPage()->GetWidgets();
for ( Widgets::const_iterator it = widgets.begin();
it != widgets.end();
++it )
{
(*it)->Enable(event.IsChecked());
}
}
void WidgetsFrame::OnSetBorder(wxCommandEvent& event)
{
int border;
switch ( event.GetId() )
{
case Widgets_BorderNone: border = wxBORDER_NONE; break;
case Widgets_BorderStatic: border = wxBORDER_STATIC; break;
case Widgets_BorderSimple: border = wxBORDER_SIMPLE; break;
case Widgets_BorderRaised: border = wxBORDER_RAISED; break;
case Widgets_BorderSunken: border = wxBORDER_SUNKEN; break;
case Widgets_BorderDouble: border = wxBORDER_DOUBLE; break;
default:
wxFAIL_MSG( wxT("unknown border style") );
// fall through
case Widgets_BorderDefault: border = wxBORDER_DEFAULT; break;
}
WidgetsPage::ms_defaultFlags &= ~wxBORDER_MASK;
WidgetsPage::ms_defaultFlags |= border;
WidgetsPage *page = CurrentPage();
page->RecreateWidget();
}
void WidgetsFrame::OnToggleGlobalBusyCursor(wxCommandEvent& event)
{
if ( event.IsChecked() )
wxBeginBusyCursor();
else
wxEndBusyCursor();
}
void WidgetsFrame::OnToggleBusyCursor(wxCommandEvent& event)
{
wxCursor cursor(*(event.IsChecked() ? wxHOURGLASS_CURSOR
: wxSTANDARD_CURSOR));
const Widgets widgets = CurrentPage()->GetWidgets();
for ( Widgets::const_iterator it = widgets.begin();
it != widgets.end();
++it )
{
(*it)->SetCursor(cursor);
}
}
void WidgetsFrame::OnDisableAutoComplete(wxCommandEvent& WXUNUSED(event))
{
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
wxCHECK_RET( entry, "menu item should be disabled" );
if ( entry->AutoComplete(wxArrayString()) )
{
wxLogMessage("Disabled auto completion.");
}
else
{
wxLogMessage("AutoComplete() failed.");
}
}
void WidgetsFrame::OnAutoCompleteFixed(wxCommandEvent& WXUNUSED(event))
{
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
wxCHECK_RET( entry, "menu item should be disabled" );
wxArrayString completion_choices;
// add a few strings so a completion occurs on any letter typed
for ( char idxc = 'a'; idxc < 'z'; ++idxc )
completion_choices.push_back(wxString::Format("%c%c", idxc, idxc));
completion_choices.push_back("is this string for test?");
completion_choices.push_back("this is a test string");
completion_choices.push_back("this is another test string");
completion_choices.push_back("this string is for test");
if ( entry->AutoComplete(completion_choices) )
{
wxLogMessage("Enabled auto completion of a set of fixed strings.");
}
else
{
wxLogMessage("AutoComplete() failed.");
}
}
void WidgetsFrame::OnAutoCompleteFilenames(wxCommandEvent& WXUNUSED(event))
{
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
wxCHECK_RET( entry, "menu item should be disabled" );
if ( entry->AutoCompleteFileNames() )
{
wxLogMessage("Enabled auto completion of file names.");
}
else
{
wxLogMessage("AutoCompleteFileNames() failed.");
}
}
void WidgetsFrame::OnAutoCompleteDirectories(wxCommandEvent& WXUNUSED(event))
{
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
wxCHECK_RET( entry, "menu item should be disabled" );
if ( entry->AutoCompleteDirectories() )
{
wxLogMessage("Enabled auto completion of directories.");
}
else
{
wxLogMessage("AutoCompleteDirectories() failed.");
}
}
void WidgetsFrame::OnAutoCompleteCustom(wxCommandEvent& WXUNUSED(event))
{
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
wxCHECK_RET( entry, "menu item should be disabled" );
// This is a simple (and hence rather useless) example of a custom
// completer class that completes the first word (only) initially and only
// build the list of the possible second words once the first word is
// known. This allows to avoid building the full 676000 item list of
// possible strings all at once as the we have 1000 possibilities for the
// first word (000..999) and 676 (aa..zz) for the second one.
class CustomTextCompleter : public wxTextCompleterSimple
{
public:
virtual void GetCompletions(const wxString& prefix, wxArrayString& res)
{
// This is used for illustrative purposes only and shows how many
// completions we return every time when we're called.
class LogCompletions
{
public:
LogCompletions(const wxString& prefix, const wxArrayString& res)
: m_prefix(prefix),
m_res(res)
{
}
~LogCompletions()
{
wxLogMessage("Returning %lu possible completions for "
"prefix \"%s\"",
m_res.size(), m_prefix);
}
private:
const wxString& m_prefix;
const wxArrayString& m_res;
} logCompletions(prefix, res);
// Normally it doesn't make sense to complete empty control, there
// are too many choices and listing them all wouldn't be helpful.
if ( prefix.empty() )
return;
// The only valid strings start with 3 digits so check for their
// presence proposing to complete the remaining ones.
if ( !wxIsdigit(prefix[0]) )
return;
if ( prefix.length() == 1 )
{
for ( int i = 0; i < 10; i++ )
for ( int j = 0; j < 10; j++ )
res.push_back(wxString::Format("%s%02d",
prefix, 10*i + j));
return;
}
else if ( !wxIsdigit(prefix[1]) )
return;
if ( prefix.length() == 2 )
{
for ( int i = 0; i < 10; i++ )
res.push_back(wxString::Format("%s%d", prefix, i));
return;
}
else if ( !wxIsdigit(prefix[2]) )
return;
// Next we must have a space and two letters.
wxString prefix2(prefix);
if ( prefix.length() == 3 )
prefix2 += ' ';
else if ( prefix[3] != ' ' )
return;
if ( prefix2.length() == 4 )
{
for ( char c = 'a'; c <= 'z'; c++ )
for ( char d = 'a'; d <= 'z'; d++ )
res.push_back(wxString::Format("%s%c%c", prefix2, c, d));
return;
}
else if ( !wxIslower(prefix[4]) )
return;
if ( prefix.length() == 5 )
{
for ( char c = 'a'; c <= 'z'; c++ )
res.push_back(prefix + c);
}
}
};
if ( entry->AutoComplete(new CustomTextCompleter) )
{
wxLogMessage("Enabled custom auto completer for \"NNN XX\" items "
"(where N is a digit and X is a letter).");
}
else
{
wxLogMessage("AutoComplete() failed.");
}
}
void WidgetsFrame::OnSetHint(wxCommandEvent& WXUNUSED(event))
{
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
wxCHECK_RET( entry, "menu item should be disabled" );
static wxString s_hint("Type here");
wxString
hint = wxGetTextFromUser("Text hint:", "Widgets sample", s_hint, this);
if ( hint.empty() )
return;
s_hint = hint;
if ( entry->SetHint(hint) )
{
wxLogMessage("Set hint to \"%s\".", hint);
}
else
{
wxLogMessage("Text hints not supported.");
}
}
#endif // wxUSE_MENUS
// ----------------------------------------------------------------------------
// WidgetsPageInfo
// ----------------------------------------------------------------------------
WidgetsPageInfo::WidgetsPageInfo(Constructor ctor, const wxChar *label, int categories)
: m_label(label)
, m_categories(categories)
{
m_ctor = ctor;
m_next = NULL;
// dummy sorting: add and immediately sort in the list according to label
if ( WidgetsPage::ms_widgetPages )
{
WidgetsPageInfo *node_prev = WidgetsPage::ms_widgetPages;
if ( wxStrcmp(label, node_prev->GetLabel().c_str()) < 0 )
{
// add as first
m_next = node_prev;
WidgetsPage::ms_widgetPages = this;
}
else
{
WidgetsPageInfo *node_next;
do
{
node_next = node_prev->GetNext();
if ( node_next )
{
// add if between two
if ( wxStrcmp(label, node_next->GetLabel().c_str()) < 0 )
{
node_prev->SetNext(this);
m_next = node_next;
// force to break loop
node_next = NULL;
}
}
else
{
// add as last
node_prev->SetNext(this);
m_next = node_next;
}
node_prev = node_next;
}
while ( node_next );
}
}
else
{
// add when first
WidgetsPage::ms_widgetPages = this;
}
}
// ----------------------------------------------------------------------------
// WidgetsPage
// ----------------------------------------------------------------------------
int WidgetsPage::ms_defaultFlags = wxBORDER_DEFAULT;
WidgetsPageInfo *WidgetsPage::ms_widgetPages = NULL;
WidgetsPage::WidgetsPage(WidgetsBookCtrl *book,
wxImageList *imaglist,
const char *const icon[])
: wxPanel(book, wxID_ANY,
wxDefaultPosition, wxDefaultSize,
wxNO_FULL_REPAINT_ON_RESIZE |
wxCLIP_CHILDREN |
wxTAB_TRAVERSAL)
{
#if USE_ICONS_IN_BOOK
imaglist->Add(wxBitmap(wxImage(icon).Scale(ICON_SIZE, ICON_SIZE)));
#else
wxUnusedVar(imaglist);
wxUnusedVar(icon);
#endif
}
wxSizer *WidgetsPage::CreateSizerWithText(wxControl *control,
wxWindowID id,
wxTextCtrl **ppText)
{
wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
wxTextCtrl *text = new wxTextCtrl(this, id, wxEmptyString,
wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
sizerRow->Add(control, 0, wxRIGHT | wxALIGN_CENTRE_VERTICAL, 5);
sizerRow->Add(text, 1, wxLEFT | wxALIGN_CENTRE_VERTICAL, 5);
if ( ppText )
*ppText = text;
return sizerRow;
}
// create a sizer containing a label and a text ctrl
wxSizer *WidgetsPage::CreateSizerWithTextAndLabel(const wxString& label,
wxWindowID id,
wxTextCtrl **ppText)
{
return CreateSizerWithText(new wxStaticText(this, wxID_ANY, label),
id, ppText);
}
// create a sizer containing a button and a text ctrl
wxSizer *WidgetsPage::CreateSizerWithTextAndButton(wxWindowID idBtn,
const wxString& label,
wxWindowID id,
wxTextCtrl **ppText)
{
return CreateSizerWithText(new wxButton(this, idBtn, label), id, ppText);
}
wxCheckBox *WidgetsPage::CreateCheckBoxAndAddToSizer(wxSizer *sizer,
const wxString& label,
wxWindowID id)
{
wxCheckBox *checkbox = new wxCheckBox(this, id, label);
sizer->Add(checkbox, 0, wxLEFT | wxRIGHT, 5);
sizer->Add(0, 2, 0, wxGROW); // spacer
return checkbox;
}