Next: Introduction [Contents][Index]
iostream
class with better formatting control, seamless
internationalization and multi-color output — but without the learning curve.
libncursesw.so.n
dynamic-load
(shared) library.
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.
Please see NcDialog Class Definition for a detailed description of each of the available NcDialog control types.
Please refer to the discussion of the InitNcDialog
class,
see Your First Application, for more information.
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.
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.
There is exactly one (1) publically-accessible Edit method for each control type:
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.
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).
Please refer to the section, see NCurses Engine,
or the section,see Your First Application, for more information.
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.
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!
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.
The application’s only direct access points to the NCurses class are:
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.
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.
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.
Of course a good programmer can find ways to violate this layering of functionality, but a great programmer will not do it.
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.
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!
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.
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.
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.
Here are a few useful definitions for terms that students often find confusing.
an improvement over version 1.0 designers,
(i.e. those who now ridicule you)
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:
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.
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’.
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:
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.
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.
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.
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.
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 :-)
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.
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:
info gcc
https://gcc.gnu.org/install/
https://gcc.gnu.org/install/configure.html
g++ −−help | less
Also, please see Building the API Library for additional information on updating and using the G++ compiler.
Please see Libraries for ncurses for details on installing the ncurses 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, also known as ’texi2any’. ’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).
info texinfo
info makeinfo
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.
help-texinfo@gnu.org
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.
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:
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:
Please see the ’alias’ shell builtin command for information on how to create your own custom commands.
’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:
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:
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.
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!
’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’ compares the files in the ’Dialog1’ directory with the corresponding files in the other directories, in this example, the ’Dialog2’ subdirectory. For any newer files in ’Dialog1’, the files are copied to ’Dialog2’, overwriting the older versions.
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
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 directoryThe '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.
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.
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.
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.
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.)
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:
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.
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:
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
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:
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’ 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:
Because ’grep’ is such a popular utility it likely has aliases (see ’ls’ above) defined for often-used options. Here is a sample:
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.
(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 !!
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
'info -f find.info'
for complete descriptions
and options.
locate -S
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)
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.
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:
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.
Here is a typical example for the NcDialog test application, Dialog4:
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.
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.
┌────────────────────────────────────────────────────────┐ │ │ │ IMPORTANT NOTE: │ │ This is the seat of great power, and as we all know: │ │ "With great power comes great responsibility!" │ │ Old Uncle Ben │ │ │ └────────────────────────────────────────────────────────┘
':'
(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
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:
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.
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:
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.
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.
Here is a straightforward note to future generations about initializing the members of a date/time structure:
If it was important today, it will still be important twenty years from today. Write it down!
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 |
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!
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.
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.
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.
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.
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.
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.)
'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)
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).
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.
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.
Copy the following into the Makefile and save it as ’Makefile’. Note that uppercase and lowercase DO matter here.
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.
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:
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.
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.
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.
Discard the current ’MyDialog’ method.
Insert the following ’MyDialog’ method.
Yes, this is a big step, but each item will be carefully explained.
InitNcDialog dInit(){}
so we pass a NULL pointer for the list of control objects.
NcDialog* dp = new NcDialog ( dInit ) ;
dp->OpenWindow()
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:
dp->WriteParagraph ()
dp->RefreshWin () ;
nckPause();
delete ( dp ) ;
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.
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.
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.
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.
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()’.
Make one more small adjustment to our existing code:
Replace the existing message text with the following message.
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.
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.
For our example application, we defined three (3) types of controls, so our user-interface loop must handle those three types.
Edit Method Control Class Control 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.
REMEMBER to delete the ’nckPause()’ call !!
Note that no direct input is collected from the user!
All direct contact with the user is through the Edit_Xxx methods.
gString lfMsg
uiInfo Info ;
short icIndex ;
'InitCtrl ic[mdCONTROLS]'
. The initial index
(and the initial input focus) are on the ’DONE’ Pushbutton.
bool done = false ;
while ( ! done )
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.
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.
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.
Note that if the focus has already changed via ’hotkey’, then we do nothing here.
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.
For a screenshot of this dialog, please see eye candy.
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
|
Many more and different examples can be found in the test applications
included in the NcDialog API package.
See Application Examples. Enjoy!
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.
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.
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.
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).
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.
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 |
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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. .
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.)
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.)
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.
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.
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.
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.
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.
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.
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.
Input : none Returns: delay in milliseconds or nckdFOREVER or nckdNODELAY
Returns the current key-input delay in milliseconds.
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.
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.
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.
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.
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.
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 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.
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.
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.
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.
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.
attr_t cAttr, bool rtl=false );
attr_t cAttr, bool rtl=false );
const wchar_t* wStr,
attr_t cAttr, bool rtl=false );
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:
const char* uChar, attr_t cAttr,
bool refresh=false, bool rtl=false );
wchar_t wChar, attr_t cAttr,
bool refresh=false, bool rtl=false );
const char* uChar, attr_t cAttr,
bool refresh=false, bool rtl=false );
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:
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.
Input : none Returns: nothing
Refresh the contents of the terminal window, making any previous changes visible.
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 ) ;
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.
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.
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.
Input : state : member of enum ncCurVis Returns: OK
Set the visibility state of the cursor.
Saves previous state for later call to RestoreCursorState().
Input : none Returns: OK
Restore the previous visibility state of the cursor.
See ’SetCursorState’ method, above.
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.
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.
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.
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.
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.)
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.
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.
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.
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* 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:
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.
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.
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.
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. |
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.
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.
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.
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.
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.
Input : none Returns: (const char*) pointer to version string
Returns a pointer to NCursesVersion, the NCurses class version number.
Input : none Returns: (const char*) pointer to version string
Returns a pointer to the ncurses (curses) C-language library version number.
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
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.
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.
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.
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?
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().
short& tt1Min, short& tt1Max );
short& tt2Min, short& ttsMax );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.
//* 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)
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.
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.
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:
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.
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’.
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.
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:
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:
If the terminal supports additional RGB registers they are:
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.
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.
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.
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.
Please see Specifying Color Attributes for more information.
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!
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:
Color variables use a short, but consistent and memorable naming convention. Each base color is specified using a two-character code:
For often-used ’color + attribute’ combinations, the following variables are defined:
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.
Variable names for often-used ’color + attribute’ combinations follow the established naming pattern:
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.
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.
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.
Adding a color attribute bit is done through a logical-OR of that bit with the base color.
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.
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.
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, 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.
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 */ }
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.
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.
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.
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.
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 | . . . |
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 | . . . |
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 |
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+ ~ |
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.
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.
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.
The NcWindow meta-layer performs three (3) major functions within the NcDialog API:
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.
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 |
Input : none Returns: nothing
Destructor. Erase the window from the display and release its resources back to the system.
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.
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.
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.
Input : cAttr : color attribute Returns: nothing
Set a background color for the interior of the window.
Does not redraw the window.
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 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.
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.
const gString& gStr, attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
const char* uStr, attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
const wchar_t* wStr, attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
Please see WriteString method in the NcDialog chapter.
attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
Please see WriteChar method in the NcDialog chapter.
const gString& gStr,
attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
Please see WriteParagraph method in the NcDialog chapter.
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.
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 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.
Input : none Returns: a winPos class object containing the Y/X cursor position
Get the window’s cursor position.
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
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.
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.
bool swheel = true );
Please see meEnableStableMouse method.
short interval=ncmiDFLT );
Please see meEnableMouse method.
Please see meDisableMouse method.
Please see meMouseEnabled method.
Please see meSetEventTypes method.
Please see meGetEventTypes method.
Please see meSetClickInterval method.
Please see meGetClickInterval method.
Please see meFlushEventQueue method.
Please see meAutoConvert method.
Please see meAutoFilter method.
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 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 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 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.
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.
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.
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.
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.
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.
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.
Input : none Returns: index of currently highlighted data item
Returns the index of the currently-highlighted item in the scrolling-data array.
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.
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.
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.
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.
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.
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.
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.
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.
Input : none Returns: a const pointer to the class-version string
Returns a pointer to NcWindowVersion, the NcWindow class version number.
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.
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.
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.
This chapter describes in detail the NcDialog class and the control objects with which a dialog-based application is populated.
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.
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
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 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 |
This chapter describes the NcDialog methods that affect the NcDialog-class object (dialog window) as a whole.
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.
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.
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.
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.)
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.
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.
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.
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.
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.
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.
attr_t cAttr=attrDFLT );
attr_t cAttr=attrDFLT );
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:
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:
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 |
Notes on using a callback method:
firstTime==true
, to perform any required initialization.
(wkey parameter will be meaningless for first call)
Subsequently, the NcDialog class always calls with firstTime==false
.
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.
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.
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.
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.)
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.
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’.
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 > │ < │ <
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.
Sreenshot see RTL text character order shows an example dialog with control object labels drawn in an RTL language (Yiddish).
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.
Sreenshot see RTL text character order shows an example dialog with contents of control objects drawn in an RTL language (Yiddish).
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.
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:
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.
Otherwise, the input focus has been shifted to another control object, and the Pushbutton has not been ’pressed’ (’dataMod’ == ’false’).
Please see uiInfo class for a discussion of the values returned from the Edit method.
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.
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.
See the test application Dialog1, Test07 for further explanation.
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.
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:
Otherwise, the input focus has been shifted to another control object, and the state of the Radiobutton has not changed (’dataMod’ == ’false’).
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... }
If the input focus is not yet on the last member, then focus is moved to the next member and the edit continues.
If the input focus is not yet on the first member, then focus is moved to the previous member and the edit continues.
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’).
Please see uiInfo class for a discussion of the values returned from the Edit method.
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.
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.
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.
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’.
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.
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.
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:
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.
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.
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:
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.
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.
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.
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.
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.
IMPORTANT NOTE: When a control is set to fixed-width, any existing text is truncated to fit the width of the field.
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!)
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.
Please see dtbmData class for information on the initialization constructors for this class.
Use a dtbmData-class object for passing data to this method.
attributeCount = lines * columns + lines ;
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.
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.
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.
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.
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.
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.
Configuration style is specified by specifying a member of enum tbCurPos as the ’offset’ parameter.
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.
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.
rkeyList.selRightKey = {nckSRIGHT, wktFUNKEY} ; (SHIFT+RightArrow (select toward the right)) rkeyList.selLeftKey = {nckSLEFT, wktFUNKEY} ; (SHIFT+LeftArrow (select toward the left))
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.
'type'
and
the 'keycode'
itself. See wkeyCode class, definition
for details.
'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.
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 ) ;
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.
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.
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.
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.
Input : none Returns: number of (wchar_t) characters (including NULLCHAR)
Returns the number of characters currently in the Textbox Local Clipboard buffer.
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’.
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.
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.
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.
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.
const attr_t* cPtr=NULL );
const attr_t* cPtr=NULL );
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.
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).
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] ) ; .. .. .. }
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.
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.
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.
attr_t cAttr=attrDFLT, short lIndex= -1,
bool attach=false );
attr_t cAttr=attrDFLT, short lIndex= -1,
bool attach=false );
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 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
:'lIndex'
specifies the target line and 'attach'==true
:IMPORTANT NOTE: If source text is too wide for the control, then excess text will be truncated, NOT wrapped to the next line.
attr_t cAttr=attrDFLT );
attr_t cAttr=attrDFLT );
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.
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.
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.)
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.
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.
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.
Working code for the following examples may be found in test application Dialogw, Test07 ’Billboard Demonstration’.
Comprehensive examples of Billboard usage are available in the various test applications. See Dialog4, Test05 and Test06.
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.
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:
'
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... }
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.
Please see uiInfo class for a discussion of the values returned from the Edit method.
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.
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.
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.
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:
'
dataMod'
flag of the returned data indicates
whether the highlight position has been modified.
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.
'
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.
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:
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.)
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.
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.
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.
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.
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.
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.
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.
You can define all display items with the same color, or you may specify a different color for each item. See example below.
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.
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.
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 () ;
The DialogDropdown-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 specified for the ’expanded’ state.
Dropdown-class controls are very similar to Scrollbox-class controls described in a previous chapter, except that when the control is in the inactive (collapsed) state, it uses only three(3) display rows, displaying only the currently-selected item. When in the active (expanded) state, it performs exactly like a Scrollbox-class control.
Data items should be of equal width, 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 DialogDropdown-class user interface control.
Input : info : uiInfo class (by reference) - initial values ignored EXCEPTION: If info.viaHotkey != false, on entry, expand the control immediately on entry. (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 dctDROPDOWN, call this method to get user’s key input.
Allows user to edit which item in the control is ’selected’ (highlighted).
When the user has selected an item OR has indicated a move to another control, then the control is returned to the ’collapsed’ state. Thus, Dropdown controls are in the ’expanded’ state only when under edit.
The EditDropdown method retains control of input until:
Otherwise, the input focus has been shifted to another control object, and no selection has been made.
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... }
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.
Please see uiInfo class for a discussion of the values returned from the Edit method.
Input : cIndex : index number of source control Returns: index of 'selected' (highlighted) item returns ERR if: a) specified control is not of type dctDROPDOWN
Returns the index of the highlighted item in the specified dctDROPDOWN control.
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 dctDROPDOWN
Set ’selected’ (highlighted) item in specified dctDROPDOWN control.
"Western Division" Dropdown control has focus, but is still in the collapsed state.
"Western Division" Dropdown control is expanded (downward).
"North and South Divisions" Dropdown control is expanded (upward and downward from center point).
"Eastern Division" Dropdown control is expanded (upward).
Working code for these examples is located in the Dialogw test application, Test07, ’Dropdown Demonstration’.
The DialogMenuwin-class user interface controls are, as the name indicates, menus which may be opened, closed, linked into multi-level groups (MenuBar objects), or made invisible.
When you create the control, you specify its appearance in both the ’collapsed’ (inactive) state and the ’expanded’ (active) state. When in the active state, Menuwin controls behave much like Scrollbox-class controls (described in a previous chapter), but with enhanced features such as wrap-around scrolling, dynamic activation/deactivation of individual data items and cascading sub-menus.
Please see InitCtrl class for information on defining and creating a DialogMenuwin-class user interface control.
Please see Menuwin notes, below for further discussion of creating and configuring menus.
Input : info : uiInfo class (by reference) - initial values ignored EXCEPTION: If info.viaHotkey != false, on entry, expand the control immediately on entry. (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 dctMENUWIN, call this method to get user’s key input. This method handles standalone (independent) menus and MenuBar groups. (For edit of ’context menus’, see next method).
Special case for hotkey selection of menu items: In applications which are
written for a multi-language user interface, or which are written in a
language which does not use the Latin alphabet ('a'-'z' 'A'-'Z')
,
(e.g. Chinese), designation of hotkeys may be inconvenient for the developer
or confusing for the user.
For this reason, the first nine menu items may each be selected by entering
the corresponding item number (1 - 9). Note: if the ’0’ (zero) key is entered,
it is processed as ’1’. This is the same menu-item selection algorithm used
by the Linux 'info'
reader utility.
The EditMenuwin method retains control of input until:
For working menu examples, please see Test10 of the Dialog1 test application, or see the examples below (see Menuwin examples).
Please see uiInfo class for a discussion of the values returned from the Edit method.
Input : cIndex : index of a context (normally invisible) Menuwin control info : uiInfo class (by reference) - initial values ignored Returns: index of control that currently has the input focus
For a context menu (control of type dctMENUWIN which is normally inactive and invisible), call this method to get user’s key input.
For standalone menus and MenuBar groups, please see previous method.
This method does more than just collect user input.
Note that in a GUI application, context menus are normally accessed by using the mouse (press Button #3). However, this option is not available to console applications because Button #3 is reserved by the GUI. For this reason, a context menu will typically be activated under direct program control in response to some user action.
The context-menu version of the EditMenuwin method retains control of input until:
wchar_t auxHotkey=ZERO );
Input : indexList: array of control index numbers (-1 ends list) auxHotkey: (optional, default==ZERO) If a value is specified, it is an auxilliary hotkey that toggles the MenuBar's visibility/invisibility. Note that this keycode will be recognized only when the input focus is not on a member of the MenuBar group. Returns: OK if successful returns ERR if: a) if index list contains an invalid index number b) an index in the list references a control which is not of dctMENUWIN type c) an index in the list references a sub-menu or context menu or a menu which is already a member of another MenuBar group
Establish a MenuBar (a group of DialogMenuwin class objects).
The controls of a MenuBar may be edited as a group by a call to the EditMenuwin method (see above).
The list of group members is passed as an array of index numbers for the
DialogMenuwin objects. List is terminated by a negative 1 (-1).
Example:
short List[] = { 4, 5, 6, -1 } ;
This MenuBar has three top-level menus. Sub-menus may be added using the
AttachMenuwinSubmenus method (see below).
NOTE: Sub-menus and other context menus MAY NOT be specified as members of a MenuBar. Only visible, top-level menus, may be specified.
NOTE: If specified indices are not consecutive, anomolous display behavior may result, so members of a group should have consecutive indices. (Sub-menus need not have sequential indices.)
const short submenuList[] );
Input : pMenu : index of parent menu of type dctMENUWIN to which sub-menus will be attached. smList : array of index numbers for the DialogMenuwin context menu objects to be associated with each data item in the parent menu. Returns: OK if successful returns ERR if: a) invalid parent menu index number b) any specified sub-menu not defined as a context menu c) any referenced control is not of dctMENUWIN type
Establish a connection between display elements in a dctMENUWIN control and context menus that will act as submenus for those elements.
Note: A context menu is a dctMENUWIN control that has been defined with a NULL string label, and is therefore invisible when in its collapsed state. Context menus are always in the collapsed state unless they are currently under edit.
Please see Menuwin examples below for more information.
Input : mbIndex: index of any top-level member control in a MenuBar Returns: OK if successful returns ERR if: a) mbIndex is not a valid control index b) specified control is not a dctMENUWIN control c) specified control is not a member of a MenuBar d) all active controls in the dialog are members of the MenuBar
Make a MenuBar (DialogMenuwin control group) invisible.
MenuBar group must have been previously established through a call to the GroupMenuwinControls method.
If a valid hotkey for any member of the MenuBar is detected, the MenuBar is made visible (see ShowMenuBar method) and the input focus is moved to that control.
By enforcing this action we ensure that there is at least one active control outside the MenuBar. There is no guarantee that the application will be happy with our chosen focus position, so it is better if the application moves the focus out of the MenuBar BEFORE calling this method.
If the application wants to hide a MenuBar containing all the active controls in the dialog, there is a work-around. Define a dummy active Pushbutton control which is active, but does nothing. Such a Pushbutton can be effectively invisible if it is one character wide, and that character is a SPACE of the same color as the dialog background. The application would then move the focus to that control before hiding the MenuBar. The user would never know the extra Pushbutton control existed.
Input : mbIndex : index of any top-level member control in a MenuBar setFocus: if 'true', immediately move the input focus to the control indicated by mbIndex. if 'false', input focus is not changed Returns: index of control with input focus. NOTE: This method will do nothing if: a) mbIndex is not a valid control index b) the specified control is not a dctMENUWIN control c) the specified control is not a member of a MenuBar d) If setFocus==true AND referenced MenuBar is already visible, input focus is simply moved to the control specified by mbIndex.
For a MenuBar (group of DialogMenuwin controls) previously hidden by a call to the HideMenuBar method (above), make the MenuBar visible.
Input : mbIndex : index of any top-level member control in a MenuBar Returns: current state of a MenuBar: 'true' if specified MenuBar is visible 'false' if MenuBar is invisible OR a) if mbIndex is not a valid control index b) if specified control is not a dctMENUWIN control c) if specified control is not a member of a MenuBar
Returns the current Visible / Invisible state of the specified MenuBar.
Input : cIndex : index of control to be positioned offY : Y offset from upper left of parent dialog offX : X offset from upper left of parent dialog Returns: OK if successful returns ERR if: a) specified control is not a context menu b) the menu is already expanded (visible) c) specified offset puts menu on or beyond dialog border
Set the position of a dctMENUWIN control which acts as a context menu.
Context menus are DialogMenuwin class objects that are invisible when in the ’collapsed’ state, which is any time they are not being edited by the user. In a GUI application, this would be the menu that opens when the right mouse button is pressed. A context menu may be opened anywhere within the dialog window. A context menu is created by instantiating a dctMENUWIN object with a zero-length label.
const attr_t* aColors=NULL, bool hide=false );
Input : cIndex : index of dctMenuwin control aFlags : an array of boolean values, one for each menu item 'true' == active, 'false' == inactive Note: At least one menu item must be 'active'. (To deactivate an entire menu, see ControlActive()) aColors: (optional, NULL pointer by default) if specified, pointer to an array of color attributes, one for each menu item. hide : (optional, false by default) if 'true' hide (make invisible) all inactive menu items [NOTE: 'hide' option is not currently implemented] Returns: OK if successful returns ERR if: a) cIndex is not a valid control index b) cIndex does not reference a control of dctMENUWIN type c) target control has input focus
Set which menu items in a dctMENUWIN control are active (user-selectable). These changes are allowed only for a control that currently does not have the input focus.
A dctMENUWIN control has a fixed number of menu items determined at the time the control is instantiated; however, some menu items may have no meaning or must be disallowed in certain contexts. Menu items may therefore be activated or deactivated as necessary, and the item’s color attribute can be adjusted to visually indicate the item’s current status.
Note on beautification: If the ’active’ menu color uses a ’reverse’ attribute, then the ’inactive’ color should also use a ’reverse’ attribute to avoid confusion with the color of the highlighted item. For an example of using this method, please see the examples below.
This method can also be used to change the color attribute for each menu item with-or-without affecting the active/inactive status of each item.
A Menuwin control is a control object which contains scrollable data from which the user can select one line item. Menuwin controls have two ’states’:
’collapsed’ : only the menu title is visible
Menuwin controls are in the ’collapsed’ state unless the user is accessing
the line items of the control
’expanded’ : both the menu title and the scrolling data list are visible
The user has requested access to the line items of the control, that is,
the menu or one of its optional sub-menus currently has the input focus.
Menus come in four(4) configurations:
Normally, the menus of a MenuBar are positioned horizontally adjacent to one another (but this positioning is not enforced).
To reduce visual clutter, the entire MenuBar optionally can be set invisible when not in use.
""
.
The menu becomes visible to the user only under a pre-defined set of circumstances (the context) and is completely invisible and inaccessible to the user at all other times. The application activates a context menu in response to this context being detected.
A sub-menu is visually in contact with the parent window (ideally,
overlapping the right border of the parent), and has been associated
with a line item of the parent menu.
See AttachMenuwinSubmenus method.
Visual association with the parent menu is not enforced but is recommended as the visual cue to which most users are accustomed.
It is customary to visually indicate to the user that the menu item
is associated with a sub-menu. The NcDialog API examples use the
'>'
character at the trailing edge of the item to indicate the
associated sub-menu. (see examples below)
Sub-menus may be cascaded to an unreasonable depth; however, a depth of more than three has been shown to confuse even an experienced user.
The user activates a sub-menu by:
a)
highlighting the parent’s menu item and pressing
the ENTER or SPACE key or the RIGHT_ARROW key
b)
pressing the Hotkey (if any) associated with the
parent’s menu item
The user returns from the sub-menu to the parent menu by:
a)
making a selection
In this case, the entire cascade of sub-menus is closed
and then the parent menu is closed.
b)
pressing the LEFT_ARROW key
In this case, the sub-menu is closed and the input focus
returns to the (still open) parent menu.
Note: Sub-menus can perform a dual function: a) as a sub-menu attached to its parent and b) as a context menu invoked under program control in the same or a different position (see PositionContextMenu method).
A menu may also be expanded for selection using its assigned Hotkey (if any).
When a menu is expanded, the highlight is always placed on the first (topmost) active line item. (This is different from the other scrolling control types which remember the previous highlight position.)
A menu is also returned to the collapsed state when the input focus moves to another control. An exception to this is when a sub-menu of the target menu currently has focus, in which case the parent menu will not be collapsed until its sub-menu has been closed.
UP_ARROW, DOWN_ARROW, PAGE_UP, PAGE_DOWN, HOME, END
Note: Hotkeys associated with other control objects are disabled during
the period when the user is making a selection from the menu to avoid
interferring with the menu’s own hotkeys.
Please see hotkey specification for a further discussion of hotkeys.
'A' - 'Z' or 'a' - 'z'
,
and are indicated to the user by underlining that character.
As with hotkeys for control objects, try to avoid using ’i’, ’I’, ’j’,
’J’, ’m’, ’M’ as menu item hotkeys because in Linux/UNIX world, the
these characters in combination with the CTRL key have special meanings.
Please see menu item hotkeys for additional hotkey information.
For instance, menus often have an inactive item which separates different item groupings. This separator is of course inactive so the user cannot hilight it. In the example, the ’Flavors’ item, the ’Toppings’ item and the separator line would be inactive line items, so when the user scrolls through the list, the highlight will automatically skip over those item.
Line items may also be dynamically activated/deactivated to allow the user access to some functionality only at certain times.
Independent menu in the 'collapsed' state.
Independent menu in the 'expanded' state.
Independent menu with sub-menu attached to 'Strawberry' item.
Working code for the above examples is located in the Dialogw test
application, Test07, ’Menu Demonstration’.
A simplified version of the code is presented here.
const short dialogROWS = 20, // display lines dialogCOLS = 51, // display columns ulY = 3, // upper left corner in Y ulX = 21, // upper left corner in X parITEMS = 13, // Parent menu items parWIDTH = 19, // Parent text column count subITEMS = 3, // Sub-menu items subWIDTH = 19 ; // Sub-menu text column count const attr_t dColor = nc.blR, // dialog background color bColor = nc.brbl ; // dialog border color //* Control indices * enum mwControls : short { mwDonePB = ZERO, mwParMW, mwSubMW, mwControlsDEFINED } ; //* Text for parent menu (use care with column count) * const char ParText[parITEMS][parWIDTH + 2] = { " Flavors: ", " ^Chocolate ", " ^Vanilla ", " ^Strawberry >", " ^Peach ", " ^Rocky Road ", " ---------------- ", " Toppings: ", " Cashe^ws ", " M & M Plai^n ", " Marshmallow ^fluff ", " Sprin^kles ", " ^Butterscotch ", } ; //* Color attributes for parent menu * attr_t ParAttr[parITEMS] = { nc.gyR, nc.bl, nc.bl, nc.bl, nc.bl, nc.bl, nc.gy, nc.gyR, nc.bl, nc.bl, nc.bl, nc.bl, nc.bl } ; //* Active/Inactive flags for parent menu * const bool ParActive[parITEMS] = { false, true, true, true, true, true, false, false, true, true, true, true, true } ; //* Text for sub-menu * const char SubText[subITEMS][subWIDTH + 1] = { " with fruit ", " with jam ", " smooth (no fruit) ", } ; //* Color attributes for sub-menu (monochrome) * attr_t SubAttr[2] = { attrDFLT, nc.bl } ; InitCtrl ic[mwControlsDEFINED] = // array of dialog control initialization objects { { //* 'DONE' pushbutton - - - - - - - - - - - - - - - - - - - - - mwDonePB * dctPUSHBUTTON, // type: .. .. .. &ic[mwParMW] // nextCtrl: link in next structure }, { //* 'Parent' Menuwin - - - - - - - - - - - - - - - - - - - - - mwParMW * dctMENUWIN, // type: define a Menuwin control rbtTYPES, // rbSubtype: (n/a) false, // rbSelect: (n/a) 1, // ulY: upper left corner in Y 4, // ulX: upper left corner in X 1, // lines: (n/a) (parWIDTH + 2), // cols: control columns (const char*)&ParText, // dispText: text-data array nc.re, // nColor: non-focus border color // and focus title color nc.reR, // fColor: focus border color // and non-focus title color tbPrint, // filter: (n/a) " Ice ^Cream ", // label: label text ZERO, // labY: (n/a) ZERO, // labX ddBoxTYPES, // exType: (n/a) parITEMS, // scrItems: elements in text/color arrays ZERO, // scrSel: (n/a) ParAttr, // scrColor: color-attribute list NULL, // spinData: (n/a) true, // active: allow control to gain focus &ic[mwSubMW] // nextCtrl: link in next structure }, { //* 'Sub-menu' Menuwin - - - - - - - - - - - - - - - - - - - - mwSubMW * dctMENUWIN, // type: define a Menuwin control rbtTYPES, // rbSubtype: (n/a) false, // rbSelect: (n/a) short(ic[mwParMW].ulY + 4), // ulY: upper left corner in Y short(ic[mwParMW].ulX + parWIDTH + 1), // ulX: upper left corner in X 1, // lines: (n/a) (subWIDTH + 2), // cols: control columns (const char*)&SubText, // dispText: text-data array nc.re, // nColor: non-focus border color nc.reR, // fColor: focus border color tbPrint, // filter: (n/a) NULL, // label: label text (no label for sub-menus) ZERO, // labY: (n/a) ZERO, // labX ddBoxTYPES, // exType: (n/a) subITEMS, // scrItems: elements in text/color arrays ZERO, // scrSel: (n/a) SubAttr, // scrColor: color-attribute list NULL, // spinData: (n/a) false, // active: sub-menu initially inactive NULL }, } ; //* 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 NULL, // no title ncltSINGLE, // border line-style bColor, // border color attribute dColor, // interior color attribute ic // list of controls ) ; //* Instantiate the dialog window * NcDialog* dp = new NcDialog ( dInit ) ; //* Open the dialog window * if ( (dp->OpenWindow()) == OK ) { //* Set the active items in parent menu item list.* dp->SetActiveMenuItems ( mwParMW, ParActive ) ; //* Attach the sub-menu to the parent menu at item index 3.* //* For data items with no associated sub-menu, use the * //* default value of MAX_DIALOG_CONTROLS. * //* The list is terminated by a -1. * short smList[] = { MAX_DIALOG_CONTROLS, MAX_DIALOG_CONTROLS, MAX_DIALOG_CONTROLS, mwSubMW, -1 } ; dp->AttachMenuwinSubmenus ( mwParMW, smList ); dp->RefreshWin () ; // make everything visible //* User interface loop * 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 != false ) { // Selection of a Pushbutton via hotkey // means it was 'pressed'. Info.HotData2Primary () ; } else icIndex = dp->EditPushbutton ( Info ) ; if ( Info.dataMod != false ) done = true ; } if ( ic[icIndex].type == dctMENUWIN ) { if ( Info.viaHotkey != false ) { // Nothing to be done here. // Menu will be expanded immediately // because 'viaHotkey' member is 'true' } icIndex = dp->EditMenuwin ( Info ) ; } //* Move to next/previous control * if ( done == false && !Info.viaHotkey ) { if ( Info.keyIn == nckSTAB ) icIndex = dp->PrevControl () ; else if ( Info.keyIn != ZERO ) icIndex = dp->NextControl () ; } } // while() } if ( dp != NULL ) // close the window delete ( dp ) ;
A MenuBar consisting of 'Menuwin A, 'Menuwin B' and Menuwin C' is defined in the upper left
corner of the dialog. 'Menuwin B' is in the expanded state.
Working code for this dialog is located in Dialog1, Test10.
The DialogSpinner-class user interface controls are used to collect range-limited numeric data from the user.
Please see InitCtrl class for information on defining and creating a DialogSpinner-class user interface control.
When you create the control, you specify the minimum, maximum and initial values to be displayed. Please see dspinData class below for information on setting the numeric limits.
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 dctSPINNER, call this method to get user’s key input.
The value of the control may be adjusted within the defined value range.
The EditSpinner method retains control of input until:
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 value has been modified.
Please see spinner key input, below for a list of user-interface keys which are recognized by the EditSpinner method.
Please see uiInfo class for a discussion of the values returned from the Edit method.
Input : cIndex : index of target dctSPINNER control spValue: (by reference, initial value ignored) receives currently-displayed value Returns: OK if successful ERR if a) specified control is not of type dctSPINNER
Return the currently-displayed value for the specified Spinner control.
Important Note: Please carefully review the notes on Spinner control value encoding in the definition of see dspinData class.
Input : cIndex : index of target dctSPINNER control spValue: new 'current' value for the control Returns: OK if successful returns ERR if: a) spValue is outside the defined range for this control b) specified control currently has the input focus c) specified control is not of type dctSPINNER
Set a new display value for specified Spinner control and update display.
Important Note: Please carefully review the notes on Spinner control value encoding in the definition of see dspinData class.
int maxValue, int setValue );
Input : cIndex : index of target dctSPINNER control minValue : new minimum data value for the control maxValue : new maximum data value for the control setValue : new currently-displayed data value Returns: OK if successful returns ERR if: a) spValue is outside the minValue to maxValue range b) specified control currently has the input focus c) specified control is not of type dctSPINNER
Specify a new minimum value, maximum value and current value for a dctSPINNER control.
Important Note: Please carefully review the notes on Spinner control value encoding in the definition of see dspinData class.
The dspinData class is used to set the initial parameters for a Spinner-class user interface control.
During instantiation of the control, the ’spinData’ member of the ’InitCtrl’ class points to an initialized instance of a dspinData-class object.
The 'dspinData'
class includes a full-initialization constructor with
default values for each data member as indicated above.
Example: an initial value of 1524 will be displayed to the user as as 1524
'value / 10'
.
Example: an initial value of 1524 will be displayed to the user as as 152.4
'value / 100'
.
Example: an initial value of 1524 will be displayed to the user as as 15.24
'value / 1000'
.
Example: an initial value of 1524 will be displayed to the user as as 1.524
The current value is displayed as a hexadecimal value using the characters: 0-9 and A-F.
Example: an initial value of 5098 (decimal) will be displayed to the user as as: 13EA
The current value is displayed as a hexadecimal value using the characters: 0-9 and a-f.
Example: an initial value of 4796 (decimal) will be displayed to the user as as: 12bc
Note that for dspinHEX1 and dspinHEX2 display formats, the minimum value must be greater-than-or-equal-to zero (0).
'indiChar'
below)
'±'
by default), which indicates to the
user that the value in the control may be incremented and decremented.
You may specify an alternate indicator character if desired.
As a special case, a NULL character ('\0'
) specifies that there should
be no indicator character. Adjust the field width specified in
the DialogSpinner
definition accordingly.
As an example, the following group of three Spinner controls could be configured as a time widget for hours, minutes and seconds, with appropriate division characters between fields (see example output below).
dspinData hspData( 0, 23, 0, dspinINTEGER, nc.blR, true, L':' ); dspinData mspData( 0, 59, 0, dspinINTEGER, nc.blR, true, L':' ); dspinData sspData( 0, 59, 0, dspinINTEGER, nc.blR, true, nckNULLCHAR );
'false'
), then unused columns on the left will be
padded with space (' '
) characters.
POSITIVE NEGATIVE Examples: ▒▒ 147±▒▒ ▒▒ -147±▒▒
If this field is set ('true'
), then unused columns on the left will be
padded with zero ('0'
) characters.
POSITIVE NEGATIVE Examples: ▒▒00147±▒▒ ▒▒-0147±▒▒
The width of the control is specified during instantiation by the
'cols'
member of the InitCtrl class object. The value specified must
include the width of the numeric data (including minus sign, if any),
as well as the width of the indicator character.
For example, a control which is to display a range of -100 to 100
must
be specified with a width of at least five(5) columns: four(4) columns
for the value and one(1) column for the ’±’ character.
If the display field is too narrow for the value to be displayed, then
the field will be filled with HASH characters ('#'
) indicating overflow.
Example: ▒▒###±▒▒
The nominal maximum width of a DialogSpinner control is
MAX_SPINNER_WIDTH(16)
columns, which is more than enough to display any
integer value up to a petabyte.
Whether you specify the display format for the value as an integer or as a decimal value, all data are passed to and from the Spinner control as signed integers. Thus, when you use a retrieved value or set a new value, you must do the proper conversion.
Example: // Retrieve the current value from a Spinner which // was defined with a format of dspinDEC3. int iValue ; dlgPtr->GetSpinnerValue ( index, iValue ); // Convert to a decimal value for calculations. // ('spValue' will be equivalent to ) // (the value displayed to the user.) double spValue = (double)iValue /= 1000.0;
Note on integer size: All values for Spinner-class objects are stored and
retrieved as signed integer values. Thus, the minimum and maximum values
which can be represented in the dspinData-class member variables is
determined by the number of bits in a '
signed int'
on your system.
While this is unlikely to be a problem except on 8-bit or 16-bit controllers,
it’s just something to keep in mind.
The following keys and key combinations are available to the user to adjust the value of the Spinner control.
Note that for convenience, the plus key ('+'
) is interpreted as ’UpArrow’,
and the minus key ('-'
) is interpreted as ’DownArrow’.
The following examples are excerpted from the Dialog2 test application, Test03. See the test application for working examples.
//*********************** //* Spinner Definitions * //*********************** // integer. 4-wide (positive values only) dspinData dsData_A( 0, 999, 0, dspinINTEGER, nc.blG ); // integer, 5-wide (positive and negative values) dspinData dsData_B( -999, 999, 0, dspinINTEGER, nc.blG ); // decimal, 5-wide (positive, 1 decimal place) dspinData dsData_C( 0, 999, 25, dspinDEC1, nc.grG ); // decimal, 6-wide (positive and negative, 1 decimal place) dspinData dsData_D( -999, 999, 0, dspinDEC1, nc.grG ); // decimal, 6-wide (positive, 2 decimal places) dspinData dsData_E( 0, 9999, 0, dspinDEC2, nc.maG ); // decimal, 7-wide (positive and negative, 2 decimal places) dspinData dsData_F( -9999, 9999, 0, dspinDEC2, nc.maG ); // decimal, 7-wide (positive, 3 decimal places) dspinData dsData_G( 0, 10000, 0, dspinDEC3, nc.brG ); // decimal, 8-wide (positive and negative, 3 decimal places) dspinData dsData_H( -10000, 10000, 0, dspinDEC3, nc.brG ); //*********************** //* User Interface Loop * //*********************** 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 == dctSPINNER ) { Info.viaHotkey = false ; // discard any hotkey data icIndex = dp->EditSpinner ( Info ) ; // If displayed value has been modified if ( Info.dataMod != false ) { // Take any necessary actions here switch ( Info.ctrlIndex ) { case T3spinnerA: break ; // Spinner A case T3spinnerB: break ; // Spinner B case T3spinnerC: break ; // Spinner C case T3spinnerD: break ; // Spinner D case T3spinnerE: break ; // Spinner E case T3spinnerF: break ; // Spinner F case T3spinnerG: break ; // Spinner G case T3spinnerH: break ; // Spinner H case T3spinOvr3: break ; // Overflow Test 1 case T3spinOvr5: break ; // Overflow Test 2 default: break ; // should never happen } } else { /* Spinner data not modified, so nothing to do */ } } .. .. .. } // (while)
Working code for the following example can be found in
the Dialogw test application, Test07: ’Time Spinner’.╔══════════╣ Time Spinner ╠══════════╗ ║ ║ ║ Enter the time (24-hour) ║ ║ ║ ║ 16:15:35 ║ ║ hh mm ss ║ ║ ║ ║ DONE ║ ║(Mouse input is active in this dialog.)║ ╚═══════════════════════════════════════╝
The DialogSlider-class user interface controls visually indicate a value within the established value range using a slider bar whose height is proportional to the current value.
┌─────┤ Environmental Control Dialog ├─────┐ │ │ │ 40 ▔ │ │ 35 ▔ ▔ │ │ ▔ 35 ▔ │ │ 30 ▔ ▔ │ │ ▔ 30 ▔ │ │ 25 ▔▃▃▃ ▔ │ │ ▔███ 25 ▔▂ │ │ 20 ▔███ ▔█ │ │ ▔███ 20 ▔█ │ │ 15 ▔███ ▔█ │ │ 15 ▔█ │ │ Temperature Control ▔█ │ │ 10 ▔█ │ │ DONE Current Temp °C │ └────────────────────────────────────────────┘
Please see InitCtrl class for information on defining and creating a DialogSlider-class user interface control.
Working examples of Slider controls may be found in at least two(2)
of the test applications:
Dialog1 App, Test #8.
Dialog4 App, Test #10.
Important Note:
The dctSLIDER control type was developed in 2021, well after the For this reason, initialization of the Slider control’s numeric data is designed to occur after the
control has been instantiated (see SetSliderConfig). For convenience, however, it is possible to
initialize all parameters of the Slider control during instantiation if you as the designer
are willing to bend the rules of C++ just a bit. This is done by passing a pointer to the
Please study the example code below for more information. |
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 dctSLIDER, call this method to get user’s keyboard or mouse input.
The value of the control may be adjusted within the defined value range.
The EditSlider method retains control of input until:
If the control grows/shrinks vertically (up and down), the UP_ARROW and DOWN_ARROW keys control value adjustment, while the RIGHT_ARROW and LEFT_ARROW keys are equivalent to TAB and SHIFT+TAB respectively, as described above.
If the control grows/shrinks horizontally (right and left), the RIGHT_ARROW and LEFT_ARROW keys control value adjustment, while the DOWN_ARROW and UP_ARROW keys are equivalent to TAB and SHIFT+TAB respectively, as described above.
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 value has been modified.
('dataMod' flag == 'false').
Please see slider key input, below for a list of user-interface keys which are recognized by the EditSlider method.
Please see uiInfo class for a discussion of the values returned from the Edit method.
Input : cIndex: index of target dctSLIDER control slData: (by reference) a partially-initialized instance of the sliderData class with the following members initialized: minValue : minimum value represented maxValue : maximum value represented curValue : initial value setting vertical : orientation 'true' : grows/shrinks vertically 'false': grows/shrinks horizontally reverse : direction 'false': if 'vertical', grows upward if 'horizontal, grows rightward 'true' : if 'vertical', grown downward if 'horizontal', grows leftward --------- Initial values of other members is are ignored. On return, the remaining fields will be initialized. Returns: OK if successful ERR if invalid input (default values used), OR specified control is not of type dctSLIDER
Specify the minimum, maximum and current values as well as the control’s “input mode” which is based on the control’s orientation (vertical vs. horizontal) and the growth direction (right/up vs. left/down).
This method redraws the control.
Parameters are specified using a partially-initialized instance of the
‘sliderData
’ class.
Required Input Values: ---------------------- double minValue ; // minimum value (default: 0.0) double maxValue ; // maximum value (default: display divisions) double curValue ; // current value (default: 0.0) bool vertical ; // true : bar grows/shrinks vertically // false: bar grows/shrinks horizontally bool reverse ; // reverse the 'standard' growth direction Example Initialization and Call: -------------------------------- double min = -500.0, max = 500.0, curr = 100.0 ; bool vert = true, rev = false ; sliderData slData( min, max, curr, vert, rev ) ; short status = dp->SetSliderConfig ( ctrlIndex, slData ) ; dp->WriteString ( 1, 1, (status == OK ? "Success" : "Failure"), nc.blR, true ) ; Initialized on Return: ---------------------- double curPercent ; // current value's percentage of range short divSteps ; // number of physical display divisions short divCurrent ; // number of divisions displayed for current value
See also 'GetSliderConfig'
method below which returns the current setup.
Input : cIndex: index of target dctSLIDER control slData: (by reference, initial values ignored) receives the current setup information for the control Returns: OK if successful ERR if specified control is not of type dctSLIDER
Returns the current configuration and values of the Slider control.
All data members of the sliderData structure are initialized.
Input : cIndex : index of target dctSLIDER control slValue: new display value either as a value or as a percentage depending on the state of the 'percent' flag. percent: if 'false', interpret 'slValue' as a decimal value if 'true', interpret 'slValue' as a percentage of the value range Returns: OK if successful ERR if spValue is out-of-range if specified control currently has the input focus if specified control is not of type dctSLIDER
Set a new display value for specified dctSLIDER control and update display.
The 'slValue'
parameter is a decimal (double) value which specifies
either:
a)
a value within the established value range
minimum value <= new value <= maximum value
OR
b)
a percentage of the established value range
0.0 <= percentage <= 100.0
Note that the actual value set may be slightly different from the specified value due to rounding errors during conversion of the floating-point value to an integer step size.
Input : cIndex : index of target dctSLIDER control slValue: (by reference, initial value ignored) receives currently-displayed value as a value or as a percentage depending on the state of the 'percent' flag. percent: if 'false', 'slValue' receives the actual decimal value if 'true', 'slValue' receives the decimal value expressed as a percentage of the value range Returns: OK if successful ERR if specified control is not of type dctSLIDER
Return the currently-displayed value for the specified dctSLIDER control.
The value returned is a decimal (double) value which specifies either the
the actual current value of the control or the current value
expressed as a percentage of the established value range:
0.0 <= percentage <= 100.0
Input : cIndex: index of target dctSLIDER control enable: 'true' to enable audible alerts 'false' to disable audible alerts Returns: OK if successful ERR if specified control is not of type dctSLIDER
Enable or disable audible alert (beep) when user attempts to increase or decrease the Slider data beyond the established limit during edit of the Slider 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 UserAlert method.
short yOffset, short xOffset, const char* fmtSpec,
attr_t txtAttr, bool reportPct )
Input : cIndex : index of target dctSLIDER control enable : 'true' to enable automatic value display 'false' to disable automatic value display yOffset: Y offset from dialog origin for value display xOffset: X offset from dialog origin for value display fmtSpec: format specification for display of value, either value or percentage with optional units (see note below) txtAttr: color attribute for display text reportPct: if 'true', report the current percentage of range if 'false', report the current value Returns: OK if successful ERR if specified control is not of type dctSLIDER
Enable or disable automatic reporting of the current Slider value.
The Slider control differs from the other control types in that its value is displayed graphically rather than textually. For this reason, in addition to the Slider control itself, the value represented by the slider bar may optionally be displayed numerically in the dialog window. This value will be automatically updated by the (EditSlider method) whenever the user changes the Slider’s value.
Note that 'SliderAutoReport()'
formats and writes the current value
to the dialog window, but does not refresh the display.
The 'yOffset'
and 'xOffset'
parameters specify the text position
as the offset from the dialog window origin (upper-left corner). If the
position specified does not allow the value to be fully displayed,
the offsets will be silently adjusted as necessary.
Notes on format specification ('fmtSpec'):
Examples: "%6.1lf °C"
"%4.0lf"
"$%5.2lf per dozen"
Example: "nopuoc htiw ffo tnecrep %3.0lf teG"
Eight navigation keys are recognized for adjusting the value within a Slider control: Up-arrow, Down-arrow, Right-arrow, Left-arrow, Page-Up, Page-Down, Home and End.
Interpretation of these keycodes is defined according to which of four(4) “input modes” is specified for the target control. The “input mode” is based on the direction in which the slider bar grows: Upward, Downward, Rightward, Leftward. A specific mode may be assigned to each Slider control during initialization of the control’s operational parameters (see SetSliderConfig).
a)
Up-Arrow increases value by one step. b)
Down-Arrow decreases value by one step. c)
Page-Up increases value by ten percent (10%) d)
Page-Down decreases value by ten percent (-10%) e)
Home key increases value to maximum. f)
End key decreases value to minimum. g)
Right-Arrow and Left-Arrow are equivalent to
TAB and SHIFT+TAB, respectively.
a)
Up-Arrow decreases value by one step. b)
Down-Arrow increases value by one step. c)
Page-Up decreases value by ten percent (-10%) d)
Page-Down increases value by ten percent (10%) e)
Home key decreases value to minimum. f)
End key increases value to maximum. g)
Right-Arrow and Left-Arrow are equivalent to
TAB and SHIFT+TAB, respectively.
a)
Right-Arrow increases value by one step. b)
Left-Arrow decreases value by one step. c)
Page-Up increases value by ten percent (10%) d)
Page-Down decreases value by ten percent (-10%) e)
Home key increases value to maximum. f)
End key decreases value to minimum. g)
Down-Arrow and Up-Arrow are equivalent to
TAB and SHIFT+TAB, respectively.
a)
Right-Arrow decreases value by one step. b)
Left-Arrow increases value by one step. c)
Page-Up decreases value by ten percent (-10%) d)
Page-Down increases value by ten percent (10%) e)
Home key decreases value to minimum. f)
End key increases value to maximum. g)
Down-Arrow and Up-Arrow are equivalent to
TAB and SHIFT+TAB, respectively.
Mouse Support
Mouse support for NcDialog control objects is discussed in detail in the chapter Mouse Configuration, and Slider-specific mouse information may be found at slider mouse interface.
The operational parameters for Slider controls are set using a
partially-initialized instance of a sliderData
object. These
parameters may be specified in either of two ways.
SetSliderConfig()
as described above.
'spinData'
member of the InitCtrl
structure as shown below.
This example is taken from the Dialog4 test application, Test 10.
See SliderTest.cpp.
The Slider control is a simple, rectangular control with dimensions of
at least one row and one column as defined in the InitCtrl
object
for the control. Any reasonable height and width for the control may be
specified, within the limits of the dialog window.
If the dimension in the non-growth direction is greater than one, a ruler with graduations will be displayed. If the growth direction is vertical, the ruler will be placed in the leftmost column. If the growth direction is horizontal, the ruler will be placed on the bottom row (see example).
The “Slider Bar” is a series of block characters. One set
of characters is used for vertical bars, and another set is used for
horizontal bars. These are standard Unicode codepoints in the range
U+2581
through U+2595
. Each set of block characters includes eight(8)
characters, and each character fills a different percentage of the character
cell, from one-eighth (1/8) of the cell to the full cell.
Because these characters may fill only part of the character cell, the
choice of foreground and background colors used is important. These colors
are specified by the 'nColor'
(non-focus color) and 'fColor'
(focus color) members of the InitCtrl
class which defines the control.
For instance, for the screenshot above, the sliders are defined using the
colors nc.brcy
(yellow-on-cyan) and nc.recy
(red-on-cyan)
which provides contrast with the dialog background color, nc.brR
(white text on a blue background).
Please see NcDialog API Color Support for a detailed discussion
of the color attributes available to the NcDialog API
.
When the Slider is set to the minimum value, the slider bar is not visible,
so an arrow character, (▼ ▲ ◀ ▶
) is used to indicate the minimum value.
The point of the arrow indicates the direction from which the slider
bar will grow. In this example, the arrow indicates that the slider will grow
from the left, toward the right:
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒◀ ▒▒
▒▒▕▕▕▕▕▕▕▕▕▕▕▕▕▕▕▕▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
When the value is increased from the minimum value, the indicator arrow
is replaced by the slider bar:
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒████▌ ▒▒
▒▒▕▕▕▕▕▕▕▕▕▕▕▕▕▕▕▕▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
A ’hotkey’ is a shortcut key which may be defined for any user-interface control. The user may press a hotkey in order to move directly to the indicated control without the need to move sequentially through the controls.
The hotkey is optionally specified for a control during the definition of the control object. This is done by placing the ’^’ (caret) character just before the desired hotkey character in the control’s ’label’ field, or in the case of Pushbutton controls (which do not have labels), in the ’dispText’ field of the InitCtrl class. This does two things:
Specification of a hotkey for a control is done according to the following guidelines.
'a'-'z' OR 'A'-'Z'
'M', 'm', 'J', 'j', 'I' or 'i'
as a hotkey is strongly
discouraged because when used in combination with the CTRL key, these
keycodes have a special meaning under Linux/UNIX:'CTRL+M', 'CTRL+m' 'CTRL+J'
and 'CTRL+j'
are all equal to the ENTER key,
while 'CTRL+I'
and 'CTRL+i'
are equal to the TAB key.
'a'-'z'
and 'A'-'Z'
will be interpreted as text input, so only the CTRL+__
version of the hotkey will be recognized within a Textbox control.'CTRL+C', 'CTRL+V'
and 'CTRL+X'
(or whatever key combinations you have
specified) will probably be reserved for that functionality (at least while
the user is in a Textbox control), so these would then be in conflict with
the equivalent hotkey.
The following control definitions show how a hotkey may be assigned to a control, and the text array shows how hotkeys may be assigned to each line-item in a Menuwin control.
In the definition for the Pushbutton control:
The Pushbutton’s display text is the word "DONE" as specified in the ’dispText’
field. The hotkey is assigned to the ’D’ character by placing a ’^’ (caret)
before it.
In the definition for the Menuwin control:
The label text for the Menuwin control is the string " Football team " as
specified in the ’label’ field. The hotkey is assigned to the ’t’
character by placing a ’^’ (caret) before it.
The line-item data defined for the Menuwin contents contains a hotkey specification for each line item. (Be sure to avoid hotkey duplication among line items.)
const short DATA_ITEMS = 12; // items in list const short ITEM_WIDTH = 20; // chars per item (incl. NULLCHAR) //* Display text for Scrollbox control * const char TeamNames[DATA_ITEMS][ITEM_WIDTH + 1] = { " ^Arsenal ", " Aston ^Villa ", " ^Blackburn ", " B^ournemouth ", " B^urnley ", " ^Chelsea ", " ^Liverpool ", " ^Manchester United ", " Mancheste^r City ", " ^Newcastle United ", " ^Southhampton ", " ^West Ham United ", }; //* Color attributes for list * attr_t monoColor[2] = { attrDFLT, nc.gr }; InitCtrl ic[2] = // array of dialog control initialization objects { { //* 'DONE' pushbutton - hsPB * dctPUSHBUTTON, // type: rbtTYPES, // rbSubtype: (n/a) false, // rbSelect: (n/a) 6, // ulY: upper left corner in Y 10, // ulX: upper left corner in X 1, // lines: control lines 8, // cols: control columns " ^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: allow control to gain focus &ic[hsMW] // nextCtrl: link in next structure }, { //* 'Team' Menuwin - hsMW * dctMENUWIN, // type: define a scrolling-data control rbtTYPES, // rbSubtype: (n/a) false, // rbSelect: (n/a) 2, // ulY: upper left corner in Y 3, // ulX: upper left corner in X 1, // lines: (n/a) (ITEM_WIDTH + 2), // cols: control columns (const char*)&TeamNames, // dispText: text-data array nc.gr, // nColor: non-focus border color nc.grR, // fColor: focus border color tbPrint, // filter: (n/a) " Football ^team ", // label: label text -1, // labY: label offset ZERO, // labX ddBoxTYPES, // exType: (n/a) DATA_ITEMS, // scrItems: elements in text/color arrays ZERO, // scrSel: (n/a) monoColor, // scrColor: color-attribute list NULL, // spinData: (n/a) true, // active: allow control to gain focus NULL // nextCtrl: link in next structure }, } ;
(Working code for this example can be found in the Dialogw test application, Test07: ’Hotkey Demonstration’.)
Technical Note: If the mouse interface has been activated, then each control object will have an assigned hotkey character: the hotkey character explicitly assigned as described above, OR if no hotkey has been explicitly assigned, then a hidden hotkey referenced only within the API will be assigned. The reason this is done is so that if the user clicks the mouse over a control, then the focus can be immediately changed to that control as if the user had pressed the assigned key. Hidden hotkeys are guaranteed not to conflict with application-specified hotkeys.
const gString& gStr, attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
const char* uStr, attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
const wchar_t* wStr, attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
Input : startY : Y cursor start position startX : X cursor start position OR startYX: Y/X cursor start position FOR UTF-8-ENCODED CHARACTERS (INCLUDING ASCII) uStr : pointer to null-terminated UTF-8-encoded string (maximum number of bytes incl. NULLCHAR == gsMAXBYTES) OR FOR wchar_t 'WIDE' CHARACTERS wStr : pointer to null-terminated 'wide' wchar_t string (maximum number of chars incl. NULLCHAR == gsMAXCHARS) OR FOR DIRECT DISPLAY OF DATA STRING IN A gString CLASS OBJECT gStr : a gString-class object (by reference) (maximum number of chars incl. NULLCHAR == gsMAXCHARS) NOTE: String length will be truncated at edge of window. NOTE: ASCII control characters, 0x01 - 0x1F are ignored. cAttr : color attribute refresh: (optional, default==false) refresh display window rtl : (optional, 'false' by default) for RTL written languages if 'true', cursor moves from right-to-left Returns: returns final position of cursor If specified starting Y/X position is valid, then cursor position returned will be the the column following the last character of displayed data (or the last column of the target line). If specified starting position is invalid, then cursor position is set to window origin (ZERO/ZERO) and no data will be written. Note on cursor position returned: Y value will be the same as startY, and X value will never be greater than last column in the window, nor less than ZERO.
Write a character string at the specified position in the window.
Optionally, refresh the display before return to caller.
Output will be truncated as necessary to avoid writing outside the dialog window’s boundaries.
All languages AND the complete UTF-8 character set are supported. Please see Multi-language Support for a further discussion of internationalization.
attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
Input : startY : Y cursor start position startX : X cursor start position OR startYX: Y/X cursor start position FOR UTF-8-ENCODED CHARACTERS (INCLUDING ASCII) uChar : pointer to character to display (single-byte or multi-byte character) OR FOR WCHAR_T CHARACTERS wChar : character to display in wchar_t format NOTE: ASCII control characters, 0x01 - 0x1F are ignored. cAttr : color attribute refresh: (optional, default==false) refresh display window rtl : (optional, 'false' by default) for RTL written languages if 'true', cursor moves from right-to-left Returns: returns final position of cursor If specified starting Y/X position is valid, AND if the specified character is a printing character, then cursor position returned will be the the column following the character (or the last column of the target line). If specified starting position is invalid, OR if non-printing character specified, then cursor position is set to window origin (ZERO/ZERO) and no data will be written.
Write a single character at the specified position.
Optionally, refresh the display before return to caller.
Output will be truncated as necessary to avoid writing outside the dialog window’s boundaries.
Programmer’s Note: Do not attempt to write a sequence of multi-column, RTL (right-to-left) characters using the
'WriteChar'
methods. Doing so requires knowledge of the number of columns occupied by each character in order to position the cursor correctly. This positioning is handled automatically by the'WriteString'
and'WriteParagraph'
methods.
IMPORTANT NOTE: Because it can never be assumed that one character equals one byte, there is no option to pass a one-byte character by value. ("You’ll thank me later." - Adrian Monk)
All languages AND the complete UTF-8 character set are supported. Please see Multi-language Support for a further discussion of internationalization.
const gString& gStr,
attr_t cAttr,
bool refresh=false, bool rtl=false );
attr_t cAttr,
bool refresh=false, bool rtl=false );
Input : startY : Y cursor start position startX : X cursor start position OR startYX: Y/X cursor start position gStr : pointer to a gString-class object (maximum number of characters incl. NULLCHAR == gsMAXCHARS) NOTE: Except for the newline character '\n', ASCII control characters, 0x01 through 0x1F are ignored cAttr : color attribute refresh: (optional, default==false) refresh display window rtl : (optional, 'false' by default) for RTL written languages if 'true', cursor moves from right-to-left Returns: returns final position of cursor If specified starting Y/X position is valid, then cursor position returned will be the the column following the last character of displayed data (or the last column of the final line). If specified starting position is invalid, then cursor position is set to window origin (ZERO/ZERO) and no data will be written.
Write a multi-line string, starting at the specified position.
Optionally, refresh the display before return to caller.
A newline character ’\n’ signals the end of each line. Automatic line-wrapping is not supported. It is the caller’s responsibility to correctly size each line to fit within the number of columns available in the target window.
Output will be truncated as necessary to avoid writing outside the dialog window’s boundaries.
All languages AND the complete UTF-8 character set are supported.
Please see Multi-language Support for a further discussion
of internationalization.
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 the specified line of the dialog using the defined background color. Display is refreshed.
bool clearAll = false );
Input : lIndex : index of line to be cleared (zero-based) altColor: color attribute for the target line clearAll: (optional, false by default) if 'true', clear entire line, if 'false' do not clear border area Returns: OK if successful ERR if invalid line index
Clear the specified line of the dialog using an alternate color attribute. Display is refreshed.
short cCount, attr_t fillColor = attr_t(-1),
wchar_t fillChar = nckSPACE);
Input : lIndex : index of top line of target area cIndex : index of left column of target area lCount : number of lines in target area cCount : number of columns in target area fillColor: (optional, dialog window's background color by default) alternate color attribute for the target area fillChar : (optional, SPACE character by default) alternate character to write into each character cell NOTE: Specified character must be a single-column character. A multi-column character specification will be ignored. Returns: OK if successful ERR if parameter(s) out-of-range
Clear the specified rectangular area of the dialog window.
Optionally use an alternate color attribute and/or an alternate fill
character.
Display is refreshed.
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
Draw a line of the specified type and style.
This is not just a simple line-drawing method. Instead, the drawing routine scans the existing contents of the window, and if the new line intersects an existing line, then a visual connection of the lines is drawn.
To prevent these automatic line connections, please set the appropriate flag(s) to ’false’: (cLeft, cRight, cTop, cBot, cInsect). Does not refresh the window.
Please see LineDef class for a further discussion of line drawing.
Please see the test application Dialog2, Test08 for line drawing
examples, and a table of line drawing characters is available at
see Line Drawing Characters.
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.
Draw a rectangle within the dialog window.
Does not refresh the display.
This screenshot is from the Dialog1 test application, Test06.
Note that we have used the DrawBox method (with title) to enclose the
two Radiobutton groups, so the user can easily identify which controls
which are grouped together.
Input : none Returns: a winPos class object containing the Y/X cursor position
Get the current position of the cursor.
This method has limited value because the cursor position is a shared resource, and therefore it can never be guaranteed that the cursor will remain where you put it.
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 cursor position within the dialog window.
This method has limited value because the cursor position is a shared resource, and therefore it can never be guaranteed that the cursor will remain where you put it.
Input : none Returns: current cursor state (member of enum ncCurVis)
Returns the current visibility state of the cursor.
This method has limited value because the cursor should be set as invisible during startup, and should remain invisible unless there are exceptional circumstances. Under normal circumstances, the only time the cursor is visible is inside the EditTextbox method.
short SetCursorState ( ncCurVis state );
Input : state : member of enum ncCurVis Returns: OK
Set the visibility state of the cursor.
This method has limited value because the cursor should be set as invisible during startup, and should remain invisible unless there are exceptional circumstances. Under normal circumstances, the only time the cursor is visible is inside the EditTextbox method.
Input : none Returns: OK
Restore the previous visibility state of the cursor.
This method has limited value because the cursor should be set as invisible during startup, and should remain invisible unless there are exceptional circumstances. Under normal circumstances, the only time the cursor is visible is inside the EditTextbox method.
Configuration of the keyboard/mouse input stream is performed during
the application’s startup sequence.
For key-input configuration, please see NCurses Startup-Shutdown.
For application-level mouse support, please see Mouse Configuration.
Gathering keyboard and mouse input from the user is generally done only
by the ’Edit’ methods for the individual control objects.
Please see User Interface Loop for a discussion of the mechanism for
user interaction.
In an NcDialog application, direct key/mouse input is neither necessary nor wise. Still, in addition to the setup and configuration operations, it is possible to directly monitor the keyboard/mouse input stream.
Input : wKey : wkeyCode-class object (by reference) to hold the key/mouse information (initial values ignored) 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.
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.
Please see Mouse Configuration for additional information.
Important note on the returned data:
Never assume that it is safe to refer only to the returned keycode.
The key ’type’ is critical to the correct interpretation of keyboard/mouse
input. Always test the returned data as a keytype/keycode unit.
Please see wkeyCode class for more information.
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.
Please see keyPushback class for information of the key-input queue.
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 its key type or a mouse event to the input queue.
Please see keyPushback class for information of the key-input queue.
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.
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.
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.
Input : none Returns: delay in milliseconds or nckdFOREVER or nckdNODELAY
Returns the current key-input delay in milliseconds.
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.
Please Note:, — The xterm mouse interface is garbage. — The ncurses library mouse interface is rotting garbage. — The NcDialog API mouse interface is rotting garbage in a colorful, heavy-duty trash bag. Please don’t expect miracles.
|
This chapter is divided into the following sections.
This section describes the methods used to configure your application for mouse input.
The NcDialog API mouse interface provides the application with transparent
access to the mouse interface without the need to interpret what mouse
events mean in a given context.
Please see User Interface Loop for more information.
If you are curious about what the raw mouse data look like, the data are available through the low-level NCurses-class methods OR through the see Dump_uiInfo method; however, using the raw data directly within an application is strongly discouraged.
bool swheel = true );
Input : dclick : (optional, ncmiSTABLE by default) This parameter indicates the time to wait after the first click event is received to determine whether the event is a double-click. Specified in thousandths (0.001) of a second OR a member of enum ncmInterval. swheel : (optional, 'true' by default) 'true' : ScrollWheel events are reported 'false' : ScrollWheel events ARE NOT reported Returns: OK if mouse-event reporting enabled and the system supports all required mouse event types and specified timing parameters. returns ERR if: a) mouse could not be enabled b) if optionally-specified 'dclick' value is out of range c) one or more required event types not supported by the system d) the required timing interval could not be established If ERR, then mouse interface will be disabled.
Enable enhanced reporting of mouse events.
The application does not directly interact with the mouse. Instead,
mouse events are reported through the ’GetKeyInput’ keyboard input stream.
The NcDialog API converts mouse events to the equivalent keycodes
whenever possible, and ignores uncoverted mouse events within the
user-interface methods for the individual dialog controls
(see Mouse Event Translation). Thus, the application does not
need to do any mouse-event processing beyond enabling and disabling
the mouse event stream.
This method requires that all necessary parameters be fully supported by the underlying mouse driver. If the system cannot be configured as required, then the mouse interface is disabled and ERR is returned.
This form of enabling the mouse interface is different from the more general meEnableMouse method described below. The purpose of this configuration method is to reduce the unfortunate timing artifacts inherited from the xterm mouse driver and from the ncurses(w) C-language library. This is accomplished by synthesizing the mouse-event timing. It is hoped that this will reduce the loss of valid mouse-event data and improve overall mouse performance.
This method restricts the mouse interface to the following event types, (with and without modifier keys CTRL, SHIFT and ALT).
Note on timing: The ’dclick’ (double-click) delay interval may be set only at the time the mouse interface is enabled, (the meSetClickInterval method is disabled when using the stabilized mouse interface).
To dynamically adjust this interval, it is necessary to disable the mouse interface and then call meEnableStableMouse with the new ’dclick’ value.
Example: .. .. .. // get new interval from user (milliseconds) short newDelay = 400; if ( newDelay >= ncmiNONE && newDelay <= ncmiMAX ) { dp->meDisableMouse (); if ( (dp->EnableStableMouse ( newDelay )) == OK ) ; // deliver good news else ; // deliver bad news }
The default double-click delay assumes a "typical" user. For a user with restricted vision, movement, or other accessibility issues, a longer delay should be specified. Also, if your application has multiple active threads, then specify a slightly longer delay to compensate for the task-switching overhead.
A user-friendly application will provide the user with a way to interactively adjust the click interval.
Example of interactive adjustment using a Spinner control:
(Working code for this dialog can be found in the Dialogw test application, Test07: ’Set Mouse Click Interval’.)
short interval=ncmiDFLT );
Input : eventTypes : bit mask of event types to be enabled Available bitmask definitions are listed below. NOTE: If no mouse-event types are specified, (eventTypes==ZERO), then the following mask is set as the default: eventTypes = BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | REPORT_SCROLL_WHEEL; interval : (optional, ncmiDFLT by default) the maximum interval to wait between the start of an event and the end of the event in thousandths (0.001) of a second. Specify an interval OR a member of enum ncmInterval. Returns: OK if mouse-event reporting enabled AND the system supports all requested event types ERR a) if mouse could not be enabled b) if optionally-specified 'interval' value is out of range c) one or more of the requested event types is not supported by the system (any valid event types will still be reported) In this case, the meGetEventTypes() method should be called to determine which events will be reported.
Enable reporting of mouse events. This method provides full access to the ncurses(w) C library mouse interface, (but see below).
Mouse events are reported within the ’GetKeyInput’ keyboard input stream. (See meEnableStableMouse method, above.)
The ’eventTypes’ parameter specifies the type(s) of mouse events which
will be reported.These definitions apply to the ’ncursesw’ library
version 5.9 (mouse version 1).
If your system defines mouse version > 1
, then please see
the ncurses.h
header file for making bitmask substitutions.
Note 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 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 REPORT_SCROLL_WHEEL Note: For convenience, we locally define the additional event-type mask item ’REPORT_SCROLL_WHEEL’ in NCurses.hpp:
REPORT_SCROLL_WHEEL = BUTTON4_PRESSED | REPORT_MOUSE_POSITION ;
Please see NCurses Mouse Access for details.Only the specified mouse-event types will be reported. All non-requested events will be silently discarded unless the event filter is disabled (see the ’meAutoFilter’ 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.If the mouse driver or mouse hardware does not support a requested event type, then this method will return an error condition; however, any requested event types which ARE supported, will still be reported.
The optional ’interval’ parameter specifies the intra-event delay. so choose an ’interval’ parameter that works for your system. To test the delay value, please see the test applications Dialog4, Test04 OR Dialogw, Test07, ’Set Mouse Click Interval’.
Please see NCurses Mouse Access for a more detailed discussion of the low-level mouse interface.
Note that although this method gives the application full access to the functionality of the low-level ncurses(w) C-library mouse interface, significant timing issues may affect the reliability of event reporting. For this reason, unless you actually need the greater functionality, we suggest that you design your application to use the ’meEnableStableMouse’ method described above.
Input : none Returns: OK if mouse events successfully disabled ERR otherwise
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 this MAY also
disable the xterm mouse driver (system dependent).
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 FlushKeyInputStream method.
Input : none Returns: 'true' if mouse events can be detected and reported else 'false'
Reports whether mouse input is currently enabled.
(See meEnableMouse method, above.)
Input : eventTypes: new mouse-event-type mask Returns: OK if mouse enabled AND all specified bits of the event-type mask have been set successfully returns ERR if: a) actual event-type mask set differs from that specified (valid event types will still be reported) b) if eventTypes == ZERO (i.e. invalid mask) c) mouse interface enabled with meEnableStableMouse, so event types may not be modified d) mouse-event reporting not enabled
Modify the type(s) of mouse events which will be reported.
Please see Mouse Event Types for a complete list of available event types.
Input : eventTypes: (by reference, initial value ignored) receives the mouse-event-type mask Returns: OK if successful ERR if mouse-event reporting not enabled
Reports the mouse-event-type mask for currently-enabled event types.
Generally useful only if ’meEnableMouse’ or ’meSetEventTypes’
methods return an error.
Input : waitMax : interval in thousandths (0.001) of a second specify an interval OR a member of enum ncmInterval oldWait : (optional, NULL pointer by default) if specified, this is a pointer to a short int variable to receive previous interval value Returns: OK if successful returns ERR if: a) 'waitMax' value out-of-range b) mouse interface enabled with meEnableStableMouse, so intra-click delay may not be modified c) mouse-event reporting not enabled
Specify the maximum interval between a button-press event and a following button-release event that will result in a mouse ’click’ being reported.
Note that this inverval is optionally set when mouse-event reporting is is enabled (see meEnableMouse method).
Note: this interval applies to single-, double- and triple-click events, as well as ScrollWheel events. If the interval between press and release is greater than this value, then a ’click’ event will not be reported. (Note also that for a ’click’ event to be reported, both the press and release must occur in the same character cell.)
The specified interval must be either a member of 'enum ncmInterval'
,
OR a value between one(1) and ncmiMAX. The default interval is ncmiDFLT
(166 milliseconds), which is about right for capturing a single-click
event. If your users have physical disabilities, or if your application uses
double or triple click events, then the click interval should be longer. If
you are capturing ScrollWheel events, then the click interval should probably
be somewhat shorter for smoother scrolling.
Input : waitMax : (by reference, initial value ignored) receives current interval Returns: OK if successful ERR if mouse-event reporting not enabled
Get the current maximum mouse-click interval in thousandths of a second.
Input : none Returns: OK if successful ERR if mouse-event reporting not enabled
Remove any mouse events waiting in the mouse-event queue.
Note that any events that have already been transferred from
the low-level mouse-event queue to the key-input queue will not
be discarded. (see FlushKeyInputStream method)
Input : enable : 'true' to enable auto-conversion (default setting) 'false' to disable auto-conversion Returns: OK if successful ERR if mouse-event reporting not enabled
Within an NcDialog window, mouse event are, by default, automatically and intelligently converted to keycodes (when possible), and will ignore (meaningless) mouse events which occur outside of any control object. This eliminates the need for the application to handle mouse events manually. In general, the less the application needs to know about mouse events, the better.
There may be circumstances, however, when you want to temporarily disable this automatic conversion, but use caution: It means that the edit routines for the dialog controls will will probably ignore the mouse event completely, or may in some cases, return from the edit with the unprocessed mouse event, and your user-input loop would need to know what to do with it.
Input : filter : 'true' enables filtering 'false disables filtering Returns: OK if successful ERR if mouse-event reporting not enabled
Temporarily disable filtering of spurious (unrequested) mouse events.
Filtering is enabled by default, and should REMAIN enabled except for testing.
This is a list of the mouse-event types which are recognized by the
ncurses(w) C-language library and are therefore available to the NcDialog API.
The naming convention is based on the enum eTypes
enumerated
type. These are roughly equivalent to the bitmask definitions discussed in
meEnableMouse method.
The mouse event types actually available to your application depend on your system configuration, your mouse hardware and other factors. You may need to experiment a bit to determine which events are visible to your application. To test event visibility, please see test application Dialog4, Test04.
Event Type Code Description metNONE no event metB1_P Button 1 - button press metB1_R, Button 1 - button release metB1_S ** Button 1 - single click metB1_D ** Button 1 - double click metB1_T Button 1 - triple click metB2_P Button 2 - button press metB2_R, Button 2 - button release metB2_S Button 2 - single click metB2_D Button 2 - double click metB2_T Button 2 - triple click metB3_P Button 3 - button press metB3_R, Button 3 - button release metB3_S Button 3 - single click metB3_D Button 3 - double click metB3_T Button 3 - triple click metB4_P Button 4 - button press metB4_R, Button 4 - button release metB4_S Button 4 - single click metB4_D Button 4 - double click metB4_T Button 4 - triple click metB5_P Button 5 - button press metB5_R, Button 5 - button release metB5_S Button 5 - single click metB5_D Button 5 - double click metB5_T Button 5 - triple click metPOS Mouse pointer position report
(not implemented in the ncurses
library at this time)metSW_D ** Scroll-wheel - scroll down metSW_U ** Scroll-wheel - scroll up Legend: ’**’ indicates that if enabled, NcDialog will translate the event type to a keycode when possible
Please see Direct Mouse-event Example for an example of how to access this information.
All other event types are currently passed through as mouse events with only the Y/X coordinates being converted from terminal relative to dialog relative offsets. In practical terms, this means that mouse events which are not translated to keycodes will be ignored by the user-interface methods for the individual controls. Additional mouse-event-to-keycode translations may be implemented in future releases. Please see Mouse Event Translation for additional details.
'BUTTON1_PRESSED | BUTTON1_RELEASED | BUTTON1_CLICKED'
Note: The mouse-to-keycode translation algorithm meets all specifications described in this section; however, we may refine the algorithm based on feedback from the community.
What follows is a discussion of how mouse events which occur above
a user-interface control object are translated into meaningful keycodes.
Please see wkeyCode class for information on how the data are
stored and transmitted, and see MouseEvent class for details
on the captured mouse data.
All of this translation occurs automatically in the background, so the application does not have to interpret mouse data; however, for an understanding of the user interface, it is useful to know the correspondence between mouse event and keycode.
The way mouse events are interpreted depends upon the type of mouse event detected as well as the type of user-interface control with which the mouse event is associated.
Mouse events that occur within the dialog window but NOT above a control object are meaningless and will be silently discarded, EXCEPT that if a control is in the ’expanded’ state, then a click event that is not associated with that control will collapse the expanded control.
Mouse events that occur outside any dialog window belong to someone else and are not available to the application.
For all active controls an associated mouse ’click’ event moves
the input focus to that control as if the user had pressed a ’hotkey’
combination associated with the control. Note that it is not necessary
to explicitly assign a hotkey to a control in order for the mouse
interface to function properly.
Note: Hotkeys for all user interface control objects
are masked when an expanded Menuwin control has the input focus (because
line items in Menuwin controls have their own hotkeys).
For more information on hotkeys, please see Select Control via Hotkey.
Mouse ’ScrollWheel’ events apply to some control types but not to other types as detailed below.
Mouse event types in the following table are referenced as members of enum meTypes, and the event type is located in the ’meType’ member of the MouseEvent class. Please refer to the discussion of event types: see Mouse Event Types.
Note that left-handed users often swap mouse Button #1 and Button #3. This swap takes place at the mouse-driver level, so that for purposes of this discussion, the ’left’ mouse button is whatever button you have assigned as the primary button during system configuration.
a)
If the target control is not the control with input focus,
convert the mouse event to the hotkey associated with the target
control. This will give the control focus AND automatically
indicates that the button has been pressed.
b)
If the target control is already the control with
input focus, then the mouse event is converted to an nckENTER
key.
All other mouse event types are ignored for Pushbutton controls.
a)
If the target control is not the control with input focus,
convert the mouse event to the hotkey associated with the target
control. This will give the control focus AND automatically
indicates that the button has been ’selected’ (set).
b)
If the target control is already the control with
input focus, then the mouse event is converted to an nckSPACE
key.
—
If the control is an independent Radiobutton, then nckSPACE
toggles the state of the button.
—
If the control is a member of an XOR Radiobutton group,
then nckSPACE sets the state of the button.
—
Please see GroupRadiobuttons method for more information
on XOR grouping, or see Your First Application for an
example of grouping Radiobutton controls.
All other mouse event types are ignored for Radiobutton controls.
a)
If the target control is not the control with input focus,
then convert the mouse event to the hotkey associated with the
target control. This will give the control focus.
b)
If the target control is the control with
input focus, then these events are currently ignored.
metB1_S : single click of left button (with CTRL modifier key)
metB1_D : double click of left button
The action is dependent on whether the control currently has focus.
a)
If the target control is not the control with input focus,
then the event has the same effect as a single-click
with no modifier key.
b)
If the target control is the control with input
focus, then convert the event to the nckENTER key which will
complete the edit and move the input focus to the next control.
metSW_U : Scroll-wheel - scroll up
metSW_D : Scroll-wheel - scroll down
This is equivalent to pressing the Right or Left navigation keys.
a)
If the target control is not the control with input focus,
these events are ignored.
b)
If the target control is the control with input focus:
metSW_U
is converted to the nckRIGHT navigation key, which will
move the highlight one character toward the end of the
data, if any.
(with SHIFT modifier key, converted to nckSRIGHT)
metSW_D
is converted to the nckLEFT navigation key, which will
move the highlight one character toward the beginning
of the data, if any.
(with SHIFT modifier key, converted to nckSLEFT)
The data will be scrolled as necessary to bring the target
character into view.
Note that the sense of Right and Left are reversed if the control
contains RTL language text.
All other mouse event types are ignored for Textbox controls.
a)
If the target control is not the control with input focus,
then a click event anywhere on or within the control’s borders will
be converted to the hotkey associated with the target control.
This will give the control focus.
b)
If the target control is the control with input focus, then:
—
if the event occurred in the control’s top border, then
the event is converted to the nckUP navigation key, which
will move the highlight upward to the previous line item, if any.
—
if the event occurred in the control’s bottom border or
in the left or right border, then the event is converted to the
nckDOWN navigation key, which will move the highlight downward
to the next line item, if any.
—
if the event occurs on a line item within the control, then
the highlight is moved to that line item, and the event is
converted to the nckENTER key which 'selects'
that line item.
The data will be scrolled as necessary to bring the target line
item into view.
metSW_U : Scroll-wheel - scroll up
metSW_D : Scroll-wheel - scroll down
This is equivalent to pressing the Up or Down navigation keys.
a)
If the target control is not the control with input focus,
then these events are ignored.
b)
If the target control is the control with input focus, then:
metSW_U
is converted to the nckDOWN navigation key, which will
move the highlight downward to the next line item, if any.
metSW_D
is converted to the nckUP navigation key, which will
move the highlight upward to the previous line item, if any.
The data will be scrolled as necessary to bring the target line
item into view.
All other mouse event types are ignored for Scrollbox and Scrollext controls.
'collapsed'
or 'expanded'
state.
a)
If the target control is in the collapsed state (with or
without focus), then convert the mouse event to the hotkey
associated with the target control. This will give the control
focus AND automatically indicates that the control is to be
immediately ’expanded’.
b)
If the control is in the expanded state, then it has
focus by definition.
—
if the event occurred in the control’s top border, then
the event is converted to the nckUP navigation key, which
will move the highlight upward to the previous line item, if any.
—
if the event occurred in the control’s bottom border or
in the left or right border, then the event is converted to the
nckDOWN navigation key, which will move the highlight downward
to the next line item, if any.
—
if the event occurs on a line item within the control, then
tne highlight is moved to that line item, and the event is
converted to the nckENTER key which 'selects'
that line item.
This selection returns the control to the 'collapsed'
state.
The data will be scrolled as necessary to bring the target line
item into view.
metSW_U : Scroll-wheel - scroll up
metSW_D : Scroll-wheel - scroll down
This is equivalent to pressing the Up or Down navigation keys.
a)
If the target control is not the control with input focus,
or if the control is in the collapsed state, then these events
are ignored.
b)
If the target control is the control with input focus,
and is in the expanded state:
metSW_U
is converted to the nckDOWN navigation key, which will
move the highlight downward to the next line item, if any.
metSW_D
is converted to the nckUP navigation key, which will
move the highlight upward to the previous line item, if any.
The data will be scrolled as necessary to bring the target line
item into view.
All other mouse event types are ignored for Dropdown controls.
'collapsed'
or 'expanded'
state, and
whether the control is a top-level menu or a submenu.
a)
If the target control is in the collapsed state (with
or without focus), then convert the mouse event to the hotkey
associated with the target control. This will give the control
focus AND automatically indicates that the control is to be
immediately ’expanded’.
b)
If the target control is in the expanded state, AND
has input focus:
—
if the event occurred in the title area, then the event
is ignored.
—
if the event occurred in the control’s top border, then
the event is converted to the nckUP navigation key, which
will move the highlight upward to the previous line item, if any,
or will wrap around to the last item.
—
if the event occurred in the control’s bottom border or
in the left or right border, then the event is converted to the
nckDOWN navigation key, which will move the highlight downward to
the next line item, if any, or will wrap around to the first item.
—
if the event occurs on a line item within the control, then
the highlight is moved to that line item, and the event is
converted to the nckENTER key which 'selects'
that line item.
This selection returns the control to the 'collapsed'
state.
c)
If the target control is in the expanded state, BUT
does not have focus, then:
the target control is the parent of a submenu which does have
focus. The event is converted into the nckLEFT key, which will
collapse the submenu which has focus. This may, or may not return
focus to the target control (depending on how many levels of
submenu are expanded).
metSW_U : Scroll-wheel - scroll up
metSW_D : Scroll-wheel - scroll down
This is equivalent to pressing the Up or Down navigation keys.
a)
If the target control is not the control with input focus,
or if the control has focus but is in the collapsed state,
then these events are ignored.
b)
If the target control is the control with input
focus, and the control is in the expanded state:
metSW_U
is converted to the nckDOWN navigation key, which will
move the highlight downward to the next line item, if any,
and otherwise will wrap around to the first line item.
metSW_D
is converted to the nckUP navigation key, which will
move the highlight upward to the previous line item, if
any, and otherwise will wrap around to the last line item.
All other mouse event types are ignored for Menuwin controls.
Please see Menuwin Controls for more information on menus and ’MenuBar’ menu groups.
a)
If the target control is not the control with input focus,
then convert the mouse event to the hotkey associated with the
target control. This will give the control focus.
b)
If the target control is already the control with
input focus, then the event is ignored.
metB1_S : single click of left button (with CTRL modifier key)
metB1_D : double click of left button
The action is dependent on whether the control currently has focus.
a)
If the target control is not the control with input focus,
then the event has the same effect as a single-click
with no modifier key.
b)
If the target control is the control with input
focus, then convert the event to the nckENTER key which will
complete the edit and move the input focus to the next control.
metSW_U : Scroll-wheel - scroll up
metSW_D : Scroll-wheel - scroll down
This is equivalent to pressing the Up or Down navigation keys.
a)
If the target control is not the control with input focus,
then these events are ignored.
b)
If the target control is the control with input focus:
metSW_U
is converted to the nckUP navigation key, which will
increase the value in the control by one(1).
- If the SHIFT key is held down when this event is received,
the event is converted to the nckSUP (SHIFT+UpArrow)
key, which will increase the value in the control by ten(10).
- If the CTRL key is held down when this event is received,
the event is converted to the nckCUP (CTRL+UpArrow)
key, which will increase the value in the control by 100.
- If the ALT key is held down when this event is received,
the event is converted to the nckAUP (ALT+UpArrow)
key, which will increase the value in the control by 1000.
metSW_D
is converted to the nckDOWN navigation key, which will
decrease the value in the control by one(1).
- If the SHIFT key is held down when this event is received,
the event is converted to the nckSDOWN (SHIFT+DownArrow)
key, which will decrease the value in the control by ten(10).
- If the CTRL key is held down when this event is received,
the event is converted to the nckCDOWN (CTRL+DownArrow)
key, which will decrease the value in the control by 100.
- If the ALT key is held down when this event is received,
the event is converted to the nckADOWN (ALT+DownArrow)
key, which will decrease the value in the control by 1000.
All other mouse event types are ignored for Spinner controls.
Please see spinner key input for more information on key input to Spinner controls.
a)
If the target control is not the control with input focus,
then convert the mouse event to the hotkey associated with the
target control. This will give the control focus.
b)
If the target control is already the control with
input focus, then the event is ignored.
In a future release, we may implement adjustment of the
slider-bar value via mouse click.
metB1_S : single click of left button (with CTRL modifier key)
metB1_D : double click of left button
The action is dependent on whether the control currently has focus.
a)
If the target control is not the control with input focus,
then the event has the same effect as a single-click
with no modifier key.
b)
If the target control is the control with input
focus, then convert the event to the nckENTER key which will
complete the edit and move the input focus to the next control.
metSW_U : Scroll-wheel - scroll up
metSW_D : Scroll-wheel - scroll down
Scroll-wheel mouse events increase or decrease the value displayed by
the Slider control, based on the current “Input Mode”.
There are four(4) Input Modes for increasing/decreasing the value
in the Slider control, and the function of the Up, Down, Left and Right
arrow keys is defined differently for each mode (see slider key input).
Consequently, interpretation of the scroll-wheel events is also defined
by the Slider control’s Input Mode.
If the target control is not the control with input focus,
then scroll-wheel events are ignored.
If the target control is the control with input focus,
the scroll-wheel events are interpreted as follows.
Mode 1)
Slider growth direction is upward:
a) metSW_U
is converted to the nckUP navigation key, which will
increase the value in the control by one(1) step.
- If the SHIFT key is held down when this event is received,
the event is converted to the nckPGUP (Page-Up) key, which
will increase the value in the control by ten percent.
- If the CTRL key or ALT key is held down when this event is
received, the event is converted to the nckHOME (Home) key
which will set the control to its maximum value.
b) metSW_D
is converted to the nckDOWN navigation key, which will
decrease the value in the control by one(1) step.
- If the SHIFT key is held down when this event is received,
the event is converted to the nckPGDOWN (Page-Down) key,
which will decrease the value in the control by ten percent.
- If the CTRL key or ALT key is held down when this event is
received, the event is converted to the nckEND (End) key
which will set the control to its minimum value.
Mode 2)
Slider growth direction is downward:
a) metSW_D
is converted to the nckDOWN navigation key, which will
increase the value in the control by one(1) step.
- If the SHIFT key is held down when this event is received,
the event is converted to the nckPGDOWN (Page-Down) key,
which will increase the value in the control by ten percent.
- If the CTRL key or ALT key is held down when this event is
received, the event is converted to the nckEND (End) key
which will set the control to its maximum value.
b) metSW_U
is converted to the nckUP navigation key, which will
decrease the value in the control by one(1) step.
- If the SHIFT key is held down when this event is received,
the event is converted to the nckPGUP (Page-Up) key, which
will decrease the value in the control by ten percent.
- If the CTRL key or ALT key is held down when this event is
received, the event is converted to the nckHOME (Home) key
which will set the control to its minimum value.
Mode 3)
Slider growth direction is to the right:
a) metSW_U
is converted to the nckRIGHT navigation key, which will
increase the value in the control by one(1) step.
- If the SHIFT key is held down when this event is received,
the event is converted to the nckPGUP (Page-Up) key, which
will increase the value in the control by ten percent.
- If the CTRL key or ALT key is held down when this event is
received, the event is converted to the nckHOME (Home) key
which will set the control to its maximum value.
b) metSW_D
is converted to the nckLEFT navigation key, which will
decrease the value in the control by one(1) step.
- If the SHIFT key is held down when this event is received,
the event is converted to the nckPGDOWN (Page-Down) key,
which will decrease the value in the control by ten percent.
- If the CTRL key or ALT key is held down when this event is
received, the event is converted to the nckEND (End) key
which will set the control to its minimum value.
Mode 4)
Slider growth direction is to the left:
a) metSW_D
is converted to the nckLEFT navigation key, which will
increase the value in the control by one(1) step.
- If the SHIFT key is held down when this event is received,
the event is converted to the nckPGDOWN (Page-Down) key,
which will increase the value in the control by ten percent.
- If the CTRL key or ALT key is held down when this event is
received, the event is converted to the nckEND (End) key
which will set the control to its maximum value.
b) metSW_U
is converted to the nckRIGHT navigation key, which will
decrease the value in the control by one(1) step.
- If the SHIFT key is held down when this event is received,
the event is converted to the nckPGUP (Page-Up) key, which
will decrease the value in the control by ten percent.
- If the CTRL key or ALT key is held down when this event is
received, the event is converted to the nckHOME (Home) key
which will set the control to its minimum value.
Please note that an intuitive use of the mouse with Slider controls would be to click on the bar and drag it to the desired position; however, the low-level ncurses mouse interface does not support click-and-drag operations. Sorry about that.
Even if you mistakenly set a Billboard control as ’active’ in your
application, input to that control will be ignored.
Please see Billboard Controls for more information.
An instance of the MouseEvent class lives within the ’wkeyCode’ class, and if a mouse event occurs, it will contain the mouse-event information in the MouseEvent-class public data members. Whether the event is also converted to a keycode depends on the type of event, the position of the event in the dialog, and whether auto-conversion is enabled.
Please see MouseEvent class for additional details on direct access to mouse-event data.
Please Note: This example is provided for informational purposes
only. In a production-worthy application, all mouse data are processed
by the user-input method for each user-interface control type.
Please see User Interface Loop for additional information.
//** Instantiate the dialog window and user-interface controls ** NcDialog* dp = new NcDialog( dInit ) ; . . . // Report the following mouse event types only: mmask_t emask = BUTTON1_CLICKED | BUTTON2_CLICKED | REPORT_SCROLL_WHEEL ; if ( (dp->meEnableMouse ( eMask )) != OK ) { /* report initialization failure, and do recovery */ } . . . gString gs ; // used for formatting the output wkeyCode wk ; // receives the input data dp->GetKeyInput ( wk ) ; // get input if ( wk.type == wktMOUSE ) // mouse event? { gs.compose( "Mouse Event:\n" "position Y:%hd X:%hd\n" "target control object index: %hd\n" "event type (see enum meTypes): %hd\n" "control key pressed: %hhd\n" "shift key pressed : %hhd\n" "alt key pressed : %hhd\n", &wk.mevent.ypos, &wk.mevent.xpos, &wk.mevent.cIndex, &wk.mevent.meType, &wk.cKey, &wk.sKey, &wk.aKey ) ; } else if ( wk.mevent.conv != false ) // converted mouse event? { gs.compose( "Mouse event converted to keycode.\n" "Key Type (see enum wkeyType): %hd Keycode: 0x%08X\n", &wk.type, &wk.key ) ; } else { gs = "No mouse event, keyboard input only\n" ; } // Report the results dp->WriteParagraph ( 1, 1, gs, nc.blR, true ) ; dp->meDisableMouse (); // Disable mouse-event reporting
Mouse support for console applications is implemented in four(4) layers:
None of these layers are very sophisticated nor particularly robust, so
while mouse support is available for NcDialog-based console applications,
please don’t expect a pristine implementation. However, considering
the simple data stream we have available, the NcDialog API does what is
possible to provide a moderately-useful interpretation of mouse input.
Please see meEnableStableMouse method for our best effort.
Because users cannot be expected to memorize complex mouse click sequences, and because the low-level (xterm/wayland)/ncursesw mouse interface is rather simplistic, only Button #1 (left mouse button) can be relied upon across all system configurations. Mouse hardware for most desktop/laptop systems also include ScrollWheels (or ScrollWheel emulation). The ’modifier keys’ (CTRL, ALT, SHIFT) are also often available. Beyond this, the GUI interface and the terminal emulator software will probably capture or redirect most mouse events for other purposes. For this reason, the NcDialog API uses only these event types in translation of mouse events to keycodes:
Please see Mouse Event Translation for more information.
If you don’t use the mouse interface in your application, but you also don’t want the xterm ScrollWheel auto-conversions, there is a hack available:
When mouse events are enabled, then xterm’s auto-conversion feature is disabled, and we receive the actual mouse events as expected.
The methods in this group fall into two categories: passthrough methods for access to lower-level functionality, and convenient, higher-level methods which can be used for common user interface tasks.
Input : gd : initialized genDialog class object (by reference) Returns: OK
Generic information dialog.
Within an application, there is often the need for a simple sub-dialog window which displays a message and waits for the user to finish reading the message before closing the window. It would be tedius and time consuming for an application developer to build individual dialog windows for each message the user needs to see.
The InfoDialog method is exactly what the name implies—the simplest kind of dialog which displays the specified message and waits for the user to close the dialog window.
The InfoDialog method may be used to display any list of constant strings, then waits for user to press ENTER (or ESC).
Give attention to the formatting of line items within the dialog. Line items are drawn leaving one empty column at the edge of the dialog. Therefore when possible leave at least one empty column at the opposite edge. This is not enforced, but style counts for two reasons. First, it will give the user confidence that you, the application designer are not just a hairy troglodyte; and second, a well-crafted message will have a calming influence on a nervous user.
Please see genDialog class for information and examples of generating an Information dialog.
Input : gd : initialized genDialog class object (by reference) Returns: 'true' if user selects 'YES' else 'false'
Generic decision dialog.
Within an application, there is often the need for a simple sub-dialog which asks the user a simple ’Yes’-or-’No’ question. Use this method to display any list of constant strings that ends with such a question, and then wait for user to select either the ’YES’ or ’NO’ pushbutton (the ESC key also equals ’NO’).
For reasons of beauty, messages begin offset by two(2) in X. See note in ’InfoDialog’ method above.
Note that the question posed by the dialog should be written in such a way that can be answered with either a ’Yes’ or ’No’ response.
Please see genDialog class for information and examples of generating a Decision dialog.
Input : pingParms : (optional, NULL pointer by default) If specified, provides parameters for a ping sequence. If not specified, a single ping is sounded. Returns: OK if specified operation is supported by the system ERR if alert not supported by the system
Sound an audible alert to attract user’s attention.
If setup parameters are provided the alert will follow the specified ping sequence until the terminal count is reached OR until user presses any key. If no parameters are provided, then a single ping will be generated, followed by an immediate return.
Note that if user presses a key during the sequence, the key-input buffer will be flushed before returning; however, a caffinated user may manage to press a key we don’t see, so caller should check the key-input buffer on return.
Note that this method supports only the ’beep’, not the ’flash’ functionality; however, the way the ’ncursesw’ C library implements these is that if the alert type specified by the caller is not supported by the system, then the other will be called. If neither is supported (unlikely), then nothing happens.
Important Note: A very small value for ’pInterval’ may not be recognized due to the low-resolution timer used by the underlying C code. Range checking is performed (minUAINTERVAL) to keep the delay within the capabilities of most systems.
While the NCurses class also includes a UserAlert() method, it is a simple, parameter-less beep. The NcDialog-class implementation is somewhat more sophisticated, yet still annoying enough to get the user’s attention.
The following example is excerpted from the NcDialog API documentation example code.
Please see AudibleAlert class for additional information and examples.
short interval = (minUAINTERVAL * 2) );
Input : count : number of pings interval : delay between pings (optional) a) if specified, then this is the inter-ping delay in 20ths of a second b) otherwise delay is set to approximately 0.2 seconds which is a short, but reliable interval Returns: OK if specified operation is supported by the system ERR if alert not supported by the system
Sound an audible alert to attract user’s attention.
This is a simplified version of the UserAlert method above, and does not require full initialization. Instead of receiving the parameters in an AudibleAlert object, this method takes only a ping count and an (optional) inter-ping delay.
Input : none Returns: nothing
Temporarily disable the NCurses engine so external terminal applications can gain full access to the terminal’s functionality.
Call the ’Wake’ method to to re-activate the NCurses engine.
The following example is a typical sequence of events for giving the user access to the command line.
IMPORTANT NOTE: The Hibernate/Wake sequence shown above is quite primitive.
At the application level, calling the ’ShellOut’ method is much preferred for
giving the user access to the command line.
Please see ShellOut method below for more information.
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.
See the example Hibernate/Wake sequence in the ’Hibernate’ method above.
const char* textColor = NULL );
Input : option : member of enum soOptions (optional, 'soE' by default) shellCmd : (optional, NULL pointer by default) - if specified, invoke the specified shell builtin command, shell program or console utility program - if NULL pointer, then invoke a copy of 'bash' shell NOTE: If your default shell IS NOT 'bash', then you should use this parameter to specify your shell program. textColor: (optional, NULL pointer by default) ANSI escape sequence which specifies the color of text written to standard output. (see below) Returns: nothing
Go to command shell.
Important Note: This method should be called ONLY from the primary dialog, AND there should be no sub-dialogs open. If invoked from a sub-dialog, then the primary dialog’s display data may not be properly saved. Note also that if the calling application uses multiple execution threads, then all threads except the calling thread must be paused or terminated before the call to avoid multiple threads simultaneously performing input/output in the terminal window. |
enum soOptions : short { soX, // No message prompts, no pause soE, // Initial message: 'type-Exit-to-return' (default) soP, // Pause after execution with message: 'press-Enter-to-exit' soPN, // Pause after execution with No messages soEP, // Both soE and soP options soEPN, // Both soE and soPN options soCX, // Clear screen, then soX option soCE, // Clear screen, then soE option soCP, // Clear screen, then soP option soCPN, // Clear screen, then soPN option soCEP, // Clear screen, then soEP option soCEPN, // Clear screen, then soEPN option soOPTIONS // number of options } ;
// invoke shell, default color with start msg dp->ShellOut (); // clear screen, write start msg, then invoke shell (blue text) dp->ShellOut ( soCE, NULL, "\033[0;34m" ); // execute 'ps' utility (red text), then pause dp->ShellOut ( soP, "ps", "\033[0;31m" ); // clear screen, execute 'cat' utility (default color), then pause dp->ShellOut ( soCP, "cat Makefile" );
Please see the test application Dialog4, Test08 for additional examples.
Note that there is also an Easter Egg for the ShellOut method in the Dialog1 test application, Test10, Menuwin_A.
ANSI Color Escape Sequences (partial list): =========== Foreground Background ============ Foreground Background Black \033[0;30m \033[0;40m Dark Gray \033[1;30m \033[1;40m Red \033[0;31m \033[0;41m Bold Red \033[1;31m \033[1;41m Green \033[0;32m \033[0;42m Bold Green \033[1;32m \033[1;42m Brown \033[0;33m \033[0;43m Yellow \033[1;33m \033[1;43m Blue \033[0;34m \033[0;44m Bold Blue \033[1;34m \033[1;44m Purple \033[0;35m \033[0;45m Bold Purple \033[1;35m \033[1;45m Cyan \033[0;36m \033[0;46m Bold Cyan \033[1;36m \033[1;46m Light Gray \033[0;37m \033[0;47m White \033[1;37m \033[1;47m
Note that if your terminal does not support ANSI colors, then specifying ’textColor’ will have no effect (except writing some garbage into the window).
It is assumed that the existing foreground/background of the terminal window is Black text on a White background. If this is not the case, then this method could cause minor color artifacts.
Although ’textColor’ may specify both foreground and background color, a
non-default background color may not be handled uniformly by the terminal.
For this reason, it is recommended that only a foreground color be
specified. However, if you feel lucky, please be sure to specify the
background color sequence first:
Example, Yellow-on-Blue: "\033[0;44\033[1;33m"
Note that some shell commands add ANSI escape sequences of their own, and these may conflict with or override the ANSI sequence you specify.
Note that under rare circumstances, when you exit the dialog application, the cursor may retain the color (if any) you specified with ’textColor’.
Note that if ’shellCmd’ specifies a shell builtin command, and if
’textColor’ is specified, then the command will probably use the
specified color, but this cannot be guaranteed.
dp->ShellOut ( "ls", true, "\033[1;31m" ) ;
dp->ShellOut ( "cat Makefile", true, "\033[1;31m" ) ;
Console utilities are more independent and will probably not use the
specified color.
dp->ShellOut ( "less Makefile", true, "\033[1;31m" ) ;
Input : Returns:
*** NOT YET IMPLEMENTED ***
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.
This is a pass-through method to the NCurses-class method of the same name.
While you have probably checked the terminal screen dimension during application startup, the user may re-size the terminal window while your application is running. (User’s can be SO annoying :)
Two things happen when the user re-sizes the terminal window:
For one possible solution, see the example, below.
Input : none Returns: pointer to const string
Returns a pointer to the const string containing the NcDialog API version number. Note that this is also the NcDialog-class version number.
The actual version number string, ’NcDialogVersion’ is located at the top of the NcDialog.cpp source module. The format is ’M.m.pp’, where ’M’ is the Major release, ’m’ is the Minor release and ’pp’ is the patch release.
Author’s Note: Unlike the marketing zombies at Fedora, Ubuntu, Firefox, and so on, who believe that what happens after version 99.9.99 will be someone else’s problem, this author believes in the value of long-term planning. For this reason, we do a strictly incremental advancement of the version number from 0.0.01 to 0.0.02 and so on for all of our software. The only exception is when a new release is functionally incompatible with previous versions.
Input : none Returns: pointer to const string
Returns a pointer to the const string containing the NcWindow-class version number.
Input : none Returns: pointer to const string
Returns a pointer to the const string containing the NCurses-class version number.
Input : none Returns: pointer to const string
Returns a pointer to the const string containing the ’ncursesw’ C-language link library version number.
Note that the library returns a longer string, but we report only the
actual version number with release date.
Example: 5.9.20130511
The following methods are for use ONLY during development. While these methods are stable and reliable, for efficiency reasons, they make intimate assumptions about the way the data are stored, retrieved and presented, and so are more likely to break if the underlying data definitions change. For this reason, these methods should not be used in production code.
Although the code for these methods is reasonably compact (less than 100Kb compiled), all development methods (except ’DebugMsg’) live under the conditional compilation flag: ENABLE_DEVELOPMENT_METHODS, located in ’NcDialog.hpp’, and can be excluded from production builds.
Input : wPos : screen coordinates for display of the sub-dialog info : uiInfo-class object containing the data to be displayed moose: (optional, 'false' by default) if 'true', then display mouse-event data (if any) Returns: nothing
Open a sub-dialog window and display the contents of a uiInfo-class object
returned from one of the control editing routines.
Please see NcDialog Public Methods for a discussion of the individual
Edit_xxx methods.
This method is useful for visually verifying the data returned when the user
has finished interacting with a particular control object.
Please see uiInfo class for a discussion of the data displayed.
bool timeStamp = true,
const char* stylePath = NULL,
short cellsPerLine = 4,
bool lineComments = true,
attr_t simpleColor = ZERO ) ;
Input : fPath : full path/filename for data to be saved fhtml : (optional, false by default) if 'false', then save as text data (viewable in text editor) if 'true', then save as HTML data (viewable in web browser) timeStamp : (optional, default == true) if 'true', then write the timestamp record at the top of the output file. if 'false, then do not write the timestamp record stylePath : (optional, HTML output only) if specified, path/filename to CSS definition file (path will be written into the HTML <head></head>) default == "screenshot-styles.css" cellsPerLine: (optional, HTML output only) range: 1-40, default == 4 if specified, the number of <td></td> cells written per output line lineComments: (optional, HTML output only, default == true) if 'true', then the raw text of each line is written as a comment for easy searching if 'false', then do not write the comment lines simpleColor : (optional, HTML output only, default == ZERO) interior color of the of the dialog being captured Referenced ONLY when simple HTML capture has been specified (see below for details) Returns: OK if successful ERR : a) if parameter out-of-range b) if unable to write data to specified file c) if development methods are disabled
Capture the dialog’s display data, text and color attributes to a file. This method provides three(3) output formats, each with its particular use.
The text portion may be copied into another document such as the this one. Several examples of this capture are available throughout this document. Please see NcDialog Class Overview for one such example.
The data are formatted as an HTML <table> element to ensure consistent horizontal and vertical aligment and to maximize the number of color attributes which can be rendered into the browser window.
By default, browser rendering engines automatically reformat the HTML document according to the rules of HTML syntax, character, word and line spacing schemes, and various non-standard or outrageously-clunky internal rules. For this reason, placing our data into a table is the only reliable way of preventing the browser from screwing with our formatting.
Each character is placed into a <td> cell with its own color attribute as
defined in the CSS definitions.
This presents a rather good-looking HTML document, with the downside that the document is rather large.
This simple format produces a much smaller footprint, and therefore the data can easily be pasted into another document. The drawback of the simplified format is that minor artifacts are produced between characters and between lines. Also, only a small subset of the color attributes available in the NcDialog API can be replicated by this type of capture.
The capture (a.k.a. screenshot) is first saved to temporary memory in a ’SaveWin’ class object, and is then written to a file in the specified format. The capture must proceed in a very specific sequence because an NcDialog window may contain many user interface control objects, each of which has its own memory space. Depending on the state of each control, it may be obscuring part of the parent window or other controls, so these objects are integrated into the parent dialog’s memory space in layers.
Capture to memory is performed by the public ’CaptureDialog’ method, and output to the target file is performed by the private ’ccapFile’ method.
There are several parameters for the ’CaptureDialog’ call which may be used to customize the output. All but the ’fPath’ parameter (target filename) are optional.
By default, ’screenshot-styles.css’ is written into the HTML document as the source of CSS style. This produces Complex HTML output with full-color support.
If however, ’stylePath’ includes the filename ’infodoc-styles.css’, then Simple HTML output is produced, as described above. Note that for Simple HTML captures, you must also specify ’simpleColor’ the color attribute used for the interior of the dialog window. The ’timeStamp’ and ’lineComments’ parameters are reset (false), and the ’cellsPerLine’ parameter is ignored. Below is an example of invoking a Simple HTML capture. Please see the Dialog1 test application (Test08) or the Dialog2 test application (Test07) to view the capture in action. The actual capture is done in the respective callback methods to avoid interfering with the user interface loop.
short status = CaptureDialog ( "simplecap.htm", true, false, "../screenshots/infodoc-styles.css", 1, false, nc.grR ) ;
'InfoDialog'
or 'DecisionDialog'
methods) are generated
internally by the NcDialog API, they cannot be captured directly by the
'CaptureDialog'
method. However, a special-purpose capture
mechanism for these dialogs is available.
To capture screenshots of these dialog windows, open the dialog and
then press ALT+INSERT
. This will capture the dialog in
both plain-text and simple-HTML formats. The capture files
'capturedlgGD.txt'
and 'capturedlgGD.html'
will be written
to the current working directory.
To disable this functionality, in NcDialog.cpp, set the 'GD_CAPTURE'
definition to '0'
.
attr_t baseColor, attr_t selColor ) ;
Input : wPos : screen coordinates for display baseColor: display color for all but 'select' character selColor : display color for 'select' character Returns: nothing
Open a sub-dialog to display the standard formats available for radio buttons.
When you define a DialogRadiobutton-class user interface control object, the
Radiobutton type is specified by the ’rbSubtype’ member of the ’InitCtrl’ class.
Please see InitCtrl class for details.
See the Dialog1 test application (Test05) for an example of this method.
ORInput : wPos : screen coordinates for display baseColor: display color dialog background Returns: nothing
Open a sub-dialog to display the characters of the Alternate Character Set (ACS). These are the ’narrow’ characters embedded within the terminal’s character set. The ACS is a holdover from the old UNIX days when only one (hopelessly unsuitable) character set was available.
The ACS is accessed by setting the ncaATTR bit of the color attribute used to display the character. The ACS is used for drawing lines in the window or displaying certain special characters. The individual characters may be accessed through the acsXXX group of constants in NCurses.hpp.
Example of drawing a line-intersect character using the ACS: char intersection = acsINSECT ; dp->WriteChar ( 2, 2, &intersection, nc.bw | ncaATTR ) ;
See the Dialog2 test application (Test10) for an example of this method.
╔═══════════════════════════════════════════════════════════╗ ║ IMPORTANT NOTE: ║ ║ The ACS is documented for hysterical reasons only, ║ ║ and should never be used within an NcDialog application. ║ ║ Use 'wide' line drawing, and special characters instead. ║ ║ (see 'DisplayLineDrawingSet' method below). ║ ╚═══════════════════════════════════════════════════════════╝
Input : wPos : screen coordinates for display baseColor: display color dialog background Returns: nothing
Open a sub-dialog to display the ’wide’ equivalents to the Alternate Character Set (ACS).
These characters are used for drawing lines in the window or for displaying certain special characters. The individual characters may be accessed through the wcsXXXX group of constants in NCurses.hpp.
NOTE: The ncaATTR color-attribute bit IS NOT USED to display these characters.
See the Dialog2 test application (Test10) for an example of this method.
Input : wPos : screen coordinates for display baseColor: display color dialog background Returns: nothing
Open a sub-dialog to display the line-drawing characters defined within the wcsXXXX group of constants in NCurses.hpp.
These characters are used for drawing lines in the dialog window. For additional information, please see LineDef class.
See the Dialog2 test application (Test08) for an example of this method.
Input : wPos : screen coordinates for display baseColor: display color dialog background Returns: nothing
Display examples lines and shapes drawn using the line-drawing characters.
For additional information, please see LineDef class.
See the Dialog2 test application (Test08) for an example of this method.
bool erase = false ) ;
Input : msg : message to be displayed if message == "%", clear the message area pause : (optional, ZERO by default, i.e. return immediately) If specified, wait before return. Value is interpreted as the number of seconds to pause. If value >= 30, then wait for keypress before returning erase : (optional, false by default): if true, erase the message after the pause interval Returns: nothing
Display a message in the bottom line of the dialog window. Note that this method is not controlled by the ENABLE_DEVELOPMENT_METHODS flag, so it is always available.
For screenshots that are to be integrated into a Texinfo document, please see Updating Texinfo Docs.
However, for a higher-quality capture, the CSS definition file ’screenshot-styles.css’ is provided. This file provides definitions for the full range of color attributes and color combinations supported by the NcDialog API. Thus, you can create a high-quality capture in a stand-alone HTML document which shows off your application to its best advantage.
Capture of an NcDialog window is performed through the ’CaptureDialog’ method as described above. ’screenshot-styles.css’ provides definitions for color and other character formatting required for display of full-color NcDialog window captures. The HTML colors displayed closely match the colors displayed in a terminal window configured to use the ’Linux Console’ color scheme.
Several examples of these screenshots are available on the author’s website (see Technical Support.)
For instance:
http://www.softwaresam.us/docs/html_doc/ss/Dialog2_7_cap.html
The following is a screenshot of the ’Paste Special’ dialog in our FileMangler application. For the ’info’ formatted version of this document, this is a Plain Text capture, but for the HTML formatted version of the document this is a Simple HTML capture.
This chapter details definitions for several classes used to support data access and configuration.
Class Name Description see AudibleAlert class make noise to alert user see cdConnect class visual connections to dialog border see dtbmData class post a temporary Textbox message see genDialog class create a utility dialog window see InitCtrl class define a control object see InitNcDialog class define a dialog window see keyPushback class key data pushback buffer see LineDef class character-based line drawing see MouseEvent class details on mouse-input events see NcColorMap class capture or initialize color map see NcColorPair class component of NcColorMap class see NcRgbSet class component of NcColorMap class see ssetData class initialize Scrollext-class data see uiInfo class contains user input data see winPos class specify y/x coordinates
This class is used to pass initialization data to the NcDialog constructor.
class InitNcDialog { public: // public data members // Dialog size in lines and columns short dLines; // display lines short dColumns; // display columns // Dialog position within the terminal window, interpreted as // an offset from the upper-left corner of terminal window short dYoffset; // offset in Y (lines) short dXoffset; // offset in X (columns) // Dialog title (optional, pass NULL pointer for no title) // If specified, title will be displayed as centered in the // first line of the dialog (integrated with the dialog border const char* dTitle; // Dialog window's border style. // Member of enum ncLineType (see notes below) ncLineType borderStyle; // Color attribute for dialog window border attr_t borderColor; // Color attribute for dialog window interior attr_t interiorColor; // Pointer to an array of user interface control definitions. // (pass a NULL pointer if no controls defined) InitCtrl* ctrlPtr; } ;
Please see SetDialogTitle method.
ncltSINGLE ┌───────────┐ ncltSINGLEBOLD ┏━━━━━━━━━━━┓ ncltDUAL ╔═══════════╗ ncltDASH2 ┌╌╌╌╌╌╌╌╌╌╌╌┐ ncltDASH2BOLD ┏╍╍╍╍╍╍╍╍╍╍╍┓ ncltDASH3 ┌┄┄┄┄┄┄┄┄┄┄┄┐ ncltDASH3BOLD ┌┅┅┅┅┅┅┅┅┅┅┅┐ ncltDASH4 ┌┈┈┈┈┈┈┈┈┈┈┈┐ ncltDASH4BOLD ┌┉┉┉┉┉┉┉┉┉┉┉┐
The following is an example of initializing the InitNcDialog class and instantiating the dialog.
Initialization data for a dialog control object.
A singly-linked list of InitCtrl objects is passed to the NcDialog constructor, one object for each control defined within the dialog. The array may contain from one(1) through MAX_DIALOG_CONTROLS control definitions. See also the ’ctrlPtr’ member of the InitNcDialog class, described above.
The definition and use of each member may be dependent upon the type of control being defined. See below for more detailed notes on the way each data member is used.
class InitCtrl { public: // public data members // Control type from enum DCType DCType type ; // For Radiobuttons controls only: button sub-type. See enum RBType. // For all other control types: unused RBType rbSubtype ; // For Radiobutton controls only: initial state of 'selected' flag. // For all other control types: unused bool rbSelect ; // Position of control expressed as an offset from the // upper-left corner of the dialog window. short ulY ; // offset in Y (lines) short ulX ; // offset in X (columns) // Height of control expressed as the number of display lines. short lines ; // Width of control expressed as the number of display columns. short cols ; // Text data to be displayed within control. // If no text to be displayed, set to NULL pointer const char* dispText ; // Color attribute for the control while it // DOES NOT have the input focus. (see notes) attr_t nColor ; // Color attribute for the control while it // DOES have the input focus. (see notes) attr_t fColor ; // For dctTEXTBOX controls, the input filter. (see notes) // For all other control types: unused tbChars filter ; // Label text for the control. Set to NULL pointer for no label. // For dctPUSHBUTTON controls: unused. const char* label ; // For controls with a label specified (see 'label' member): // Y/X offset from the control's origin for display of the label text. short labY ; short labX ; // For Dropdown controls: direction of expansion. // For all other types: unused. ddBoxExpansionType exType ; // For scrolling controls (dctSCROLLBOX, dctSCROLLEXT, dctDROPDOWN, // and dctMENUWIN), the number of items in the display list. // For all other types: unused. short scrItems ; // For scrolling controls (dctSCROLLBOX, dctSCROLLEXT, dctDROPDOWN, // and dctMENUWIN), the INDEX of initially-highlighted line item. // For all other types: unused. short scrSel ; // For scrolling controls (dctSCROLLBOX, dctSCROLLEXT, dctDROPDOWN, // and dctMENUWIN) controls and optionally for dctBILLBOARD controls, // specifies the color attribute for each line item. (see notes) // For all other types: unused. attr_t* scrColor ; // For dctSPINNER controls: pointer to a dspinData class object // for control initialization. // For dctSLIDER controls: pointer to a sliderData class object // for control initialization. Cast as: (const dspinData*) // For all other types: unused. const dspinData* spinData ; // Indicates whether the control is initially 'active' i.e. is // able to receive the input focus. (see notes) // Important Note: The first control in the list MUST // have this member set ('true'). // For dtcBILLBOARD controls: unused. bool active ; // Pointer to next instance in the singly-linked list of // control definitions.. // If last entry in the list, then set to NULL pointer. InitCtrl* nextCtrl ; };
As a correlary, DO NOT declare this class as ’const’ because the data may need to change dynamically.
Please see DisplayRadiobuttonTypes method for a chart of the Radiobutton formats available.
For independent Radiobutton controls, either state is allowed.
For Radiobutton controls which are part of a Radiobutton group, only
one member of the XOR group may be ’true’, so be sure to define this
member as ’true’ for only one control in the group.
Please see GroupRadiobuttons method for details.
Exception:
Menuwin controls may be positioned to descend beyond the lower boundary
of the parent dialog when expanded. Sub-menus may not
be attached at a position beyond the dialog window.
Note that it is the application’s responsibility to restore any display data outside the parent dialog that may be overwritten by the Menuwin expansion.
Please be aware that writing outside the dialog window carries some risk. The size of the terminal window physically limits how far below the dialog the Menuwin control can expand, and if there is insufficient space, the menu will not expand. The user will see this as an application error, so defend yourself: if the Menuwin control extends beyond the dialog window, then test the height of the terminal window before calling the Edit method to expand the control.
Scrollbox and Scrollext controls are designed to extend into the
dialog’s border area if needed.
Please see ConnectControl2Border method for additional information.
Note however, that the expanding controls, Menuwin and Dropdown controls, may obscure other controls when in the expanded state because the underlying data are saved before the control is expanded, and are restored after the control returns to the collapsed state.
Control Type Minimum Maximum dctPUSHBUTTON 1 height of dialog dctTEXTBOX 1 calculated according to capacity of buffer dctBILLBOARD 1 height of dialog dctSCROLLBOX 3 height of dialog dctSCROLLEXT 3 height of dialog dctDROPDOWN 3 height of dialog (when expanded) dctMENUWIN (ignored) dctRADIOBUTTON forced to 1 dctSPINNER forced to 1 dctSLIDER 1 height of dialog
- NOTE: The height of an ’expanded’ Menuwin control is fixed as the number of line items (’scrItems’ member) + 2 (top and bottom borders).
- NOTE: The height of a Textbox control may be automatically adjusted by the constructor to ensure that:
(lines * cols) <= gsMAXCHARS
- NOTE: The height of an ’expanded’ Dropdown control may be automatically adjusted by the constructor to ensure that the control stays entirely within the dialog window.
cols=9;
▒▒▒▒▒2045.198±▒▒▒▒▒
Control Type Minimum Maximum dctPUSHBUTTON 1 width of dialog dctTEXTBOX 1 width of dialog dctBILLBOARD 1 width of dialog dctSCROLLBOX 3 width of dialog dctSCROLLEXT 3 width of dialog dctDROPDOWN 3 width of dialog dctMENUWIN 3 (expanded) dctRADIOBUTTON (ignored) dctSPINNER max data width + 1 dctSLIDER 1 width of dialog
const char*
.
Note that this is a multi-purpose pointer which accomodates several different text-formatting options for different control types:
dispText = "Eat at Elliot's Donut Hole, Chicago" ;
dispText = "[是]" ;
// Radiobutton example
dispText = " ^Exit " ;
// Pushbutton example
dispText = NULL ;
// no data specified
dctSCROLLBOX
dctDROPDOWN
dctMENUWIN
Points to a two-dimensional UTF-8 character array, OR
to a single array of UTF-8 characters.
For the two-dimensional array, this will require
that you cast your pointer. (see example)
Note that the two-dimensional array with line-item data
that has been pre-sized is much faster to parse, and is
recommended for that reason.
IMPORTANT NOTE ON WIDTH OF DISPLAY ITEMS: It can NEVER be assumed that one character is one column wide. In the real world, people often speak a language other than English, so prepare to become multilingual. To size your line items, you can use experimentation, OR you can use the gString internationalization tool’s ’gscols’ method: (see Statistical Info) If you are new to internationalization of user interfaces, please see the chapter on preparing for multiple languages: (see Multi-language Support) |
For dctSCROLLEXT controls, this data member is optional.
This means that the control’s display data may either be set during
instantiation OR may be set after instantiation. If set during
instantiation, it requires that ALL of the following members be
initialized:
dispText, scrColor, scrItems and scrSel
.
Please see SetScrollextText method for more information.
This member may also optionally be used to set the initial display text
for each display line of a dctBILLBOARD control.
Please see Billboard Controls for more information.
For standard dctRADIOBUTTON controls, dctSPINNER controls, and dctSLIDER controls this member is ignored.
For certain control types, the display text may optionally contain a ’hotkey’ character, specified by placing the ’^’ (caret) character before the hotkey character:
Examples: const char src[][13] = { " Item ^One ", " Item ^Two ", " Item T^hree" }; const char* src = " ^DONE " ;
For other control types, the hotkey is placed in the ’label’ text.
Please see Select Control via Hotkey for more information on
how to specify and use hotkeys.
For controls with borders, this is the color attribute of the border
while control DOES NOT have input focus:
dctSCROLLBOX
dctSCROLLEXT
dctDROPDOWN
For borderless controls, this is the color attribute of the text while
control DOES NOT have input focus:
dctPUSHBUTTON
dctTEXTBOX
dctBILLBOARD
dctRADIOBUTTON
dctSPINNER
dctSLIDER
For dctMENUWIN controls, the ’nColor’ and ’fColor’ members have a special interpretation.
This is confusing, but was a necessary design compromise. Please see the Dialog1 test application, Test10 for a demonstration of how focus and non-focus colors are implemented for Menuwin controls.
For controls with borders, this is the color attribute of the border
while control DOES have input focus:
dctSCROLLBOX
dctSCROLLEXT
dctDROPDOWN
dctMENUWIN (when in expanded state - see above)
For borderless controls, this is the color attribute of the text while
control DOES have input focus:
dctPUSHBUTTON
dctTEXTBOX
dctBILLBOARD
dctRADIOBUTTON
dctSPINNER
dctSLIDER
For the special case of dctMENUWIN controls, please see note for the ’nColor’ member, above.
'enum tbChars'
.
Specifies the text input filter to be applied to user input. The filter
is also applied to any initial contents of the control specified during
instantiation, AND to re-initialization performed through
see SetTextboxText method.
For all other control types, this member is ignored.
tbChars enumerated type (UTF-8 encoding fully supported)
Filter Type Description tbPrint All printing characters (control codes excluded) tbPrintUpper All printing characters and force lowercase to uppercase tbPrintLower All printing chars and force uppercase to lowercase tbAsciiPrint All 7-bit printing characters from SPACE (0x20) through TILDE (0x7E) tbAlNum Alphanumeric characters (all alphabets && numeric systems) including PERIOD tbAlNumSp Alphanumeric characters (all alpha && num) including PERIOD and SPACE tbAlpha Upper and lower case alphabetic characters except SPACE (all alphabets) tbAlphaSp Upper and lower case alpha (all alphabets) including SPACE tbNumeric Numbers ‘0’ through ‘9’ plus PERIOD, PLUS, MINUS (ASCII) tbNumber Numbers only ‘0’ through ’9’ (ASCII) tbHexNum Numbers ‘0’ through ‘9’ and ‘A’ through ‘F’ (‘a’ - ‘f’) (ASCII) tbHexNumUp Same as tbHexNum except force lower case to upper case tbLower Lower case alpha except SPACE (forces upper to lower, all alphabets) tbLowerSp Lower case alpha including SPACE (forces upper to lower, all alphabets) tbUpper Upper case alpha except SPACE (forces lower to upper, all alphabets) tbUpperSp Upper case alpha including SPACE (forces lower to upper, all alphabets) tbURL Characters valid in a web address according to RFC3986 (URL character encoding is not performed within the Textbox control.
See the ‘Encode_URI’ method)tbFileName All valid Linux filename characters except for the ‘special’ characters (see note below) tbFileLinux Same as tbFileName but including the ‘special’ characters. tbPathName Same as tbFileName but with addition of '/'
(forward slash)tbPathLinux Same as tbPathName but including the ‘special’ characters (see note below)
Note on ‘special’ characters:
For Linux filenames, all characters except ‘/’ (forward slash) and ‘\0’ (the NULL character) are valid. However, not all filesystems and operating systems will accept the full range of characters.While strict adherence to the super-restrictive POSIX standard for filenames is rather ridiculous, care should be used to maintain filename portability.
For instance, Windows(tm) reserves the ‘\’ (back slash) and the ‘:’ (colon) for special purposes.
Note also that filesystems such as VFAT and NTFS are not able to handle filenames which contain some of these special characters.
Filenames that must travel across the web should be aware of the following:
# < > $ + % ! ` & * ? ‘ | { } " = / : \ @ and whitespace charactersIn addition, several ‘special’ characters must be ‘escaped’ when sent to the shell (terminal-window control program). What this means is that their special meaning must be removed before they may be sent to shell utilities.
See also EscapeLinuxSpecialChars method for more information.The characters with special meaning for the shell are:
| & ; < > ( ) $ ` \ " ' <space> <tab> <newline> and in some circumstances: * ? [ # ~ = %The filenames ’.’ and ’..’ are of course reserved on nearly all systems.
The ‘tbFileName’ and ‘tbPathName’ filters allow:
1) all alphanumeric characters (all languages) 2) all punctuation characters (all languages) except:< > | : ; & * ? " ` \
3) the'/'
character (‘tbPathName’ only) The ‘tbFileLinux’ and ‘tbPathLinux’ filters allow all of the above characters including the special characters Some languages (e.g. Arabic) include characters which consist of a main character plus metacharacter(s). These may be excluded for technical reasons. (Sorry...) Use of Control Codes 00-1F and 7F (hex) in filenames is not allowed.
('\n')
characters as
line breaks.
Examples: label = "Append to existing data" ; label = "To retain existing data\n" "select the 'append' button." ;
Note that for labels which are positioned as ’Title’ text, only a single line of text is displayed, so any line breaks will be discarded.
Example: label = "Specify a ^Horrible Choice";
Please see Select Control via Hotkey for more information on how to specify and use hotkeys.
POSITION: ulY+labY and ulX+labX
labY = labX = ZERO ;
Examples: // one line above the control and starting in the same column labY = -1 ; labX = ZERO ; // one line below the control and offset two columns to the right labY = 1 ; labX = 2 ; // on the same line as the control and to the right of it labY = ZERO ; labX = 24 ; // on the same line as the control and to the left of it labY = ZERO ; labX = -24 ; // label to be drawn as a control 'Title' // dctSCROLLBOX and dctSCROLLEXT controls only labY = labX = ZERO ;
'enum ddBoxExpansionType'
. Specifies the direction in which
the Dropdown control will expand when it receives the input focus.
The ’ulY’ and ’ulX’ members determine the control’s position.
The ’exType’ member determines the direction(s) of expansion.
The ’lines’ member determines the expanded height of the control, with a minimum value of three(3) and a maximum value determined by the available dialog space in the specified direction(s).
For all other control types, this member is ignored.
NOTE: For Scrollbox, Scrollext and Dropdown controls, the height of the control (see ’lines’ member) determines the number of line items that are simultaneously visible.
NOTE: For Menuwin controls, ALL line items are simultaneously visible
when the control is in the ’expanded’ state; therefore, the height of a
Menuwin control is fixed as: 'scrItems + 2'
.
For all other control types, this member is ignored.
For dctMENUWIN controls, when the menu is expanded, the highlight is always placed on the first line item.
For all other control types, this member is ignored.
This member may also optionally be used to set the initial color attributes
for each display line of a dctBILLBOARD control IF ’dispText’ member
is also specified.
Please see Billboard Controls for more information.
For all other control types, this member is ignored.
scrColor[0] = attrDFLT;
and scrColor[1] == desired color attribute for all line items
scrColor[0] == color attribute for line item 0
, scrColor[1] == color attribute for line item 1
, scrColor[2] == color attribute for line item 2
,For dctSLIDER controls, this is optionally a pointer to
the initialization data for the control.
Note: if used, the pointer must be cast to (const dspinData*)
to fool the compiler. Kludgy, we admit...
Please see sliderData class for more information.
For all other control types, this member is ignored.
Because the input focus must be somewhere, the first control in
the array of controls passed to the constructor is forced to
active = true;
.
Billboard controls are always read-only and can never receive the
input focus, so for dctBILLBOARD controls this member is forced to
active = false;
.
Please see ControlActive method for toggling the active/inactive state of the control under program control.
Because the NcDialog API fully supports the C++11 standard, the entire array of controls may be initialized at once, OR each control may be defined independently and then pointers to the individual definitions may be placed into an array of pointers.
To signal the end of the list, BE SURE to set the ’nextCtrl’ member
of the last item in the array to the NULL ptr:
nextCtrl = NULL
Failure to do so would cause runtime embarrassment.
Data returned to the application’s input loop from the Edit method for each user interface control type.
Please see Dialog Control Objects for more information on the specific values returned from each control’s Edit method.
class uiInfo { public: // public data members short ctrlType ; // type of control edited (enum DCType) short ctrlIndex ; // index of edited control in control list bool hasFocus ; // true if control has input focus on return from edit bool dataMod ; // true if control's data modified during edit wchar_t keyIn ; // last key input received (or ZERO if n/a) wkeyCode wk ; // most recent actual keycode or mouse event // (generally used only for debugging) short selMember ; // for controls that have more than one member: // i.e. Scroll Box, Scrollext, Radio Button Group, // Drop-Down, and Menu-win, this is the // currently-selected member of the group bool isSel ; // for controls that have binary data i.e. Pushbuttons // and independent Radio Buttons, current state: // Radio Button: true if 'selected' // Pushbutton : true if 'pressed' bool viaHotkey ; // true if a valid hotkey was detected during edit, // causing the control being edited to lose focus // NOTE: The following fields contain valid data only if the viaHotkey // flag != false on return from edit routine short h_ctrlType ; // type of control accessed via hotkey (enum dcTYPE) short h_ctrlIndex ; // index of control that received focus via hotkey bool h_hasFocus ; // true if the control has input focus bool h_dataMod ; // true if control's data modified wchar_t h_keyIn ; // last key input received (or ZERO if n/a) wkeyCode h_wk ; // actual last key pressed (generally unused) short h_selMember ; // for controls that have more than one member: // i.e. Scroll Box, Radio Button Group, and Drop-Down, // this is the currently-selected member of the group bool h_isSel ; // for controls that have binary data i.e. Pushbuttons // and independent Radio Buttons, current state: // Radio Button: true if 'selected' // Pushbutton : true if 'pressed' };
ctrlType
ctrlIndex
hasFocus
dataMod
keyIn
selMember
isSel
wk
(for debugging) viaHotkey
h_ctrlType
h_ctrlIndex
h_hasFocus
h_dataMod
h_keyIn
h_selMember
h_isSel
h_wk
(for debugging) 'info.viaHotkey = true;'
'info.viaHotkey = false;'
before the call, if you want a
warm-and-fuzzy feeling.
dataMod
’ flag.
If 'dataMod == false'
, then the data of the control have not
changed, so there is nothing for your user interface loop to do.
If 'dataMod != false'
, then the data of the control have changed,
and you may want to take some action based on those changes.
isSel
’ member indicates the true/false state of the control.
selMember
’ member indicates which
data item in that control has been selected.
'dataMod != false'
,
then call the GetTextboxText or GetSpinnerValue methods, respectively to
retrieve the user’s changes.For the binary controls, moving the input focus to the control by pressing
its hotkey combination is equivalent to navigating to that control and
then pressing the ENTER key. For more information, please see the Edit
methods for the binary controls:
See EditPushbutton method.
See EditRadiobutton method.
One public method, ’HotData2Primary’ is defined for the uiInfo class.
On return from an Edit method for any of the user-interface control types, the user may have shifted the input focus to another control via a defined ’hotkey’.
When this happens, the results of the edit for the control which
previously had the focus are stored in the primary data members,
and the results of the completed edit (if any) for the control
which now has the focus are stored in the hotkey member
variables designated by names of the format 'h_xxx'
. This applies
ONLY to binary-state controls, which at this time include Pushbuttons
and Radiobuttons.
When a hotkey has been used to shift the input focus to a Pushbutton or
Radiobutton control, then that control is likely to have changed its state.
Thus, there will be no need to call the Edit method for the control because
the user’s wishes are already contained in the 'h_xxx'
members, so simply
copy the data from the hotkey members to the primary members using the
’HotData2Primary’ method.
You will know whether the edit was terminated by a hotkey by testing the
'viaHotkey'
member, and you will know whether the control’s state has
changed by testing the new value of the 'dataMod'
member.
Please study the example user-interface loop below.
//* Move the hotkey data and invalidate the h_xx fields * void HotData2Primary ( void ) { ctrlType = h_ctrlType ; ctrlIndex = h_ctrlIndex ; hasFocus = h_hasFocus ; dataMod = h_dataMod ; keyIn = h_keyIn ; wk = h_wk ; selMember = h_selMember ; isSel = h_isSel ; viaHotkey = false ; }
Example: uiInfo Info; // user interface data returned here short icIndex = ZERO; // index of control with input focus bool done = false; // loop control while ( ! done ) { // If user selects a Pushbutton control using a hotkey, // then this implies that the button has been pressed. if ( ic[icIndex].type == dctPUSHBUTTON ) { // If the control obtained input focus through TAB, STAB, etc. // then call the edit method for this type of control. if ( !Info.viaHotkey ) icIndex = dp->EditPushbutton ( Info ) ; // However, if we arrived at this control through a // 'hotkey', then move the results of the completed // edit into the main data members else Info.HotData2Primary () ; // If user modified the control's state if ( Info.dataMod != false ) { .. .. .. } } // If user toggles a Radiobutton control using a hotkey, // then this implies that the button state has been modified. else if ( ic[icIndex].type == dctRADIOBUTTON ) { // If the control obtained input focus through TAB, STAB, etc. // then call the edit method for this type of control. if ( !Info.viaHotkey ) icIndex = dp->EditRadiobutton ( Info ) ; // However, if we arrived at this control through a // 'hotkey', then move the results of the completed // edit into the main data members else Info.HotData2Primary () ; // If user modified the control's state if ( Info.dataMod != false ) { .. .. .. } } // EXCEPT for binary-state controls (Pushbuttons and Radiobuttons), // data in the hotkey members is meaningless and can be ignored. else if ( ic[icIndex].type == dctTEXTBOX ) { icIndex = dp->EditTextbox ( Info ) ; // If user modified the control's state if ( Info.dataMod != false ) { .. .. .. } } // For expanding controls, (Dropdown and Menuwin): // If you want to force the control to expand immediately // on entry to the Edit method, set the 'viaHotkey' flag. // If we arrived at this point via hotkey, then the // 'viaHotkey' flag is _already_ set. else if ( ic[icIndex].type == dctDROPDOWN ) { Info.viaHotkey = true ; // force expansion icIndex = dp->EditDropdown ( Info ) ; if ( Info.dataMod != false ) { .. .. .. } } else if ( ic[icIndex].type == dctMENUWIN ) { Info.viaHotkey = true ; // force expansion icIndex = dp->EditMenuwin ( Info ) ; if ( Info.dataMod != false ) { .. .. .. } } .. .. .. // If the loop will continue AND if the input focus // has not already been changed via hotkey, then // move the input focus to the next/previous control. if ( done == false && !Info.viaHotkey ) { if ( Info.keyIn == nckSTAB ) icIndex = dp->PrevControl () ; else if ( Info.keyIn != ZERO ) icIndex = dp->NextControl () ; } } // while()
class winPos { public: winPos ( void ) ; // Default constructor winPos ( const short& yval, // Initialization constructor const short& xval ) ; short ypos ; // Line number (zero-based) short xpos ; // Column number (zero-based) } ;
This class implements an Y/X coordinate pair for use in positioning objects (or the cursor) on the screen.
Note that in mathematics and in most real-world environments, the order of operators is X-then-Y; however, in ’ncurses’ world the order is Y-then-X, that is Row-then-Column. This is logical, but may take a bit of getting used to. Initialization values are interpreted as offsets from the terminal window origin (upper-left corner of the window) defined as offset zero/zero.
The most common use of winPos is for positioning text output.
Here’s a typical example of following one text string with another.
Note that the value returned by the ’WriteString’ method is the
current cursor position in the form of a winPos class object.
What's the sum of 4 + 6 + 8 ? : The sum is 18 !
Implementation Note: The winPos class supports the initialization of object arrays for certain class objects under the C++11 standard.
Please see wkeyCode class in the chapter on Keycode Constants.
This class is used internally by the NcDialog API to implement the key input look-ahead buffer.
For these reasons, we have made the design decision to implement a more rubust push-back queue within the NCurses class.
If the application uses ’KeyPeek’ (see KeyPeek method) to look ahead in the key-input queue, OR if the application pushes a keyboard/mouse event back into the queue using ’UngetKeyInput’ (see UngetKeyInput method), then the data are stored in this class.
The keyPushback FIFO queue is private data, so the application never accesses the queue directly. Data are retrieved from the queue using ’GetKeyInput’ (see GetKeyInput method).
Although it is generally not necessary for application code to look inside the MouseEvent class, it is useful to know what is happening behind-the-scenes.
An instance of the MouseEvent class lives within the ’wkeyCode’ class, and if an un-converted mouse event occurs, it will contain the following information in its public data members; however, if ’wkeyCode’ contains a converted mouse event or other valid key data, then the mouse-event data are undefined. See GetKeyInput method.
// this is the event-type bitmask used by the ncurses library mmask_t eventType ; // id of mouse or mouse-like device (for multiple devices) short deviceID ; // Screen-relative position group. // These coordinates are relative to the upper left corner of the // ACTIVE area of the terminal window, and are used internally // by the NCurses-class, NOT by NcDialog API applications. short sypos ; short sxpos ; short szpos ; // for touchpads only (not supported) // Dialog window-relative position group // (used only by NcDialog class, not referenced by NCurses class) // These coordinates are relative to the upper left corner of the // dialog window to which the mouse event belongs. short ypos ; short xpos ; short zpos ; // for touchpads only (not supported) short cIndex ; // NcDialog-class control index (if any) short meType ; // NcDialog-class event-type // (member of enum meTypes) bool cKey ; // 'control' key down during event bool sKey ; // 'shift' key down during event bool aKey ; // 'alt' key down during event bool conv ; // 'true' if event data have been // converted to keycode data
Please see Mouse Configuration for additional information.
Please see termColorInfo class in the chapter discussing the NCurses Engine startup sequence.
Component class of the NcColorMap class (see below).
class NcColorPair { public: NcBaseColors fgnd ; // indicates foreground color NcBaseColors bkgnd ; // indicates background color };
Component class of the NcColorMap class (see below).
class NcRgbSet { public: short r ; // Red color register short g ; // Green color register short b ; // Blue color register };
The NcColorMap class is used to capture the current display color settings, or to modify the existing color map.
class NcColorMap { public: // The constructor takes one, optional parameter: // the default background color. NcColorMap ( NcBaseColors bkgnd = ncbcDEFAULT ); // Public data members //-------------------- //* Array of foreground/background color-pairs NcColorPair pairMap[ncPAIR_MAX]; //* Array of (virtualized) R-G-B register values NcRgbSet rgbMap[ncCOLOR_MAX]; // Default backgroud for all foreground colors NcBaseColors bkgndColor; // Number of color pairs supported by terminal short pairCount; // Number of RGB registers supported by terminal short rgbCount; // Number of colors supported by terminal // (This is for information only, and is ) // (not used in any mapping calculations.) short supColors; // 'true' if terminal supports color-pair modification bool canModifyPairs; // 'true' if terminal supports RGB register modification bool canModifyRGB; };
For more information on color mapping, please see Color Attributes.
For more information on adjusting the color map, please refer to:
see NCurses Startup-Shutdown: ’StartNCursesEngine’ and
’StartColorEngine’ methods, and
see NCurses Configuration: ’GetColorMap’ and ’SetColorMap’ methods.
class LineDef { public: // The initialization constructor takes the following parameters: LineDef( type, // indicates line direction: horizontal (ncltHORIZ) // or vertical (ncltVERT) style, // indicates the line style as a member of // enum ncLineType (see below) startY, // startX, // length, // length of line in rows (vertical lines) // or columns (horizontal lines) color // color attribute ) : // The constructor sets all the auto-intersection flags to 'true': // cLeft // connect at left end (horizontal lines) // cRight // connect at right end (horizontal lines) // cTop // connect at top end (vertical lines) // cBot // connect at bottom end (vertical lines) // cInsect // connect when lines cross // Public data members: // -------------------- ncLineType type ; // line type (ncltHORIZ or ncltVERT) ncLineType style ; // line style: member of enum ncLineType short startY ; // start position Y short startX ; // start position X short length ; // line length in rows or columns attr_t color ; // color attribute // if 'true' create an intersection with an existing // line, (except at at new line's endpoints) bool cInsect ; // if 'true' connect on left with an existing line bool cLeft ; // if 'true' connect on right with an existing line bool cRight ; // if 'true' connect on top with an existing line bool cTop ; // if 'true' connect on bottom with an existing line bool cBot ; } ; //* Line-drawing codes for drawing lines and window borders * enum ncLineType : short { ncltHORIZ, // horizontal line ncltVERT, // vertical line ncltSINGLE, // single line ncltSINGLEBOLD, // single, bold line ncltDUAL, // dual line ncltDASH2, // dashed line style 2 ncltDASH2BOLD, // dashed line style 2, bold ncltDASH3, // dashed line style 3 ncltDASH3BOLD, // dashed line style 3, bold ncltDASH4, // dashed line style 4 ncltDASH4BOLD // dashed line style 4, bold } ;
Line definition class used as a parameter for the ’DrawLine’ method.
See DrawLine method.
Lines are drawn left-to-right and top-to-bottom.
By default, as new lines are drawn, they will form a visual connection
with existing lines. To prevent this automatic connection, set the
appropriate flag(s) to ’false’.
Please see Line Drawing Characters for a table of line-drawing characters.
Please see DrawBox method to draw a rectangle in one operation.
Please see dspinData class in the chapter on Spinner-class user interface controls..
class cdConnect { public: cdConnect() // constructor { ul2Left = false ; ul2Top = false ; ll2Left = false ; ll2Bot = false ; ur2Right = false ; ur2Top = false ; lr2Right = false ; lr2Bot = false ; connection = false ; } // connect upper-left of control to left edge of parent dialog bool ul2Left ; // connect upper-left of control to top edge of parent dialog bool ul2Top ; // connect lower-left of control to left edge of parent dialog bool ll2Left ; // connect lower-left of control to bottom edge of parent dialog bool ll2Bot ; // connect upper-right of control to right edge of parent dialog bool ur2Right ; // connect upper-right of control to top edge of parent dialog bool ur2Top ; // connect lower-right of control to right edge of parent dialog bool lr2Right ; // connect lower-right of control to bottom edge of parent dialog bool lr2Bot ; // if 'true', then apply specified connections, else ignore connections bool connection ; } ;
This class is used for passing connection-point data to the ’ConnectControl2Border’ method. The method copies the specified ’cdConnect’ class data into the target control’s definition and then redraws the control.
An initialized genDialog
-class object is used to pass parameters to
the ’InfoDialog’ and ’DecisionDialog’ methods to produce a simple
message dialog.
The ’InfoDialog’ method displays the data contained in the genDialog
-class
object, and then waits for the user to close the dialog.
Please see InfoDialog method for more information.
The ’DecisionDialog’ method displays the data contained in the
genDialog
-class object (formatted as a yes-or-no question), and
then waits for the user to respond.
Please see DecisionDialog method for more information.
The minimum dimensions for the ’InfoDialog’ and ’DecisionDialog’ are defined by two constants.
The maximum dimensions are the dimensions of the parent dialog window.
See the 'dLines'
and 'dCols'
members.
By default, the dialog will be centered in the parent dialog window,
but this can be overridden by passing positioning offsets to the
constructor. See the 'yoffset'
and 'xoffset'
members.
Two constructors are provided: a full-initialization constructor used by the application to create the dialog, and a default constructor which simply inserts a place-holder dialog (see example below).
Note that there are no public data members in the genDialog class. All initialization is based upon the parameters passed to to constructor. While this is somewhat unusual for a class definition, the text and color-attribute data are formatted according to internal criteria for display within the defined dialog dimensions. This makes for a simple, reasonably-bulletproof, general-purpose dialog.
(If you are curious about the details of the data formatting, the constructor is implemented in the ’NcDialog.cpp’ source module.)
// Full-initialization constructor. // Parameters are fully range-checked and are adjusted if necessary. genDialog ( // list of constant string to be displayed, // one string per dialog display line const char** msgList, // dialog background color attr_t dColor, // number of dialog lines // (including top and bottom borders) short dLines, // number of dialog columns // (including left and right borders) short dCols, // Optional: // Y and X offsets from upper-left of parent dialog // (default: centered in parent dialog) short yoffset=(-1), short xoffset=(-1), // Optional: // array of color attributes, one attribute for each line of // data to be displayed. // (default: all data written using 'dColor') const attr_t* msgAttr=NULL, // Optional: // If 'true', interpret strings as RTL language // If 'false' (default), interpret string as LTR language bool rtl=false, // Optional: // Color of Pusbutton control when it DOES NOT have focus. // (default: nc.gyR) attr_t pnColor=attrDFLT, // Optional: // Color of Pusbutton control when it DOES have focus. // (default: nc.reG) attr_t pfColr=attrDFLT, // Optional: // Specify the text (and width) of the 'YES' and 'OK' Pushbuttons. // (Decision-dialog default: " ^YES ") // (Info-dialog default : " ^OK ") const char* yes_text, // Optional: // Specify the text (and width) of the 'NO' Pushbutton. // (Decision-dialog default: " ^NO ") // (Info-dialog default : not used) const char* no_text, );
The default constructor (no parameters specified) simply creates one message: "unitialized", which will be displayed in the title line of the dialog as a reminder that your dialog definition is incomplete.
dLines - 3
dLines - 2
.
Note that the dialog must be positioned entirely within the parent dialog. If it is not, then the dialog will be automagically resized.
Note that the dialog must be positioned entirely within the parent dialog. If it is not, then the dialog will be automagically resized.
The default values are -1/-1
indicating that the dialog is to be centered
within the parent dialog. Note that the dialog must be positioned entirely
within the parent dialog. If it is not, then the position will be automagically
shifted.
NOTE: Failure to carefully count the attributes in the array will result in an out-of-bounds system exception. For this reason, it is recommended that you always build your array with a few extra color attributes to avoid embarrassment.
By default, this is a NULL pointer, indicating that all text should be displayed using the color attribute specified by the ’dColor’ member.
Note that the default names of the Pushbutton(s) are fixed, and are therefore always drawn as LTR text. (but see ‘yes_text’ and ‘no_text’ members)
Each Pushbutton control has two associated color attributes:
'nc.reG'
(bold white text on red background.)
'nc.gyR'
(white text on grey background.)
If the background color specified by the ’dColor’ member is aesthetically incompatible with the default Pushbutton colors, then you can specify a different set of colors to match the dialog background.
For instance, your application dialog may have an overall blue color scheme. In that case the the default Pushbutton colors would have good contrast and would be easily visible. On the other hand if your application’s color scheme were red, then the red Pushbuttons would be invisible against the background. In that case, a different Pushbutton color such as brown or black would provide better contrast.
Note that the caret (’^’) charater indicates the optional hotkey for the control and is not displayed.
Alternate display text for this Pushbutton may be specified, provided that the width (column count) of the text fits within the specified width of the dialog window, AND that it conveys the same general meaning as the default text, AND that the buttons do not overlap.
║ ║ ║ GOT IT! ║ ║ ║ ╚════════════════════════════════════════════╝
Alternate display text for this Pushbutton may be specified, provided that the width (column count) of the text fits within the specified width of the dialog window, AND that it conveys the same general meaning as the default text, AND that the buttons do not overlap.
║ ║ ║ I AGREE ENTIRELY NO WAY, JOSE! ║ ║ ║ ╚════════════════════════════════════════════╝
║ ║ ║ 我完全同意     你肯定是在逗我! ║ ║ ║ ╚════════════════════════════════════════════╝
The following is an excerpt from Test05 of the Dialog2 test application.
short dlines = 10, // vertical size of dialog dcols = 46, // horizontal size of dialog yoff = 10, // Y offset from upper-left of parent xoff = 14 ; // X offset from upper-left of parent //* Create the array of display strings.* gString gs( " %s ", lfName ) ; const char* mList[] = { " Save Captured Key Data To Log File ", // (title) " ", "Captured key data will be appended to the", "following file in the current directory: ", gs.ustr(), "If file does not exist, it will be created.", " Continue?", " ", NULL } ; //* Color attributes, one for each line * const attr_t mAttr[] = { nc.brcy, // (title) dColor, dColor, dColor, nc.bwB, dColor, dColor, dColor } ; //* Create an initialized instance of a genDialog class object.* genDialog gd( mList, dColor, dlines, dcols, yoff, xoff, mAttr ); //* Open the dialog and get user's response.* bool result = dp->DecisionDialog ( gd ) ;
The following example displays our somewhat cynical poem in both English
(LTR language) and Yiddish (RTL language), as well as a Chinese version
to demonstrate multi-column character data.
(Working code for this example can be found in the Dialogw test application,
Test07: ’genDialog Demonstration’.)
The dtbmData class is used for passing text and color parameters to the ’DisplayTextboxMessage’ method (see DisplayTextboxMessage method).
The ’enum dtbmColors’ constants indicate default text color attributes for the data to be displayed (see the ’colorData’ member variable).
enum dtbmColors : attr_t { // use non-focus color defined for the Textbox dtbmNFcolor = (attrDFLT - 1), // use focus color defined for the Textbox dtbmFcolor = (attrDFLT - 2) } ; class dtbmData { public: //* public data members // wchar_t (wide) text data wchar_t textData[gsMAXCHARS]; // color attribute data attr_t colorData[gsMAXCHARS]; // if 'true' (default) refresh display after update bool refreshControl; // if 'true' adjust message to be centered in textbox bool centered; // if 'true' process data as RTL (right-to-left) bool rtlText; };
For convenience, several different constructors are available for initializing the dtbmData class.
pointer to a UTF-8 encoded string
(max length gsMAXBYTES), OR
pointer to a wchar_t string
(max length gsMAXCHARS)
bool refresh = true, short center = ZERO,
bool rtl = false );
bool refresh = true, short center = ZERO,
bool rtl = false );
an array of color attribute values, one for each character
cData[0] == dtbmNFcolor, (use non-focus color)
cData[0] == dtbmFcolor, (use focus color)CAUTION: If cData[0] != dtbmNFcolor && cData[0] != dtbmFcolor,
then your color data buffer must have at least as many elements as
the number of characters (not byte count) in tData. ALSO,
if the ’center’ parameter is specified, the length of the tData
string is dynamically adjusted to fill the target field, so the number
of color attributes in the ’cData’ array must be at least as great
as the total number of displayed characters. Otherwise, a system memory
access violation and application crash will be the likely results.
To be safe, if you are not using one of the defined default color
attributes, always use a color buffer >= number of columns defined for the
target control, or MAX_DIALOG_WIDTH.
To assist in data initialization, the following public methods are defined for the dtbmData class.
For the curious, the dtmbData class implementation is located in the ’NcdControlTB.cpp’ source code module.
The AudibleAlert class is used to pass setup parameters to the UserAlert method to produce an audible user-alert sequence.
Please see UserAlert method for more information.
class AudibleAlert { public: // Default constructor - parameters set for a single ping AudibleAlert ( void ) { this->pCount = 1 ; this->pInterval = minUAINTERVAL ; this->pRepeat = ZERO ; this->pPattern = NULL ; } // Initialization constructor - specify ping sequence. // Note that all parameters except 'pCount' are optional. AudibleAlert ( short c, short i = minUAINTERVAL, short r = ZERO, short d = ZERO, const short* p = NULL ) { this->pCount = c ; this->pInterval = i ; this->pRepeat = r ; this->pDelay = d ; this->pPattern = p ; } // ------------------- // Public Data Members // ------------------- // number of pings (range: 1 - 32,768) short pCount ; // delay between pings (in twentieths of a second) // (range: minUAINTERVAL - 32,768) // Note that units of this parameter were selected as a // compromise between what the simple hardware device can // produce, the resolution of the internal timer, and // what the human ear can distinguish. short pInterval ; // number of times to repeat pCount/pInterval sequence // (range: 1 - 32,768) // A value of -1 indicates that the sequence should be // repeated until a key is pressed. short pRepeat ; // delay (in tenths of a second) between repeats of sequence // (range: 0 - 32,768) short pDelay ; // If specified, this array of interval values replaces // the 'pInterval' data with a sequence of interval values // (in tenths of a second). // The 'pCount' member indicates the length of the array. const short* pPattern ; } ;
For an interactive example of audible-alert sequences, please refer to the test application Dialog4, Test02.
Here is the interesting part of the code and the result:
See Progbar class, for a description of the Progress Bar widget.
This chapter is for applications which require ’Copy’, ’Cut’ and ’Paste’ operations, either within the application itself or for data sharing with other applications.
’Copy’, ’Cut’ and ’Paste’ operations are common in interactive applications, and these operations use a globally-accessible, temporary buffer called the ’clipboard.’
The NcDialog API Local Clipboard is a static local buffer used for transfer of text data among the Textbox controls of the application.
The local clipboard also provides hooks to transparently connect the application’s Textbox controls with the system clipboard for Copy/Cut/Paste operations (see Clipboard Interface for details).
The Local Clipboard IS NOT a member of the NcDialog class. It is a single, shared resource used by all instances of the NcDialog class within the terminal window, but is not visible to other applications.
Please see clipboard flow diagram for a graphical representation of the Local Clipboard’s place in the copy/cut/paste sequence.
Internally, the Local Clipboard is implemented as a private class,
class TextboxLocalClipboard
which is accessed through the following NcDialog public methods:
These methods are described in detail in the discussion of Textbox controls. See Textbox Controls.
Traditionally, the system clipboard was part of the X-windows system;
however, the GNU/Linux community is moving away from X-windows toward a
more modern window manager. The X.org Foundation, along with the the
GNOME and KDE communities and the Free Software Foundation, are leading
the transition from 'X'
to the Wayland compositor.
Previous versions of the NcDialogAPI supported access to the X clipboard, but that support was frankly half-hearted and incomplete. Therefore, support for X has been dropped in favor of Wayland. While Wayland is itself incomplete, it is now established as the future of user-interface management.
Note: If you have an existing NcDialog application which uses a callback method
to access the system clipboard, please comment out that clipboard-access code
to avoid potential conflict with the WaylandCB clipboard interface.
The current version of the NcDialogAPI interfaces with the GNOME/Wayland
clipboard through the “wl-clipboard” utilities written and
maintained by Sergey Bugaev and friends. These utilities
(“wl-copy” and “wl-paste”) must be installed on your
system in order for the WaylandCB class interface to function properly.
Please see Wayland Clipboard for a technical description of
the “wl-clipboard” utilities.
Access to the “wl-clipboard” utilities is integrated into the
NcDialogAPI through a series of pass-through methods which interface with
the WaylandCB class, which in turn, manages the Wayland clipboard interface.
These methods are described below.
While these pass-through methods provide access to all public methods of
the WaylandCB interface class, only four are generally needed by applications
based on the NcDialogAPI:
NcDialog::wcbEnable ( void ) ;
NcDialog::wcbEnable ( reservedKeys& rk ) ;
NcDialog::wcbIsConnected ( void ) ;
NcDialog::wcbDisable ( void ) ;
When the WaylandCB clipboard interface is active, all other clipboard-access
functionality is handled transparently within the EditTextbox()
method group.
Technical Note: Internally, the WaylandCB-class object is a static, non-member object shared among all NcDialog windows. This means that when the application establishes a connection with the system clipboard, any child dialogs opened by the application will automatically inherit access to the system clipboard.
Except where otherwise noted, these NcDialog-class methods simply call
the WaylandCB-class method of the same name.
(See WaylandCB Public Methods.)
wcbEnable
( void );
Input : none Returns: 'true' if successful, else 'false'
WaylandCB pass-through default constructor.
Instantiate the WaylandCB-class object, define the default reserved
keycodes and establish the connection between the application and
the system clipboard.
(See WaylandCB constructor.)
wcbEnable
( reservedKeys& rk );
Input : rk (by reference) list of custom keycodes for copy/cut/paste operations Returns: 'true' if successful, else 'false'
WaylandCB pass-through initialization constructor.
Instantiate the WaylandCB-class object, define the reserved keycodes and
establish the connection between the application and the system clipboard.
(See WaylandCB constructor, and SetTextboxReservedKeys method.)
wcbDisable
( void );
Input : none Returns: 'true' if successful, else 'false'
WaylandCB pass-through destructor.
Terminate the connection with the system clipboard, return all resources
to the system and delete the WaylandCB-class object.
(See WaylandCB destructor.)
wcbIsConnected
( void );
Input : none Returns: 'true' if connection has been established, else 'false'
Report whether communication between the application and the system clipboard has been established.
wcbGet
( char* trg, bool primary = false,
short len = gsMAXBYTES );wcbGet
( wchar_t* trg, bool primary = false,
short len = gsMAXCHARS );wcbGet
( gString& trg, bool primary = false,
short len = gsMAXBYTES );Input : trg : pointer to buffer to receive data char* or wchar_t* or gString& primary : (optional, 'false' by default) 'false', read from "regular" (ordinary, main) clipboard 'true', read from "primary" (highlighted-data) clipboard len : (optional) specify length of target buffer for wchar_t* targets, default == gsMAXCHARS for char* targets, default == gsMAXBYTES for gString targets, default == gsMAXBYTES Important Note: Longer buffers may be specified for char* targets, but for wchar_t* and gString objects, this is the max length because it is the size of the UTF-8 to UTF-32 conversion buffer. Returns: for wchar_t target, number of characters read (incl.NULLCHAR) for char target or gString target, number of bytes read (incl. NULLCHAR) returns wcbsNOINIT if WaylandCB not instantiated returns wcbsNOCONNECT if error i.e. not connected to clipboard returns wcbsNOINSTALL if 'wl-copy' utility not installed
Get a copy of the data on the system clipboard.
wcbSet
( const char* csrc, bool primary = false,
short ccnt = -1 );wcbSet
( const wchar_t* csrc, bool primary = false,
short ccnt = -1 );wcbSet
( const gString& csrc, bool primary = false,
short ccnt = -1 );Input : csrc : pointer to buffer containing source data wchar_t* or char* or gString& primary : (optional, 'false' by default) 'false', write to "regular" (ordinary, main) clipboard 'true', write to "primary" (highlighted-data) clipboard cnt : (optional, -1 by default) number of characters or bytes to write -- If default (-1) specified, write all source data to and including the null terminator. -- If 'cnt' is reached before null terminator is reached, a null terminator is appended and any remaining source data are ignored. -- If 'cnt' == ZERO, then instead of processing 'csrc' data, the wcbClear() method is called instead. Returns: for wchar_t target, number of characters written (incl.NULLCHAR) for char target or gString target, number of bytes written (incl. NULLCHAR) returns wcbsNOINIT if WaylandCB not instantiated returns wcbsNOCONNECT if error i.e. not connected to clipboard returns wcbsNOINSTALL if 'wl-copy' utility not installed
Set contents of the system clipboard.
wcbClear
( bool primary = false );
Input : primary: (optional, 'false' by default) if 'false', clear the "Regular" clipboard if 'true', clear the "Primary" clipboard Returns: 'true' if successful 'false' if not connected, or other error
Clear the clipboard.
wcbBytes
( bool primary = false );
Input : primary: (optional, 'false' by default) if 'false', report the "Regular" clipboard if 'true', report the "Primary" clipboard Returns: bytes of data on the clipboard incl. NULLCHAR returns wcbsNOINIT if WaylandCB not instantiated returns wcbsNOCONNECT if error i.e. not connected to clipboard returns wcbsNOINSTALL if 'wl-copy' utility not installed
Report number of bytes of data stored on the system clipboard.
wcbTypes
( char* trg, short cnt = -1,
bool primary = false );
wcbTypes
( wchar_t* trg, short cnt = -1,
bool primary = false );
wcbTypes
( gString& trg, short cnt = -1,
bool primary = false );
Input : trg : buffer to receive descriptive text for available formats cnt : (optional, -1 by default) size of target buffer for char* and gString targets, default: gsMAXBYTES for wchar_t* target default: gsMAXCHARS NOTE: On average, approximately 200-300 bytes of (ASCII) data will be returned, but be safe. primary: (optional, 'false' by default) if 'false', report the "Regular" clipboard if 'true', report the "Primary" clipboard Returns: for wchar_t target, number of characters read (incl.NULLCHAR) for char target or gString target, number of bytes read (incl. NULLCHAR) returns wcbsNOINIT if WaylandCB not instantiated returns wcbsNOCONNECT if error i.e. not connected to clipboard returns wcbsNOINSTALL if 'wl-paste' utility not installed
Report the available MIME-type formats for retrieving data from the system clipboard.
wcbTest
( const char* testdata );
Input : testdata: a short null-terminated string to use as test data Returns: member of enum wcbStatus: wcbsNOINSTALL 'wl-copy' and/or 'wl-paste' utility not installed wcbsNOCONNECT unable to establish connection with system clipboard, or communication interrupted wcbNOINIT WaylandCB class not instantiated wcbsACTIVE system clipboard communication established and active
Test the connection with the Wayland clipboard.
wcbReinit
( void );
Input : none Returns: 'true' if connection re-established, else 'false'
Terminate the current connection (if any) with the Wayland clipboard, release all local resources, reinitialize local data members, and re-establish the connection.
wcbVersion
( void );
Input : none Returns: pointer to const string of the format: "x.y.zz"
Report the WaylandCB-class version number.
wcbUserAlert
( wcbStatus warnLevel,
const gString* gsptr = NULL, attr_t color = ZERO );Input : warnLevel : indicates the type of warning to be displayed wcbsACTIVE: always report status of connection test wcbsNOINSTALL: always report if not connected wcbsNOCONNECT: report if 'wl-clipboard' utilities installed, but unable to establish connection gsptr : (optional, NULL pointer by default) If specified, pointer to a gString object containing the text to be displayed, with display lines separated by NEWLINE characters. The first line is assumed to be the dialog title. color : (optional, 0 by default) If specified, the dialog border and interior color. Returns: nothing
Display an information dialog reporting the status of the clipboard connection.
This method executes the “wcbTest” method (see above), and presents a simple message describing the results of the test.
Position:
The dialog is centered in the parent dialog window.
Size (x):
The dialog is the width of the widest text string (+4 columns),
but not less than 32 columns and not wider than parent dialog.
Size (y):
The dialog is the height sufficient to display all text strings
(+3 rows), but not less than 4 rows and not greater than parent
dialog.
Color :
Color of the dialog is the same as interior of parent dialog.
Text :
Default text depends on the ’warnLevel’ argument.
Note that if custom text is specified, then the connectivity
test is not performed, because it is assumed that caller has
already performed a call to wcbTest() (or another form of
diagnostic) and has set the display text accordingly.
Example
┌───────────┤ System Clipboard ├───────────┐ │ Connection between application and │ │ system clipboard established and active. │ │ │ │ OK │ └────────────────────────────────────────────┘
To display a customized message, for example to display the status message in a language other than English or in an alternate color, the optional arguments for the call may be specified.
Example
NcDialog* dp = new NcDialog ( dInit ) ; if ( (dp->OpenWindow()) == OK ) { . . . dp->RefreshWin () ; if ( (dp->wcbEnable ()) == false ) { gString gsMsg ( " 系统剪贴板错误! \n \n 无法与系统剪贴板建立连接:通信错误。 " ) ; dp->wcbUserAlert ( wcbsNOCONNECT, gsMsg, nc.maR ) ; } . . . }┌────────┤  系统剪贴板错误! ├─────────┐ │ │ │ 无法与系统剪贴板建立连接:通信错误。   │ │ │ │ OK │ └───────────────────────────────────────┘
For greater control over the layout and content of an information dialog, please see InfoDialog method which provides access to all dialog parameters.
The following is a simple example of initializing the WaylandCB interface
when opening a dialog window, and terminating the connection when the
dialog closes. For a more complete example, please refer to
Dialog1.cpp, Test01()
or Dialogw.cpp, Test10()
.
// Instantiate the NcDialog window. NcDialog* dp = new NcDialog ( dInit ) ; // Open the dialog window. if ( (dp->OpenWindow()) == OK ) { // Establish connection with system clipboard. if ( (dp->wcbEnable ()) != false ) dp->WriteString ( 1, 1, "WaylandCB interface is active.", nc.bl ) ; else dp->WriteString ( 1, 1, "WaylandCB initialization failed.", nc.re ) ; dp->RefreshWin () ; // Make the dialog visible. // User interface loop. . . . //* Terminate connection with system clipboard. * dp->wcbDisable () ; } if ( dp != NULL ) // close the window delete ( dp ) ;
In a future release, the NcDialogAPI will interface directly with the Wayland clipboard, but that is a long-term project, while the WaylandCB class is fully functional and available immediately. |
If your system does not use the Wayland compositor to manage the system interface, then the NcDialogAPI callback functionality may be used to manually interface with X-windows or whatever window manager your system uses.
Please see EstablishCallback method for more information.
On a traditional X-windows system, a shortcut for copy-and-paste into
a terminal window is provided. This shortcut is built on the key
combinations CTRL+SHIFT+C
(copy) and CTRL+SHIFT+V
(paste).
Fortunately, the Wayland development team was wise enough to include
this shortcut method in the Wayland compositor’s design. A brief
description of this important copy/paste method is included here.
First, text in a terminal window or other windowed application may be ’selected’ using the mouse.
Now that the source text has been selected, you have two options. The first is the quick paste which bypasses the system clipboard:
Try it out:
Using the mouse as described above, highlight the sentence you are now
reading. Then position the mouse pointer over an empty terminal window
and press Mouse Button 2. Your highlighted text should be pasted into
the target window.
Your second option is to copy the highlighted text to the system clipboard so it can be accessed by any application:
CTRL+SHIFT+C
CTRL+C
CTRL+C and CTRL+V
in GUI applications, pasting
text from the clipboard into a terminal window (or a terminal-based
application) requires a slightly different action. Use either of
the key combinations: CTRL+SHIFT+V
CTRL+SHIFT+INSERT
As a technical note, what happens is not an actual ’paste’ operation. Instead, the contents of the clipboard are converted to a stream of keycodes which are sequentially written into the window, so pasting text into a terminal window is exactly the same as typing each of the characters on the keyboard (only faster).
Additional technical note: The CTRL+SHIFT+V
and
CTRL+SHIFT+INSERT
commands do not filter ASCII control
codes (such as newline '\n'
characters) and other
non-printing characters, which will be interpreted by your
application as unexpected command codes (e.g. the ENTER key).
(We did mention that this shortcut interface is a simple one, right?)
Our experience shows that novice users of GNU/Linux don’t understand this simple copy-and-paste sequence, and more importantly they don’t want to know about it; so let’s move on to a more direct and intuitive way for users to access the clipboard from within your NcDialog application. The following diagram shows the flow of data to and from the system (Wayland compositor) clipboard and NcDialog Textbox controls within your application.
Please see SetTextboxReservedKeys method for more information on assigning keycodes for clipboard access.
Since the early days of GUI (Graphical User Interface) computing under UNIX, the X Windows windowing system has been used to draw most of what the user sees, as well as hooks to enable most of the users’ interaction with the system. X Windows began life at MIT (Massachusetts Institute of Technology), but for most of its life has been based at the X.Org Foundation which is a non-profit standards group which manages a wide variety of computing projects.
X Windows was never really designed; but rather emerged bit-by-bit, butt-first from the Wild West days of computing. It is truly an amazing system that few of us can actually understand, even if we wanted to do so. However, the ad-hoc nature of X has led to a long series of unsupervised, obsolete or abandoned software protocols as hardware and software environments have evolved. It is also a breeding ground for security vulnerabilities. And it is this last point that has, more than anything else, driven the X.Org Foundation’s effort to replace X with a more modern and robust communications protocol for GUI environments. That new protocol is known as Wayland.
The primary beneficiary of the Wayland protocol is the GNU/Linux community.
In 2017, the GNOME world began the painful and slow transition from X to
Wayland. The interface to Wayland is primarily through the GTK or Qt
developer’s toolkits, which provides only limited support for pure console
applications.
Wayland was, and remains a hotbed of semi-functional code filled with
annoying bugs and questionable design decisions. However, since early 2019 the
Wayland protocol, as implemented within the “GNOME/Wayland compositor”
has stabilized to the point where we are actually starting to get some real
work done again instead of stopping twice a day to write a bug report or
to fire off a rant about how “it used to work under X!!”
And here we are today, introducing our own first step into the Wayland world, the Wayland clipboard interface class “WaylandCB” for console applications.
For GUI developers, access to the Wayland clipboard is built into the GTK or Qt libraries which provide the framework for most GUI applications under Linux. We are happy to let the GUI developers draw their pretty (and sometimes undeniably awesome) pictures on the screen.
However, your author was developing UNIX software long before there was any such thing as a GUI, and believes that if it cannot be done at the command prompt, it probably shouldn’t be done at all. While this is arguably a Neandertal’s point-of-view, the command line is still the heart of the Linux system, and access to the system clipboard from within a terminal window is essential.
Several developers/enthusiasts, notably Sergey Bugaev, have created a suite of console utilities known as the “wl-clipboard” package. The package consists of two console utilities, “wl-copy” and “wl-paste”. While these utilities are simple in concept, they have undergone significant improvement since they were first released.
The wl-clipboard
utilities now provide reliable console access to the
Wayland system clipboard without the need application-specific implementations.
Visit Sergey at:
https://github.com/bugaevc/
Because these are console utilities, they are written primarily for passing text data between the console and the clipboard. They do however support the basics of a general-purpose clipboard.
If you are a developer in Perl, Ruby, Python, etc. these utilities may be called directly. If you are developing in C, C++ or another high-level programming language, it is inconvenient and often messy or dangerous to be calling external utilities. For this reason, we have created a small interface module, WaylandCB which sits between your application and the “wl-clipboard” utilities.
The “wl-clipboard” package must be installed on your system in order to use the WaylandCB clipboard access module. Installation is simple. The package can be installed directly from the repository using your preferred package manager:
sudo dnf install 'wl-clipboard'
or
sudo apt-get install 'wl-clipboard'
The two console utilities will be installed (probably in the
'/usr/bin'
directory).
In the console window, test the installation by copying something to the clipboard and reading it back:
wl-copy "Roses are red, violets are violet. Send me some soon, or I may become violent."
wl-paste
If you get back what you sent, the package is installed correctly.
Note that the usual rules of escaping characters apply to the text which prevents the shell program from “helpfully” interpreting them as shell instructions.
The package also includes a simple “man page.”
info 'wl-clipboard'
or
man 1 'wl-clipboard'
WaylandCB provides a simple interface between console applications and the Wayland clipboards. The Wayland Clipboard Class, “WaylandCB” is a very simple C++ class definition, consisting of two source files, and two dependencies.
The WaylandCB class itself is 800 lines of C++ code in two files:
WaylandCB.hpp
// class definition
WaylandCB.cpp
// class implementation
Software Sam’s first rule of software design is “Write the comments first!”, so you will not be surprised to find that the code is supported by detailed comments to assist the developer in understanding how the clipboard works and how to access it. Many of those comments are duplicated in this document.
It is not actually necessary to understand the mechanics of the code in order to get the full value of its functionality, but for the curious, the path to understanding is an easy one.
Dependency #1:
wl-clipboard utilities: wl-copy and wl-paste
The wl-clipboard utilities and the method for installing them are
described in the previous section.
Dependency #2:
gString.hpp
gString.cpp
The gString module performs encoding conversions between
UTF-8 and UTF-32 (wchar_t) text. In addition, it provides text analysis
and formatting tools similar to the GTK Glib::ustring class, but
much smaller and faster.
The gString module is bundled