Skip to content
theavegePublic

About

Rust bindings for the 'Curses Development Kit'

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

Repository files navigation

cdk-rs

platform

Rust bindings for the Curses Development Kit

What is CDK 1?

CDK is a library of functions which allow a programmer to quickly create a full screen interactive program with ease. The CDK widgets support the following features:

Ncurses library. : Instead of using the standard curses library, CDK can take advantage of the colors that Ncurses provides.

Key Bindings. : Individual keys can be overridden with a callback.

Pre and Post Processing. : Certain widgets allow the user to trap a character before and after the character has been applied to the widget. This allows programmers to "filter" character input.

Self Test Widgets. : With the use of the inject function class and the activate function, programmers can have the widgets test themselves.

Special Display Formats. : There are special character format commands that can be inserted into any string in CDK and the contents will get mapped to a chtype (see the curses manual page) with character attributes. This allows the programmer to insert format types on each character if they wish.

The Ability To Build Predefined Screens. : Widgets can be associated to any given screen. If there is more than one screen defined, then CDK has the ability to "flip" from one screen to another with ease.

Why CDK?

To develop console-based interfaces, there is a library found on all Linux systems called ncurses. ncurses is to console interfaces what Xlib is to graphical interfaces. It contains everything needed to create console-based interfaces while remaining fairly low-level. Although the standard HOWTO collection includes an Ncurses HOWTO, ncurses is nevertheless not a library that can be approached very intuitively, and a great deal of time must be spent before one can program a satisfactory interface.

There is a higher-level and easier-to-use library that brings together numerous pre-built widgets. It is called CDK, an acronym for Curses Development Kit 1. CDK is a library written in C. Nevertheless, it was designed in a strongly object-oriented style, with each widget having methods in the form of associated functions. A rigorous definition of the structures and the casting of pointers also provides a semblance of inheritance.

Dependencies

  • Linux
  • CDK5 development files, ncurses, and libclang

Terminal and widget constructors return Result values. Applications should handle initialization failures and strings containing NUL bytes instead of relying on panics.

Tutorial

This is the Rust version of the classic CDK workflow: create a curses window, attach a CDK screen, add widgets, activate them, and let the owners clean up the terminal when they leave scope.

1. Install dependencies

On Debian or Ubuntu:

sudo apt install cargo clang libcdk5-dev pkg-config

curdk-sys uses the CDK5 development installation. If cdk5-config is not on PATH, set CDK5_CONFIG to its full path before building.

2. Create a screen

Window initializes the curses terminal. Screen connects that terminal to CDK and owns the lifetime required by its widgets:

let window = curdk::Window::new()?;
let screen = curdk::Screen::new(&window)?;
# Ok::<(), curdk::Error>(())

Keep the Window and Screen alive while using widgets. Dropping a widget destroys its native CDK object; dropping the screen restores the terminal.

3. Add and activate widgets

The constructors accept Rust strings and return an error if CDK rejects the native allocation or a string contains an interior NUL byte:

let window = curdk::Window::new()?;
let screen = curdk::Screen::new(&window)?;
let label = curdk::Label::new(
    &screen,
    curdk::CENTER,
    curdk::TOP,
    "Name",
    curdk::Border::NONE,
)?;
let entry = curdk::Entry::new(
    &screen,
    curdk::CENTER,
    curdk::CENTER,
    "Input",
    "Name: ",
    curdk::Border::NONE,
)?;

screen.refresh();
let value = entry.activate()?;
label.set_message(&format!("Hello, {value}!"))?;
screen.refresh();
# Ok::<(), curdk::Error>(())

Interactive widgets block in activate until the user finishes. Buttons, button boxes, dialogs, menus, lists, and selections also provide activate_result(), which returns Activation::Selected(index) or Activation::Cancelled instead of exposing CDK's raw return code.

4. Finish the session

Call screen.exit() when the application should leave CDK's main loop. The normal Rust drop order then releases widgets, the screen, and the terminal.

Widget constructors that wrap CDK's Box / Shadow arguments take a Border. Use Border::NONE for an unframed widget, Border::BOXED for a border, or Border::SHADOWED for a border and drop shadow.

Key bindings and pre/post-process hooks are available on every widget:

entry.bind_key(b'q' as u32, |_| 1)?;
entry.set_preprocess(|key| if key == b'!' as u32 { 0 } else { 1 });

Return 1 from a key binding to consume the key, 0 to let CDK handle it. A preprocess callback returns 1 to apply the character and 0 to ignore it.

To share one event loop across a screen of widgets, call screen.traverse(). Tab moves focus; a binding that calls screen.exit() (or screen.cancel()) ends the loop. Screen is cheap to clone so the callback can own a handle:

let done = screen.clone();
entry.bind_key(b'x' as u32 & 0x1f, move |_| {
    done.exit();
    1
})?;
let accepted = screen.traverse();

The repository contains complete examples:

cargo run -p curdk --example counter
cargo run -p curdk --example temperature_converter
cargo run -p curdk --example crud
cargo run -p curdk --example flight_booker
cargo run -p curdk --example alphalist
cargo run -p curdk --example template
cargo run -p curdk --example matrix
cargo run -p curdk --example swindow
cargo run -p curdk --example form

Tutorial, part 2: compose a screen

The second part of the original CDK tutorial demonstrates the important step after creating one widget: compose a screen from several focused widgets and let each activation produce an application message. In Rust, keep the application state separate from CDK handles, and make the event loop the only place that changes that state.

enum Message {
    Search,
    Select(usize),
    Quit,
}

fn update(model: &mut Model, message: Message) {
    match message {
        Message::Search => model.refresh_results(),
        Message::Select(index) => model.selected = index,
        Message::Quit => model.running = false,
    }
}

Create widgets once, then update their contents during each view pass. This avoids recreating native objects and keeps ownership predictable:

let results = curdk::Scroll::new(
    &screen,
    curdk::CENTER,
    curdk::CENTER,
    curdk::RIGHT,
    8,
    48,
    "Results",
    &["First result", "Second result"],
    false,
    curdk::Border::NONE,
)?;
let actions = curdk::Buttonbox::new(
    &screen,
    curdk::CENTER,
    curdk::BOTTOM,
    5,
    32,
    1,
    2,
    &["Search", "Quit"],
    curdk::Border::NONE,
)?;

A typical CDK event loop follows this order:

  1. Render model state into labels, entries, and lists.
  2. Refresh the screen once.
  3. Activate the widget that owns the next interaction.
  4. Convert its result into a message.
  5. Apply update and repeat until the model requests Quit.

Use Widget when a function only needs common operations such as drawing or changing the box. Use widget-specific methods for values, selections, and activation. Scroll, Radio, and Selection accept Rust slices, convert their strings for the duration of the native call, and expose current-item accessors. Selection additionally exposes per-item boolean choices.

For a complete application-shaped version of this pattern, see the counter, booker, crud, calculator, and temperature_converter examples. form shows Screen::traverse over several widgets. This section is adapted from the archived second CDK tutorial.

Other bindings for CDK

Alternatives

Widgets

Footnotes

  1. Curses Development Kit. ↩ ↩2

About

Rust bindings for the 'Curses Development Kit'

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages