NcDialog API User’s Guide

NcDialog Library API

Copyright © 2005 - 2023 Mahlon R. Smith, The Software Samurai This document describes version 0.0.36 of the NcDialog-class API library. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled  "GNU Free Documentation License".




Table of Contents


Introduction

┌─────┤ NcDialog API ├─────┐ Hello World! Enter Here └────────────────────────────┘

What NcDialog Is

  • NcDialog is a C++ class definition.
    The class is as straightforward and easy-to-use as any standard class definition, and is considerably less complex than most. Think of the standard iostream class with better formatting control, seamless internationalization and multi-color output — but without the learning curve.
  • NcDialog is an API (Application Programming Interface)
    NcDialog allows fast and flexible development for applications which run in a terminal window. The API encapsulates the most important of the Linux ’ncurses’ (actually ’ncursesw’) C-language library primitive functions.
  • NcDialog is a link library which can be linked to any Linux console application which has access to the libncursesw.so.n dynamic-load (shared) library.
  • NcDialog is simple, small, fast and thoroughly documented.
    When was the last time you built a complete and intuitive user interface from the ground, up in 30 minutes?
    Today is the day. :-)

What NcDialog Does

  • Provides a comprensive set of tools for interacting with users.
  • Provides seamless internationalization through full support for all UTF-8-encoded languages, both LTR (left-to-right) and RTL (right-to-left) languages.
  • The C++ class structure of the API transforms application maintenance from a horrifying C-language nightmare into a simple, non-threatening task.
  • Provides a modern, intuitive interface to the underlying ’ncurses’ functionality without the need to memorize cryptic function names and arcane command sequences left over from the days when dinosaurs roamed the earth.
  • Provides a tranparent interface to Linux shell commands and system command-line utilities.
  • Because an NcDialog-based application runs in a terminal window, the NcDialog API provides an ideal interface for remote-system maintenance.





Operational Overview







Description of a Dialog

The Concept of a Dialog

  • A ’dialog’ is a self-contained user interface module, used primarily to gather information from the user on a single topic and to pass that information to the main application, or to provide information to the user about a pending or recently-completed operation.
  • A dialog opens as a floating window on top of whatever may be happening in the visual background which is usually an application’s main window.
  • A dialog typically contains one or more user-interface objects commonly referred to as ’controls’. A ’control’ is a user-interface device designed specifically for the type of information to be gathered or displayed. An example would be a ’Radio Button’ through which the user may make a binary decision: ’yes’ or ’no’, ’on’ or ’off’, ’upper case’ or ’lower case’, or similar decisions. Many control types such as text input controls are universally recognizable, and some controls are created for very specific circumstances.
  • Within a dialog, it is often useful to open a sub-dialog, that is a dialog object created by the currently-active dialog. The practical limit to layering of sub-dialogs, sub-sub-dialogs, etc. is the point at which the user is more confused than enlightened by the information presented.
  • A dialog closes (disappears) when user interactions have been completed. Flow-of-control then returns to the parent application.

An NcDialog API Dialog

  • A dialog created by the NcDialog API (application programmer’s interface) is typical of dialogs in other environments. The primary difference is that the dialog itself is the main application. Quite often, the main application does not need to be a complex, monolithic structure (Libre Office for example), but can be a simple shell for interacting with the user to accomplish a single task or a group of tasks.
  • The visual background to an NcDialog-based application is the ’terminal window’ or ’console window’, which offers the user detailed access to the system through command-line utilities. Under Linux this is generally the GNOME or the Konsole terminal emulator program by default, although your system may be configured for another terminal program.

    Under Linux/UNIX systems, the command line is the seat of power. It provides access to system tools and configuration data that cannot be accessed in any other way. The difficulty with the command line system interface is that it is massively complex and its functionality appears frighteningly obscure from the typical user’s point of view.

    In its essense, the NcDialog API is a means of presenting all that complexity in small, easily-understood increments, so that the user can safely accomplish complex tasks without having to first spend hours reading cryptic online documentation or searching the web for undocumented solutions to everyday problems.

  • The NcDialog API offers all the usual types of interface ’controls’ which the application programmer can use to construct an intuitive, interactive experience for the user.

    Please see NcDialog Class Definition for a detailed description of each of the available NcDialog control types.

  • Sub-dialogs may be created within the main application dialog to any reasonable level. A sub-dialog will temporarily obscure its parent (both visually and functionally), and when it closes, the parent will regain control.
  • When an NcDialog application is closed, flow-of-control returns the user to the command line within the terminal window.



Application Layer Methods

  1. Startup Code: All NcDialog-based applications have a standard sequence of startup-up activities. This sequence is demonstrated in the ’main’ method of each of the test applications (see Test Applications).
    For more information on the startup sequence, please see NCurses Engine, or see Your First Application, for a step-by-step explanation of the startup sequence.
  2. Define the NcDialog object: An instance of an NcDialog window object has the following characteristics:
    Parameter Description ......... .................................................... Size The number of rows and columns for the window Position The offset of the dialog from terminal window origin Color Color attributes for window border and interior Style Border style Title Optional window title to be displayed in border

    Please refer to the discussion of the InitNcDialog class,
    see Your First Application, for more information.

  3. Define and configure the controls the NcDialog window will contain.
    For each control contained in an NcDialog window, there is a control definition which specifies size, position, color, contents and other parameters.

    In addition, many optional configuration methods are provided which can be called after instantiation to further refine each control object for your particular needs. Please see Dialog Control Objects for details on the definition and optional configuration parameters for each control type.

  4. Instantiate and open the dialog window. Once the NcDialog window object and its controls have been defined, open the dialog using the following steps.
    1. Instantiate the dialog and its controls.
    2. Call any optional configuration methods which must be completed before the window is opened for the first time.
    3. Open the dialog window.
    4. Call any additional configuration methods for the controls.
    5. Write any desired static text to the window.
    6. Make the window visible to the user.
    7. Enter the user-interface loop.

    For an example sequence, please refer to the discussion in see Your First Application.
    Please refer to see Dialog Control Objects for details on optional configuration parameters for each control type.

  5. User Interface loop: The basic application layer consists of a simple user-interface loop. This loop organizes user input and decides what to do with that input. It tracks which control object currently has the input focus and calls the appropriate ’Edit’ method for that control type.

    There is exactly one (1) publically-accessible Edit method for each control type:

    Edit Method Control Class Control Type ........... ............. .............. EditPushbutton DialogPushbutton dctPUSHBUTTON EditTextbox DialogTextbox dctTEXTBOX EditBillboard DialogBillboard dctBILLBOARD EditRadiobutton DialogRadiobutton dctRADIOBUTTON EditScrollbox DialogScrollbox dctSCROLLBOX EditDropdown DialogDropdown dctDROPDOWN EditMenuwin DialogMenuwin dctMENUWIN EditScrollext DialogScrollext dctSCROLLEXT EditSpinner DialogSpinner dctSPINNER EditSlider DialogSlider dctSLIDER
  6. Keyboard and Mouse Input: All, or nearly all user input is handled within the Edit methods listed above. However, there are certain instances where it is useful to obtain information directly from the user. The most common of these would be the nckPause() macro which simply waits for the user to press a key.

    All keyboard and mouse input is channeled through the method
                    GetKeyInput( wkeyCode& wk )
    Please note that for reasons of thread safety, this method is designed in layers. The NcDialog::GetKeyInput() method should be used in nearly all cases because it incorporates not only thread safety, but also translates mouse input into keycodes and dialog coordinates associated with the mouse pointer wherever possible.
    Please see Mouse Configuration for a detailed description of the mouse interface.
    Please see Thread Safety for a more detailed discussion of thread safety.

    The 'NcWindow::GetKeyInput()' method is a thread-safe pass-through to the underlying 'NCurses::GetKeyInput()' method, which IS NOT thread safe, and neither of these layers should be called directly from within an NcDialog application.

  7. Output to the Display: There are three (3) primary methods for writing data to the NcDialog window:
    Output Method Description ............. ..................................... NcDialog::WriteChar() Writes a single character NcDialog::WriteString() Writes a text string to current line NcDialog::WriteParagraph() Writes a paragraph (with line breaks)

    These methods are actually member methods of the parent class, the NcWindow class, and are fully thread-safe, that is: they will not interfere with each other if multiple threads are simultaneously writing to the dialog.

    For a detailed description of how these methods are used, please refer to the section, see NcDialog Display Output.
    For a more detailed discussion of thread safety, please refer to the section, see Thread Safety.

    Note that the NCurses class also has 'WriteChar()' and 'WriteString()' methods for writing directly to the terminal window; however, these methods ARE NOT thread safe, and should not be used when an NcDialog window is open (except possibly for writing debugging messages to the terminal during application development).

  8. Shutdown Code: An orderly shutdown of the NcDialog API is necessary in order to prevent memory leaks, pointers to unallocated data space and other application bête noire. Fortunately, the shutdown sequence is very simple:
    1. delete the NcDialog-class object,
    2. then stop the NCurses Engine.

    Please refer to the section, see NCurses Engine,
    or the section,see Your First Application, for more information.




Library Internals

This document is intended as a reference for the application designer. As such, the private, support methods which implement the low-level NcDialog API functionality are not discussed in detail here.

However, your author has spent most of his career documenting code, his own code and everyone else’s code; therefore, the NcDialog API library source code is as close to being self-documenting as we can make it. In addition, copious programming notes are included in every source module and in the header of every non-trivial method, so the next poor bastard who updates the code will have an easier time of it.

If, however, you are having trouble with any section of the source code, just remember that your author has a massive ego (as all software designers do), and is happy to discuss his work with anyone who has a serious question.
See Technical Support.




Inheritance Layers

A Short History Lesson

The C language is powerful, concise, infinitely adaptable, and in the right hands, imbued with the seeds of artistry.

However, C is a terrible language for generational software such as the Linux kernel and the ncurses function library because one designer’s artistry is the next generation’s frustration and misery.

In a past life, this author partnered with a true software genius to start a little company in the Silicon Valley. His code was pristine—it did exactly what he intended it to do, smooth and fast—a true work of art. The problem was his total recall: he never wrote a word of comment because he remembered in great detail every line of code he ever wrote. So when he went off the rails, as genius always does, it became our job as his number two to come along behind, documenting what he had done and porting the code for next-generation projects. Frustration and misery, indeed!

Layering to the Rescue

Just as parents work all their lives to create a stable environment from which their children can launch themselves into the future; exactly so, the strength of C++ is the ability to inherit robust, reliable, self-documenting code from parent classes, building layer-by-layer upon the successes of the past.

The NCurses / NcWindow / NcDialog class progression starts simple and becomes progressively more sophisticated. We make no wild claim, however, that all bugs have been banished. Indeed, sophistication breeds fragility, and each layer requires an order of magnitude greater planning, care and field testing.

  1. The NCurses Layer
    The function of the NCurses class is to define and configure input and output streams, and to interact directly with the underlying ncursesw C-language library.

    The application’s only direct access points to the NCurses class are:

    1. the start-up sequence
    2. the defined constants for keycodes and color attributes
    3. the shut-down sequence

    The application needs NO direct contact with the underlying C library, and in fact, doing so would very likely trash the application’s working environment. DON’T DO IT!

    Please study the ’Dialogw’ test application, tests 1 and 2 for a demonstration of the NCurses class methods.
    See Dialogw App.

    For a detailed explanation of all public methods and data of the NCurses class, please see NCurses Engine.

  2. The NcWindow Layer
    The true value of the ncurses(w) C library is its definition of a text-mode "window." This ’window’ is a block of memory which contains the text and color attribute data, along with positioning and configuration information representing a section of the terminal’s display area. It’s primitive C-style naming conventions, and ad-hoc design are rather difficult to work with, but it is also quite a powerful construct.

    However, in order to harness this power for non-trivial projects, it is necessary to encapsulate the ncurses(w) window primitives, simplifying its application interface and compensating for its weaknesses.

    The NcWindow class leverages the low-level power of the NCurses class for input and output while creating a cushion between the application programmer and the difficult process of creating and maintaining window objects. In short, the NcWindow class converts the ncurses(w) ’window’ construct from a sequence of C function calls into a true window ’object’.

    Simultaneously, the NcWindow class creates a thread-safe application environment upon which its derived classes can rely.

    Like the NCurses class, the NcWindow class makes no attempt to encapsulate the entire ncurses(w) windowing interface. Instead, it uses the absolute minimum number of ncurses(w) primitive functions necessary to get the job done. This is not a matter of laziness (or of arrogance), but is an exercise in defensive programming: we want our API to be robust and reliable, and much of the ncurses(w) C library is neither.

    Please study the ’Dialog1’ test application, tests 3 and 4, and the ’Dialogw’ test application, test 3 for a demonstration of the NcWindow class methods:
    See Dialog1 App.
    See Dialogw App.

    For a detailed explanation of all public methods of the NcWindow class, please see NcWindow Meta-layer.

  3. The NcDialog Layer

    While it is possible to write a decently-robust application using the NcWindow class directly, the NcWindow class lacks any kind of sophisticated user interface or visual polish.

    The NcDialog class is a ’derived class’ whose parent is the NcWindow class. Essentially everything inside the NcDialog class is a window object or a group of window objects. The NcDialog layer makes no direct calls to the ncurses(w) C library, and is thus free from the problems that arise when changes are made to underlying third-party libraries. See Description of a Dialog, for more information on dialog objects.

    The NcDialog class is the application programmer’s working environment.

    • The application knows nothing at all about the ncurses(w) C library.
    • The application knows nothing about the NcWindow class.
    • Apart from the start-up and shut-down sequences, and the constant definitions (keycodes and color attributes), the application knows nothing about the NCurses class.

    Of course a good programmer can find ways to violate this layering of functionality, but a great programmer will not do it.

  4. The Dialog Control-Object Layer
    Within a dialog object, interaction with the user is the primary focus. To interface smoothly with the user, several dialog control objects are defined. Each control object has a specific interface function so the application programmer does not have to create all new interface functionality.

    Each control object is itself a dialog object which is in turn, created from one or more NcWindow objects. For instance, the DialogMenuwin class is actually a linked set of three(3) NcWindow objects: a title, a border and a scrolling display area which constitute a collapsible menu object. See Application Layer Methods, for an overview of the user interface controls.

    For a detailed explanation of all public methods, data and control objects of the NcDialog class, please see NcDialog Class Definition.




Thread Safety

Introduction

In any non-trivial application, thread safety can become an important issue. In the world of multi-core CPUs, built-in language support for multi-threading, and an application programmer’s burning need for speed, multi-threading is a natural choice.

Multiple threads may be launched from any active process, up to the limits of system resources. This means that threads using shared code and resources must play nicely with each other to avoid all kinds of potentially nasty consequences.

The underlying ’ncursesw’ library upon which the NcDialog class relies, was designed to run under single-threaded processes. This is understandable, since at the time, the concept of multi-threading was still in its infancy. The ’ncursesw’ library is therefore unsuited and inherently unsafe for multi-threaded environments—but fear not!

Implementation

The NcDialog class library manages the input and output resources so that application threads need not worry about I/O resource conflicts.

The actual thread-safety mechanism is implemented in the NcWindow class
(see NcWindow Meta-layer,) and this mechanism carries through to all of the NcWindow-class descendants, including the NcDialog class as well as the individual user interface control objects with which an NcDialog window may be populated. (See NcDialog Class Definition.)

The implementation is conceptually simple. There are two data streams, the keyboard/mouse data input stream and the display data output stream. Any executing thread within the application may request exclusive access to to one or both of these streams simply by calling the needed input or output method(s). There is no need for application-level thread management of I/O resources; simply launch the threads to do their assigned tasks, and terminate them when they are no longer needed.

Thread-safe Operation

  1. As mentioned, the ’ncurses’ and ’ncursesw’ libraries included as part of Linux/UNIX systems ARE NOT thread safe.
  2. The NCurses class methods (see NCurses Engine,) provide direct access to the ’ncursesw’ input and output streams, and are therefore also not thread safe.
  3. The NcWindow class (and its derived classes) implement thread safety through two exclusive-access-lock <recursive_mutex> objects:
    1. ’InputStream_Lock’ for keyboard/mouse input, and
    2. ’OutputStream_Lock’ for data output to the display.

    These mutexes are not data members of the NcWindow class. They are a single, static, shared resource for all NcWindow-derived objects.

    All input/output member methods, as well as I/O configuration methods must obtain exclusive access to the target stream before each operation. In practice this means that after requesting a currently-unavailable resource, the requesting thread will sleep until the resource becomes available, thus ensuring that resource conflicts will not occur.

  4. Keyboard/Mouse Input: The ’ncursesw’ library primitives which comprise the low-level keyboard/mouse interface are implemented as a single resource shared among all window objects. It operates as a FIFO queue, and for this reason, input is naturally robust, though still potentially vulnerable to resource conflicts, especially during application start-up and configuration.
    1. It is recommended that all application start-up tasks be completed by the primary thread before secondary threads are launched.
    2. Similarly, when temporarily putting the NCurses Engine to sleep (’Hibernate’ method) or re-awakening it (’Wake’ method), it is strongly recommended that all other program threads should be either ’join’ed (terminated), OR blocked. It would be quite embarrassing for a thread to run amok, calling NCurses/NcDialog methods which are not currently available.
  5. Cursor positioning: Because the terminal window in which the application operates (GNOME, Konsole, etc.) is a single display area, the cursor (output insertion point) is is also a single resource, shared among all objects within that terminal window, so at no time, should a thread rely upon the cursor being where it was previously positioned. Another thread may have moved it. This is why all methods which write to the screen are designed to EXPLICITlY set the cursor position at the start of the output sequence.
    1. Note that if one thread makes the cursor visible, then the user may be surprised to see the cursor jumping around as other threads write data to the display. There is no elegant way to prevent this without inter-thread communications regarding what each thread is doing with the cursor, so, it is recommended that the cursor remain invisible as much as possible in order to reduce user confusion.
    2. Under extreme duress, multi-threaded output will occasionally show screen artifacts - this is unavoidable due to inherent weaknesses in the underlying ’ncursesw’ library, as well as hardware/kernel task switching issues. However, in a ’typical’ application, where events move at a user-oriented pace, such artifacts will be rare. For an over-the-top stress test of multi-threaded output, please refer to test seven (7) of the Dialog4, test application. See Dialog4.
  6. Please note that multi-threading IS NOT USED within the NcWindow class nor any of its descendants, and thus, the ’lpthread’ library need not be linked to the target application unless the application itself uses multi-threading.
  7. For convenience, the thread safety functionality is controlled during the library build by the NCD_THREAD_SAFETY flag in NcWindow.hpp, so the mutexes can be temporarily disabled during testing; however, this flag should be enabled for all production builds, even if the target system does not support multi-threading.



Newbie Corner

Introduction

Software Sam may be a caffine-swilling, hard-core, old-school assembly-language programmer, but he is also a classroom teacher, so he understands that for a programmer who is just starting out on his or her career, even a very small misunderstanding over terminology or some minor technical issue which needs to be researched can stall a project for hours—or even weeks. For this reason, we offer some simple, introductory information for a few of the problems which beginning programmers and those new to GNU/Linux are likely to encounter.





Vocabulary

Here are a few useful definitions for terms that students often find confusing.

  • Newbie
    a) an inexperienced person b) a learner who often needs someone’s help c) a person who is ridiculed by more experienced peers d) designer 2.0, the next generation of software designers; an improvement over version 1.0 designers, (i.e. those who now ridicule you)
  • GNU
    GNU is Not UNIX. A silly, but useful reminder that although GNU/Linux shares much functionality with the various flavors of the UNIX operating system, the GNU project is entirely free of smelly UNIX code, and provides a free-as-in-Freedom operating system for those of us who want full control over our computing lives. Visit the Free Software Foundation website for further information.
  • Linux
    The core code of the GNU/Linux operating system. Linux is not an operating system, but provides the operating system with access to the hardware and low-level driver software. The Linux core is generally completely invisible to a GUI user, but command-line users have a significant level of access. See also ’kernel’.
  • GUI
    Graphical User Interface. These are the pretty images used to present the functionality of the operating system to the user. Self-respecting code warriors avoid GUI-based tools as much as possible in order to retain maximum control and also to ensure victory in all technology-based pissing contests.
  • kernel
    The kernel is the basic program (or group of programs) that are launched by the bootloader, and run in the background, managing memory, granting input/output and other requests for system resources submitted by the operating system through the kernel’s API (Application Programming Interface). See also ’Linux’.
  • bootloader
    The second level of software which is launched during system startup. The first level is the BIOS (firmware) which reads the Master Boot Record on your primary storage device (hard drive) which indicates where on the disc your bootloader lives. Once the bootloader has been launched, it then loads the kernel package into memory. The most common bootloaders used with Linux are ’grub’, and the older but sometimes useful ’lilo’.
  • instance, instantiation
    In C++ and other object-oriented languages, object templates called ’classes’ are used to create actual code and data constructs. The template (class) itself requires no system resources and has no function. Creating an actual object based on the template is called ’instantiation’. This object occupies memory space for the data members and code space for any member methods, and is known as an ’instance’. Please see What Is a Class? for a more complete discussion of objects and object-oriented programming.
  • thread
    A ’thread of execution’ is the path the CPU takes through a sequence of instructions within your code. A thread is like a ’process’ except that it requires fewer dedicated resources. Many threads may be launched within a single process, and all threads within that process share memory space and other resources. Most modern processors have hardware support for ’multithreading’ which means that multiple tasks can be performed (almost) simultaneously within your application. For an example of using multiple threads within you application, please see Multi-threading.
  • sudo
    Switch User and DO something. This command allows the user to execute an application at a higher user privelege (as Superuser). Ordinary user privilege is limited to avoid unfortunate or catastrophic accidents during normal operation. However ’sudo’ allows you to create nearly unlimited chaos and destruction, one command at a time. Use it wisely!
  • Superuser (root)
    The Superuser, or ’root’ user has unlimited access to the system’s functionality. The Superuser, sometimes known as the Systems Administrator or ’that guy from IT’, can install and configure any and all operating-system and application software that may be needed by a user. Fortunately, under GNU/Linux, YOU are the Superuser of your own life (see the ’sudo’ command).
  • Windows(tm)
    1. An evil plot, oozing out of Redmond, Washington USA, which is trying to dictate what a user may and may not do with his or her own computer.
    2. A virus magnet.
    3. The world’s largest collection of software bugs.
    4. The last pathetic refuge of failed programmers.
  • console (or terminal)
    In ancient times, the console was a Teletype machine, or a combination of display and keyboard which gave users access to the giagantic-but-retarded computers of prehistoric times. Today, the console is the software program which emulates on your own personal computer the consoles of yesteryear; it is the window in which the command-line interface lives; it is a programmer’s best friend and the seat of all power.
  • curses (or ncurses, or ncursesw)
    ’curses’ is the UNIX version of a text-based system which allows for formatted data display in the terminal window.
    ’ncurses’, or New Curses, is the GNU/Linux replacement for and enhancement of the original ’curses’. Both ’curses’ and ’ncurses’ are intended primarily for use with 7-bit and 8-bit (ASCII) text data, and are therefore nearly worthless in an international environment.
    ’ncursesw’ is the ’wide’ (32-bit) version of ’ncurses’ which supports all human languages (and Klingon :). The NcDialog API uses the ’ncursesw’ library exclusively in order to support full internationalization.
  • dialog
    A conversation between two beings. As used here, it is the name for a simple window within the console window through which you can have a conversation with your computer.




What Is a Class?

Why do I need to have Class?

In the early days of computing, a computer program was a sequence of instructions which performed a sequence of tasks in a particular order. This style is sometimes referred to as ’structured programming’ because the structure of a program was task oriented, like a Rube Goldberg Machine:

a) the marble rolls down the incline, hitting the bottle b) the bottle falls over, causing the water to spill c) the water drains into the cup, making it heavy d) the heavy cup pushes down the lever which strikes a bell

While such a device is a fantastic toy, it is a terrible model on which to build a software program because every time you need to perform a new task, you need to create a complex new sequence of sub-tasks to support it. That’s why all modern programmers need to have class.

Object Oriented Programming

Work in the real world is based on using tools which are designed for a specific purpose. You drive a nail with with a hammer, not a corkscrew; and unless you are a drunken engineering student, you open your bottle of wine with a corkscrew, not a hammer.

Each tool has been tested under real-world conditions and has proven itself to be reliable. The tool is able to do its job independently, without depending on help from any other tool.

Each tool is reusable for a variety of related tasks; thus, if you need to perform a given task, all you need to do is select the right tool for the job.

In the world of modern programming, we emulate the real world. We use existing, well-behaved tools when available; we modify existing tools when necessary to meet our current needs; and create new tools to meet new challenges. In C++, Java and other object-oriented languages, these tools are called ’classes’.

Now that I have Class what do I do with it?

A ’class’ may be thought of as a specific set of data (variables) AND the code needed to access and modify that data. This is a huge step forward in programming because it protects your data from outside influences (forces of evil?) which might otherwise randomly trash your application without your being able to trace the source of the problem.

Working in C++ means leveraging class definitions to handle most of the details in an execution sequence. Not only does this allow for robust and modular code which can be easily modified or re-used, it ALSO means that the code is human-readable i.e. maintainable.
These classes fall into four categories:

  1. Primary classes
    These classes define major operations and control the program flow.
    The Primary classes of the NcDialog API are the NCurses class, the NcWindow class and the NcDialog class.
  2. Derived classes
    These are classes based on one of the Primary classes, but modified to accomodate special cases of the task the Primary class was created to perform. For instance, the NcDialog class is actually ’derived’ from the NcWindow class. That is, the basic, reliable and well-behaved functionality of the NcWindow class is leveraged to create a special case of the parent class. Specifically, the primitive ’window’ object of the NcWindow class is enhanced to create the ’dialog’ object of the NcDialog class.

    Some additional examples of Derived classes in the NcDialog API are the user interface control objects, which are themselves based on the NcWindow and/or the NcDialog classes, to perform specific types of user interaction.

  3. Secondary classes
    These classes are needed to pass information between the application code and the Primary class methods or internally among methods. A few of the often used Secondary classes of the NcDialog API are:
    see winPos class
    see wkeyCode class
    see InitCtrl class
    see InitNcDialog class
    see uiInfo class
    All of these classes are used to transport data between the application layer and the NcDialog API methods.
  4. Support classes
    This group of classes is used internally by the Primary, Derived and Secondary classes. Because they are not used directly by the application code, these classes are not discussed in this document. Support classes are defined and described in the the associated header files: NCurses.hpp, NcWindow.hpp and NcDialog.hpp.

Don't worry! Be happy!

In summary, don’t let your professors or or other programmers frighten you with technical jargon about objects, classes, inheritance, overloading and other such nonsense. The jargon is not the thing itself, so just get familiar with the tools by studying example code and through personal experimentation. In a very short time, you will start to wonder how anyone ever wrote software before there were classes.





Reading Texinfo documentation

Texinfo is the official documentation engine for the entire GNU project, which includes GNU/Linux and all of its component applications. The Texinfo engine is not very sophisticated, but it is surprisingly powerful.

On the command line, type the ’info’ command to view the main page of the info document tree. Use the arrow keys, PgUp, PgDn, Home, End to navigate through the page. With the cursor on a line which contains the ’*’ (hyperlink) character, press the ENTER (RET) key to access the specified node on the tree.

The ’info’ reader has a large number of options which can be seen by pressing the ’h’ key for Help. (Press the ’x’ key to close the Help window.)

The ’n’ and ’p’ keys move to the Next and Previous chapters respectively, and the ’u’ (up) key takes you to the parent node of the current position in the info tree.

