Difference between revisions of "Wxs ext tutorial2 properties"

From Code::Blocks
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
== WARNING: NOT YET FINISHED ==
 
  
 
== Preface ==
 
 
 
In [[Creating a plugin which adds new item into wxSmith|previous]] tutorial we created simple plugin which added one item into wxSmith's palette. After loading this plugin into Code::Blocks we were able to add this item into resource and set some basic properties like size or position. In this tutorial we will add more customization for this item by adding it's specific properties. But before we do this, I need to explain some things.
 
 
 
== How wxSmith creates properties ==
 
 
 
The final set of properties is result of merging three basic sets:
 
* Some standard properties which are used in almost any widget (size, position, font etc)
 
* Properties added by parent control like border size inside sizers or notebook page name
 
* Properties which are specific to one widget only
 
 
 
=== Standard properties ===
 
 
 
The first set is added through constructor. In the code from previous tutorial, constructor is as follows:
 
 
wxsChart::wxsChart(wxsItemResData* Data):
 
    wxsWidget(
 
        Data,              // Data passed to constructor
 
        &Reg.Info,          // Info taken from Registering object previously created
 
        NULL,              // Structure describing events, we have no events for wxChart
 
        wxsChartStyles)    // Structure describing styles
 
{
 
}
 
 
so the only thing we see here is set of styles (that's one of standard properties). Because it's rather complex and require extra initialization, this property must be specified separately. If there was <tt>NULL</tt> instead of <tt>wxsChartStyles</tt>, wxChart would have no style property.
 
Other standard properties are given through flags, which are passed through <tt>PropertiesFlags</tt> argument in constructor of wxsWidget:
 
 
wxsWidget(
 
    wxsItemResData* Data,
 
    const wxsItemInfo* Info,
 
    const wxsEventDesc* EventArray = NULL,
 
    const wxsStyleSet* StyleSet=NULL,
 
    long PropertiesFlags = flWidget);
 
 
We can see here that default value for this argument is flWidget. It means that standard properties which are usually used by any kind of widget will be added into properties set. That value is silently passed to wxsWidget's constructor in case of wxsChart class so we have all those standard properties in property browser without even line of code. Individual flags which can be used are:
 
 
* <tt>flVariable</tt> - allow variable and ''Is Member'' flag
 
* <tt>flId</tt> - allow identifier
 
* <tt>flPosition</tt> - allow position
 
* <tt>flSize</tt> - allow size
 
* <tt>flEnabled</tt> - allow ''Enabled'' switch
 
* <tt>flFocused</tt> - allow ''Focused'' switch
 
* <tt>flHidden</tt> - allow ''Hidden'' switch
 
* <tt>flColours</tt> - allow foreground and background colours
 
* <tt>flToolTip</tt> - allow tooltip
 
* <tt>flFont</tt> - allow font
 
* <tt>flHelpText</tt> - allow help text
 
* <tt>flSubclass</tt> - allow changing of class name (the ''"subclass"'' term comes from XRC terminology)
 
* <tt>flMinMaxSize</tt> - allow MinSize and MaxSize
 
 
And when we want for example only variable and position, we would pass <tt>flVariable|flPosition</tt> instead of <tt>flWidget</tt> into wxsWidget's contructor. This technique is not recommended though, because it may introduce some problems (just imagine widget which have no variable of any kind - there's problem even with creating it).
 
 
Some properties are also filtered depending on some circumstances:
 
* <tt>flMinMaxSize</tt> will be disabled when XRC file is used
 
* <tt>flVariable</tt> / <tt>flId</tt> are disabled for top-most items (like wxDialog and wxFrame)
 
* <tt>flHidden</tt> does not affect item when it's shown inside editor (but it's used for exact previews shown after pressing ''Preview'' button)
 
 
 
=== Properties added by parent control ===
 
 
 
Some parent controls require extra information for each of it's children. This data is included in set of properties in property browser and child item have no control of it. Properties added in this way are:
 
