A new wobbly wheel for GUIDeFATE

A couple of weeks ago a little misunderstanding about what GUIDeFATE was about led to an interesting comment. This tool had been designed to simplify GUI design using a text editor, and met the challenges of having a number of weakly supported potential targets to produce a semi consistent interface. Essentially producing a GUI for Perl applications has never been easy. A number of back-ends exist ( e.g Wx, Tk, Gtk, Win32, Qt etc) all with different approaches, most with rather outdated documentation, often not universally easy to install. A newbie like myself was never going to find this straight forward. So a tool was born that abstracts out the complexities of GUI design, producing near identical interfaces in multiple back-ends, all from a textual representation. As each interface was accommodated and announced, came reports of other folk being unable to use said interface, followed by a new module to use another GUI toolkit; so now we have a tool that can now accommodate 5 desktop UI systems.Surely that must cover all bases? Apparently not.

In response to a blog out-lining the difficulty I had had with the Qt paradigm of SLOTS and SOCKETS for interaction between the UI and application logic, and the need for a custom dispatcher, was a comment relating to WebSockets. Now GUIDeFATE was intended to be desktop UI focused, so clearly WebSockets are not the Sockets at issue. But Ron suggested I try out other people's efforts before re-inventing the wheel, thus finding this particular wheel rolling in a different direction. I started finding out about Mojolicious, Dancer, Catalyst. These are clearly the efforts of geniuses, with multiple dependencies and difficult to crowbar into an existing toolkit without duplication and “re-inventing the wheel”. I requested advice.

Flexibility is proportional to complexity

To connect to my less efficient brain requires much greater simplicity. So I quickly abandoned all these powerful frameworks. I chose the simplest possible websocket client, with the simplest available server, unashamedly ripping off the code from the examples provided. Attached them to quite possibly the simplest UI generator in the world... GUIDeFATE, of course☺. The result is GFweb.pm. A module for GUIDeFATE that generates and starts both the server and the client for a web-app-like interaction with a UI nearly identical to the desktop applications and with nearly completely unchanged programming logic. The extra effort required to transform a desktop app to a web application? Just change the small string selecting which back-end you want and the address/port to use.

my $gui=GUIDeFATE->new($window,"web","q");

The wheels come off..

Websocket rpsls.png

Admittedly the tool keeps things simple: Only a handful of widgets, with limited interaction potential: hopefully just enough for a quick and dirty graphical application, simple enough for a noob like me with little knowledge of JavaScript or WebSockets. The reinvented wheel is decidedly wobbly. File selection and message boxes are not yet done...my problem is how to handle the client side responses which the server-side programming logic is waiting for to further process. I will figure it out, or somebody will point me in the right direction...it's inevitable. This experimental version is uploaded into GitHub. The applications need to be started in a folder containing the dependent files (preferably from a terminal) and popups need to be enabled (the application currently also starts a logging window to enable debugging).

Four backends now for GUIDeFATE...but the struggle continues

Just as you are thinking you got the hang of something, believing you know how to work the system, imagining you have a problem licked, then you wake up to find out it was just a dream. That has been my experience in developing GUIDeFATE (A contrived acronym for the project - Graphical User Interface Design From A Text Editor).

GUIDeFATE is a tool that simplifies GUI design by choosing only a few useful elements that make a usable graphical application and making those elements accessible to the beginner developer. Handy too if you want a quick and dirty desktop application in Perl. A tool that converts a string into a GUI, using one of the many backends that exist. So I have been making this over the past month or so, using the often woefully outdated resources found on the internet. I had a rudimentary Wx Backend after about a week, by another week I had Tk, and was persuaded to put the project up on Github. Soon Gtk was also covered easy as pie in 3 days. Even started working on Win32...(I only have Linux machines at home, fortunately also have more skilled help in this matter in the form of mpersico)...then CRUNCH...

