Skip to main content

More about WYSIWG GUI Designers and VI Programming

I've not always been blind.

For about twenty years I was a programmer, with a varying level of visual impairment.

Before I lost my sight very quickly in 2008 I had a level of sight which was the same for a long time, although it was gradually decreasing.

What this meant to me as a programmer in the early days of MS Windows was:

  • Keeping track of the mouse-pointer on the screen was tiring and not always easy
  • Using Windows graphical IDEs to design forms was hence not always comfortable for long periods
  • It was easier for me to rough-out a form, for example in MS Access with the IDE and then tweak the code with a text editor

For years I used QEdit, which was a very lovely text editor for MSDOS. I miss it.

Actually losing my sight totally, which made it necessary to embrace the use of a screen-reader made things a bit easier in some ways, and flipped things around a bit:

  • Now using the GUI on either MS Windows or Linux was easier, assuming the applications used are accessible

But, now using a drag-and-drop GUI designer was no longer possible, or at least not easy.

GUI Programming using Absolute Positioning

I used to write applications for MS Windows in vanilla C, using the native Win32 API calls.

That involved either generating controls with calls to CreateWindow and it's variants or by using resource (.rc files).

That made programming once I lost my sight difficult because:

  • I could no longer tell if my controls were all lined up correctly vertically and horizontally
  • My head was spinning with arithmetic every time I tried to size and position one control relative to the previous/next one

This approach, using absolute positioning also falls down when another user is not using the same sized font as you, or when the user clicks and drags the corner of your window to resize it. The formatting goes all to pot and looks like a dog's breakfast.

But more recent development tools have started using sizers.

In the sizer approach, controls are added to a kind of invisible net which controls the positioning.

Visualise it like this:

  1. There is a clear flat surface in front of you
  2. You need to place objects on that surface ina controlled way
  3. Imagine an invisible shield which is floating a couple of inches above the surface
  4. Cut into that shield are a number of holes through which you can place the objects on the surface
  5. When the objects are placed, changing the size of the surface will cause the invisible shield to change size as well and the objects will move and resize in a known and predictable way

I know of several GUI toolkits and languages that do this:

  • GTK, on Linux, and (I think) Windows and Mac
  • wxWidgets, multi-platform
  • wx.Python, multi platform
  • Java, multi platform

Varieties of sizer

Each of these tools has a variety of sizer types. Here is a by-no-means exhaustive list of them and a description of each:

Box Sizer

In either horizontal or vertical variants. Controls added either stack across (horizontal) or down/up (vertical).

Grid Sizer

A number of variants exist but essentially an X and Y grid of cells which are filled with controls by specifying their coordinates.

Sizers within Sizers

It is possible to add a sizer to another sizer to create complex GUIs.

For example if your form had a horizontal box sizer into which you have placed two vertical box sizer sizers, you will get left and right vertical sizers.

I know this explanation sounds complex but it really not.

One thing to remember is that the parent of a control is NOT the sizer into which it is placed but the object, usually termed something like panel, to which the sizer containing the control is added.

Using these sizer objects to position controls you will get:

  • A window which handles resizing and font changes correctly
  • A much easier life with no absolute-positioning headaches like arithmetic-overload

Sizers usually have some properties which control the way controls placed upon them will expand, contract and position themselves when the window is stretched or shrunken.

I still don't find WYSIWYG/drag-and-drop form designers very easy, or even possible to use, being totally blind, but the sizer approach has given me back a way to write complex and visually pleasing applications even though I can't see.

And of course the sighted authors of drag-and-drop IDEs tend to either just ignore accessibility, or assume that using them when you can't see is impossible. So keyboard shortcuts may not be included.

My personal favourite toolkit at the moment is wxWidgets, which is giving me a way to teach myself C++. Previously I stuck to C like a limpet.

I have yet to get to grips with:

  • GTK programming in C
  • Qt

Talking of Qt I believe accessibility is improved in version 5. It's been getting better and better. And now my C++ is coming on apace I will take a look at it.

All this is very exciting for the visually impaired programmer in a world where it is not as acceptable any more for an application to only run on one platform.

wxWidgets Accessibility

For a while now I've been writing wx.Python and wxWidgets applications for MS Windows.

But I've always assumed both to be inaccessible on Linux/GTK. In fact that was the response from one of the regular contributors on the Orca mailing list.

