Creating a plugin which adds new item into wxSmith
Warning - it's under construction
What you should know before reading this tutorial
This tutorial is about creating new plugin which extends the functionality of wxSmith plugin. Before you start you should have wxWidgets and Code::Blocks compiled from source code. This step is required and you shouldn't continue as long as you're not interested in theoretical knowledge only. And you should read Creating a simple "Hello World" plugin, it's not necessary, but may help in many situations I haven't considered. I also assume that you know at least basics of C++ ;).
This tutorial was created on Windows environment but it should be quite easy to work simillar on Linux (at least by using Code::Blocks). We will try to add wxChart item into wxSmith. We won't cover all aspects of wxChart class here, but this tutorial may be a good starting point for creating more powerfull and sophisticated extensions :) It will show only some basics of wxSmith, so I hope to write few more tutorials covering other parts of this system.
Just need to make one more appointment - internal structure of wxSmith may change. I'll try to stay as close to current interface as it's possible, I also try not to write about things I'm planning to change (or I'll at least notify that it can be outdated soon), but can not grant that all your work will compile after a year (or maybe even few months). I'll try to keep these tutorials updated so you'll be able to get back here and find changes.
Creating new plugin
Let's start with new plugin. Most of informations here will be simillar to Creating a simple "Hello World" plugin, but there may be some small differences :)
We start with new Code::Blocks plugin wizard. It's available in File->New->Project menu. We select Code::Blocks plugin there and start with following window:
I've named my plugin wxSmith - Contrib Items and placed it into contrib plugins folder. Choosing this folder probably wasn't a good idea. Any other folder, not related to Code::Blocks will work the same, and that should be your choice ;)
On the next wizard page we choose plugin type.
Because this plugin doesn't match any particular plugin type, we use Generic. In fact, our plugin won't do many do usual things other plugins do. It will use totally different scheme for extending wxSmith's functionality. But even though, we have to create it using some scheme to let Code::Blocks recognize and load it.
We follow the instructions in wizard and end up with new plugin.
We should now be able to compile out project, but let's add binding to wxSmith first. We need to add wxSmith's directory into include locations list:
and it's output folder where .lib file will be placed:
Last thing we need to add to bind our plugin into wxSmith is wxSmith's library:
Make sure it's on the top of list since it looks like MingW des care about the order in which libraries are linked.
Now we close project's options and try to compile. Code::Blocks will ask for settings for wxSmith. We have to fill base path which is required, but also include and lib directories will be required since they are not as in usual cases:
Note that include dir points to wxSmith's directory and lib points to codeblocks\src\devel\share\CodeBlocks\plugins because that's where wxSmith will create it's .lib file.
If everything compiles fine, we can move to next step
Compiling in contrib widget
Now it's time to add widget we want to add into wxSmith right into our plugin. I have choosen wxChart hosted at wxCode, mostly because it will be easy to add and it looks promising :) First thing we need is source code. It's freely available at sourceforge (the link above). After unpacking it into our plugin's folder the directory structure should look like this:
I'd like to compile this item just as a part of plugin. Compiling it as external dll may lead to some problems because plugin would consist of many files. The easiest way is just to add wxChart's files into plugin's project.
Files we need are placed in wxchart-1.0\include\wx and wxchart-1.0\src (watch out for file in samples folder since it will try to create whole application).
There's one more thing left to make wxChart compile with wxSmith. We have to add it's include dir into search paths:
After adding that, project should compile fine with wxChart compiled into it.
It this point I wanted to test whether our plugin still works. To do that I've installed it in plugin manager. I've got the proove that it all went OK:
Enabling new item inside wxSmith
Adding suporting class
Now it's time to enable our item inside wxSmith. To do this first thing we have to do is to create new class that will support our wxChart. The name of class should be unique to prevent conflicts with other classes. Convention used in wxSmith is to replace wx in class names with wxs. So we create wxsChart class:
Note three extra settings which have to be added: consructor arguments (*), Ancestor(**) and Ancestor's include filename (***). Filling up these three fields make things much easier.
Item's images
Another thing we need for out item are icons. wxSmith require two icons for each item. First one should be 32x32 pixels (it's used for bigger version of palette and inside tools pane), second one 16x16 (used in resource tree and default small palette). I've created them from wxChart's screenshots using Paint.NET and converted them to XPM using GIMP. You may wonder why I want XPM files. The reason I've choosen that is that XPM files can be linked directly into source code with one single #include and they're directly supported inside wxBitmap and wxImage constructors. When we link images into dll, we won't have to take care about some extra image files required for plugin to work.
Creating global information objects
The only thing needed to register item inside wxSmith is to create one variable from template called wxsRegisterItem. Created object will automatically register and unregister item from wxSmith and will provide basic informations about item before it's created. Because it does require bitmaps, we will load xpm data first. After instantiating wxsRegisterItem template we also define set of used styles, but that will be described later.
namespace { // Loading images from xpm files #include "images/wxchart16.xpm" #include "images/wxchart32.xpm" // This code provides basic informations about item and register // it inside wxSmith wxsRegisterItem<wxsChart> Reg( _T("wxChartCtrl"), // Class name wxsTWidget, // Item type _T("wxWindows"), // License _T("Paolo Gava"), // Author _T("paolo_gava@NOSPAM!@hotmail.com"), // Author's email (in real plugin there's no need to do anti-spam tricks ;) ) _T("http://wxcode.sourceforge.net/components/wxchart/"), // Item's homepage _T("Contrib"), // Category in palette 80, // Priority in palette _T("Chart"), // Base part of names for new items wxsCPP, // List of coding languages supported by this item 1, 0, // Version wxBitmap(wxchart32_xpm), // 32x32 bitmap wxBitmap(wxchart16_xpm), // 16x16 bitmap false); // We do not allow this item inside XRC files // Defining styles WXS_ST_BEGIN(wxsChartStyles,_T("wxSIMPLE_BORDER")) WXS_ST_DEFAULTS() WXS_ST_END() }
Important thing here is that we put all those informations inside nameless namespace. This will prevent redeclaration errors since usually all wxsRegisterItem instatiations produce variabe called Reg.
The arguments passed to wxsRegisterItem are easy to understand. Not all of them are used now, many are given just as information which may be used in future (f.ex. license may be used to check whether we can use item freely or not). Essential data fields which are used by wxSmith now are:
- Class name – name of item's class, will be used while generating declaration and for new operator, it's also identifier for item type, so there should not be two items with same name (only one of them will be available)
- Item type - type of item, for widgets like wxChart (they don't have children), it should be wxsTWidget. Type of item should match base class of class created to support this item. Other options are: wxsTContiner (f.ex. wxPanel), wxsTSizer, wxsTSpacer (only one item of this type is present) and wxsTool (f.ex. wxTimer). This tutorial concentrates on wxsTWidget classes so information presented here may be not enough to create other item types.
- Category in palette - giving empty category will prevent the item from being displayed, this name should not be translated in info (it must use _T() instead of _()), it will be translated later while generating palette
- Priority - Items with high values are placed on the left side of item palette and are easily accesible because of that
- Base part for variable names - it's used to generate variable name and identifier for items which don't have one or have invalid values
- Languages - set of languages supported by item, currently only wxsCPP is supported
- bitmaps - used in palette and resource browser
- XRC switch - if this value is true, this item is allowed in resources using XRC files. If it's false, item is not supported by XRC (which is usual case for contrib items). This value may be replaced by flags in future to allow supporting more characteristics of item. After switching to flags, code should still compile becuase XRC flag will have value 1 (value of true when it's converted to integer).
After registration object, we define item's styles. wxChart makes here two style sets: it's own made as enum STYLE (you should be carefull about that because it is really common name and it's defined globally in <chartctrl.h>) and flags (styles of window). When we talk about styles in wxSmith we always mean style argument as described in wxWidgets documentation (so here it will be flags). To help generating style set, wxSmith gives set of macros. Definition of set begins with WXS_ST_BEGIN. First argument is name of set, second is default style. WXS_ST_DEFAULTS() adds all default styles listed in wxWindow class help (not all may be used by particular item). Adding user-defined styles is done through WXS_ST(<style>) macro, but it wont be described with details in this tutorial. Definition of styles end with WXS_ST_END()
Constructor
Now we have all informations about item, so we can create out class. We had to declare these informations before supporting class' constructor because constructor require them. Here's some code from wxsChart:
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 { }
And that's all for constructor. When we try to compile it now, compiler complains about pure virtual functions. So we have to implement them. List of functions is as follows:
- Generating source code for this item
void OnBuildCreatingCode(wxString& Code,const wxString& WindowParent,wxsCodingLang Language);
- Building preview of this item (either for editor or for full window preview)
wxObject* OnBuildPreview(wxWindow* Parent,long Flags);
- Enumerating extra properties of this widget
void OnEnumWidgetProperties(long Flags);
- Enumerating header files required by this widget
void OnEnumDeclFiles(wxArrayString& Decl,wxArrayString& Def,wxsCodingLang Language);