* Settings for item inside sizer (''border size'', ''border flags'', ''proportion'' and some flags like ''expand')
 
* Names of pages and switch for default page in wxNotebook, wxChoicebook and wxListbook
 
 
 
=== Properties specific to only one item ===
 
 
 
Most of items have their own proeprties which can not be generalized and provided as common ones. These properties are added in special function which in case of widgets is declared as:
 
 
void OnEnumWidgetProperties(long Flags);
 
 
wxSmith has complex property managment system which handle most of work related to properties automatically, including operating on property grid and XRC files. Usually one variable is mapped to one property (in case of most complex properties such as position, special structure is used to keep data in one variable).
 
Binding between variable and property managment system is done in function mentioned above. It require generating one variable for one property and calling <tt>Property</tt> function for it. Usually ot looks like this:
 
 
void ClassName::OnEnumWidgetProperties(long Flags)
 
{
 
    static wxsBoolProperty SomePropertyVariable(
 
                            _("Name in property grid"), _T("name_in_xrc_file"),
 
                            wxsOFFSET(ClassName,ClassMemberVariable), false );
 
    Property(SomePropertyValue);
 
}
 
 
Properties may be added in this way or may be defined through macros. Using macro, the code adding bool property will look like this:
 
 
void ClassName::OnEnumWidgetProperties(long Flags)
 
{
 
    WXS_BOOL(ClassName,ClassMemberVariable,_("Name in property grid"), _T("name_in_xrc_file"), false);
 
}
 
 
Both methods will give the same result (macros simply generate static variable and call Property on it). So it's up to you to choose one of them. I preffer macros because they give cleaner view, but smoetimes they may hide some extra parameters and may not be preffered by other coders (not everyone likes c macros ;) ). So I'll describe both methods.
 
 
Before we begin detailed description of available properties, I'll have to make few remarks:
 
* Variables used in properties must be members of the class which adds them (it's possible to use members of other class, but it's advanced technique and won't be covered in this tutorial). So it's not possible to create property from pointer to variable (for example when we have <tt>bool*</tt> member in class and want to make property for value pointer by it). The technique which allow such things will be described later in this tutorial but won't use wxSmith's property managment system.
 
* Objects which create binging between property variable and property managment system (like <tt>SomePropertyVariable</tt> in example above) should be declared static or at least should exist as long as all objects using this property are not deleted. Simple <tt>static</tt> modifier eliminates all problems.
 
 
 
==== List of available properties ====
 
 
Here you have list of properties supported by wxSmith's property managment system. Each one of them have exact type of variable it supports and examples of using this property. In those examples, <tt>ClassName</tt> represents name of class containing properties, <tt>ClassMemberVariable</tt> represents name of member variable inside <tt>ClassName</tt> (note that current there's no type checking so you should check if valid types of variables are used).
 
 
 
Here you have list of properties supported by wxSmith's property managment system. Each one of them have exact type of variable it supports and examples of using this property. In those examples, <tt>ClassName</tt> represents name of class containing properties and <tt>ClassMemberVariable</tt> represents name of member variable inside <tt>ClassName</tt> (note that current there's no type checking so you should check if valid types of variables are used).
 
 
 
===== bool =====
 
 
 
Variable type: <tt>bool</tt>
 
 
Example using macros:
 
 
WXS_BOOL(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    false);                      // Default value
 
 
Example using objects:
 
 
static wxsBoolProperty SomePropertyVariable(
 
    _("Name in property grid"),              // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                  // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable), // Offset from class beginning to variable
 
    false );                                  // Default value
 
Property(SomePropertyValue);
 
 
 
===== wxString =====
 
 
 
Variable type: <tt>wxString</tt>
 
 
Example using macros (for one-line strings):
 
 
WXS_SHORT_STRING(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    false,                        // Default value
 
    false);                      // If set to true, empty strings won't be stored in XRC files (
 
 
Example using macros (for multiline strings):
 
 
WXS_STRING(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    _T(""),                      // Default value
 
    false);                      // If set to true, empty strings won't be stored in XRC files
 
 
Example using objects:
 
 
static wxsStringProperty SomePropertyVariable(
 
    _("Name in property grid"),              // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                  // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable), // Offset from class beginning to variable
 
    true,                                    // True for multiline string, false for one-line
 
    _T("") );                                // Default value
 
Property(SomePropertyValue);
 
 
 