But I think there must have been some advance in versions or something because in the last couple of days I have:

  • Written a Hello World! application for Linux in `wx.Python
  • Written the same for Linux using wxWidgets (in C++)

And they are both totally accessible!

OK that's probably a rash statement because the apps I wrote did not have every kind of wxWidgets control. But buttons, message boxes, menus and static labels are all spoken by Orca.

My wxWidgets Hello World! program did have all the above.

So, now I'm on a mission to try out as many of the other native GTK controls as I can, or at least all those which are obviously not irrelevant to blind folks, like bitmaps and stuff.

The versions I am running are:

  • wxWidgets version 3.0
  • GTK 3.0

I don't know about the wx.Python version but it's what is in the Debian Jessie repo so it is probably quite up-to-date at the time of writing.

Next mission, given good results with more controls is to write a tree-based GUI designer, because being a blind programmer, drag-and-drop WYSIWYG GUI designers are not really of any use.

Emacs/Emacspeak Initialization Strategy

This afternoon I have changed the way my emacs and emacspeak initialization works.

Until now I have always used the file:

~/.emacs

For my initialization. But today, in reading about how emacs initialization and library-loading works, to try to understand how T.V. Raman does it and how his files in the git repository all hang together, I have made a discovery which has made me understand things a lot better and change my strategy.

Initialization Files

emacs will look for any of these files for it's initialization:

  • ~/.emacs
  • ~/.emacs.el
  • ~/.emacs.d/init.el

So, I changed from using ~/.emacs to ~/.emacs.d/init.el.

Not only that but I have made some other discoveries, things which I did not know about before.

In our .emacs files we have usually had two blocks of lisp that begin with:

  • (custom-set-variables ...
  • (custom-set-faces ...

These two blocks of code are places into which changes are made when the emacs customization screens are used to make adjustments, hence the commentary in these blocks which warn about editing them by hand and not having more than one occurrence of each block.

Now, of course when adding stuff to the emacs initialization files by hand it is very easy to screw something up and stop the initialization from working.

When running emacspeak this is always immediately obvious because it comes up talking very, very slowly. Assuming of course you have emacspeak configured to talk more quickly than the default.

It is possible, it seems, to place the custom-set-variables and custom-set-faces code blocks into a separate file, name it as the custom file and then load it from the main initialization file.

So, bearing in mind we are now using ~/.emacs.d/init.el as our initialization file, place these two lines at the top of it:

(setq custom-file "~/.emacs.d/custom.el")
(load custom-file)

The first of these lines instructs emacs that we want to use a different file from our main initialization file for custom changes made by the emacs customization mechanism.

The second line instructs emacs to load it.

Now we can merrily add other stuff to ~/.emacs.d/init.el, knowing that we are at no risk of messing up those customizations added with the emacs mechanism.

Loading Personal Libraries

Instead of loading everything we want in our initialization file, we can split it up, and make it much more modular. In this way we can tinker with something new, and when something breaks, we know more easily what broke it and probably how to fix it.

The first thing we need to do, again in our shiny new ~/.emacs.d/init.el file, is to add some paths to the load-path variable in emacs. It is this variable which acts a bit like the $PATH environment variable in the bash shell.

Put this fragment of code in your ~/.emacs.d/init.el file, just underneath the top two lines which specify and load the custom file:

;; add some paths to load-path
(let ((default-directory "~/.emacs.d/lisp/"))(setq load-path
(append
(let ((load-path (copy-sequence load-path))) ;; Shadow
(append
(copy-sequence (normal-top-level-add-to-load-path '(".")))
(normal-top-level-add-subdirs-to-load-path)))
load-path)))

This will add:

~/.emacs.d/lisp

And all of the sub-directories thereof to the load-path variable. Well, not ALL the sub-directories. It will ignore things like version-control related paths, sub-directory names that start with a dot etc., very useful if you want to put your initialization stuff in git or CVS.

Now we can add a whole bunch of load-library directives below this to load individual personal libraries of lisp code:

(load-library "elpa-prepare.el")
(load-library "markdown-prepare")
(load-library "rst-prepare.el")
(load-library "abbrev-prepare")
(load-library "c-code-folding-prepare.el")

These are just a few libraries I have created from splitting off the code which I previously used to have in my ~/.emacs file.

It should be obvious from the names what each library is for.

What was left in ~/.emacs?

There were a few lines of code remaining in my original ~/.emacs file which I left in the new initialization file:

(setq-default truncate-lines t)
(setq inhibit-splash-screen t)

Before I did this work today it was very hard to wade through all of the custom stuff, the markdown initialization code, the rst initialization code, and find these lines.

Conclusion

By doing this stuff this afternoon I think I have:

  • Split my original emacs initialization file into multiple library files which I load individually
  • Split my manually added initialization code from the code added and changed by the Emacs customization mechanism, which should make identifying errors easier
  • Dramatically increased the modularity of my initializations, making it more scalable
  • Made tinkering with emacs configuration less scary and hence more inclined to get done
  • Learned some valuable stuff about Emacs and Emacs Lisp

Note About load-library and .elc Files

By adding the path to our personal-libraries to the load-path variable we can leave out the .el extension of our libraries.

If byte-compiled versions of any of our libraries exist in .elc files, these will be loaded in preference to .el files, giving us an appreciable speed advantage.

To batch compile all the .el files in ~/.emacs.d/lisp:

emacs -batch -f batch-byte-compile *.el

The above will create .elc versions of each of the .el files. These will be the files which are loaded in preference to the .el files.

A Way of Using Include Directives in Markdown Posts and Pages

Using an include directive with Markdown in Nikola Pages

I love markdown. I think it's the best thing since sliced-bread. The ability to write complex documents with a simple set of formatting syntax that can then be converted into a raft of other formats, possibly with pandoc is probably the single biggest boost to your productivity you could find if you write a lot of documentation.

Nikola uses markdown, among other flavours of document formatting such as restructured text and org-mode text (an Emacs major-mode). But my choice is usually markdown. One thing I thought it was lacking until somebody asked the question on the Nikola mailing list was an include directive similar to that in the C pre-processor.

What follows is a distillation of the ensuing posts and discussion from the list.

First install the markdown-include Python package:

sudo pip install markdown-include

Now modify your conf.py to add this, there is one commented out which looks similar:

MARKDOWN_EXTENSIONS = ['fenced_code', 'codehilite', 'extra', 'markdown_include.include']

Embedding include Directives in Markdown Posts and Pages

To include a file in a Markdown post or page:

Note the path is relative to where markdown_include is being called from, not from the directory containing the post/page. So something like:

{!include/md/links.md!

Assuming you have include/md/* immediately underneath where your conf.py is, e.g. the root of your Nikola site.

To change the root of files you wish to include, in conf.py place the following:

from markdown_include.include import MarkdownInclude
my_include = MarkdownInclude(
    configs={'base_path':'/srv/content/'} # can also be relative path to conf.py
)
MARKDOWN_EXTENSIONS = ['fenced_code', 'codehilite', 'extra', my_include]

I can't claim any originality for this as it was pulled directly from the Nikola email list. I'm putting it here because it's a subject that is very close to my heart, e.g. modularity. I've already installed the txt2tags plugin and I'm using t2t includes to pull-in tables of keyboard commands for such things as Emacs major-mode key-bindings.

This site seems to be veering slightly away from it's originally intended purpose of gathering into one place all kinds of stuff relating to accessibility on the Linux platform and becoming something of a personal blog and library archive for snippets of useful stuff.

Oh well, I guess it's my party...

Debian Mate Media Controls

This is another post which deals with issues surrounding the use of pulseaudio for text-to-speech and access tech such as the Orca screen-reader.

In the previous post I described how to switch speech-dispatcher over to ALSA and avoid the use of pulseaudio. Doing this will make the console accessible with speakup even when you are logged in to a graphical desktop.

But the default media controls in a Debian machine using the Mate desktop, at least at the time of writing with Debian Jessie, are for pulseaudio.

I have experienced issues with my Dell Latitude D630 where the headphone jack goes silent. I have never established why. This can be very annoying and happens at the most inopportune moments, usually in a room full of sighted folks who would very quickly try and lynch me if they had to listen to espeak through my PC speakers for more than five minutes.

This can be fixed by uninstalling a couple of packages and installing some alternatives.

The packages we are going to remove are:

  • `mate-media-pulse
  • mate-settings-daemon-pulse

The two packages we are going to install in their place are:

  • mate-media-gstreamer
  • mate-settings-daemon-gstreamer

But, beware! The first time I did this I made the mistake of purging the first two before I installed the new packages and it broke my installation. I then had to re-install Orca, Mate and lightdm.

So we are going to let apt-get make the decisions about what to install and what to remove.

Do the following:

$ sudo apt-get install mate-media-gstreamer
$ sudo apt-get install mate-settings-daemon-gstreamer

You will hear some stuff about removing one and replacing it with the other.

After this your sound controls in Mate should be much more usable and include the headphone jack if you have one.

I can't claim originality for this. The problem and the fix described was experienced by my fellow Linux and Raspberry Pi hacker Rill.