Styling wxWidgets/wxAUI to look like Visual Studio 2010
I like wxWidgets; it is a nice way to write graphical user interfaces in C++ (though some people will say that writing graphical user interfaces in C++ is stupid, and that you should use C# instead, but I digress). In particular, wxAUI is a nice quick way to create interfaces with draggable / resizable / floatable / dockable / splittable panes / tabs and all that jazz, and wxScintilla/wxSTC is a nice wrapper around Scintilla to give you the basis for a very nice code editor control. One problem with wxAUI is that most people use the default theme, so the default theme begins to look common once you've seen a few wxAUI-based applications. The default theme is also starting to look a little bit dated and old. Conveniently, wxAUI was structured to have pluggable art providers, meaning that it really isn't too hard to write a completely different theme for it. I've taken advantage of this feature of wxAUI to give a Visual Studio 2010 theme to applications written with wxAUI. The end result looks like the following:
For reference, the same application using the default wxAUI theme looks like:
For reference, Visual Studio 2010 looks like:
Most of the process of implementing this is obvious: take the code for the default art providers, rip out most of their innards, and replace them with new drawing code. There are however a few difficult steps:
- Changing the colour of the text in the status bar is only possible by using an owner-drawn status bar, which wxWidgets doesn't support by default. To support this, I derived a new class from wxStatusBar and overwrote the virtual methods which send the configuration windows messages to the native status bar, in order to add the SBT_OWNERDRAW flag to them. Then, as wxWidgets' built-in owner-drawn support only covers menus and controls, I added some logic to wxFrame to detect owner-draw messages intended for the status bar and send them to it. Then the derived class receives this message and writes the correct text in the correct colour.
- wxAuiNotebook creates its own wxAuiManager internally, so even if you call SetArtProvider on the wxAuiNotebook, you only replace the default tab art with your custom tab art. You also need to replace the default dock art of the notebook with your custom dock art. The best way I've found to do this is call SetArtProvider on the notebook to set the tab art, then call GetAuiManager on the wxAuiNotebook, do a cast to remove the const-ness of the resulting object, and then call SetArtProvider on that to set the dock art. It seems ugly to do that cast, but I can't see a cleaner way without adding a new method to wxAuiNotebook, which I try to avoid doing.
- To allow the active tab / pane to be drawn slightly differently, you're meant to pass the wxAUI_MGR_ALLOW_ACTIVE_PANE flag to wxAuiManager. As far as I can tell, this isn't currently working correctly in the trunk version of wxWidgets, and I'm still trying to get it work fully correctly. So far, I've tweaked wxAuiManager::OnChildFocus to better find the focused panel from the focused window, which improves the behaviour a fair bit.
- The current notebook implementation keeps track of a normal/hover/active state for buttons, but only normal/active for tabs. To get the styling I wanted, I extended the notebook implementation to track a hover state for tabs - this just needs a few extensions to wxAuiTabCtrl::OnMotion and wxAuiTabCtrl::OnLeaveWindow.
- Related other changes to wxWidgets: ticket 11552 and ticket 12014.
PS. Yes, my current project is a Lua IDE / debugger.