Probably the most useful command is the ’s’ (search) key or the equivalent ’/’ (forward slash) key which invokes a search. After pressing ’s’, type in a string for which to search and press ENTER (RET). To search for the same string again, either press the ’}’ key (search forward) or ’{’ key (search backward), or just press ’/’ and then ENTER (RET).
Case sensitivity: Whether the search will be case sensitive depends on the search string. If you enter all lower-case characters, then the search is not case sensitive; however, if you enter mixed upper-case and lower-case, then the search is case sensitive. (Who thinks this stuff up? :)
The search tool is not perfect, and you may end up in a document which is completely unrelated to your needs, but it is still a useful tool.

The 'l' key move to the ’last’ (most-recently-visited) chapter, so if you find that your search has gone astray, you can walk backward through the list of visited pages.

Press the ’q’ (quit) key to exit the info reader.


There are two(2) general ways to access the documentation for a specific application package.

  • Read an ’installed’ info document.
    A document which has been ’installed’ is one which is visible as a node on the system’s info reader tree. An installed document can be accessed simply by typing:
       info documentname

    For instance, at the command line, type:
       info which
    This will bring you to the documentation page for the ’which’ utility.

    You can even type the following to learn how to use the info reader:
       info info
        OR
       info info index

    PLEASE NOTE: Like most things Linux, data passed to the info reader IS case sensitive.


  • Read a specific info document file.
    Documents in the ’.info’ format do not need to be installed for you to use them (although an installed document is more convenient).

    You can access a specific document directly by typing:
       info -f document-name.info
    The ’-f’ option indicates that what follows is a document name, and this will open the specified document to its main page.

    To open the document to a specific chapter (node):
       info -f document-name.info -n 'chapter name'
    The ’-n’ option indicates that what follows is the name of a chapter. Note that if the chapter name contains spaces, it must be enclosed within quote marks as shown.

    For instance, to access the chapter you are reading at this moment, you would invoke the info reader with:
       info -f ncdialogapi.info -n 'Reading Texinfo documentation'
    This will open the document at the top of the current chapter.

    If you wanted to open the document to a specific section within a chapter, and you happen to know the name of the hyperlink for that section, you can substitute it instead of the chapter name as follows:
       info -f ncdialogapi.info -n 'OpenWindow method'
    This will take you to the entry for the OpenWindow method, within the chapter, ’Dialog Window Methods’.

    You can also search the document’s index for a particular string or substring identifying an item:
       info -f ncdialogapi.info --index-search=OpenWindow
    This will take you to the entry for the OpenWindow method without having to know the exact name of the entry. Note however that if there are multiple entries containing the same substring, then you get the page for the first match found.

    If you are not sure of the name of the chapter or topic you want, then type:
       info -f ncdialogapi.info index
    This will take you to the document’s Index page. Note that some documents are better indexed than others, but with great modesty, we can say that this document’s index is the index against which all other document indices are measured. (and that’s as modest as we ever get :-)





Configuring Linux

GNU/Linux Installation and Configuration

The GNU/Linux distribution packages available for download or purchase are generally robust and easy to install if you accept all the default options. However, we have never met a Linux warrior who could accept all of these default options. These defaults were dreamed up by some tool in the Marketing department, based on their idea of an imaginary lowest-common-denominator user.

We all need more than that, especially those of us who write software for fun and profit. Using the NcDialog API requires very few non-default Linux installation and configuration options, but be sure that your development system is properly set up for the following tools.

  1. GNU G++ compiler, headers and libraries
    The compiler may be properly installed by default on your system because it is needed for a number of other installation and update tasks.

    However, it is important that your compiler is up-to-date and has the correct paths set for all components, including the linker.

    When you invoke the compiler, at the command line, a great number of complex activities are performed, and if even one of them goes wrong, the compile will not be successful.

    Setting up the compiler is beyond the scope of this simple document, but you can find additional information here:

    • Read the official documentation:
         info gcc
    • See the Free Software Foundation website’s installation pages:
         https://gcc.gnu.org/install/
    • Building the compiler from source:
         https://gcc.gnu.org/install/configure.html
    • Reference the compiler’s help:
         g++ --help | less

    Also, please see Building the API Library for additional information on updating and using the G++ compiler.



  2. ncurses (ncursesw) development system
    It is quite possible that the ’ncurses’ development system including needed headers and the ’ncursesw’ link library will not be installed by default on your system.

    Please see Libraries for ncurses for details on installing the ncurses development system.



  3. Texinfo documentation (makeinfo) development system

    Documentation written for GNU/Linux, its utilities and applications is written using the Texinfo documentation system. Source documents are initially written as plain text files, similar to HTML source documents, but with Texinfo formatting commands. Source documents are identified by the ’.texinfo’ filename extension (often shortened to just ’.texi’).

    Documentation is produced using the Texinfo ’makeinfo’ utility. ’makeinfo’ operates on the Texinfo source files to produce output in a variety of file formats. While the NcDialog API documentation is generated in ’.info’ and ’.html’ output formats only, several other formats are available through ’makeinfo’ options.

    The Texinfo (makeinfo) utility is often not installed by default, so if you want to create or modify documentation, you will need to install it. Please see Updating Texinfo Docs for additional information.

    Using the Texinfo documentation engine is too big a subject to cover here, but moderately good, and sometimes excellent information is readily available to help you get started with Texinfo (makeinfo).

    • The Texinfo documentation (if installed on your system):
         info texinfo
         info makeinfo
    • The GNU Texinfo official page:
         http://www.gnu.org/software/texinfo/

      Shameless plug: The GNU Texinfo page also contains a link to Software Sam’s contribution to the Texinfo project.

    • The Texinfo users’ mailing list:
         help-texinfo@gnu.org




Selected command-line utilities

The Linux Terminal and the Command Line

While it is not our intention to frighten those who are new to Linux, be aware that it will take several years and many tears to fully master the system command line, and most of us never do fully understand the hundreds of available commands.

Fortunately, a very modest general knowledge of command-line utilities is sufficient to produce highest-quality applications based on the NcDialog API.

What follows is a short list of command-line utilities you will probably find useful, and very simple descriptions of how to use them.

Full information on each of these utilities is available, through the ’info’ documentation system. Note that some command-line utilities have the same name as equivalent C-language functions. If for instance, you type  'info mkdir',  you will get the ’mkdir’ C function. If this happens for a command you are researching, invoke the info system like this:  'info coreutils mkdir to access information on the command-line utility.



  • ’cd’ Change Directory
    Navigating around the directory tree of your local drives using ’cd’ is somewhat tedious, and there are several innovative ways to navigate the directory. For example, the ’Teleport’ utility (see tp command), or our own FileMangler utility see Technical Support. However, a basic knowledge of ’cd’ is necessary for every computer user.
    First, before changing directories, it is important to know where you are in the directory tree. This is done using the 'pwd' command: pwd This should yield something like: /home/JoeUser/Documents/NcDialog Some special characters: '~' (tilde) This references the user's home directory. '.' (here) This directory i.e. the current directory '..' (parent) The parent directory of this directory '/' (seperator) Separate file and directory names from each other (Note that this IS NOT the Windoze '\' backslash.) '/' (root) The forward slash, if it is the first (or only) character in the path, indicates the 'root' directory, the grandparent of all files in the tree. '-' (minus) return to the previous directory Move from the current directory to the specified absolute path: cd /usr/include cd /run/media/JoeUser Move from the current directory to its parent directory: cd .. Move to a subdirectory below the current directory: cd source/archive/version-0.21 Move from the current directory to a directory at the same level: cd ../Homework Move to your home directory: cd ~ cd (no option) Move from the current directory to another directory, then return: cd /usr/lib64/nautilus/extensions-3.0 cd -
  • ’ls’ LiSt filenames
    View the names of files and directories on your directory tree.

    The ’ls’ command takes an optional ’regular expression’ as a filter for the filenames which will be displayed. ’ls’ also has many options for formatting the output. Here are a few common examples:

    The 'ls' command with no options will yield a simple list of the files in the current directory, listed alphabetically in columns based on the width of your terminal window. Note that files of certain special types may be displayed in distinctive colors. ls BillboardTest.cpp DMouseTest.hpp NcWindow.hpp BillboardTest.hpp GlobalDef.hpp RTL_ContentTest.cpp CMouseTest.cpp gString.hpp RTL_ContentTest.hpp CMouseTest.hpp Makefile screenshot-styles.css Dialog4 NcDialog.a ShellTest.cpp Dialog4.cpp NcDialog.hpp ShellTest.hpp DialogAppShared.hpp NCurses.hpp ThreadTest.cpp DMouseTest.cpp NCursesKeyDef.hpp ThreadTest.hpp An example with a search pattern which limits the list to files with a '.cpp' filename extension: ls *.cpp BillboardTest.cpp DMouseTest.cpp ThreadTest.cpp CMouseTest.cpp RTL_ContentTest.cpp Dialog4.cpp ShellTest.cpp The '-l' option formats the output to provide detailed information on each listed file. ls -l *.cpp -rw-rw-r--. 1 sam sam 68901 Jul 10 2014 BillboardTest.cpp -rw-rw-r--. 1 sam sam 48799 Feb 4 12:05 CMouseTest.cpp -rw-r--r--. 1 sam sam 105476 Apr 14 11:56 Dialog4.cpp -rw-rw-r--. 1 sam sam 77911 Feb 4 12:06 DMouseTest.cpp -rw-rw-r--. 1 sam sam 51477 Apr 11 11:19 RTL_ContentTest.cpp -rw-rw-r--. 1 sam sam 43658 Apr 15 06:57 ShellTest.cpp -rw-rw-r--. 1 sam sam 27059 Apr 14 12:25 ThreadTest.cpp Please refer to the documentation for the 'ls' command for an explanation of each of the reported items.

    Note that most systems include some aliases for the ’ls’ utility. These aliases are shorthand ways of accessing ’ls’ with specific and often-used options. Here are some common aliases:

    alias l.='ls -d .* --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto'

    Please see the ’alias’ shell builtin command for information on how to create your own custom commands.


  • ’cp’ Copy a file or group of files
    The ’cp’ command copies a file, a group of files or whole directory trees to the target directory. ’cp’ is a complex utility that transparently handles access to all supported filesystems, removable drives, remote drives (servers) and more. The ’cp’ command also automatically manages modification of file ownership and permission bits (see ’chmod’ below) as well as creating backup files.

    ’cp’ also offers options to copy either ’symbolic links’ OR the link targets, as well as the option to create a ’hard link’ to the source file rather than making an actual copy of the source file.

    Useful ’cp’ options:

    • ’--update’ or ’-u’ option specifies that any existing target file of the same name which is OLDER than the source file will be overwritten, but that if an existing target file is NEWER, than the source file, the file will not be copied.
    • ’--no-clobber’ or ’-n’ option specifies that existing target files will not be overwritten.
    • ’--preserve[=ATTR_LIST]’ or ’-p’ option specifies that certain attributes of the source file such as owner and timestamps will be preserved in the target file. Without this option, the target file timestamp will be the current date/time.
    • ’--target-directory=TARGET_DIR’ or ’-t’ option specifies a target directory for a list of files to be copied (see below).
    • ’--symbolic-link’ or ’-s’ option specifies that a ’symbolic link’ (shortcut) file should be created as the target file (see below).

    While all the advanced options will be useful to you at times, for a new user, the important issue is simply protecting the time and effort you have put into creating your source documents, by making a safe copy of those documents from your ’home’ directory to different media.

    To do this, it is important to know where the external media are ’mounted’ (visible). The point on the system directory tree where external storage devices are visible depends on the type of system and its age. The modern GNU/Linux and POSIX standards say that removable storage devices should be mounted at:

    /run/media/UserName/ Example: /run/media/sam/TravelDrive

    Note that above path does not include “smartphones” and tablets which are mounted using “GVFS” (the Gnome Virtual Filesystem).

    For older systems, the mountpoint might be one of the following or some other position on the tree.
        /media/
        /mnt/

    There are several ways to locate mountpoints for removable filesystems. One of the most useful is the ’findmnt’ command which lists mounted devices with a variety of options and formats.

    Examples: findmnt -A (shows the entire directory tree) findmnt -D (shows only 'real' devices)

    Once you have located the target media, you can copy files to it. Let’s say that our target is a subdirectory on the device:
        '/run/media/sam/TravelDrive'
    and that your CWD (current working directory) is:
        '/home/sam/NcDialog/Dialog4'

    List the names of the subdirectories on the target.
    (For now, don’t worry about how that happens):
        ls -F1 /run/media/sam/TravelDrive | grep '/'
        Backup/
        Homework/
        Photos/

    Copy one file from CWD to target:
    Because ’Backup’ is the name of a subdirectory, it is not necessary to enter the target filename, but appending the ’/’ (forward slash) to the target path is good practice in case you accidentally copy to a filename rather than a directory name.
        cp -u Dialog4 /run/media/sam/TravelDrive/Backup/

    Copy one file from CWD to target with rename:
        cp -u Dialog4 /run/media/sam/TravelDrive/Backup/Dialog4_Jan06

    Copy all files with ’.hpp’ and ’.cpp’ extensions from CWD to target:
        cp -u *.[hc]pp /run/media/sam/TravelDrive/Backup/

    Copy a list of files from CWD to specified target directory:
        cp -ut /run/media/sam/TravelDrive/Backup/  a.txt b.odt c.hpp

    Copy a file that is not in the CWD to target:
        cp -u ../Dialog/Dialog1.cpp /run/media/sam/TravelDrive/Backup/

    Creating ’symbolic links’ (shortcut files) is another useful feature of the ’cp’ command. Here, we create a symbolic link ’d4’ on the executable path which points to our local binary file, ’Dialog4’. This means that you will be able to invoke the file from any location (CWD) on your directory tree. Note that symbolic links cannot cross filesystem boundaries.
        cp -sx Dialog4 ~/home/sam/bin/d4


    It will take time to discover the full power of the ’cp’ command, but you will have mastered a skill that will serve you well.

    Important Note: Your local hard drive is the weakest component in your system, and the most likely to fail at any time. Back up your data to alternate media AT LEAST once every day, and at least once a week, perform a backup to a DIFFERENT media device. In short, never have fewer than three(3) copies of every file you create. Your data is your life’s work—don’t lose it!

    Editorial: Never-never-never backup your data to the 'Cloud'. The Cloud is a marketing concept, dreamed up as a means for Black Hats (marketing analysts, or worse) to mine your private data. DON'T DO IT!


  • ’rsync’ Synchronize source and target files
    Like an intelligent ’cp’ command, ’rsync’ synchronizes the target files and directories with the corresponding source files and directories. This can be quite useful, especially if you are copying over a network because only files that have changed since the previous backup will be copied.

    ’rsync’ has a huge number of options for a wide variety of daily file-maintence activities. For a practical example of ’rsync’ usefulness, please examine the ’Makefile’ located in the Dialog1 subdirectory of the NcDialog API package. A quick introduction is provided here.

    # 'rsync' is used to update the files for the test # applications after the NcDialog library is rebuilt: .PHONY: publish publish: rsync -pogtiu $(ND_HFILES) DialogAppShared.hpp ../Dialog2 rsync -pogtiu NcDialog.a ../Dialog2 # Switches: # -p preserve permission flags # -o preserve owner (not really needed in this example) # -g preserve group name # -t preserve modification timestamp # -i itemize (report) all copy operations # -u update only for source files newer than target

    ’rsync’ compares the files in the ’Dialog’ directory with the corresponding files in the other directories, in this example, the ’Dialog2’ subdirectory. For any newer files in ’Dialog’, the files are copied to ’Dialog2’, overwriting the older versions.


  • ’mv’ MoVe (rename) a file or directory
    Renaming or moving a file is a simple operation, but has some hidden dangers, so it is important to understand how the ’mv’ command works.
    Rename a file:
        mv Today_data Yesterday_data
    
    Move a file in the current working directory (CWD) to a 
    lower-level subdirectory named 'Old', retaining the 
    original filename:
        mv Today_data  Old/
    
    Move a file in the CWD to a lower-level subdirectory 
    named 'Old', but with a different target filename:
        mv Today_data  Old/Yesterday_data
    
    Move a file in the CWD to another subdirectory at the same 
    level, retaining the original filename:
        mv Today_data  ../Old/
    
    Make a backup file of any target file that would otherwise 
    be overwritten. If the file 'def.txt' already exists, then the 
    following will make a backup copy of it and THEN overwrite the 
    existing target file.
    
    View current directory contents:
        ls *.txt*
      yields:
        abc.txt def.txt
    
    Rename 'abc.txt' as 'def.txt'
        mv -b  abc.txt def.txt
    
    View the results:
        ls *.txt*
      yields:
        def.txt def.txt~
    
    Note that the appended tilde character ('~') indicates 
    a backup file.
    
    - - - - -
    Note: When the source file is a 'Symbolic Link' file, the link 
    file itself, and NOT the file it points to is moved/renamed.
    
    View current directory contents:
        ls
      yields:
        Dialog4
    
    Create a Symbolic Link to 'Dialog4'
        cp -s Dialog4 link2Dialog4
    
    View the results:
        ls
      yields:
        Dialog4 link2Dialog4
    
    Rename the Symbolic Link file:
        mv link2Dialog4 d4_link
    
    View the results:
        ls
      yields:
        Dialog4 d4_link
    

  • ’mkdir’ Make Directory (create a new subdirectory)
    The GNU/Linux filesystem is organized as a directory tree, with the root directory ’/’ as its base. Keeping your files organized is one of the most important habits of a software designer, and creating accurately-named branches (subdirectories) on the filesystem tree is the primary way to do that.

    Generally, your files will all be stored within your ’Home’ directory where all the files belong to YOU and ONLY to you.
        /home/UserName/

    This means that you need not worry too much about whether you have permission to create new subdirectories, or what permissions those subdirectories will have. (See the ’chmod’ utility, below, for more information on file permisisons.)

    Create a new subdirectory within the current working directory (CWD):
        mkdir tmpStorage
    
    View the results:
        ls -ld tmpStorage
      yields:
        drwxrwxr-x. 2 sam sam 4096 Apr 18 12:32 tmpStorage
    
    Create an entire subdirectory tree. Create all directories in the 
    specified sequence. If one or more of the targets already exists, 
    it will not be modified.
        mkdir --parents Level2/Level3/Level4/newDir
    
    Create a new subdirectory with specific permissions:
        mkdir --mode=u+rwx,g-rwx,o-rwx  PrivateData
    
    View the results:
        ls -ld tmpStorage
      yields:
        drwx------. 2 sam sam 4096 Apr 18 12:47 PrivateData
    

  • 'rm', 'rmdir', 'unlink' Delete a file or directory
    The ’rm’ command removes (deletes) a file or group of files from the filesystem tree, and optionally the contents of a filesystem tree. USE CAUTION!

    The 'rmdir' command removes an empty subdirectory name.

    The ’unlink’ command is a much simplified version of ’rm’. It can remove only one file.

    Some Examples:
        rm  LottoLosers.odt          (delete specified file)
        rm  Test.txt Test.htm        (delete specified files)
        rm  *.o                      (delete all object files)
        rmdir tmpdir                 (delete an empty directory)
        rmdir -r old_crap_dir        (delete a directory and its contents)
        unlink timeline.txt~         (delete a backup file)
    

    In general, it is better to send files to the trash, rather than simply deleting them from the filesystem tree; however, there are some files that you ’know’ you will never need again, such as out-of-date object files.

    Shameless plug: Note that accessing the local Trashcan from the command line is not as easy as it sounds; however, Software Sam offers two utilities for command-line access to the system’s Trashcan.

    • cTrash
      The ’cTrash’ utility is a simple, console-based application providing complete control over the Trashcan through a command-line interface.
    • FileMangler
      Our ’FileMangler’ file-management application provides full support for the Trashcan (trash and restore) from inside a console dialog interface.
    • Please see Technical Support for more information.

  • ’gmake’ (make) Execute the commands in a Makefile
    ’Makefile’ is the default name for a file which contains ’recipes’ i.e. sequences of conditional commands which are used for everything from building a C-language application to performing complex installations.

    Makefiles are executed by the ’gmake’ (’make’) utility.
    While ’gmake’ itself is fairly simple to use, writing complex makefiles is an art form.

    The ’gmake’ (GNU make) utility searches for files of specific names in a specific order (’GNUmakefile’, ’makefile’, and ’Makefile’), and it processes the first one it finds. You can override this search by directly specifying the file or files to be processed.

    Some Examples: gmake gmake -f makeit make -f townmake -f countrymake -f citymake

    Please see the ’Additional Tools’ section of see Development Tools for further information, or study any of the ’Makefile’ files used to build the NcDialog API and its test applications.


  • ’chmod’ Change file Mode bits (permission bits)
    The ’chmod’ command is actually simple, but the built-in ’--help’ instructions and the ’info’ documentation for the command are rather weak and confusing. For this reason, we will try to provide a simple (if incomplete) explanation that will be useful to most users.

    What is a ‘file type’?

    First, we have the concept of ’file types’. Here is a list of the common file types. Additional file types exist for certain systems and special cases, but unless you’re a UNIX geek, you will probably never see those types.

    • Regular files: most non-system files fall into this category
    • Directory files: a file which contains the names of the files in the specified subdirectory
    • FIFO files: special, byte-oriented communications channels
      (named pipes)
    • Socket files: special, interprocess and inter-system communications channels, most commonly used to communicate between your local system and other systems in your network, or with the internet.
    • Block Device files: driver file for block-oriented devices
      (hard drives, CD drives, Flash drives, SD cards, etc.)
    • Character Device files: driver file for character-oriented devices
      (keyboards, displays, Teletype machines, some printers, etc.)
    • Symbolic Link files: shortcut files which point to actual files.

    The ’chmod’ command operates primarily on ’Regular’ files and ’Directory’ files; however, if the target file is a ’Symbolic Link’, the the file the link points to will be modified, NOT the link itself.
    (Unless you know exactly what you are doing, don’t use ’chmod’ on other file types.)

    What are ‘mode bits’?

    The next concept is that of ’mode bits’. Mode bits fall into two categories, ’permission’ bits and ’special mode’ bits. For most practical applications, you can ignore the ’special mode’ bits, so we will concentrate on the ’permission’ bits. The permission bits are organized as three groups of three bits each, and are defined as follows:

    • Owner: the person to whom the file belongs
      • Read: permission to read the file’s contents
      • Write: permission to modify the file’s contents or to delete the file.
      • Execute: permission to execute (run) the file
        Applies to binaries and script files only.

      Note that the Owner is also referenced as ’User’ because ’Owner’ and ’Other’ both begin with the letter ’O’. You’ll see why this is an issue in a moment.

    • Group: the work group whose members are allowed to access the file. For files on a local system, the Owner and Group are generally the same; however, in a corporate setting, a Group is a list of user names for the users who have access to the file.
      • Read
      • Write
      • Execute
    • Other: everyone else
      The universe of users who are neither the file’s Owner nor a member of the file’s Group.
      • Read
      • Write
      • Execute

      Interestingly, Owner and Group ARE NOT members of the ‘Other’ universe, so they must receive explicit permission to access the file.

    For Directory files only, the permission bits have some additional special meanings:

    • Read: ability to list the names of files in the directory
    • Write: ability to add or remove files from the directory
    • Execute: ability to access the files in the directory

    What are the file's current permission bits?
    ............................................
    

    To determine the current permissions on a file, you can use the ’ls’ command described above:

    List a 'Regular' file:
        ls -l Dialog4
    yields:
        -rwxrwxr-x. 1 sam sam 949572 Apr 15 06:57 Dialog4
    
    List a 'Directory' file:
        ls -ld NcDialog
    yields:
        drwxrwxr-x. 10 sam sam 4096 Apr  3 09:55 NcDialog
    

    The first ten(10) characters on the left indicate the current state of the file’s permission bits. The leftmost character indicates the file’s ’type’. For the remaining characters, if the bit is ’set’ (true), then an alphabetical character is displayed. If the bit is ’reset’ (false), then a dash ’-’ character is displayed.

       1) -   = regular file
          d   = directory filetype
          l   = symbolic link filetype
          p   = FIFO filetype
          s   = socket filetype
          b   = block special filetype
          c   = character special filetype
     2-4) rwx = Owner's read/write/execute permissions
     5-7) rwx = Group's read/write/execute permissions
    8-10) rwx = Other's read/write/execute permissions
    

    Using the ‘chmod’ command

    Finally, we come to the use of the ’chmod’ command, itself.
    ‘chmod’ can be used in either ’numeric bit mode’ or ’symbolic bit mode’. Since ’numeric bit mode’ uses the octal (base-8) number system, and since no one in their right mind would use octal in a modern computer system, we will discuss only the ’symbolic bit mode’ method.

    Symbolic representation of the permission bits is done with the following characters:

    'u'   = Owner (User)
    'g'   = Group
    'o'   = Other
    '+'   = add (grant) a permission
    '-'   = remove (deny) a permission
    '='   = exclusive OR (only specified permissions granted, others removed)
    'r'   = user has Read permission
    'w'   = user has Write (modify) permission
    'x'   = user has Execute (run) permission
    

    Given the example output from the ’ls’ command, above:
        -rwxrwxr-x. 1 sam sam 949572 Apr 15 06:57 Dialog4
    note the permission bits:
        -rwxrwxr-x

    First, the initial bit settings (left-to-right) represent the following:

    - regular file (file type) r Owner (User) read permission w Owner (User) write (modify) permission x Owner (User) execute (run) permission r Group read permission w Group write (modify) permission x Group execute (run) permission r Other read permission - Other NO write (modify) permission x Other execute (run) permission

    We will use this character sequence to indicate the sequential changes made to the file using the ’chmod’ command.

    In our examples, we will modify the permissions for a single file; however, note that multiple files or entire directory trees can be modified with a single command.

    Remove Other's permission to execute the file:
        chmod o-x  Dialog4
      yields: -rwxrwxr--
    
    Remove all of Group's permissions:
        chmod g-rwx  Dialog4
      yields: -rwx---r--
    
    Add execute permission for both Group and Other:
        chmod go+x  Dialog4
      yields: -rwx--xr-x
    
    Remove write (modify) permission for all users
    i.e. write-protect the file:
        chmod ugo-w  Dialog4
      yields: -r-x--xr-x
    
    Give all users, Owner, Group and Other read/write permission
    but NOT execute permission:
        chmod a=rw  Dialog4
      yields: -rw-rw-rw-
    
    Add execute permission for Owner and Group, AND remove all 
    permissions from Other:
        chmod ug+x o-rwx  Dialog4
      yields: -rwxrwx---
    


    Note on the ’umask’: The ’umask’ is the system’s default method of assigning permissions to a file. Generally, the system guesses correctly, but sometimes the ’umask’ causes some unexpected results. See the info docs chapter, ’Assigning File Permissions’ for more information.



    Two additional commands, ’chown’ and ’chgrp’ may be used to modify the file’s owner and the file’s group respectively, but since they are seldom needed, we won’t discuss them further here.



  • ’grep’ Search for text strings in target files
    The ’grep’ command is an incredibly powerful and flexible utility. As a software designer, you may come to depend on ’grep’ more than any other tool.

    ’grep’ has more than 20 options, but there are three(3) options which stand out among the crowd: ’-r’ (recurse subdirectories), ’-n’ (print line numbers), and ’-i’ (perform case-insensivive search). Here are a few examples:

    For all header files in the current directory, find each instance of the word 'Copyright' (case-sensitive search). grep 'Copyright' *.hpp For all source files in the current directory, find each instance of the sequence 'TESTING ONLY', (case-sensitive with line numbers). grep -n 'TESTING ONLY' *.[hc]pp List all NcDialog-class methods in the specified source file (case-sensitive with line numbers). grep -n 'NcDialog::' NcdControl.cpp List all instances of the word 'BUG' in the source modules in this directory (case-insensitive with line numbers). grep -ni 'bug' *.cpp Find all instances of the 'CaptureDialog' method used in the NcDialog test applications (recurse subdirectories). Note that the line with matching text AND the line that follows it are displayed grep -nA1 'CaptureDialog ' Dialog/Dialog1.cpp Dialog[234wx]/*.cpp This will yield: Dialog/Dialog1.cpp:5229: Test08Dialog->CaptureDialog ( Dialog/Dialog1.cpp-5230- (fmt ? capHtml : capText), -- Dialog2/CapTest.cpp:1060: status = capDlg->CaptureDialog ( capHtml, fmt, Dialog2/CapTest.cpp-1061- false, "../Texinfo/infodoc-styles.css", -- Dialog2/CapTest.cpp:1065: status = capDlg->CaptureDialog ( Dialog2/CapTest.cpp-1066- (fmt ? capHtml : capText), fmt ); -- Dialogw/Dialogw.cpp:4205: Test09Dialog->CaptureDialog ( Dialogw/Dialogw.cpp-4206- (fmt ? capHtml : capText), fmt ) ;

    Because ’grep’ is such a popular utility it likely has aliases (see ’ls’ above) defined for often-used options. Here is a sample:

    alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto'

  • Using pipes
    ’Pipes’ are a form of re-direction of terminal output from one utility, to be used as input for another utility. It is impossible to overstate the importance of learning how to use pipes.

    The special character ’|’ (vertical bar) indicates redirection through an unnamed pipe.
    (Named pipes i.e. FIFOs are not discussed here.)
    The specialized pipes ’>’ (overwrite) and ’>>’ (append) redirect output to a file.

    Here is an assignment used in our Introduction To Linux class.

    "Given the complete works of Shakespeare in plain-text format, your task is to find every line of text that contains BOTH the word ’darkness’ AND the word ’light’ (uppercase or lowercase), but that DOES NOT include the word ’you’. Occurrances are not necessarily sequential, and are not in any particular order." (Aren’t you glad you didn’t take this class?)

    One student wrote a lovely, 400-line C program to scan all 42 files, but actually, the answer is incredibly simple using pipes.

    Command:
    grep -nid recurse 'darkness' WillsWorks/* 
              | grep -i 'light' | grep -vi 'you' >dark_light.txt
    
    The answer is captured to a file 'dark_light.txt':
    
    11:WillsWorks/comedies/periclesprinceoftyre.txt:1280:	
            The which hath fire in darkness, none in light: 
    29:WillsWorks/histories/2kinghenryvi.txt:1235:
            Gives light in darkness, comfort in despair!
    

                    Pipes Rule !!


  • ’less’ Display the contents of a file
    Quickly viewing the contents of a file without the time and effort needed to load it into an editor, is one of the most common activities in computing.

    There are many ways to view file contents. The ancient ’cat’ command has its uses, but we are 30 years on from ’cat’. The ’more’ command is a great improvement over ’cat’ because it displays one screenful of information at a time.

    However, the ’less’ command allows you to view the entire file, scrolling back and forth through the data, searching (foreward and backward) for specific strings and much more--all without having to open an editor.

    Some Examples:
        less Makefile
        less README
        less Makefile READEME VERSION_HISTORY
    

  • ’findutils’ A collection of utilities for searching through the files on your directory tree. These utilities are incredibly powerful, but outrageously difficult to use. We offer only a few examples for the more useful and easy-to-comprehend options.
    Please refer to 'info -f find.info' for complete descriptions and options.
    • ’locate’
      The ’locate’ utility searches various databases which contain path/filename entries. This is a quick way to search for a system file, a directory name or other needed file. ’locate’ does not search the actual directory tree, but simply reads databases. To see which databases are searched, type:
      locate -S
      This will list the name and location of each database and some statistics about its contents.

      By default, the filename pattern you specify will be compared against the entire path/filename string for each entry. To check against only actual filenames (not path elements) use the ’b’ (basename) option:
      locate -b '.odt'
      This will list all the Open Document Text files in the database.

      Instead of searching for a substring, you can use the '-r' option so that locate will parse the search pattern as a ’regular expression’
      locate -ber 'ccpp_[er]'
      Using regular expressions (’regex’) is a whole topic in itself.
      See info -f find.info -n ’Regular Expressions’ for more information.

      Other useful options are:
      '-i' case-insensitive search
      '-c' count, but do not list the number of matches found
      '-e' list only files which still exist (use this, obviously)

    • ’find’
      Unlike the ’locate’ utility above, ’find’ actually scans the contents of the specified node(s) of the directory tree structure for the specified files.

      First, you specify the name(s) of the subdirectories to scan. If you omit this, then the current directory (and all its subdirectories) is assumed.

      Then you specify an ’expression’ option. There are a truly outrageous number of these options, with many combinations and actions to take, but the only one that is useful on a daily basis is the ’-name’ option.

      To find all files named ’Makefile’ contained in the directory tree beginning at the specified subdirectory:
      find ./DvdRep -name 'Makefile'

      To find all instances of the file ’curses.h’ file in the system’s ’include’ directory tree:
      find /usr/include -name 'curses.h'

      If there are symbolic links in the path(s) searched, they are not followed by default (but see -L and -H options).

    Again, the ’Findutils’ commands and options are a broad and complex topic, so explore them at your leisure.


  • ’tar’ Create, add to, or unpack a ’tar’ (tape archive) archive file. Of course, in this century, no individual would use actual streaming-tape as the target medium, but ’tar’ can work with almost any mass-storage device.

    A ’tar’ archive file is (humorously?) referred to as a ’tarball’, although it will only be humorous if your mother read the Br’er Rabbit and Uncle Remus stories to you. (Otherwise, it’s just dumb :-)

    Archive files combine a specified list of files or directory trees into a single, portable archive file. The archive may optionally be compressed to save space or to fascilitate transmission of the archive over a network.

    An archive file is primarily a convenient way to protect yourself from system meltdown, theft, data corruption (or late-night stupidity). ’tar’ makes a quick and reliable copy of your work, or restores a previous version of your work. It is also extremely useful for synchronizing your data across multiple installations.

    Here are just a couple of examples:

    a) Archive (and compress) a copy of your home directory: cd ~ tar tar -cvjf HomeBackup_2015.tar.bz2 * b) List the contents of an archive: tar -tvf HomeBackup_2015.tar.bz2 c) Extract one file from the archive to the current directory: tar -xf HomeBackup_2015.tar.bz2 --strip-components=1 Documents/homework.odt d) Extract one file from the archive to the original directory: cd ~ tar -xf HomeBackup_2015.tar.bz2 Documents/homework.odt e) Extract all files from the archive to the original directory: cd ~ tar -xf HomeBackup_2015.tar.bz2

    Note that extraction overwrites any existing target files by default.

    The ’tar’ utility has far more options than you will ever use, so experiment a bit to find the options that are best for protecting your data.


  • ’ldd’ Display resources needed by an executable (binary) file
    It is quite often useful to peek inside an executable binary file to determine what system resources are needed in order for the binary to run on a given system.

    Here is a typical example for the NcDialog test application, Dialog4:

    ldd Dialog4 linux-vdso.so.1 => (0x00007ffee9bb8000) libncursesw.so.5 => /lib64/libncursesw.so.5 (0x0000003a1a400000) libtinfo.so.5 => /lib64/libtinfo.so.5 (0x0000003a2fc00000) libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003a19800000) libstdc++.so.6 => /lib64/libstdc++.so.6 (0x0000003a28000000) libm.so.6 => /lib64/libm.so.6 (0x0000003a1a000000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003a1bc00000) libc.so.6 => /lib64/libc.so.6 (0x0000003a19000000) libdl.so.2 => /lib64/libdl.so.2 (0x0000003a19400000) /lib64/ld-linux-x86-64.so.2 (0x0000003a18c00000)

    If you are new to programming, this information probably won’t mean much to you, but for experienced code warriors, this is better than Christmas.


  • ’info’ Use the documentation reader
    See above (see Reading Texinfo documentation) for examples of using the ’info’ reader.

  • ’makeinfo’ Create Texinfo documentation
    See above (see makeinfo utility for more information on ’makeinfo’.

  • ’sudo’’ Execute the following command as the ’Superuser’
    At times, it is necessary to enhance your ’user privilege’ in order to perform a task that an ordinary user is not allowed to do.

    This can be done by logging into your system as the Superuser (’root’), but it is considerably less dangerous to your system to execute a single command as the Superuser using the ’sudo’ command.

    Example: Read a directory that is not normally visible. sudo ls -l /root Enter your user password when prompted, and you can see the files in the Superuser's private directory. Example: Change permissions of a file that belongs someone else. sudo chmod o+w CharlieBiography.odt
          ┌────────────────────────────────────────────────────────┐
          │                                                        │
          │  IMPORTANT NOTE:                                       │
          │  This is the seat of great power, and as we all know:  │
          │  "With great power comes great responsibility!"        │
          │                                       Old Uncle Ben    │
          │                                                        │
          └────────────────────────────────────────────────────────┘
    

  • The execution PATH:
    When you type the name of an application or shell script on the command line and press ENTER (RET), the system will search for the specified file on the execution PATH. This is a list of directories where executable files are generally stored, seperated by the ':' (colon) character. This list will be scanned in order from left to right, and the first instance found will be the file that is executed. This is an important concept because it means that you can modify the system’s search order by changing the ’PATH’ environment variable.

    Here is a typical ’PATH’ definition:

    echo $PATH
    /bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:
    /usr/sbin:/home/sam/.local/bin:/home/sam/bin
    

    Please see the ’env’ command for additional information on environment variables.

    - Executing a file which is not on the PATH -
    For security reasons, the current working directory (see ’pwd’ command) IS NOT on the search path.

    To execute a file in the current working directory, you must directly specify the location of the file using the special character sequence: './' meaning "look here". For instance, the examples above were captured while the current working directory was ’Dialog4’. To invoke the test application, ’Dialog4’ located in this directory, you would enter:

    ./Dialog4

    While this extra step may seem annoying, it is much less annoying that getting your system trashed by a moment of inattention, or by a Black Hat who is trying to steal your data.




We don’t provide direct hyperlinks to the documents referenced in the above list because this document may not be integrated into the ’info’ document tree, and would therefore cause broken links.

Please see Development Tools for additional information.

Also, there are numerous tutorial websites that explain how to use Linux command-line utilities and the dreaded ’regular expressions’ syntax. We like Dr. Bob’s Lowfat Linux (http://lowfatlinux.com), but please search the online world or your nearest bookstore to find a tutorial that is right for you.

If you are interested in Alvin Alexander’s Teleport (’tp’) utility, please visit
http://alvinalexander.com/linux/linux-teleport-command-cd-improved





Friendly Advice for New Programmers

Starting to Design an Application

Classroom instruction in programming is much like playing with a pile of Leggos. It introduces you to the concepts of writing software and produces some cute output, but it does nothing to prepare you for the realities of staring at a blank screen hoping for an idea on how to begin. Here is how to write an application: WRITE THE COMMENTS FIRST!

This is not optional. Human beings do not think in C, C++ or Java. We think in the language our mother taught us. Use it!

First, answer a couple of questions:

1) Who am I doing this for? 2) What do I want the application to do? 3) How much time and energy am I willing to invest in this project?

Answer each question with a short paragraph. Then open a blank source document and expand your answer to question #2, answering this:

Question 2a) How do I get the application to do this?

Here is an example of how to start an application. Your ideas will begin to flow more smoothly and the goals will become clearer for each comment line that you write.

// read the user's arguments // has user asked for something stupid? // if yes, call user a dumb guy and exit // perform the startup sequence // query the system's capabilities // query the user for any additional information needed // grant the user's request // report the results // ask if user needs anything else // if yes, then loop // perform the shuddown sequence and exit

Keep inserting comments, layer upon detailed layer. At some point, you will be tempted to start inserting bits of actual code into your comments. Resist this temptation for as long as possible because organized thought leads to organized code. Divide the functionality into sections and create one or more source modules for each section.

Question 2b) How do the sections interact with each other?

Different sections of the code should interact with each other in a very controlled and specific way. The reason for this is that a change in one section should never cause another section to break. This is the essense of object-oriented design.

Question 2c) Which section should I do first, second and third?

If you need to do research on some aspect of the project, it is usually best to start there. The actual process of doing the research will lead to a better understanding of the work required.

Second, do error checking on the input and error reporting. This will help you to focus on what information the application needs and how to obtain and verify it.

Next, experiment a little bit. There is no need to have finished code at this point, just make something happen. Make comments about what happens, and what fails to happen as expected. This builds confidence and provides a clearer picture of the overall project.

Clean up your mess, and then begin the actual development of the application. Procrastination about cleaning up the comments and experimental code inevitably leads to product delays, ridicule from your peers, and eventually failure.

Question 2d) Is the user interface as intuitive as I think it is?

Just because things make sense to you, doesn’t mean that anyone else will see it that way. Invest your money wisely: buy your roommate a pizza, and get him or her to test the thing for you. An enthusiastic and knowledgeable beta-tester is a treasure beyond golden-crust pizza, so put your massive, fracking ego on hold for five minutes:

DO NOT call your tester an idiot! DO NOT interrupt, DO NOT make rude noises, and DO NOT try to explain your design. DO LISTEN to what your tester has to say, and take careful notes.

Why Do I Need To Write All These Comments?

Code tells the story, so why do I need to write so many comments?
We have heard this from everyone from brilliant students, to frustrated burn-out cases, to grizzled, clear-eyed code warriors.

It is true that really great code is always and naturally self-documenting code. And it is true that over time we develop an ability to read code almost as well as we read human language. The problem is that the code only tells WHAT is being done. We need comments to communicate the thought process behind the code: WHY it is being done in this particular way, and WHY it is not being done in some other, more obvious way.

Source code has a lot in common with a good novel. It is created by an author with a burning need to tell his or her story in the hope that someone will read it and fully understand the passion and the pain that went into creating it. Source code is two intelligent human beings, the designer and the maintainer, having a conversation with each other. More often than not, the designer and the maintainer are the same person, separated by time and experience—so do your future self a favor.

A couple of examples:

Here is a simple, but typical comment written to explain why we made a seemingly redundant and unnecessary system call inside a loop. We learned the original lesson the hard way, and didn’t want to re-learn it in a future revision, NOR did we want to force someone who borrowed from the FileMangler code to go through the same pain we did.

// Programmer's Note: We could get the file type from // dirstat.d_type, (type DT_DIR=4) except that not all // filesystems have this field; thus, we ALSO lstat the target.

Here is a straightforward note to future generations about initializing the members of a date/time structure:

// Programmer's Note: If we are beyond the dreaded year 2038 // overflow point, the assignment to member time_t sysepoch // may be truncated here.

If it was important today, it will still be important twenty years from today. Write it down!


Style Counts

Programmers are highly-individualized personalities. Each of us has a unique style and approach to problem solving. Be sure that your vision and the style you see in your head translate accurately into the source code itself. Whatever your style may be, and however your style develops over time, be consistent, be clear and be honest with yourself about your strengths and limitations.

There is a worthwhile book by Herb Sutter and Andrei Alexandrescu:
C++ Coding Standards - 101 Rules, Guidelines and Best Practices.
This is the best book of its kind, filled with no-nonsense guidelines for producing successful software. If you remember nothing else from the book, remember this:

"Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure."

               — Sutter and Alexandrescu


Others Will Follow. Make It Easy For Them

The code you write today, is just the first step in a legacy that will last for years, or decades to come. You are the first contributor to the code, but you will not be the last (nor even the best).

Version 1.0 may seem like a distant dream today, but the person who writes Version 7.0, whether it is your future self, or some kid who hasn’t been born yet, will appreciate the effort you have put into making the base code easy to read and and yet robust and flexible enough to endure through generations.

The efforts of the the entire "free-as-in-freedom" software movement are based on the idea of generational software. Will the kid who takes over the project in the the year 2035, worship and admire you, or will she think you were a worthless douche-bag who should never have been allowed near a computer? Today, your legacy as a software designer is in your own hands; tomorrow is too late. Plan for the future!


Documentation Is Just As Important As Code

Users really want to trust that your application does what they need for it to do. Even more importantly, they want to trust that your application does what you say it will do.

It really doesn’t matter how good your application is if potential users don’t know what it does or can’t figure out how to use it. The quality of your application must be reflected in the quality of the documentation.

Maybe you are comfortable expressing yourself in human speech, and maybe you are only comfortable talking to your computer. Either way, do your very best to explain in writing what your application does and how it does it. If necessary, hire a technical writer to help you reach the necessary level of clarity.

Tell the truth. Marketing department goons are the Organized Crime of the corporate world. They are willing to do anything and say anything to get a new customer. This is fine for trade show brochures, but is a huge mistake for technical documentation.

Don’t lie — and don’t exaggerate. Tell the truth and speak it clearly. Your customers will be loyal to you for a lifetime.



Your First Application

The structure of an NcDialog application is a simple and easy-to-understand, even for newbie programmers, and only basic tools are needed to create sophisticated applications.





Development Tools

Developing terminal (text-based) applications is not like working in a GUI environment. It is not necessary to learn how to use a "development environment" in order to get useful work done. In fact, working in an "environment" feels to us like having to drag around a bag of rocks wherever we go. For a lovely visual of what it feels like to work within a development environment, we recommend the opening scenes of the film, "Johnny English—Reborn."

To create a complete and sophisticated NcDialog application, all you will need is a simple text editor, a terminal program and the compiler.

Text Editor

If you are an experienced programmer, you probably already have a favorite text editor, one with which you feel comfortable. If you are new to bit-herding, we do recommend that you select a text editor that has direct support for C++ formatting, i.e. a "programmer’s text editor," but the most important qualities for any tool are that it doesn’t get in the way of your productivity and that it feels right for you.

Terminal Program

We assume that you are at least generally familiar with how to use a terminal program, and that you understand the basic command-line utilities; but even if you are not familiar with 'ls', 'grep', 'chmod' and a few of the other basic commands, don’t worry. You WILL succeed.

The default terminal program for most GNU/Linux installations is either the GNOME Terminal or the KDE Konsole. Both of these are excellent choices for command-line work. Konsole is a bit more configurable (as are all things KDE), but for our purposes there is little difference between them. If you already have a favorite terminal program, you are definitely nerd enough to succeed at any task.

GCC (g++) Compiler

The use of an up-to-date compiler and its associated header files and libraries are critical to any software project. In our not-too-humble opinion the GNU GCC compiler collection is the finest piece of software ever written for public use.

The NcDialog API relies on full compiler support for the GNU++11 (C++11) standard. According to the GCC compiler’s own documentation, full support for C++11 was achieved in GCC version 4.8.1. However, several earlier versions actually had full (if poorly documented) support for C++11 functionality.

(If you are a member of that annoyingly enthusiastic group who uses LLVM/Clang as your C++ compiler, be sure that you are using version 3.3 or higher.)

Additional Tools

'make':
-------

The ’make’ utility is an integral part of software development, and you should know the basics of writing a ’Makefile’; however, the NcDialog package provides several Makefiles which you can copy and use with very little modification to build your own projects. Note that we refer to the ’make’ utility as ’gmake’ throughout this document. The reason is that we grew up using UNIX make and that worthless steaming pile of cow dung known as Microsoft make(tm), and we want to distinguish between those and GNU ’make’ which actually performs as documented.

The good news is that all you need to know for now is that you type the word ’gmake’ (or ’make’) and press ENTER.


'grep':
-------

If you are like us, you probably use ’grep’ at least three times before you’ve even had your morning coffee. This is especially true if you are working on a large project. For instance, the NcDialog project, including the test applications, is now over 45,000 lines of code.

Here’s a quick example. If you want to find the debugging method, Dump_uiInfo() in the NcDialog source code, type:
  grep -n ’NcDialog::Dump_uiInfo’ *.cpp
This will yield your answer:
  NcdControl.cpp:904:void NcDialog::Dump_uiInfo(winPos wPos, uiInfo info)




Application Framework

IMPORTANT NOTE: If you have not installed the ’ncursesw’ development package, then do it now (see Libraries for ncurses).

IMPORTANT NOTE: If you have not yet compiled the ’NcDialog.a’ link library, then do it now (see Building the API Library).

Create a Directory for Your New Application

Your new project deserves a new, empty subdirectory in which to live.
If you are new to programming, new to C++ or new to Linux, please go to Newbie Corner for general information about finding your way through the wonderful world of GNU/Linux programming.
If you’re not a programming virgin, then feel free to move ahead.


  • Open a terminal window
    This is the GNOME, Konsole or other terminal emulator.
    Expand the window to at least 132 columns wide by 32 lines high.
  • Create a subdirectory
    For this exercise we recommend that you create your work directory at the same level as the NcDialog test applications:
    cd NcDialog mkdir FirstProg cd FirstProg
  • Copy the NcDialog Support files
    cp --preserve=all ../Dialog1/*.hpp cp --preserve=all ../Dialog1/NcDialog.a
  • Create your Main Source file
    Open your favorite text editor and create an empty C++ source file. In this example we will use the name ’FirstProg.cpp’.

    Do what every programmer has done since Dennis Ritchie wrote his first ’Hello World!’ (although we will do it better than Dennis ever did).

    Copy the following into your empty source file and save it.

    // FirstProg.cpp // Written by: your_name_here // All definitions needed for your application #include "GlobalDef.hpp" // Prototype for local method void MyDialog ( void ) ; int main ( int argc, char* argv[], char* argenv[] ) { MyDialog () ; exit ( 0 ) ; } void MyDialog ( void ) { }
  • Create a Makefile
    Open another empty document which will be your Makefile.

    Copy the following into the Makefile and save it as ’Makefile’. Note that uppercase and lowercase DO matter here.

    # This variable is defined for technical reasons # (see 'make' documentation for more information) .RECIPEPREFIX = > # Definition for compiler invocation COMPILE = g++ -x c++ -std=gnu++11 -Wall -c # Link the main source file to create an executable binary FirstProg: FirstProg.o NcDialog.a > g++ -o FirstProg FirstProg.o NcDialog.a -lncursesw # Comile the main source file FirstProg.o: FirstProg.cpp > $(COMPILE) FirstProg.cpp
  • Test Your Setup
    You now have created enough of your application to try a compile, although at this time, the application still does nothing. At the command line, invoke gmake:

    gmake (ENTER)

    Your application should compile without errors and without warnings. If it does not, then please check your compiler installation and your ’ncursesw’ C-language library installation.


Add the Start-up and Shut-down Sequences

Although the start-up sequence can include several additional configuration options, this is just our first try, so we will keep it simple.

Modify main() and and the ’MyDialog’ method to look like this:

int main ( int argc, char* argv[], char* argenv[] ) { // Start-up sequence if( (nc.StartNCursesEngine ()) == OK ) { nc.ClearScreen () ; // clear the terminal window MyDialog () ; // Shut-down sequence nc.StopNCursesEngine () ; // Deactivate the NCurses engine } else { wcout << "Unable to start the NCurses Engine!" << endl ; } exit ( 0 ) ; } void MyDialog ( void ) { nc.WriteString ( 0, 0, " Hello World! ", nc.grR ) ; nc.RefreshScreen () ; // make our output visible nckPause(); // wait for a key press }

Try another compile. Your application should build without errors and without warnings. However, this time your application can show a bit of life, so after a successful build, invoke your application, admire it, invite your friends to admire it — and then press any key to exit.

gmake ./FirstProg

Congratulations!

With 22 lines of code, you have mastered almost everything you need to know about using ’ncurses’. (It really is that easy.)

The next chapter will show you how to create your first NcDialog-based application. See Create a Dialog Window.




Create a Dialog Window

Now that you have created your application template (see Application Framework) you can create a useful application based on a dialog window. Then in the next chapter, see Create Control Objects, we will add control objects.

Define What Your Dialog Will Look Like

Discard the current ’MyDialog’ method.

Insert the following ’MyDialog’ method.
Yes, this is a big step, but each item will be carefully explained.

void MyDialog ( void ) { const short dialogROWS = 24 ; // display lines const short dialogCOLS = 80 ; // display columns attr_t dColor = nc.blR, // dialog background color bColor = nc.brbl, // dialog border color mColor = nc.brbl ; // dialog message color short ulY = 2, // upper left corner in Y ulX = 2 ; // upper left corner in X const char* msg = " Hello World! \n\nPress any key to exit... " ; //* Initial parameters for dialog window * InitNcDialog dInit( dialogROWS, // number of display lines dialogCOLS, // number of display columns ulY, // Y offset from upper-left of terminal ulX, // X offset from upper-left of terminal " NcDialog - Our First Effort ", // dialog title ncltDUAL, // border line-style bColor, // border color attribute dColor, // interior color attribute NULL // pointer to list of control definitions ) ; //* Instantiate the dialog window * NcDialog* dp = new NcDialog ( dInit ) ; //* Open the dialog window * if ( (dp->OpenWindow()) == OK ) { dp->WriteParagraph ( 5, 28, msg, mColor ) ; dp->RefreshWin () ; // make everything visible nckPause(); // wait for a keypress } else { // The most likely cause of error is // that the terminal window is too small. nc.WriteString ( ulY, ulX, "Unable to open dialog window!", nc.re, true ) ; nckPause(); // wait for a keypress } if ( dp != NULL ) // close the window delete ( dp ) ; }

A Closer Look At Our Dialog

  • The first two lines define the SIZE of the dialog.
  • The next three lines define the COLOR of the dialog.
  • The next two lines define the POSITION of the dialog.
  • The next line is our display message
    And what kind of programmers would we be if we didn’t follow the only tradition in the high-tech world?.
  • InitNcDialog dInit(){}
    Next, we populate a class (structure) for passing our dialog definition to the constructor.
    We initialize this object with the following:
    — the dialog dimensions — the dialog position — the dialog title (optional) — the dialog border style — the dialog’s border color and interior color — Note: We have not yet defined any control objects, so we pass a NULL pointer for the list of control objects.
  • NcDialog* dp = new NcDialog ( dInit ) ;
    Instantiate (create) the dialog window object. This operation creates an ’instance’ of an NcDialog class object. Although nothing is yet visible, all necessary memory allocation and data configuration are now complete.
  • dp->OpenWindow()
    ’Opening’ the window means drawing the window (text and color attributes) into the dialog’s reserved memory space. The data are not yet visible because we want to write additional data into the window before making it visible.

    Note that if the dialog does not open, we display a message in the parent window calling the user a dumb-guy. There are three (3) major reasons why a dialog might fail to open:

    1. memory allocation error (unlikely)
    2. invalid dialog definition parameters
    3. the terminal window is too small to hold our dialog
      This is the most likely cause, so if the dialog doesn’t open, expand you terminal window.
  • dp->WriteParagraph ()
    Write a message into the dialog.
  • dp->RefreshWin () ;
    nckPause();
    Make the dialog visible to the user and wait for a key press.
  • delete ( dp ) ;
    If the dialog was successfully opened, then close it now.
    To ’close’ a dialog means to make it invisible and then return all its resources to the system. If you forget this step, you will have an orphaned dialog floating around your application until you return to the command line.
  • Return to main() for the shut-down sequence.

Re-compile and run your application again.

gmake ./FirstProg

Congratulations!

You have successfully created your first dialog window. Yes, we admit that our dialog still doesn’t do anything useful, but we are getting close — and with only 54 lines of code.

The next chapter will show you how to design and position some control objects which we will use to interact with the user.
See Create Control Objects.




Create Control Objects

We now have a simple dialog object (see Create a Dialog Window), and we are ready to create some control objects.

We will define a list of four (4) control objects, 1 Pushbutton, 2 Radio buttons and 1 Textbox. Then in the next chapter will provide the user with access to these controls. See Simple Interface Loop.

Give names to our controls

Although we could use magic numbers to refer to our various controls, good programming practice dictates that we should name them in a consistent and meaningful way.

Copy this name list into the ’MyDialog’ method just above the InitNcDialog initialization.

enum mdControls : short { DonePB = ZERO, // PushButton (item ZERO) lfTB, // TextBox grRB, // Radio Button for green messages yeRB, // Radio Button for yellow messages mdCONTROLS // number of controls defined } ;

Define the list of control objects

Control objects are defined by creating an initialized array of ’InitCtrl’ class objects.

The ’InitCtrl’ class is fairly complex, but for now, we will just use it, and later we will come to understand it. A detailed description of the ’InitCtrl’ class can be found at See InitCtrl class.

Copy the following array into the ’MyDialog’ method just below our name list.

InitCtrl ic[mdCONTROLS] // array of dialog control initialization objects { { //* 'DONE' Pushbutton - - DonePB * dctPUSHBUTTON, // control type rbtTYPES, // rbSubtype: (n/a) false, // rbSelect: (n/a) short(dialogROWS - 3), // ulY: upper-left Y short(dialogCOLS / 2 - 4), // ulX: upper-left X 1, // lines: height 8, // cols: width " ^DONE ", // dispText: nc.gyR, // nColor: non-focus color nc.reG, // fColor: focus color tbPrint, // filter: (n/a) NULL, // label: (n/a) ZERO, // labY: (n/a) ZERO, // labX (n/a) ddBoxTYPES, // exType: (n/a) 1, // scrItems: (n/a) 1, // scrSel: (n/a) NULL, // scrColor: (n/a) NULL, // spinData: (n/a) true, // active: can receive focus &ic[lfTB] // nextCtrl: next control }, { //* 'Linux Flavor' Textbox - - lfTB * dctTEXTBOX, // control type rbtTYPES, // rbSubtype: (n/a) false, // rbSelect: (n/a) 7, // ulY: upper-left Y 26, // ulX: upper-left X 1, // lines: height 26, // cols: width NULL, // dispText: nc.bw, // nColor: non-focus color nc.grR, // fColor: focus color tbPrint, // filter: any printing character "Favorite Linux flavor:", // label: ZERO, // labY: -23, // labX ddBoxTYPES, // exType: (n/a) 1, // scrItems: (n/a) 1, // scrSel: (n/a) NULL, // scrColor: (n/a) NULL, // spinData: (n/a) true, // active: can receive focus &ic[grRB] // nextCtrl: next control }, { //* 'Green Message' Radio Button - - grRB * dctRADIOBUTTON, // type: rbtS3s, // rbSubtype: standard3 false, // rbSelect: dflt sel short(ic[lfTB].ulY + 2), // ulY: upper-left Y ic[lfTB].ulX, // ulX: upper-left X 1, // lines: (n/a) 0, // cols: (n/a) NULL, // dispText: (n/a) nc.bw, // nColor: non-focus color nc.grR, // fColor: focus color tbPrint, // filter: (n/a) "Green Messages:", // label: ZERO, // labY: -16, // labX ddBoxTYPES, // exType: (n/a) 1, // scrItems: (n/a) 1, // scrSel: (n/a) NULL, // scrColor: (n/a) NULL, // spinData: (n/a) true, // active: can receive focus &ic[yeRB] // nextCtrl: next control }, { //* 'Yellow Message' Radio Button - - yeRB * dctRADIOBUTTON, // type: rbtS3s, // rbSubtype: standard3 true, // rbSelect: dflt sel short(ic[grRB].ulY + 1), // ulY: upper-left Y ic[grRB].ulX, // ulX: upper-left X 1, // lines: (n/a) 0, // cols: (n/a) NULL, // dispText: (n/a) nc.bw, // nColor: non-focus color nc.grR, // fColor: focus color tbPrint, // filter: (n/a) "Yellow Messages:", // label: ZERO, // labY: -17, // labX ddBoxTYPES, // exType: (n/a) 1, // scrItems: (n/a) 1, // scrSel: (n/a) NULL, // scrColor: (n/a) NULL, // spinData: (n/a) true, // active: can receive focus NULL // nextCtrl: end of list }, } ;

Group the Radio Buttons

We have defined two Radio Buttons, and each button selects a color attribute for our displayed message. Clearly, the message cannot be BOTH colors at the same time, so we must allow the user to select only one of the Radio Buttons at a time.

To do this, we create an Exclusive-OR grouping for the buttons. An XOR group means that exactly one member of the group may be selected at any given time. (The ’yellow’ button is initially selected.)

Copy the following into the ’MyDialog’ method just below ’dp->OpenWindow()’, and just above ’dp->WriteParagraph()’.

//* Create an Exclusive-OR Radio Button group * short XorGroup[] = { grRB, yeRB, -1 } ; dp->GroupRadiobuttons ( XorGroup ) ;

Update our message

Make one more small adjustment to our existing code:
Replace the existing message text with the following message.

Replace: const char* msg = " Hello World! \n\nPress any key to exit... " ; With: const char* msg = " Hello World! " ;

Rebuild and Run the Application

gmake ./FirstProg

Congratulations!

You now have a fully-populated dialog application, although the user doesn’t yet have access to the controls. Let’s do that next.
See Simple Interface Loop.




Simple Interface Loop

An application based on an NcDialog dialog window uses an extremely simple user interface loop. The loop simply transfers the input focus among the defined controls.

All actual keyboard (and mouse) input is handled by the ’Edit_Xxx’ method for the control object which currently has the input focus.

Note: If you’re having trouble understanding the concept of input focus, just think of it as aiming a paintball gun. Whatever the gun is aimed at, gets hit by the paintball (receives the keycode).

For our example application, we defined three (3) types of controls, so our user-interface loop must handle those three types.

Edit MethodControl ClassControl Type
 EditPushbutton DialogPushbutton dctPUSHBUTTON
 EditTextbox DialogTextbox dctTEXTBOX
 EditRadiobutton DialogRadiobutton dctRADIOBUTTON

Copy the following code into the ’MyDialog’ method just above ’nckPause();’, and then delete the ’nckPause();’ line because we don’t need it anymore.

Again, this is a big step, but each item will be carefully explained.

//* Interact with user * gString lfMsg ; // message buffer uiInfo Info ; // user interface data returned here short icIndex = ZERO ; // index of control with input focus bool done = false ; // loop control while ( ! done ) { if ( ic[icIndex].type == dctPUSHBUTTON ) { if ( !Info.viaHotkey ) icIndex = dp->EditPushbutton ( Info ) ; else Info.HotData2Primary () ; if ( Info.dataMod != false ) { if ( Info.ctrlIndex == DonePB ) done = true ; } } else if ( ic[icIndex].type == dctTEXTBOX ) { icIndex = dp->EditTextbox ( Info ) ; if ( Info.dataMod != false ) { // get contents of Textbox dp->GetTextboxText ( lfTB, lfMsg ) ; // write it to the dialog display area winPos wp( 14, 14 ) ; dp->ClearLine ( wp.ypos ) ; if ( lfMsg.gschars() > 1 ) { lfMsg.insert( " My favorite Linux flavor is: " ) ; lfMsg.append( " " ) ; dp->WriteString ( wp, lfMsg, mColor, true ) ; } } } else if ( ic[icIndex].type == dctRADIOBUTTON ) { icIndex = dp->EditRadiobutton ( Info ) ; if ( Info.dataMod != false ) { // re-draw message(s) in specified color mColor = Info.selMember == grRB ? nc.grR : bColor ; dp->WriteString ( 5, 28, msg, mColor ) ; if ( lfMsg.gschars() > 1 ) dp->WriteString ( 14, 14, lfMsg, mColor ) ; dp->RefreshWin () ; } } //* Move input focus to next/previous control.* if ( done == false && Info.viaHotkey == false ) { if ( Info.keyIn == nckSTAB ) icIndex = dp->PrevControl () ; else icIndex = dp->NextControl () ; } } // while()

REMEMBER to delete the ’nckPause()’ call !!


A Closer Look At the Loop Elements

Note that no direct input is collected from the user!
All direct contact with the user is through the Edit_Xxx methods.

  • gString lfMsg
    This is a message buffer used inside the user-interface loop.
    For more information on the gString class, please see gString Text Tool.
  • uiInfo Info ;
    Define a class (structure) which is used to pass user input information between the ’Edit_Xxx’ methods and our control loop.
  • short icIndex ;
    Define an index variable to track which control object currently has the input focus. This is an index into the array of control objects we defined above: 'InitCtrl ic[mdCONTROLS]'. The initial index (and the initial input focus) are on the ’DONE’ Pushbutton.
  • bool done = false ;
    This is our loop-control flag. We keep processing user input until this flag becomes ’true’.
  • while ( ! done )
    This is the top of our user-input loop.
  • There are four(4) sections to this loop.
    • The first section tests for a ’dctPUSHBUTTON’ control type. If it is, then call the EditPushbutton() method.

      On return, Pushbuttons have one of two states: ’true’ or ’false’. If ’true’, then user is ready to exit the dialog, else move to the next/previous control.

      Also note that this control may be selected using the ’hotkey’ defined for the control. The ’hotkey’ can be identified by the underlined character which in this case is ’D’ indicating that the hotkey is CTRL+D.

      Thus, if focus arrived at the control via ’hotkey’, then we don’t call the EditPushbutton() method because the user’s instructions are already in the ’uiInfo’ data, so we just unpack it using the 'uiInfo::HotData2Primary()' method.

    • The second section tests for a ’dctTEXTBOX’ control type. If it is, then call the EditTextbox() method.

      On return, we have some fun with the contents of the Textbox control. If the contents were changed, we display them in the main dialog window using the current message color. If no change, we do nothing.

    • The third section tests for a ’dctRADIOBUTTON’ control type. Because the Radio Buttons are an XOR group. the edit method does not return until user leaves the group.

      On return, if the active member of the group has changed, then we re-draw the messages in the new color. If no change, we do nothing.

    • The fourth section of the input loop simply moves the input focus to whatever control the user has specified.

      Note that if the focus has already changed via ’hotkey’, then we do nothing here.

  • Of course, we could add more controls and more types of controls to our dialog, so in that case, the user-interface loop would need an entry for each type of control defined.

    In a real-world application, data provided by the user would be used for more than just drawing pretty pictures, but we hope that the examples clearly describe the mechanism for expanding the power of the user-interface loop.


Rebuild and Run the Application

gmake ./FirstProg

It's Playtime!

  • You can now use the TAB and Shift+TAB keys to navigate among the dialog controls.
  • Enter text into the Textbox control.
    Press ENTER or TAB to exit the Textbox.
  • Change the message color with the Radio Button controls.
    Press ENTER or SPACE to activate a Radio Button.
  • Exit the dialog
    Navigate to the ’DONE’ Pushbutton control and press ENTER, or use the defined ’hotkey’ for the ’DONE’ button: (CTRL+D) to exit the dialog from within any of the controls.
  • Note that the Panic Button (CTRL+C) is captured, so the application will always be shut down in an orderly manner.

For a screenshot of this dialog, please see eye candy.


Congratulations!

You have successfully created your first NcDialog application!

It may be simple, but it can already do real things. How long did it take? If you are an experienced programmer, it probably took less than 30 minutes. If you are just beginning your career as an author of world-changing software, then perhaps an hour. Well done!!

Note that if you ran into problems, we have left you an Easter Egg. The source module, ‘FirstProg.cpp’ and ‘Makefile’ may be found at NcDialog/Misc/fp.tar It is our belief and our hope that you have learned more through your step-by-step construction of the application than you would have learned by simply copying the files. This is something teachers do——sorry for the trick. :-)

Many more and different examples can be found in the test applications included in the NcDialog API package.
See Application Examples. Enjoy!





NCurses Engine

This chapter covers the NCurses class definition and the NCurses Engine which forms the connection between an NcDialog-based application and the ’ncurses’ C library primitives.







Introduction to ncurses

The ’curses’ interface was originally created for BSD UNIX to allow for formatted text output. A.T.&T. created a much-enhanced version of curses for use in its versions of UNIX.

The GNU ’ncurses’ (New Curses) C-language library is ’free software’ created under Linux to avoid copyright issues with SystemV(tm) UNIX. This is the version of curses included in all major Linux distributions. The ’ncurses’ C-language library comes in two flavors:
    ’ncurses’     This is the narrow (8-bit) character interface.
    ’ncursesw’    This is the wide (32-bit) character interface.
The functionality of these two versions is nearly identical; however, the ’wide’ version is recommended for all modern applications, because it fully supports all languages and character sets for internationalization of user interfaces.

Several people have been involved in the developmet of ’ncurses’ including Pavel Curtis, Zeyd Ben-Halim, Eric Raymond and Juergen Pfeifer. However, most of the heavy lifting in recent times has been done by the inestimable Thomas E. Dickey <http://invisible-island.net/> who, as he once posted on his website, took it up as a hobby. (Some hobby!)

Many terminal-based Linux applications use the ’ncurses’ C library, either directly or through one of the toolkits developed to make ’ncurses’ programming easier. ’ncurses’ is extremely portable and terminal-independent, and is reasonably-well documented. It suffers, however, from many years of questionable extensions (code bloat) and a general seediness that is revealed in a large number of small, but annoying bugs which most developers simply work around.

The only major drawback to the ’ncurses’ library is that it is oriented toward C-language programming and all that entails: lax prototyping, lack of type-checking, ’structs’, random casts, maintenance nightmares, and the constant threat of buffer overruns. This is not the fault of ’ncurses’, but of Kernighan and Ritchie, darn their lazy and unimaginative hides. :-)

Overall, ’ncurses’ is a tremendous accomplishment that brings a GUI-like interface and a quick application-development process to the obscure world of Linux command-line utilities.




NCurses Class Overview

The NCurses Engine is based on the ’ncurses’ C-language library functions. It is written entirely in C++ and encapsulates the most vulnerable constructs of C-language programming within the ’ncurses’ library for a nearly-indestructable (albeit, single-threaded) user interface.

The NCurses Engine uses the ‘ncursesw’ (wide-character) version of the ‘ncurses’ C library exclusively. The 8-bit character library, ‘ncurses’ is not used.

NCurses is implemented as a C++ class definition with approximately sixty (60) public methods for initialization and use of the underlying ‘ncurses’ library for keyboard and mouse input and formatted text output to the terminal window.

A comprehensive array of color-attribute constants and keycode constants are also available as public data members.
See Keycode Constants.
See Color Attributes.

The NCurses-class methods follow the ’ncurses’ C library convention regarding defined return values:
   (short int) ’OK’  indicates a successful execution
   (short int) ’ERR’ indicates a general error condition
(See note below on the choice of ’short int’ over the ’int’ integral type.)

The NCurses class makes absolutely no effort to be an inclusive wrapper for the ’ncurses’ library. In the author’s view, most of the capabilities provided by ’ncurses’ are seldom, if ever used — certainly not in a simple terminal application, so there is no need to provide a high-level interface to them. Note however, that if you find a need for ’ncurses’ functionality that is not supported within the NCurses class, please send the author a note, and we’ll see what can be done.
See Technical Support.

IMPORTANT NOTE

There is a single instance of the NCurses class in each application program. Because the NCurses-class object is instantiated globally (see GlobalDef.hpp), access to the NCurses methods and public data members is through the global handle, ’nc’. Example:
              nc.WriteString ( 5, 2, "What’s up doc?", nc.bl ) ;
This call will write the message using the NCurses::WriteString() method, AND the message will be written using the color attribute defined in the public data member, NCurses::bl (blue on default background).

Notes

  1. The NCurses-class methods ARE NOT thread safe!
    The NCurses-class provides direct, or nearly direct access to the underlying ’ncurses’ C library functions. Be sure, therefore, to complete all initialization and configuration which uses NCurses methods BEFORE launching any secondary threads and BEFORE performing any Input/Output operations.
  2. Beyond the start-up and shut-down sequences described, direct use of the NCurses-class methods in applications is strongly discouraged.

    Instead, use the NcDialog API for all non-trivial applications, so that you are working in a controlled dialog window rather that writing haphazardly to the base terminal window.

    The exception would be if you are writing what appears to the user to be an application that is writing to ’stdout’ (’wcout’, ’wprintf’) BUT is actually capable of formatted, multi-color output. In that case, by all means, amaze your friends with your command-line skills! In particular, please refer to the OutputStreamScrolling method.

  3. The NCurses class, and in fact, the entire NcDialog API uses the ’short int’ integral type wherever practical. The author learned programming on an IBM360(tm), DEC PDP8(tm), PDP11(tm), S/100-bus hacks, the PET(tm), the Apple2(tm), Amiga(tm), and on and on: all in assembly language. The declaration of variables with 2, 4, 6, 12 or more extra bytes that do nothing at all is an offense to the author’s sensibilities.
    (We will admit, however, that memory-access time on certain platforms is more efficient in larger chunks.)



NCurses Public Methods

What follows is a list of all public methods of the NCurses class.
Methods are arranged in functional groups.

        NCurses Method Name            Chapter Reference    
 NCurses [constructor] see NCurses Startup-Shutdown
 ~NCurses [destructor] 
 StartNCursesEngine 
 StartColorEngine 
 ColorText_Available 
 ColorText_Initialized 
 TerminalColorSupport 
 StopNCursesEngine 
  
 ScreenDimensions see NCurses Configuration
 GetColorMap 
 SetColorMap 
 SetLocale 
 GetLocale 
 VerifyLocale 
 SetDefaultBackground 
 KeyEcho 
 GetKeyProcState 
 SetKeyProcState 
 GetKeyDelay 
 SetKeyDelay 
 SetKeycodeWidth 
  
 GetKeyInput see NCurses Keyboard Input
 UngetKeyInput 
 KeyPeek 
 GetEscapeSequence 
 FlushKeyInputStream 
  
 WriteString see NCurses Display Output
 WriteChar 
 ClearScreen 
 RefreshScreen 
 ClearLine 
 GetCursor 
 SetCursor 
 GetCursorState 
 SetCursorState 
 RestoreCursorState 
  
 EnableMouseEvents see NCurses Mouse Access
 DisableMouseEvents 
 MouseEventsEnabled 
 GetMouseEventTypes 
 SetMouseEventTypes 
 GetMouseClickInterval 
 SetMouseClickInterval 
 GetMouseEvent 
 UngetMouseEvent 
 FlushMouseEventQueue 
 GetMousePosition 
 FilterSpuriousMouseEvents 
  
 Hibernate see NCurses Utility Methods
 Wake 
 BiDiEnable 
 UserAlert 
 Get_NCurses_Version 
 Get_nclibrary_Version 
  
 WriteStream see NCurses Debugging Methods
 OutputStreamScrolling 
 DisplayColorOptions 
 DisplayDefinedColors 
 DisplayAlternateFont 
 GetTransTable1 
 GetTransTable2 
 GetTransTable3 
 Get_stdscr_Address 



NCurses Startup-Shutdown

  • NCurses ( void );
      Input  : none
    
      Returns: nothing
    

    NCurses-class constructor.

    The NCurses-class object is instantiated only once for the application. Global instantiation allows all application modules access to the methods and public data members of the class.

    NOTE: The instantiation occurs in GlobalDef.hpp and the instance 
          actually lives at the top of NCurses.cpp, and it is declared 
          as 'extern' everywhere else.
    


  • ~Ncurses(void);
      Input  : none
    
      Returns: nothing
    

    NCurses-class destructor.

    The destructor returns any local resources to the system, and then calls the underlying ’ncurses’ C-library to shut down ncurses and release control of the input/output streams.

    NOTE: The destructor is called @emph{implicitly} as the NCurses 
          object goes out of scope (as the application exits to the 
          command line). The destructor actually has nothing to do if 
          the application exits in an orderly manner. See below for a 
          description of the 'StopNCursesEngine' method.
    


  • short StartNCursesEngine ( bool autostartColorEngine = true,
                               NcColorMap* colorMap = NULL );
      Input  :
         autostartColorEngine : (optional, true by default)
            - if 'true' (AND if terminal supports color output), call the
              StartColorEngine() method before return to caller
            - if 'false', do not start the Color Engine, and only 2-color
              output will be available unless StartColorEngine() is called
              before any color output is performed.
         colorMap  : (optional, NULL* pointer by default)
            - if autostartColorEngine != false AND colorMap != NULL* , then this
              is a pointer to a fully-initialized NcColorMap object containing
              the color-pair and RGB values for the available color attributes.
    
      Returns:
         OK if successful
         ERR if unable to gain access to terminal firmware (or emulator)
             OR if provided color data do not match terminal definition
             OR if NCurses engine previously initialized
    

    Initialize the NCurses engine for formatted-text input and output.
    Must be called after instantiation of the NCurses class (which happens automagically when the application is executed) but before any other method of this class is called. See examples in test applications (see Test Applications).

    Default Settings On Startup

    • Locale: set according to terminal window’s environment
    • Cursor shape: nccvINVISIBLE
    • Keycode width: nckbEIGHT (UTF-8 encoding requires 8-bit width)
    • Key processing: nckpRAW
    • Key echo: disabled
    • Key delay: nckdFOREVER (blocking read)
    • Additional delay after ESC key detected: none
    • Escape sequence translation: enabled
    • I/O stream scrolling: disabled
    • Mouse input: disabled
    • Display colors:
      If a color-map is not specified by ’colorMap’ parameter, then the NCurses default color mapping is used, and RGB registers are not modified.

    Notes on color map initialization

    • If colorMap.rgbCount == actual number of RGB register sets supported by the terminal AND if the terminal allows modification of the RGB registers, then colorMap.rgbMap[] data is applied to the registers.
    • If colorMap.pairCount == actual number of color pairs supported by the terminal AND the terminal allows modification of the color pairs, then colorMap.pairMap[] data is applied to the terminal’s foreground/background color pairs.
    • if autostartColorEngine != false AND colorMap == NULL* , then the NCurses default color mapping will be used to initialize the Color Engine.
    • See NcColorMap class, for more information.
    • See also the descriptions of ’GetColorMap’ and ’SetColorMap’ elsewhere in this chapter.


  • short StartColorEngine ( NcColorMap* colorMap = NULL );
      Input  :
         colorMap  : (optional, NULL* pointer by default)
            - if specified, then this is a pointer to a fully-initialized
              NcColorMap object containing the RGB register set values and/or
              the color-pair values.
            - to set RGB registers: set colorMap.rgbCount == number of register
              sets supported by the terminal (see 'TerminalColorSupport' method)
            - to set Color Pairs: set colorMap.pairCount == number of color
              pairs supported by the terminal
            - if not specified, then the NCurses default color mapping will be
              used to initialize the Color Engine.
    
      Returns:
         OK if successful
         ERR if unable to gain access to terminal firmware (or emulator)
             OR if provided color data do not match terminal definition
    

    Please see NcColorMap class for additional information on color map initialization.

    Initialize the NCurses color engine for color text output.
    This method is called automatically as part of StartNCursesEngine() UNLESS the application specifically overrides the default start-up sequence: (autostartColorEngine parameter == false) to start the NCurses Engine in monochrome mode.
    If multi-color output is desired, but automatic Color Engine startup was disabled in the call to StartNCursesEngine(), then call this method immediately after a successful call to StartNCursesEngine() OR at the latest, before any color-text output is performed.



  • void StopNCursesEngine ( void );
      Input  : none
    
      Returns: nothing
    

    Shut down the NCurses Engine and release all associated resources.
    (To be called just before driving application exits.)

    Once the NCurses Engine has been shut down, the underlying ’ncurses’ C-library has returned all of its resources to the system and the terminal’s ’stdin’ and ’stdout’ character streams are once again available.



  • bool ColorText_Available ( void );
      Input  : none
    
      Returns:
         'true' if the terminal supports multi-color text output
         'false' if the terminal does not support multi-color text output
                 OR if the NCurses Engine has not yet been started 
                    i.e. system information is not yet available
    

    Determine whether the terminal or terminal emulator is capable of displaying color text. This will almost always be true on a computer, but may return false if running on a monochrome dumb terminal.



  • bool ColorText_Initialized ( void );
      Input  : none
    
      Returns:
         'true' if Color Engine has been successfully initialized
         'false' otherwise
    

    Determine whether the Color Engine has been successfully initialized.

    If the terminal supports color output, then the NCurses Color Engine is started automatically by the call to ’StartNCursesEngine()’ unless the call explicity excludes color initialization. See also the description of ’StartColorEngine()’ above.



  • bool TerminalColorSupport ( termColorInfo& cinfo );
      Input  :
         cinfo : (by reference) receives terminal color information
    
      Returns:
         'true' if the terminal supports multi-color text output
                parameters will be initialized
         'false' if the terminal does not support multi-color text output
                 OR if Color Engine has not yet been started i.e. info is
                    not yet available
                 (term_colors, rgb_regs and fgbg_pairs set to ZERO)
                 (mod_pairs and mod_rgb set to 'false')
    

    Report terminal (or terminal emulator) color output capabilities.
    Data are returned in the specified termColorInfo-class object.

    class termColorInfo { public: // number of colors supported by the terminal short term_colors ; // number of RGB register sets supported (16 max) short rgb_regs ; // number of foreground/background color pairs supported short fgbg_pairs ; // 'true' if terminal supports color-pair modification bool mod_pairs ; // 'true' if terminal supports RGB register modification bool mod_rgb ; } ;





NCurses Configuration

  • void ScreenDimensions ( short& scrLines, short& scrColumns );
      Input  :
         scrLines (by reference) receives screen line-count
         scrColumns (by reference) receives screen column-count
    
      Returns: nothing
    

    Returns the terminal window dimensions in lines and columns.

    All applications need some minimum amount of display area in which to operate, and many applications will expand to fill the available space. Therefore, it is important to check the dimensions of the terminal window as the application starts to be sure there is enough room to play.

    In addition, the user will sometimes re-size the terminal window while the application is running. If the size of the terminal window could affect the performance of your application, then you may want to check the dimensions regularly.



  • short GetColorMap ( NcColorMap& cMap );
      Input  : 
         cmapPtr: (by reference, initial values ignored)
                  NcColorMap-class object to receive the color-pair
                  and RGB register data
    
      Returns: 
         OK if successful,
         ERR if Color Engine not started
    

    Get a copy of the terminal’s color-pair and RGB-register settings.
    Each element of a color-pair is indicated as a member of enum NcBaseColors. RGB register value range: minRGBvalue to maxRGBvalue (virtual values).

    For a full explanation of color mapping please see Color Attributes.



  • short SetColorMap ( NcColorMap* cmapPtr,
                        bool setPairs, bool setRGB );
      Input  :
         cmapPtr : pointer to an initialized NcColorMap-class object
                   containing the new color-pair AND/OR RGB register data
         setPairs: if 'true', use data provided in cmapPtr.pairMap[] array
                   to modify ALL color pairs supported by the terminal
                   - Each value is a member of enum NcBaseColors or
                     enum NcExtendedColors.
                   - Each terminal implementation has a 'default'
                     foreground and background color, usually
                     white-on-black OR black-on-white. Use of defaults
                     may be specified for either or both fgnd/bkgnd by
                     entering ncbcDEFAULT in the appropriate field(s).
         setRGB  : if 'true', use data provided in cmapPtr.rgbMap[] array
                   to modify ALL RGB registers supported by the terminal
                   - RGB register value range: minRGBvalue to maxRGBvalue.
    
      Returns: OK if successful, else ERR
    

    Modify the terminal’s foreground/background color pairs AND/OR modify the RGB (Red-Green-Blue) register values (color hue).

    The safe way to modify the color data is to first get a copy of the existing color data and then modify it as needed.

    NcColorMap colorMap; nc.GetColorMap ( colorMap ); [ perform desired modifications to the data ] nc.SetColorMap ( colorMap, true, true );

    Please see Dialog2 App, Test 4, ’Adjusting the Text-color Map’ for a demonstration of color mapping, including saving the formatted data to a file and initializing the color data from the file. .



  • short SetColorMap ( short pairIndex,
                        const NcColorPair& pairData );
      Input  :
         pairIndex: index of color pair to be modified
         pairData : new foreground and background color numbers
    
      Returns: OK if successful, else ERR
    

    Modify a single foreground/background color-pair.
    (See above for more information.)



  • short SetColorMap ( short rgbIndex,
                        const NcRgbSet& rgbData );
      Input  :
         rgbIndex : index of RGB register set to be modified
         rgbData  : new red/green/blue register-set values
    
      Returns: OK if successful, else ERR
    

    Modify a single RGB register set.
    (See above for more information.)



  • const char* GetLocale ( void );
      Input  : none
    
      Returns: pointer to locale string
    

    Returns a pointer to a const string containing the name of the currently-active locale setting.

    Please see Multi-language Support for a description of how the application’s locale affects text processing and the user interface.



  • short SetLocale ( const char* newLocaleName );
      Input  :
         newLocaleName : string containing name of new locale
    
      Returns: OK if successful, else ERR
    

    Specify a new locale setting for multi-byte character interpretation.

    Note that when the NCurses class is instantiated, the locale used is the one specified by the terminal window’s environment variables. If the terminal window’s locale is not a UTF-8 locale, then this method must be called to specify a UTF-8-compliant locale before any I/O takes place.

    USE CARE! If the locale is not UTF-8 compliant, then NCurses methods will not be able to handle characters beyond simple ASCII (7-bit) characters.

    NOTE: For a complete list of locales supported by your terminal,
    use the ’locale -a’ command.



  • short VerifyLocale ( const char* lcName=NULL );
      Input  :
         lcName : (optional, NULL by default)
                  NULL indicates that current local setting should be tested
                  If non-NULL, test the locale name provided
    
      Returns:
         OK if specified locale is known to support UTF-8 encoding
         ERR otherwise.
    

    Attempts to verify whether the local name provided specifies a locale that supports UTF-8 encoding.

    We perform a very simple test: If the locale name contains one of the following substrings ’UTF-8’ or ’utf8’ (case insensitive) then UTF-8 support is assumed. This assumption is somewhat dangerous because it relies on the folks at GNU.org to use consistent naming conventions, but we have (provisional) faith.



  • void SetDefaultBackground ( NcBaseColors bkGround,
                                NcBaseColors pzfgnd=ncbcDEFAULT );
      Input  :
         bkGround : background color for the basic color pairs directly
                    supported by the ncurses library (usually pairs 0-7)
         pzfgnd   : (optional, ncbcDEFAULT by default)
                    foreground text color for color pair zero (ncbcBK)
    
      Returns: nothing
    

    Establish a default background color to be used with all the basic text (foreground) colors.

    Note that the results of this operation will likely be disappointing, especially if a black background (ncbcBK) is specified.
    See also: ’SetColorMap()’. Please see Dialog2 App, Test 4, ’Adjusting the Text-color Map’ for a demonstration of color mapping.



  • short KeyEcho ( bool enable );
      Input  :
         enable : if 'true', enable key input echo
                  if 'false', disable key input echo
    
      Returns: OK if successful, else ERR
    

    Enable or disable automatic echo of key input.

    IMPORTANT NOTE: Use of this method is not recommended.
    To ’echo’ key input means that for every keystroke you enter, the system immediately prints it to the display. While this is useful in ordinary command-line (’stdio’) user interaction, it is inappropriate for applications that used formatted output.
    Input echo is disabled by default inside the NCurses Engine, and should stay that way.



  • ncKeyProc GetKeyProcState ( void );
      Input  : none
    
      Returns: member of ncKeyProc
    

    Returns the current level of key-input processing done by the kernel, the ncurses library, and the NCurses class before data are passed to the application.



  • short SetKeyProcState ( ncKeyProc procState );
      Input  :
         procState : member of ncKeyProc
    
      Returns: OK if successful, else ERR
    

    Set the level of key-input processing done by the kernel, the ncurses library, and the NCurses class before data are passed to the application code.

    The default value set during startup is nckpRAW because key input will be fully encapsulated in the NCurses class making the maximum number of keys available to the driving application. Have a good reason before modifying this parameter.

    Applications should always request key data through the ’GetKeyInput’ method, and NEVER directly from the system or through C/C++ functions.



  • short GetKeyDelay ( void );
      Input  : none
    
      Returns:
         delay in milliseconds
           or
         nckdFOREVER
           or
         nckdNODELAY
    

    Returns the current key-input delay in milliseconds.



  • short SetKeyDelay ( short delay );
      Input  :
         delay : delay in milliseconds (1 to 1000)
                   or
                 nckdFOREVER == wait indefinitely for input (blocking read)
                   or
                 nckdNODELAY == returns immediately if no key data available
    
      Returns: OK
    

    Set the number of milliseconds to delay while waiting for key input.

    If no key data arrives before the timeout, the ’GetKeyInput’ method will return ERR and the target variable will be undefined.

    The default value on startup is nckdFOREVER (blocking read).
    Please see NCurses Startup-Shutdown for more information on the startup defaults.



  • short SetKeycodeWidth ( ncKeyBits codeWidth );
      Input  :
         codeWidth : member of ncKeyBits
    
      Returns: OK if successful, else ERR
    

    Set the number of significant bits of key input from keyboard controller.

    IMPORTANT NOTE: Use of this method is not recommended.
    The default value set during startup is nckbEIGHT (8-bit) because UTF-8 encoding requires 8-bit width, so don’t modify default without a good reason.




NCurses Keyboard Input

  • wkeyType GetKeyInput ( wkeyCode& wKey, bool rawData=false );
      Input  :
         wKey   : wkeyCode-class object (by reference) to hold the key
                  information (initial values ignored)
         rawData: (optional, false by default)
                  if false, capture and translate escape sequences
                  if true, no local processing by the NCurses class,
                  BUT the ncurses library will still do its translations
                  UNLESS there has been a prior call to
                  SetKeyProcState(nckpNO_TRANSLATION);
    
      Returns:
         member of enum wkeyType
         wktPRINT  if key is a valid, printing wchar_t character code
         wktFUNKEY if key is a translated function key (cursor key, Fnn, etc)
                   OR if key is an ASCII (non-printing) control code < 0x0020.
         wktMOUSE  if a mouse event in the input stream has been detected,
                   then the mouse event will be returned in wKey.mevent.
                   (wKey.key will be set to ZERO and should be ignored.)
         wktEXTEND This is an extension to the key input captured by the
                   ncurses library primitives. It provides additional
                   keycodes to the application: Alt+'a' through Alt+'z',
                   Alt+Shift+'a' through Alt+Shift+'z' and Alt+Ctrl+'a'
                   through Alt+Ctrl+'z'. (See notes in NCursesKeyDef.hpp.)
         wktESCSEQ if an untranslated escape sequence was captured.
                   The keycode (wKey.key) will be set to ZERO.
                   This should only happen if application has turned
                   off key-input translation (or in the rare case that
                   neither the ncurses library nor the NCurses class can
                   translate the sequence).
                   The captured escape sequence is held in a static
                   buffer and can be retrieved via GetEscapeSequence()
                   before it is overwritten by the next untranslated
                   sequence.
         wktERR    early return if no key data available.
                    This method performs a non-blocking read if 
                    'SetKeyDelay' method not set to nckdFOREVER,
                    and will retur wktERR if key data not available.
                   OR 
                    If system call returned an error (unlikely).
                   The keycode (wKey.key) will be set to ZERO.
    
         IT IS STRONGLY RECOMMENDED THAT THE RETURN VALUE ALWAYS BE CHECKED!
    

    Get a keycode and keytype from the ncursesw input stream. This includes all supported international character codes as well as captured-and-translated escape sequences representing function keys, cursor keys and other special-purpose key combinations.

    If mouse input has been enabled, mouse events will also be returned in caller’s wkeyCode-class object. For additional information, please see MouseEvent class.

    To use this method properly, the key processing state must be set to nckpUNBUFFERED or nckpRAW (see the ’SetKeyProcState’ method).
    In nckpCOOKED mode, system does not return data until the ENTER (RET) key is pressed, We short-circuit cooked-mode input gathering by a direct call to the ncurses-library primitive. Note also that mouse events cannot be detected while in cooked-mode. No developer in his/her/its right mind would use cooked-mode input anyway.



  • wkeyType GetKeyInput ( short& sChar, bool rawData=false );
      Input  :
         sChar  : returned key value (by reference, initial value ignored)
         rawData: (optional, false by default)
                  if false, capture and translate escape sequences
                  if true, no local processing by the NCurses class
    
      Returns:
         member of enum wkeyType
         See GetKeyInput(wkeyCode&), above for details.
    

    Get a 16-bit key from the input stream.

    IMPORTANT NOTE: Use of this method is not recommended.
    Internally, the NCurses family of classes uses 32-bit input and output exclusively. However this 16-bit method is available if it is known that ’wide’ characters and keycodes will never be input by the user.

    Note that mouse input requires the 32-bit input stream. If a mouse event is captured through the 16-bit method, it will be discarded and reported as wktERR.



  • short GetKeyInput ( void );
      Input  : none
    
      Returns: OK
    

    Wait for a keystroke i.e. PAUSE. The key input data are discarded.

    It is recommended that you use the ’nckPause();’ macro to initiate a wait-for-keypress, rather than calling this method directly.



  • short UngetKeyInput ( wkeyCode& wKey );
      Input  :
         wKey : (by reference)
                contains keycode and key type of input to be 
                returned to the input queue
    
      Returns:
         OK if successful
         ERR if invalid key data (e.g. part of an escape sequence)
             or if un-get queue is full
    

    Return the wchar_t keycode and keytype, or a mouse event to the input queue.

    • The ncurses C-library function, ’unget_wch’ is very limited, and frankly, too buggy to be useful.
      For this reason, we have made the design decision to implement a more rubust push-back queue within the NCurses class.
    • Note that no more than KEYPUSH_MAX keycodes may be pushed back into the queue without an intervening call to the ’GetKeyInput’ method.
    • Note that only valid keycodes and mouse events can be pushed back into the queue. Escape sequences MAY NOT be pushed back into the queue.

    The primary use for this method is to implement keystroke macros to be executed within your application. For instance, if a user often enters a particular sequence of keystrokes, then this could be encapsulated and assigned a shortcut key, with your record_macro method and then executed with your play_macro method.



  • wkeyType KeyPeek ( wkeyCode& wKey );
      Input  :
         wKey : wkeyCode-class object (by reference) to
                hold the key information (initial values ignored)
    
      Returns:
         member of enum wkeyType
            if key data waiting:
               wKey.type == wktPRINT, wktFUNKEY or wktMOUSE
               wKey.key  == key code
            if no key data waiting (or untranslated escape sequence):
               wKey.type == wktERR
               wKey.key  == ZERO and should be ignored
    

    If there is key data waiting in the key input buffer, return a copy of it. Does not remove key data from input stream.



  • const wchar_t* GetEscapeSequence ( short& charCount );
      Input  :
         charCount : (by reference, initial value ignored)
                     receives the number of items in the escape 
                     sequence array
    
      Returns:
         const pointer to static buffer containing untranslated 
         escape sequence
           OR
         returns a pointer to an empty string if no untranslated
         sequence has been captured and 'charCount' set to ZERO.
    

    If an escape sequence has not been translated into a keycode within a call to the ’GetKeyInput’ method — either because the application has disabled translation, or because the sequence is unknown, then — ’GetKeyInput’ returns wktESCSEQ and the sequence is stored in a static buffer for potential retrieval. This method returns a pointer to the most recently captured sequence.

    If an untranslated sequence is generated by a key combination which you often use, then please contact the author with details so the NcDialog API can be updated. Please see Technical Support.



  • short FlushKeyInputStream ( void );
      Input  : none
    
      Returns: OK
    

    Flush (discard) any key input data currently in the key input stream. If mouse input has been enabled, then flush the mouse-event queue also.



Please see NCurses Configuration for information on configuring the key input stream.




NCurses Display Output

The following methods write text and color-attribute data directly to the main terminal window. As with all NCurses-class methods, access is through the global handle: 'nc'.
Example: nc.WriteString ( 4, 1, "Hello World!", nc.bl );

Note that if NcWindow-class or NcDialog-class objects also exist in the terminal window, then those objects will need to be refreshed AFTER you have finished writing data to the terminal window.

IMPORTANT NOTE:
NCurses-class output methods are not thread safe; thread safety is implemented at a higher level (see thread-safe operation).
When using NCurses-class methods, be very sure that only one execution thread in your application is writing to the display.



  • winPos WriteString ( const winPos& startYX, const char* uStr,
                         attr_t cAttr, bool rtl=false );
  • winPos WriteString ( const winPos& startYX, const wchar_t* wStr,
                         attr_t cAttr, bool rtl=false );
  • winPos WriteString ( short startY, short startX,
                         const wchar_t* wStr,
                         attr_t cAttr, bool rtl=false );
  • winPos WriteString ( short startY, short startX,
                         const char* uStr,
                         attr_t cAttr, bool rtl=false );
      Input  :
         startYX: start position in Y/X (row/column)
               OR
         startY : start position in Y (row)
         startX : start position in X (column)
    
         -- FOR UTF-8-ENCODED CHARACTERS (INCLUDING ASCII)
           uStr : pointer to null-terminated UTF-8-encoded string
                  note: gsMAXBYTES is the maximum number of bytes in
                        the string (including the NULLCHAR byte)
         -- FOR wchar_t 'WIDE' CHARACTERS
           wStr : pointer to null-terminated wchar_t ('wide') string
                  note: gsMAXCHARS is the maximum number of characters
                        in the string (including the NULLCHAR)
    
         cAttr  : color attribute - one of the NCurses defined colors 
                  with any additional attributes bits
         rtl    : (optional, 'false' by default) for RTL written languages
                  if 'true', cursor moves from right-to-left
    
      Returns:
         returns final position of cursor
           specifies the row/column following the last character written,
           or if the target line has been filled, the last column 
           of the target line
    

    Write a text string with color attribute at the specified position in the stdscr window i.e. the main terminal window.

    The display IS REFRESHED to make the output visible.


    NOTES:

    • If specified starting position is invalid (beyond the window boundaries), then cursor will be set to the LTR or RTL window origin before data are written.
    • Output will be truncated at the edge of the window.
    • ASCII control characters, 0x01 through 0x1F are ignored.


  • winPos WriteChar ( const winPos& startYX,
                       const char* uChar, attr_t cAttr,
                       bool refresh=false, bool rtl=false );
  • winPos WriteChar ( const winPos& startYX,
                       wchar_t wChar, attr_t cAttr,
                       bool refresh=false, bool rtl=false );
  • winPos WriteChar ( short startY, short startX,
                       const char* uChar, attr_t cAttr,
                       bool refresh=false, bool rtl=false );
  • winPos WriteChar ( short startY, short startX,
                       wchar_t wChar, attr_t cAttr,
                       bool refresh=false, bool rtl=false );
      Input  :
         startYX: start position in Y/X (row/column)
               OR
         startY : start position in Y (row)
         startX : start position in X (column)
    
         -- FOR UTF-8-ENCODED CHARACTERS (INCLUDING ASCII)
           uChar: pointer to character to display
                  (single-byte or multi-byte character)
    
         -- FOR wchar_t 'WIDE' CHARACTERS
    
      Returns:
         returns final position of cursor
           specifies the row/column following the last character written,
           or if the target line has been filled, the last column 
           of the target line
    

    NOTES:

    • If specified starting position is invalid (beyond the window boundaries), then cursor will be set to the LTR or RTL window origin before data are written.
    • Output will be truncated at the edge of the window.
    • ASCII control characters, 0x01 through 0x1F are not written.
    • Be aware! A UTF-8 character can never be assumed to be a single byte.
      This is why the ’uChar’ parameter is a ’const char*’.
    • Be aware! For some languages, a wchar_t character may require additional zero-width meta-characters in order to be displayed properly. If so, use the WriteString method instead.


  • void ClearScreen ( void );
      Input  : none
    
      Returns: nothing
    

    Erase the entire contents of the terminal window using the default background color, and then refresh the display to make the change visible.



  • void RefreshScreen ( void );
      Input  : none
    
      Returns: nothing
    

    Refresh the contents of the terminal window, making any previous changes visible.



  • short ClearLine ( short ypos, attr_t cAttr = ZERO );
      Input  :
         ypos : line number (zero-based)
         cAttr: (optional, default==terminal background color: nc.bw)
                if specified, set the BACKGROUND color attribute
    
      Returns:
         OK  if successful
         ERR if invalid line index
    

    Clear the specified line of the terminal window. Sets all characters of specified line to SPACE character.

    Terminal window is refreshed.

    Examples: If 'cAttr' is specified, it should indicate
              the BACKGROUND color. Because the character written is 
              the SPACE character, there is no visible foreground.
    
       nc.ClearLine ( 4 );                  // clear using default background
       nc.ClearLine ( 4, nc.bl | ncrATTR ); // clear using blue background
       nc.ClearLine ( 4, nc.blR );          // clear using blue background
       nc.ClearLine ( 4, nc.blcy );         // clear using cyan background
    
       // Clear entire terminal window to red background
       const short ROWS = 25 ;
       for ( short i = ZERO ; i < ROWS ; i++ )
          nc.ClearLine ( i, nc.reR ) ;
    


  • winPos GetCursor ( void );
      Input  : none
    
      Returns:
         current cursor position is returned in a winPos-class object
    

    Get the current position of the terminal window’s cursor (insertion point).

    Example: winPos wp = nc.GetCursor ();

    USE OF THIS METHOD IS NOT RECOMMENDED:
    The cursor is not guaranteed to remain at its current position. Screen refresh operations, or other functionality may move the cursor at any time.



  • short SetCursor ( short ypos, short xpos );
  • short SetCursor ( winPos yxpos );
      Input  :
         ypos : Y offset from upper-left corner (zero-based)
         xpos : X offset from upper-left corner (zero-based)
             OR
         yxpos: Y/X offset from upper-left corner (zero-based)
    
      Returns:
         OK  if successful
         ERR if parameter(s) out of range
    

    Set the terminal window’s cursor position (insertion point).

    USE OF THIS METHOD IS NOT RECOMMENDED:
    The cursor is not guaranteed to remain where it is placed. Screen refresh operations, or other functionality may move the cursor at any time.



  • ncCurVis GetCursorState ( void );
      Input  : none
    
      Returns:
         current cursor state (member of enum ncCurVis)
    

    Returns the current visibility state of the cursor.

    The cursor is set as invisible during startup, and should usually remain invisible at all times to avoid ugliness during re-drawing of the window contents.

    Internally, the NcDialog API makes the cursor visible ONLY within the ’EditTextbox’ method, so the user can see the text-insertion point.



  • short SetCursorState ( ncCurVis state );
      Input  :
         state : member of enum ncCurVis
    
      Returns: OK
    

    Set the visibility state of the cursor.
    Saves previous state for later call to RestoreCursorState().



  • short RestoreCursorState ( void );
      Input  : none
    
      Returns: OK
    

    Restore the previous visibility state of the cursor.
    See ’SetCursorState’ method, above.




NCurses Mouse Access

The NCurses-class mouse implementation is simply a primitive
interface to the underlying ncursesw C-language library mouse
interface. For the application layer mouse interface, please
see the NcDialog API mouse interface.
                See Mouse Configuration.

Introduction to the Text-based Mouse Interface

  • Please note that the xterm (or Wayland) mouse driver and the ncurses(w) C-language library mouse interface are, as distributed, completely useless to console applications.
  • Because the NCurses-class mouse interface provides direct access to the xterm/ncurses(w) mouse interface, we must admit that the NCurses-class mouse interface is nearly useless on its own.
  • The methods described in this chapter form the basis of the much more sophisticated NcDialog mouse interface:
    (see Mouse Configuration).
  • The mouse is a shared resource:
    • Events located beyond the writable area of the terminal window belong to someone else and are therefore not available to us.
    • Some mouse events within the writable area of the terminal window are captured by the GUI desktop, and are therefore not available to us. Examples: Button 3 click is the terminal’s context menu, and by default, Button 2 click is masked by the ’paste selection’ shorcut.
  • Timing artifacts:
    • While mouse events in a GUI application are handled in a sophisticated way (see the GTK+ mouse interface), mouse events in an ncurses(w) text-based environment are not handled very well at the xterm level. This puts most error-recovery beyond the reach of console applications unless they circumvent the majority of the ncurses(w) library mouse interface altogether.
    • Mouse events are presented in a LIFO (last-in-first-out) queue. This means that events which are older than the one you just extracted from the queue are probably stale and meaningless.
    • The scan interval for mouse events in a terminal window is a fixed period, which unfortunately means that the actual event may occur partly during one interval, and partly during the following interval.
    • These timing issues lead to all sorts of partial event captures, misinterpreted events, un-requested events and loss of valid events. (We hates meeces to pieces!)
    • Filtering of spurious events is done locally to prevent reporting of unexpected events related to timing artifacts, but the occasional loss of valid mouse activity is unavoidable at this level. See the ’FilterSpuriousMouseEvents’ method for more information.
  • Mouse-cursor position:
    Mouse movements cannot be directly determined through the ncurses(w) C-language library interface. The Y/X coordinates which indicate mouse position are available ONLY in conjunction with a button event. While we hope for an enhancement to the ncurses(w) library which will support independent position reporting, it’s not likely to happen any time soon.
  • Mouse hardware:
    Different platforms and different mouse manufactures present a wide variety of mouse input; however, the most important features are the number of mouse buttons implemented and whether the mouse includes a scroll wheel. Certain joysticks and other game input devices also use the mouse interface in innovative ways. Touchpads, which are a kind of mouse hardware, support Y/X/Z coordinates, but the ncurses(w) library does not currently support the ’Z’ axis (vertical) coordinate or multi-point touch. Clearly, the underlying ncurses(w) library can only hope to support a common subset of all these possible options, so developers of text-based games are basically out of luck.
  • Scroll-Wheel events:
    • xterm supports ScrollWheels (and button2-TrackPoint(tm) scroll emulation, although it may be disabled by default).
    • The ncurses(w) library, however, has no way to reliably report these events across all systems, so expect the unexpected.
      (See the event-mask definition, REPORT_SCROLL_WHEEL, below.)
    • IMPORTANT NOTE: When mouse events are disabled in the ncurses(w) C-language library, then the xterm mouse driver may convert ScrollWheel events to a series of UpArrow or DownArrow keys (usually groups of 3). This is a standard feature of terminals. However, when the ncurses(w) C-language library’s mouse interface is enabled, then the terminal’s automagic conversions are blocked, and we receive the actual mouse events.

Please see the test application, Dialog4, Test03 for an example of the NCurses-class mouse interface.

Please see the test application, Dialog4, Test04 for an example of the NcDialog-class mouse interface.

In general, using the mouse for a text-based application is unnecessary, and actually makes the user interface more difficult to use. This is especially true at the level of the NCurses (terminal window) abstraction layer. For this reason, please consider the following method descriptions as reference information only, and not as an invitation to use them directly. However, if you must have mouse input for your application, use the NcDialog mouse interface instead: see Mouse Configuration, which transparently converts most mouse events into the equivalent keystroke data.




NCurses Mouse Methods

  • short EnableMouseEvents ( mmask_t eventTypes );
      Input  :
         eventTypes : bit mask of event types to be enabled
                      (at least one event-type bit must be set)
                      Bit definitions are the BUTTONxxxx group of
                      defines in ncurses.h
      Returns:
         OK  if mouse enabled AND all bits of the event-type mask
             have been set successfully
         ERR if a) mouse not enabled OR
                b) actual event-type mask differs from that specified
                c) eventTypes == ZERO
    

    Allow mouse events to be reported, either indirectly through the ’GetKeyInput’ method, or directly through the ’GetMouseEvent’ method.

    See the list of mouse event bitmask values in the SetMouseEventTypes method, below.



  • short DisableMouseEvents ( mmask_t* oldeventTypes=NULL );
      Input  :
         oldeventTypes : (optional, NULL pointer by default)
                         if not a NULL pointer, then target
                         receives previous event-type bit mask
    
      Returns:
         OK  if mouse-event reporting disabled
             (mouse driver MAY BE disabled also - system dependent)
         ERR if mouse-event reporting could not be disabled
             (this could be due to a timing issue, so try again)
    

    Disable reporting of mouse events.

    The connection with the mouse interface will be disabled and no further mouse events will be placed in the input queue.

    Note that any mouse events that have already arrived in the queue will still be available, so it is good practice to flush the input queue after disabling the mouse interface. See the ’FlushKeyInputStream’ method.



  • bool MouseEventsEnabled ( void );
      Input  : none
    
      Returns:
         'true' if mouse events can be detected and reported
         else 'false'
    

    Reports whether mouse input is currently enabled.
    (See ’EnableMouseEvents’ method, above.)



  • short GetMouseEventTypes ( mmask_t& eventTypes );
      Input  :
         eventTypes: (by reference, initial value ignored)
                     receives the mouse-event-type mask
    
      Returns:
         OK  if successtul
         ERR if mouse-event input disabled
    

    Reports the type(s) of mouse events which will be reported.
    This is the current mouse-event-type bitmask.



  • short SetMouseEventTypes ( mmask_t eventTypes );
      Input  :
         eventTypes: new mouse-event-type mask
    
      Returns:
         OK  if mouse enabled AND all bits of the event-type mask
             have been set successfully
         ERR if mouse not enabled, OR 
             if actual event-type mask set differs from that specified, OR
             if eventTypes == ZERO (i.e. invalid mask)
    

    Specify the type(s) of mouse events which will be reported.
    Bit definitions for the event mask are the BUTTONxxxx group of defines in ncurses.h. As of ’ncursesw’ library version 5.9 (mouse version 1), these are as follows. Note however, that not all events will be reported in the same way by all system/hardware combinations.

    BUTTON1_RELEASED BUTTON2_RELEASED BUTTON1_PRESSED BUTTON2_PRESSED BUTTON1_CLICKED BUTTON2_CLICKED BUTTON1_DOUBLE_CLICKED BUTTON2_DOUBLE_CLICKED BUTTON1_TRIPLE_CLICKED BUTTON2_TRIPLE_CLICKED BUTTON1_RESERVED_EVENT BUTTON2_RESERVED_EVENT BUTTON3_RELEASED BUTTON4_RELEASED BUTTON3_PRESSED BUTTON4_PRESSED (also ScrollWheel-Down) BUTTON3_CLICKED BUTTON4_CLICKED BUTTON3_DOUBLE_CLICKED BUTTON4_DOUBLE_CLICKED BUTTON3_TRIPLE_CLICKED BUTTON4_TRIPLE_CLICKED BUTTON3_RESERVED_EVENT BUTTON4_RESERVED_EVENT BUTTON_CTRL (CTRL key down) BUTTON_SHIFT (SHIFT key down) BUTTON_ALT (ALT key down) REPORT_MOUSE_POSITION (also ScrollWheel-Up)

    Note that we define an additional event-type mask item, REPORT_SCROLL_WHEEL, in NCurses.hpp. However, this definition has been tested only for the common mouse type with two-buttons plus clickable Scroll-Wheel. Note that even with this limited test, the results are disappointing. This is because the ’ncursesw’ C library defines two seldom-used bits to indicate ScrollWheel activity: BUTTON4_PRESSED==ScrollDown and REPORT_MOUSE_POSITION==ScrollUp.
    While these definitions are helpful in supporting ScrollWheels, the default scan interval is too long for capturing a sequence of ScrollWheel events. (See the SetMouseClickInterval method, below.)

    Note that the BUTTON_CTRL, BUTTON_SHIFT and BUTTON_ALT flags are for reporting only, and will be reported regardless of whether you specify them in the bitmask.



  • short GetMouseClickInterval ( short& max4Click );
      Input  :
         max4Click : (by reference, initial value ignored)
                     receives current interval
    
      Returns:
         OK  if successful
         ERR if mouse-event input disabled
    

    Get the current maximum mouse-click interval in thousandths of a second.



  • short SetMouseClickInterval ( short max4Click,
                                  short* oldMax=NULL );
      Input  :
         max4Click : interval in thousandths (0.001) of a second
                     specify an interval OR a member of enum ncmInterval
         oldMax    : (optional, NULL pointer by default)
                     pointer to variable to receive previous interval value
    
      Returns:
         OK  if successful
         ERR if value out-of-range OR
             if mouse-event input disabled
    

    Specify the maximum interval for collecting a series of mouse-button-press and mouse-button-release events which will be interpreted as a ’click’ event.

    This interval is set to ncmiDFLT (166ms) by default, but can be adjusted for the dexterity and caffination level of the individual user.

    Examples:

    • Scanning for a ’single-click’ event:
      One ’press’ event followed by one ’release’ event must be received within the specified interval.
    • Scanning for a ’double-click’ event:
      The event series ’press’, ’release’, press’, ’release’ must be received within the specified interval.
    • Scanning for a ’triple-click’ event:
      The event series ’press’, ’release’, press’, ’release’, ’press’, ’release’ must be received within the specified interval.


  • short GetMouseEvent ( MouseEvent& mevent );
      Input  :
         mevent : (by reference, initial value ignored)
                  receives the mouse-event data
    
      Returns:
         OK  if mouse event extracted successfully
         ERR if no mouse event in the queue OR
             if mouse-event input disabled
    

    Extract the newest mouse event from the event queue.

    PLEASE NOTE: The low-level ’ncursesw’ C-library functions that handle mouse events are not reliable; therefore IT IS STRONGLY RECOMMENDED that all mouse-event storage and retrieval be done through the ’GetKeyInput’ and ’UngetKeyInput’ methods, and that the ’GetMouseEvent’ and ’UngetMouseEvent’ methods should not be called directly.



  • short UngetMouseEvent ( MouseEvent& mevent );
      Input  :
         mevent : (by reference) contains the mouse-event data to be 
                  pushed back into the event queue.
    
      Returns:
         OK  if mouse event successfully re-queued
         ERR if event queue is full OR 
             if mouse-event input disabled
    

    Push a previously-extracted mouse event back into the input queue.

    PLEASE NOTE: The low-level ’ncursesw’ C-library functions that handle mouse events are not reliable; therefore IT IS STRONGLY RECOMMENDED that all mouse-event storage and retrieval be done through the ’GetKeyInput’ and ’UngetKeyInput’ methods, and that the ’GetMouseEvent’ and ’UngetMouseEvent’ methods should not be called directly.



  • short FlushMouseEventQueue ( void );
      Input  : none
    
      Returns:
         OK if successful, or
         ERR if mouse-event input disabled
    

    Remove any mouse events waiting in the mouse-event queue.

    The ’GetMouseEvent’ method returns events in LIFO (last-in-first-out) order. If you have received the event you’re looking for and don’t want any more events, OR if your mouse has become tempramental and is sending undesired or unexpected events, then this method can be used to flush the mouse-event queue.



  • short GetMousePosition ( MouseEvent& mpos );
      Input  :
         mevent : (by reference, initial value ignored)
                  receives the mouse-event data
    
      Returns:
         OK if current mouse position determined
         ERR if unable to determine mouse position, or
             if mouse-event input disabled
             
    

    Report the current mouse position in the ’sypos’ and ’sxpos’ data members of the provided MouseEvent object.

    NOTE: At present, there is no method provided by the ncurses C-language library for obtaining the mouse-pointer position unless it is returned as part of a button event. Therefore, this method will always return ERR.



  • short FilterSpuriousMouseEvents ( bool filter );
      Input  :
         filter : 'true' enables filtering
                  'false disables filtering
    
      Returns:
         OK if successful, or
         ERR if mouse-event input disabled
    

    Enable or disable filtering of mouse events that arrive in the queue even though events of that type have not been requested via the event mask.

    Filtering is enabled by default, and it is recommended that it remain enabled unless there is a specific need to see the spurious events.

    While filtering is enabled: - If an unrequested event is received by the ’GetMouseEvent’ method, then it is discarded, and reported as no event. - If an unrequested event is received in the keyboard-input queue via the ’GetKeyInput’ method, then the event is discarded AND: a) if ’GetKeyInput’ is set to block, then wait for the next keycode b) if ’GetKeyInput’ is set for timeout, then wktERR is returned. - In either case, if an unrequested event is received, then the mouse-input queue is flushed. While filtering is disabled: - All detected mouse events, whether or not they match those enabled through the event mask, will be reported as normal mouse events. - Note that the ’ncursesw’ library is not really at fault for reporting unrequested mouse events. Rather it is the xterm mouse driver which allows the spurious events into the event queue.



NCurses Utility Methods

  • void Hibernate ( void );
      Input  : none
      Returns: nothing
    

    Temporarily disable the NCurses Engine so external terminal applications can gain full access to the terminal’s functionality.

    IMPORTANT NOTE: Unlike the ’StopNCursesEngine()’ method, all resources held by the NCurses Engine are retained while in hibernation mode.

    Call ’Wake()’ or ’RefreshScreen()’ method to re-activate the NCurses engine.



  • void Wake ( void );
      Input  : none
      Returns: nothing
    

    Re-enable the NCurses Engine after a previous call to Hibernate().
    Also flushes any remaining data from the keyboard input stream.



  • void BiDiEnable ( bool enable );
      Input  : 
         enable : if 'false', disable terminal control of RTL output
                  if 'true',  return control of RTL output to terminal
      Returns: nothing
    

    Disable or re-enable the terminal emulator’s automatic control of BiDi (Bi-Directional) output.

    This method must be called when the NCurses Engine IS NOT active.

    The NCurses Engine calls this method during start-up to disable the terminal’s BiDi detection, and calls the method again during the shut-down sequence to re-enable terminal control of BiDi data.
    See NCurses Startup-Shutdown, “StartNCursesEngine” and “StopNCursesEngine” methods, as well as the discussion of RTL (Right-To-Left) text rendering at: BiDi Support for more information.



  • short UserAlert ( void );
      Input  : none
      Returns: OK if audible alert supported, else ERR
    

    Sound an audible alert. The actual sound produced is system dependent.
    Note that if the system does not support audible alerts, then then the screen will visibly flash instead.



  • const char* Get_NCurses_Version ( void );
      Input  : none
      Returns:
         (const char*) pointer to version string
    

    Returns a pointer to NCursesVersion, the NCurses class version number.



  • const char* Get_nclibrary_Version ( void );
      Input  : none
      Returns:
         (const char*) pointer to version string
    

    Returns a pointer to the ncurses (curses) C-language library version number.




NCurses Debugging Methods

  • winPos WriteStream ( const wchar_t* wStr, attr_t cAttr );
      Input  :
         wStr : pointer to null-terminated wchar_t 'wide'
                character string
         cAttr: color attribute for output
    
      Returns:
         returns final position of cursor
    

    Write data to the main terminal window (’stdscr’). This method is to be called ONLY to output data to the terminal window when output-stream scrolling has been enabled. (see the OutputStreamScrolling method) If output-stream scrolling has not been enabled, then this method redirects to the standard NCurses-class ’WriteString’ method to produce formatted, non-scrolling data.

    Note that the NcDialog API does not support ’narrow’ (char) output.
    Because the input to this unformatted-output method may be of any length, we avoid possible conversion-buffer overrun by allowing only ’wide’ input.

    This method does not filter the output in any way. While the standard output methods ignore ASCII control characters to ensure consistent formatting, WriteStream() outputs all characters, regardless of type. Note however, that the C language output primitives embedded in the ’ncursesw’ C library will either ignore most ASCII control characters, or will choke and output garbage. Only newline '\n' and tab '\t' will be reliably recognized on all systems.

    IMPORTANT NOTE:
    This method gives the underlying ’ncurses’ C-language library direct control of the output, which is generally not a good idea. That is why this method is classified as a debugging method. Use with caution.

    IMPORTANT NOTE:
    This method is not to be used when the higher-level NcWindow and NcDialog classes have been instantiated in the terminal window. Doing so will cause all kinds of ugliness. You have been warned.


    Example of stream-oriented output:
    
    if( (nc.StartNCursesEngine ()) == OK )
    {
       nc.ClearScreen () ;                    // clear terminal window
       nc.OutputStreamScrolling ( true ) ;    // enable stream output
    
       nc.SetCursor ( 0, 0 ) ;                // set cursor to window origin
       for ( short i = 100 ; i > ZERO ; i-- ) // output some data
          nc.WriteStream ( L"Raw stream output.**", nc.bl ) ;
       nckPause();                            // wait for user
    
       nc.OutputStreamScrolling ( false ) ;   // disable stream output
       nc.ClearScreen () ;                    // clear terminal window
       nc.StopNCursesEngine () ;              // Deactivate the NCurses engine
    }
    

    See test application Dialog2, Test11 (see Stream Output) for a working example of this method. Invoke with:  ./Dialog2 -11 



  • short OutputStreamScrolling ( bool enable );
      Input  :
         enable : if 'true', enable automatic line wrap and scrolling
                  if 'false', disable automatic line wrap and scrolling
    
      Returns: OK
    

    Enable or Disable "standard output" style scrolling in the stdscr window.

    By default, the underlying ’ncurses’ library disables scrolling. The NCurses library also leaves scrolling disabled by default because it produces ugly and undisciplined output.

    If, however, you have a need to emulate a common console application which is unaware of screen edges and data formatting then use this method to enable/disable scrolling.

    For an example of an application built around this functionality, please see Keymap App.

    a) If the cursor reaches the right edge of the terminal window, the cursor is automatically repositioned to the leftmost column of the following display line. (This is dumb-terminal character wrapping, NOT word wrap.) b) If the cursor reaches the right edge of the last display line in the terminal window, then all data in the window will be scrolled up by one line, and the cursor will be repositioned to the leftmost column of the last display line. IMPORTANT INFORMATION ABOUT AUTOMATIC SCROLLING: - The NCurses-class output methods ’WriteString’ and ’WriteChar’ are fully aware of the terminal-window edges and therefore truncate output at the edge of the window REGARDLESS of the state of output-stream scrolling. - Only the ’WriteStream’ method ignores the terminal window dimensions and allows for automatic scrolling. - Scrolling output applies ONLY to the main terminal window and NOT to any sub-window objects within the terminal window. Therefore, do not define any sub-windows when output-stream scrolling is enabled. In practical terms, this means that you must not instantiate any of the higher-level NcWindow and NcDialog classes while scrolling is enabled. - The cursor remains where is was placed after the last character in the string is written, so subsequent output will begin where the previous output left off unless the ’SetCursor’ method is explicitly called. Note that any attempt to set the cursor at a position outside the terminal window will be ignored. - This functionality IS NOT THREAD SAFE. It is the application’s responsibility to ensure that only one thread writes data to the output stream. - Because output-stream scrolling emulates output to a dumb terminal, this method does not support RTL languages.


  • void DisplayColorOptions ( short ypos=3, short xpos=1,
                               bool pause=true );
      Input  :
         ypos      : (optional, default==3) Y screen offset
         xpos      : (optional, default==1) X screen offset
         pause     : (optional, default==true)
                     if 'true' wait for key input before returning
      Returns:
         nothing
    

    Display samples of the standard color scheme defined in the ’ncurses’ C-language library, using the current background color.

    The ’ncurses’ library directly supports the basic eight (8) color attributes and the associated color-modification bits.
    Please see Color Attributes for a detailed discussion of color attributes.



  • void DisplayDefinedColors ( short ypos=3, short xpos=1,
                                bool pause=true );
      Input  :
         ypos      : (optional, default==3) Y screen offset
         xpos      : (optional, default==1) X screen offset
         pause     : (optional, default==true)
                     if 'true' wait for key input before returning
      Returns:
         nothing
    

    Display a character string to demonstrate each of the public data member color attributes defined in NCurses.hpp.

    Although the ’ncurses’ C-language library directly supports only the basic eight (8) foreground/background color pairs available on all color terminals, most modern system hardware supports 16 or more color pairs. As an extension to ’ncurses’, the NCurses Engine dynamically defines as many color pairs as the target hardware will support up to 64 color pairs. See Color Attributes.

    This method may also be used to visually verify that during startup, the ’SetDefaultBackground’ method has properly initialized these members.



  • void DisplayAlternateFont ( short ypos=3, short xpos=1,
                                bool pause=true );
      Input  :
         ypos      : (optional, default==3) Y screen offset
         xpos      : (optional, default==1) X screen offset
         pause     : (optional, default==true)
                     if 'true' wait for key input before returning
      Returns:
         nothing
    

    Display the characters of the Alternate Character Set (ACS). These are the ’narrow’ (ncurses) or ’wide’ (ncursesw) characters, which are built into the terminal’s character set for most terminal emulation software. Display of these characters is controlled by a bit in the color attribute value. This alternate character set consists mainly of line-drawing characters, along with some miscellaneous symbols.

    As an example, in the normal ASCII character set, the value 0x6B is displayed as the letter ’k’. To display this character in the terminal window using the default color, you would call:
        nc.WriteChar ( 1, 1, 'k', nc.bw ) ;            - ->'k'
    However, by changing a bit in the color attribute, the line drawing character, ’upper right corner’ will be displayed instead.
        nc.WriteChar ( 1, 1, 'k', nc.bw | ncaATTR ) ;  - ->'┐'

    While this sequence works, it is not intuitive to work with, nor particulary maintainable. It is recommended that the equivalent (’wide’) character constants be used for all new development. These constants for line-drawing and other characters are declared in NCurses.hpp. See Line Drawing Characters.

    Please note that the UTF-8 character set which is the system default, knows nothing about the ACS, so that the low-level ncurses C-language library is probably emulating the ACS anyway, so why bother with the ACS at all?


  • void DebugBorder ( short wLines, short wCols,
                       short wulY, short wulX, attr_t attr );
      Input  :
         wLines    : verical size of area in lines
         wCols     : horizontal size of area in columns
         wulY      : Y offset from upper left of terminal window
         wulX      : X offset from upper left of terminal window
         attr      : color attribute for drawing
      Returns: nothing
    

    Draw a fake border around an imaginary window.

    NOTE: This method is for use only with the development methods:
          DisplayDefinedColors(), DisplayColorOptions(), and
          DisplayAlternateFont().


  • void GetTransTable1 ( const char**& tt1,
                          short& tt1Min, short& tt1Max );
  • void GetTransTable2 ( const char**& tt2,
                          short& tt2Min, short& ttsMax );
  • void GetTransTable3 ( const char**& tt3, short& tt3Entries );
      Input  :
         tt1 | tt2 | tt3    : receives address of specified lookup table
         tt1Min | tt2Min | tt3Min : receives lowest code in table
         tt1Max | tt2Max | tt3Max : receives highest code in table
      Returns: nothing
    

    Provides access to tables of string literals matching the keycodes defined in the NCurses class. These can be used to unambiguously display any captured keycode which has been defined within the environment.

    TransTable1
       Contains the ASCII control codes, pluse ENTER, TAB, ESCAPE
       and NULLCHAR.
    TransTable2
       Contains the range of keycodes available to the 'ncurses' 
       C-language library; however, remember that 'ncurses' can define 
       a maximum of 64 keycodes, so not all values in the table have 
       associated key definitions.
    TransTable3
       Contains the wktEXTENDED keycode group which consists of keys 
       defined in the NCurses Engine. These are ALT+key and ALT+SHIFT+key 
       key combinations.
    

    Examples

    //* Access to debugging data for key translation *
    const char **TransTable1, **TransTable2, **TransTable3 ;
    short tt1Min, tt1Max, tt2Min, tt2Max, tt3Entries ;
    nc.GetTransTable1 ( TransTable1, tt1Min, tt1Max ) ;
    nc.GetTransTable2 ( TransTable2, tt2Min, tt2Max ) ;
    nc.GetTransTable3 ( TransTable3, tt3Entries ) ;
    
    const char* cptr ;
    const char* ovrflow = "OVERFLOW" ;
    wchar_t wOut[100] ;
    wkeyCode wk ;
    nc.GetKeyInput ( wk ) ;
    switch ( wk.type )
    {
       case wktPRINT:
          swprintf ( wOut, 99, L"Printing character: '%C'", wk.key ) ;
          break ;
       case wktFUNKEY:
          if ( wk.key >= tt1Min && wk.key <= tt1Max )
             cptr = TransTable1[wk.key] ;
          else if ( wk.key >= tt2Min && wk.key <= tt2Max )
             cptr = TransTable2[wk.key - tt1Max] ;
          else   
             cptr = ovrflow ;
          swprintf ( wOut, 99, L"Function key: %s", cptr ) ;
          break ;
       case wktEXTEND:
          if ( wk.key >= ZERO && wk.key < tt3Entries )
             cptr = TransTable3[wk.key] ;
          else
             cptr = ovrflow ;
          swprintf ( wOut, 99, L"Extended key: %s", cptr ) ;
          break ;
       case wktMOUSE:
          swprintf ( wOut, 99, L"Mouse event" ) ;
          break ;
       case wktESCSEQ:
          swprintf ( wOut, 99, L"Un-translated escape sequence" ) ;
          break ;
       case wktERR:
          swprintf ( wOut, 99, L"Key-wait timeout" ) ;
          break ;
    } ;
    nc.WriteString ( 2, 0, wOut, nc.bw ) ;
    

    For a more complete example, please refer to the Dialog2 test
    application, Test #5. (see Dialog2 App)




Color Attributes




ncurses Color Support

Color Attributes In ncurses World

In order to provide the same support for all hardware platforms, all operating systems and terminal types, the ncurses C-language library provides only very basic color mapping for the text displayed in a terminal window.

However, the ncurses library is aware of the (virtual) RGB color registers and the foreground/background color pairs which are part of the terminal definition and this awareness allows for expanding color support to match the capabilities of each platform.

The actual resources available for a particular installation are determined by the hardware platform and terminal-emulator software version, as well as the terminal type being emulated and the color palette selected during terminal configuration.

Because direct color support in the underlying library is so rudimentary, the NcDialog API provides comprehensive color support matching the capabilities of the target terminal. Please see the following chapters for additional information.




Platform Color Support

A Note on Dumb Terminals

In the early days of computing, before personal computers were available and before our screens were filled with pretty screen-saver slide shows, a "terminal" was a physical piece of hardware consisting of a cathode-ray tube driven by a minimal bit of electronics which provided a simple, text-based interface to the host computer. Each hardware manufacturer had one or more hardware designs with varying capabilities. You may have heard about some of these designs, the VT-100 and so on. Nearly all of these are now in some landfill, leaking lead and arsinic into our water supply—so our discussion will focus on "terminal emulators" which are software programs that "emulate" the physical terminals they replace and provide us with a text-based interface to the guts of our operating system.


How Color Is Implemented In a Modern Terminal Emulator

Except for monochrome dumb terminals, most modern terminals support color text output. Terminal configuration is a complex subject, but for color there are two mechanisms in play:

  1. RGB Registers
    The number of RGB (Red - Green - Blue) register sets determines the number of unique colors which can be simultaneously displayed by the terminal. These are not physical registers, but are software-emulated registers which provide a subset of the colors available to the parent (GUI) environment.

    In most systems, there will be either eight(8) or sixteen(16) RGB register sets. For some systems the register settings are fixed, while on other systems you may change the individual color bits of these registers to customize the terminal’s color palette.

    The ncurses library provides access to these registers and determines whether they are read-write or read-only. If the RGB values are read-write, then each of the three base colors may be set to any value between 0 and 1000 with the default being 680 (decimal). For a typical Gnome terminal, set to the ’Linux Console’ color scheme, the 16 RGB registers would look like this.

    R G B R G B Black 0000 0000 0000 Bright Black 0000 0000 0000 Red 0680 0000 0000 Bright Red 1000 0000 0000 Green 0000 0680 0000 Bright Green 0000 1000 0000 Brown 0680 0680 0000 Bright Brown 1000 1000 0000 Blue 0000 0000 0680 Bright Blue 0000 0000 1000 Magenta 0680 0000 0680 Bright Magenta 1000 0000 1000 Cyan 0000 0680 0680 Bright Cyan 0000 1000 1000 Grey 0680 0680 0680 Bright Grey 1000 1000 1000
  2. Color Pairs
    A ’color pair’ is a pair of index values that indicate which RGB register will be used for the foreground (text) color and which RGB register will be used for the background color.

    The ncurses C-language library initializes only the first eight(8) color pairs (pairs 0 through 7). These eight pairs are all set to use the terminal’s default background color, and the foreground colors are set to Black, Red, Green, Brown, Blue, Magenta, Cyan and Grey, respectively.

    Note that color pair zero(0) is a special case. Strictly speaking, color pair zero should be set as white text on a black background; however, research has shown that this is hard on the eyes. For this reason, the terminal definition often exchanges the foreground and background colors of color pair zero (black on near-white) to provide better visual contrast.

The ncurses library and the NcDialog API handle all the low-level details of color mapping, so in general, it is not necessary for the application to deal directly with the terminal’s color configuration unless you want to create a custom configuration. For details on how to capture and modify the terminal’s color map, please see Adjusting the Color Map in test application ’Dialog2’.




NcDialog API Color Support

The NcDialog API takes full advantage of the ncurses library’s support for color in the terminal window using up to sixteen (16) RGB register sets and initializing all available foreground/background color pairs up to 256 pairs.

Note however, that except for the start-up sequence, direct uses of the low-level registers and color pairs is strongly discouraged. All application-level access to color attributes should be through the NcDialog API color variables see NcDialog Color Variables.

NcDialog API Color Support

Although the ncurses library initializes only color pairs 0 through 7, most terminals support many more color pairs. The NcDialog API initializes all available color pairs up to 256 pairs so that your application will encounter no surprises when using them to write text data in the terminal window.

The following discussion may be unsatisfying in ’info’ format because the Texinfo documentation engine is unable display color data, however, the NcDialog test applications display the information in full color.

The most common color terminal configurations are:

  • Eight(8) RGB registers with sixty-four(64) color pairs, OR
  • Sixteen(16) RGB registers with either 128 or 256 color pairs.
  • Each system also supports some subset of the so-called color attribute bits which modify the formatting of the displayed text.
  • Monochrome Output
    In the unlikely event that your system supports only two-color (monochrome) output, the NcDialog API initializes all color pairs and color variables to the terminal’s default foreground/background color.

RGB Registers

The number of RGB registers available determines the number of colors which can be simultaneously displayed in the terminal window. The NcDialog API assigns each of these foreground colors to a foreground/background color pair using the terminal’s default background color.
The basic eight(8) RGB registers are:

COLOR COLOR PAIR 00 Black 00h (fg/bg are often swapped by the terminal) 01 Red 01h 02 Green 02h 03 Brown 03h 04 Blue 04h 05 Magenta 05h 06 Cyan 06h 07 Grey 07h

If the terminal supports additional RGB registers they are:

COLOR COLOR PAIR 08 Bright Black 40h (64 decimal) 09 Bright Red 41h 10 Bright Green 42h 11 Bright Brown (yellow) 43h 12 Bright Blue 44h 13 Bright Magenta 45h 14 Bright Cyan 46h 15 Bright Grey 47h (often indistinguishable from white)

Color Pairs

In addition to mapping the 16 RGB registers to individual color pairs, if additional color pairs are available, the NcDialog API initializes 56 high-contrast foreground/background color combinations and assigns them to color pairs 08h through 3Fh as follows.

COLOR PAIR FOREGROUND/BACKGROUND COLOR PAIR FOREGROUND/BACKGROUND 08h Black on Red 24h Blue on Black 09h Black on Green 25h Blue on Red 0Ah Black on Brown 26h Blue on Green 0Bh Black on Blue 27h Blue on Brown 0Ch Black on Magenta 28h Blue on Magenta 0Dh Black on Cyan 29h Blue on Cyan 0Eh Black on Grey 2Ah Blue on Grey 0Fh Red on Black 2Bh Magenta on Black 10h Red on Green 2Ch Magenta on Red 11h Red on Brown 2Dh Magenta on Green 12h Red on Blue 2Eh Magenta on Brown 13h Red on Magenta 2Fh Magenta on Blue 14h Red on Cyan 30h Magenta on Cyan 15h Red on Grey 31h Magenta on Grey 16h Green on Black 32h Cyan on Black 17h Green on Red 33h Cyan on Red 18h Green on Brown 34h Cyan on Green 19h Green on Blue 35h Cyan on Brown 1Ah Green on Magenta 36h Cyan on Blue 1Bh Green on Cyan 37h Cyan on Magenta 1Ch Green on Grey 38h Cyan on Grey 1Dh Brown on Black 39h Grey on Black 1Eh Brown on Red 3Ah Grey on Red 1Fh Brown on Green 3Bh Grey on Green 20h Brown on Blue 3Ch Grey on Brown 21h Brown on Magenta 3Dh Grey on Blue 22h Brown on Cyan 3Eh Grey on Magenta 23h Brown on Grey 3Fh Grey on Cyan

If the terminal supports RGB registers 8-15, and if a sufficient number of color pairs are available, the NcDialog API assigns an additional 56 color combinations to color pairs 48h through 7Fh using the ’Bright’ versions of the color combinations shown in the table above.

COLOR PAIR FOREGROUND/BACKGROUND 48h Bright Black on Bright Red. . . . 7Fh Bright Grey on Bright Cyan

Color Pairs 128 and Above

Note that although the NcDialog API directly uses only color pairs 00h-7Fh; if the system supports color pairs beyond 7Fh (127 decimal), then color pairs 80h-FFh (128 through 255 decimal) are initialized to the terminal’s default foreground/background color. This is done because unitialized color pairs result in black-on-black which is a rather unfortunate display color.


Color Attribute Bits

Each foreground/background color may be modified using one or more of the color-attribute bits.

Note that no hardware-based terminals support all of these attribute bits and that most terminal emulators support only the most useful subset. Note that specifying an unsupported attribute will have no effect on the output.

'attr_t' type Bit Number Attribute 00000000h n/a NORMAL (no attribute) 00010000h 16 STANDOUT (fgnd/bkgnd reversed and both Bold) 00020000h 17 UNDERLINE (underlined text) 00040000h 18 REVERSE (foreground/background reversed) 00080000h 19 BLINK (blinking text) 00100000h 20 DIM (faded text) 00200000h 21 BOLD (bold foreground text) 00400000h 22 ALT_CHAR_SET (interpret character as value in 'alternate character set') 00800000h 23 INVISIBLE (invisible text bkgnd==fgnd) 01000000h 24 PROTECT ('protected' i.e. read-only) 02000000h 25 HORIZONTAL (unsupported) 04000000h 26 LEFT (unsupported) 08000000h 27 LOW (unsupported) 10000000h 28 RIGHT (unsupported) 20000000h 29 TOP (unsupported) 40000000h 30 VERTICAL (unsupported)

Please see Specifying Color Attributes for more information.




NcDialog Color Variables

The previous chapter described the low-level color mapping mechanism; however, the application accesses all these color data through the defined color-attribute variables.

These variables are defined as public data members of the NCurses class.

IMPORTANT NOTE: In order to simplify and speed up the initialization process of the NCurses Engine, and to avoid the need for macros for accessing color variables, we have made the design decision to declare these color variables as ordinary public ’attr_t’ variables rather than ’const attr_t’ as they should be.

However, it is YOUR responsibility as the application programmer to ALWAYS consider these variables as being READ-ONLY! Of course, we trust you completely, but be aware that re-defining ’red’ as ’blue’ (for instance) would be somewhat counter-productive, so remember: READ-ONLY!

Naming Convention

As described elsewhere (see Accessing NCurses Class Members) all NCurses-class public methods and data are accessed through the global handle ’nc’. Thus, color data are accessed as shown in the example:

attr_t MsgColor = nc.bl ;

Color variables use a short, but consistent and memorable naming convention. Each base color is specified using a two-character code:

CODE COLOR VARIABLE bk BlacK nc.bk re REd nc.re gr GReen nc.gr br BRown nc.br bl BLue nc.bl ma MAgenta nc.ma cy CYan nc.ma gy GreY nc.gy bw nc.bw Specifies the terminal's default foreground which will usually be either black-on-white OR white-on-black.

For often-used ’color + attribute’ combinations, the following variables are defined:

CODE COLOR VARIABLE bkB BlacK (Bold) nc.bkB bkU BlacK (Underlined) nc.bkU bkR BlacK (Reversed) nc.bkR bkG BlacK (Bold+Reverse) nc.bkG bkS BlacK (Standout) nc.bkS bkD BlacK (Dim) nc.bkD Variable names for the remaining base colors follow this naming pattern for color+attribute combinations: BOLD UNDERLINED REVERSED BOLD+REV STANDOUT DIM nc.reB nc.reU nc.reR nc.reG nc.reS nc.reD nc.grB nc.grU nc.grR nc.grG nc.grS nc.grD nc.brB nc.brU nc.brR nc.brG nc.brS nc.brD nc.blB nc.blU nc.blR nc.blG nc.blS nc.blD nc.maB nc.maU nc.maR nc.maG nc.maS nc.maD nc.cyB nc.cyU nc.cyR nc.cyG nc.cyS nc.cyD nc.gyB nc.gyU nc.gyR nc.gyG nc.gyS nc.gyD

For 16-color systems, add ’b’ (’Bright’) to specify the color variable name.

Note that for 8-color systems, these color variables are duplicates of the variables for color pairs 00h-07h.

CODE COLOR VARIABLE bbk Bright BlacK nc.bbk bre Bright REd nc.bre bgr Bright GReen nc.bgr bbr Bright BRown nc.bbr bbl Bright BLue nc.bbl bma Bright MAgenta nc.bma bcy Bright CYan nc.bma bgy Bright GreY nc.bgy

Variable names for often-used ’color + attribute’ combinations follow the established naming pattern:

BOLD UNDERLINED REVERSED BOLD+REV STANDOUT DIM nc.bbkB nc.bbkU nc.bbkR nc.bbkG nc.bbkS nc.bbkD nc.breB nc.breU nc.breR nc.breG nc.breS nc.breD nc.bgrB nc.bgrU nc.bgrR nc.bgrG nc.bgrS nc.bgrD nc.bbrB nc.bbrU nc.bbrR nc.bbrG nc.bbrS nc.bbrD nc.bblB nc.bblU nc.bblR nc.bblG nc.bblS nc.bblD nc.bmaB nc.bmaU nc.bmaR nc.bmaG nc.bmaS nc.bmaD nc.bcyB nc.bcyU nc.bcyR nc.bcyG nc.bcyS nc.bcyD nc.bgyB nc.bgyU nc.bgyR nc.bgyG nc.bgyS nc.bgyD

Additional Color Variables

Color variables are also established for the remaining initialized color pairs 08h-3Fh (8 through 63 decimal), and if available, color pairs 48h-7Fh (72 through 127 decimal).

Note that if color pairs 48h-7Fh are not available, then the corresponding color variables are duplicates of the variables for color pairs 08h-3Fh.

NORMAL BRIGHT VARIABLE FOREGROUND/BACKGROUND VARIABLE nc.rebk Red on Black nc.brebk nc.grbk Green on Black nc.bgrbk nc.brbk Brown on Black nc.bbrbk nc.blbk Blue on Black nc.bblbk nc.mabk Magenta on Black nc.bmabk nc.cybk Cyan on Black nc.bcybk nc.gybk Grey on Black nc.bgybk nc.bkre Black on Red nc.bbkre nc.grre Green on Red nc.bgrre nc.brre Brown on Red nc.bbrre nc.blre Blue on Red nc.bblre nc.mare Magenta on Red nc.bmare nc.cyre Cyan on Red nc.bcyre nc.gyre Grey on Red nc.bgyre nc.bkgr Black on Green nc.bbkgr nc.regr Red on Green nc.bregr nc.brgr Brown on Green nc.bbrgr nc.blgr Blue on Green nc.bblgr nc.magr Magenta on Green nc.bmagr nc.cygr Cyan on Green nc.bcygr nc.gygr Grey on Green nc.bgygr nc.bkbr Black on Brown nc.bbkbr nc.rebr Red on Brown nc.brebr nc.grbr Green on Brown nc.bgrbr nc.blbr Blue on Brown nc.bblbr nc.mabr Magenta on Brown nc.bmabr nc.cybr Cyan on Brown nc.bcybr nc.gybr Grey on Brown nc.bgybr nc.bkbl Black on Blue nc.bbkbl nc.rebl Red on Blue nc.brebl nc.grbl Green on Blue nc.bgrbl nc.brbl Brown on Blue nc.bbrbl nc.mabl Magenta on Blue nc.bmabl nc.cybl Cyan on Blue nc.bcybl nc.gybl Grey on Blue nc.bgybl nc.bkma Black on Magenta nc.bbkma nc.rema Red on Magenta nc.brema nc.grma Green on Magenta nc.bgrma nc.brma Brown on Magenta nc.bbrma nc.blma Blue on Magenta nc.bblma nc.cyma Cyan on Magenta nc.bcyma nc.gyma Grey on Magenta nc.bgyma nc.bkcy Black on Cyan nc.bbkcy nc.recy Red on Cyan nc.brecy nc.grcy Green on Cyan nc.bgrcy nc.brcy Brown on Cyan nc.bbrcy nc.blcy Blue on Cyan nc.bblcy nc.macy Magenta on Cyan nc.bmacy nc.gycy Grey on Cyan nc.bgycy nc.bkgy Black on Grey nc.bbkgy nc.regy Red on Grey nc.bregy nc.grgy Green on Grey nc.bgrgy nc.brgy Brown on Grey nc.bbrgy nc.blgy Blue on Grey nc.bblgy nc.magy Magenta on Grey nc.bmagy nc.cygy Cyan on Grey nc.bcygy

Note that some of the above color-combination variables include the ’Bold’ (ncbATTR) color attribute bit in order to produce acceptable contrast between foreground and background. Even so, there are a few combinations which do not produce easily-readable text, so experiment a bit to determine which combinations look best in your applications.


Specifying Color Attributes

The NcDialog API defines the following color attribute bit masks.
These bit masks are defined in NCurses.hpp.

As noted in a previous chapter, not all systems support all of these color attribute bits, and terminal emulators support only a common subset, usually ’Bold’, ’Underline’, ’Reverse’, and ’AltCharSet’. Use of an unsupported attribute bit will have no effect on the output.

const attr_t ncnATTR ; // NORMAL (no attribute) const attr_t ncsATTR ; // STANDOUT (fgnd/bkgnd reversed and both Bold) const attr_t ncuATTR ; // UNDERLINE (underlined text) const attr_t ncrATTR ; // REVERSE (foreground/background reversed) const attr_t nckATTR ; // BLINK (blinking text) const attr_t ncdATTR ; // DIM (faded text) const attr_t ncbATTR ; // BOLD (bold foreground text) const attr_t ncaATTR ; // ALT_CHAR_SET (interpret character as alternate- // character-set value - use is not recommended) const attr_t ncgATTR ; // REVERSE+BOLD (combines ncbATTR and ncrATTR) const attr_t nciATTR ; // INVISIBLE (invisible text) const attr_t ncpATTR ; // PROTECT (unsupported) const attr_t nchATTR ; // HORIZONTAL (unsupported) const attr_t nclATTR ; // LEFT (unsupported) const attr_t ncwATTR ; // LOW (unsupported) const attr_t ncqATTR ; // RIGHT (unsupported) const attr_t nctATTR ; // TOP (unsupported)

Adding a color attribute bit is done through a logical-OR of that bit with the base color.

Combine Blue text with the Underline attribute: attr_t msgColor = nc.bl | ncuATTR ; Write a message using Magenta text with Bold and Reverse attributes: dp->WriteString ( wp, "Hello World!", nc.ma | ncbATTR | ncrATTR ) ;



Keycode Constants

What Is a Character?

The native language of Linux is UTF-8. UTF-8 encoding is a byte-oriented way of representing all characters of all human languages.

’Curses’ was developed long before UTF-8 encoding, so character encoding and processing in curses world is not as simple as one would hope. The original 7-bit and 8-bit curses C-language library was completely inadequate for international communication, so the ’wide character’ library (ncursesw) was developed. The ’wide’ library is based on a ’wchar_t’ (32-bit integer) character type. At the lowest level, some tricks are played to enable ’wide’ character support in the ’ncursesw’ library. Fortunately, an NcDialog API application doesn’t need to worry about these details because the printing characters are equivalent to ’Unicode code points’. However, a few things must be kept in mind.

The first thing to remember is that character codes fall into two general categories.

1) printing character codes and meta-characters 2) command (function) codes

Because the ’ncursesw’ library has only a very limited number of codes available, the numerical values for characters and for commands overlap; therefore, a character is always handled as a pair of codes.

a) the character CODE, and b) the charater TYPE.

In general, it is not possible to know whether a given code is a character or a command code unless we look at both of these elements (see below for examples).

The ’ncursesw’ C-language library provides basic support for all printing characters (and meta-characters) as well as a useful selection of function-key definitions; however, the way the ’ncursesw’ library handles the code pairs is inconvenient, to say the least. For this reason, the NcDialog API encapsulates all the underlying messiness into the wkeyCode class.


The wkeyCode Class

The wkeyCode class, defined in NCurses.hpp, is the workhorse of character processing. The wkeyCode class has three public data members:

  wchar_t    key ;
  wkeyType   type
  MouseEvent mevent ;

First, let’s look at the ’type’ member. The type is specified by the enumeration list, ’wkeyType’:

  enum wkeyType : short
  {               // == INDICATES ==
     wktPRINT,    // a printing character or metacharacter
     wktFUNKEY,   // a command code (function-key code)
     wktMOUSE,    // a mouse event code
     wktEXTEND,   // a member of the 'extended' command-key group
     wktESCSEQ,   // an untranslated escape sequence
     wktERR       // an invalid code
  } ;

wktPRINT and wktFUNKEY correspond roughly to the designations in the underlying ncurses(w) library.

wktMOUSE indicates that a mouse event has been captured and that the mouse data have been stored in the ’mevent’ data member. For more information on the mouse interface, please see NCurses Mouse Access.

wktEXTEND indicates that the code is one of the extended command-keys defined by the NcDialog API. These command keys are mostly 'ALT+x' key combinations. For instance, if the user presses and holds the ’ALT’ key and then presses the ’A’ key, that combination, 'ALT+A' is a non-printing command key (defined as 'nckA_A').

wktESCSEQ indicates that an unknown sequence of bytes has been received from the underlying keyboard interface. Because the ncurses(w) library has only a limited number of keycodes available, and because the ncurses(w) library must support a very wide variety of modern and legacy keyboards, not all escape sequences can have a keycode assigned to them. As an example, the ncurses(w) library does not translate the following sequence of hexadecimal bytes received from the keyboard. An escape sequence like this is generally meaningless at the application level, and so should be ignored.

  1B 5B 31 7E     // represents numeric keypad 'Home' key

wktERR indicates than the attempt to retrieve keyboard input has failed or that the data received do not represent a valid code.


Testing Key Data

Next, The wchar_t value, ’key’ defines the keycode. Before discussing the values that ’key’ can contain, it is important to understand that a given value of ’key’ can only be properly interpreted within its ’type’ context.

Here are some practical examples of testing the key input:

// define some wkeyCode-class objects
wkeyCode wk, wkesc( nckESC, wktFUNKEY );

// get key input from user
// (note that key type is also the return value)
nc.GetKeyInput ( wk ) ;

// testing for the return of the LeftArrow function key
if ( wk.type == wktFUNKEY && wk.key == nckLEFT )
{
   /* DO STUFF */ 
}

