SmartWin Internals

From SmartWin Wiki

Table of contents

Architecture

The basic building blocks behind SmartWin++ are:

Widgets

A Widget is everything visible to the user and often can be interacted with by the end user in some way such as clicked, dragged, pushed etc. Almost all classes in SmartWin++ are template classes and Widgets are no different.

Widget Parameters

Most Widgets have two template parameters although there are variations.

One parameter defines the type of the Parent Widget or the Widget responsible for handling events. This is necessary in order to provide type-safe Event Handlers. The Event Handler internals expect the callback function submitted to be of type "Parent", so it's almost impossible to get this wrong or declare a function to something "wild" as the Event Handler for a given Event.

The second template parameter to the Widget is the type of the MessageMap:

  • DialogWidget
  • ModalDialogWidget
  • NormalWidget
  • MDIChildWidget

This is a policy parameter (ref. Policy Based Design, Andrei Alexandrescu) which defines how the Widget behaves in certain circumstances, for example, how to return from a handled/unhandled message. This is necessary because the Windows API differentiates how the controls behave in their message handling and since SmartWin++ strives to reuse code every place it can. You wouldn't expect a GUI library with more than 20 Widgets, thread classes, drawing classes etc. and with more then 50 functions in each Widget to have less then 25 000 lines of code... but, in fact, about half of all code is comments! SmartWin++ has brought the reuse of code onto a new level!

Some Widgets have only one parameter. For instance, the WidgetMessageBox only needs some way to access the HANDLE to its parent and therefore expects a function called handle() returning an HWND on it's Policy class. These Widgets can often be used without bringing in the rest of the library by simply including only that specific Widget.

Aspects

Aspects is just another way to reuse existing code. For instance, look at WidgetWindowBase. There's not much code there, maybe a few hundreds lines. Still there are almost 100 member functions (through inheritance from more the 10 Aspects) to which you have access! Aspects are also template classes so it's still 100% type-safe reuse, unlike normal OOP in which you lose more of the original type the further up in the inheritance hierarchy you come! In fact most Event Handler setters are implemented in an Aspect, but since the original Widget type and the Parent argument is given through template arguments, the Aspect still knows the exact type of both the event handling Widget (Parent argument) and the Widget, even though the Aspect is reused in maybe 10+ different Widgets!

Events

An Event is something which occurs. In SmartWin++ you can choose to get notified when certain Events happens. For instance, when someone chooses a new value in a WidgetComboBox or when a Widget needs repainting, you can be notified of this Event. (Or you can just choose to let the default Windows processing take care of it.) If you choose to handle an Event, this is done through Event Handlers which is client code (code you write) called when the Event occurs. You can set your Event Handler to an Event through calling one of the Event Handler setter functions which all starts with "on". For example, the Painting Event Handler is set through calling onPainting with a function pointer pointing to the (member/global/static) function you wish to get notified of when that Event occurs. All Event Handlers are expected to have a specific signature, but the first argument (in most cases) is the Widget Type raising the Event, this means you cannot reuse Event Handlers to different Events (almost) but you can reuse Event Handlers for different Widgets of the same type. For instance, the onPainting Event is expected to be handled in a function which takes a Canvas object by reference, plus if it's a Widget for a control (e.g. WidgetStatic) it's expected to take a WidgetStatic pointer as the first argument. Now if the Event, in addition to being for a WidgetStatic, is handled in a global or a static class function (as opposed to a member function) it's also expected to take as the very first parameter (before the WidgetStatic pointer) a pointer to the Event Handling Widget or a pointer to the object in which the WidgetStatic is contained. (A WidgetStatic cannot be "free." It must be contained within one of the "Container Widgets," for instance the WidgetWindow or the WidgetDialog.)

Coding Standard

The Coding Standard in SmartWin++ looks like this:

	class Zoo            // Capitalize Classes.
	{ // Start ALL opening braces on new lines.

		Human itsKeeper; // Prefix with "its" to indicate member variables.

		void setKeeper( Human keeper ) // Start with lower case for member functions.
		{
			itsKeeper= keeper;
		}
	};

	template<T1, T2> // We differ between the template arguments...
	class X          // ... and the class declaration.
	{
	private: // Accessor declarations on the same column as the class name and class opening brace.
		bool isMumboJumbo; // We start decalarations right after the accessor declaration...

	public: // ...and have one line of space between the next accessor declaration.
	};

// In class definition files...

/*...License info
*/
#include "x.h" // Start the inclusion parts right after the SmartWin license header...
#include "y.h" // ...and single space the inclusion directives.

namespace SmartWin  // Have one blank line before the namespace declaration
{

X::X()  // One blank line before the first member definition.
	: itxX( true ), // One tab before the first initializer...
	itsX2( false ) // ...and the next initializer on a new line.
{}  // Empty functions with opening and ending brace on same line.

void X::foo() // One line between every member implementation
{
	/*...*/
}

// When declaring and calling functions which takes parameters:
void foo( int x ); // Note the space in front and after the parameter declaration.

// If the function takes more then one parameter:
void bar( int x, int y ); // Notice the space after the first comma.

// When declaring for loops:
for( int x = 0; x < 100; x++ ) // Notice the space before the int, after the x++ and the space after every semicolon

// In addition the x < 100 has space, but this is less important.

// If adding multiline Doxygen comments, do it like this:
/** First line
  * Second line
  * Third line
  */
Note the space which indents the second and the third line to make 
the actual text start at the same place as in the first line.
Note also that the closing of the comment is on it's own line with the 
asterisk aligned at the same place as the asterisk above.
Note also the SPACE in FRONT of the text in each line. This is to separate 
the text from the asterisk to make it more readable when reading from the 
code itself and not from the Doxygen output.
Note also that these are SPACES and NOT tabs. This is to make sure it looks okay in all IDEs.

Everywhere we have non-empty parentheses add space before and after the included part. If the parentheses are empty do not add space internal spaces.

As much as possible try to use NATIVE types in the "interface" to the library. If a Windows API function returns a bool, we return a bool. For example:

BOOL WindowsAPIFunction() become
bool retVal = WindowsAPIFunction() == TRUE;
return retVal;

The variable name retVal is often used in returning values from functions. We prefer passing arguments by reference instead of by pointer. If the Windows API passes some kind of struct pointer we normally create our own struct which "wraps" the Windows API struct. A good example of this is the SmartWin::CreationalStruct which wraps the CREATIONALSTRUCT which is Windows API internal. We want to abstract the Windows API as much as possible, but there is more work to be done here. The Windows API way of passing the CREATIONALSTRUCT would be as a pointer. We pass it as a "const SmartWin::CreationalStruct &" to indicate it's an INPUT parameter. In POD structs we normally have all datamembers public and declares it as a struct.

If you write for the library as a member of the team or you're writing code which you think might be included in the main SmartWin++ branch and become a part of the library, you MUST follow these rules! If several people write code for the library and each has their own coding standard, it will be very difficult to read and understand the code. Note that we are not saying that our coding standard is right. We're just saying it's there'.' There probably exists a better coding standard, but as long as it's there it's sacred to us.

Do you work in a company which doesn't have a coding standard? It should be impossible to know who has authored which code. If you have five developers on your team and you can tell which developer has written each part of the code, due to different bracing standards and so on, it will become impossible to read that code at some point. Adopt a coding standard TODAY!

The Distinct Commenting Style

The comments found in SmartWin++ make look unusual to you. They are used to create the documentation. For instance:

/// Function for doing foo stuff
/** \image html x.jpg
  * \WidgetUsageInfo
  * foo is basically totally useless, but after heavy debates in the parliament we've decided to keep it as a
  * reference of how little it is possible to do with this much hassle!
  */
void foo();

We create the SmartWin++ documentation with a marvelous tool called Doxygen (http://www.doxygen.org). Doxygen relies upon some "funny" commenting style and can auto-extract those comments and format them into HTML and other formats. To facilitate the creation of the documentation, we've relied on Donald Knuth in these matters and are using, through Doxygen, Literate Programming!

Directory structure

SmartWin    Main SmartWin install directory
-include    The header files you'll have to include
--boost     The Boost library included for convenience
--io        Input Output helper classes not directly a part of SmartWin, see the iolib sample application
--loki      The Loki files included for convenience
--smartwin  Actual SmartWin++ inclusion files
---aspects  All SmartWin aspects
---widgets  All SmartWin Widgets
-lib        SmartWin library (.lib file and .a file) files
-source     SmartWin .cpp files, only needed when building the library
-tests      Sample Applications for SmartWin++ usage, also serves as "unit tests"
--PocketPC  Pocket PC, Windows CE or SmartPhone sample applications

The necessary parts of the Boost and Loki libraries are included in SmartWin++. If you have your own install of these libraries you may want to delete those directories and rebuild the library and your applications.