s11n.net
Save the planet. Save the trees. Save your data, man.
Project powered by:
SourceForge.net

ncutil

A utility library for curses based on ncurses++

In mid-February 2005 i finally started writing a curses-based application, called the Teeny Weeny Boardgame Engine. Curses, as you probably know, is a C-based toolkit for working with text-base interfaces. It's been around since before Columbus claimed America in the name of Spain, and exists in a variety of flavours on different platforms. The code described below works specifically with "ncurses" (New Curses, though the "new" is definately no longer justified ;), mainly because it's got more features than conventional curses, but also because that's what comes on my Linux boxes. It is derived from code written by Thomas Dickey, a long-time ncurses maintainer.

Whe core curses API is quite flexible and fairly straightforward to use, but the C++ wrappers which have cropped up around it, namely NCursesWindow and friends (which come with curses as "ncurses++"), have a few unfortunate/unecessary design limitations. So i took a two-week side-trip to learn curses and write some code to simplify the usage of and extend the standard NCursesWindow family of classes.

NCursesWindow and friends have been around a long time and are in far too much code to make significant changes to them feasible... So i decided to steal a copy of the ncurses++ 5.4 tree, and forked copies of those classes into this tree so i could fix the problems instead of yelling at them.

Why? So i can use it in my client code, of course :). And if you can get any use out of it as well, that's great, too.

The list of significant features includes:
  • The "NCMode" sentry class provides a "scope" which automatically switches the screen in and out of curses mode as needed. It uses with C scoping rules to restrict curses mode to any given scope (or deeper: deeper scopes inherit the screen mode of upper scopes).
  • Access to color pairs by name. e.g., COLOR_PAIR(XX) becomes ncutil::color_pair("white","blue"). To simplify this, the toolkit installs a full 64-color palette at startup, so the color pairs are consistent across all apps which link to it.
  • The new NCKeyConsumer interface consolidates key handling management between the (unforunately) disparate NCPad and NCPanel interfaces, to simplify event management involving multiple windows and/or pads.
  • Extended support for the NCFramedPad (scroll-window). It now has page up/down and scroll to top/bottom support. Its event loop can now be optionally delegated to client code, e.g. to feed requests to the pad conditionally or one at a time. Remapping the pad's movement keys can now be done from client code without subclassing.
  • Direct arbitrary std::ostreams, including std::cerr/cout, to an NCWindow using NCStreamPad, complete with NCFramedPad's scroll support. These streambuffers may also carry curses attribute info with them, which allows us to redirect multiple streams to one window while using different attributes for each (e.g., green for std::cout and blinking red for std::cerr).
  • NCFileViewer can load text files or read istreams, and provides scrolling access to browse the data.
  • A "scoped signal" type which greatly simplifies the use of C signal handlers, and makes it trivial to embed them to arbitrary depths without having to remember which handler needs to be replaced. This class ended the woes i found when mixing GNU Readline and ncurses in the same app.
  • Experimental support for rendering arbitrary objects to arbitrary NCWindows via the use of NCRenderer<> class template. This allows us to render, e.g., strings, integers, and MyOwnType to a window using the exact same interface, which provides greater flexibility for template-based algorithms which want to draw to windows. This will eventually allow us to have a single ListView class which can view any type of object, provided we have a renderer specialization for the type being listed. This is conceptually very similar to the s11n API, without the deserialization side.
  • The experimental NCActionItem<ItemT,FunctorT> support works in conjunction with NCRenderer<> to not only view lists of arbitrary ItemT types, but also to "activate" them by calling a FunctorT on the item. This "should" work with all ItemT types, from int to (NCWindow *), provided an appropriate NCRenderer specialization is in place. This will provide the basis for the planned NCMenu/NCListView/etc. classes.
  • An experimental "workspace" class is intended to act as a primitive window manager of sorts. We can have arbitrarily many workspaces in memory at once and view any given one of them at a time, including doing primitive focus handling for child panels.
  • By storing curses attribute information in containers we can serialize with ease them using s11n. Capturing all on-screen curses attributes would require adding in support to NCWindow, or the like, because curses doesn't seem to offer a way to fetch them once they are set.

All that said, it is experimental. The file ncdemo.cpp demonstrates how to use it, but be aware it's usage may change considerably over time, as experimentation reveals what needs to be done. Some of the more signifant TODOs include:
  • NCListView is awaiting the completion of ListViewItem, which needs more testing. i also need to write a widget type to manage the movement/selection (via NCVPad's interface, with slightly different keys).
  • NCWorkspace: define a convention for how it should a) collect keystrokes, b) handle/notify of window focus.
  • An NCWorkspaces (plural) class to manage multiple NCWorkspace objects. e.g., switch to next/previous/specific workspace.
  • NCWindowOps, the intent of which is to allow the NCWorkspace type to have an interface with which to manipulate it's child panels via common window-level operations like close(), doLocalInputLoop(), etc. This type need not be a widget, but care must be taken that it is cleaned up when it's related panel is cleaned up.
  • Signals and slots, thanks to some code from Dr. Marc Duerner. This will completely replace the current event model, i hope.

Licenses:

The sources contain a mixture of GNU LGPL, Public Domain, and a "leave this copyright here but otherwise do what you want" styles of licenses.

Download:

from the downloads page. Note that it ships only as sources and a makefile, not a complete build system. It is standalone code and the tree may be dropped into an existing project with very little effort.

Screenshots: