Wx::Perl::Smart Design Decisions

The simple goal of Wx::Perl::Smart (WPS now for short) is to make WxPerl - GUI programing fast, fun and technically sober. By that I mean you still have full access under the hood (like Moose does) to all features of the old ways. Oh, and speaking of OO, I decided using no framework (yet), not even Moo. While sitting on top of Wx, you don't count bytes in memory, but there is no big syntactical gain now, since there are almost no attributes and the ones I have need a special treatment as described further along this article.

First thing people gets annoyed of, when the shiny visuals of Wx pursued them into using it, is the wordy syntax. And you can face that with two strategies: wrapping and subclassing.

I use both at once, but in two flavours. On one hand I create "new" widgets like Wx::Perl::DisplaySlider or Wx::Perl::RadioGroup (should also appear on CPAN this year) by subclassing from Wx::Panel. On this panel I placed a group of functionally tied widgets with an API reduced to the minimum.

Wx::Perl::RadioGroup->new($parent, [qw(one two three)]);

That will give you a horizontal group of logically combined radio button, with the first selected, but of course you can with optional parameters say which is default, choose a vertical orientation and what callback to run when hitting any of it. And you get a unified getter and setter which tells you which number is selected. Yes there is the Wx::RadioBox doing the same thing, but its more wordy and it's just a sizer, so you have to deal more with reparenting widgets and some other issues too. In the same spirit is the DisplaySlider a panel with an optionally labelled slider with a small textbox, showing the selected value, with the option, that you can change value of the textbox too, which moves the slider and the same event gets triggered. Both widget modules shorten the widget generating code (also no additional line to mount the callback) and arranging gets simpler when you only deal with the logical groups.

Because both are also useful as standalone modules they use nothing from the Smart namespace, just vanilla WxPerl and they will also become standalone CPAN modules. Of course and as promised here I publish them with the useful work of other authors as a Bundle. Wx::Perl::DrawMap is an animal on its own since it simplifies to get custom graphics on a selected canvas and frees you from dealing with the interplay of DC, Bitmap, pens, colors, .... you just talk with the StaticBitmap on which it gets drawn.

The parameters of these widgets resemble the old style but I usually leave out position and size because that's handled by a sizer anyway and only in rare cases you want to set up a min size that's more useful that what Wx provides e.g. with Comboboxes. The ID also doesn't interests hardly anybody. Since the reference to the Wx object ends up in a Perl data structure you have other means to ID this widgets and Wx::Perl::Smart Frame (or Panel later too) does it also for you if you like, getting a nice string name not a number. These 3 parameters bloat your code in most cases, because the really interesting stuff, a parameter called style comes after them. And this is done by merging longish numeral constants, so there is plenty room for dropping sugar on in too.

To put this sugar on top of the usual stuff and the selfmade widgets (I tried not be too smart and different from vanilla with the basic stuff) I created the Wx::Perl::Smart::WidgetFactory. I was rather stupid with this because I have smart widget generation spread over several modules and didn't even spotted that code smell immediately. So that where I am currently (fixed now) but like with the individual widgets, even if Wx::Perl::Smart will come as a bundle (its all not so much pure Perl) you could just use the factory separately.

The WPS::Sizer then only does combine the widgets, but if it gets smart shortcuts, it forwards them to the factory. This way you can also subscribe widgets to a smart frame/panel and the widget is actually generated only when put into a layout. And the Sizer is one module to rule them all, BoxSizer, various GrindSizer even notebook or splitter are in essence just thing to arrange subgroups of widgets and have similar syntax in GCL. Like with factory this code is also now arranged stupidly and will be refactored into one class.

The WPS::Frame is like described previously a granddaddy to its widgets. When you subscribe widgets to it with the smart factory syntax you can even omit the parent, which you do also if placing it directly into the layout, because the sizer knows the current parent and takes care of that. So the frame is the admin of the logical units of the program. Lately I found out that strings should belong to it too. Not only it makes your GCL (layout code) clearer but you also don't have to change layout when strings are changing or when you set the localisation into the different language. So the frame becomes the functional abstraction layer for assembling the big parts. And with WPS you're free free to choose how much organizational overhead you need. (its really a tiny thin layer at all). Here some snippet of the current state of GCL (labels start with ~ which is a forward compatible syntax with Perl 6 I think)

],[ # right half
	-TabbedBox => [ 
		'~oscillators' =>[[
			{border => 5, flags => &Wx::wxGROW|&Wx::wxALL},
			['~mode :', '<app_mode>'],
			-LabeledBox =>['~frequency' =>[qw( <frequency_x> <frequency_y>)]],
...

So whats left for the module GCL::Wx, which has already its repo on bitbucket. Thats merely clue code, anothe very thin layer because Wx doesnt have to stay the only backend for GCL.

Leave a comment

About lichtkind

user-pic Kephra, Articles, Books, Perl, Programming