===== long int =====
 
 
 
Variable type: <tt>long int</tt>
 
 
Example using macros:
 
 
WXS_LONG(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    10);                          // Default value
 
 
Example using objects:
 
 
static wxsLongProperty SomePropertyVariable(
 
    _("Name in property grid"),              // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                  // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable), // Offset from class beginning to variable
 
    10);                                      // Default value
 
Property(SomePropertyValue);
 
 
 
===== enum =====
 
 
 
Variable type: <tt>long int</tt> which is one of predefined values
 
 
Example using macros:
 
 
static const long    Values[] = { 5, 100 };
 
static const wxChar* Names[]  = { _("Few"), _("Many"), NULL }; // Must end with NULL entry
 
 
WXS_ENUM(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    Values,                      // Array of values
 
    Names,                        // Array of names
 
    5);                          // Default value
 
 
Example using objects:
 
 
static const long    Values[] = { 5, 100 };
 
static const wxChar* Names[]  = { _("Few"), _("Many"), NULL }; // Must end with NULL entry
 
 
static wxsEnumProperty SomePropertyVariable(
 
    _("Name in property grid"),              // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                  // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable), // Offset from class beginning to variable
 
    Values,                                  // Array of values
 
    Names,                                    // Array of names
 
    false,                                    // Setting to true notifies that content of arrays may change (not tested)
 
    5,                                        // Default value
 
    true);                                    // If false, XRC node will contain value as number, if true, it will contain name
 
Property(SomePropertyValue);
 
 
 
===== flags =====
 
 
 
Variable type: <tt>long int</tt> which is value produced by or-ing some one-bit flags
 
 
Example using macros:
 
 
static const long    Values[] = { 0x01, 0x02, 0x04, 0x08, 0x10 };
 
static const wxChar* Names[]  = { _T("C"), _T("C++"), _T("Java"), _T("C#"), _T("D"), NULL };
 
 
WXS_FLAGS(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    Values,                      // Array of values
 
    Names,                        // Array of names
 
    0x01 | 0x10 );                // Default value
 
 
Example using objects:
 
 
static const long    Values[] = { 0x01, 0x02, 0x04, 0x08, 0x10 };
 
static const wxChar* Names[]  = { _T("C"), _T("C++"), _T("Java"), _T("C#"), _T("D"), NULL };
 
 
static wxsFlagsProperty SomePropertyVariable(
 
    _("Name in property grid"),              // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                  // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable), // Offset from class beginning to variable
 
    Values,                                  // Array of values
 
    Names,                                    // Array of names
 
    false,                                    // Setting to true notifies that content of arrays may change (not tested)
 
    0x01 | 0x10,                              // Default value
 
    true);                                    // If false, XRC node will contain value as number, if true, it will contain names separated by '|' character
 
Property(SomePropertyValue);
 
 
 
===== wxArrayString =====
 
 
 
Variable type: <tt>wxArrayString</tt>
 
 
Example using macros:
 
 
WXS_ARRAYSTRING(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    _T("xrc_subnode"));          // Name of sub-node generated for each string in xrc file
 
 
Example using objects:
 
 
static wxsArrayStringProperty SomePropertyVariable(
 
    _("Name in property grid"),              // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                  // Name of XML node used in xrc files
 
    _T("xrc_subnode"),                        // Name of sub-node generated for each string in xrc file
 
    wxsOFFSET(ClassName,ClassMemberVariable));// Offset from class beginning to variable
 
Property(SomePropertyValue);
 
 
 
===== wxArrayString with checked items =====
 
 
 
Variable type: <tt>wxArrayString</tt> with <tt>wxArrayBool</tt>
 
 
Example using macros:
 
 
WXS_ARRAYSTRINGCHECK(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable1,        // Name of member variable of type <tt>wxArrayString</tt>
 
    ClassMemberVariable2,        // Name of member variable of type <tt>wxArrayBool</tt>
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    _T("xrc_subnode"));          // Name of sub-node generated for each string in xrc file
 
 
Example using objects:
 
 
static wxsArrayStringCheckProperty SomePropertyVariable(
 
    _("Name in property grid"),                // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                    // Name of XML node used in xrc files
 
    _T("xrc_subnode"),                          // Name of sub-node generated for each string in xrc file
 
    wxsOFFSET(ClassName,ClassMemberVariable1),  // Offset from class beginning to variable
 
                                                // of type wxArrayString
 
    wxsOFFSET(ClassName,ClassMemberVariable2)); // Offset from class beginning to variable
 
                                                //of type wxArrayBool
 
