Bringing serialization into the 21st century... bit by bit.
Project powered by:
|
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:
|