// testing for return of the extended-definition key, ALT+SHIFT+B
else if ( wk.type == wktEXTEND && wk.key == nckAS_B )
{
   /* DO STUFF */
}

// testing for equality with another wkeyCode object
else if ( wk == wkesc )
{
   /* DO STUFF */
}

// You may also test for inequality with another wkeyCode object:
if ( wk != wkesc )
{
   /* DO STUFF */
}


Printing Characters and Metacharacters

A printing character is one which can be written to the display and we can see it. Most human language characters fall into this category.

There are a few character which are known as control codes, the 'CTRL+C' (break) and the ’ENTER’ (RETURN) key are common examples. These characters are not visible, but they control the flow of the output.

However, some languages and character sets, while quite complex and beautiful when written by hand, are not so simple to render electronically. A base character may require one or more additional marks or glyphs in order to be complete. These additional glyphs are not characters in themselves, and so are never printed alone, but only in combination with a base character. These special glyphs are known as metacharacters. The Arabic language is a good example of a language which uses metacharacters.

For additional information on character encoding please
see Multi-language Support.


Defined Constants

While printing characters and metacharacters are well-defined and standardized, function keys and their associated control codes vary from system to system.

The ncurses(w) C-language library defines certain keycodes based on information in the terminal definition database (termcap, terminfo, environment variables and so on). These definitions may refer to a single key, or may refer to a key combination. Because the ncurses(w) library must support a wide variety of systems (many of which no longer exist) many of these keycodes are implemented as macros. However, macros are difficult to work with and tend to be fat and slow when converted to CPU instructions.