Property(SomePropertyValue);
 
 
 
===== wxBitmap =====
 
 
 
Variable type: <tt>wxsBitmapData</tt>
 
 
Example using macros:
 
 
WXS_BITMAP(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable of type wxBitmapData
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    _T("wxART_OTHER"));          // Name of default art client (see [http://www.wxwidgets.org/manuals/2.6/wx_wxartprovider.html#wxartprovider wx docs])
 
 
Example using objects:
 
 
static wxsBitmapProperty SomePropertyVariable(
 
    _("Name in property grid"),              // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                  // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable,  // Offset from class beginning to variable of type wxsBitmapData
 
    _T("wxART_OTHER"));                      // Name of default art client (see [http://www.wxwidgets.org/manuals/2.6/wx_wxartprovider.html#wxartprovider wx docs])
 
Property(SomePropertyValue);
 
 
 
===== wxIcon =====
 
 
 
Variable type: <tt>wxsIconData</tt>
 
 
Example using macros:
 
 
WXS_ICON(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable of type wxBitmapData
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    _T("wxART_OTHER"));          // Name of default art client (see [http://www.wxwidgets.org/manuals/2.6/wx_wxartprovider.html#wxartprovider wx docs])
 
 
Example using objects:
 
 
static wxsIconProperty SomePropertyVariable(
 
    _("Name in property grid"),              // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                  // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable), // Offset from class beginning to variable of type wxsIconData
 
    _T("wxART_OTHER"));                      // Name of default art client (see [http://www.wxwidgets.org/manuals/2.6/wx_wxartprovider.html#wxartprovider wx docs])
 
Property(SomePropertyValue);
 
 
 
===== wxColour =====
 
 
 
