- Fix display of right aligned columns in wxGenericListCtrl (jl).
- Restore text drag-and-drop in wxSTC broken by Scintilla 2 update (Jens Lody).
- Improve wxGTK print/page setup dialog (rafravago).
+- Add support for id ranges to XRC (David Hart).
- Added wxToolbook XRC handler (Andrea Zanellato).
- Added wxDocManager::FindTemplate() (troelsk).
- Return bool, not void, from wxImage::ConvertAlphaToMask() (troelsk).
- @ref overview_xrcformat_sizers
- @ref overview_xrcformat_other_objects
- @ref overview_xrcformat_platform
+- @ref overview_xrcformat_idranges
- @ref overview_xrcformat_extending
- @ref overview_xrcformat_extending_subclass
- @ref overview_xrcformat_extending_unknown
+@section overview_xrcformat_idranges ID Ranges
+
+Usually you won't care what value the XRCID macro returns for the ID of an
+object. Sometimes though it is convenient to have a range of IDs that are
+guaranteed to be consecutive. An example of this would be connecting a group of
+similar controls to the same event handler.
+
+The following XRC fragment 'declares' an ID range called @em foo and another
+called @em bar; each with some items.
+
+@code
+ <object class="wxButton" name="foo[start]">
+ <object class="wxButton" name="foo[end]">
+ <object class="wxButton" name="foo[2]">
+ ...
+ <object class="wxButton" name="bar[0]">
+ <object class="wxButton" name="bar[2]">
+ <object class="wxButton" name="bar[1]">
+ ...
+<ids-range name="foo" />
+<ids-range name="bar" size="30" start="10000" />
+@endcode
+
+For the range foo, no @em size or @em start parameters were given, so the size
+will be calculated from the number of range items, and IDs allocated by
+wxWindow::NewControlId (so they'll be negative). Range bar asked for a size of
+30, so this will be its minimum size: should it have more items, the range will
+automatically expand to fit them. It specified a start ID of 10000, so
+XRCID("bar[0]") will be 10000, XRCID("bar[1]") 10001 etc. Note that if you
+choose to supply a start value it must be positive, and it's your
+responsibility to avoid clashes.
+
+For every ID range, the first item can be referenced either as
+<em>rangename</em>[0] or <em>rangename</em>[start]. Similarly
+<em>rangename</em>[end] is the last item. Using [start] and [end] is more
+descriptive in e.g. a Bind() event range or a @em for loop, and they don't have
+to be altered whenever the number of items changes.
+
+Whether a range has positive or negative IDs, [start] is always a smaller
+number than [end]; so code like this works as expected:
+
+@code
+for (int n=XRCID("foo[start]"); n < XRCID("foo[end]"); ++n)
+ ...
+@endcode
+
+ID ranges can be seen in action in the <em>objref</em> dialog section of the
+@sample{xrc}.
+
+@note
+@li All the items in an ID range must be contained in the same XRC file.
+@li You can't use an ID range in a situation where static initialisation
+occurs; in particular, they won't work as expected in an event table. This is
+because the event table's IDs are set to their integer values before the XRC
+file is loaded, and aren't subsequently altered when the XRCID value changes.
+
+@since 2.9.2
+
@section overview_xrcformat_extending Extending the XRC Format
The XRC format is designed to be extensible and allows specifying and loading
friend class wxXmlResourceHandler;
friend class wxXmlResourceModule;
+ friend class wxIdRangeManager;
+ friend class wxIdRange;
static wxXmlSubclassFactories *ms_subclassFactories;
DESTDIR =
WX_RELEASE = 2.9
-WX_VERSION = $(WX_RELEASE).1
+WX_VERSION = $(WX_RELEASE).2
LIBDIRNAME = $(wx_top_builddir)/lib
XRCDEMO_CXXFLAGS = -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) \
$(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) \
xrcdemo_xrcdemo.o \
xrcdemo_myframe.o \
xrcdemo_derivdlg.o \
- xrcdemo_custclas.o
+ xrcdemo_custclas.o \
+ xrcdemo_objrefdlg.o
### Conditionally set variables: ###
data:
@mkdir -p ./rc
- @for f in artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm; do \
+ @for f in artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm; do \
if test ! -f ./rc/$$f -a ! -d ./rc/$$f ; \
then x=yep ; \
else x=`find $(srcdir)/rc/$$f -newer ./rc/$$f -print` ; \
xrcdemo_custclas.o: $(srcdir)/custclas.cpp
$(CXXC) -c -o $@ $(XRCDEMO_CXXFLAGS) $(srcdir)/custclas.cpp
+xrcdemo_objrefdlg.o: $(srcdir)/objrefdlg.cpp
+ $(CXXC) -c -o $@ $(XRCDEMO_CXXFLAGS) $(srcdir)/objrefdlg.cpp
+
# Include dependency info, if present:
@IF_GNU_MAKE@-include ./.deps/*.d
//-----------------------------------------------------------------------------
-// Name: xmldemo.cpp
+// Name: derivdlg.h
// Purpose: XML resources sample: A derived dialog
// Author: Robert O'Connor (rob@medicalmnemonics.com), Vaclav Slavik
// RCS-ID: $Id$
$(OBJS)\xrcdemo_xrcdemo.obj \\r
$(OBJS)\xrcdemo_myframe.obj \\r
$(OBJS)\xrcdemo_derivdlg.obj \\r
- $(OBJS)\xrcdemo_custclas.obj\r
+ $(OBJS)\xrcdemo_custclas.obj \
+ $(OBJS)\xrcdemo_objrefdlg.obj
\r
### Conditionally set variables: ###\r
\r
\r
data: \r
if not exist $(OBJS)\rc mkdir $(OBJS)\rc\r
- for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
+ for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
$(OBJS)\xrcdemo_sample.res: .\..\..\samples\sample.rc
brcc32 -32 -r -fo$@ -i$(BCCDIR)\include -d__WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__NDEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) -i$(SETUPHDIR) -i.\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES_1_p) -i. $(__DLLFLAG_p_1) -i.\..\..\samples -dNOPCH .\..\..\samples\sample.rc
$(OBJS)\xrcdemo_custclas.obj: .\custclas.cpp\r
$(CXX) -q -c -P -o$@ $(XRCDEMO_CXXFLAGS) .\custclas.cpp\r
\r
+$(OBJS)\xrcdemo_objrefdlg.obj: .\objrefdlg.cpp
+ $(CXX) -q -c -P -o$@ $(XRCDEMO_CXXFLAGS) .\objrefdlg.cpp
$(OBJS)\xrcdemo_xrcdemo.o \\r
$(OBJS)\xrcdemo_myframe.o \\r
$(OBJS)\xrcdemo_derivdlg.o \\r
- $(OBJS)\xrcdemo_custclas.o
+ $(OBJS)\xrcdemo_custclas.o \
+ $(OBJS)\xrcdemo_objrefdlg.o
\r
### Conditionally set variables: ###\r
\r
\r
data: \r
if not exist $(OBJS)\rc mkdir $(OBJS)\rc\r
- for %%f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%%f copy .\rc\%%f $(OBJS)\rc
+ for %%f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%%f copy .\rc\%%f $(OBJS)\rc
$(OBJS)\xrcdemo_sample_rc.o: ./../../samples/sample.rc
windres --use-temp-file -i$< -o$@ --define __WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__NDEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) --include-dir $(SETUPHDIR) --include-dir ./../../include $(__CAIRO_INCLUDEDIR_p) --include-dir . $(__DLLFLAG_p_1) --include-dir ./../../samples --define NOPCH
$(OBJS)\xrcdemo_custclas.o: ./custclas.cpp\r
$(CXX) -c -o $@ $(XRCDEMO_CXXFLAGS) $(CPPDEPS) $<\r
\r
+$(OBJS)\xrcdemo_objrefdlg.o: ./objrefdlg.cpp
+ $(CXX) -c -o $@ $(XRCDEMO_CXXFLAGS) $(CPPDEPS) $<
+
.PHONY: all clean data\r
\r
\r
xrcdemo_xrcdemo.o \
xrcdemo_myframe.o \
xrcdemo_derivdlg.o \
- xrcdemo_custclas.o
+ xrcdemo_custclas.o \
+ xrcdemo_objrefdlg.o
### Conditionally set variables: ###
xrcdemo_custclas.o: ./custclas.cpp
$(CXX) -c -o $@ $(XRCDEMO_CXXFLAGS) $(CPPDEPS) $<
+xrcdemo_objrefdlg.o: ./objrefdlg.cpp
+ $(CXX) -c -o $@ $(XRCDEMO_CXXFLAGS) $(CPPDEPS) $<
+
.PHONY: all install uninstall clean
$(OBJS)\xrcdemo_xrcdemo.obj \\r
$(OBJS)\xrcdemo_myframe.obj \\r
$(OBJS)\xrcdemo_derivdlg.obj \\r
- $(OBJS)\xrcdemo_custclas.obj\r
+ $(OBJS)\xrcdemo_custclas.obj \
+ $(OBJS)\xrcdemo_objrefdlg.obj
XRCDEMO_RESOURCES = \\r
$(OBJS)\xrcdemo_sample.res
\r
\r
data: \r
if not exist $(OBJS)\rc mkdir $(OBJS)\rc\r
- for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
+ for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
$(OBJS)\xrcdemo_sample.res: .\..\..\samples\sample.rc
rc /fo$@ /d WIN32 $(____DEBUGRUNTIME_3_p_1) $(__NO_VC_CRTDBG_p_1) /d __WXMSW__ $(__WXUNIV_DEFINE_p_1) $(__DEBUG_DEFINE_p_1) $(__NDEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) $(__UNICODE_DEFINE_p_1) $(__MSLU_DEFINE_p_1) /i $(SETUPHDIR) /i .\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES_1_p) /i . $(__DLLFLAG_p_1) /d _WINDOWS /i .\..\..\samples /d NOPCH .\..\..\samples\sample.rc
$(OBJS)\xrcdemo_custclas.obj: .\custclas.cpp\r
$(CXX) /c /nologo /TP /Fo$@ $(XRCDEMO_CXXFLAGS) .\custclas.cpp\r
\r
+$(OBJS)\xrcdemo_objrefdlg.obj: .\objrefdlg.cpp
+ $(CXX) /c /nologo /TP /Fo$@ $(XRCDEMO_CXXFLAGS) .\objrefdlg.cpp
$(OBJS)\xrcdemo_xrcdemo.obj &\r
$(OBJS)\xrcdemo_myframe.obj &\r
$(OBJS)\xrcdemo_derivdlg.obj &\r
- $(OBJS)\xrcdemo_custclas.obj\r
+ $(OBJS)\xrcdemo_custclas.obj &
+ $(OBJS)\xrcdemo_objrefdlg.obj
\r
\r
all : $(OBJS)\r
\r
data : .SYMBOLIC \r
if not exist $(OBJS)\rc mkdir $(OBJS)\rc\r
- for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
+ for %f in (artprov.xpm artprov.xrc basicdlg.xpm basicdlg.xrc controls.xpm controls.xrc custclas.xpm custclas.xrc derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif resource.xrc toolbar.xrc uncenter.xpm objref.xrc objrefdlg.xpm uncenter.xrc update.gif variable.xpm variable.xrc throbber.gif stop.xpm) do if not exist $(OBJS)\rc\%f copy .\rc\%f $(OBJS)\rc
$(OBJS)\xrcdemo_sample.res : .AUTODEPEND .\..\..\samples\sample.rc
wrc -q -ad -bt=nt -r -fo=$^@ -d__WXMSW__ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) $(__NDEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) $(__THREAD_DEFINE_p) $(__UNICODE_DEFINE_p) -i=$(SETUPHDIR) -i=.\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES) -i=. $(__DLLFLAG_p) -i=.\..\..\samples -dNOPCH $<
$(OBJS)\xrcdemo_custclas.obj : .AUTODEPEND .\custclas.cpp\r
$(CXX) -bt=nt -zq -fo=$^@ $(XRCDEMO_CXXFLAGS) $<\r
\r
+$(OBJS)\xrcdemo_objrefdlg.obj : .AUTODEPEND .\objrefdlg.cpp
+ $(CXX) -bt=nt -zq -fo=$^@ $(XRCDEMO_CXXFLAGS) $<
#include "derivdlg.h"
// Our custom class, for the custom class example.
#include "custclas.h"
+// And our objref dialog, for the object reference and ID range example.
+#include "objrefdlg.h"
// For functions to manipulate our wxTreeCtrl and wxListCtrl
#include "wx/treectrl.h"
#include "wx/listctrl.h"
EVT_MENU(XRCID("derived_tool_or_menuitem"), MyFrame::OnDerivedDialogToolOrMenuCommand)
EVT_MENU(XRCID("controls_tool_or_menuitem"), MyFrame::OnControlsToolOrMenuCommand)
EVT_MENU(XRCID("uncentered_tool_or_menuitem"), MyFrame::OnUncenteredToolOrMenuCommand)
+ EVT_MENU(XRCID("obj_ref_tool_or_menuitem"), MyFrame::OnObjRefToolOrMenuCommand)
EVT_MENU(XRCID("custom_class_tool_or_menuitem"), MyFrame::OnCustomClassToolOrMenuCommand)
EVT_MENU(XRCID("platform_property_tool_or_menuitem"), MyFrame::OnPlatformPropertyToolOrMenuCommand)
EVT_MENU(XRCID("art_provider_tool_or_menuitem"), MyFrame::OnArtProviderToolOrMenuCommand)
}
+void MyFrame::OnObjRefToolOrMenuCommand(wxCommandEvent& WXUNUSED(event))
+{
+ // The dialog redirects log messages, so save the old log target first
+ wxLog* oldlogtarget = wxLog::SetActiveTarget(NULL);
+
+ // Make an instance of the dialog
+ ObjrefDialog* objrefDialog = new ObjrefDialog(this);
+ // Show the instance of the dialog, modally.
+ objrefDialog->ShowModal();
+ objrefDialog->Destroy();
+
+ // Restore the old log target
+ delete wxLog::SetActiveTarget(oldlogtarget);
+}
+
+
void MyFrame::OnCustomClassToolOrMenuCommand(wxCommandEvent& WXUNUSED(event))
{
wxDialog dlg;
void OnDerivedDialogToolOrMenuCommand(wxCommandEvent& event);
void OnControlsToolOrMenuCommand(wxCommandEvent& event);
void OnUncenteredToolOrMenuCommand(wxCommandEvent& event);
+ void OnObjRefToolOrMenuCommand(wxCommandEvent& event);
void OnCustomClassToolOrMenuCommand(wxCommandEvent& event);
void OnPlatformPropertyToolOrMenuCommand(wxCommandEvent& event);
void OnArtProviderToolOrMenuCommand(wxCommandEvent& event);
--- /dev/null
+//-----------------------------------------------------------------------------
+// Name: objref.cpp
+// Purpose: XML resources sample: Object references and ID ranges dialog
+// Author: David Hart, Vaclav Slavik
+// RCS-ID: $Id$
+// Copyright: (c) Vaclav Slavik
+// Licence: wxWindows licence
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Standard wxWidgets 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 (this file is usually all you
+// need because it includes almost all "standard" wxWidgets headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+//-----------------------------------------------------------------------------
+// Header of this .cpp file
+//-----------------------------------------------------------------------------
+
+#include "objrefdlg.h"
+
+//-----------------------------------------------------------------------------
+// Remaining headers: Needed wx headers, then wx/contrib headers, then application headers
+//-----------------------------------------------------------------------------
+
+#include "wx/xrc/xmlres.h" // XRC XML resouces
+
+
+
+//-----------------------------------------------------------------------------
+// Public members
+//-----------------------------------------------------------------------------
+ObjrefDialog::ObjrefDialog(wxWindow* parent)
+{
+ wxXmlResource::Get()->LoadDialog(this, parent, wxT("objref_dialog"));
+
+ nb = XRCCTRL(*this, "objref_notebook", wxNotebook);
+ wxCHECK_RET(nb, "failed to find objref_notebook");
+ nb->Bind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &ObjrefDialog::OnNotebookPageChanged, this);
+ iconspage_bound = false;
+ calcpage_bound = false;
+}
+
+ObjrefDialog::~ObjrefDialog()
+{
+ // Select page 0. Otherwise if the Calc page were selected, when it's removed the Icons page is selected
+ // and sets the log target again in idle time, *after* myframe restores the old one!
+ nb->ChangeSelection(0);
+}
+
+//-----------------------------------------------------------------------------
+// Private members (including the event handlers)
+//-----------------------------------------------------------------------------
+void ObjrefDialog::OnNotebookPageChanged( wxNotebookEvent &event )
+{
+ switch(event.GetSelection())
+ {
+ case copy_page:
+ {
+ // This is a straight object reference to the first page
+ // so change the text programmatically
+ nb->SetPageText(copy_page, "Page 1 copy");
+
+ wxNotebookPage *page = nb->GetPage(copy_page);
+ wxTextCtrl *text = XRCCTRL(*page, "description_text", wxTextCtrl);
+ text->ChangeValue(
+ wxString("This is a duplicate of page 1, using an object reference. ")
+ + wxString("It was created by this very simple xml:\n\n")
+ + wxString("<object class=\"notebookpage\">\n\t<object_ref ref=\"page1\"/>\n")
+ + wxString("\t<label>Page 1 copy</label>\n</object>")
+ + wxString("\n\n(Then I'm cheating by inserting this text programmatically.)")
+ );
+ break;
+ }
+
+ case icons_page:
+ {
+ wxNotebookPage *page = nb->GetPage(icons_page);
+ if (!iconspage_bound)
+ {
+ iconspage_bound = true;
+ // We want to direct UpdateUI events for the ID range 'first_row' to OnUpdateUIFirst().
+ // We could achieve this using first_row[0] and first_row[2], but what if a fourth
+ // column were added? It's safer to use the 'typedefs' for the two ends of the range:
+ page->Bind(wxEVT_UPDATE_UI, &ObjrefDialog::OnUpdateUIFirst,
+ this, XRCID("first_row[start]"), XRCID("first_row[end]"));
+ // Similarly for the other two rows
+ page->Bind(wxEVT_UPDATE_UI, &ObjrefDialog::OnUpdateUISecond,
+ this, XRCID("second_row[start]"), XRCID("second_row[end]"));
+ page->Bind(wxEVT_UPDATE_UI, &ObjrefDialog::OnUpdateUIThird,
+ this, XRCID("third_row[start]"), XRCID("third_row[end]"));
+
+ }
+
+ text = XRCCTRL(*page, "log_text", wxTextCtrl);
+ if (text)
+ delete wxLog::SetActiveTarget(new wxLogTextCtrl(text));
+ break;
+ }
+
+ case calc_page:
+ {
+ wxNotebookPage *page = nb->GetPage(calc_page);
+ if (!calcpage_bound)
+ {
+ calcpage_bound = true;
+ // Bind the id ranges, using the [start] and [end] 'typedefs'
+ page->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ObjrefDialog::OnNumeralClick,
+ this, XRCID("digits[start]"), XRCID("digits[end]"));
+ page->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ObjrefDialog::OnOperatorClick,
+ this, XRCID("operators[start]"), XRCID("operators[end]"));
+ }
+
+ result_txt = XRCCTRL(*page, "result", wxTextCtrl);
+ text = XRCCTRL(*page, "log_text", wxTextCtrl);
+ if (text)
+ delete wxLog::SetActiveTarget(new wxLogTextCtrl(text));
+
+ ClearCalculator();
+ break;
+ }
+
+ default: return;
+ }
+}
+
+// There are undoubtedly simpler ways of doing all this, but we're demonstrating the use of ID ranges
+void ObjrefDialog::OnUpdateUIFirst(wxUpdateUIEvent& event)
+{
+ // The checkbox with the XRCID 'check[0]' controls this row of icons
+ wxCheckBox *chk = XRCCTRL(*(nb->GetPage(icons_page)), "check[0]", wxCheckBox);
+ if (chk)
+ event.Enable(chk->IsChecked());
+
+ // Let's create a log-window entry
+ static bool checked = true;
+ if (chk->IsChecked() != checked)
+ {
+ checked = chk->IsChecked();
+ wxLogMessage("Row one has been %s by check[0], XRCID = %i", checked ? "enabled" : "disabled", XRCID("check[0]"));
+ wxLogMessage("XRCIDs: first_row[start] = %i, first_row[0] = %i, first_row[1] = %i, first_row[2] = %i, first_row[end] = %i",
+ XRCID("first_row[start]"), XRCID("first_row[0]"), XRCID("first_row[1]"), XRCID("first_row[2]"), XRCID("first_row[end]"));
+ }
+}
+
+void ObjrefDialog::OnUpdateUISecond(wxUpdateUIEvent& event)
+{
+ // The checkbox with the XRCID 'check[1]' controls this row of icons
+ wxCheckBox *chk = XRCCTRL(*(nb->GetPage(icons_page)), "check[1]", wxCheckBox);
+ if (chk)
+ event.Enable(chk->IsChecked());
+
+ // Let's create a log-window entry
+ static bool checked = true;
+ if (chk->IsChecked() != checked)
+ {
+ checked = chk->IsChecked();
+ wxLogMessage("Row two has been %s by check[1], XRCID = %i", checked ? "enabled" : "disabled", XRCID("check[1]"));
+ wxLogMessage("XRCIDs: second_row[start] = %i, second_row[0] = %i, second_row[1] = %i, second_row[2] = %i, second_row[end] = %i",
+ XRCID("second_row[start]"), XRCID("second_row[0]"), XRCID("second_row[1]"), XRCID("second_row[2]"), XRCID("second_row[end]"));
+ }
+}
+
+void ObjrefDialog::OnUpdateUIThird(wxUpdateUIEvent& event)
+{
+ // The checkbox with the XRCID 'check[2]' controls this row of icons
+ wxCheckBox *chk = XRCCTRL(*(nb->GetPage(icons_page)), "check[2]", wxCheckBox);
+ if (chk)
+ event.Enable(chk->IsChecked());
+
+ // Let's create a log-window entry
+ static bool checked = true;
+ if (chk->IsChecked() != checked)
+ {
+ checked = chk->IsChecked();
+ wxLogMessage("Row three has been %s by check[2], XRCID = %i", checked ? "enabled" : "disabled", XRCID("check[2]"));
+ wxLogMessage("XRCIDs: third_row[start] = %i, third_row[0] = %i, third_row[1] = %i, third_row[2] = %i, third_row[end] = %i",
+ XRCID("third_row[start]"), XRCID("third_row[0]"), XRCID("third_row[1]"), XRCID("third_row[2]"), XRCID("third_row[end]"));
+ }
+}
+
+void ObjrefDialog::OnNumeralClick(wxCommandEvent& event)
+{
+ // See how the id range simplifies determining which numeral was clicked
+ int digit = event.GetId() - XRCID("digits[start]");
+
+ char c = '0' + digit;
+ if (current==0 && previous==0)
+ {
+ // We're just starting a calculation, so get rid of the placeholder '0'
+ result_txt->Clear();
+ }
+ else if (operator_expected == true)
+ {
+ // If we've just finished one calculation, and now a digit is entered, clear
+ ClearCalculator();
+ result_txt->Clear();
+ }
+ (*result_txt) << c;
+
+
+ current = current*10 + digit;
+
+ wxLogMessage("You clicked digits[%c], XRCID %i", c, event.GetId());
+}
+
+void ObjrefDialog::OnOperatorClick(wxCommandEvent& event)
+{
+ static const char symbols[] = "+-*/=";
+
+ operator_expected = false;
+ int ID = event.GetId() - XRCID("operators[start]");
+
+ // We carefully used "operators[end]" as the name of the Clear button
+ if (event.GetId() == XRCID("operators[end]"))
+ {
+ wxLogMessage("You clicked operators[%i], XRCID %i, 'Clear'", ID, event.GetId());
+ return ClearCalculator();
+ }
+
+ switch(ID)
+ {
+ case operator_plus:
+ case operator_minus:
+ case operator_multiply:
+ case operator_divide:
+ if (current!=0 || previous!=0)
+ {
+ // We're in the middle of a complex calculation, so do the first bit
+ Calculate();
+ }
+ curr_operator = (CalcOperator)ID;
+ break;
+
+ case operator_equals:
+ Calculate();
+ wxLogMessage("You clicked operators[%i], XRCID %i, giving a '%c'", ID, event.GetId(), symbols[ID]);
+ curr_operator = operator_equals;
+ // Flag that the next entry should be an operator, not a digit
+ operator_expected = true;
+ return;
+ }
+
+ (*result_txt) << ' ' << symbols[ID] << ' ';
+
+ wxLogMessage("You clicked operators[%i], XRCID %i, giving a '%c'", ID, event.GetId(), symbols[ID]);
+}
+
+void ObjrefDialog::Calculate()
+{
+ switch(curr_operator)
+ {
+ case operator_plus:
+ previous += current; break;
+ case operator_minus:
+ previous -= current; break;
+ case operator_multiply:
+ previous *= current; break;
+ case operator_divide:
+ if (current!=0)
+ previous /= current;
+ break;
+ default: return;
+ }
+
+ curr_operator = operator_plus;
+ current = 0;
+ result_txt->Clear();
+
+ (*result_txt) << previous;
+}
+
+void ObjrefDialog::ClearCalculator()
+{
+ current = previous = 0;
+ curr_operator = operator_plus;
+ operator_expected = false;
+ result_txt->ChangeValue("0");
+}
--- /dev/null
+//-----------------------------------------------------------------------------
+// Name: objref.h
+// Purpose: XML resources sample: Object references and ID ranges dialog
+// Author: David Hart, Vaclav Slavik
+// RCS-ID: $Id$
+// Copyright: (c) Vaclav Slavik
+// Licence: wxWindows licence
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Begin single inclusion of this .h file condition
+//-----------------------------------------------------------------------------
+
+#ifndef _OBJREFDLG_H_
+#define _OBJREFDLG_H_
+
+//-----------------------------------------------------------------------------
+// Headers
+//-----------------------------------------------------------------------------
+
+#include "wx/dialog.h"
+#include "wx/notebook.h"
+
+//-----------------------------------------------------------------------------
+// Class definition: ObjrefDialog
+//-----------------------------------------------------------------------------
+
+class ObjrefDialog : public wxDialog
+{
+
+public:
+
+ // Constructor.
+ ObjrefDialog( wxWindow* parent );
+
+ // Destructor.
+ ~ObjrefDialog();
+
+private:
+ enum PageNumbers { first_page, copy_page, icons_page, calc_page };
+ enum CalcOperator { operator_plus, operator_minus, operator_multiply, operator_divide, operator_equals };
+
+ void OnNotebookPageChanged( wxNotebookEvent &event );
+ void OnUpdateUIFirst(wxUpdateUIEvent& event);
+ void OnUpdateUISecond(wxUpdateUIEvent& event);
+ void OnUpdateUIThird(wxUpdateUIEvent& event);
+ void OnNumeralClick(wxCommandEvent& event);
+ void OnOperatorClick(wxCommandEvent& event);
+ void Calculate();
+ void ClearCalculator();
+
+ wxNotebook *nb;
+ wxTextCtrl *text;
+ wxTextCtrl *result_txt;
+ bool iconspage_bound;
+ bool calcpage_bound;
+ int current;
+ int previous;
+ bool operator_expected;
+ CalcOperator curr_operator;
+
+};
+
+#endif //_OBJREFDLG_H_
<object class="wxMenu" name="advanced_demos_menu">
<label>_Advanced</label>
<help>Advanced techniques with XRC</help>
+ <object class="wxMenuItem" name="obj_ref_tool_or_menuitem">
+ <label>_Object References Example</label>
+ <bitmap>objrefdlg.xpm</bitmap>
+ <help>Use of object references and event ranges</help>
+ </object>
<object class="wxMenuItem" name="custom_class_tool_or_menuitem">
<label>_Custom Class Example</label>
<bitmap>custclas.xpm</bitmap>
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<resource version="2.3.0.1" xmlns="http://www.wxwidgets.org/wxxrc">
+ <object class="wxDialog" name="objref_dialog">
+ <object class="wxFlexGridSizer">
+ <object class="sizeritem">
+ <object class="wxNotebook" name="objref_notebook">
+ <object class="notebookpage">
+ <object class="wxPanel" name="page1">
+ <object class="wxFlexGridSizer">
+ <object class="sizeritem">
+ <object class="wxTextCtrl" name="description_text">
+ <value>This dialog demonstrates the use of object references and ID arrays.\n\nAs you turn the pages of the notebook, you will notice that each has an identical section at the bottom. Instead of writing that section's xml several times, this is done just once, as a wxPanel named 'bottom__panel'. The panel is then added to each page's sizer by the single line: <object__ref ref="bottom__panel"/></value>
+ <style>wxTE_MULTILINE|wxTE_READONLY</style>
+ </object>
+ <option>1</option>
+ <flag>wxALL|wxEXPAND</flag>
+ <border>5</border>
+ </object>
+ <object class="sizeritem">
+ <object_ref ref="bottom_panel"/>
+ <flag>wxEXPAND</flag>
+ </object>
+ <cols>1</cols>
+ <rows>0</rows>
+ <vgap>0</vgap>
+ <hgap>10</hgap>
+ <growablecols>0</growablecols>
+ <growablerows>0</growablerows>
+ <growablerows>1</growablerows>
+ </object>
+ </object>
+ <label>Page 1</label>
+ </object>
+ <object class="notebookpage">
+ <object_ref ref="page1"/>
+ <label>Page 1 copy</label>
+ </object>
+ <object class="notebookpage">
+ <object class="wxPanel" name="page2">
+ <object class="wxFlexGridSizer">
+ <object class="sizeritem">
+ <object class="wxTextCtrl" name="description_text">
+ <value>ID ranges are a way to simplify the management of several similar controls, especially their event-handling.\nAn ID range is declared by putting something like this into the XRC file:\n <ids-range name="check" size="3" start="10000" />\n'size' and 'start' being optional.\n\nIf you then give an item the name 'check[2]', it will be allocated that ID in the range.\n\nBy default the IDs in a range are negative, being assigned by wxWindow::NewControlId. If you wish, you can specify the start of the range; if so, the IDs *must* be positive (and it's your responsibility to avoid clashes, so start above wxID__HIGHEST).</value>
+ <style>wxTE_MULTILINE|wxTE_READONLY</style>
+ </object>
+ <option>1</option>
+ <flag>wxALL|wxEXPAND</flag>
+ <border>5</border>
+ </object>
+ <object class="sizeritem">
+ <object class="wxBoxSizer">
+ <object class="spacer">
+ <option>1</option>
+ <flag>wxLEFT</flag>
+ <border>100</border>
+ </object>
+ <object class="sizeritem">
+ <object class="wxBoxSizer">
+ <object class="sizeritem">
+ <object class="wxStaticText">
+ <label>Uncheck to disable a row</label>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object_ref ref="checkboxes"/>
+ <flag>wxALIGN_CENTRE</flag>
+ </object>
+ <orient>wxVERTICAL</orient>
+ </object>
+ <flag>wxALIGN_CENTRE_VERTICAL</flag>
+ </object>
+ <orient>wxHORIZONTAL</orient>
+ <object class="spacer">
+ <size>50,-1</size>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBoxSizer">
+ <object class="sizeritem">
+ <object class="wxGridSizer">
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="first_row[0]">
+ <bitmap>update.gif</bitmap>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="first_row[1]">
+ <bitmap>basicdlg.xpm</bitmap>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="first_row[2]">
+ <bitmap>controls.xpm</bitmap>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="second_row[0]">
+ <bitmap>custclas.xpm</bitmap>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="second_row[1]">
+ <bitmap>derivdlg.xpm</bitmap>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="second_row[2]">
+ <bitmap>platform.xpm</bitmap>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="third_row[0]">
+ <bitmap>objrefdlg.xpm</bitmap>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="third_row[1]">
+ <bitmap>uncenter.xpm</bitmap>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBitmap" name="third_row[2]">
+ <bitmap>variable.xpm</bitmap>
+ </object>
+ </object>
+ <rows>3</rows>
+ <vgap>7</vgap>
+ <hgap>7</hgap>
+ </object>
+ <flag>wxALL</flag>
+ <border>3</border>
+ </object>
+ <label>Icons</label>
+ <orient>wxVERTICAL</orient>
+ </object>
+ <flag>wxALIGN_CENTRE_VERTICAL</flag>
+ </object>
+ <object class="spacer">
+ <option>1</option>
+ <flag>wxLEFT</flag>
+ <border>100</border>
+ </object>
+ </object>
+ <flag>wxTOP|wxBOTTOM|wxEXPAND</flag>
+ <border>15</border>
+ </object>
+ <object class="sizeritem">
+ <object_ref ref="bottom_panel"/>
+ <option>1</option>
+ <flag>wxEXPAND</flag>
+ </object>
+ <cols>1</cols>
+ <rows>0</rows>
+ <vgap>0</vgap>
+ <hgap>10</hgap>
+ <growablecols>0</growablecols>
+ <growablerows>0</growablerows>
+ <growablerows>2</growablerows>
+ </object>
+ </object>
+ <label>Icons</label>
+ </object>
+ <object class="notebookpage">
+ <object class="wxPanel" name="page3">
+ <object class="wxFlexGridSizer">
+ <object class="sizeritem">
+ <object class="wxTextCtrl" name="description_text">
+ <value>This not very useful calculator demonstrates some features of ID ranges. One range is defined for the number keys, and another for the operators.\n\nIf you look at the .xrc file, you'll see that I wrote:\n <ids-range name="digits" size="8"/>\ncreating that range with a size of 8 (I must have forgotten to count my thumbs). The code will still work, though: the actual number of range items is counted when the file is loaded, and the range extended if necessary to accommodate them. However if the size is too big, it isn't truncated.\n\nAn ID range always has the special items defined: <rangename>[start] and <rangename>[end]. So, for the range 'digits', digits[start] == digits[0], and digits[end] == digits[9]. [end] will always refer to the end of the range, even if there's no object with that ID.\n\nThe digits of the calculator are named 'digits[0]' to 'digits[9]'. Adjacent range items are guaranteed to be assigned consecutive IDs, so code such as this will work as expected:\n for (int n=XRCID("digits[start]"); n < XRCID("digits[end]"); ++n) { DoFoo(n); }\nor\n int index = event.GetId() - XRCID("digits[0]");</value>
+ <style>wxTE_MULTILINE|wxTE_READONLY</style>
+ </object>
+ <option>1</option>
+ <flag>wxALL|wxEXPAND</flag>
+ <border>5</border>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticBoxSizer">
+ <object class="sizeritem">
+ <object class="wxGridBagSizer">
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[7]">
+ <label>7</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>0,0</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[8]">
+ <label>8</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>0,1</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[9]">
+ <label>9</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>0,2</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="operators[3]">
+ <label>/</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>0,3</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[4]">
+ <label>4</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>1,0</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[5]">
+ <label>5</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>1,1</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[6]">
+ <label>6</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>1,2</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="operators[2]">
+ <label>X</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>1,3</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[1]">
+ <label>1</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>2,0</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[2]">
+ <label>2</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>2,1</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[3]">
+ <label>3</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>2,2</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="operators[1]">
+ <label>-</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>2,3</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="digits[0]">
+ <label>0</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>3,0</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="operators[4]">
+ <label>=</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>3,1</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="operators[end]">
+ <label>Cl</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>3,2</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="operators[0]">
+ <label>+</label>
+ <style>wxBU_EXACTFIT</style>
+ </object>
+ <flag>wxEXPAND</flag>
+ <cellpos>3,3</cellpos>
+ </object>
+ <object class="sizeritem">
+ <object class="wxTextCtrl" name="result"/>
+ <flag>wxEXPAND</flag>
+ <cellpos>4,0</cellpos>
+ <cellspan>1,4</cellspan>
+ </object>
+ <vgap>5</vgap>
+ <hgap>5</hgap>
+ </object>
+ <flag>wxALL</flag>
+ <border>5</border>
+ </object>
+ <label>Calculator</label>
+ <orient>wxVERTICAL</orient>
+ </object>
+ <flag>wxTOP|wxALIGN_CENTRE_HORIZONTAL</flag>
+ <border>10</border>
+ </object>
+ <object class="sizeritem">
+ <object_ref ref="bottom_panel"/>
+ <option>1</option>
+ <flag>wxEXPAND</flag>
+ </object>
+ <cols>1</cols>
+ <rows>0</rows>
+ <vgap>0</vgap>
+ <hgap>10</hgap>
+ <growablecols>0</growablecols>
+ <growablerows>0</growablerows>
+ <growablerows>2</growablerows>
+ </object>
+ </object>
+ <label>Calc</label>
+ </object>
+ </object>
+ <option>1</option>
+ <flag>wxGROW|wxALIGN_CENTER_VERTICAL|wxALL</flag>
+ <border>5</border>
+ </object>
+ <object class="sizeritem">
+ <object class="wxButton" name="wxID_OK">
+ <label>OK</label>
+ <default>1</default>
+ </object>
+ <flag>wxTOP|wxBOTTOM|wxALIGN_CENTRE</flag>
+ <border>20</border>
+ </object>
+ <cols>1</cols>
+ <rows>0</rows>
+ <vgap>0</vgap>
+ <hgap>0</hgap>
+ <growablecols>0</growablecols>
+ <growablerows>0</growablerows>
+ </object>
+ <title>Object References and ID Ranges Example</title>
+ <centered>1</centered>
+ <style>wxCAPTION|wxSYSTEM_MENU|wxRESIZE_BORDER</style>
+ <exstyle>wxDIALOG_EX_CONTEXTHELP</exstyle>
+ </object>
+ <object class="wxPanel" name="bottom_panel">
+ <object class="wxBoxSizer">
+ <orient>wxVERTICAL</orient>
+ <object class="sizeritem">
+ <object class="wxStaticLine">
+ <style>wxLI_HORIZONTAL</style>
+ </object>
+ <flag>wxTOP|wxEXPAND</flag>
+ <border>20</border>
+ </object>
+ <object class="sizeritem">
+ <object class="wxStaticText">
+ <label>Log window:</label>
+ </object>
+ <flag>wxTOP</flag>
+ <border>5</border>
+ </object>
+ <object class="sizeritem">
+ <object class="wxTextCtrl" name="log_text">
+ <size>-1,100</size>
+ <style>wxTE_MULTILINE</style>
+ </object>
+ <option>1</option>
+ <flag>wxEXPAND</flag>
+ </object>
+ </object>
+ </object>
+ <object class="wxPanel" name="checkboxes">
+ <object class="wxBoxSizer">
+ <orient>wxVERTICAL</orient>
+ <object class="sizeritem">
+ <object class="wxCheckBox" name="check[0]">
+ <checked>1</checked>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxCheckBox" name="check[1]">
+ <checked>1</checked>
+ </object>
+ </object>
+ <object class="sizeritem">
+ <object class="wxCheckBox" name="check[2]">
+ <checked>1</checked>
+ </object>
+ </object>
+ </object>
+ </object>
+ <ids-range name="check" size="3" start="10000"/>
+ <ids-range name="first_row"/>
+ <ids-range name="second_row"/>
+ <ids-range name="third_row"/>
+ <ids-range name="digits" size="8"/>
+ <ids-range name="operators"/>
+</resource>
--- /dev/null
+/* XPM */
+static const char *const objrefdlg_xpm[] = {
+"16 16 7 1",
+" c None",
+". c #EBF70E",
+"+ c #000000",
+"@ c #808080",
+"# c #0000FF",
+"$ c #FFFFFF",
+"% c #F8A836",
+" . ",
+"+++.++++++++++++",
+"+.@.@.@@@@@@.@@+",
+"+@...#######.#@+",
+"...@....@@.@.@.+",
+"+@...$$$$$$...@+",
+"+.$.@.@@@%%%$%..",
+"+@$.@@@@@@@%%%@+",
+"+@$.$$$$$$%$%$%+",
+"+@$$$$$$$$$$%$@+",
+"+@$$$$@@@@$$$$@+",
+"+@$$$$@@@@$$$$@+",
+"+@$$$$$$$$$$$$@+",
+"+@@@@@@@@@@@@@@+",
+"++++++++++++++++",
+" "};
<longhelp>Disable autocentering of a dialog on its parent</longhelp>
</object>
<object class="separator"/>
+ <object class="tool" name="obj_ref_tool_or_menuitem">
+ <bitmap>objrefdlg.xpm</bitmap>
+ <tooltip>Object references and event ranges example</tooltip>
+ <longhelp>Use of object references and event ranges</longhelp>
+ </object>
<object class="tool" name="custom_class_tool_or_menuitem">
<tooltip>Custom Class Example</tooltip>
<bitmap>custclas.xpm</bitmap>
myframe.cpp
derivdlg.cpp
custclas.cpp
+ objrefdlg.cpp
</sources>
<headers>
derivdlg.h
xrcdemo.h
myframe.h
custclas.h
+ objrefdlg.h
</headers>
<wx-lib>xrc</wx-lib>
<wx-lib>html</wx-lib>
derivdlg.xpm derivdlg.xrc fileopen.gif filesave.gif frame.xrc
fuzzy.gif menu.xrc platform.xpm platform.xrc quotes.gif
resource.xrc toolbar.xrc uncenter.xpm
+ objref.xrc objrefdlg.xpm
uncenter.xrc update.gif variable.xpm variable.xrc
throbber.gif stop.xpm
</files>
return false;
// If there is any of a certain format of image in the xrcs, then first
- // load a handler for that image type. This example uses XPMs, but if
- // you want PNGs, then add a PNG handler, etc. See wxImage::AddHandler()
+ // load a handler for that image type. This example uses XPMs & a gif, but
+ // if you want PNGs, then add a PNG handler, etc. See wxImage::AddHandler()
// documentation for the types of image handlers available.
wxImage::AddHandler(new wxXPMHandler);
+ wxImage::AddHandler(new wxGIFHandler);
// Initialize all the XRC handlers. Always required (unless you feel like
// going through and initializing a handler of each control type you will
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\..\..\samples\sample.rc
+SOURCE=.\objrefdlg.cpp
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\..\..\samples\sample.rc
+# End Source File
+# Begin Source File
+
SOURCE=.\xrcdemo.cpp
# End Source File\r
# End Group\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\objrefdlg.h
+# End Source File
+# Begin Source File
+
SOURCE=.\xrcdemo.h\r
# End Source File\r
# End Group\r
//-----------------------------------------------------------------------------
-// Name: xmldemo.cpp
+// Name: xmldemo.h
// Purpose: XML resources sample: Main application file
// Author: Robert O'Connor (rob@medicalmnemonics.com), Vaclav Slavik
// RCS-ID: $Id$
RelativePath=".\myframe.cpp">\r
</File>\r
<File\r
+ RelativePath=".\objrefdlg.cpp">
+ </File>
+ <File
RelativePath=".\xrcdemo.cpp">\r
</File>\r
</Filter>\r
RelativePath=".\myframe.h">\r
</File>\r
<File\r
+ RelativePath=".\objrefdlg.h">
+ </File>
+ <File
RelativePath=".\xrcdemo.h">\r
</File>\r
</Filter>\r
>\r
</File>\r
<File\r
+ RelativePath=".\objrefdlg.cpp"
+ >
+ </File>
+ <File
RelativePath=".\xrcdemo.cpp"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\objrefdlg.h"
+ >
+ </File>
+ <File
RelativePath=".\xrcdemo.h"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\objrefdlg.cpp"
+ >
+ </File>
+ <File
RelativePath=".\xrcdemo.cpp"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\objrefdlg.h"
+ >
+ </File>
+ <File
RelativePath=".\xrcdemo.h"\r
>\r
</File>\r
#include "wx/imaglist.h"
#include "wx/dir.h"
#include "wx/xml/xml.h"
+#include "wx/hashset.h"
class wxXmlResourceDataRecord
// this is a class so that it can be forward-declared
};
+WX_DECLARE_HASH_SET(int, wxIntegerHash, wxIntegerEqual, wxHashSetInt);
+
+class wxIdRange // Holds data for a particular rangename
+{
+protected:
+ wxIdRange(const wxXmlNode* node,
+ const wxString& rname,
+ const wxString& startno,
+ const wxString& rsize);
+
+ // Note the existence of an item within the range
+ void NoteItem(const wxXmlNode* node, const wxString& item);
+
+ // The manager is telling us that it's finished adding items
+ void Finalise(const wxXmlNode* node);
+
+ wxString GetName() const { return m_name; }
+ bool IsFinalised() const { return m_finalised; }
+
+ const wxString m_name;
+ int m_start;
+ int m_end;
+ unsigned int m_size;
+ bool m_item_end_found;
+ bool m_finalised;
+ wxHashSetInt m_indices;
+
+ friend class wxIdRangeManager;
+};
+
+class wxIdRangeManager
+{
+public:
+ ~wxIdRangeManager();
+ // Gets the global resources object or creates one if none exists.
+ static wxIdRangeManager *Get();
+
+ // Sets the global resources object and returns a pointer to the previous
+ // one (may be NULL).
+ static wxIdRangeManager *Set(wxIdRangeManager *res);
+
+ // Create a new IDrange from this node
+ void AddRange(const wxXmlNode* node);
+ // Tell the IdRange that this item exists, and should be pre-allocated an ID
+ void NotifyRangeOfItem(const wxXmlNode* node, const wxString& item) const;
+ // Tells all IDranges that they're now complete, and can create their IDs
+ void FinaliseRanges(const wxXmlNode* node) const;
+ // Searches for a known IdRange matching 'name', returning its index or -1
+ int Find(const wxString& rangename) const;
+ // Removes, if it exists, an entry from the XRCID table. Used in id-ranges
+ // to replace defunct or statically-initialised entries with current values
+ static void RemoveXRCIDEntry(const char *str_id);
+
+protected:
+ wxIdRange* FindRangeForItem(const wxXmlNode* node,
+ const wxString& item,
+ wxString& value) const;
+ wxVector<wxIdRange*> m_IdRanges;
+
+private:
+ static wxIdRangeManager *ms_instance;
+};
+
namespace
{
}
}
+static void PreprocessForIdRanges(wxXmlNode *rootnode)
+{
+ // First go through the top level, looking for the names of ID ranges
+ // as processing items is a lot easier if names are already known
+ wxXmlNode *c = rootnode->GetChildren();
+ while (c)
+ {
+ if (c->GetName() == wxT("ids-range"))
+ wxIdRangeManager::Get()->AddRange(c);
+ c = c->GetNext();
+ }
+
+ // Next, examine every 'name' for the '[' that denotes an ID in a range
+ c = rootnode->GetChildren();
+ while (c)
+ {
+ wxString name = c->GetAttribute(wxT("name"));
+ if (name.find('[') != wxString::npos)
+ wxIdRangeManager::Get()->NotifyRangeOfItem(rootnode, name);
+ // Do any children by recursion, then proceed to the next sibling
+ PreprocessForIdRanges(c);
+ c = c->GetNext();
+ }
+}
bool wxXmlResource::UpdateResources()
{
}
ProcessPlatformProperty(rec->Doc->GetRoot());
+ PreprocessForIdRanges(rec->Doc->GetRoot());
+ wxIdRangeManager::Get()->FinaliseRanges(rec->Doc->GetRoot());
#if wxUSE_DATETIME
#if wxUSE_FILESYSTEM
rec->Time = file->GetModificationTime();
bool recursive,
wxString *path) const
{
- // ensure everything is up-to-date: this is needed to support on-remand
+ // ensure everything is up-to-date: this is needed to support on-demand
// reloading of XRC files
const_cast<wxXmlResource *>(this)->UpdateResources();
return NULL;
}
+wxIdRange::wxIdRange(const wxXmlNode* node,
+ const wxString& rname,
+ const wxString& startno,
+ const wxString& rsize)
+ : m_name(rname),
+ m_start(0),
+ m_size(0),
+ m_item_end_found(0),
+ m_finalised(0)
+{
+ long l;
+ if ( startno.ToLong(&l) )
+ {
+ if ( l >= 0 )
+ {
+ m_start = l;
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "a negative id-range start parameter was given"
+ );
+ }
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "the id-range start parameter was malformed"
+ );
+ }
+
+ unsigned long ul;
+ if ( rsize.ToULong(&ul) )
+ {
+ m_size = ul;
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "the id-range size parameter was malformed"
+ );
+ }
+}
+
+void wxIdRange::NoteItem(const wxXmlNode* node, const wxString& item)
+{
+ // Nothing gets added here, but the existence of each item is noted
+ // thus getting an accurate count. 'item' will be either an integer e.g.
+ // [0] [123]: will eventually create an XRCID as start+integer or [start]
+ // or [end] which are synonyms for [0] or [range_size-1] respectively.
+ wxString content(item.Mid(1, item.length()-2));
+
+ // Check that basename+item wasn't foo[]
+ if (content.empty())
+ {
+ wxXmlResource::Get()->ReportError(node, "an empty id-range item found");
+ return;
+ }
+
+ if (content=="start")
+ {
+ // "start" means [0], so store that in the set
+ if (m_indices.count(0) == 0)
+ {
+ m_indices.insert(0);
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "duplicate id-range item found"
+ );
+ }
+ }
+ else if (content=="end")
+ {
+ // We can't yet be certain which XRCID this will be equivalent to, so
+ // just note that there's an item with this name, in case we need to
+ // inc the range size
+ m_item_end_found = true;
+ }
+ else
+ {
+ // Anything else will be an integer, or rubbish
+ unsigned long l;
+ if ( content.ToULong(&l) )
+ {
+ if (m_indices.count(l) == 0)
+ {
+ m_indices.insert(l);
+ // Check that this item wouldn't fall outside the current range
+ // extent
+ if (l >= m_size)
+ {
+ m_size = l + 1;
+ }
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "duplicate id-range item found"
+ );
+ }
+
+ }
+ else
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "an id-range item had a malformed index"
+ );
+ }
+ }
+}
+
+void wxIdRange::Finalise(const wxXmlNode* node)
+{
+ wxCHECK_RET( !IsFinalised(),
+ "Trying to finalise an already-finalised range" );
+
+ // Now we know about all the items, we can get an accurate range size
+ // Expand any requested range-size if there were more items than would fit
+ m_size = wxMax(m_size, m_indices.size());
+
+ // If an item is explicitly called foo[end], ensure it won't clash with
+ // another item
+ if ( m_item_end_found && m_indices.count(m_size-1) )
+ ++m_size;
+ if (m_size == 0)
+ {
+ // This will happen if someone creates a range but no items in this xrc
+ // file Report the error and abort, but don't finalise, in case items
+ // appear later
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "trying to create an empty id-range"
+ );
+ return;
+ }
+
+ if (m_start==0)
+ {
+ // This is the usual case, where the user didn't specify a start ID
+ // So get the range using NewControlId().
+ //
+ // NB: negative numbers, but NewControlId already returns the most
+ // negative
+ m_start = wxWindow::NewControlId(m_size);
+ wxCHECK_RET( m_start != wxID_NONE,
+ "insufficient IDs available to create range" );
+ m_end = m_start + m_size - 1;
+ }
+ else
+ {
+ // The user already specified a start value, which must be positive
+ m_end = m_start + m_size - 1;
+ }
+
+ // Create the XRCIDs
+ for (int i=m_start; i <= m_end; ++i)
+ {
+ // First clear any pre-existing XRCID
+ // Necessary for wxXmlResource::Unload() followed by Load()
+ wxIdRangeManager::RemoveXRCIDEntry(
+ m_name + wxString::Format("[%i]", i-m_start));
+
+ // Use the second parameter of GetXRCID to force it to take the value i
+ wxXmlResource::GetXRCID(m_name + wxString::Format("[%i]", i-m_start), i);
+ wxLogTrace("xrcrange","integer = %i %s now returns %i", i,
+ m_name + wxString::Format("[%i]", i-m_start).mb_str(),
+ XRCID(m_name + wxString::Format("[%i]", i-m_start).mb_str()));
+ }
+ // and these special ones
+ wxIdRangeManager::RemoveXRCIDEntry(m_name + "[start]");
+ wxXmlResource::GetXRCID(m_name + "[start]", m_start);
+ wxIdRangeManager::RemoveXRCIDEntry(m_name + "[end]");
+ wxXmlResource::GetXRCID(m_name + "[end]", m_end);
+ wxLogTrace("xrcrange","%s[start] = %i %s[end] = %i",
+ m_name.mb_str(),XRCID(wxString(m_name+"[start]").mb_str()),
+ m_name.mb_str(),XRCID(wxString(m_name+"[end]").mb_str()));
+
+ m_finalised = true;
+}
+
+wxIdRangeManager *wxIdRangeManager::ms_instance = NULL;
+
+/*static*/ wxIdRangeManager *wxIdRangeManager::Get()
+{
+ if ( !ms_instance )
+ ms_instance = new wxIdRangeManager;
+ return ms_instance;
+}
+
+/*static*/ wxIdRangeManager *wxIdRangeManager::Set(wxIdRangeManager *res)
+{
+ wxIdRangeManager *old = ms_instance;
+ ms_instance = res;
+ return old;
+}
+
+wxIdRangeManager::~wxIdRangeManager()
+{
+ for ( wxVector<wxIdRange*>::iterator i = m_IdRanges.begin();
+ i != m_IdRanges.end(); ++i )
+ {
+ delete *i;
+ }
+ m_IdRanges.clear();
+
+ delete ms_instance;
+}
+
+void wxIdRangeManager::AddRange(const wxXmlNode* node)
+{
+ wxString name = node->GetAttribute("name");
+ wxString start = node->GetAttribute("start", "0");
+ wxString size = node->GetAttribute("size", "0");
+ if (name.empty())
+ {
+ wxXmlResource::Get()->ReportError
+ (
+ node,
+ "xrc file contains an id-range without a name"
+ );
+ return;
+ }
+
+ int index = Find(name);
+ if (index == wxNOT_FOUND)
+ {
+ wxLogTrace("xrcrange",
+ "Adding ID range, name=%s start=%s size=%s",
+ name, start, size);
+
+ m_IdRanges.push_back(new wxIdRange(node, name, start, size));
+ }
+ else
+ {
+ // There was already a range with this name. Let's hope this is
+ // from an Unload()/(re)Load(), not an unintentional duplication
+ wxLogTrace("xrcrange",
+ "Replacing ID range, name=%s start=%s size=%s",
+ name, start, size);
+
+ wxIdRange* oldrange = m_IdRanges.at(index);
+ m_IdRanges.at(index) = new wxIdRange(node, name, start, size);
+ delete oldrange;
+ }
+}
+
+wxIdRange *
+wxIdRangeManager::FindRangeForItem(const wxXmlNode* node,
+ const wxString& item,
+ wxString& value) const
+{
+ wxString basename = item.BeforeFirst('[');
+ wxCHECK_MSG( !basename.empty(), NULL,
+ "an id-range item without a range name" );
+
+ int index = Find(basename);
+ if (index == wxNOT_FOUND)
+ {
+ // Don't assert just because we've found an unexpected foo[123]
+ // Someone might just want such a name, nothing to do with ranges
+ return NULL;
+ }
+
+ value = item.Mid(basename.Len());
+ if (value.at(value.length()-1)==']')
+ {
+ return m_IdRanges.at(index);
+ }
+ wxXmlResource::Get()->ReportError(node, "a malformed id-range item");
+ return NULL;
+}
+
+void
+wxIdRangeManager::NotifyRangeOfItem(const wxXmlNode* node,
+ const wxString& item) const
+{
+ wxString value;
+ wxIdRange* range = FindRangeForItem(node, item, value);
+ if (range)
+ range->NoteItem(node, value);
+}
+
+int wxIdRangeManager::Find(const wxString& rangename) const
+{
+ for ( int i=0; i < (int)m_IdRanges.size(); ++i )
+ {
+ if (m_IdRanges.at(i)->GetName() == rangename)
+ return i;
+ }
+
+ return wxNOT_FOUND;
+}
+
+void wxIdRangeManager::FinaliseRanges(const wxXmlNode* node) const
+{
+ for ( wxVector<wxIdRange*>::const_iterator i = m_IdRanges.begin();
+ i != m_IdRanges.end(); ++i )
+ {
+ // Check if this range has already been finalised. Quite possible,
+ // as FinaliseRanges() gets called for each .xrc file loaded
+ if (!(*i)->IsFinalised())
+ {
+ wxLogTrace("xrcrange", "Finalising ID range %s", (*i)->GetName());
+ (*i)->Finalise(node);
+ }
+ }
+}
+
class wxXmlSubclassFactories : public wxVector<wxXmlSubclassFactory*>
{
return wxString();
}
+/* static */
+void wxIdRangeManager::RemoveXRCIDEntry(const char *str_id)
+{
+ int index = 0;
+
+ for (const char *c = str_id; *c != '\0'; c++) index += (int)*c;
+ index %= XRCID_TABLE_SIZE;
+
+ XRCID_record **p_previousrec = &XRCID_Records[index];
+ for (XRCID_record *rec = XRCID_Records[index]; rec; rec = rec->next)
+ {
+ if (wxStrcmp(rec->key, str_id) == 0)
+ {
+ // Found the item to be removed so delete its record; but first
+ // replace it in the table with any rec->next (usually == NULL)
+ (*p_previousrec) = rec->next;
+ free(rec->key);
+ delete rec;
+ return;
+ }
+ else
+ {
+ (*p_previousrec) = rec;
+ }
+ }
+}
+
static void CleanXRCID_Record(XRCID_record *rec)
{
if (rec)
void OnExit()
{
delete wxXmlResource::Set(NULL);
+ delete wxIdRangeManager::Set(NULL);
if(wxXmlResource::ms_subclassFactories)
{
for ( wxXmlSubclassFactories::iterator i = wxXmlResource::ms_subclassFactories->begin();
test_gui_socket.o \
test_gui_boxsizer.o \
test_gui_clientsize.o \
- test_gui_setsize.o
+ test_gui_setsize.o \
+ test_gui_xrctest.o
TEST_GUI_ODEP = $(_____pch_testprec_test_gui_testprec_h_gch___depname)
### Conditionally set variables: ###
test_gui_setsize.o: $(srcdir)/window/setsize.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/window/setsize.cpp
+test_gui_xrctest.o: $(srcdir)/xml/xrctest.cpp $(TEST_GUI_ODEP)
+ $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/xml/xrctest.cpp
+
# notice the ugly hack with using CXXWARNINGS: we can't use CPPFLAGS as
# currently the value in the makefile would be ignored if we did, but
$(OBJS)\test_gui_socket.obj \\r
$(OBJS)\test_gui_boxsizer.obj \\r
$(OBJS)\test_gui_clientsize.obj \\r
- $(OBJS)\test_gui_setsize.obj\r
+ $(OBJS)\test_gui_setsize.obj \
+ $(OBJS)\test_gui_xrctest.obj
\r
### Conditionally set variables: ###\r
\r
$(OBJS)\test_gui_setsize.obj: .\window\setsize.cpp\r
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\window\setsize.cpp\r
\r
+$(OBJS)\test_gui_xrctest.obj: .\xml\xrctest.cpp
+ $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\xml\xrctest.cpp
$(OBJS)\test_gui_socket.o \\r
$(OBJS)\test_gui_boxsizer.o \\r
$(OBJS)\test_gui_clientsize.o \\r
- $(OBJS)\test_gui_setsize.o\r
+ $(OBJS)\test_gui_setsize.o \
+ $(OBJS)\test_gui_xrctest.o
\r
### Conditionally set variables: ###\r
\r
$(OBJS)\test_gui_setsize.o: ./window/setsize.cpp\r
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<\r
\r
+$(OBJS)\test_gui_xrctest.o: ./xml/xrctest.cpp
+ $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
+
.PHONY: all clean data fr\r
\r
\r
$(OBJS)\test_gui_socket.obj \\r
$(OBJS)\test_gui_boxsizer.obj \\r
$(OBJS)\test_gui_clientsize.obj \\r
- $(OBJS)\test_gui_setsize.obj\r
+ $(OBJS)\test_gui_setsize.obj \
+ $(OBJS)\test_gui_xrctest.obj
TEST_GUI_RESOURCES = \\r
$(OBJS)\test_gui_sample.res\r
\r
$(OBJS)\test_gui_setsize.obj: .\window\setsize.cpp\r
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\window\setsize.cpp\r
\r
+$(OBJS)\test_gui_xrctest.obj: .\xml\xrctest.cpp
+ $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\xml\xrctest.cpp
$(OBJS)\test_gui_socket.obj &\r
$(OBJS)\test_gui_boxsizer.obj &\r
$(OBJS)\test_gui_clientsize.obj &\r
- $(OBJS)\test_gui_setsize.obj\r
+ $(OBJS)\test_gui_setsize.obj &
+ $(OBJS)\test_gui_xrctest.obj
\r
\r
all : $(OBJS)\r
$(OBJS)\test_gui_setsize.obj : .AUTODEPEND .\window\setsize.cpp\r
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<\r
\r
+$(OBJS)\test_gui_xrctest.obj : .AUTODEPEND .\xml\xrctest.cpp
+ $(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
sizers/boxsizer.cpp
window/clientsize.cpp
window/setsize.cpp
+ xml/xrctest.cpp
</sources>
<wx-lib>richtext</wx-lib>
<wx-lib>media</wx-lib>
SOURCE=.\controls\windowtest.cpp
# End Source File
+# Begin Source File
+
+SOURCE=.\xml\xrctest.cpp
+# End Source File
# End Group\r
# End Target\r
# End Project\r
<File
RelativePath=".\controls\windowtest.cpp">
</File>
+ <File
+ RelativePath=".\xml\xrctest.cpp">
+ </File>
</Filter>\r
<Filter\r
Name="Resource Files"\r
RelativePath=".\controls\windowtest.cpp"
>
</File>
+ <File
+ RelativePath=".\xml\xrctest.cpp"
+ >
+ </File>
</Filter>\r
<Filter\r
Name="Resource Files"\r
RelativePath=".\controls\windowtest.cpp"
>
</File>
+ <File
+ RelativePath=".\xml\xrctest.cpp"
+ >
+ </File>
</Filter>\r
<Filter\r
Name="Resource Files"\r
--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+// Name: tests/xml/xrctest.cpp
+// Purpose: XRC classes unit test
+// Author: wxWidgets team
+// Created: 2010-10-30
+// RCS-ID: $Id$
+// Copyright: (c) 2010 wxWidgets team
+///////////////////////////////////////////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "testprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif // WX_PRECOMP
+
+#include "wx/xml/xml.h"
+#include "wx/sstream.h"
+#include "wx/wfstream.h"
+#include "wx/xrc/xmlres.h"
+
+#include <stdarg.h>
+
+// ----------------------------------------------------------------------------
+// helpers to create/save some xrc
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+static const char *TEST_XRC_FILE = "test.xrc";
+
+// I'm hard-wiring the xrc into this function for now
+// If different xrcs are wanted for future tests, it'll be easy to refactor
+void CreateXrc()
+{
+ const char *xrcText =
+ "<?xml version=\"1.0\" ?>"
+ "<resource>"
+ " <object class=\"wxDialog\" name=\"dialog\">"
+ " <object class=\"wxBoxSizer\">"
+ " <orient>wxVERTICAL</orient>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxPanel\" name=\"panel1\">"
+ " <object class=\"wxBoxSizer\">"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxBoxSizer\">"
+ " <orient>wxVERTICAL</orient>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxButton\" name=\"FirstCol[0]\">"
+ " <label>0</label>"
+ " </object>"
+ " </object>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxButton\" name=\"FirstCol[1]\">"
+ " <label>1</label>"
+ " </object>"
+ " </object>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxButton\" name=\"FirstCol[2]\">"
+ " <label>2</label>"
+ " </object>"
+ " </object>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxButton\" name=\"FirstCol[3]\">"
+ " <label>3</label>"
+ " </object>"
+ " </object>"
+ " </object>"
+ " </object>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxBoxSizer\">"
+ " <orient>wxVERTICAL</orient>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxButton\" name=\"SecondCol[start]\">"
+ " <label>0</label>"
+ " </object>"
+ " </object>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxButton\" name=\"SecondCol[1]\">"
+ " <label>1</label>"
+ " </object>"
+ " </object>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxButton\" name=\"SecondCol[2]\">"
+ " <label>2</label>"
+ " </object>"
+ " </object>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxButton\" name=\"SecondCol[end]\">"
+ " <label>3</label>"
+ " </object>"
+ " </object>"
+ " </object>"
+ " </object>"
+ " <orient>wxHORIZONTAL</orient>"
+ " </object>"
+ " </object>"
+ " </object>"
+ " <object class=\"sizeritem\">"
+ " <object class=\"wxPanel\" name=\"ref_of_panel1\">"
+ " <object_ref ref=\"panel1\"/>"
+ " </object>"
+ " </object>"
+ " </object>"
+ " <title>test</title>"
+ " </object>"
+ " <ids-range name=\"FirstCol\" size=\"2\" start=\"10000\"/>"
+ " <ids-range name=\"SecondCol\" size=\"100\" />"
+ "</resource>"
+ ;
+
+ // afaict there's no elegant way to load xrc direct from a string
+ // So save it as a file, from which it can be loaded
+ wxStringInputStream sis(xrcText);
+ wxFFileOutputStream fos(TEST_XRC_FILE);
+ CPPUNIT_ASSERT(fos.IsOk());
+ fos.Write(sis);
+ CPPUNIT_ASSERT(fos.Close());
+}
+
+} // anon namespace
+
+
+// ----------------------------------------------------------------------------
+// test class
+// ----------------------------------------------------------------------------
+
+class XrcTestCase : public CppUnit::TestCase
+{
+public:
+ XrcTestCase() {}
+
+ virtual void setUp() { CreateXrc(); }
+ virtual void tearDown() { wxRemoveFile(TEST_XRC_FILE); }
+
+private:
+ CPPUNIT_TEST_SUITE( XrcTestCase );
+ CPPUNIT_TEST( ObjectReferences );
+ CPPUNIT_TEST( IDRanges );
+ CPPUNIT_TEST_SUITE_END();
+
+ void ObjectReferences();
+ void IDRanges();
+
+ DECLARE_NO_COPY_CLASS(XrcTestCase)
+};
+
+// register in the unnamed registry so that these tests are run by default
+CPPUNIT_TEST_SUITE_REGISTRATION( XrcTestCase );
+
+// also include in it's own registry so that these tests can be run alone
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( XrcTestCase, "XrcTestCase" );
+
+
+
+void XrcTestCase::ObjectReferences()
+{
+ wxXmlResource::Get()->InitAllHandlers();
+
+ for ( int n = 0; n < 2; ++n )
+ {
+ // Load the xrc file we're just created
+ CPPUNIT_ASSERT( wxXmlResource::Get()->Load(TEST_XRC_FILE) );
+
+ // In xrc there's now a dialog containing two panels, one an object
+ // reference of the other
+ wxDialog dlg;
+ CPPUNIT_ASSERT( wxXmlResource::Get()->LoadDialog(&dlg, NULL, "dialog") );
+ // Might as well test XRCCTRL too
+ wxPanel* panel1 = XRCCTRL(dlg,"panel1",wxPanel);
+ wxPanel* panel2 = XRCCTRL(dlg,"ref_of_panel1",wxPanel);
+ // Check that the object reference panel is a different object
+ CPPUNIT_ASSERT( panel2 != panel1 );
+
+ // Unload the xrc, so it can be reloaded and the test rerun
+ CPPUNIT_ASSERT( wxXmlResource::Get()->Unload(TEST_XRC_FILE) );
+ }
+}
+
+void XrcTestCase::IDRanges()
+{
+ // Tests ID ranges
+ for ( int n = 0; n < 2; ++n )
+ {
+ // Load the xrc file we're just created
+ CPPUNIT_ASSERT( wxXmlResource::Get()->Load(TEST_XRC_FILE) );
+
+ // foo[start] should == foo[0]
+ CPPUNIT_ASSERT_EQUAL( XRCID("SecondCol[start]"), XRCID("SecondCol[0]") );
+ // foo[start] should be < foo[end]. Usually that means more negative
+ CPPUNIT_ASSERT( XRCID("SecondCol[start]") < XRCID("SecondCol[end]") );
+ // Check it works for the positive values in FirstCol too
+ CPPUNIT_ASSERT( XRCID("FirstCol[start]") < XRCID("FirstCol[end]") );
+
+ // Check that values are adjacent
+ CPPUNIT_ASSERT_EQUAL( XRCID("SecondCol[0]")+1, XRCID("SecondCol[1]") );
+ CPPUNIT_ASSERT_EQUAL( XRCID("SecondCol[1]")+1, XRCID("SecondCol[2]") );
+ // And for the positive range
+ CPPUNIT_ASSERT_EQUAL( XRCID("FirstCol[2]")+1, XRCID("FirstCol[3]") );
+
+ // Check that a large-enough range was created, despite the small
+ // 'size' parameter
+ CPPUNIT_ASSERT_EQUAL
+ (
+ 4,
+ XRCID("FirstCol[end]") - XRCID("FirstCol[start]") + 1
+ );
+
+ // Check that the far-too-large size range worked off the scale too
+ CPPUNIT_ASSERT( XRCID("SecondCol[start]") < XRCID("SecondCol[90]") );
+ CPPUNIT_ASSERT( XRCID("SecondCol[90]") < XRCID("SecondCol[end]") );
+ CPPUNIT_ASSERT_EQUAL( XRCID("SecondCol[90]")+1, XRCID("SecondCol[91]") );
+
+ // Check that the positive range-start parameter worked, even after a
+ // reload
+ CPPUNIT_ASSERT_EQUAL( XRCID("FirstCol[start]"), 10000 );
+
+ // Unload the xrc, so it can be reloaded and the tests rerun
+ CPPUNIT_ASSERT( wxXmlResource::Get()->Unload(TEST_XRC_FILE) );
+ }
+}