A fellow redditor daxim suggested Qt. Great idea, I thought. Qt well supported on Linux and other platforms. And Gtk was a breeze to handle. Significantly Qt and Perl have had a close relationship. This would be a walk in the park I figured. I figured wrong. Just to get Qt development setup on my system was a struggle. Installs from CPAN failed, installs from repositories are no longer updated. ppas claiming to offer this also fail. Switched to Kubuntu, wrecking some of my settings, no joy. Near defeat, daxim once again gently guided me to a reasonable install of Qt4. Problems over? No. Just beginning.

Qt

Qt is sophisticated, powerful, all-encompassing. Getting control of this sophistication and power needs huge brains which I lack and a dextrous use of Qt Designer, which defeats the object of GUIDeFATE. Secondly, Qt internal design appears to have evolved in a parallel universe, isolated from other paradigms of GUI design, even though on the surface looking similar. Sort of like Convergent evolution that gave flies and birds wings and legs. To crowbar this interface into GUIDeFATE was not easy (for me).

Key to this is how GUIDeFATE allocates actions (eg on button click, menu select etc) to widgets...it merely takes a reference to subroutine in main:: that has not been yet created. An example from a button widget generator from the front end sends a reference to a list of parameters for each widget like this: -

addWidget(["btn",$bid, $label,[$locationX,$locationY,[$width,$height], \&{"main::btn".$bid}]);

GUIDeFATE's middleware for each backend stores this referenced list in a list of widgets before it sets up content in new(). This means that the developer can create his own functions easily as long as he knows the id of the widgets, the autogenerator can generate the skeleton for these functions and Bob's your uncle. All the other backends quite easily accepted a dereferenced function as parameter in their widget.

Not so Qt. Qt uses SLOTs and SIGNALss. A powerful system, SLOTS are attached to the Qt::MainWindow, which is a Parent of the Qt::Widget container (in my case) containing all the widgets. So the SLOTS are in a different place to the generator of the SIGNAL. There is no way to add slots dynamically (as far as I can see), and you have to declare them at the beginning...difficult if you dont know what the functions are going to be. Then you have select a SIGNAL to be associated with a widget and connect the two. A simple Perl example is here.

Fortunately there is SignalMapper. This allows SIGNALs to be mapped to a single SLOT in signal mapper. Then comes the complexity of extracting signals from different events by a dispatcher which distributes that signal to the correct function.

Setting up the SignalMapper in new(): -

$self->{SigMan} = Qt::SignalMapper($self);
$self->connect($self->{SigMan}, SIGNAL 'mapped(QString)', $self, SLOT 'mapAction(QString)');

Adding a Signal to the widget, and giving the signal mapper clues about the source for the dispatcher to work on:-

$self->connect($canvas->{"btn".$id}, SIGNAL 'clicked()', $self->{SigMan}, SLOT 'map()');
$self->{SigMan}->setMapping($canvas->{"btn".$id}, "btn".$id);

And creating a dispatcher: -

sub mapAction{
   my $widgetIndex=getItem(shift);                   #find the widget parameters
   my @widget=@{$widgets[$widgetIndex]};             #using the clue (the Id)
                                                     #provided by SignalMapper
   my $wType=shift @widget;                          #remove the type,
                                                     #which allows you locate
   if ($widgetIndex !=-1){                           
      if     ($wType eq "mb")   { &{$widget[3]};}    # the function referenced
      elsif  ($wType eq "btn")  { &{$widget[4]};}    # and call that function
      elsif  ($wType eq "combo")  { &{$widget[4]};}
   }

}

So learnt a new paradigm, and finally GUIDeFATE 0.08 has another backend.

Four backends supported.png

One thing I am struggling with is understanding packages and the differences between "use ", "use parent " and "use base ", and other ways of absorbing other modules into the code. It takes a lot of guesswork and fiddling and trying different combinations for me to get these backends to work. It may be the way their Perl interfaces and the C libraries work. More likely it is something to do with my lack of understanding, but it sure leads to messy code, and scrambled brains.

Guiding Fate

Fate

Somebody once said, that the power of a programming language is not what it lets you do, but what it lets you do easily. Might be Larry himself who said it, not sure, but I heard it at the London Perl Workshop. I started learning Perl from an old second hand book I found in a charity shop a few years ago. I can't say I am any good at it. While previously I could find lots of resources available, these are increasingly harder to find, more outdated, and less able to address modern use cases. Some folk even suggest it is terminal decline. It would be a pity. It is a powerful language, and using it for me has given me a daily discovery for some feature that I didn't know, and exposed me to a large number of clever folk who can bring a different angle to a problem you have struggling with. To my mind it reflects the versatility of a language that has more than one way to to anything.

I guess that leaves us a few choices. One may be to learn a different language, deserting an old faithful friend for something more modern and youthful. Another may be to just hang around the old meeting grounds, reminiscing about the good old days, tapping the bar with the calloused fingertips, mumbling about hashes and sigils, and talking about how they don't make programming languages like they used to. Yet another may be to prove that anything that can be done by those young whippersnapper python and go programmers can be done in Perl, easier, quicker and more intelligently. Of course we all know it can be done, but many of us stopped believing it...and there starts the downwards spiral. Kismet, as Nelson said.

The only way to reverse this is a steady stream of evidence that makes Perl useful and accessible to everyone.

GUIDeFATE

Ultimately the product of a programming effort must exceed the effort required to achieve it, not just in terms of actual yield, but the appearance of that yield. As I say, I know I am not a skilled programmer. But GUIDeFATE is an attempt at making programming a GUI application easier. It just uses the power of Perl in text manipulation and converts a textual representation into a quick and easy to use interface with the potential for multiple target backends. It is still a work in progress (only started a couple of weeks ago). But how is this for a quick and dirty GUI text editor and function plotter? Without knowing much about GUIs?

Designing the interface required nothing more than the ability to use the simplest text editor.

#!/usr/bin/env perl 
#A test script that crtaes a minimalist gui gnuplot
#use GUIDeFATE (which in turn depends on Wx)
#needs gnuplot to be installed

use strict;
use warnings;
use GUIDeFATE qw<$frame>;

#This string contains the definition of the interface
my $window=<<END;
+------------------------------------------------------------------------------+
|T  Test GnuPlot                                                               |
+M-----------------------------------------------------------------------------+
|+T------------------------------------++I------------------------------------+|
||text editor                          ||plot.png                             ||
||                                     ||                                     ||
||                                     ||                                     ||
||                                     ||                                     ||
||                                     ||                                     ||
||                                     ||                                     ||
||                                     ||                                     ||
||                                     ||                                     ||
|+-------------------------------------++-------------------------------------+|
|                                                                              |
+------------------------------------------------------------------------------+

Menu
-File
--New
--Open
--Save
--Quit
-Chart
--Plot
--Save As

END


GUIDeFATE::convert($window, "v");
my $gui=GUIDeFATE->new();
$gui->MainLoop;

Adding a few more bits of gnuplot piping yields a functioning graphical interface to gnuplot... GUIGnuplot.png

What next?

As I have developed this it is clear that while exciting and potentially very helpful, there are many things that need to be considered form this time on:

  1. Entry to CPAN : This is not yet, I feel, ready. Nor am I exactly sure how this should be done. I am working on it though
  2. It is clear that many potential users have difficulty on installing wx on which the current iteration depends, (although eventually GUIDeFATE will support multiple back ends) I need to know which will the best target that will benefit the most people.
  3. I will be adding bits to the interface, of course. It would be useful to know what other people would find useful.

My difficulty would be picking what to do next...

About Saif

user-pic An Orthopaedic Surgeon, A Tissue Engineering Scientist, Lecturer, (and Hobbyist Programmer, Electronics Engineer and Roboticist)