Adding new widget to wxSmith
Warning: Not finished yet
Hi. Because wxSmith is still under development it misses some standard widgets in it's palette. I hope this will change soon. But If you really need some kind of widget maybe you could help us a little bit with wxSmith development :).
At the very beginning I must point that technique described here will work with default widget set and I cannot grant that this will work with external ones. There may be a problem even with standard ones but hopefully we could work on that together ;)
Here I will show how to add new widget realy fast. It will work only with widgets that have no children. Let's see an example (source files should be placed inside defwidgets directory since wxSmith uses such convention). Here's extra-commented source code for wxSpinButton widget:
#ifndef __WXSSPINBUTTON_H #define __WXSSPINBUTTON_H #include "../wxsdefwidget.h" // this file declares most of usefull macros #include "wxsstdmanager.h" // declaration of default widget manager WXS_ST_DECLARE(wxsSpinButtonStyles) // declaring styles for wxsSpinButton class WXS_EV_DECLARE(wxsSpinButtonEvents) // declaring events for wxsSpinButtin class wxsDWDeclareBegin(wxsSpinButton,wxsSpinButtonId) // Beginning of class declaration // Here are additional properties (standard ones like position/size etc. // are processeed automatically) int value; int min; int max; wxsDWDeclareEnd() // End of class declaration #endif
#include "../wxsheaders.h" // Standard include for precompiled headers #include "wxsspinbutton.h" #include <wx/spinbutt.h> // Here's definition of spin button styles WXS_ST_BEGIN(wxsSpinButtonStyles) // Category definition - currently not used but maybe in future ;) WXS_ST_CATEGORY("wxSpinButton") // Example of masked style (available in one platform/not available in xrc etc.) WXS_ST_MASK(wxSP_HORIZONTAL,wxsSFAll,wxsSFGTK,true) // Example of standard style (available everywhere) WXS_ST(wxSP_VERTICAL) WXS_ST(wxSP_ARROW_KEYS) WXS_ST(wxSP_WRAP) WXS_ST_END(wxsSpinButtonStyles) // Here's dedfinition of spin button events WXS_EV_BEGIN(wxsSpinButtonEvents) WXS_EVI(EVT_SPIN,wxSpinEvent,Change) WXS_EVI(EVT_SPIN_UP,wxSpinEvent,ChangeUp) WXS_EVI(EVT_SPIN_DOWN,wxSpinEvent,ChangeDown) WXS_EV_DEFAULTS() WXS_EV_END(wxsSpinButtonEvents) // Declaration of spin button widget wxsDWDefineBegin(wxsSpinButton,wxSpinButton, WXS_THIS = new wxSpinButton(WXS_PARENT,WXS_ID,WXS_POS,WXS_SIZE,WXS_STYLE); WXS_THIS->SetRange(min,max); WXS_THIS->SetValue(value); // This is code producing this widget ) // Bindings for additional properties wxsDWDefInt(value,"Default:",0); wxsDWDefInt(min,"Min:",0) wxsDWDefInt(max,"Max:",100) wxsDWDefineEnd()
Maybe it seems to be a little bit complicated but If You think so, just take a look at wxsWidget class ;) Without most of usefull macros presented here, adding new widget would be a nightmare :)
Ok, let's explain this code:
Each widget has set of styles it uses and events it throws. All is done in:
WXS_ST_DECLARE(wxsSpinButtonStyles) // declaring styles for wxsSpinButton class WXS_EV_DECLARE(wxsSpinButtonEvents) // declaring events for wxsSpinButtin class
WXS_ST_BEGIN(wxsSpinButtonStyles) ... WXS_ST_END(wxsSpinButtonStyles) WXS_EV_BEGIN(wxsSpinButtonEvents) ... WXS_EV_END(wxsSpinButtonEvents)
First one declares events and styles (note that argument for WXS_ST_DECLARE and WXS_EV_DECLARE is name of class inside wxSmith - with wxs prefix). Second one will be described in more details.
Each entry between WXS_ST_BEGIN and WXS_ST_END can be:
- category definition - WXS_ST_CATEGORY(name) - this is currently not used but will probably be in future to dividee styles
- global style - WXS_ST(style_name)
- global extra style - WXS_EXST(style_name)
- masked style - WXS_ST_MASK(style_name,include_mask,exclude_mask,can_use_in_xrc)
- masked extra style - WXS_EXST_MASK(style_name,include_mask,exclude_mask,can_use_in_xrc)
Masked styles were added to notify that some styles work on some platforms, some other don't work on other platforms. Some styles are not used insided XRC. Platforms are defined in wxsstyle.h:
const unsigned int wxsSFWin = 0x00000002; ///< This style can be used in Windows (any) const unsigned int wxsSFWin95 = 0x00000004; ///< This style can be used in Win95 const unsigned int wxsSFWinCE = 0x00000008; ///< This style can be used in WinCE const unsigned int wxsSFGTK = 0x00000010; ///< This style can be used in GTK+ (any GTK) const unsigned int wxsSFGTK12 = 0x00000020; ///< This style can be used in GTK (1.2 only) const unsigned int wxsSFGTK20 = 0x00000040; ///< This style can be used in GTK (1.2 only) const unsigned int wxsSFOSX = 0x00000080; ///< This style can be used in MAC (any OSX port Cocoa or Carbon) const unsigned int wxsSFCOCOA = 0x00000100; ///< This style can be used in MAC (OSX port Cocoa API) const unsigned int wxsSFCARBON = 0x00000200; ///< This style can be used in MAC (MacOS for Carbon CFM) const unsigned int wxsSFMotif = 0x00000400; ///< This style can be used in Motif const unsigned int wxsSFMGL = 0x00000800; ///< This style can be used in MGL const unsigned int wxsSFOS2 = 0x00001000; ///< This style can be used in OS2 const unsigned int wxsSFX11 = 0x00002000; ///< This style can be used in X11 const unsigned int wxsSFPALMOS = 0x00004000; ///< This style can be used in PALMOS const unsigned int wxsSFUNIV = 0x00008000; ///< This style can be used in wxUNIV
Meaning of macro arguments is as follows:
- include_mask - mask of platforms where style can be used. If this argument is specified, exclude_mask should be 0
- exclude_mask - mask of platforms where style does not work. If this argument is specified, include_mask should be wxsSFAll (all platforms)
- can_use_in_xrc - set to true when xrc uses this style or false if not (but it's listed in documentation)
Next thing are events. They are defined between WXS_EV_BEGIN and WXS_EV_END macros:
- Event using identifier: WXS_EVI(entry_name,argument_type,default_name) - where entry_name is name of this entry in event array, argumetn_name is name of wxEvent-derived class passed as argument in this handler, default_name - default suffix for new event handlers (without "")
- Event not using identifiers: WXS_EV(entry_name,argument_type,default_name) - these may be only used in top-level objects like wxDialog. Meaning of arguments is the same.
- At the end of events list is WXS_EV_DEFAULTS() - this macro currently does nothing but may be used in future to add common events like mouse processing etc.
- You can also use WXS_EV_CATEGORY() macro simillar to WXS_ST_CATEGORY() but it currently do nothing
Next thing is declaration. It can be easily done using wxsDWDeclareBegin() and wxsDWDeclareEnd() macros. wxsDWDeckareBegin has two arguments - name of wxSmith class handling this widget (i usually use same names with wxWidgets classes but with wxs prefix instead of wx). The second argument is class ideentifier. Identifiers will be discussed later. Between macros just presented there is list of additional properties. This list is standard c++ declaration. In fact You can put here anything You want to be inside class declaration.
Next thing is class definition. It's little bit harder. Class definition begins with following macro:
- wxs_class_name - name of class in wxSmith (with wxs prefix)
- wx_class_name - name of modeelled wxWidgets class (with wx prefix)
- producing_code - code used for building widget - both it's source code and visual representation in editor. I'll describe this in more details.
wxSmith must be able to build source code and show widget in editor. These two operations looks simillar. Standard widgets can do both operations automatically using producing code. It's standard c++ code creating and setting up widget but with some restrictions:
- widget which is currently built can be accessed through WXS_THIS variable
- WXS_PARENT variable is pointer to parent widget
- WXS_ID, WXS_POS, WXS_SIZE, WXS_STYLE contains values of standard properties
- operations on complex data structures (wxArrayString is currently only one supported) may be accessed through special functions only
- properties binded in class definition may be used in this code
Binding properties is done between wxsDWDefineBegin() and wxsDWDefineEnd() macros. It's done through wxsDWDef... macros:
- wxsDWDef2Int(V1,V2,Name,PropName,Def1,Def2) - this can be used for two integers threated as one property (f.ex. some size, dimensions)
Arguments are as follows:
- Name - name of variable used for property
- PropName - name used in property editor for this property (with " characters but without unicode converting macros)
- Default - usually default value for this property (exception is StrArray where this should be name of variable which will kepp number of item selected by default)
- V1, V2 - used instead of one name of variable (something is messed up here, I'll have to clear this code, currently try not to use wxsDWDef2Int and wxsDWDef2IntX macros)
- SortFlag - flag in widget style used for sorting it's elements (used when meaning of selection property changes after adding this flag)
- XrcParentName, XrcChildName - names of parent/child xrc node names
Each property binding has two versions of binding macro - the one without X is used when name of property (variable declared in class declaration) is same as name of node inside xrc file. The one with X at the end could be useed when name of xrc node with this value is other than name of variable (f.ex. name of node is sometimes 'default' which can not be a name of variable in c++).
One additional note: when using StrArray (for binging wxArrayString properties) You can only use following functions for them in producing code:
- void wxsDWAddStrings(const wxArrayString& Array,wxControlWithItems* Ctrl) for adding strings for widget
- void wxsDWSelectString(const wxArrayString& Array,size_t Index,wxControlWithItems* Ctrl) for setting default selection