Variable type: <tt>wxsColourData</tt>
 
 
Example using macros:
 
 
WXS_COLOUR(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"));      // Name of XML node used in xrc files
 
 
Example using objects:
 
 
static wxsColourProperty SomePropertyVariable(
 
    _("Name in property grid"),                // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                    // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable)); // Offset from class beginning to variable
 
Property(SomePropertyValue);
 
 
 
===== wxDimension =====
 
 
 
Variable type: <tt>wxsDimensionData</tt>
 
 
Example using macros:
 
 
WXS_DIMENSION(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _("Dialog-Units name"),      // Name of [http://www.wxwidgets.org/manuals/2.6/wx_wxwindow.html#wxwindowconvertpixelstodialog dialog units] switch entry in property grid
 
    _T("name_in_xrc_file"),      // Name of XML node used in xrc files
 
    10,                          // Default value
 
    true);                        // Default value for [http://www.wxwidgets.org/manuals/2.6/wx_wxwindow.html#wxwindowconvertpixelstodialog dialog units] switch
 
 
Example using objects:
 
 
static wxsDimensionProperty SomePropertyVariable(
 
    _("Name in property grid"),                // Name of property shown in property grid
 
    _("Name of Dialog-Units"),                // Name of [http://www.wxwidgets.org/manuals/2.6/wx_wxwindow.html#wxwindowconvertpixelstodialog dialog units] switch in property grid
 
    _T("name_in_xrc_file"),                    // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable),  // Offset from class beginning to variable
 
    10,                                        // Default value
 
    true);                                    // Default value for [http://www.wxwidgets.org/manuals/2.6/wx_wxwindow.html#wxwindowconvertpixelstodialog dialog units] switch
 
 
Property(SomePropertyValue);
 
 
 
===== wxFont =====
 
 
 
Variable type: <tt>wxsFontData</tt>
 
 
Example using macros:
 
 
WXS_FONT(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name in property grid"),  // Name of property shown in property grid
 
    _T("name_in_xrc_file"));      // Name of XML node used in xrc files
 
 
Example using objects:
 
 
static wxsFontProperty SomePropertyVariable(
 
    _("Name in property grid"),                // Name of property shown in property grid
 
    _T("name_in_xrc_file"),                    // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable)); // Offset from class beginning to variable
 
Property(SomePropertyValue);
 
 
 
===== wxPosition =====
 
 
 
Variable type: <tt>wxsPositionData</tt>
 
 
Example using macros:
 
 
WXS_POSITION(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name of Default switch"),  // Name of default position switch in property grid
 
    _("Name of X data"),          // Name of X coordinate in property grid
 
    _("Name of Y data"),          // Name of Y coordinate in property grid
 
    _("Name of Dialog-Units"),    // Name of [http://www.wxwidgets.org/manuals/2.6/wx_wxwindow.html#wxwindowconvertpixelstodialog dialog units] switch in property grid
 
    _T("name_in_xrc_file"));      // Name of XML node used in xrc files
 
 
Example using objects:
 
 
static wxsPositionProperty SomePropertyVariable(
 
    _("Name of Default switch"),              // Name of default position switch in property grid
 
    _("Name of X data"),                      // Name of X coordinate in property grid
 
    _("Name of Y data"),                      // Name of Y coordinate in property grid
 
    _("Name of Dialog-Units"),                // Name of [http://www.wxwidgets.org/manuals/2.6/wx_wxwindow.html#wxwindowconvertpixelstodialog dialog units] switch in property grid
 
    _T("name_in_xrc_file"),                    // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable)); // Offset from class beginning to variable
 
Property(SomePropertyValue);
 
 
 
===== wxSize =====
 
 
 
Variable type: <tt>wxsSizeData</tt>
 
 
Example using macros:
 
 
WXS_SIZE(
 
    ClassName,                    // Name of this class
 
    ClassMemberVariable,          // Name of member variable
 
    _("Name of Default switch"),  // Name of default position switch in property grid
 
    _("Name of Width data"),      // Name of Width value in property grid
 
    _("Name of Height data"),    // Name of Height value in property grid
 
    _("Name of Dialog-Units"),    // Name of [http://www.wxwidgets.org/manuals/2.6/wx_wxwindow.html#wxwindowconvertpixelstodialog dialog units] switch in property grid
 
    _T("name_in_xrc_file"));      // Name of XML node used in xrc files
 
 
Example using objects:
 
 
static wxsSizeProperty SomePropertyVariable(
 
    _("Name of Default switch"),              // Name of default position switch in property grid
 
    _("Name of Width data"),                  // Name of Width value in property grid
 
    _("Name of Height data"),                  // Name of Height vlaue in property grid
 
    _("Name of Dialog-Units"),                // Name of [http://www.wxwidgets.org/manuals/2.6/wx_wxwindow.html#wxwindowconvertpixelstodialog dialog units] switch in property grid
 
    _T("name_in_xrc_file"),                    // Name of XML node used in xrc files
 
    wxsOFFSET(ClassName,ClassMemberVariable)); // Offset from class beginning to variable
 
Property(SomePropertyValue);
 
 
 
 
=== Fully customizable properties ===
 
 
 
The set of properties available in wxSmith's property managment system may be insufficient for some kind of properties. A good example here may be a situation, when number of available properties dynamically changes. In such cases, we have to take care about properties manually and provide following operations for each property:
 
 
* Adding property to property grid
 
* Reacting to change of this property
 
* Reading data from XML (XRC) structures
 
* Writing data to XML (XRC) structures
 
 
Each of these operations is done inside one virtual function. Overriding it and giving out implementation allows to freely operate on properties.
 
 
==== Adding custom property to property grid ====
 
 
To include our own properties in list of properties, we have to add following function into our class:
 
 
void OnAddExtraProperties(wxsPropertyGridManager* Grid);
 
 
Inside this class we can freely operate on given <tt>wxsPropertyGridManager</tt> class (see [http://wxpropgrid.sourceforge.net/ wxPropertyGrid site] to learn more on how to operate on this class), but the operations should be limited to ading properties (it may be risky to delete or change existing properties).
 
 
At the end of custom implementation of this function, one should also call the original function declared inside wxsWidget class:
 
 
void CustomClass::OnAddExtraProperties(wxsPropertyGridManager* Grid)
 
{
 
    // Add custom properties here
 
 
    wxsWidget::OnAddExtraProperties(Grid);
 
}
 
 
If it won't be called, item wont allow to edit any events because they are added inside <tt>wxsItem::OnAddExtraProperties(Grid);</tt> call.
 
 
 
==== Reacting to change of custom properties ====
 
 
 
Processing changes of custom properties is simillar to creating them. We just have to override following function:
 
 
void OnExtraPropertyChanged(wxsPropertyGridManager* Grid,wxPGId Id);
 
 
It has extra parameter comparing to previous function - Id. It's id of property which was changed. It's advised that you compare value of Id with identifiers generated inside <tt>OnAddExtraProperties</tt> to avoid unnecessary reads from property grid. At the end of this function you should also call original one but only if you're sure that your properties have not changed:
 
 
void CustomClass::OnExtraPropertyChanged(wxsPropertyGridManager* Grid,wxPGId Id)
 
{
 
    if ( Id == Property_Id )
 
    {
 
        // Read value of property here
 
 
        NotifyPropertyChange(true);
 
        return;
 
    }
 
 
    wxsWidget::OnExtraPropertyChanged(Grid,Id);
 
}
 
 
Note that there's also call to <tt>NorifyPropertyChange(true);</tt> at the end of value reading. This call updates all things related to current resource: regenerates source code and XRC files if necessary, updates the content of editor and does few more things to keep wxSmith's state up to date.
 
 
==== Reading data from XML (XRC) structures ====
 
 
 
Reading of our custom properties is done inside following function:
 
 
bool OnXmlRead(TiXmlElement* Element,bool IsXRC,bool IsExtra);
 
 
The Element argument is object represending xml node of current widget. To load custom properties we must locate child nodes and read data from them. Code::Blocks and wxSmith are using [http://www.grinninglizard.com/tinyxml/ TinyXml] to operate on xml structures so to get more informations on how to read and manipulate xml data, read [http://www.grinninglizard.com/tinyxmldocs/index.html TinyXml's documentation].
 
 
The <tt>IsXRC</tt> and <tt>IsExtra</tt> arguments require some better description.
 
From the very beginning wxSmith tends to be compatible with XRC files which allow storing structure of window inside xml file. Usually XRC files are limited to widgets which are provided with wxWidgets library. And they don't provide some extra data used by wxSmith like enteries for event handlers and variable name. wxSmith does split data of widgets into two parts - the firs one is strict XRC data and the second one is extra data provided by wxSmith. If <tt>IsXRC</tt> parameter is true, this mean that function should read XRC data part, if <tt>IsExtra</tt> is true, this mean that it should read extra data (both arguments may be true in one call). Most of contrib items would have XRC support disabled so we should read data only when IsExtra is true:
 
 
bool CustomClass::OnXmlRead(TiXmlElement* Element,bool IsXRC,bool IsExtra)
 
{
 
    if ( IsExtra )
 
    {
 
        // Process xml structures here
 
    }
 
 
    return wxsTool::OnXmlRead(Element,IsXRC,IsExtra);
 
}
 
 
At the end of this implementation we must call original function as usual ;)
 
 
 
==== Writing data to XML (XRC) structures ====
 
 
 
Writing data into xml structures is simillar to reading them. We have to implement following function:
 
 
bool CustomClass::OnXmlWrite(TiXmlElement* Element,bool IsXRC,bool IsExtra)
 
{
 
    if ( IsExtra )
 
    {
 
        // Store data into xml structure
 
    }
 
 
    return wxsTool::OnXmlRead(Element,IsXRC,IsExtra);
 
}
 
 
The meaning of arguments is same as in case of reading data. The only difference is that we write data here instead of reading it.
 
 
 
 
== Updating wxChart item ==
 
 
Ok, now if we have some theoretical knowledge, it's high time to do some real example. We will update wxChart item and add some more properties into it.
 
 
 
=== Adding property for internal wxChart's style ===
 
 
 
First thing is that extra style we wasn't able to provide last time. We will use flags property for it. Previously we provided empty function body for <tt>wxsChart::OnEnumWidgetProperties</tt> and now it's time to fill it.
 
 
To build flags property, we need values for it and it's names. For values array we could use direct values of flags as they are declared in wx/chartctrl.h header file, but this has one disadventage: We won't be able to use DEFAULT_STYLE flag since it contains few other flags inside. So we will have to create out custom flag for that grouping style:
 
 
void wxsChart::OnEnumWidgetProperties(long Flags)
 
{
 
    static const long DEFAULT_STYLE_FIX = 0x1000;  // Fixed flag value for DEFAULT_STYLE
 
 
    static const long Values[] = { USE_AXIS_X, USE_AXIS_Y, USE_LEGEND, USE_ZOOM_BUT,
 
                                    USE_DEPTH_BUT, USE_GRID, DEFAULT_STYLE_FIX };
 
 
    static const wxChar* Names[] = { _T("USE_AXIS_X"), _T("USE_AXIS_Y"), _T("USE_LEGEND"),
 
                                      _T("USE_ZOOM_BUT"), _T("USE_DEPTH_BUT"), _T("USE_GRID"),
 
                                      _T("DEFAULT_STYLE"), NULL };
 
 
    WXS_FLAGS(wxsChart,m_Flags,_("wxChart styles"),_T("wxchart_styles"),Values,Names, DEFAULT_STYLE_FIX )
 
}
 
 
So the first thing we do here is to create arrays with values and names for them. We used DEFAULT_STYLE_FIX for last value to allow DEFAULT_STYLE too but in names we used standard name. Also note that names array MUST end with NULL entry to mark end of array. Another thing worth mentioning is that we also have to add <tt>long m_Flags</tt> member into <tt>wxsChar</tt> Class
 
 
Ok, let's recompile and test our result:
 
 
[[Image:Wxs_ext_12.png]]
 
 
So we have our property working. Now it's time to make in affect preview and generated code. But before we do this, let's move those arrays used to create property into global scope (into unnamed namespace) because we will need them in other functions. Also we need to set initial value for m_Flags member, so let's set it to DEFAULT_STYLE_FIX to include DEFAULT_STYLE when creating new charts.
 
 
Code after change should look like this:
 
 
...
 
    // Defining styles
 
    WXS_ST_BEGIN(wxsChartStyles,_T("wxSIMPLE_BORDER"))
 
        WXS_ST_DEFAULTS()
 
    WXS_ST_END()
 
 
 
    static const long DEFAULT_STYLE_FIX = 0x1000;
 
    static const long Values[] = { USE_AXIS_X, USE_AXIS_Y, USE_LEGEND, USE_ZOOM_BUT,
 
                                    USE_DEPTH_BUT, USE_GRID, DEFAULT_STYLE_FIX };
 
    static const wxChar* Names[] = { _T("USE_AXIS_X"), _T("USE_AXIS_Y"), _T("USE_LEGEND"),
 
                                      _T("USE_ZOOM_BUT"), _T("USE_DEPTH_BUT"), _T("USE_GRID"),
 
                                      _T("DEFAULT_STYLE"), NULL };
 
 
}
 
 
wxsChart::wxsChart(wxsItemResData* Data):
 
    wxsWidget(
 
        Data,              // Data passed to constructor
 
        &Reg.Info,          // Info taken from Registering object previously created
 
        NULL,              // Structure describing events, we have no events for wxChart
 
        wxsChartStyles)    // Structure describing styles
 
{
 
    m_Flags = DEFAULT_STYLE_FIX;
 
}
 
...
 
 
 
Ok, now we can change function which builds source code. now it looks like this:
 
 
void wxsChart::OnBuildCreatingCode(wxString& Code,const wxString& WindowParent,wxsCodingLang Language)
 
{
 
    switch ( Language )
 
    {
 
        case wxsCPP:
 
        {
 
            wxString StyleCode;
 
            for ( int i=0; Names[i]; i++ )
 
            {
 
                if ( m_Flags & Values[i] ) StyleCode << Names[i] << _T("|");
 
            }
 
 
            if ( StyleCode.IsEmpty() ) StyleCode = _T("0");
 
            else                      StyleCode.RemoveLast();
 
 
            Codef(_T("%C(%W,%I,(STYLE)(%s),%P,%S,%T);\n"),StyleCode.c_str());
 
            break;
 
        }
 
 
        default:
 
            wxsCodeMarks::Unknown(_T("wxsChart::OnBuildCreatingCode"),Language);
 
    }
 
}
 
 
First we iterate through all styles and test if given style is set (note we have to use braces because we declare local variable inside switch statement). If it is, we add style's name ended with '|' operator (to allow more styles). Finally we have to check if string containing styles is empty. If it is, we replace it with zero (because we can not put empty string in place of function's argument). If it's not empty (at least one style was added), we have to remove unnecessary '|' character at the end of string by calling <tt>RemoveLast()</tt>. In Codef function we use %s formating sequence, just like in standard printf function. To prevent compile errors, we convert produced style to STYLE enum.
 
 
Now let's affect preview. This will be much easier since we almost have exact values:
 
 
wxObject* wxsChart::OnBuildPreview(wxWindow* Parent,long Flags)
 
{
 
    long RealFlags = m_Flags;
 
    if ( RealFlags & DEFAULT_STYLE_FIX ) RealFlags |= DEFAULT_STYLE;
 
    return new wxChartCtrl(Parent,GetId(),RealFlags,Pos(Parent),Size(Parent),Style());
 
}
 
 
The only thing which have to be fixed is that if DEFAULT_STYLE_FIX flag is set, we "unfix" that by or-ing value with DEFAULT_STYLE.
 
 
Ok, let's find out how it works... everything works fine :). My first impression was that there's something wrong, but wxChart seems to interpret properties in strange way. This is probably caused by fact that there's no chart data to be displayed yet.
 
 
 
=== Adding chart data property ===
 
 
Now it's time to do some really complex task. We will add property which adds some data into chart widget so it would be possible to show some content in editor, preview and of course in target application. But before we do this, we have some knowledge about wxChart's data managment.
 
 
Each wxChartCtrl widget can show few sets of data which create one chart shape (one pie, one line etc). Each of these sets is stored inside classes derived from wxChartPoints. And this structure keep data of specific points, percentages etc. In wxChart we have following types of charts:
 
 
* Bar
 
* Bar3D
 
* Pie
 
* Pie3D
 
* Points
 
* Points3D
 
* Line
 
* Line3D
 
* Area
 
* Area3D
 
 
And different types may be stored inside one chart giving many charts inside one control.
 
 
Ok, first thing we need is to provide dynamically changing list of data sets (wxChartPoints structures). Because it's not as easy as in case of base properties, we have to handle our properties manually. So first we add new functions which will manage our custom properties.
 
 
We add this code into wxsChart's declaration:
 
 
        void OnAddExtraProperties(wxsPropertyGridManager* Grid);
 
        void OnExtraPropertyChanged(wxsPropertyGridManager* Grid,wxPGId Id);
 
        bool OnXmlRead(TiXmlElement* Element,bool IsXRC,bool IsExtra);
 
        bool OnXmlWrite(TiXmlElement* Element,bool IsXRC,bool IsExtra);
 
 
and the following basic implementations:
 
 
void wxsChart::OnAddExtraProperties(wxsPropertyGridManager* Grid)
 
{
 
    wxsWidget::OnAddExtraProperties(Grid);
 
}
 
 
void wxsChart::OnExtraPropertyChanged(wxsPropertyGridManager* Grid,wxPGId Id)
 
{
 
    wxsWidget::OnExtraPropertyChanged(Grid,Id);
 
}
 
 
bool wxsChart::OnXmlRead(TiXmlElement* Element,bool IsXRC,bool IsExtra)
 
{
 
    return wxsWidget::OnXmlRead(Element,IsXRC,IsExtra);
 
}
 
 
bool wxsChart::OnXmlWrite(TiXmlElement* Element,bool IsXRC,bool IsExtra)
 
{
 
    return wxsWidget::OnXmlWrite(Element,IsXRC,IsExtra);
 
}
 
 
These implementations are just calling original functions to let wxSmith do it's work inside of them.
 

Latest revision as of 20:34, 19 April 2007