For this reason, the NcDialog API, and specifically the NCurses class define a large number of useful control code constants as well as some common character codes.


ASCII Control Codes

The ASCII (American Standard Code for Information Interchange) control codes are represented in various human readable forms ’^A’, ’Ctrl+A’, 0x01 and so on. In the NcDialog API, these control codes are referenced by their named constant values, e.g. ’nckC_A’ means ’NCursesKey Control+A’.

 Constant  Code Constant  Code Constant  Code
 nckC_A Ctrl+A nckC_K Ctrl+K nckC_V Ctrl+V
 nckC_B Ctrl+B nckC_L Ctrl+L nckC_W Ctrl+W
 nckC_C Ctrl+C nckC_N Ctrl+N nckC_X Ctrl+X
 nckC_D Ctrl+D nckC_O Ctrl+O nckC_Y Ctrl+Y
 nckC_E Ctrl+E nckC_P Ctrl+P nckC_Z Ctrl+Z
 nckC_F Ctrl+F nckC_Q Ctrl+Q nckESC Ctrl+[
 nckC_G Ctrl+G nckC_R Ctrl+R nckC_4 Ctrl+4
 nckC_H Ctrl+H nckC_S Ctrl+S nckC_5 Ctrl+5
 nckTAB Ctrl+I nckC_T Ctrl+T nckC_6 Ctrl+6
 nckENTER Ctrl+J nckC_U Ctrl+U nckC_7 Ctrl+7

Note that the zero (0, \0, 0x00) character is designated as nckNULLCHAR.

Note that the ’Ctrl+M’ (carriage return) keycode is not used in Linux/UNIX systems. The ’Ctrl+J’ (linefeed) keycode is used instead.


Navigation Keys

The navigation keys, Up, Down, Right, Left, Tab, PageUp, PageDown, Home and End are familiar to most computer users. These keys when used alone or in combination with the ’Shift’, ’Ctrl’ and ’Alt’ (’Meta’) keys move the text cursor and/or the input focus around the window.

Some of these key combinations are not generated by the keyboard itself, some are captured by the system before they reach the terminal window, some are captured by the terminal window itself, and some cannot be handled by the underlying ncurses(w) C-language library. The remainder are available to an application running in a terminal window. The exact list of navigation keys which will be available is system dependent. For instance, this list shows an example of the possible key combinations for the DownArrow key; however, it is likely that some of these key combinations will not be available on your system.

  • DownArrow
  • Shift+DownArrow
  • Ctrl+DownArrow
  • Alt+Shift+DownArrow
  • Ctrl+Shift+DownArrow
  • Alt+Ctrl+DownArrow
  • Alt+Ctrl+Shift+DownArrow

The following table shows the navigation-key combinations which are actually seen by an NcDialog application running in a terminal window on typical Wintel hardware.

 Name  Base +Shift+Alt+Shift
 Up Arrow nckUP nckSUP nckASUP
 Down Arrow nckDOWN nckSDOWN nckASDOWN
 Right Arrow nckRIGHT nckSRIGHT nckASRIGHT
 Left Arrow nckLEFT nckSLEFT nckASLEFT
 Page Up nckPGUP . . . . . .
 Page Down nckPGDOWN . . . . . .
 Home nckHOME . . . . . .
 End nckEND . . . . . .
 Tab nckTAB nckSTAB . . .
    
 Name +Alt+Ctrl+Alt+Ctrl
 Up Arrow nckAUP nckCUP . . .
 Down Arrow nckADOWN nckCDOWN . . .
 Right Arrow nckARIGHT nckCRIGHT . . .
 Left Arrow nckALEFT nckCLEFT . . .
 Page Up nckAPGUP . . . nckACPGUP
 Page Down nckAPGDN . . . nckACPGDN
 Home . . . . . . . . .
 End . . . . . . . . .
 Tab . . . nckTAB . . .

Numeric Keypad

For keyboards which have built-in numeric keypads or for externally-mounted numeric keypads, some additional navigation keys and other keys may be available. Some of these extra keys will yield the same keycodes as the equivalent key on the main keyboard, so they cannot be individually identified. The keycodes which can be identified as belonging to the numeric keypad are indicated with a ’nckpXXX’ named constant, but within this group, note that many of the key combinations yield the same keycode as the base key, so this table contains some duplicates.

IMPORTANT NOTE: In order to see these keycodes, the ’Numlock’ key must be ON and the ’Shift’ key MUST NOT be pressed.

 Name  Base +Alt+Ctrl +Alt+Ctrl
 Up Arrow . . . . . . . . . nckpACUP
 Down Arrow . . . . . . . . . nckpACDN
 Right Arrow . . . . . . . . . nckpACRIGHT
 Left Arrow . . . . . . . . . nckpLEFT
 Page Up . . . nckpAPGUP nckpCPGUP nckpACPGUP
 Page Down . . . nckpAPGDN nckpCPGDN nckpACPGDN
 Home . . . . . . . . . . . .
 End . . . . . . . . . . . .
 Center(’5’) nckpCENTER nckpCENTER nckpCENTER nckpCENTER
 Insert . . . . . . . . . . . .
 Delete . . . . . . . . . nckpACDEL
 Enter(RET) nckpENTER nckpENTER nckpENTER nckpENTER
 Plus(’+’) nckpPLUS nckpPLUS . . . . . .
 Minus(’-’) nckpMINUS nckpMINUS . . . . . .
 Mult(’*’) nckpMULT nckpMULT nckpMULT . . .
 Div(’/’) nckpDIV nckpDIV nckpDIV . . .


Function Keys

A ’Function Key’ is any keycode which represents a command rather than a printing character.

The navigation keys described above are a type of function key because they command the cursor to go somewhere. However, there are many other command keys. The most notable of these is the row of 'Fnn' keys found at the top of most keyboards. The number of these keys actually present and the way they are interpreted are system dependent.

PCs, i.e. Wintel hardware generally have either ten or twelve ’Fnn’ keys. Mainframes, minicomputers and high-end workstations often have several more.

Some of these keys, (the ’F01’ equals ’Help’ for instance), have become standard keyboard fuctionality, while the definition of other key combinations is left to the system or to individual applications. As with the navigation keys described above, function keys can be combined with the modifier keys ’Shift’, ’Alt’ ("Meta’) and ’Ctrl’ to provide the user with many ways to quickly accomplish common tasks.

Some of these key combinations are not generated by the keyboard itself, some are captured by the system before they reach the terminal window, some are captured by the terminal window itself, and some cannot be handled by the underlying ncurses(w) C-language library. The remainder are available to an application running in a terminal window. The exact list of function/command keys which will be available to your application is system dependent. The following table describes the Function Key combinations defined directly by the underlying ncurses(w) library OR translated from escape sequenced by the NcDialog API.

The ncurses(w) C-language library can store up to a maximum of sixty-four (64) function keycodes. In practice, however, the library does not use all of this reserved storage. The NcDialog API uses some of the free keycode storage for other command keys, and some slots remain undefined.

 Name  Base  +Shift +Ctrl +Ctrl+Shift
 F01 nckF01 nckSF01 nckCF01 nckCSF01
 F02 nckF02 nckSF02 nckCF02 nckCSF02
 F03 nckF03 nckSF03 nckCF03 nckCSF03
 F04 nckF04 nckSF04 nckCF04 nckCSF04
 F05 nckF05 nckSF05 nckCF05 nckCSF05
 F06 nckF06 nckSF06 nckCF06 nckCSF06
 F07 nckF07 nckSF07 nckCF07 nckCSF07
 F08 nckF08 nckSF08 nckCF08 nckCSF08
 F09 nckF09 nckSF09 nckCF09 nckCSF09
 F10 nckF10 nckSF10 nckCF10 nckCSF10
 F11 nckF11 nckSF11 nckCF11 nckCSF11
 F12 nckF12 nckSF12 nckCF12 nckCSF12


Extended Command Codes

Because the ncurses(w) C-language library has limited space for keycode storage, it does not handle most command codes generated using the ’Alt’ (’Meta’) key.

To provide a larger variety of command codes for use in your applications, the NcDialog API defines as many of the 'Alt+n' command codes as is practical. These command codes are not as portable among different hardware platforms as are the base ncurses(w) keycodes; however, for systems that support them (Wintel/PC hardware for instance), these command codes are available for application development. (see NCursesKeyDef.hpp)

 Constant  Code Constant  Code Constant  Code
 nckA_A Alt+a nckAS_A Alt+Shift+a nckAC_A Alt+Ctrl+a
 nckA_B Alt+b nckAS_B Alt+Shift+b nckAC_B Alt+Ctrl+b
 nckA_C Alt+c nckAS_C Alt+Shift+c nckAC_C Alt+Ctrl+c
 nckA_D Alt+d nckAS_D Alt+Shift+d nckAC_D Alt+Ctrl+d
 nckA_E Alt+e nckAS_E Alt+Shift+e nckAC_E Alt+Ctrl+e
 nckA_F Alt+f nckAS_F Alt+Shift+f nckAC_F Alt+Ctrl+f
 nckA_G Alt+g nckAS_G Alt+Shift+g nckAC_G Alt+Ctrl+g
 nckA_H Alt+h nckAS_H Alt+Shift+h nckAC_H Alt+Ctrl+h
 nckA_I Alt+i nckAS_I Alt+Shift+i nckAC_I Alt+Ctrl+i
 nckA_J Alt+j nckAS_J Alt+Shift+j nckAC_J Alt+Ctrl+j
 nckA_K Alt+k nckAS_K Alt+Shift+k nckAC_K Alt+Ctrl+k
 nckA_L Alt+l nckAS_L Alt+Shift+l nckAC_L Alt+Ctrl+l
 nckA_M Alt+m nckAS_M Alt+Shift+m nckAC_M Alt+Ctrl+m
 nckA_N Alt+n nckAS_N Alt+Shift+n nckAC_N Alt+Ctrl+n
 nckA_O Alt+o nckAS_O Alt+Shift+o nckAC_O Alt+Ctrl+o
 nckA_P Alt+p nckAS_P Alt+Shift+p nckAC_P Alt+Ctrl+p
 nckA_Q Alt+q nckAS_Q Alt+Shift+q nckAC_Q Alt+Ctrl+q
 nckA_R Alt+r nckAS_R Alt+Shift+r nckAC_R Alt+Ctrl+r
 nckA_S Alt+s nckAS_S Alt+Shift+s nckAC_S Alt+Ctrl+s
 nckA_T Alt+t nckAS_T Alt+Shift+t nckAC_T Alt+Ctrl+t
 nckA_U Alt+u nckAS_U Alt+Shift+u nckAC_U Alt+Ctrl+u
 nckA_V Alt+v nckAS_V Alt+Shift+v nckAC_V Alt+Ctrl+v
 nckA_W Alt+w nckAS_W Alt+Shift+w nckAC_W Alt+Ctrl+w
 nckA_X Alt+x nckAS_X Alt+Shift+x nckAC_X Alt+Ctrl+x
 nckA_Y Alt+y nckAS_Y Alt+Shift+y nckAC_Y Alt+Ctrl+y
 nckA_Z Alt+z nckAS_Z Alt+Shift+z nckAC_Z Alt+Ctrl+z
      
 nckA_0 Alt+0 nckAS_0 Alt+Shift+0  
 nckA_1 Alt+1 nckAS_1 Alt+Shift+1  
 nckA_2 Alt+2 nckAS_2 Alt+Shift+2  
 nckA_3 Alt+3 nckAS_3 Alt+Shift+3  
 nckA_4 Alt+4 nckAS_4 Alt+Shift+4  
 nckA_5 Alt+5 nckAS_5 Alt+Shift+5  
 nckA_6 Alt+6 nckAS_6 Alt+Shift+6  
 nckA_7 Alt+7 nckAS_7 Alt+Shift+7  
 nckA_8 Alt+8 nckAS_8 Alt+Shift+8  
 nckA_9 Alt+9 nckAS_9 Alt+Shift+9  

A few additional ’Alt+____’ definitions using punctuation characters are also defined.

 Constant  Code Constant  Code
 nckA_DUBL Alt+ " nckA_RCHV Alt+ >
 nckA_SING Alt+ ’ nckA_QUES Alt+ ?
 nckA_PLUS Alt+ + nckA_LBRK Alt+ [
 nckA_COMM Alt+ , nckA_BSTR Alt+ \
 nckA_MINU Alt+ - nckA_RBRK Alt+ ]
 nckA_STOP Alt+ . nckA_UNDR Alt+ _
 nckA_FSTR Alt+ / nckA_GRAV Alt+ ‘
 nckA_COLO Alt+ : nckA_LBRC Alt+ {
 nckA_SEMI Alt+ ; nckA_VBAR Alt+ |
 nckA_LCHV Alt+ < nckA_RBRC Alt+ }
 nckA_EQUL Alt+ = nckA_TILD Alt+ ~



Line Drawing Characters

Text characters may be used for simple line drawings using lines, corners and intersections. These characters can be quite useful in enhancing the readability of data written to a terminal window.

High-level utility methods which are available for line drawing:
See DrawLine method.
See DrawBox method.

Two development methods are available which display examples of the line drawing characters:
See DisplayLineDrawingSet method.
See DisplayLineDrawingExamples method.

The following is a chart of the basic Unicode line-drawing characters and their constant definitions as defined in NCurses.hpp. For additional Unicode graphic characters, please refer to Unicode Consortium’s Unicode Character Table, starting with codepoint U+2500.

┌───────────────────────────┤ Line-drawing Characters ├───────────────────────────┐ │ │ wcsHORIZs 0x2500 wcsLLs 0x2514 wcsTTEEbh 0x252F │ wcsHORIZb 0x2501 wcsLLb 0x2517 wcsTTEEdv 0x2565 │ wcsHORIZd 0x2550 wcsLLd 0x255A wcsTTEEdh 0x2564 │ wcsHDASH2s 0x254C wcsLRs 0x2518 wcsBTEEs 0x2534 │ wcsHDASH2b 0x254D wcsLRb 0x251B wcsBTEEb 0x253B │ wcsHDASH3s 0x2504 wcsLRd 0x255D wcsBTEEd 0x2569 │ wcsHDASH3b 0x2505 wcsLTEEs 0x251C wcsBTEEbv 0x2538 │ wcsHDASH4s 0x2508 wcsLTEEb 0x2523 wcsBTEEbh 0x2537 │ wcsHDASH4b 0x2509 wcsLTEEd 0x2560 wcsBTEEdv 0x2568 │ wcsVERTs 0x2502 wcsLTEEbv 0x2520 wcsBTEEdh 0x2567 │ wcsVERTb 0x2503 wcsLTEEbh 0x251D wcsINSECTs 0x253C │ wcsVERTd 0x2551 wcsLTEEdv 0x255F wcsINSECTb 0x254B │ wcsVDASH2s 0x254E wcsLTEEdh 0x255E wcsINSECTd 0x256C │ wcsVDASH2b 0x254F wcsRTEEs 0x2524 wcsINSECTbv 0x2542 │ wcsVDASH3s 0x2506 wcsRTEEb 0x252B wcsINSECTbh 0x253F │ wcsVDASH3b 0x2507 wcsRTEEd 0x2563 wcsINSECTdv 0x256B │ wcsVDASH4s 0x250A wcsRTEEbv 0x2528 wcsINSECTdh 0x256A │ wcsVDASH4b 0x250B wcsRTEEbh 0x2525 wcsBLOCKl 0x2591 │ wcsULs 0x250C wcsRTEEdv 0x2562 wcsBLOCKm 0x2592 │ wcsULb 0x250F wcsRTEEdh 0x2561 wcsBLOCKd 0x2593 │ wcsULd 0x2554 wcsTTEEs 0x252C wcsBLOCKs 0x2588 │ wcsURs 0x2510 wcsTTEEb 0x2533 │ wcsURb 0x2513 wcsTTEEd 0x2566 │ wcsURd 0x2557 wcsTTEEbv 0x2530 │ │ │ └───────────────────────────────────────────────────────────────────────────────────┘




Note that the ncurses(w) library defines macros for line-drawing characters which live in both the ’narrow’ and ’wide’ versions of the so-called ’Alternate Character Set’ which is part of the basic Linux/UNIX terminalcharacter set. Before there was a Unicode Standard, the Alternate Character Set may have seemed like a good idea; however, use of the ACS_xxx and WACS_xxx line-drawing characters in new code is strongly discouraged. Use the Unicode/UTF-8 characters directly. For more information on the Alternate Character Set, please see Color Attributes.




NcWindow Meta-layer

This chapter covers the NcWindow class definition. The NcWindow class is seldom, if ever used directly, but classes derived from it form the basis of the NcDialog class and its descendants which constitute the application programmer’s interface.

Some of the methods described in this chapter are inherited by the NcDialog class, while others are masked by NcDialog-class method redefinitions.







NcWindow Class Overview

The NcWindow meta-layer performs three (3) major functions within the NcDialog API:

  1. NcWindow provides direct access to the underlying ’ncursesw’ C-language library.
  2. NcWindow is the ancestor class for most NcDialog constructs.
  3. NcWindow implements thread safety for the keyboard/mouse input stream and for the text (display) output stream.

Applications should never call NcWindow methods directly, but should call the equivalent NcDialog-class method instead. That’s why the NcWindow-class it is called a ’Metalayer’. The NcWindow-class functionality is discussed ONLY to provide a greater understanding of the API’s underlying structure.




NcWindow Public Methods

What follows is a list of all public methods of the NcWindow class.
Methods are arranged in functional groups.

Some of these methods are passthroughs to the NCurses class; others are directly inherited by the NcDialog class or are redefined in the NcDialog class.

        NcWindow Method Name            Chapter Reference    
 NcWindow [constructors] see NcWindow Basics
 ~NcWindow [destructor] 
 OpenWindow 
 WinDimensions 
  
 SetInteriorColor see NcWindow Formatting
 DrawBorder 
 DrawBox 
 DrawLine 
  
 WriteString see NcWindow Display Output
 WriteChar 
 WriteParagraph 
 ClearWin 
 RefreshWin 
 ClearLine 
 GetCursor 
 SetCursor 
  
 GetKeyInput see NcWindow Keyboard Input
 meEnableStableMouse 
 meEnableMouse 
 meDisableMouse 
 meMouseEnabled 
 meSetEventTypes 
 meGetEventTypes 
 meSetClickInterval 
 meGetClickInterval 
 meFlushEventQueue 
 meAutoConvert 
 meAutoFilter 
  
 KeyPeek see NcWindow Passthroughs
 UngetKeyInput 
 FlushKeyInputStream 
 GetCursorState 
 SetCursorState 
 RestoreCursorState 
 GetKeyProcState 
 SetKeyProcState 
 GetKeyDelay 
 SetKeyDelay 
 ScreenDimensions 
 Hibernate 
 Wake 
 Get_NCurses_Version 
 Get_nclibrary_Version 
  
 PaintData see NcWindow Data Scrolling
 PaintMenuData 
 RepaintData 
 EraseData 
 ScrollData 
 ScrollMenuData 
 ScrollView 
 GetHilightIndex 
 Track2Top 
 Track2Bottom 
 Track2Next 
 Track2Previous 
 Track2Item 
  
 Get_NcWindow_Version see NcWindow Utility Methods
 DebugMsg 



NcWindow Basics

  • ~NcWindow ( void );
      Input  : none
      Returns: nothing
    

    Destructor. Erase the window from the display and release its resources back to the system.



  • NcWindow ( short lines, short columns,
               short startY, short startX );
      Input  :
         lines   : number of lines in the window
         columns : number of columns in the window
         begin_y : vertical offset from upper left corner of screen
         begin_x : horizontal offset from upper left of screen
      Returns: nothing
    

    Constructor. Creates an NcWindow object. The constructor specifies only the size of the window and its position relative to the upper left corner of the terminal window. All other data members for the NcWindow object are initially set to their default values.

    Window background color, border and other contents must be specified separately after instantiation is complete. It is recommended that all additional configuration be completed before making the window visible for the first time.

    The underlying ’ncurses’ window is not created by the constructor, but is created by the ’OpenWindow()’ method, below.



  • short OpenWindow ( void );
      Input  : none
      Returns:
         OK if successfully opened, else ERR
    
          Note that most likely causes of error are:
          a) terminal screen is too small to hold the window
             plus offsets from upper-left corner
          b) insufficient heap memory (unlikely)
    

    Allocate resources for the window based upon the parameters passed to the constructor. Calls a series of functions in the underlying ’ncurses’ C-language library to create the primitive window, and then makes the window visible to the user.

    Note that the ’ncurses’ C-library allows a window to be opened even if it extends beyond the borders of the terminal window; however, the NcWindow class DOES NOT allow that kind of foolishness.



  • void WinDimensions ( short& lines, short& columns );
      Input  :
         lines   : (by reference) receives lines (rows) in window
         columns : (by reference) receives vertical columns in window
      Returns: nothing
    

    Returns the window dimensions in lines and columns.




