Tuesday, July 12, 2016

Pip-Boy like terminal application in Guile, part 4: the terminal

This is the fourth in a series of articles where I try to recreate some Pip Boy like displays in GNU Guile and ncurses.

A Pip Boy is a fictional computer in the Fallout 4 computer games.  GNU Guile is an implementation of the Scheme language.  Ncurses is a library for creating text user interfaces on terminals like the Linux terminal, Xterm, or the Gnome Terminal.

One of the iconic experiences in Fallout 4 is using the in-game computers, which are bulky, green screen monochrome terminals not unlike a DEC VT100.  Actually a closer match is the Televideo TVI-912.  Generally they are used in two ways: displaying a text block with some selectable links, or playing a hacking minigame.  Today we'll look at the first.

The basic user experience is this:
  • When activated, the terminal will begin an animation where it is add adding text to the screen one glyph at a time at about ~75 characters per second.  There is a tick sound associated with each glyph appearing on the screen.
  • Clicking the mouse or pressing enter will interrupt this drawing animation and will make all the text appear on the screen.  There is a tick sound associated with this.
  • Once drawing is complete, any text surrounded by square brackets become a link.
  • The first link is highlighted.
  • Mousing over a link or using the arrow keys will move between links.  There is a tick sound associated with moving between links.
  • Clicking on a link or pressing enter will select the highlighted link and end the interaction.  There is a sound associated with selection.
So, here there is user interaction, audio cues, time-based rendering.  It actually is a fair bit of functionality, and it also is not too friendly to the paradigm provided by the ncurses toolkit.


So I put together three different code units
As a side note, Guile has had a complete set of bindings to the multimedia enving GStreamer, which I wanted to use, but, it appears to be in need of some maintenance.  I did look at it so see if I could patch it up, but, the binding is related to the Glib binding, and I didn't want to take the time to understand all that right now.  Pulseaudio is much lower level, but, also much simpler.  I had code lying around from some old game engine attempt.

If you've coded in QT or GTK, you know that a central function of a GUI toolkit main loop is to allow each widget to send out notifications and to have other widgets be able to subscribe and react to these notifications.  In QT, these are "signals" and "slots".  In GTK they are "signals" and "signal handlers".
To keep things somewhat simple, the primitive main loop works like this...
  • There are one or more event handlers. An event handler may have an associated widget.
  • The main loop checks for an event in the queue: either a keypress, a mouse event, or a signal sent out by one of the widgets. If it finds an event, it sends it to all the event handlers.  Every handler receives every event: there is no attempt to be precise.
  • If no event is ready, the main loop sends an "idle" event to all the signal handlers, does a single step in Pulseaudio's main loop, and then sleeps for a few microseconds.

This is familiar territory.  There's nothing new under the sun.

I had to choose between letting Pulseaudio run its own event loop in its own thread, or to merge Pulseaudio's event look in to my main event loop.  I chose the latter.

Put together, it all looks like this.  For the life of me, I cannot seem to record audio on my screengrab.  I blame Wayland.



The code, in its current form, is here.  It is not ready for use.