wxwidgets/samples/widgets/notebook.cpp
Vadim Zeitlin a8b4753d1d Reconnect events to the widget after recreating it in the sample
This ensures that the expected events are given even after the widget is
recreated due to a change of some controls on its page (and not because
it's recreated by one of the menu commands in the parent frame).

We also don't need to connect to these events from WidgetsFrame any
longer (and, in fact, doing it would be wrong as we'd connect twice),
which simplifies its code.
2024-02-19 00:40:30 +01:00

747 lines
22 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Program: wxWidgets Widgets Sample
// Name: notebook.cpp
// Purpose: Part of the widgets sample showing book controls
// Author: Vadim Zeitlin, Wlodzimierz ABX Skiba
// Created: 06.04.01
// Copyright: (c) 2001 Vadim Zeitlin, 2006 Wlodzimierz Skiba
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// for compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#if wxUSE_BOOKCTRL
// for all others, include the necessary headers
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/log.h"
#include "wx/button.h"
#include "wx/checkbox.h"
#include "wx/combobox.h"
#include "wx/radiobox.h"
#include "wx/statbox.h"
#include "wx/textctrl.h"
#endif
#include "wx/sizer.h"
#include "wx/bookctrl.h"
#include "wx/artprov.h"
#include "wx/imaglist.h"
#include "widgets.h"
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// control ids
enum
{
BookPage_Reset = wxID_HIGHEST,
BookPage_SelectPage,
BookPage_AddPage,
BookPage_InsertPage,
BookPage_RemovePage,
BookPage_DeleteAll,
BookPage_InsertText,
BookPage_RemoveText,
BookPage_SelectText,
BookPage_NumPagesText,
BookPage_CurSelectText,
BookPage_Book
};
// book orientations
enum Orient
{
Orient_Top,
Orient_Bottom,
Orient_Left,
Orient_Right,
Orient_Max
};
// ----------------------------------------------------------------------------
// BookWidgetsPage
// ----------------------------------------------------------------------------
class BookWidgetsPage : public WidgetsPage
{
public:
BookWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist, const char *const icon[]);
virtual ~BookWidgetsPage();
virtual wxWindow *GetWidget() const override { return m_book; }
virtual void RecreateWidget() override { RecreateBook(); }
// lazy creation of the content
virtual void CreateContent() override;
protected:
// event handlers
void OnButtonReset(wxCommandEvent& event);
void OnButtonDeleteAll(wxCommandEvent& event);
void OnButtonSelectPage(wxCommandEvent& event);
void OnButtonAddPage(wxCommandEvent& event);
void OnButtonInsertPage(wxCommandEvent& event);
void OnButtonRemovePage(wxCommandEvent& event);
void OnCheckOrRadioBox(wxCommandEvent& event);
void OnUpdateUINumPagesText(wxUpdateUIEvent& event);
void OnUpdateUICurSelectText(wxUpdateUIEvent& event);
void OnUpdateUISelectButton(wxUpdateUIEvent& event);
void OnUpdateUIInsertButton(wxUpdateUIEvent& event);
void OnUpdateUIRemoveButton(wxUpdateUIEvent& event);
void OnUpdateUIResetButton(wxUpdateUIEvent& event);
// reset book parameters
void Reset();
// (re)create book
void RecreateBook();
virtual wxBookCtrlBase *CreateBook(long flags) = 0;
// create or destroy the image list
void CreateImageList();
// create a new page
wxWindow *CreateNewPage();
// get the image index for the new page
int GetIconIndex() const;
// get the numeric value of text ctrl
int GetTextValue(wxTextCtrl *text) const;
// is the value in range?
bool IsValidValue(int val) const
{ return (val >= 0) && (val < (int) m_book->GetPageCount()); }
// the controls
// ------------
// the check/radio boxes for styles
wxCheckBox *m_chkImages;
wxRadioBox *m_radioOrient;
// the text controls containing input for various commands
wxTextCtrl *m_textInsert,
*m_textRemove,
*m_textSelect;
// the book itself and the sizer it is in
wxBookCtrlBase *m_book;
wxSizer *m_sizerBook;
// the image list for our book
wxImageList *m_imageList;
private:
wxDECLARE_EVENT_TABLE();
};
// ----------------------------------------------------------------------------
// event tables
// ----------------------------------------------------------------------------
wxBEGIN_EVENT_TABLE(BookWidgetsPage, WidgetsPage)
EVT_BUTTON(BookPage_Reset, BookWidgetsPage::OnButtonReset)
EVT_BUTTON(BookPage_SelectPage, BookWidgetsPage::OnButtonSelectPage)
EVT_BUTTON(BookPage_AddPage, BookWidgetsPage::OnButtonAddPage)
EVT_BUTTON(BookPage_InsertPage, BookWidgetsPage::OnButtonInsertPage)
EVT_BUTTON(BookPage_RemovePage, BookWidgetsPage::OnButtonRemovePage)
EVT_BUTTON(BookPage_DeleteAll, BookWidgetsPage::OnButtonDeleteAll)
EVT_UPDATE_UI(BookPage_NumPagesText, BookWidgetsPage::OnUpdateUINumPagesText)
EVT_UPDATE_UI(BookPage_CurSelectText, BookWidgetsPage::OnUpdateUICurSelectText)
EVT_UPDATE_UI(BookPage_SelectPage, BookWidgetsPage::OnUpdateUISelectButton)
EVT_UPDATE_UI(BookPage_InsertPage, BookWidgetsPage::OnUpdateUIInsertButton)
EVT_UPDATE_UI(BookPage_RemovePage, BookWidgetsPage::OnUpdateUIRemoveButton)
EVT_CHECKBOX(wxID_ANY, BookWidgetsPage::OnCheckOrRadioBox)
EVT_RADIOBOX(wxID_ANY, BookWidgetsPage::OnCheckOrRadioBox)
wxEND_EVENT_TABLE()
// ============================================================================
// implementation
// ============================================================================
BookWidgetsPage::BookWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist, const char *const icon[])
:WidgetsPage(book, imaglist, icon)
{
// init everything
m_chkImages = nullptr;
m_imageList = nullptr;
m_book = nullptr;
m_radioOrient = nullptr;
m_sizerBook = nullptr;
}
void BookWidgetsPage::CreateContent()
{
wxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);
// left pane
wxStaticBoxSizer *sizerLeft = new wxStaticBoxSizer(wxVERTICAL, this, "&Set style");
wxStaticBox* const sizerLeftBox = sizerLeft->GetStaticBox();
// must be in sync with Orient enum
wxArrayString orientations;
orientations.Add("&top");
orientations.Add("&bottom");
orientations.Add("&left");
orientations.Add("&right");
wxASSERT_MSG( orientations.GetCount() == Orient_Max,
"forgot to update something" );
m_chkImages = new wxCheckBox(sizerLeftBox, wxID_ANY, "Show &images");
m_radioOrient = new wxRadioBox(sizerLeftBox, wxID_ANY, "&Tab orientation",
wxDefaultPosition, wxDefaultSize,
orientations, 1, wxRA_SPECIFY_COLS);
sizerLeft->Add(m_chkImages, 0, wxALL, 5);
sizerLeft->Add(5, 5, 0, wxGROW | wxALL, 5); // spacer
sizerLeft->Add(m_radioOrient, 0, wxALL, 5);
wxButton *btn = new wxButton(sizerLeftBox, BookPage_Reset, "&Reset");
sizerLeft->Add(btn, 0, wxALIGN_CENTRE_HORIZONTAL | wxALL, 15);
// middle pane
wxStaticBoxSizer *sizerMiddle = new wxStaticBoxSizer(wxVERTICAL, this, "&Contents");
wxStaticBox* const sizerMidleBox = sizerMiddle->GetStaticBox();
wxTextCtrl *text;
wxSizer *sizerRow = CreateSizerWithTextAndLabel("Number of pages: ",
BookPage_NumPagesText,
&text,
sizerMidleBox);
text->SetEditable(false);
sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
sizerRow = CreateSizerWithTextAndLabel("Current selection: ",
BookPage_CurSelectText,
&text,
sizerMidleBox);
text->SetEditable(false);
sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
sizerRow = CreateSizerWithTextAndButton(BookPage_SelectPage,
"&Select page",
BookPage_SelectText,
&m_textSelect,
sizerMidleBox);
sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
btn = new wxButton(sizerMidleBox, BookPage_AddPage, "&Add page");
sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
sizerRow = CreateSizerWithTextAndButton(BookPage_InsertPage,
"&Insert page at",
BookPage_InsertText,
&m_textInsert,
sizerMidleBox);
sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
sizerRow = CreateSizerWithTextAndButton(BookPage_RemovePage,
"&Remove page",
BookPage_RemoveText,
&m_textRemove,
sizerMidleBox);
sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
btn = new wxButton(sizerMidleBox, BookPage_DeleteAll, "&Delete All");
sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
// right pane
m_sizerBook = new wxBoxSizer(wxHORIZONTAL);
// the 3 panes compose the window
sizerTop->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10);
sizerTop->Add(sizerMiddle, 0, wxGROW | wxALL, 10);
sizerTop->Add(m_sizerBook, 1, wxGROW | (wxALL & ~wxRIGHT), 10);
RecreateBook();
// final initializations
Reset();
CreateImageList();
SetSizer(sizerTop);
}
BookWidgetsPage::~BookWidgetsPage()
{
delete m_imageList;
}
// ----------------------------------------------------------------------------
// operations
// ----------------------------------------------------------------------------
void BookWidgetsPage::Reset()
{
m_chkImages->SetValue(true);
m_radioOrient->SetSelection(Orient_Top);
}
void BookWidgetsPage::CreateImageList()
{
if ( m_chkImages->GetValue() )
{
if ( !m_imageList )
{
// create a dummy image list with a few icons
m_imageList = new wxImageList(32, 32);
wxSize size(32, 32);
m_imageList->Add(wxArtProvider::GetIcon(wxART_INFORMATION, wxART_OTHER, size));
m_imageList->Add(wxArtProvider::GetIcon(wxART_QUESTION, wxART_OTHER, size));
m_imageList->Add(wxArtProvider::GetIcon(wxART_WARNING, wxART_OTHER, size));
m_imageList->Add(wxArtProvider::GetIcon(wxART_ERROR, wxART_OTHER, size));
}
if ( m_book )
m_book->SetImageList(m_imageList);
}
else // no images
{
wxDELETE(m_imageList);
}
// because of the bug in wxMSW we can't use SetImageList(nullptr) - although
// it would be logical if this removed the image list from book, under
// MSW it crashes instead - FIXME
}
void BookWidgetsPage::RecreateBook()
{
// do not recreate anything in case page content was not prepared yet
if(!m_radioOrient)
return;
int flags = GetAttrs().m_defaultFlags;
switch ( m_radioOrient->GetSelection() )
{
default:
wxFAIL_MSG( "unknown orientation" );
wxFALLTHROUGH;
case Orient_Top:
flags |= wxBK_TOP;
break;
case Orient_Bottom:
flags |= wxBK_BOTTOM;
break;
case Orient_Left:
flags |= wxBK_LEFT;
break;
case Orient_Right:
flags |= wxBK_RIGHT;
break;
}
wxBookCtrlBase *oldBook = m_book;
m_book = CreateBook(flags);
NotifyWidgetRecreation(m_book);
CreateImageList();
if ( oldBook )
{
const int sel = oldBook->GetSelection();
const int count = oldBook->GetPageCount();
// recreate the pages
for ( int n = 0; n < count; n++ )
{
m_book->AddPage(CreateNewPage(),
oldBook->GetPageText(n),
false,
m_chkImages->GetValue() ?
GetIconIndex() : -1);
}
m_sizerBook->Detach( oldBook );
delete oldBook;
// restore selection
if ( sel != -1 )
{
m_book->SetSelection(sel);
}
}
m_sizerBook->Add(m_book, 1, wxGROW | wxALL, 5);
m_sizerBook->SetMinSize(150, 0);
m_sizerBook->Layout();
}
// ----------------------------------------------------------------------------
// helpers
// ----------------------------------------------------------------------------
int BookWidgetsPage::GetTextValue(wxTextCtrl *text) const
{
long pos = -1;
if ( !text || !text->GetValue().ToLong(&pos) )
pos = -1;
return (int)pos;
}
int BookWidgetsPage::GetIconIndex() const
{
if ( m_book )
{
const int nImages = m_book->GetImageCount();
if ( nImages > 0 )
{
return m_book->GetPageCount() % nImages;
}
}
return -1;
}
wxWindow *BookWidgetsPage::CreateNewPage()
{
return new wxTextCtrl(m_book, wxID_ANY, "I'm a book page");
}
// ----------------------------------------------------------------------------
// event handlers
// ----------------------------------------------------------------------------
void BookWidgetsPage::OnButtonReset(wxCommandEvent& WXUNUSED(event))
{
Reset();
RecreateBook();
}
void BookWidgetsPage::OnButtonDeleteAll(wxCommandEvent& WXUNUSED(event))
{
m_book->DeleteAllPages();
}
void BookWidgetsPage::OnButtonSelectPage(wxCommandEvent& WXUNUSED(event))
{
int pos = GetTextValue(m_textSelect);
wxCHECK_RET( IsValidValue(pos), "button should be disabled" );
m_book->SetSelection(pos);
}
void BookWidgetsPage::OnButtonAddPage(wxCommandEvent& WXUNUSED(event))
{
m_book->AddPage(CreateNewPage(), "Added page", false,
GetIconIndex());
}
void BookWidgetsPage::OnButtonInsertPage(wxCommandEvent& WXUNUSED(event))
{
int pos = GetTextValue(m_textInsert);
wxCHECK_RET( IsValidValue(pos), "button should be disabled" );
m_book->InsertPage(pos, CreateNewPage(), "Inserted page", false,
GetIconIndex());
}
void BookWidgetsPage::OnButtonRemovePage(wxCommandEvent& WXUNUSED(event))
{
int pos = GetTextValue(m_textRemove);
wxCHECK_RET( IsValidValue(pos), "button should be disabled" );
m_book->DeletePage(pos);
}
void BookWidgetsPage::OnUpdateUISelectButton(wxUpdateUIEvent& event)
{
event.Enable( IsValidValue(GetTextValue(m_textSelect)) );
}
void BookWidgetsPage::OnUpdateUIInsertButton(wxUpdateUIEvent& event)
{
event.Enable( IsValidValue(GetTextValue(m_textInsert)) );
}
void BookWidgetsPage::OnUpdateUIRemoveButton(wxUpdateUIEvent& event)
{
event.Enable( IsValidValue(GetTextValue(m_textRemove)) );
}
void BookWidgetsPage::OnUpdateUIResetButton(wxUpdateUIEvent& event)
{
if(m_chkImages && m_radioOrient)
event.Enable( !m_chkImages->GetValue() ||
m_radioOrient->GetSelection() != wxBK_TOP );
}
void BookWidgetsPage::OnUpdateUINumPagesText(wxUpdateUIEvent& event)
{
if(m_book)
event.SetText( wxString::Format("%u", unsigned(m_book->GetPageCount())) );
}
void BookWidgetsPage::OnUpdateUICurSelectText(wxUpdateUIEvent& event)
{
if(m_book)
event.SetText( wxString::Format("%d", m_book->GetSelection()) );
}
void BookWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& WXUNUSED(event))
{
RecreateBook();
}
#if wxUSE_NOTEBOOK
#include "icons/notebook.xpm"
#include "wx/notebook.h"
// ----------------------------------------------------------------------------
// NotebookWidgetsPage
// ----------------------------------------------------------------------------
class NotebookWidgetsPage : public BookWidgetsPage
{
public:
NotebookWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist)
: BookWidgetsPage(book, imaglist, notebook_xpm)
{
RecreateBook();
}
virtual ~NotebookWidgetsPage() {}
protected:
// event handlers
void OnPageChanging(wxNotebookEvent& event);
void OnPageChanged(wxNotebookEvent& event);
// (re)create book
virtual wxBookCtrlBase *CreateBook(long flags) override
{
return new wxNotebook(this, BookPage_Book,
wxDefaultPosition, wxDefaultSize,
flags);
}
private:
wxDECLARE_EVENT_TABLE();
DECLARE_WIDGETS_PAGE(NotebookWidgetsPage)
};
// ----------------------------------------------------------------------------
// event table
// ----------------------------------------------------------------------------
wxBEGIN_EVENT_TABLE(NotebookWidgetsPage, BookWidgetsPage)
EVT_NOTEBOOK_PAGE_CHANGING(wxID_ANY, NotebookWidgetsPage::OnPageChanging)
EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, NotebookWidgetsPage::OnPageChanged)
wxEND_EVENT_TABLE()
#if defined(__WXUNIVERSAL__)
#define FAMILY_CTRLS UNIVERSAL_CTRLS
#else
#define FAMILY_CTRLS NATIVE_CTRLS
#endif
IMPLEMENT_WIDGETS_PAGE(NotebookWidgetsPage, "Notebook",
FAMILY_CTRLS | BOOK_CTRLS
);
void NotebookWidgetsPage::OnPageChanging(wxNotebookEvent& event)
{
wxLogMessage("Notebook page changing from %d to %d (currently %d).",
event.GetOldSelection(),
event.GetSelection(),
m_book->GetSelection());
event.Skip();
}
void NotebookWidgetsPage::OnPageChanged(wxNotebookEvent& event)
{
wxLogMessage("Notebook page changed from %d to %d (currently %d).",
event.GetOldSelection(),
event.GetSelection(),
m_book->GetSelection());
event.Skip();
}
#endif // wxUSE_NOTEBOOK
#if wxUSE_LISTBOOK
#include "icons/listbook.xpm"
#include "wx/listbook.h"
// ----------------------------------------------------------------------------
// ListbookWidgetsPage
// ----------------------------------------------------------------------------
class ListbookWidgetsPage : public BookWidgetsPage
{
public:
ListbookWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist)
: BookWidgetsPage(book, imaglist, listbook_xpm)
{
RecreateBook();
}
virtual ~ListbookWidgetsPage() {}
protected:
// event handlers
void OnPageChanging(wxListbookEvent& event);
void OnPageChanged(wxListbookEvent& event);
// (re)create book
virtual wxBookCtrlBase *CreateBook(long flags) override
{
return new wxListbook(this, BookPage_Book,
wxDefaultPosition, wxDefaultSize,
flags);
}
private:
wxDECLARE_EVENT_TABLE();
DECLARE_WIDGETS_PAGE(ListbookWidgetsPage)
};
// ----------------------------------------------------------------------------
// event table
// ----------------------------------------------------------------------------
wxBEGIN_EVENT_TABLE(ListbookWidgetsPage, BookWidgetsPage)
EVT_LISTBOOK_PAGE_CHANGING(wxID_ANY, ListbookWidgetsPage::OnPageChanging)
EVT_LISTBOOK_PAGE_CHANGED(wxID_ANY, ListbookWidgetsPage::OnPageChanged)
wxEND_EVENT_TABLE()
IMPLEMENT_WIDGETS_PAGE(ListbookWidgetsPage, "Listbook",
GENERIC_CTRLS | BOOK_CTRLS
);
void ListbookWidgetsPage::OnPageChanging(wxListbookEvent& event)
{
wxLogMessage("Listbook page changing from %d to %d (currently %d).",
event.GetOldSelection(),
event.GetSelection(),
m_book->GetSelection());
event.Skip();
}
void ListbookWidgetsPage::OnPageChanged(wxListbookEvent& event)
{
wxLogMessage("Listbook page changed from %d to %d (currently %d).",
event.GetOldSelection(),
event.GetSelection(),
m_book->GetSelection());
event.Skip();
}
#endif // wxUSE_LISTBOOK
#if wxUSE_CHOICEBOOK
#include "icons/choicebk.xpm"
#include "wx/choicebk.h"
// ----------------------------------------------------------------------------
// ChoicebookWidgetsPage
// ----------------------------------------------------------------------------
class ChoicebookWidgetsPage : public BookWidgetsPage
{
public:
ChoicebookWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist)
: BookWidgetsPage(book, imaglist, choicebk_xpm)
{
RecreateBook();
}
virtual ~ChoicebookWidgetsPage() {}
protected:
// event handlers
void OnPageChanging(wxChoicebookEvent& event);
void OnPageChanged(wxChoicebookEvent& event);
// (re)create book
virtual wxBookCtrlBase *CreateBook(long flags) override
{
return new wxChoicebook(this, BookPage_Book,
wxDefaultPosition, wxDefaultSize,
flags);
}
private:
wxDECLARE_EVENT_TABLE();
DECLARE_WIDGETS_PAGE(ChoicebookWidgetsPage)
};
// ----------------------------------------------------------------------------
// event table
// ----------------------------------------------------------------------------
wxBEGIN_EVENT_TABLE(ChoicebookWidgetsPage, BookWidgetsPage)
EVT_CHOICEBOOK_PAGE_CHANGING(wxID_ANY, ChoicebookWidgetsPage::OnPageChanging)
EVT_CHOICEBOOK_PAGE_CHANGED(wxID_ANY, ChoicebookWidgetsPage::OnPageChanged)
wxEND_EVENT_TABLE()
IMPLEMENT_WIDGETS_PAGE(ChoicebookWidgetsPage, "Choicebook",
GENERIC_CTRLS | BOOK_CTRLS
);
void ChoicebookWidgetsPage::OnPageChanging(wxChoicebookEvent& event)
{
wxLogMessage("Choicebook page changing from %d to %d (currently %d).",
event.GetOldSelection(),
event.GetSelection(),
m_book->GetSelection());
event.Skip();
}
void ChoicebookWidgetsPage::OnPageChanged(wxChoicebookEvent& event)
{
wxLogMessage("Choicebook page changed from %d to %d (currently %d).",
event.GetOldSelection(),
event.GetSelection(),
m_book->GetSelection());
event.Skip();
}
#endif // wxUSE_CHOICEBOOK
#endif // wxUSE_BOOKCTRL