Last week was quite prolific as I focused on setting up the foundations of the libdeng2 UI widget framework and creating a minimal text-based shell app for connecting to a server. There was a good sense of forward momentum as I had the opportunity to build new classes from scratch and improve the existing libdeng2 implementation.
Widgets and Rules
The libdeng2 widget framework is intended to be device-independent and suitable for both text-based and graphical UIs. It focuses on the logical structure of the UI and event propagation. The plan is to start out with the Shell applications (that control/monitor a server) to develop and debug the code, and later integrate it also into the client's GUI.
One of the things I was experimenting with in the Hawthorn branch was dynamic widget layout. Traditionally, hierarchical UI layout is done with a tree of layout managers. Back then I had an idea about a different mechanism called "rules" that are dependent on each other: for instance, one could say that a widget's bottom edge is always attached to another widget's top edge, and follows it around if the latter moves. Last week I imported the old code for the rules from Hawthorn and rewrote the implementation. Now my plan is to create a couple of UIs with this mechanism and see how it pans out in practice. So far it's working very well in the text-based Shell application: unlike before, the command line widget for entering console commands expands when entering a long command, and the UI as a whole reacts to window resizing. In the future, this kind of dynamic features will be available in the client's GUI as well.
Network and Log Output
As the objective was to build a minimal shell application, there was other functionality that I needed to work on in addition to the widgets. First of all, a shell needs to open a network connection to a server for issuing commands and receiving status information and log messages. As the existing network code is mostly deprecated, I needed to get one more component from Hawthorn: an object-oriented network protocol. Eventually, all network communications will be based on this -- for now, only the shell connection uses it.
I also started building libshell, the shared library for shell-related functionality. It currently contains a set of character-based UI widgets, the shell network protocol, and a class for handling the connection to a server. With all this generic functionality ready for use, I anticipate it will be quite fast to set up a GUI shell in addition to the text-based shell app.
However, one important element was still missing: a way for the server's log message buffer to pass messages over the network to a connected shell app. The libdeng2 log implementation already had a hard-coded mechanism for sending out log entries to different destinations, e.g., the doomsday.out file, stdout/stderr, or a debug output stream. I applied a refactoring that removed the hard-coded implementation with a set of "log sinks" that can be attached and detached from the log buffer at runtime. This allows one to easily receive log output anywhere simply by adding a new sink to the log buffer. This is exactly how a shell connection receives log output: it acts as a sink for messages, which instead of being written to a file or stream get flushed over the network connection.
This completes the basic functionality needed by the text-based shell: opening a connection to a server, sending commands and have them executed on the server, receiving log entries from the server and showing them on screen. The work with the Shell is far from complete, though. Next, I'll keep refining shell-text for a fuller feature set (e.g., word completion, menu, scrolling in the log history), and also clean up the code for merging into the master.