NcWindow Formatting

  • void SetInteriorColor ( attr_t cAttr );
      Input  :
         cAttr : color attribute
      Returns: nothing
    

    Set a background color for the interior of the window.
    Does not redraw the window.



  • short DrawBorder ( attr_t cAttr, const char* title=NULL,
                       ncLineType style = ncltSINGLE,
                       bool rtlText = false );
      Input  :
         cAttr  : color attribute
         title  : (optional, default==NULL)
                  if non-NULL, points to window title string
         style  : (optional, ncltSINGLE by default)
                  member of enum ncLineType
         rtlText: (optional, false by default)
                  if 'title' != NULL, then:
                  if false, draw as LTR text, if true, draw as RTL text
      Returns:
         If no title string is specified:
           OK on success,
           else ERR (window too small, must be at least 2 lines by 2 cols)
         If a title string IS specified:
           returns the X offset at which the title is displayed.
           (this is optionally used to position a hotkey indicator)
    

    Draw an inside border around the window, and optionally a title which is centered in the top line of the window.
    Does not refresh the window.



  • short DrawBox ( short startY, short startX,
                    short rows, short cols,
                    attr_t cAttr, const char* title=NULL,
                    ncLineType style=ncltSINGLE, bool rtlText=false );
      Input  :
         startY : y offset for start of line
         startX : x offset for start of line
         rows   : number of rows
         cols   : number of columns
         cAttr  : color attribute
         title  : (optional, default==NULL)
                  if non-NULL, points to box title string
         style  : (optional, ncltSINGLE by default)
         rtlText: (optional, false by default)
                  if 'title' != NULL, then:
                  if false, draw as LTR text, if true, draw as RTL text
      Returns:
         If no title string is specified:
           OK on success,
           else ERR (box would extend beyond parent window)
         If a title string IS specified:
           returns the X offset at which the title is displayed.
    

    Please see DrawBox method in the NcDialog chapter.



  • short DrawLine ( const LineDef& ldef );
      Input  :
         lDef (by reference)
              initialized fields
           type   : ncltHORIZ or ncltVERT
           style  : normal, bold, dual-line, or one of the
                    dashed line types
           startY : y offset for start of line
           startX : x offset for start of line
           length : number of lines (vert) or columns (horiz)
           attr   : color attribute
      Returns:
         OK if success, else ERR
    

    Please see DrawLine method in the NcDialog chapter.




NcWindow Display Output

  • winPos WriteString ( short startY, short startX,
                         const gString& gStr, attr_t cAttr,
                         bool refresh=false, bool rtl=false );
  • winPos WriteString ( const winPos& startYX, const char* uStr,
                         attr_t cAttr,
                         bool refresh=false, bool rtl=false );
  • winPos WriteString ( short startY, short startX,
                         const char* uStr, attr_t cAttr,
                         bool refresh=false, bool rtl=false );
  • winPos WriteString ( const winPos& startYX, const wchar_t* wStr,
                         attr_t cAttr,
                         bool refresh=false, bool rtl=false );
  • winPos WriteString ( short startY, short startX,
                         const wchar_t* wStr, attr_t cAttr,
                         bool refresh=false, bool rtl=false );
  • winPos WriteString ( const winPos& startYX, const gString& gStr,
                         attr_t cAttr,
                         bool refresh=false, bool rtl=false );

    Please see WriteString method in the NcDialog chapter.



  • winPos WriteChar ( short startY, short startX, const char* uChar,
                       attr_t cAttr,
                       bool refresh=false, bool rtl=false );
  • winPos WriteChar ( const winPos& startYX, const char* uChar,
                       attr_t cAttr,
                       bool refresh=false, bool rtl=false );
  • winPos WriteChar ( short startY, short startX, wchar_t wChar,
                       attr_t cAttr,
                       bool refresh=false, bool rtl=false );
  • winPos WriteChar ( const winPos& startYX, wchar_t wChar,
                       attr_t cAttr,
                       bool refresh=false, bool rtl=false );

    Please see WriteChar method in the NcDialog chapter.



  • winPos WriteParagraph ( short startY, short startX,
                            const gString& gStr,
                            attr_t cAttr,
                            bool refresh=false, bool rtl=false );
  • winPos WriteParagraph ( const winPos& startYX, const gString& gStr,
                            attr_t cAttr,
                            bool refresh=false, bool rtl=false );

    Please see WriteParagraph method in the NcDialog chapter.



  • short ClearWin ( bool clearAll=true, bool refresh=true );
      Input  :
         clearAll: (optional, true by default)
                   if false do not clear window border.
                   else, clear entire window.
         refresh : (optional, true by default)
                    if true, refresh the display
    
      Returns: OK
    

    Erase the contents of the window and optionally refresh the display.

    Note that windows of one line, by definition, have no borders, so clearAll is assumed for one-line windows.



  • void RefreshWin ( void );
      Input  : none
    
      Returns: nothing
    

    Refresh the display of window contents.

    Any changes made to the window contents since the last refreh will become visible.



  • short ClearLine ( short ypos, bool clearAll = false,
                      short xpos = 1, bool rtl = false ) ;
      Input  : 
         ypos    : line number (zero-based)
         clearAll: (optional, false by default) if 'true', clear entire
                   line, if 'false' do not clear border area
         xpos    : (optional)
                   starting column (zero-based)
                   Note: for LTR, default is one(1)
                         for RTL, default is (columns-2)
                   (ignored if clearAll != false)
         rtl     : (optional, 'false' by default)
                   if 'false', then clear from 'xpos' toward right
                   if 'true',  then clear from 'xpos' toward left
                   (ignored if clearAll != false)
    
      Returns: 
         OK if successful
         ERR if invalid line index
    

    Clear from specified cursor position to end of line. Display is refreshed.



  • winPos GetCursor ( void );
      Input  : none
    
      Returns: a winPos class object containing the Y/X cursor position
    

    Get the window’s cursor position.



  • short SetCursor ( short ypos, short xpos );
  • short SetCursor ( winPos yxpos );
      Input  : 
         ypos : Y offset from upper-left corner (zero-based)
         xpos : X offset from upper-left corner (zero-based)
           OR
         yxpos: Y/X offset from upper-left corner (zero-based)
    
      Returns: 
         OK if successful
         ERR if parameter(s) out of range
    

    Set the window’s cursor position




NcWindow Keyboard Input

The meta-layer keyboard input method and the application-layer mouse interface are implemented in the NcWindow class to provide thread-safe operation. The mouse method group is directly inherited by the NcDialog class.

Please see GetKeyInput method for a description of the application-layer keyboard input method.

Please see Mouse Configuration for full descriptions and notes on configuring mouse input.



  • wkeyType GetKeyInput ( wkeyCode& wKey );
      Input  : wKey (by reference, initial values ignored)
               receives the key input data
      Returns: member of enum wkeyType
    

    Get a keycode and keytype from the input stream.
    This includes all supported international character codes as well as captured-and-translated escape sequences representing function keys, cursor keys and other special-purpose key combinations.

    If mouse input has been enabled, mouse events will also be returned in caller’s wkeyCode-class object’s ’mevent’ data member.

    • This method is the thread-safe version of the lower-level keyboard interface in the NCurses class.
    • In addition to the simple filtering of invalid input done by the NCurses-class version of this method, significant filtering of unrequested and/or broken mouse input is performed.


  • short meEnableStableMouse ( short dclick = ncmiSTABLE
                                bool swheel = true );

    Please see meEnableStableMouse method.


  • short meEnableMouse ( mmask_t eventTypes,
                          short interval=ncmiDFLT );

    Please see meEnableMouse method.


  • short meDisableMouse ( void );

    Please see meDisableMouse method.


  • bool meMouseEnabled ( void );

    Please see meMouseEnabled method.


  • short meSetEventTypes ( mmask_t eventTypes );

    Please see meSetEventTypes method.


  • short meGetEventTypes ( mmask_t& eventTypes );

    Please see meGetEventTypes method.


  • short meSetClickInterval ( short waitMax, short* oldMax=NULL );

    Please see meSetClickInterval method.


  • short meGetClickInterval ( short& waitMax );

    Please see meGetClickInterval method.


  • short meFlushEventQueue ( void );

    Please see meFlushEventQueue method.


  • short meAutoConvert ( bool enable );

    Please see meAutoConvert method.


  • short meAutoFilter ( bool filter );

    Please see meAutoFilter method.





NcWindow Data Scrolling

One of the basic methods for viewing and selection of data items is scrolling the items up and down in a window. The following methods implement the meta-layer of data scrolling. For application-layer scrolling, please refer to the NcDialog-class user-interface control objects:

see Scrollbox Controls
see Scrollext Controls
see Dropdown Controls
see Menuwin Controls

Note than an example of scrolling using the NcWindow methods can be found in Test03 of the Dialog1 test application.



  • short PaintData ( const char* dataPtr[], short count,
                      short hiliteIndex, attr_t color,
                      bool hilite=true, bool rtlFmt=false );
      Input  :
         dPtr   : pointer to an array of character pointers
         count  : number of data items
         hIndex : index of highlighted data item
         color  : text color attribute
         hilite : (optional, true by default)
                  hilight currently indexed item
         rtlFmt : (optional, false by default)
                  draw data as RTL (right-to-left) text
    
      Returns:
         index of currently highlighted data item
    

    Write into the window the display data to be scrolled and initialize the tracking variables. See also the ’RepaintData’ method.

    Note that the data item specified by the ’hIndex’ parameter is positioned as near to top of window as possible, even when withHilte==false. This guarentees that the specified item will be displayed when the window is first opened.

    This version of ’PaintData’ is for single-color data only (all data items are displayed in the same color).

    Note: It is assumed that the caller has properly sized the display strings to fit within the window’s width. If not, we may experience unsightly or uneven edges.



  • short PaintData ( const char* dataPtr[], const attr_t colorData[],
                      short count, short hiliteIndex, 
                      bool hilite=true, bool rtlFmt=false );
         dPtr   : pointer to an array of character pointers
         cPtr   : pointer to an array of (attr_t) color attributes
         count  : number of data items
         hIndex : index of highlighted data item
         hilite : (optional, true by default)
                  hilight currently indexed item
         rtlFmt : (optional, false by default)
                  draw data as RTL (right-to-left) text
    
      Returns:
         index of currently highlighted data item
    

    Write into the window the display data to be scrolled and initialize the tracking variables. See also the ’RepaintData’ method.

    Note that the data item specified by the ’hIndex’ parameter is positioned as near to top of window as possible, even when withHilte==false. This guarentees that the specified item will be displayed when the window is first opened.

    This version of ’PaintData’ is for multi-color data (one color per data item).

    Note: It is assumed that the caller has properly sized the display strings to fit within the window’s width. If not, we may experience unsightly or uneven edges.



  • short PaintMenuData ( const char* textData[], short count,
                          short hiliteIndex, attr_t color, 
                          bool hilite=true, bool rtlFmt=false );
      Input  :
         dPtr   : pointer to an array of character pointers
         count  : number of data items
         hIndex : index of highlighted data item
         color  : text color attribute
         hilite : (optional, true by default)
                  hilight currently indexed item
         rtlFmt : (optional, false by default)
                  draw data as RTL (right-to-left) text
    
      Returns:
         index of currently highlighted data item
    

    Write menu data including strings with hotkey indicators into a window to be scrolled, and initialize the scroll-tracking variables.

    This version of ’PaintMenuData’ is for single-color data only (all data items are displayed in the same color).

    Important Note: We do not make a local copy of the caller’s text strings because menu text can change dynamically based on action in the application code. Therefore, we use the actual application data each time this method is called.

    Note: This method scans the display strings for the hotkey character indicator ’^’ (caret) and displays the character that follows it with the Underline attribute.

    Note: It is assumed that the caller has properly sized the display strings to fit within the window’s width. If not, we may experience unsightly or uneven edges.



  • short PaintMenuData ( const char* textData[],
                          attr_t colorData[], short count,
                          short hiliteIndex,
                          bool hilite=true, bool rtlFmt=false );
      Input  :
         dPtr   : pointer to an array of character pointers
         cPtr   : pointer to an array of color attributes
         count  : number of data items
         hIndex : index of highlighted data item
         hilite : (optional, true by default)
                  hilight currently indexed item
         rtlFmt : (optional, false by default)
                  draw data as RTL (right-to-left) text
    
      Returns:
         index of currently highlighted data item
    

    Write menu data including strings with hotkey indicators into a window to be scrolled, and initialize the scroll-tracking variables.

    This version of ’PaintMenuData’ is for multi-color data (one color per data item).

    Important Note: We do not make a local copy of the caller’s text strings because menu text can change dynamically based on action in the application code. Therefore, we use the actual application data each time this method is called.

    Note: This method scans the display strings for the hotkey character indicator ’^’ (caret) and displays the character that follows it with the Underline attribute.

    Note: It is assumed that the caller has properly sized the display strings to fit within the window’s width. If not, we may experience unsightly or uneven edges.



  • void RepaintData ( bool hilite=true );
      Input  :
         hilite : (optional, true by default)
                  hilight currently indexed item
    
      Returns: nothing
    

    Redraw data controlled by the scrollData structure previously initialized through a call to ’PaintData’.

    Although ’RepaintData’ appears to do the same thing as the ’PaintData’ methods above, this method is much faster because the display data and tracking variables do not need to be range-checked and recalculated. It is assumed that all data members of the control structure are valid.



  • short EraseData ( void );
      Input  : none
    
      Returns: OK
    

    Erase currently displayed data and reset the tracking variables.

    Note that the display and color data belong to the application’s memory space; there is no memory allocated for it within the NcWindow class.



  • short ScrollData ( wchar_t scrollKey );
      Input  :
         scrollKey : key input (non-scroll-keys are ignored)
                     nckUP     = scroll up by one line
                     nckDOWN   = scroll down by one line
                     nckPGUP   = scroll up by one page
                     nckPGDOWN = scroll down by one page
                     nckHOME   = scroll to top of data
                     nckEND    = scroll to bottom of data
    
      Returns:
         index of currently highlighted data item
    

    Scroll the display data by one scrolling unit.

    If the target item is already visible in the window, then simply move the highligh to it. If the target item is not visible, then first re-index the list to bring the target item into the viewable area before positioning the highlight.



  • short ScrollMenuData ( wchar_t scrollKey );
      Input  :
         scrollKey : key input (non-scroll-keys are ignored)
    
      Returns:
         index of currently highlighted data item
         (if highlight moved, window is refreshed before return)
    

    Scroll through the items in a menu. Menu data may or may not have hot-key associations, indicated by the caret (’^’) before the character. If a caret is present in the data, the data are displayed with the character following the caret underlined to indicate the hot-key. See also PaintMenuData().

    Note that unlike regular scrolling display lists, menu data are all visible in the menu window. For this reason, only the highlight is moved. Scrolling the data elements up and down is not required.

    Note also that unlike regular scrolling display lists, if nckUP is pressed while highlight is on first item, highlight will wrap to the last item; and similarly, if nckDOWN is pressed while highlight is on last item, highlight will wrap to the first item.



  • short ScrollView ( wchar_t scrollKey );
      Input  :
         scrollKey : key input (non-scroll-keys are ignored)
    
      Returns:
         index of data item at top of window
    

    Scroll the disp display data by one scrolling unit.

    This method performs the same task as the ScrollData method above, EXCEPT that there is no visible highlight to indicate the current line.

    Because there is no visible highlight, the return value is the index of the item currently visible at the top of the window.



  • short GetHilightIndex ( void );
      Input  : none
    
      Returns:
         index of currently highlighted data item
    
    

    Returns the index of the currently-highlighted item in the scrolling-data array.



  • bool IsScrollKey ( wkeyCode wk );
      Input  :
         wk  : wkeyCode-class object containing 
               keycode and key classification
    
      Returns:
         returns true if a scroll key, else false
    

    Tests caller’s key datum to determine whether it is one of the scrolling keys, nckUP, nckDOWN, nckLEFT, nckRIGHT, nckHOME, nckEND, nckPGUP, nckPGDOWN.



  • void HilightItem ( bool show, bool refresh=false );
      Input  :
         show   : 'true' to add hilight, 'false' to remove hilight
         refresh: (optional, false by default)
                  if 'true', repaint the data and refresh the display
                             (highlight will be visible)
                  if 'false', then display is not updated,
                             (i.e. the changes are not yet visible)
    
      Returns: nothing
    

    Hilight or remove hilight from the display line referenced by the ’hIndex’ data member, i.e. the logically-highlighted item.

    Removing the highlight (un-hilighting) the data means drawing the data using the base color attribute for that line.

    Highlighting the data means TOGGLING the Reverse video (ncrATTR) bit of the base color attribute and then drawing the data. If the base color data for the string does not include the ncrATTR bit, then the data are drawn with ncrATTR SET. If the base color data for the string does include the ncrATTR bit, then the data are drawn with ncrATTR RESET.



  • short Track2Top ( bool refresh=false );
      Input  :
         refresh: (optional, false by default)
                  if 'true', repaint the data and refresh the display
                             (highlight will be visible)
                  if 'false', then display is not updated,
                             (i.e. the changes are not yet visible)
    
      Returns:
         index of the logically-highlighted item (i.e. ZERO)
    
    

    Move the logical highlight to the first item in window, and optionally update the display.

    If display ’refresh’ not specified, then call the ’RepaintData’ method to refresh the display and make the changes visible.



  • short Track2Bottom ( bool refresh=false );
      Input  :
         refresh: (optional, false by default)
                  if 'true', repaint the data and refresh the display
                             (highlight will be visible)
                  if 'false', then display is not updated,
                             (i.e. the changes are not yet visible)
    
      Returns:
         index of the logically-highlighted item
    

    Move the logical highlight to the last item in window, and optionally update the display.

    If display ’refresh’ not specified, then call the ’RepaintData’ method to refresh the display and make the changes visible.



  • short Track2Next ( bool refresh=false );
      Input  :
         refresh: (optional, false by default)
                  if 'true', repaint the data and refresh the display
                             (highlight will be visible)
                  if 'false', then display is not updated,
                             (i.e. the changes are not yet visible)
    
      Returns:
         index of the logically-highlighted item
    

    Move the logical highlight to the next (lower) item in window, and optionally update the display.

    If display ’refresh’ not specified, then call the ’RepaintData’ method to refresh the display and make the changes visible.



  • short Track2Previous ( bool refresh=false );
      Input  :
         refresh: (optional, false by default)
                  if 'true', repaint the data and refresh the display
                             (highlight will be visible)
                  if 'false', then display is not updated,
                             (i.e. the changes are not yet visible)
    
      Returns:
         index of the logically-highlighted item
    

    Move the logical highlight to the previous (higher) item in window, and optionally update the display.

    If display ’refresh’ not specified, then call the ’RepaintData’ method to refresh the display and make the changes visible.



  • short Track2Item ( short iIndex, bool refresh=false );
      Input  :
         iIndex : index of target item
         refresh: (optional, false by default)
                  if 'true', repaint the data and refresh the display
                             (highlight will be visible)
                  if 'false', then display is not updated,
                             (i.e. the changes are not yet visible)
    
      Returns:
         index of the logically-highlighted item
           If iIndex out-of-range, then index of currently-highlighted
           item is returned.
    

    Move the logical highlight to the specified item in window, and optionally update the display.

    If display ’refresh’ not specified, then call the ’RepaintData’ method to refresh the display and make the changes visible.




NcWindow Passthroughs

Pass-through methods to the NCurses class. These methods are fully described in the indicated chapter on the NCurses Engine. Please note however, that the NcWindow passthroughs are the thread-safe versions of the low-level methods.

  • wkeyType GetKeyInput ( wkeyCode& wKey );
  • wkeyType KeyPeek ( wkeyCode& wKey );
  • short UngetKeyInput ( wkeyCode& wKey );
  • short FlushKeyInputStream ( void );
    (see NCurses Keyboard Input)

  • ncCurVis GetCursorState ( void );
  • short SetCursorState ( ncCurVis state );
  • short RestoreCursorState ( void );
    (see NCurses Display Output)

  • void ScreenDimensions ( short& scrLines, short& scrColumns );
  • ncKeyProc GetKeyProcState ( void );
  • short SetKeyProcState ( ncKeyProc procState );
  • short GetKeyDelay ( void );
  • short SetKeyDelay ( short delay );
    (see NCurses Configuration)

  • void Hibernate ( void );
  • void Wake ( void );
  • const char* Get_NCurses_Version ( void );
  • const char* Get_nclibrary_Version ( void );
    (see NCurses Utility Methods)



NcWindow Utility Methods

  • const char* Get_NcWindow_Version ( void );
      Input  : none
      Returns: a const pointer to the class-version string
    

    Returns a pointer to NcWindowVersion, the NcWindow class version number.



  • void DebugMsg ( const char* msg, short startY = -1,
                    short startX=1, bool pause=false );
      Input  :
         msg    : pointer to null-terminated message string
         startY : Y cursor start position
                  (optional, default == -1, write to last line of window
         startX : X cursor start position
                  (optional, default == 1, write to 2nd column of window
         pause  : (optional, default==false)
      Returns: nothing
    

    Write a message to the current window and refresh the window.
    This method has some special properties that the WriteString() method does not.

    • The application’s cursor position is saved and then restored after the message is written to avoid interferring with the application flow.
    • The target line is cleared before the message is written.
    • Color attribute for the message is the window default color, but with ’Standout’ attribute added.
    • The method optionally waits for user to press a key.



NcWindow Hotkey Selection

A ’hotkey’ is a special key combination which is used as a shortcut access to a particular application function or information item. For instance, the 'F01' function key is traditionally used to invoke the application’s 'Help' information.

The NcWindow class implements hotkeys for window objects and for individual data items in menus. The NcDialog derived class builds on this basic hotkey functionality.

A complete discussion of using hotkeys may be found in the NcDialog chapter on hotkey definition and uses.
See Select Control via Hotkey.




NcWindow Thread Handling

The NcDialog API thread-safety mechanism is implemented in the NcWindow-class meta-layer. This thread-safe operation carries through all classes derived from the NcWindow class. For a full discussion of multithreaded access to the NcDialog API, please see Thread Safety.




NcDialog Class Definition

This chapter describes in detail the NcDialog class and the control objects with which a dialog-based application is populated.







NcDialog Class Overview

In previous chapters, we have examined the interface to the underlying ’ncursesw’ C-language library which implements the low-level curses interface for GNU/Linux systems.

In this chapter, we will describe the application layer interface. This is where the action is, and the information presented here provides nearly everything you need to create sophisticated, fast and bulletproof applications in a terminal environment.

We outline all the public methods of the NcDialog class, how they are used and when they are used. There is always a learning curve when working with a new tool, but we hope that once you have read this chapter, you will have no trouble easily and quickly building sophisticated applications without the kind of frustrating and time-consuming research which would be needed for some gigantic GUI API.

If you find that any of the concepts presented here are confusing or difficult to understand, please see Operational Overview for a review of basic concepts.


Eye Candy for Techies

We will present several screen captures for various dialogs and the controls they contain. We apologize that the Texinfo documentation system info-format document cannot render them in color, so some detail may be lost; but note that the HTML-format version of this document shows screen captures in eight(8) colors.

The screen capture below is the dialog we create in the chapter,
                  see Your First Application


╔══════════════════════╣ NcDialog - Our First Effort ╠═══════════════════════╗ Hello World! Favorite Linux flavor: Ubuntu! (Unity disabled)! Green Messages: [◆] Yellow Messages: [ ] My favorite Linux flavor is: Ubuntu! (Unity disabled)! DONE ╚══════════════════════════════════════════════════════════════════════════════╝

Note that the screen captures in this document use a simplified, but essentially accurate
color attribute map to compress the captured data. For details, see CSS for screenshots.





NcDialog Public Methods

        NcDialog Method Name            Chapter Reference    
 NcDialog [constructor] see Dialog Window Methods
 ~NcDialog [destructor] 
 OpenWindow 
 RefreshWin 
 ClearWin 
 SetDialogTitle 
 HideWin 
 MoveWin 
 SetDialogObscured 
 GetDialogPosition 
 GetDialogDimensions 
 EstablishCallback 
  
 NextControl see Using Dialog Controls
 PrevControl 
 GetCurrControl 
 ControlActive 
 ConnectControl2Border 
 DrawLabelsAsRTL 
 DrawContentsAsRTL 
  
 EditPushbutton see Pushbutton Controls
 SetPushbuttonText 
 EnablePushbuttonBorder 
  
 EditRadiobutton see Radiobutton Controls
 GetRadiobuttonState 
 SetRadiobuttonState 
 GroupRadiobuttons 
 GetRbGroupSelection 
 SetRbGroupSelection 
  
 EditTextbox see Textbox Controls
 SetTextboxText 
 GetTextboxText 
 FixedWidthTextbox 
 DisplayTextboxTail 
 DisplayTextboxMessage 
 VerifyTbText 
 TextboxAlert 
 Encode_URI 
 Decode_URI 
 SetTextboxCursor 
 SetTextboxReservedKeys 
 SetLocalClipboard 
 GetLocalClipboard 
 GetLocalClipboard_Bytes 
 GetLocalClipboard_Chars 
 SetTextboxInputMode 
 IsOverstrike 
  
 EditBillboard see Billboard Controls
 SetBillboard 
 GetBillboard 
 Append2Billboard 
 Insert2Billboard 
 ClearBillboard 
 GetBillboardColors 
 SetBillboardColors 
  
 EditScrollbox see Scrollbox Controls
 GetScrollboxSelect 
 SetScrollboxSelect 
  
 EditScrollext see Scrollext Controls
 ViewScrollext 
 GetScrollextSelect 
 SetScrollextSelect 
 SetScrollextText 
 RefreshScrollextText 
 MoveScrollextHighlight 
  
 Edit Dropdown see Dropdown Controls
 GetDropdownSelect 
 SetDropdownSelect 
  
 EditMenuwin see Menuwin Controls
 GroupMenuwinControls 
 AttachMenuwinSubmenus 
 HideMenuBar 
 ShowMenuBar 
 MenuBarVisible 
 PositionContextMenu 
 SetActiveMenuItems 
  
 EditSpinner see Spinner Controls
 GetSpinnerValue 
 SetSpinnerValue 
 SetSpinnerLimits 
  
 EditSlider see Slider Controls
 GetSliderConfig 
 SetSliderConfig 
 GetSliderValie 
 SetSliderValue 
 SliderAlert 
 SliderAutoReport 
  
 WriteString see NcDialog Display Output
 WriteChar 
 WriteParagraph 
 ClearLine 
 ClearArea 
 DrawLine 
 DrawBox 
 GetCursor 
 SetCursor 
 GetCursorState 
 SetCursorState 
 RestoreCursorState 
  
 GetKeyInput see Direct Keyboard Input
 KeyPeek 
 UngetKeyInput 
 FlushKeyInputStream 
 GetKeyProcState 
 SetKeyProcState 
 GetKeyDelay 
 SetKeyDelay 
  
 meEnableStableMouse see Mouse Configuration
 meEnableMouse 
 meDisableMouse 
 meMouseEnabled 
 meSetEventTypes 
 meGetEventTypes 
 meSetClickInterval 
 meGetClickInterval 
 meFlushEventQueue 
 meAutoConvert 
 meAutoFilter 
  
 wcbEnable see Clipboard Interface
 wcbDisable 
 wcbIsConnected 
 wcbGet 
 wcbSet 
 wcbClear 
 wcbytes 
 wcbTest 
 wcbReinit 
 wcbVersion 
 wcbUserAlert 
  
 ~WaylandCB see WaylandCB Public Methods
 WaylandCB 
 wcbIsConnected 
 wcbGet 
 wcbSet 
 wcbClear 
 wcbytes 
 wcbTest 
 wcbReinit 
 wcbVersion 
  
 InfoDialog see Utility Methods
 DecisionDialog 
 UserAlert 
 Hibernate 
 Wake 
 ShellOut 
 PseudoShell 
 ScreenDimensions 
 Get_NcDialog_Version 
 Get_NcWindow_Version 
 Get_NCurses_Version 
 Get_nclibrary_Version 
  
 Dump_uiInfo see Development and Debugging
 CaptureDialog 
 DisplayRadiobuttonTypes 
 DisplayAltCharacterSet 
 DisplayWideCharacterSet 
 DisplayLineDrawingSet 
 DisplayLineDrawingExamples 
 DebugMsg 



Dialog Window Methods

This chapter describes the NcDialog methods that affect the NcDialog-class object (dialog window) as a whole.

  • virtual ~NcDialog ();
      Input  : none
    
      Returns: nothing
    

    Destructor for an NcDialog object.
    Release all resources held by the dialog window and its associated control objects. Erase dialog from the display.



  • NcDialog ( InitNcDialog& dDef );
      Input  :
         dDef: a fully initialized InitNcDialog class object (by reference)
               See definition of InitNcDialog class for details.
    
      Returns:
         constructors implicitly return a pointer to the object
    

    Constructor for an NcDialog object.
    Creates an instance of the NcDialog class, initializes all public and private data members, and then calls the constructors for all specified dialog control objects.

    Important Note: Every effort is made to maintain the integrity of the dialog’s initialization parameters for future reference by the application-level code. However, certain critical errors in the initialization parameters, if found, will be automatically and silently corrected. The most critial is that the first dialog control in the array of control definitions must be set as ’active’, that is, it must be able to receive input focus.

    For a complete description of initialization data passed to the constructor, please see InitNcDialog class.

    For a complete description of how to define dialog control objects, please see InitCtrl class.



  • short OpenWindow ( void );
      Input  : none
    
      Returns:
         OK if successful
         else ERR 
           Note that most likely causes of error are:
           1. terminal screen too small to hold the window plus
              offsets from upper-left corner
           2. insufficient heap memory (unlikely)
    

    Allocate additional resources for a previously-instantiatiated dialog and draw the dialog and all its control objects in the terminal window.



  • void RefreshWin ( void );
      Input  : none
    
      Returns: nothing
    

    Refresh display of dialog window and all its controls.
    Any changes made to the dialog window or any of its control since the previous refresh will become visible.

    If the dialog had previously been marked as ’obscured’, re-draw the dialog using the saved image and then discard the saved image data. In the unlikey case that changes were made to the dialog window after the backup image was created, those changes will be lost.
    (See HideWin method.)



  • short ClearWin ( bool clearAll = false );
      Input  :
         clearAll: (optional, false by default)
                   if 'false' clear interior, leaving border
                   if 'true' clear entire window including border
    
      Returns: OK
    

    Erase (overwrite with spaces) contents of the window using the window’s background color. Does not refresh display.

    IMPORTANT NOTE: Please use extreme caution with this method!
    Please call the ’ClearWin’ method ONLY if there are no user-interface controls defined, or if only Pushbutton controls have been defined.

    Calling ’ClearWin’ when controls have been defined may have unexpected results, specifically, all control labels will disappear, and if specified, the border will also disappear. The controls themselves are self-contained, so calling ’RefreshWin’ will redraw the controls, but really, the dialog will have become useless to the user, so again: use caution!.

    Please see ClearLine method for a more controlled form of erasing data from the window.



  • short HideWin ( attr_t blankingColor=ZERO );
      Input  :
         blankingColor: (optional) specifies a background color to be
                        used for erasing the dialog window
                        default: use parent window's background color
     
      Returns: OK
    

    Hide the dialog window from view, that is, save its display data, then erase it from the screen.

    • If display data have not already been saved by a previous call to SetDialogObscured(), data will be saved before erase.
    • If application has already saved the display data through a previous call to SetDialogObscured(), just erase the dialog’s display data.
    • A call to RefreshWin() will make window visible again and release the saved data.


  • short SetDialogObscured ( void );
      Input  : none
    
      Returns: 
         OK if successful
         ERR if window data has already been saved
    

    Capture the dialog window display data and set the winObscured flag.

    The application should call this method in anticipation of the dialog being wholly or partially obscured by another object. Similar to HideWin() except that the dialog is not erased.

    Note that you must call this method BEFORE the dialog is actually obscured.



  • short MoveWin ( winPos& ulYX, bool relative=false );
      Input  : 
         ulYX    : Y/X offset of new position
         relative: (optional, false by default)
                   if 'true', coordinates are interpreted as an offset
                              from current dialog position.
                   if 'false', coordinates are interpreded as an offset
                              from upper left of terminal window.
    
      Returns: 
         OK if successful
            On successful return, the ulYX parameter has been updated
            with the previous coordinates of the dialog window.
         ERR if:
           1. window data has already been saved (see SetDialogObscured()).
           2. if the new position would place all or part of the dialog
              outside the terminal window's display area
           3. memory-allocation error
    

    Move the dialog window from its current position in the terminal window to the specified position.

    Note that this is not simply a matter of erasing the display data at the current position and displaying it somewhere else. Significant behind-the-scenes adjustments are made which cascade through all layers of code abstraction.

    See the test application Dialog1, Test08 for an example which uses this method.



  • winPos GetDialogPosition ( void );
      Input  : none
    
      Returns: Y/X window position
    

    Report the dialog window’s current position as an offset from the upper left corner of the terminal window. Please see winPos class for a description of the data returned.

    While the position of the dialog in the terminal window is generally fixed, some applications will find it convenient to allow the user to move the dialog window within the terminal window (see MoveWin method above). ’GetDialogPosition’ allow the application to determine the dialog’s current position.



  • void GetDialogDimensions ( short& dLines, short& dColumns );
      Input  :
         dLines : (by reference)
                   receives the number of display lines in dialog
         dCols  : (by reference)
                   received the number of display columns in dialog
    
      Returns: nothing
    

    Report the dialog window’s dimensions as the number of display lines and display columns.



  • winPos SetDialogTitle ( const char* dTitle,
                            attr_t cAttr=attrDFLT );
  • winPos SetDialogTitle ( const wchar_t* dTitle,
                            attr_t cAttr=attrDFLT );
  • winPos SetDialogTitle ( gString& dTitle,
                            attr_t cAttr=attrDFLT );
      Input  : 
         dTitle : title string
                  maximum character columns <= dialog width minus 4
                  (truncated if necessary to fit available display area)
                  title may be in UTF-8, wchar_t or gString format
         cAttr  : (optional, default: dialog's border color)
                  alternate color attribute for title text
    
      Returns:
         Y/X position for start of centered title
         (This return value is seldom useful, but see   )
         (the title of our FileMangler utility where the)
         (title and the menu bar share the same space.  )
    

    Create a centered title in line ZERO of the dialog window.

    If a title for the dialog window was not specified during instantiation (see InitNcDialog class), or if you wish to change the existing title, then a title may be specified for the dialog. It is customary (but not enforced) that one or two leading and trailing spaces be included in your title string for visual appeal.

    Note that if either the title or the dialog window require an odd number of display columns, then the centering may be off by one. (It’s algebra, not magic.)

    Note: While an existing title may be replaced using this method, try not to confuse the user. The most common replacement title would be to draw the same title text, but in a different color.

    Example:

    Line zero of a dialog which has no title:

    ╔════════════════════════════════════════════════════════╗

    dp->SetDialogTitle ( "   My Killer App   ", nc.reR ) ;

    Line zero of the dialog after inserting title:

    ╔══════════════════╣ My Killer App ╠═══════════════════╗



  • short EstablishCallback ( CUPTR methodname );
      Input  : 
         methodname: valid pointer to caller's method of the correct type
                     OR NULL pointer to disable existing callback
    
      Returns: OK
    

    Establish (or disable) a callback method that allows the mainline code to dynamically update the controls within the dialog window.

    The external method handles situations that the dialog code cannot. For example:

    • secondary validation of text data in a text box
    • manual update of non-active controls i.e. display-only controls that user can view, but cannot access.
    • Transfer of data to or from the system clipboard,
      but see Clipboard Interface.

    Example: . . . NcDialog* dp = new NcDialog ( dInit ); // Instantiate dialog window if ( (dp->OpenWindow()) == OK ) // Open dialog window { dp->RefreshWin () ; // Make everything visible dp->EstablishCallback ( &cbMethod ); . . . } //* This is the callback method * short cbMethod ( const short currIndex, const wkeyCode wkey, bool firstTime ) { if ( firstTime != false ) { // do stuff here... } // do stuff here... }

    See the Dialog1 test application for examples of how to establish and utilize callback methods. The callback for Test08 (T8_ControlUpdate method) is particularly exciting.


    The macro CUPTR defines the callback method reference used during the call to EstablishCallback. This macro is located in NcDialog.hpp.

    typedef short (*CUPTR)( const short currentIndex, 
                            const wkeyCode wkey, bool firstTime ) ;
    

    Programmer’s Note: Since C++11 it has been possible to specify a member method as a callback method; however, we have resisted using the std::function and std::bind functions, or the std::invoke (since C++17) functionality because it would break existing code. If we can find a way to do it transparently we will implement it in a future release.


    Notes on using a callback method:

    • Dialog must be instantiated (see NcDialog constructor) AND opened (see OpenWindow method) before calling the EstablishCallback method since the callback will be performed for the first time immediately after it is established.
    • The EstablishCallback method calls the specified method once with the parameter firstTime==true, to perform any required initialization. (wkey parameter will be meaningless for first call) Subsequently, the NcDialog class always calls with firstTime==false.
    • It is sometimes useful for the application to call the callback method directly, but you will need to fake the parameters carefully.
    • IMPORTANT NOTE: If caller passes an invalid method pointer to EstablishCallback, the application will immediately crash. So there!



Dialog Control Objects

A dialog control object is a logical device used for collecting input from the user and displaying information to the user. Several different types of controls are available, so you can present and collect information in the way that is most convenient for that type of information.







Using Dialog Controls

All methods and data of dialog control objects are private.
This ensures data integrity and robust code execution.

Access to the data and functionality of control objects is through NcDialog-class methods which carefully range check all input parameters and validate all data returned from the target control.

Most of the methods in this chapter apply only to one, specific control type. However, there are several configuration and navigation methods which apply to all (or multiple) control types. These are listed below.


Configuration Of and Navigation Among Control Objects

  • short NextControl ( void );
      Input  : none
    
      Returns: index of control which currently has the input focus
    

    Shift input focus to the next control in list.
    Note that only controls which are marked as ’Active’ may receive the input focus.

    When you create a list of control objects for the dialog (see InitCtrl class), they are instantiated as a linked list. This method allows the user to move to the next sequential control in the list.
    (See also the ’PrevControl’ method, below.)

    Note on focus latency: There is a timing latency between the moment that a control receives the input focus and the moment that your application calls the user-input method associated with that control. Normally, this latency will not be a problem, but good practice would indicate that you should call the appropriate user-input (Edit) method as soon as possible after the input focus has changed.



  • short PrevControl ( void );
      Input  : none
    
      Returns: index of control which currently has the input focus
    

    Shift input focus to the previous control in list.
    Note that only controls which are marked as ’Active’ may receive the input focus.
    (See also the ’NextControl’ method, above.)



  • short GetCurrControl ( void );
      Input  : none
    
      Returns: index of control which currently has the input focus
    

    Return the index of the control which currently has the input focus.

    Ideally, the application should track which control has the input focus through an index value in the user input loop, but sub-dialogs or other special operations may be unaware of this index, so this method is provided.



  • short ControlActive ( short cIndex, bool activate );
      Input  : 
         cIndex   : index of control to activate/deactivate
         activate : if true, activate the control 
                    if false, de-activate the control
    
      Returns: 
         OK if successful
         ERR if invalid index OR 
             if target control currently has input focus
    

    Activate or deactivate the specified control.
      a. If active, control can receive input focus.
      b. If inactive, control cannot receive input focus.

    On instantiation, each control may be declared Active or Inactive. During application execution, however, circumstances may arise where it does not make logical sense to allow the user to access a given control. Under these circumstances, the control may be deactivated, that is, it will still be visible in the dialog, but cannot obtain the input focus.

    Note: Billboard controls are defined as read-only (user may not modify them), and thus, may never be set as ’Active’.



  • short ConnectControl2Border ( short cIndex,
                                  cdConnect& connectPoints );
      Input  : 
         cIndex: index of target control
         connPoint: flags indicating which connections to make
    
      Returns: 
         OK if successful
         ERR if:
             a. invalid control index
             b. connection is not supported for target control type
    

    Connect the border of a dialog control object to the dialog window border.

    Visual connection does not alter the behavior of the control in any way; it is just visually pleasing at times to integrate display of a control and the dialog border.

    Note that not all controls have borders AND that not all controls are allowed to extend into the parent window’s border. Currently, only dctSCROLLBOX and dctSCROLLEXT controls may be connected to the parent dialog’s border.

    Note that this method does not validate the actual position of the control relative to the parent dialog’s border, but instead, assumes that you know what you’re doing. Please see cdConnect class for additional information.

    This is an example of a Scrollbox control in the upper left corner of a dialog window, before and after the call to ConnectControl2Border. This example is excerpted from the test application Dialog2, Test02.
    Notice that the example on the right shows that the upper-right and lower-left corners of the control have been integrated into the dialog border.

    ┌──────────────┐───>       ┌──────────────┬───> Test Data #000│ >       Test Data #000│ > Test Data #001│ <       Test Data #001│ < Test Data #002│ >       Test Data #002│ > Test Data #003│ <       Test Data #003│ < Test Data #004│ >       Test Data #004│ > Test Data #005│ <       Test Data #005│ < Test Data #006│ >       Test Data #006│ > Test Data #007│ <       Test Data #007│ < └──────────────┘ <       ├──────────────┘ < │ Control #1 >       │ Control #1 > │ <       │ <


  • short DrawLabelsAsRTL ( bool rtlFormat=true );
      Input  : 
         rtlFormat : (optional, 'true' by default)
                     draw all labels and title as RTL
    
      Returns: OK
    

    Specify that when the dialog is opened, all control labels and the dialog title should be interpreted as RTL (right-to-left) language text.

    • By default, all control labels and the dialog title (if specified) are interpreted as LTR (left-to-right) language text.
    • To draw labels and title as RTL language text, this method must be called AFTER dialog instantiation but BEFORE the call to OpenWindow().
    • NOTE: Normally, it would make no sense to call with rtlFormat==false because this would have no effect on labels or title which have already been written into the dialog’s display space. However, calling with rtlFormat==false would allow any SUBSEQUENT calls to SetDialogTitle() to be interpreted as LTR text.

    Sreenshot see RTL text character order shows an example dialog with control object labels drawn in an RTL language (Yiddish).



  • short DrawContentsAsRTL ( short cIndex, bool rtlFormat=true );
      Input  : 
         cIndex   : index of control for which to enable/disable RTL 
                    content formatting
         rtlFormat: (optional, true by default)
                    if true, output control contents as RTL text
                    if false, output control contents as LTR text
    
      Returns:
         OK if successful
         ERR if invalid index OR if specified format cannot be applied 
             to target control.
             a) Not applicable for dctSPINNER and dctRADIOBUTTON controls 
                (spinners contain only ASCII numeric text)
                (radio buttons contain only single-character symbols)
             b) For controls with static contents format may only be set
                before display is drawn for the first time.
             c) For dctTEXTBOX controls: formatting may not be changed if
                control currently has the input focus.
             d) For dctMENUWIN controls: formatting may not be changed if
                control is currently in the 'expanded' state.
    

    Enable (or disable) drawing/redrawing the contents of the control object as RTL-language text. Does not refresh display.

    • By default, contents of all controls are interpreted as LTR (left-to-right) language text.
    • For RTL languages, it is strongly recommended, though not enforced, that this method be called BEFORE the first time dialog display is refreshed (see above for error conditions returned).
    • Normally, there will be no need to call this method a second time for a particular control; however, for some control types, it may be theoretically useful to toggle between RTL and LTR data--for example, to shift contents of a control to a different language. Toggling between RTL and LTR formatting is supported for controls whose contents can be dynamically updated:
      dctPUSHBUTTON, dctTEXTBOX, dctBILLBOARD, dctSCROLLEXT and dctMENUWIN.

    Sreenshot see RTL text character order shows an example dialog with contents of control objects drawn in an RTL language (Yiddish).




Pushbutton Controls

The DialogPushbutton-class user interface controls allow the user to select the activity the Pushbutton represents.

Please see InitCtrl class for information on defining and creating a DialogPushbutton-class user interface control.



  • short EditPushbutton ( uiInfo& info );
      Input  :
         info : uiInfo class (by reference) - initial values ignored
                (see description of uiInfo class for values returned)
    
      Returns: 
         index of control that currently has the input focus
    

    If the control with input focus is of type dctPUSHBUTTON, call this method to get user’s key input.

    The EditPushbutton method retains control of input until:

    • ENTER or SPACE key pressed.
      User has ’pressed’ (activated) the Pushbutton.
    • TAB, SHIFT+TAB, LEFT_ARROW, RIGHT_ARROW,
      UP_ARROW or DOWN_ARROW key pressed.
      Control is returned to the application, and the Pushbutton has not been ’pressed’ (’dataMod’ == ’false’).

      Note that the interpretation of navigation keys:
      nckTAB, nckRIGHT and nckDOWN will cause a subsequent move to the next control, while nckSTAB, nckLEFT and nckUP will cause a subsequent move to the previous control. While this is entirely logical, it may not be entirely intuitive to the user, since the physical layout of the controls on the screen may not coincide with these directions. This is a minor, but annoying design issue to be kept in mind when positioning your controls within the dialog window.

    • A ’Hotkey’ combination has been detected.
      The edit is complete. If the Hotkey belongs to the current control, it is processed like the ENTER key.

      Otherwise, the input focus has been shifted to another control object, and the Pushbutton has not been ’pressed’ (’dataMod’ == ’false’).

    • The nckESC (Escape) key pressed.
      It is assumed that the user is in panic mode. Control is returned to the application as if the user had pressed the nckTAB key.

    Please see uiInfo class for a discussion of the values returned from the Edit method.



  • short SetPushbuttonText ( short ctrlIndex,
                              const char* pbText,
                              attr_t fAttr=attrDFLT,
                              attr_t nAttr=attrDFLT );
      Input  : 
         cIndex: index into array of dialog controls
         pbText: pointer to new text data
         fAttr : (optional) if specified, replaces the color attribute for
                 the control when it has input focus
         nAttr : (optional) if specified, replaces the color attribute for
                 the control when it does not have input focus
    
      Returns: 
         OK if successful
         ERR if specified control is not of type dctPUSHBUTTON
    

    Set the display text and optionally the color attributes for a dctPUSHBUTTON control, and refresh the control’s display.

    This is useful for changing the text each time the button is pressed, for example: ’ENABLE’ vs. ’DISABLE’.

    Style Note: If you specify a ’hotkey’ in the text string for the control, good style would indicate that a given control should always have the same hotkey. This is not enforced, but is highly recommended.

    See the test application Dialog2, Test04 for an example of using this method.



  • short EnablePushbuttonBorder ( short cIndex,
                                   ncLineType style=ncltSINGLE );
      Input  : 
         cIndex: index into array of dialog controls
         style : (optional, 'ncltSINGLE' by default)
                 If specified, border style is a member of enum ncLineType.
    
      Returns: 
         OK if successful
         ERR if specified control is not of type dctPUSHBUTTON
             OR if control is too small to have a border
    

    Enable display of a border around a dctPUSHBUTTON control.

    • By default, pushbutton controls have no border.
    • Pushbutton controls defined with less than three (3) display lines or less than three (3) columns NEVER have a border.
    • A border for pushbutton controls defined with >= 3 display lines/columns MAY be specified.
    • Display text for the control should reflect whether the border is activated. With border, the display text is automagically offset to avoid overwriting the border.
      Example: For a 3-line, 8-column control with "OK" centered in it: If no border: const char* txt = " \n OK " ; With border : const char* txt = " OK " ;
    • Aesthetically, if the border is to be enabled, it should happen before the first call to ’RefreshWin’, however, this is not enforced.

    See the test application Dialog1, Test07 for further explanation.




Radiobutton Controls

The DialogRadiobutton-class user interface controls allow the user to select between binary options: On and Off, Yes and No, Active and Inactive. Radiobutton controls may also be grouped to form an ’Exclusive OR’ selection, that is exactly one(1) of the options in the XOR group is active at any given time.

Please see InitCtrl class for information on defining and creating a DialogRadiobutton-class user interface control.



  • short EditRadiobutton ( uiInfo& info );
      Input  :
         info : uiInfo class (by reference) - initial values ignored
                (see description of uiInfo class for values returned)
    
      Returns: 
         index of control that currently has the input focus
    

    If the control with input focus is of type dctRADIOBUTTON, call this method to get user’s key input.

    Allows user to edit the state of an independent Radio Button or the selection within a Radio Button group.

    The EditRadiobutton method retains control of input until:

    • For Independent Radiobuttons:
      • SPACE key pressed.
        The state of the control has been toggled and the ’dataMod’ flag of the returned data is returned as ’true’.
      • ENTER key pressed.
        The state of the control has been set and the ’dataMod’ flag indicates whether the state of the control has been modified.
      • TAB, SHIFT+TAB, LEFT_ARROW, RIGHT_ARROW,
        UP_ARROW or DOWN_ARROW key pressed.
        Control is returned to the application, and the state of the Radiobutton has not changed (’dataMod’ == ’false’).
      • A ’Hotkey’ combination has been detected.
        The edit is complete. If the Hotkey belongs to the current control, it is processed like the ENTER key.

        Otherwise, the input focus has been shifted to another control object, and the state of the Radiobutton has not changed (’dataMod’ == ’false’).

      • The nckESC (Escape) key pressed.
        The Escape key makes no sense in this context, so it is converted to the nckTAB key.
    • For XOR Group of Radiobuttons:
      • ENTER KEY or SPACE key pressed.
        The state of the control has been set, the input focus has been shifted to the last member of the XOR group, and the ’dataMod’ flag indicates whether the ’selected’ member of the group has been changed.

        Note: To determine whether the user has re-selected the original item, check for the Enter key using the following test:

           if ( Info.dataMod != false || Info.keyIn == nckENTER )
           {
              // do stuff here...
           }
        
      • TAB, RIGHT_ARROW or DOWN_ARROW key pressed.
        If the input focus is already on the last member of the XOR group, then control is returned to the application with (’dataMod’ == ’false’).

        If the input focus is not yet on the last member, then focus is moved to the next member and the edit continues.

      • SHIFT+TAB, LEFT_ARROW or UP_ARROW key pressed.
        If the input focus is already on the first member of the XOR group, then control is returned to the application with (’dataMod’ == ’false’).

        If the input focus is not yet on the first member, then focus is moved to the previous member and the edit continues.

      • A ’Hotkey’ combination has been detected.
        The edit is complete. If the Hotkey belongs to a member of the current XOR group, then it is processed like the ENTER key.

        Otherwise, the input focus has been shifted to a control object outside the current group, and the ’selected’ member of the group has not changed (’dataMod’ == ’false’).

      • The nckESC (Escape) key pressed.
        The input focus is moved to the last member of the XOR group, and control is returned to the application with (’dataMod’ == ’false’).

    Please see uiInfo class for a discussion of the values returned from the Edit method.



  • short SetRadiobuttonState ( short ctrlIndex, bool select );
      Input  :
         cIndex: index into array of dialog controls
         select: new state of 'selected' flag
    
      Returns:
         OK  if successful
         ERR if:
             a. specified control is a member of a radiobutton group
                (use 'SetRbGroupSelection' method instead)
             b. specified control is not of type dctRADIOBUTTON
    

    Set or reset the ’selected’ flag of the specified, independent Radiobutton control, and refresh the control’s display.

    Sometimes it is convenient to programatically change the state of a Radiobutton control, rather than leaving its state entirely to the user. For instance, several of the NcDialog API’s test methods include a read-only Radiobutton control which dynamically tracks the state of the Insert/Overstrike flag for the mode of text input. Other examples would be reporting whether a printer is online or whether a removable media device is currently mounted.



  • short GetRadiobuttonState ( short ctrlIndex, bool& select );
      Input  :
         cIndex: index into array of dialog controls
         select: (by reference, initial contents ignored)
                 receives current state of 'selected' flag
    
      Returns:
         OK  if successful
         ERR if specified control is not of type dctRADIOBUTTON
    

    Return the current state of the ’selected’ flag for the specified Radiobutton control.



  • short GroupRadiobuttons ( short indexList[] );
      Input  :
         indexList : array of control index numbers (-1 ends list)
    
      Returns:
         OK  if successful
         ERR if:
             a. if list references a control which is not 
                a dctRADIOBUTTON object
             b. if list contains an invalid control index
    

    Establish a group of DialogRadiobutton-class objects as an exclusive-OR group. Within this group, exactly ONE radio button may be ’selected’ by the user.

    The ’indexList’ parameter is an array of index numbers for the DialogRadiobutton objects in the group. Terminate the list with a negative 1 (-1).
    Example:  short List[] = { 4, 5, 6, -1 };

    Note: The specified indices should be sequential, although this is not enforced. Non-consecutive indices may produce anomolous behavior.



  • short GetRbGroupSelection ( short cIndex );
      Input  :
         cIndex : index of any Radiobutton control in
                  the target button group
    
      Returns:
         index of 'selected' control of the group
         returns ERR if:
             a. referenced control is not a member of a Radiobutton group
             b. specified control is not of type dctRADIOBUTTON
    

    For the Radiobutton group of which the specified radio button control is a member, determine which button in the group is currently ’selected’. Note that exactly one member of a radio button group is ’selected’.



  • short SetRbGroupSelection ( short cIndex );
      Input  :
         cIndex : index of control to be set as 'selected'
    
      Returns:
         index of 'selected' group member
         returns ERR if:
             a. referenced control is not a member of a Radiobutton group
             b. specified control is not of type dctRADIOBUTTON
    

    Set the ’selected’ control of a Radiobutton group.
    The previously-selected group member will be reset.




Textbox Controls

The DialogTextbox-class user interface controls allow the user to enter text data. Textbox controls may also be configured to display temporary messages without disturbing the underlying data.

Textbox controls may be of any reasonable height and width, and have a data capacity of gsMAXBYTES (approximately four kilobytes).

Textbox controls accept both Left-To-Right (LTR) input and Right-To-Left (RTL) input, as well as right-justified input.

Please see InitCtrl class for information on defining and creating a DialogTextbox-class user interface control.



  • short EditTextbox ( uiInfo& info );
      Input  :
         info : uiInfo class (by reference) - initial values ignored
                (see description of uiInfo class for values returned)
    
      Returns: 
         index of control that currently has the input focus
    

    If the control with input focus is of type dctTEXTBOX, call this method to get user’s key input.

    The EditTextbox method retains control of input until:

    • ENTER, TAB or SHIFT+TAB key pressed
      Indicates that edit is complete, and the ’dataMod’ flag of the returned data indicates whether the text data have been modified.
    • The DOWN_ARROW or UP_ARROW key has been pressed.
      For single-line Textboxes, these keys are equivalent to the TAB and SHIFT+TAB keys, respectively.

      For multi-line Textboxes, the action of the DOWN_ARROW key depends upon the current insertion point (text cursor) and whether the end of the string is currently visible.
      If the insertion point is on the last line of the control and the end of the string is visible, DOWN_ARROW is equivalent to the TAB key. Otherwise, the insertion point is moved downward and the edit continues.

      For multi-line Textboxes, the action of the UP_ARROW key depends upon the current insertion point (text cursor) and whether the beginning of the string is currently visible.
      If the insertion point is on the first line of the control and the beginning of the string is visible, UP_ARROW is equivalent to the SHIFT+TAB key. Otherwise, the insertion point is moved upward and the edit continues.

    • A ’Hotkey’ combination has been detected.
      If the Hotkey belongs to the current control, it is ignored, and the edit continues.

      Otherwise, the edit is complete and the input focus has been shifted to another control. The ’dataMod’ flag of the returned data indicates whether the text data have been modified.

    • ESCAPE key pressed
      Any changes to the data will be discarded and the previous contents of the control will be restored (’dataMod’ == ’false’).

    Textbox Navigation Keys

    Moving the cursor (insertion point) within a Textbox control uses the standard navigation keys:
    RightArrow, LeftArrow, UpArrow, DownArrow, Home, End
    As expected, their function is the same as in a text editor or in LibreOffice(tm). The Backspace and Delete keys also perform their normal functions. The Delete key may also be used to delete any currently “selected” text.
    Please see SetTextboxReservedKeys method for a discussion of the keys used for selecting text and for moving data to and from the clipboard.

    Editing text within a Textbox control is a complex operation, including:

    • control configuration for LTR, RTL or right-justified input
    • direct user input
    • use of an IME as an input tool
    • application of the input filter specified for the control
    • insert/overstrike input mode
    • copying data to and from the system clipboard
      (see Clipboard Interface for more information)
    • buffer limits (normally not a problem)
    • possible text pre-formatting issues

    Please study carefully the Textbox configuration options described below, and familiarize yourself with editing text data by experimenting with Textbox controls defined in the various test applications. Dialogw, Test10 would be a good place to start.

    Please see uiInfo class for a discussion of the values returned from the Edit method.



  • short SetTextboxText ( short cIndex, const char* uPtr );
  • short SetTextboxText ( short cIndex, const wchar_t* wPtr );
  • short SetTextboxText ( short cIndex, const gString& gsData );
      Input  : 
         cIndex : index of target dctTEXTBOX control
         uPtr   : pointer to new display data in UTF-8 format
              OR
         wPtr   : pointer to new display data in wchar_t format
              OR
         gsData : gString object (by reference) containing the new text
    
      Returns: 
         number of characters in string including the NULLCHAR
         returns ERR if:
            a. data filter detected an invalid character
            b. specified control currently has input focus
            c. specified control is not of type dctTEXTBOX
    

    Replace current textbox data, if any, with specified data.

    Internally, all data are handled as wchar_t type (’wide’) characters, and the limits described below refer to wchar_t storage.

    Text data provided may be longer than control width up to gsMAXCHARS. If source data > gsMAXCHARS, it will be silently truncated to gsMAXCHARS.

    • For single-line textbox controls:
      If horizontal shifting is disabled, text will be silently truncated to the width of control.
    • For multi-line textbox controls: If horozontal shifting is disabled, text will be silently truncated to the size of the control, which is calculated as: (display lines * display columns).
    • Applying the specified text filter:
      • All non-printing control characters (0x01 - 0x1F) will be silently stripped from the display text BEFORE the specified text filter is applied.
      • If the text filter encounters an invalid character, the operation will fail, and the control’s contents will be set to the NULL string.


  • short GetTextboxText ( short cIndex, char uPtr[gsMAXBYTES] );
  • short GetTextboxText ( short cIndex, wchar_t wPtr[gsMAXCHARS] );
  • short GetTextboxText ( short cIndex, gString& gsData );
      Input  : 
         cIndex : index of target dctTEXTBOX control
         uPtr   : pointer to UTF-8 target buffer
                  (length of gsMAXBYTES recommended)
              OR
         wPtr   : pointer to wchar_t target buffer
                  (length of gsMAXCHARS recommended)
              OR
         gsData : gString object (by reference) to receive text
    
      Returns: 
         length of the text string
            a. if target buffer is a UTF-8 buffer: returns 
               the number of bytes in string including NULLCHAR
            b. if target buffer is a wchar_t buffer or a 
               gString object: returns the number of characters
               in string including NULLCHAR
         returns ERR if:
            specified control is not of type dctTEXTBOX
    

    Returns a copy of the text data contained in the specified Textbox object.

    It is the caller’s responsibility to provide a buffer large enough to hold the text data. To avoid the possibility of buffer overrun—it is recommended that a gString object be specified as the target buffer.



  • short FixedWidthTextbox ( short cIndex, bool enable );
      Input  : 
         cIndex : index of target dctTEXTBOX control
         enable : if 'true' allow 'EditTextbox' method to shift data
                   left/right for text longer than control width.
                  if 'false' display data width is limited to the 
                   width of the field
                   (data will not be scrolled left and right)
    
      Returns: 
         OK if successful
         ERR if:
            a. target control currently has input focus
            b. width of target control is less than MIN_TB_SHIFT_WIDTH
            c. target control is configured for right-justified input
            d. target control is a multi-line Textbox
            e. specified control is not of type dctTEXTBOX
    

    Set specified dctTEXTBOX control as a fixed-width field.
    OR
    Reset specified control from a fixed-width field to an extended-text field.

    Notes:

    • Specified control
      • must be defined as a single-line control
      • must be defined with >= MIN_TB_SHIFT_WIDTH columns
      • must be configured for LTR or RTL input
      • must not currently have the input focus
    • Extended text is text that may be wider than the display field width and and will be horizontally shifted as necessary for visibility during editing.

      When extended text data is enabled, the text may expand during editing to gsMAXCHARS characters (approx. gsMAXCHARS*2 columns) even though all the text may not be simultaneously visible.

    • In a fixed-width field, the text may never be wider than the field. That is, the number of text columns may never exceed the number of columns defined for the control.
    • All Textbox controls defined with >= MIN_TB_SHIFT_WIDTH columns are extended-text fields by default. Extended text may be disabled or re-enabled for controls that meet the above criteria.

      IMPORTANT NOTE: When a control is set to fixed-width, any existing text is truncated to fit the width of the field.

    • Textbox controls which are configured for right-justified input are always fixed-width fields.
    • Textbox controls defined with < MIN_TB_SHIFT_WIDTH columns, are always fixed-width fields.


  • short DisplayTextboxTail ( short cIndex );
      Input  :
         cIndex : index of target dctTEXTBOX control
    
      Returns: 
         OK if successful
         returns ERR if:
            a. target control currently has input focus
            b. target control is configured for right-justified input
            c. target control is configured with horizontal shift disabled
            d. specified control is not of type dctTEXTBOX
    

    Re-display the contents of the specified dctTEXTBOX control so that the last character of the data is visible.

    This is useful for display of path/filename strings or other text where it is advantageous for the user to see the the tail of the string. This method does not modify the contents of the textbox in any way; it temporarily displays the text with the last character at the end of the field (lower right corner for LTR text or lower left corner for RTL text).

    If the entire string is already visible in the control, OR if the specified control currently has the input focus, then no action will be taken.

    Note that internally, this method calls ’DisplayTextboxMessage’ (see below), but does the shift calculation for you. (You’re welcome!)



  • short DisplayTextboxMessage ( short cIndex, dtbmData& uData );
      Input  : 
         cIndex : index of target dctTEXTBOX control
         uData  : initialized dtbmData class object
    
      Returns: 
         OK if successful
         returns ERR if:
            a. message too long for control
               (message will be displayed, but truncated)
            b. target control currently has input focus
            c. specified control is not of type dctTEXTBOX
    

    In addition to collecting user input, a Textbox control may also be used as a message display area. Use this method to display a single-color or multi-color message in a Textbox control. The message is not saved, merely written to the display area. Any existing text data in the control is unchanged, but is temporarily obscured.

    Notes on passing message data to the Textbox

    Please see dtbmData class for information on the initialization constructors for this class.

    Use a dtbmData-class object for passing data to this method.

    1. ’textData’ member
      receives the text to be displayed (UTF-8 format).
      • The text input filter defined for the target control is ignored by this method.
      • Because automatic line wrap is not performed by this method, it is recommended that for multi-line target controls. line breaks (’\n’) be used to pre-format the data. (Line breaks are ignored for single-line controls.)
      • To erase the message and redisplay the contents (if any) of the control object, call this method with ’textData’ set to an empty string ( "" ).
    2. ’colorData’ member
      specifies the color attribute(s) of the text
      • If colorData[0] == ’dtbmNFcolor’, (default), then text will be displayed in the non-focus color defined for the text box.
      • If colorData[0] == ’dtbmFcolor’, then text will be displayed in the focus color defined for the text box.
      • Otherwise an array of color attributes is expected, and a bit of experimentation may be needed to achieve the desired result.
      • Each character in textData (including any newline characters) should have a corresponding color attribute.
      • Note that if the text is to be ’centered’, AND if colorData[0] DOES NOT contain one of the special attributes described above, then the ’colorData’ array must contain at least as many attributes as the number of character columns defined for the control (plus newlines). In general, this is:
        attributeCount = lines * columns + lines ;
    3. ’refreshControl’ member
      ’true’ by default. Indicates whether the display should be refreshed immediately.
    4. ’centered’ member
      ’false’ by default.
      • If ’false’, the text is written as provided.
      • If ’true’, then each line of text will be horizontally centered in the field.
    5. ’rtlText’ member
      ’false’ by default.
      • If ’false’, the text is processed as LTR (left-to-right) data.
      • If ’true’, the text is processed as an RTL (right-to-left) language (Arabic, Hebrew, Persian, Urdu, etc.).


  • short VerifyTbText ( short cIndex, char* uStr, tbChars filter );
  • short VerifyTbText ( short cIndex, wchar_t* wStr, tbChars filter );
  • short VerifyTbText ( short cIndex, gString& gStr, tbChars filter );
      Input  : 
         cIndex : index of target dctTEXTBOX control
         uStr   : text data to be verified in UTF-8 format
                  (Recommend that uStr be at least gsMAXBYTES)
              OR
         wStr   : text data to be verified in wchar_t format
                  (Recommend that wStr be at least gsMAXCHARS in size)
              OR
         gStr   : text data to be verified contained in a gString object
         filter : member of enum tbChars, indicates which filter to apply
    
      Returns: 
         OK  if all characters match filter criteria
             Note: Some filters such as upper/lower case will adjust
                   the provided source data to match filter criteria.
         ERR if data filter detected an invalid character
             (original data unchanged)
             OR specified control is not of type dctTEXTBOX
    

    Verify that a text string meets the specified filtering criteria for strings created or displayed in the target Textbox control. The filter to be applied may either be the same filter previously established for the Textbox control, or may be a differet filter.

    Use before pre-loading a text box with string data or to apply a secondary filter to edited data. (target Textbox data and configuration are not modified.)

    Please refer to 'enum tbChars' for a complete list of available text filters.



  • short TextboxAlert ( short cIndex, bool enable );
      Input  :
         cIndex : index of target dctTEXTBOX control
         enable : 'true'  to enable audible alerts
                  'false' to disable audible alerts
    
      Returns:
         OK if successful
         ERR if specified control is not of type dctTEXTBOX
    

    Enable or disable audible alert (beep) for invalid characters received during edit of Textbox data. An invalid character in this context is any keycode that is not recognized OR that has been filtered out by the active input filter associated with the control.

    Audible alert is initially disabled, and may be enabled after instantiation of the control. The alert mechanism is a call to the ’UserAlert’ method (with no parameters) as described in see UserAlert method..



  • short EscapeLinuxSpecialChars ( gString& pathSpec );
      Input  :
         pathSpec: (by reference) string to be scanned 
                   (usually a filename or path specification)
    
      Returns:
         number of characters 'escaped'
    

    For string data which contain special Linux reserved characters which are interpreted by the shell program as shell instructions, “escape” each special character so the shell will interpret the character as plain text.
    The Linux special characters are:

    ' " ? : ; & > < | * \

    Character escaping is used primarily when passing filenames or path specifications to the shell or to invoke a shell program, ensuring that the shell does not misinterpret the received command.

    To “escape” a character, a backslash character ( '\' ) is inserted before that character.

    Example, A filename of: When She’s Gone - Hootie & the Blowfish.oga becomes: When She\’s Gone - Hootie \& the Blowfish.oga

    Important Note: Any previously-escaped characters will be ignored.

    For more information on the use of Linux special characters in filenames, please see Special Characters.



  • bool Encode_URI ( gString& gStr );
  • bool Decode_URI ( gString& gStr );
      Input  : 
         gStr : (by reference) data string to be encoded/decoded
      Returns: 
         'true' if all characters match tbURL filter criteria
         'false' otherwise
    

    NOTE: THIS PAIR OF METHODS IS NOT YET IMPLEMENTED.

    Encode a raw, unencoded URI/URL sequence, or Decode an encoded URI/URL sequence into its raw text form using the RFC 3986 standard or its successors.

    For unambiguous internet addresses (URI/URL), spaces and other characters which may be misinterpreted by the routing software may be encoded to avoid confusion. The internet standard, RFC 3986 specifies how these addresses should be encoded/decoded.

    If you collect a URI/URL from the user, it is recommended that you use this encoding scheme before pasting the address into a browser, FTP server or other routing software. Conversely, the encoding is not people-friendly, so if you want to display a URI/URL address to the user, it may be useful to decode it into plain text before display.



  • short SetTextboxCursor ( short cIndex, short offset );
      Input  : 
         cIndex : index number of text box control
         offset : member of enum tbCurPos (see below)
                  -OR- character offset at which to set the cursor
                       Range ZERO <= offset < number of text characters
                       in data (not incl NULLCHAR)
      Returns: 
         OK if successful
         ERR if:
            a. specified position is out of range
               - if 'offset' > End-Of-Data, then cursor set at 'append'
            b. specified member of enum tbCurPos is not applicable
            c. specified text box currently has input focus
               (a control may not be reconfigured while it has focus)
            d. specified control is not of type dctTEXTBOX
    

    Configure the way the target control accepts and displays text input during editing.
    OR
    Set the cursor position over the specified character of the text string.

    Configuring the dctTEXTBOX control for editing style

    Configuration style is specified by specifying a member of enum tbCurPos as the ’offset’ parameter.

    • tbcpHOME : Set the cursor on the first character of the text data.
      • For controls previously configured as LTR (left-to-right), this will be the top left corner. Note: LTR is the default editing style.
      • For controls previously configured as RTL (right-to-left), this will be the top right corner.
      • Not applicable if control configured as right-justified
      • Ignored if control contains no data.
    • tbcpAPPEND: Set the cursor to the ’append’ position just past the last character of text data, so that the next character entered will be appended to the end of the existing text.
      • Not applicable if control configured as right-justified
      • Ignored if control contains no data.
    • tbcpRIGHTJUST: Configure the target control for right-justified editing. The cursor is fixed at the right edge of the field, and as text is entered, existing data are shifted left to make room for the new character.
      • Note: Right-justified editing is available ONLY for single-line controls.
      • Note: Right-justified text cannot grow beyond the width of the control. If existing data are wider than control when this parameter is specified, then data will be truncated to fit the field.

      Note: Right-justified input is not the same as RTL-language input. For right-justified input, existing text is shifted left with each new character entered, and the new character is inserted at the right edge of the field.


    Setting a specific cursor position

    • Set the cursor at the specified offset into the text data.
    • Note that because text data may contain multi-column characters, the actual cursor position MAY NOT be specified directly. The cursor position specified is interpreted as the character offset into the text string and the cursor will be set over that character.
    • Does not immediately modify position of the visible cursor. The change becomes visible when control receives input focus.


  • short SetTextboxReservedKeys ( reservedKeys& rkeyList );
      Input  : 
         rkeyList : (by reference)
                    an initialized list of keycodes to be reserved
                    -- to re-enable any previously-reserved keycodes
                       call with rkeyList.reserve == false
      Returns:
         OK if successful
         ERR otherwise
    

    Specifiy a list of keycodes reserved by the application for use in ‘selecting’ text, and for Copy/Cut/Paste operations to the Textbox Local clipboard from within the EditTextbox() method.

    The user will be able to select, copy, cut and paste text ONLY if you have defined this set of keycodes.


    Specifying Keycodes for Clipboard Access

    1. To provide the application designer with maximum flexibility, we have made the design decision not to pre-define constant Copy/Cut/Paste keycode definitions; however, default clipboard-access keycodes are set during instantiation of the NcDialog object.

      'Copy' : CTRL + C 'Cut' : CTRL + X 'Paste' : CTRL + V 'SelectAll' : CTRL + A 'Select Right' : SHIFT + RightArrow 'Select Left' : SHIFT + LeftArrow These are also the default keycodes set when initializing the connection between the NcDialog local clipboard and the system clipboard. See Clipboard Interface.
    2. Although any key not dedicated to other uses may be selected as one of the clipboard access keys, typically, an application will use the conventional keycode groups to avoid confusing the user:
      1. Universal convention specifies that the CTRL+X (cut), CTRL+C (copy) and CTRL+V (paste) should be used for clipboard access whenever possible. In addition CTRL+A (select All) is conventionally used to select all text in the field.
        • If these keys are unavaliable or are unacceptable to you, then the ALT+X, ALT+C, ALT+V and ALT+A are the recommended substitutes.
        • Note that character-by-character selection keycodes are pre-defined constants to allow integration with mouse input:
             rkeyList.selRightKey = {nckSRIGHT, wktFUNKEY} ;
                      (SHIFT+RightArrow (select toward the right))
             rkeyList.selLeftKey  = {nckSLEFT, wktFUNKEY} ;
                      (SHIFT+LeftArrow (select toward the left))
          
        • Note on mouse input: The character-by-character selection keys are generated by the SHIFT key + the mouse ScrollWheel up/down.

          Note however, that on many systems, the Wayland compositor for instance, the SHIFT key is no longer reported in conjunction with ScrollWheel events, so text-selection via mouse may not be available inside a Textbox control.

      2. For Linux/UNIX console applications, SHIFT+CTRL+C (copy) and SHIFT+CTRL+V (paste) are defined to avoid conflict with shell command codes. Your application will never see these keycodes because they are captured by the terminal emulator, so don’t use them in you list. There is no defined console equivalent to the ’Cut’ command keycode.
      3. Keycodes are defined in two parts: the key 'type' and the 'keycode' itself. See wkeyCode class, definition for details.
        • If you know the key(s) you want to use, but are not sure of the key’s 'type' and 'keycode', then please use the Dialog2 test application, Test 05 which returns the key type and NcDialog key const definition for each keyboard key pressed.
    3. It is assumed that the keycode data specified through this method are valid. Keycode validation IS NOT performed here.
    4. To release a previously-specified list of reserved keys, call with the ’reserve; member reset. (see example below)
    5. Note that if you specify ’hotkeys’ for user-interface control access, be sure that they are different from the keycodes specified for clipboard access. Within the EditTextbox method, clipboard-access keycodes will mask any conflicting hotkeys.
          Example: Initialization of reserved keys.
          -- -- -- -- -- -- -- -- -- -- -- -- -- --
             reservedKeys rk ;
             rk.reserve = true ;
             rk.copyKey     = {nckC_C,    wktFUNKEY} ;
             rk.cutKey      = {nckC_X,    wktFUNKEY} ;
             rk.pasteKey    = {nckC_V,    wktFUNKEY} ;
             rk.selAllKey   = {nckC_A,    wktFUNKEY} ;
             rk.selLeftKey  = {nckSLEFT,  wktFUNKEY} ;
             rk.selRightKey = {nckSRIGHT, wktFUNKEY} ;
             dp->SetTextboxReservedKeys ( rk ) ;
          
          Example: release of reserved keys.
          -- -- -- -- -- -- -- -- -- -- -- --
             rk.reset() ;
             dp->SetTextboxReservedKeys ( rk ) ;
    

    Clipboard Access Implementation

    Please refer to the descriptions of the methods below for accessing the NcDialog Textbox Local Clipboard.

    Please see Clipboard Interface for a description of communication between the NcDialog local clipboard and the system clipboard.



  • short SetLocalClipboard ( const gString& srcText );
      Input  : 
         srcText: text to be stored
    
      Returns: 
         number of characters stored (including NULLCHAR)
    

    Copy the specified text data to the Textbox Local Clipboard buffer.
    Previous contents (if any) of the Local Clipboard are discarded.

    Note that the data copied to the Local Clipboard using this method ARE NOT associated with any particular Textbox control.



  • short GetLocalClipboard ( gString& trgText );
      Input  :
         trgText: receives the text data
    
      Returns:
         number of characters retrieved (including NULLCHAR)
    

    Retrieve a copy of the current contents of the Textbox Local Clipboard buffer.



  • short GetLocalClipboard_Bytes ( void );
      Input  : none
    
      Returns:
         number of data bytes (including NULLCHAR)
    

    Returns the number of data bytes currently in the Textbox Local Clipboard buffer.

    Note that the data are UTF-8 encoded, so the number of bytes IS NOT equivalent to the number of characters.



  • short GetLocalClipboard_Chars ( void );
      Input  : none
    
      Returns:
         number of (wchar_t) characters (including NULLCHAR)
    

    Returns the number of characters currently in the Textbox Local Clipboard buffer.



  • void SetTextboxInputMode ( bool overstrike, bool disable=false );
      Input  :
         overstrike :
            - 'true'  to set overstrike mode,
            - 'false' to set insert mode
         disable    : (optional, 'false' by default)
            - if 'true', then the 'Insert' key is disabled to prevent the
              user from changing the state of the insert/overstrike flag.
            - if 'false', then user can select the Textbox input mode 
              using the 'Insert' key.
    
      Returns: nothing
    

    Set the editing mode for Textbox controls to ’insert’ or ’overstrike’.

    ’insert’ mode: When user enters a character, the character under cursor and all characters to the right of it are shifted one position to make room for the new character. For LTR languages, characters are shifted to the right. For RTL languages, characters are shifted to the left. ’overstrike’ mode: When user enters a character, the character under the cursor is replaced with the new character.

    Applies to all Textbox controls defined for the dialog, except that the Insert/Overstrike flag is always ignored for Textbox controls which are configured for right-justified input (see enum tbCurPos).

    This method is generally used to set the initial state of the insert/overstrike flag just before calling the ’EditTextbox’ method. The user can then toggle the state of this flag using the ’Insert’ key on the keyboard.

    Under some circumstances, a Textbox should remain in one mode or the other throughout the text-editing process. In this case, call with the optional ’disable’ parameter set ’true’, and then the state of the Overstrike flag will remain in the specified state until the next call to ’SetTextboxInputMode’.

    Notes:
    If the ’disable’ parameter is ’true’, then the ’Insert’ key will be ignored to prevent the user from toggling the value of the Overstrike flag.

    If both ’overStrike’ and ’disable’ parameters are ’true’, then for the ’EditTextbox’ method only: the ’Delete’ and ’Backspace’ keys will ALSO be ignored to protect the formatting of a preformatted Textbox field.



  • bool IsOverstrike ( void );
      Input  : none
      Returns: 'true'  if Overstrike input mode
               'false' if Insert input mode
    

    Returns the current state of the OverStrike flag.
    See ’SetTextboxInputMode’ method, above.




Billboard Controls

The DialogBillboard-class user interface controls display text data to the user, and the data may be dynamically updated under program control to keep the user informed.

Billboard controls are read-only, that is the user may not directly modify the contents of the control.

Please see InitCtrl class for information on defining and creating a DialogBillboard-class user interface control.



  • short EditBillboard ( uiInfo& info );
      Input  :
         info : uiInfo class (by reference) - initial values ignored
                (see description of uiInfo class for values returned)
    
      Returns: 
         index of control that currently has the input focus
    

    Data displayed in a Billboard control cannot be directly edited by the user. This method is a stub to compensate for application error, i.e. a Billboard-class control should never receive the input focus.

    EditBillboard waits for key input indicating that the input focus is moving to another control. All other input is ignored.

    Please see uiInfo class for a discussion of the values returned from the Edit method.



  • short SetBillboard ( short cIndex, const char* uPtr,
                         const attr_t* cPtr=NULL );
  • short SetBillboard ( short cIndex, const wchar_t* wPtr,
                         const attr_t* cPtr=NULL );
  • short SetBillboard ( short cIndex, const gString& gsData,
                         const attr_t* cPtr=NULL );
      Input  :
         cIndex : index of target dctBILLBOARD control
    
         uPtr   : pointer to new display data in UTF-8 format
              OR
         wPtr   : pointer to new display data in wchar_t format
              OR
         gsData : gString object (by reference) containing the new data
    
         cPtr   : (optional, NULL pointer by default)
                  if specified, points to an array of color attributes,
                  one value for each display line defined for the control
    
      Returns:
         sourceIndex: The value returned is the number of data elements 
                      (bytes or characters) processed. (see notes)
         ERR if specified control is not of type dctBILLBOARD
    

    Replace current display data, if any, for a dctBILLBOARD control with specified data. The data is a single, null-terminated character array with each line’s data optionally separated by an newline (’\n’) character.

    NOTE: Automatic inter-word line break calculation is performed, but is rudimentary, so if a line needs to break in a certain place, be certain by indicating the breakpoint with a newline (’\n’) character.

    Internally, all data are handled as wchar_t type (’wide’) characters, and the limits described below refer to wchar_t storage. The limits are based on the amount of display area available in the target control.

    1. The text stored for, and displayed on a single line is limited by the number of display columns i.e. the width of the control.
    2. If source data for any line of the control is wider than the control, the excess will be wrapped to the next line.
    3. If the number of delimited lines of data is greater than the number of display lines defined for the control, OR if undelimited text contains more characters than will fit into the display area, then the excess data will not be processed (see notes below).
    4. All non-printing characters (Ctrl+A - Ctrl+Z, etc.) including newline characters will be silently stripped from the display data.

    If specified, ’cPtr’ references an array of color attributes to replace the existing color attribute for each display line. If not specified, (NULL pointer), then all text will be displayed using the default (non-focus) color attribute specified during instantiation (see InitCtrl class).

    Notes on return value:

    • If all data elements have been successfully displayed, the value returned will be the size of the source array.
    • If there was insufficient space to display all the data, then the return value will be the index of the first unprocessed source-data element.
      • If source lines have been delimited with newline characters, AND if the number of display lines in the control is less that the number of source lines, then the return value is the index of the first character of the first unprocessed source line.
      • If source data are undelimited (or incorrectly delimited), AND if there are more source characters than display space in the control, then the return value is the index of the first unprocessed character.
      • IMPORTANT NOTE: For UTF-8 source data, the index returned is the byte index. Otherwise, the index returned is the character index. Either way, the index will always fall on a character boundary.

    Examples

    short bbCTRL = 2 ;   // ID of target Billboard control
    
    //* Color attributes, one for each display line *
    attr_t lineColors[5] = { nc.re, nc.bl, nc.br, nc.gr, nc.bw };
    
    //* UTF-8 source data *
    const char* utf8Source = 
    "Roses are red\n"
    "Violets are blue\n"
    "That't why I picked some\n"
    "just for you!" ;
    
    short uIndex = dp->SetBillboard ( bbCTRL, utf8Source, lineColors ) ;
    
    // If not all data displayed
    if ( uIndex < (strlen(utf8Source)) )
    {
       ..  ..  ..
       // append the first previouly undisplayed line
       uIndex += dp->Append2Billboard ( bbCTRL, &utf8Source[uIndex] ) ;
       ..  ..  ..
    }
    
    //* gString or 'wide' data *
    gString wideSource( L"Roses are pink\n"
                         "Violets are purple\n"
                         "Sugar is sweet\n"
                         "And so's maple syrple." ;
    
    short wIndex = dp->SetBillboard ( bbCTRL, wideSource, lineColors ) ;
    
    // If not all data displayed
    if ( wIndex < (wideSource.gschars()) )
    {
       ..  ..  ..
       // append the first previouly undisplayed line
       wIndex += dp->Append2Billboard ( bbCTRL, &wideSource.gstr()[wIndex] ) ;
       ..  ..  ..
    }
    


  • short GetBillboard ( short cIndex, multiText* mtPtr );
      Input  :
         cIndex : index of target dctBILLBOARD control
         mtPtr  : pointer to an array of multiText-class objects to 
                  receive the text data
    
      Returns:
         OK  if successful
         ERR if specified control is not of type dctBILLBOARD
    

    Returns a copy of the specified dctBILLBOARD display data.

    The data are copied to an array of multiText-class objects, one for each line of the control.

    Note that the data returned are ’wide’ (wchar_t) characters. If you need UTF-8 data, then use the gString conversion tool as shown below.

    short lineCount = 5 ; multiText billboardData[lineCount]; // wchar_t data (source) char utfData[lineCount][mtLENGTH * 4]; // UTF-8 data (target) gString gs ; // conversion tool for ( short i = ZERO ; i < lineCount ; i++ ) { gs = billboardData[i].ln ; gs.copy( utfData[i], (mtLENGTH*4) ) ; }


  • short GetBillboard ( short cIndex, gString& gsData, short lIndex );
      Input :
         cIndex : index of target dctBILLBOARD control
         gsData : (by reference) receives the text data
         lIndex : index of target control line
    
      Returns:
         OK  if successful
         ERR if:
            a) 'lIndex' is out-of-range
            b) specified control is not of type dctBILLBOARD
    

    Returns a copy of the display data for the specified line of a dctBILLBOARD control.



  • short GetBillboardIndex ( short cIndex, short& lIndex );
      Input  : cIndex : index of target dctBILLBOARD control
               lIndex : (by reference) receives index of next free line
                        Range: ZERO through total-Billboard-lines-minus-one
                          Exception: returns (-1) if all display lines are 
                          occupied. In this case, for the next insertion all 
                          lines will be scrolled up and last line will become
                          the free line (insertion line).
    
      Returns:
         OK  if successful
         ERR if specified control is not of type dctBILLBOARD
    

    Get the index of the next free display line. This is the line which will by default, receive the text from the next Append2Billboard() call.

    Note that the Insert2Billboard() method always inserts text at index ZERO.

    Example: const short bbLINES = 12 ; // number of Billboard display lines short lineIndex ; // index of insertion line if ( (dp->GetBillboardIndex ( ctrlBB, lineIndex )) == OK ) { dp->Append2Billboard ( bbCTRL, L"My dog's name is: ", attrDFLT, lineIndex ) ; if ( lineIndex == -1 ) lineIndex = bbLINES - 1 ; dp->Append2Billboard ( bbCTRL, L"Captain Sparrow", attrDFLT, lineIndex, true ) ; } Yields: My dog's name is: Captain Sparrow


  • short Append2Billboard ( short cIndex, const char* uPtr,
                             attr_t cAttr=attrDFLT, short lIndex= -1,
                             bool attach=false );
  • short Append2Billboard ( short cIndex, const wchar_t* wPtr,
                             attr_t cAttr=attrDFLT, short lIndex= -1,
                             bool attach=false );
  • short Append2Billboard ( short cIndex, const gString& gsData,
                             attr_t cAttr=attrDFLT, short lIndex= -1,
                             bool attach=false );
      Input  :
         cIndex : index of target dctBILLBOARD control
    
         uPtr   : pointer to new display data in UTF-8 format
              OR
         wPtr   : pointer to new display data in wchar_t format
              OR
         gsData : gString object (by reference) containing the new data
    
         cAttr  : (optional, attrDFLT by default)
                  - if not specified:
                    text will be written using target line's 
                    previously-established color attribute
                  - if specified:
                    text will be written using the specified color 
                    attribute. Options are: a member of enum dtbmColors
                    or one of the color attributes defined in NCurses.hpp.
         lIndex : (optional, (-1) by default)
                  if specified, value is interpreted as an index of 
                  the control line whose data is to be replaced by 
                  the new data. If not a valid line index, then it 
                  will be ignored.
         attach : (optional, false by default)
                  if 'false', then
                     replace existing text (if any) on target line, 
                     TRUNCATING the result if necessary to fit on the 
                     target display line 
                  if 'true', then
                     for the target line, append new text to existing text 
                     (if any), shifting the old data out as necessary 
                     to fully display the new text on the target display 
                     line
                     NOTE: If new data is too wide for the field, i.e. 
                     an application error, then new data will be 
                     truncated to fit the field AND subsequent calls on 
                     the same data stream may be incorrectly indexed.
    
      Returns:
         number of characters or bytes added to displayed data
           (See notes on return value in 'SetBillboard' method, above.)
         ERR if specified control is not of type dctBILLBOARD
    

    Append a single line of text data below the currently-displayed data (if any). Text positioning is determined by the existing text for the control, as well as the values of 'lIndex' (line index) and 'attach' (attach new text to existing text on target line) as described below. Also see the example screenshots at the end of this chapter.

    • 'lIndex' NOT specified (’attach’ is ignored):
      If there is an unoccupied line following the existing data, then that line becomes the target line.

      If all display lines are already occupied, then scroll all lines up by one, discarding data on first line, and insert the new data as the last line.

    • 'lIndex' specifies the target line and 'attach'==false:
      Replace the existing data (if any) for the target line. No other display lines will be affected, i.e. no vertical scrolling will be done.
    • 'lIndex' specifies the target line and 'attach'==true:
      Extend the existing data on target line. If necessary, shift the existing text to make room for the new text. No other display lines will be affected.

    IMPORTANT NOTE: If source text is too wide for the control, then excess text will be truncated, NOT wrapped to the next line.



  • short Insert2Billboard ( short cIndex, const char* uPtr,
                             attr_t cAttr=attrDFLT );
  • short Insert2Billboard ( short cIndex, const wchar_t* wPtr,
                             attr_t cAttr=attrDFLT );
  • short Insert2Billboard ( short cIndex, const gString& gsData,
                             attr_t cAttr=attrDFLT );
      Input  :
         cIndex : index of target dctBILLBOARD control
    
         uPtr   : pointer to new display data in UTF-8 format
              OR
         wPtr   : pointer to new display data in wchar_t format
              OR
         gsData : gString object (by reference) containing the new data
    
         cAttr  : (optional, attrDFLT by default)
                  if specified, text will be written using the specified
                  color attribute. Options are: a member of enum dtbmColors
                  or one of the color attributes defined in NCurses.hpp.
    
      Returns:
         OK  if successful
         ERR if specified control is not of type dctBILLBOARD
    

    Insert a single line of text data in the top line of the control. Any existing data are scrolled DOWN by one line before the new text is inserted.



  • short ClearBillboard ( short cIndex, bool clearAll=true,
                           const attr_t* cPtr=NULL );
      Input  :
         cIndex  : index of target dctBILLBOARD control
         clearAll: (optional, 'true' by default)
                   - if 'true',  then the color attribute for each line
                     will be reset to the default (non-focus) color
                   - if 'false', then any previously-specified
                    'alternate' color attributes will be retained
         cPtr    : (optional, NULL pointer by default)
                   if specified, points to an array of color attributes,
                   one value for each display line defined for the control
                   (overrides the 'clearAll' flag)
    
      Returns:
         OK  if successful
         ERR if specified control is not of type dctBILLBOARD
    

    Erase the text data from the control, and optionally reset (’clearAll’) or reinitialize (’cPtr’) the color-attribute data.



  • short ScrollBillboardColors ( short cIndex, bool scroll ) ;
      Input  :
         cIndex : index of target dctBILLBOARD control
         scroll : if 'true', when text data are scrolled upward or 
                     downward in the window, the color attribute associated 
                     with that text is scrolled along with the text.
                  if 'false', when text data are scrolled upward or 
                     downward in the window, the color attribute for each 
                     line remains unchanged.
                     Exception: If the text-insertion command specifies a 
                     non-default color attribute, then the insertion line 
                     (only) is set to the specified value.
    
      Returns:
         OK  if successful
         ERR if specified control is not of type dctBILLBOARD
    

    Enable or disable scrolling of color attributes along with scrolling text.

    The color attributes for the Billboard control are set by one of the following:
       SetBillboard()
       ClearBillboard()
       SetBillboardColors()

    By default, the color attribute associated with each line of the window remains constant unless explicitly changed.

    When text is scrolled upward or downward using:
       Append2Billboard()  or
       Insert2Billboard()
    by default, the color attribute assigned to each line of the window will remain unchanged.

    However, in some applications it is desirable for the color attribute to remain attached to the associated text when that text is scrolled upward or downward.

    In this case, call: ScrollBillboardColors ( true ) ;
    The color attributes will be attached to the displayed text for each line.
    To see an example of a Billboard control with this feature enabled, please see Dialogx App.

    To disable this feature, call: ScrollBillboardColors ( false ) ;
    The color attributes will be attached to the line of the control window. (This is the default state when the control is instantiated.)



  • const attr_t* GetBillboardColors ( short cIndex,
                                       short& lineCount );
      Input  :
         cIndex   : index of target dctBILLBOARD control
         lineCount: (by reference, initial value ignored)
                    receives the number of items in the referenced array
    
      Returns:
         pointer to color-attribute array
          OR
         NULL pointer if specified control is not of type dctBILLBOARD
    

    Returns a const pointer to the color-attribute array for the specified dctBILLBOARD control AND the number of items in the array.

    NOTE: This is an array of ’const’ values which may not be modified directly. Please see ’SetBillboardColors’ method, below.



  • short SetBillboardColors ( short cIndex, const attr_t* cPtr=NULL );
      Input  :
         cIndex : index of target dctBILLBOARD control
         cPtr   : (optional, NULL pointer by default)
                  - if specified, points to an array of color attributes,
                    one value for each display line of the control
                  - if not specified, then the color map is set to the
                    default color specified during instantiation
    
      Returns:
         OK  if successful
         ERR if specified control is not of type dctBILLBOARD
    

    Establish an alternate color attribute map for the specified dctBILLBOARD display data. Text data (if any) are not modified.



  • short SetBillboardColors ( short cIndex, short lIndex,
                               attr_t cAttr );
      Input  :
         cIndex : index of target dctBILLBOARD control
         lIndex : index of target line
         cAttr  : new color attribute for line
    
      Returns:
         OK  if successful
         ERR if:
            a) 'lIndex' is out-of-range
            b) specified control is not of type dctBILLBOARD
    

    Modify the color attribute for the specified display line of a dctBILLBOARD control. Text data (if any) are not modified.


Examples

Working code for the following examples may be found in test application Dialogw, Test07 ’Billboard Demonstration’.

╔════╣ Poetry Corner ╠════╗ Roses are red, Violets are blue, That's why I picked some just for you! --- Set Billboard Contents NEXT DONE ╚═══════════════════════════╝

╔════╣ Poetry Corner ╠════╗ Violets are blue, That's why I picked some just for you! -- -- -- -- -- -- -- --- Append a Line (1) NEXT DONE ╚═══════════════════════════╝

╔════╣ Poetry Corner ╠════╗ -- -- -- -- -- -- -- Violets are blue, That's why I picked some just for you! --- Insert Line at Top NEXT DONE ╚═══════════════════════════╝

╔════╣ Poetry Corner ╠════╗ -- -- -- -- -- -- -- Violets are blue, Forget the flowers, just for you! --- Replace Third Line NEXT DONE ╚═══════════════════════════╝

╔════╣ Poetry Corner ╠════╗ -- -- -- -- -- -- -- Violets are blue, the flowers, give jewelry! just for you! --- Extend Third Line NEXT DONE ╚═══════════════════════════╝

Comprehensive examples of Billboard usage are available in the various test applications. See Dialog4, Test05 and Test06.




Scrollbox Controls

The DialogScrollbox-class user interface controls present a list of data items to the user in the form of a scrolling list. The list may be of any reasonable length, with the number of simultaneously-visible items determined by the vertical dimension of the control.

Data items should be of equal width (column count), and the contents of the list are fixed at the time the control is created.

Please see InitCtrl class for information on defining and creating a DialogScrollbox-class user interface control.



  • short EditScrollbox ( uiInfo& info );
      Input  :
         info : uiInfo class (by reference) - initial values ignored
                (see description of uiInfo class for values returned)
    
      Returns: 
         index of control that currently has the input focus
    

    If the control with input focus is of type dctSCROLLBOX, call this method to get user’s key input.

    Allows user to edit which item in the control is ’selected’ (highlighted).

    The EditScrollbox method retains control of input until:

    • ENTER or SPACE key pressed.
      The highlighted item has been actively selected, indicating that edit is complete. The 'dataMod' flag of the returned data indicates whether the highlight position has been modified.

      Note: To determine whether the user has re-selected the original item, check for the Enter key using the following test:

         if ( Info.dataMod != false || Info.keyIn == nckENTER )
         {
            // do stuff here...
         }
      
    • TAB, SHIFT+TAB, LEFT_ARROW or RIGHT_ARROW key pressed.
      The highlighted item has been implicitly selected, indicating that edit is complete. The ’dataMod’ flag of the returned data indicates whether the highlight position has been modified.
    • A ’Hotkey’ combination has been detected.
      The edit is complete. If the Hotkey belongs to the current control, it is processed like the ENTER key.

      Otherwise, the input focus has been shifted to another control object, and the ’dataMod’ flag of the returned data indicates whether the highlight position has been modified.

    • The nckESC (Escape) key pressed.
      It is assumed that the user is in panic mode. The highlighted item is returned to its original position, and control is returned to the application as if the user had pressed the nckTAB key (’dataMod’ flag == ’false’).

    Please see uiInfo class for a discussion of the values returned from the Edit method.



  • short GetScrollboxSelect ( short ctrlIndex );
    Input  :
         ctrlIndex : index number of source control
    
    Returns:
         index of highlighted item
         returns ERR if:
           a) specified control is not of type dctSCROLLBOX
    

    Returns the index of the highlighted item in the specified dctSCROLLBOX control.



  • short SetScrollboxSelect ( short ctrlIndex, short selMember );
    Input  :
         ctrlIndex : index number of target control
         selMember : index of item to be set as 'selected'
    
    Returns:
         index of 'selected' member
         returns ERR if:
           a) invalid item index specified
           b) specified control currently has the input focus
           c) specified control is not of type dctSCROLLBOX
    

    Set ’selected’ (highlighted) item in specified dctSCROLLBOX control.




Scrollext Controls

The DialogScrollext-class user interface controls presents a list of data items to the user in the form of a scrolling list. The list may be of any reasonable length, with the number of simultaneously-visible items determined by the vertical dimension of the control.

Scrollext-class controls are very similar to Scrollbox-class controls (see previous chapter), except that the data live in application space rather than in the control’s private memory space.

Data items should be of equal width, and the content and color attribute of each data item (but not the number of data items) may be dynamically updated in response to user action.

Please see InitCtrl class for information on defining and creating a DialogScrollext-class user interface control.



  • short EditScrollext ( uiInfo& info );
      Input  :
         info : uiInfo class (by reference) - initial values ignored
                (see description of uiInfo class for values returned)
    
      Returns: 
         index of control that currently has the input focus
    

    If the control with input focus is of type dctSCROLLEXT, call this method to get user’s key input.

    Allows user to edit which item in the control is ’selected’ (highlighted).

    The EditScrollext method retains control of input until:

    • TAB, SHIFT+TAB, LEFT_ARROW or RIGHT_ARROW key pressed.
      The highlighted item has been implicitly selected, indicating that edit is complete. The 'dataMod' flag of the returned data indicates whether the highlight position has been modified.
    • A ’Hotkey’ combination has been detected.
      If the Hotkey belongs to the current control, it is ignored, and the edit continues.

      Otherwise, the edit is complete and the input focus has been shifted to another control. The ’dataMod’ flag of the returned data indicates whether the highlight position has been modified.

    • All other key input terminates the edit and is returned to caller for potential processing. The key data are stored in the 'wk' member of the returned data.

      The 'dataMod' flag of the returned data is set if:

        — the position of the highlight has changed
        — the ENTER or SPACE key was pressed

      Because the text and color attributes for the Scrollext control are in application data space, they may be dynamically modified either after the return from edit or during edit via a callback method.

      Please see EstablishCallback method for more information on using callback methods.

      See our FileMangler application for an example of dynamic data modification for a Scrollext control.
      See Technical Support.

    Please see uiInfo class for a discussion of the values returned from the Edit method.



  • short ViewScrollext ( uiInfo& info );
      Input  :
         info : uiInfo class (by reference) - initial values ignored
                (see description of uiInfo class for values returned)
    
      Returns: 
         index of control that currently has the input focus
    

    This method is similar to the EditScrollext method above, except that the highlight is not displayed for the current data item and the user cannot ’select’ a data item. This method is useful for scrolling through informational text rather than through selectable items.

    The ViewScrollext method retains control of input until:

    • TAB, SHIFT+TAB, LEFT_ARROW or RIGHT_ARROW key pressed
      indicating that edit is complete.
    • A ’Hotkey’ combination has been detected.
      If the Hotkey belongs to the current control, it is ignored, and the edit continues. Otherwise, the edit is complete and the input focus has been shifted to another control.
    • The nckESC (Escape) key pressed.
      It is assumed that the user is in panic mode, so control is returned to the application as if the user had pressed the nckTAB key

    For a useful example of ViewScrollext, please see the Dialog2 test application, Test05. Press the ’HELP’ Pushbutton to see the Help data in a scrolling window. (In the source code, this is the ’ktHelp’ method in KeyTest.cpp.)



  • short SetScrollextText ( short cIndex,
                             ssetData& displayData );
      Input  :
         cIndex     : index of target dctSCROLLEXT control
         displayData: an initialized ssetData-class object
           Data Members:
           dispText : pointer to an array of pointers to text strings
           dispColor: pointer to an array of color attribute codes (attr_t)
           dispItems: number of items in the display arrays
           hlIndex  : specifies the item that is initially highlighted
           hlShow   : if true, show the highlight, else, hide it
                      Highlight remains in the specified state until
                      changed by another call to SetScrollextText or until
                      RefreshScrollextText or EditScrollext is called.
    
      Returns:
         OK if successful
         return ERR if:
            a) text data and/or color attributes pointers not 
               initialized or if item count <= ZERO
            b) specified highlight item is out-of-range
            c) specified control is not of type dctSCROLLEXT
    

    Specify the display text and associated color attributes for a Scrollext-class control.

    Unlike the display data for other control types, the display data for Scrollext controls is external to the NcDialog’s memory space. This allows the application to dynamically update the display text and color attribute data..

    Please see ssetData class below for more information.

    NOTE:
    It is the application’s responsibility to ensure that each item’s text string width (number of display columns) exactly fits the width of the control window i.e. the ’cols’ specified during instantiation, minus 2 (for left and right border columns).

    NOTE:
    If there are fewer data items than display lines, the unused lines will be filled with the background color of the first display item.



  • short RefreshScrollextText ( short cIndex,
                                 bool hlShow = true );
      Input  :
         cIndex : index of target dctSCROLLEXT control
         hlShow : (optional, default==true): if true, highlight
                  the current data item, else current data item is
                  drawn without highlight. Highlight remains in the
                  specified state until changed by another call to
                  RefreshScrollextText() or until SetScrollextText() 
                  or EditScrollext() is called.
    
      Returns:
         OK if successful
         returns ERR if:
           a) specified control is not of type dctSCROLLEXT
    
    

    Refresh the dctSCROLLEXT display data previously specified during instantiation or via a call to SetScrollextText(). Call this method if the text data and/or color attribute data have been modified BUT the number of items in the arrays have not. This method provides a much faster display update that calling SetScrollextText() again.



  • short MoveScrollextHighlight ( short cIndex,
                                   wchar_t scrollKey,
                                   short itemIndex= -1 );
      Input  :
         cIndex   : index of target dctSCROLLEXT control
         scrollKey: key code for one of the valid scrolling keys:
                    nckUP, nckDOWN, nckPGUP, nckPGDOWN, nckHOME, nckEND
                   (all other keycode values ignored)
         itemIndex: (optional: default == -1):
                    if specified, indicates the index of the data
                    item to be highlighted ('scrollKey' will be ignored)
    
      Returns:
         index of data item which is currently highlighted
         returns ERR if:
           a) invalid item index specified
           b) specified control is not of type dctSCROLLEXT
    

    Move the highlight within a dctSCROLLEXT control.
    Operates as if the user had pressed the specified scrolling key.



  • short GetScrollextSelect ( short cIndex );
    Input  :
         cIndex : index number of source control
    
    Returns:
         index of 'selected' (highlighted) item
         returns ERR if:
           a) specified control is not of type dctSCROLLEXT
    

    Returns the index of the highlighted item in the specified dctSCROLLEXT control.



  • short SetScrollextSelect ( short cIndex, short selMember );
    Input  :
         cIndex    : index number of target control
         selMember : index of item to be set as 'selected'
    
    Returns:
         index of 'selected' member
         returns ERR if:
           a) invalid item index specified
           b) specified control currently has the input focus
           c) specified control is not of type dctSCROLLEXT
    

    Set ’selected’ (highlighted) item in specified dctSCROLLEXT control.


ssetData Class

The ssetData class is used to set the text and color attribute data for the Scrollext-class user interface control, or to modify the the existing data.

  • Text and color attribute data optionally may be initialized during instantiation of the control. Please see InitCtrl class for details.
  • If text and color data are not set during instantiation, then the contents of the control are set to simple defaults. See example below.
  • Because the text and color data for Scrollext controls live in application space rather than in the private memory of the control object, the data may be initialized or updated at any time. Of course you should select a moment when the user will not be confused by the change.
    See SetScrollextText method, for initialization or re-initialization of data using the ssetData class.
    See RefreshScrollextText method, for modification of existing data.

//* Structure for passing data to the SetScrollextText() method * class ssetData { public: //* Default constructor * ssetData ( const char** dt = NULL, const attr_t* dc = NULL, int di = ZERO, int hi = ZERO, bool hs = true ) : dispText(dt), dispColor(dc), dispItems(di), hlIndex(hi), hlShow(hs) {} const char** dispText ; //* Pointer to an array of display string pointers const attr_t* dispColor ;//* Pointer to an array of color attributes //* (one for each display string) int dispItems ; //* Number of display items in above arrays int hlIndex ; //* Index of display item initially highlighted bool hlShow ; //* Show/hide the highlight for current item } ;

  • ’dispText’ member (default: NULL pointer)
    Pointer to an array of ’const char’ pointers, with each item in the array referencing the text for one line item of display data.

    Professional versus Ugly:
    The text for each item should exactly fill the number of character columns defined for the width of the control (minus left and right border). While the drawing algoithm can handle a line item which contains more or fewer columns than the control width, the displayed data will look ugly, indicating to the user that the programmer is a loser.
    Don’t be a loser — verify your output.

  • ’dispColor’ member (default: NULL pointer)
    Pointer to an array of color attribute values, one value for each line item in the ’dispText’ member.

    You can define all display items with the same color, or you may specify a different color for each item. See example below.

  • ’dispItems’ member (default: ZERO)
    The number of item in the ’dispText’ and ’dispColor’ arrays.

    Important Note: The SetScrollextText method has no way of knowing whether the ’dispText’ and ’dispColor’ arrays actually contain the specified number of elements, so if you specify more items than you actually have, a system exception will be generated, and your application will crash and burn.
    Defensive Programming 101: If ’dispItems’ specifies fewer elements than the arrays actually contain, then the excess will be ignored.

  • ’hlIndex’ member (default: ZERO)
    Index of the line item which is initially highlighted. The data will be scrolled up or down as necessary to bring the specified item into the viewable area.

    If a sufficient number of items follow, then the specified item will be positioned at the top of the viewable area. You may adjust the highlight position after initializing the data:
    See MoveScrollextHighlight method.

  • ’hlShow’ member (default: true)
    Determines whether the item specified by ’hlIndex’ will be highlighted (displayed with foreground and background colors reversed).

    The highlight should be visible while user is selecting an item, but may be invisible at other times. Visibility of the highlight may be toggled by calling the ’RefreshScrollextText’ method using the optional ’hlShow’ parameter.



The following is an excerpt from the clipboard browser section of our FileMangler utility. Space is allocated for the text and color attribute data; then the data are formatted, and finally are loaded into a Scrollext control object for the user to play with.

//* If there is file data to display 'Just Do It' (tm Nike) *
char*       blkPtr ;
ssetData    sData( NULL, NULL, tlFiles, ZERO, false ) ;
if ( tlFiles > ZERO )
{
   //* Space for display strings (there is extra space for each string) *
   blkPtr = new char[dAlloc * dialogCols] ;
   //* Space for pointers to strings *
   sData.dispText  = new const char*[dAlloc] ;
   //* Space for color attributes *
   sData.dispColor = new attr_t[dAlloc] ;

   //* Create display strings *
   this->bcbStandardView ( blkPtr, sData ) ;

   //* Send the data to the scrolling control *
   dp->SetScrollextText ( scrollSE, sData ) ;
}  // if(tlFiles>ZERO)

//* Make everything visible *
dp->RefreshWin () ;
┌───────┤ FileMangler - v:0.0.33 (c)2005-2015 [Press F2 for Menu] ├───────┐ │Status: Ctrl+Q=Quit, Shift+F1=Help, F2=Menu ├────────────────────────────────────────────────────────────────────────────┤ /home/xiao/software/NcDialog/Dialog1 ├───────────────────────────┤ Browse Clipboard ├───────────────────────────┤ │ Source Dir: /home/xiao/software/NcDialog/Dialog1 │ Files on Clipboard: 25 Byte Total, All Files: 2,569,748 │ Clipboard Storage Bytes Allocated: 12,240 Pending Operation: Copy Detailed View Close Clear Clipboard │ TYPE FILENAME (Tab to list, then scroll keys to view) ├──────────────────────────┤ Files On Clipboard ├──────────────────────────┤ REG Dialog1.cpp REG NCurses.cpp REG NcDialog.cpp REG NcKey.cpp REG NcWindow.cpp REG NcdControl.cpp REG NcdControlBB.cpp REG NcdControlDD.cpp REG NcdControlMW.cpp REG NcdControlPB.cpp REG NcdControlRB.cpp REG NcdControlSB.cpp └────────────────────────────────────────────────────────────────────────────┘