Next: Introduction [Contents][Index]
Next: Operational Overview, Previous: NcDialog Library API, Up: (top) [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.
Next: Your First Application, Previous: Introduction, Up: NcDialog Library API [Contents][Index]
Next: Application Layer Methods, Up: Operational Overview [Contents][Index]
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.
Next: Library Internals, Previous: Description of a Dialog, Up: Operational Overview [Contents][Index]
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.
Next: Inheritance Layers, Previous: Application Layer Methods, Up: Operational Overview [Contents][Index]
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.
Next: Thread Safety, Previous: Library Internals, Up: Operational Overview [Contents][Index]
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.
Next: Newbie Corner, Previous: Inheritance Layers, Up: Operational Overview [Contents][Index]
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.
Previous: Thread Safety, Up: Operational Overview [Contents][Index]
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.
Next: What Is a Class?, Up: Newbie Corner [Contents][Index]
Here are a few useful definitions for terms that students often find confusing.
Next: Reading Texinfo documentation, Previous: Vocabulary, Up: Newbie Corner [Contents][Index]
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.
Next: Configuring Linux, Previous: What Is a Class?, Up: Newbie Corner [Contents][Index]
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.
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 :-)
Next: Selected command-line utilities, Previous: Reading Texinfo documentation, Up: Newbie Corner [Contents][Index]
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:
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. ’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).
Shameless plug: The GNU Texinfo page also contains a link to Software Sam’s contribution to the Texinfo project.
Next: Friendly Advice for New Programmers, Previous: Configuring Linux, Up: Newbie Corner [Contents][Index]
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 ’Dialog’ directory with the corresponding files in the other directories, in this example, the ’Dialog2’ subdirectory. For any newer files in ’Dialog’, the files are copied to ’Dialog2’, overwriting the older versions.
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
The 'rmdir' command removes an empty subdirectory name.
The ’unlink’ command is a much simplified version of ’rm’. It can remove only one file.
Some Examples: rm LottoLosers.odt (delete specified file) rm Test.txt Test.htm (delete specified files) rm *.o (delete all object files) rmdir tmpdir (delete an empty directory) rmdir -r old_crap_dir (delete a directory and its contents) unlink timeline.txt~ (delete a backup file)
In general, it is better to send files to the trash, rather than simply deleting them from the filesystem tree; however, there are some files that you ’know’ you will never need again, such as out-of-date object files.
Shameless plug: Note that accessing the local Trashcan from the command line is not as easy as it sounds; however, Software Sam offers two utilities for command-line access to the system’s Trashcan.
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.
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
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 │ │ │ └────────────────────────────────────────────────────────┘
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
Previous: Selected command-line utilities, Up: Newbie Corner [Contents][Index]
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.
Next: NCurses Engine, Previous: Operational Overview, Up: NcDialog Library API [Contents][Index]
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.
Next: Application Framework, Up: Your First Application [Contents][Index]
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)
Next: Create a Dialog Window, Previous: Development Tools, Up: Your First Application [Contents][Index]
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.
Next: Create Control Objects, Previous: Application Framework, Up: Your First Application [Contents][Index]
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.
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:
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.
Next: Simple Interface Loop, Previous: Create a Dialog Window, Up: Your First Application [Contents][Index]
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.
Previous: Create Control Objects, Up: Your First Application [Contents][Index]
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.
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 NcDialog/Misc/fp.tar It is our belief and our hope that you have learned more through your step-by-step construction of the application than you would have learned by simply copying the files. This is something teachers do——sorry for the trick. :-)
Many more and different examples can be found in the test applications
included in the NcDialog API package.
See Application Examples. Enjoy!
Next: NcWindow Meta-layer, Previous: Your First Application, Up: NcDialog Library API [Contents][Index]
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.
Next: NCurses Class Overview, Up: NCurses Engine [Contents][Index]
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.
Next: NCurses Public Methods, Previous: Introduction to ncurses, Up: NCurses Engine [Contents][Index]
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.
Next: NCurses Startup-Shutdown, Previous: NCurses Class Overview, Up: NCurses Engine [Contents][Index]
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 |
Next: NCurses Configuration, Previous: NCurses Public Methods, Up: NCurses Engine [Contents][Index]
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.
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.
Next: NCurses Keyboard Input, Previous: NCurses Startup-Shutdown, Up: NCurses Engine [Contents][Index]
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.
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. .
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.)
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.
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.
Next: NCurses Display Output, Previous: NCurses Configuration, Up: NCurses Engine [Contents][Index]
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.
Next: NCurses Mouse Access, Previous: NCurses Keyboard Input, Up: NCurses Engine [Contents][Index]
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.
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:
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.
Next: NCurses Utility Methods, Previous: NCurses Display Output, Up: NCurses Engine [Contents][Index]
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.
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.
Next: NCurses Debugging Methods, Previous: NCurses Mouse Access, Up: NCurses Engine [Contents][Index]
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.
Next: Color Attributes, Previous: NCurses Utility Methods, Up: NCurses Engine [Contents][Index]
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.
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.
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.
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?
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().
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)
Next: Keycode Constants, Previous: NCurses Debugging Methods, Up: NCurses Engine [Contents][Index]
Next: Platform Color Support, Up: Color Attributes [Contents][Index]
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.
Next: NcDialog API Color Support, Previous: ncurses Color Support, Up: Color Attributes [Contents][Index]
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’.
Next: NcDialog Color Variables, Previous: Platform Color Support, Up: Color Attributes [Contents][Index]
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.
Previous: NcDialog API Color Support, Up: Color Attributes [Contents][Index]
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.
Next: Line Drawing Characters, Previous: Color Attributes, Up: NCurses Engine [Contents][Index]
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+ ~ |
Previous: Keycode Constants, Up: NCurses Engine [Contents][Index]
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.
Next: NcDialog Class Definition, Previous: NCurses Engine, Up: NcDialog Library API [Contents][Index]
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.
Next: NcWindow Public Methods, Up: NcWindow Meta-layer [Contents][Index]
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.
Next: NcWindow Basics, Previous: NcWindow Class Overview, Up: NcWindow Meta-layer [Contents][Index]
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 |
Next: NcWindow Formatting, Previous: NcWindow Public Methods, Up: NcWindow Meta-layer [Contents][Index]
Input : none Returns: nothing
Destructor. Erase the window from the display and release its resources back to the system.
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.
Next: NcWindow Display Output, Previous: NcWindow Basics, Up: NcWindow Meta-layer [Contents][Index]
Input : cAttr : color attribute Returns: nothing
Set a background color for the interior of the window.
Does not redraw the window.
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.
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.
Next: NcWindow Keyboard Input, Previous: NcWindow Formatting, Up: NcWindow Meta-layer [Contents][Index]
Please see WriteString method in the NcDialog chapter.
Please see WriteChar method in the NcDialog chapter.
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.
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
Next: NcWindow Data Scrolling, Previous: NcWindow Display Output, Up: NcWindow Meta-layer [Contents][Index]
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.
Please see meEnableStableMouse method.
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.
Next: NcWindow Passthroughs, Previous: NcWindow Keyboard Input, Up: NcWindow Meta-layer [Contents][Index]
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.
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.
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.
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.
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.
Next: NcWindow Utility Methods, Previous: NcWindow Data Scrolling, Up: NcWindow Meta-layer [Contents][Index]
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.
Next: NcWindow Hotkey Selection, Previous: NcWindow Passthroughs, Up: NcWindow Meta-layer [Contents][Index]
Input : none Returns: a const pointer to the class-version string
Returns a pointer to NcWindowVersion, the NcWindow class version number.
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.
Next: NcWindow Thread Handling, Previous: NcWindow Utility Methods, Up: NcWindow Meta-layer [Contents][Index]
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.
Previous: NcWindow Hotkey Selection, Up: NcWindow Meta-layer [Contents][Index]
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.
Next: gString Text Tool, Previous: NcWindow Meta-layer, Up: NcDialog Library API [Contents][Index]
This chapter describes in detail the NcDialog class and the control objects with which a dialog-based application is populated.
Next: NcDialog Public Methods, Up: NcDialog Class Definition [Contents][Index]
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.
Next: Dialog Window Methods, Previous: NcDialog Class Overview, Up: NcDialog Class Definition [Contents][Index]
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 |
Next: Dialog Control Objects, Previous: NcDialog Public Methods, Up: NcDialog Class Definition [Contents][Index]
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.
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 std::function and std::bind functions, or the std::invoke (since C++17) functionality because it would break existing code. If we can find a way to do it transparently we will implement it in a future release. |
Notes on using a callback method:
Next: NcDialog Display Output, Previous: Dialog Window Methods, Up: NcDialog Class Definition [Contents][Index]
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.
Next: Pushbutton Controls, Up: Dialog Control Objects [Contents][Index]
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’.
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).
Next: Radiobutton Controls, Previous: Using Dialog Controls, Up: Dialog Control Objects [Contents][Index]
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.
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.
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.
Next: Textbox Controls, Previous: Pushbutton Controls, Up: Dialog Control Objects [Contents][Index]
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.
Next: Billboard Controls, Previous: Radiobutton Controls, Up: Dialog Control Objects [Contents][Index]
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.
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.
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.
Next: Scrollbox Controls, Previous: Textbox Controls, Up: Dialog Control Objects [Contents][Index]
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.
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.
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.
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.
IMPORTANT NOTE: If source text is too wide for the control, then excess text will be truncated, NOT wrapped to the next line.
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.
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.)
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.
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.
Next: Scrollext Controls, Previous: Billboard Controls, Up: Dialog Control Objects [Contents][Index]
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:
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.
Next: Dropdown Controls, Previous: Scrollbox Controls, Up: Dialog Control Objects [Contents][Index]
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:
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.
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.)
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.
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.
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 () ;
Next: Menuwin Controls, Previous: Scrollext Controls, Up: Dialog Control Objects [Contents][Index]
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’.
Next: Spinner Controls, Previous: Dropdown Controls, Up: Dialog Control Objects [Contents][Index]
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:
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.)
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.
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:
The user returns from the sub-menu to the parent menu by:
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.
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.
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.
Next: Slider Controls, Previous: Menuwin Controls, Up: Dialog Control Objects [Contents][Index]
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.
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
Example: an initial value of 1524 will be displayed to the user as as 152.4
Example: an initial value of 1524 will be displayed to the user as as 15.24
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).
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 );
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.)║ ╚═══════════════════════════════════════╝
Next: Select Control via Hotkey, Previous: Spinner Controls, Up: Dialog Control Objects [Contents][Index]
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 InitCtrl class definition
was established (2006). The InitCtrl class is used to define the physical attributes all controls
such as position, dimensions and colors; however, the InitCtrl class does not include a way to
directly initialize the Slider control’s numeric parameters: minimum, maximum and initial
values as well as the orientation (vertical or horizontal) and the direction of growth, (upward,
downward, leftward or rightward). 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 'sliderData' configuration structure by attaching it to the 'spinData' member of the InitCtrl-class object. This requires casting the pointer: sliderData slData(....) ; // define the configuration object (const dspinData*)&slData // perform a cast of the pointer to the object 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.
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.
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'):
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).
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.
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:
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒████▌ ▒▒
▒▒▕▕▕▕▕▕▕▕▕▕▕▕▕▕▕▕▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Previous: Slider Controls, Up: Dialog Control Objects [Contents][Index]
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.
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.
Next: Direct Keyboard Input, Previous: Dialog Control Objects, Up: NcDialog Class Definition [Contents][Index]
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.
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.
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.
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.
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.
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.
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.
Next: Mouse Configuration, Previous: NcDialog Display Output, Up: NcDialog Class Definition [Contents][Index]
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.
Next: Utility Methods, Previous: Direct Keyboard Input, Up: NcDialog Class Definition [Contents][Index]
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. (but see the meEnableStableMouse method) |
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.
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’.)
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.
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.
All other mouse event types are ignored for Scrollbox and Scrollext controls.
Please see Menuwin Controls for more information on menus and ’MenuBar’ menu groups.
Please see spinner key input for more information on key input to Spinner controls.
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.
Next: Development and Debugging, Previous: Mouse Configuration, Up: NcDialog Class Definition [Contents][Index]
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.
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.
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
Next: Secondary Classes, Previous: Utility Methods, Up: NcDialog Class Definition [Contents][Index]
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.
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 ) ;
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'.
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.
Input : 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.
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.
Next: System Clipboard, Previous: Development and Debugging, Up: NcDialog Class Definition [Contents][Index]
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.
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
Note that this is a multi-purpose pointer which accomodates several different text-formatting options for different control types:
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.
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.
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.
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 ;
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.
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' };
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.
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.
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:
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.
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.
Previous: Secondary Classes, Up: NcDialog Class Definition [Contents][Index]
This chapter is for applications which require ’Copy’, ’Cut’ and ’Paste’ operations, either within the application itself or for data sharing with other applications.
Next: Local NcDialog Clipboard, Up: System Clipboard [Contents][Index]
’Copy’, ’Cut’ and ’Paste’ operations are common in interactive applications, and these operations use a globally-accessible, temporary buffer called the ’clipboard.’
Next: Clipboard Interface, Previous: Clipboard Overview, Up: System Clipboard [Contents][Index]
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.
Next: Wayland Clipboard, Previous: Local NcDialog Clipboard, Up: System Clipboard [Contents][Index]
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.)
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.)
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.)
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.)
Input : none Returns: 'true' if connection has been established, else 'false'
Report whether communication between the application and the system clipboard has been established.
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.
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.
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.
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.
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.
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.
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.
Input : none Returns: pointer to const string of the format: "x.y.zz"
Report the WaylandCB-class version number.
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.
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:
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.
Next: Wayclip Demo App, Previous: Clipboard Interface, Up: System Clipboard [Contents][Index]
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 and
frankly incomplete in execution, they hold promise for a robust
console/clipboard interface.
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.
The package also includes a rudimentary “man page.”
info '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 600 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 with the WaylandCB package.
Also, the gString package is integrated into the NcDialogAPI, or is available as a separate download from the author’s website.
If your application is based on the NcDialogAPI, the WaylandCB interface
is fully-integrated into the API, so building the stand-alone WaylandCB
module into your application is unnecesary.
Please see Clipboard Interface for details on using the Wayland
Clipboard within an application built using the NcDialogAPI.
If your application does not use the NcDialogAPI, then the WaylandCB and gString modules may be built as a separate link library or may be built directly into your application source. Because they are both very small modules, it is recommended that they be built as ordinary source modules in your application. Your makefile would then include entries something like this.
Your application would then call the public methods of the WaylandCB class as needed. See the next section for details.
Input : none Returns: nothing
Destructor:
1) Delete all temp files.
2) Return all resources to the system
Input : none Returns: constructors implicitly return a pointer to the object
Default Constructor:
1) Initialize all class data members.
2) Locate the system’s temp-file directory.
3) Create a temporary file for communicating
with the clipboard interface.
4) Determine whether "wl-copy" and "wl-paste"
utilities are installed.
5) Test access to the GNOME/Wayland clipboard.
Input : none Returns: 'true' if connected to clipboard, else 'false'
Report whether connection to the Wayland clipboard has been established.
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 wcbsNOCONNECT if error i.e. not connected to clipboard returns wcbsNOINSTALL if 'wl-copy' utility not installed
Get a copy of the GNOME/Wayland clipboard data.
Data returned will be NULL terminated.
Data may contain newline characters (’\n’) but will not include
a trailing newline.
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 wcbsNOCONNECT if error i.e. not connected to clipboard returns wcbsNOINSTALL if 'wl-copy' utility not installed
Set contents of the GNOME/Wayland clipboard.
Source data terminated at null terminator or if ’cnt’ specified, then specified number of items (PLUS null terminator if not included in count).
IMPORTANT NOTE: Always size your source buffer several bytes larger than any data it will contain. This is to ensure that there is space to "escape" any special characters that might be misinterpreted by the shell program.
IMPORTANT NOTE: If the source data (’csrc’) are wchar_t (UTF-32) characters, then character input (’cnt’) is limited to the width of the UTF-32 to UTF-8 conversion buffer (gsMAXBYTES). Therefore if the number of UTF-8 bytes required to represent the UTF-32 source data is more than gsMAXBYTES, truncation may occur.
Input : primary: (optional, 'false' by default) if 'false', clear the "Regular" clipboard if 'true', clear the "Primary" clipboard useCmd : (optional, 'false' by default) if 'false', clear clipboard by sending an empty string if 'true', _attempt_ to clear the clipboard using the "--clear" argument Returns: 'true' if successful 'false' if not connected, or other error
Clear the clipboard.
Important Note: As stated elsewhere, the wl-copy arguments '--clear and '-c' apparently do nothing. For this reason, by default WaylandCB transmits an empty string to clear the clipboard.
The optional 'useCmd' parameter is provided to allow testing of the --clear (-c) arguments. However, the 'useCmd' argument should not be set in an application unless functionality on the target system has been verified.
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 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 specified clipboard.
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 wcbsNOCONNECT if error i.e. not connected to clipboard returns wcbsNOINSTALL if 'wl-paste' utility not installed
Report the available formats for retrieving data from the specified clipboard.
For a given set of text data on the clipboard, the wcbTypes() method will report the formats in which that data may be retrieved by the application.
The Wayland clipboard supports essentially the same MIME type designations for transmitting text as its predecessor, the X-clipboard.
Please note however, that WaylandCB transmits and receives text using ONLY the “text/plain;charset=UTF-8” format. The 16-bit, ASCII and ISO-8859-1 formats are Windows(tm) garbage which is seldom seen on real (i.e. GNU/Linux) systems.
For those who are unfamiliar with MIME types (media types), these are standards for transmitting data accross the internet. These standards are administered by the IANA (Internet Assigned Numbers Authority). Only a small subset of these types are associated with clipboard text data.
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 wcbsACTIVE system clipboard communication established and active
Test the connection with the Wayland clipboard.
Send a short (< 1000 bytes) message to the clipboard, then retrieve the data and compare the results.
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.
Technical Note:
The ’wl-copy’ and/or ’wl-paste’ utility will occasionally go off into the
weeds. The reasons for this are unclear, but communication can usually be
re-established by running the initialization sequence again. However, to
do this, it is necessary to first call 'wcbReinit' to reset all class
resources to the initial state and then execute the startup sequence.
Input : none Returns: pointer to const string of the format: "x.y.zz"
Report the WaylandCB-class version number.
Previous: Wayland Clipboard, Up: System Clipboard [Contents][Index]
The “wl-clipboard” suite: “wl-copy” and “wl-paste” must be installed on your system for the Wayclip application to function properly. Please see Wayland Clipboard Interface for installation instructions.
The Wayland communications protocol is the successor to the X-Windows protocol, and the GNOME/Wayland compositor is the new window manager based on the Wayland protocol.
Note that other communication protocols for UNIX-like systems exist at various stages of development; however, both GNOME and KDE have committed to supporting Wayland. Most systems based on these platforms have also announced support for Wayland as the “official” successor to X-Windows.
‘Wayclip’ is a simple console application that demonstrates the “WaylandCB” interface class which provides access to the Wayland clipboard.
‘Wayclip’ is an embarrassingly simple console application written
in C++. The application provides straightforward examples
for accessing the public methods of the WaylandCB interface class.
Please see WaylandCB class for more information.
The WaylandCB class, in turn, provides access to the “wl-clipboard”
utilities: “wl-copy” and “wl-paste” written by Sergey
Bugaev (and friends).
Please see Wayland Clipboard Interface for more information.
The application is designed around a menu of available commands (see User Interface). These commands exercise each of the public methods of the WaylandCB interface class.
Wayclip produces color-coded output using simple ANSI color commands (escape sequences).
Although Wayclip will run in a terminal window of any reasonable size, it is recommended that you expand your terminal window to at least 36 rows and 132 columns for optimal viewing.
Set the initial target clipboard to the Wayland “Primary” clipboard.
This clipboard is designed primarily for data that have been highlighted within an application; however for text data, this clipboard has all the same capabilities as the “Regular” clipboard.
The target clipboard may also be specified from within the application using the '-a' (Active-clipboard) command.
Set the initial target clipboard to the Wayland “Regular” clipboard.
This is the main system clipboard and can handle all the standard data types and data formats. This is the default clipboard, so if the target clipboard is not specified on the Wayclip command line, the “Regular” clipboard is the initial target.
The target clipboard may also be specified from within the application using the '-a' (Active-clipboard) command.
––help (or –h) Help for application.Display the application version number and the basic copyright notice.
Display a list of available command-line options.
The Wayclip application’s user interface is menu driven so there is little need to refer to this documentation except to satisfy the naturally insatiable curiosity of the software programmer.
Data may be copied to the Regular (main) clipboard from any application on the desktop, for instance a text editor, a LibreOffice(tm) document, or from a web page in your browser.
Data may be copied to the Primary clipboard by using the mouse to highlight text in any application on the desktop including the current terminal window.
For the tests performed by the Wayclip application, data are limited to text data only.
Type the command letter and then press the ENTER key.
User is prompted to select either the “Regular” (main) system clipboard, or the “Primary” clipboard as the Active clipboard. This selection will be reflected in the upper-right corner of the menu.
All subsequent Wayclip operations will be performed on this Active clipboard.
Note: Do not be confused by the term “primary”. This is actually a secondary clipboard. The name is an artifact left over from the X-Windows clipboard cluster, and does not indicate the default system clipboard.
Several test-data sequences in the form of familiar quotations, are defined within the application. The test-data sequence to be used for copy operations is selected by the 's' command (see below).
When the 'c' command is invoked, the previously-selected test data are copied to the active clipboard.
Retrieve the data from the active keyboard and paste it into the terminal window.
Clear the active clipboard. (Set its contents to the empty string.)
Several test-data sequences in the form of familiar quotations, are defined within the application. The test-data sequence to be used for copy operations is selected by the 's' command.
These text sequences were selected because they are short, easily formatted, and arguably somewhat cute.
Then when the 'c' command is invoked, the specified test data are copied to the active clipboard.
To maximize flexibility and test coverage, data may be transmitted between the application and the WaylandCB interface class in any of three encodings.
While the WaylandCB class accepts any of these encodings from the application for copy/paste operations, it is important to note that communications between the WaylandCB class and the system clipboard are encoded as UTF-8 text exclusively.
Display a copy of the main menu. This command may be used if the menu has been scrolled out of the terminal window by other operations.
The system clipboard can provide its contents in a variety of encodings depending on the type of data it contains.
Request this report to retrieve a list of the MIME-type encodings available for retrieving the data currently on the clipboard.
Because we are interested only in text encodings here, the following is a list of the text encodings most likely to be available.
Additional information is appended to the end of this list, specifically the number of bytes of data currently on the clipboard, and the version number for the WaylandCB class.
Note On MIME Types: For those who are unfamiliar with MIME types (media types), these are standards for transmitting data accross the internet. These standards are administered by the IANA (Internet Assigned Numbers Authority). Only a small subset of these types are associated with clipboard text data.
See wcbTypes method for more information.
On application startup, the WaylandCB interface class establishes a connection with the system clipboard during instantiation of the class object.
Occasionally, that connection will be lost due to various conditions which are beyond the control of the application layer. Our testing has shown that timing issues are the most likely cause of a dropped connection.
When this happens, the connection may be re-established by resetting all internal data of the WaylandCB class and performing the clipboard handshake sequence again.
Perform a simple test of the connection to the Wayland clipboards.
Clear the terminal window and re-display the menu.
Exit the application.
Three additional commands are available but to save space, were not included in the menu. These commands are primarily for the convenience of the developer, but the commands are fully functional and available for use.
Please note that these are upper-case letters.
Copy the test data previously selected via the 's' command (see above) to the inactive clipboard.
Paste the data currently on the inactive clipboard into the terminal window.
Clear the inactive clipboard. (Set its contents to the empty string.)
Please note that this application disables the “Panic Button” (CTRL+C),
so the user must exit the application using the ‘q’ (ENTER) command.
The reason for this is that our beta-testers continually tried to use
CTRL+C and CTRL+V as copy and paste, respectively. |
Next: Application Examples, Previous: NcDialog Class Definition, Up: NcDialog Library API [Contents][Index]
’gString’ is a small, fast and flexible way to seamlessly convert, format and analyze both UTF-8 and wchar_t (’wide’) text.
Next: gString Public Methods, Up: gString Text Tool [Contents][Index]
Modern applications must be designed for a worldwide audience, and for this reason, the application designer must plan for multi-language support.
Fortunately, the Universal Character Set standard ISO/IEC 10646 and UTF-8, the most popular and flexible method of character-encoding smoothly provide all the character sets, alphabets and special characters which are currently in general use.
Unfortunately, the C and C++ languages offer only minimal support for
internationalization. std::string and std::wstring are nothing more than a
cruel joke to a serious application designer. The GTK+ toolkit’s Glib::ustring
class is an excellent internationalization tool, but it requires installation
of the GTK+ toolkit’s ’glib’ and ’glibmm’ libraries. For more information on
Glib::ustring, see:
http://library.gnome.org/devel/glibmm/unstable/classGlib_1_1ustring.html
’gString’ falls halfway between the full feature set of Glib::ustring and the meaningless garbage that is std::string. ’gString’ consists of one C++ header file and one C++ source code module. ’gString’ is integrated into the NcDialog API library, but may also be compiled independently as a small (16Kb) link library or the source may be embedded directly into your application.
Here are the basic ideas you will need to understand in order for your application to smoothly support multiple languages.
See also a discussion of multiple-language support in the NcDialog API.
see Multi-language Support.
Next: gString Instantiation, Previous: Introduction to gString, Up: gString Text Tool [Contents][Index]
What follows is a list of all public methods of the gString class.
Methods are arranged in functional groups.
gString Method Name | Chapter Reference |
---|---|
gString [constructor] | see gString Instantiation |
~gString [destructor] | |
operator= | see Assignment Operators |
compose | see Formatted Assignments |
formatInt | see Integer Formatting |
gstr | see Data Access |
ustr | |
copy | see Copying Data |
operator<< | |
substr | |
append | see Modifying Existing Data |
insert | |
limitChars | |
limitCols | |
shiftChars | |
shiftCols | |
padCols | |
strip | |
erase | |
replace | |
loadChars | |
textReverse | |
compare | see Comparisons |
operator== | |
operator!= | |
find | |
findlast | |
after | |
findx | |
scan | |
gscanf | see Extract Formatted Data |
gschars | see Statistical Info |
gscols | |
utfbytes | |
isASCII | |
clear | see gString Miscellaneous |
Get_gString_Version | |
dbMsg |
Next: Assignment Operators, Previous: gString Public Methods, Up: gString Text Tool [Contents][Index]
The following are the ’constructors’ for the gString class.
For those new to C++, a constructor creates an ’instance’ of the class. An instance is a particular, named object, and can be thought of as a complex variable.
Input : none Returns: nothing
Constructor: Initialize members to default values (NULL string).
Input : usrc : pointer to a UTF-8-encoded, null-terminated string charLimit : (optional, gsMAXCHARS by default) maximum number of characters from source array to convert Returns: nothing
Constructor: Convert specified UTF-8-encoded source to gString.
Input : wsrc : pointer to a wchar_t-encoded, null-terminated string charLimit : (optional, gsMAXCHARS by default) maximum number of characters from source array to convert Returns: nothing
Constructor: Convert specified wchar_t (’wide’) source to gString.
Input : iVal : value to be converted Supported value range: plus/minus 9.999999999999 terabytes fWidth: field width (number of display columns) range: 1 to FI_MAX_FIELDWIDTH lJust : (optional, false by default) if true, strip leading spaces to left-justify the value in the field. (resulting string may be less than fWidth) sign : (optional, false by default) 'false' : only negative values are signed 'true' : always prepend a '+' or '-' sign. kibi : (optional, false by default) 'false' : calculate as a decimal value (powers of 10) kilobyte, megabyte, gigabyte, terabyte 'true' : calculate as a binary value (powers of 2) kibibyte, mebibyte, gibibyte, tebibyte units : (optional) member of enum fiUnits (fiK by default) specifies the format for the units suffix. Note that if the uncompressed value fits in the field, then this parameter is ignored. Returns: nothing Note: if field overflow, field will be filled with '#' characters.
Constructor: Convert specified integer value to gString.
Please see Integer Formatting, 'formatInt' method group
for formatting details.
Input : fmt : a format specification string in the style of sprintf(), swprintf() and related formatting C/C++ functions. arg1 : pointer to first value to be converted by 'fmt' ... : optional arguments (between ZERO and gsfMAXARGS - 1) Each optional argument is a POINTER (address of) the value to be formatted. Returns: nothing
Constructor: Convert formatting specification and its arguments to gString. Please refer to the compose() method (see Formatted Assignments) for more information.
Technical Note: There is no constructor using a “const wchar_t* fmt” format specification because it would conflict with the constructor which limits the number of characters used to initialize the instance.
Input : gsf : initialized gsForm class object containing parameters for creating a formatted text string. charLimit : (optional, gsMAXCHARS by default) maximum number of characters from source array to convert Returns: nothing
DEPRECATED: May be removed in a future release.
This method seemed like a good idea back in 2011, but neither we,
nor our beta testers have ever had a desire to use it.
Constructor: Convert formatting instructions in gsForm class object to gString. See compose() for more information.
Input : none Returns: nothing
Destructor: Release all resources associated with the gString object.
Object is destroyed either when it goes out of scope, or by explicitly deleting the object.
For those new to C++, please note that if you use the ’new’ keyword to create objects, then those objects persist (take up space) until you explicitly delete them or until the application is closed, even if the pointer to the object has gone out-of-scope. See examples below.
void calling_method ( void ) { gString *gsPtr = playful_kitten ( "Hello World!" ) ; // report contents of object created by called method wcout << gsPtr->gstr() << endl ; delete gsPtr ; // delete object created by called method } gString* playful_kitten ( const char* msg ) { gString gs_local( "I love tuna!" ) ; // local object gString *gsPtr1 = new gString, // global object *gsPtr2 = new gString(msg) ; // global object (initialized) gString *gsArray = new gString[4] ; // global array *gsPtr1 = gs_local ; // be a kitten: play with the strings... gsArray[2] = *gsPtr2 ; gsArray[3] = "Scratch my belly!" ; gsArray[1] = gsArray[3] ; delete gsPtr1 ; // delete object referenced by gsPtr1 delete [] gsArray ; // delete object array referenced by gsArray return gsPtr2 ; // return pointer to object referenced by gsPtr2 // (caller is responsible for deleting object) } // 'gs_local' goes out of scope and is destroyed here
Next: Formatted Assignments, Previous: gString Instantiation, Up: gString Text Tool [Contents][Index]
For those new to C++, an assignment operator assigns (initializes) the object to the left of the ’=’ using the data on the right of the ’=’. You may also hear the term ’overloaded operator’. This just means that the ’=’ assignment operator may be defined in more than one way, so it will perform different tasks according to the context or circumstance.
Input : usrc : pointer to an array of UTF-8-encoded characters Returns: nothing
Assignment operator: converts UTF-8-encoded source to gString.
Input : wsrc : pointer to an array of wchar_t 'wide' characters Returns: nothing
Assignment operator: converts wchar_t (’wide’) source to gString.
Input : gssrc : gString object to be copied (by reference) Returns: nothing
Assignment operator. Copies one gString object to another.
Input : gsf : an initialized gsForm object (by reference) Returns: nothing
DEPRECATED: May be removed in a future release.
Assignment operator: Converts gsForm-class instructions to gString.
char utf8Data[] = { "Youth is wasted on the young." } ; gString gs1, gs2 ; gs1 = utf8Data ; gs2 = gs1 ; wcout << gs2 << endl ; - - -> Youth is wasted on the young.
Next: Integer Formatting, Previous: Assignment Operators, Up: gString Text Tool [Contents][Index]
Input : fmt : a format specification string in the style of sprintf(), swprintf() and related formatting C/C++ functions. ... : optional arguments (between ZERO and gsfMAXARGS) Each optional argument is a POINTER (address of) the value to be formatted. - Important Note: There must be AT LEAST as many optional arguments as the number of format specifiers defined in the formatting string. Excess arguments will be ignored; HOWEVER, too few arguments will result in an application crash. You have been warned. Returns: const wchar_t* to formatted data
Create formatted text data from a format specification string including between ZERO and gsfMAXARGS format specifications and their corresponding argument pointers.
Supported data types: %d, %i integer (decimal) %o integer (octal) %u integer (unsigned) %x, %X integer (hex lower or upper case) %f floating point (fixed point) %e, %E floating point (scientific notation, lower/uppercase) %g, %G floating point (normal/exponential, lower/uppercase) %a, %A floating point (hex fraction) %c character %C character (alias for %lc) %s string %S string (alias for %ls) %p pointer %b, %B (extension to swprintf - see description below) %m capture 'errno' description string (see /usr/include/errno.h) %n number of characters printed so far (value written to corresponding argument's location) %% literal '%' See man pages for the C/C++ function 'swprintf' or 'Table of Output Conversions' for additional details.
char Greeting[] = { "Hello!" } ; int iValue = 27064 ; long long int qValue = 7842561 ; long int lValue = 485772 ; short int sValue1 = 28875, sValue2 = -261, sValue3 = 529 ; bool flagValue = true ; float fltValue = 278.5610234 ; double dblValue = 9982.5610234 ; gString gs ; gs.compose( "%s - %d %12hd, %-hi, %#hx %08lXh %lld %hhd", Greeting, &iValue, &sValue1, &sValue2, &sValue3, &lValue, &qValue, &flagValue ) ; wcout << gs << endl ; - - -> Hello! - 27064 28875, -261, 0x211 0007698Ch 7842561 1 gs.compose( "floating downstream:%10.2f and doubling our pace:%.4lf", &fltValue, &dblValue ) ; wcout << gs << endl ; - - -> floating downstream: 278.56 and doubling our pace:9982.5610
See also formatted instantiation: see gString Instantiation.
Because THE PARAMETERS ARE POINTERS TO THEIR DATA, similar to the C/C++ library function ’sscanf’ and friends, the compiler cannot perform automatic promotions from short int* to int* or from float* to double*, and so-on as it would for swprintf.
This implementation was selected because a) it eliminates data-width conflicts when moving among hardware platforms, and b) it reduces code size while increasing performance.
This implementation relies on you, the designer, to use care that the data type you specify in the formatting string matches the data type of the variable referenced by its parameter pointer AND that you use the ’address-of’ (’&’) operator to reference non-pointer variables. Note also that ’literal’ values may not be used as parameters because literals have no address.
The following constructs will produce errors:
gString gs ; char grade = 'A' ; short age = 21 ; int sat = 1550 ; double gpa = 3.75 ; // These examples fail to use the 'address-of' operator for the // referenced variables, and will cause a 'segmentation fault' // i.e. an application crash. gs.compose( "My grade is an %c", grade ) ; gs.compose( "I got a %d on my SAT.", sat ) ; // The above should be: gs.compose( "My grade is an %c", &grade ) ; gs.compose( "I got a %d on my SAT.", &sat ) ; // These examples use mismatched format-specification/variable // reference. This will result in either bad data out OR will // cause a memory-access violation. gs.compose( "I can't wait to be %d.", &age ) ; gs.compose( "My GPA is %1.3f", &gpa ) ; gs.compose( "The hex value of %c is: %#x", &grade, &grade ) ; gs.compose( "My GPA is %1.3lf", 3.88 ) ; // (literal value) // The above should be: gs.compose( "I can't wait to be %hd.", &age ) ; gs.compose( "My GPA is %1.3lf", &gpa ) ; gs.compose( "The hex value of %c is: %#hhx", &grade, &grade ) ;
Parameter Type Checking:
Unfortunately, type-checking of wchar_t formatting strings is not yet
supported by the gnu (v:4.8.0) compiler, (but see wchar.h which is
preparing for the future). Thus, use care when constructing your
’wchar_t fmt’ formatting string. The ’char fmt’ string IS type-checked.
IMPORTANT NOTE:
Depending on your compiler version, you may get a warning when using
the '%b' binary format specification (described below):
"warning: unknown conversion type character ‘b’ in format [-Wformat=]"
This is because the preprocessor does not recognize our custom format
specifier. If this happens, use a ’wchar_t’ (wide) formatting template
to avoid the preprocessor type checking.
Instead of: gs.compose( "bitmask: %b", &wk.mevent.eventType ); Use this (not type checked by the preprocessor): gs.compose( L"bitmask: %b", &wk.mevent.eventType );
We implement an extension to the swprintf output-conversion-specifiers for binary formatted output. We have found this formatting option useful when working with bit masks, for verifying bit-shifting operations during encryption/decryption and other uses.
The standard library ’swprintf’ function has a design flaw for format specifications that include a field-width specifier.
’swprintf’ pads the string to the specified number of CHARACTERS, not the number of COLUMNS as it should do. For ASCII numeric source values this is not a problem because one character equals one display column. For string source data, however, if the source string contains characters that require more than one display column each, then the output may be too wide.
Therefore, for string-source-formatting specifications ONLY:
(examples: "%12s" "%-6s" "%16ls" "%5S" "%-24S")
we compensate for this ethnocentric behavior by interpreting the field-width
specifier as number-of-columns, NOT number-of-characters. For non-ASCII string
data, this will result in output that appears different (and better) than
output created directly by the ’swprintf’ function.
Conversion modifiers that are not fully supported at this time:
’j’, ’z’, ’t’, ’%[’
Also, the ’*’ field-width specification or precision specification which uses
the following argument as the width/precision value IS NOT supported.
Next: Data Access, Previous: Formatted Assignments, Up: gString Text Tool [Contents][Index]
Input : iVal : value to be converted Supported value range: plus/minus 9.999999999999 terabytes fWidth: field width (number of display columns) range: 1 to FI_MAX_FIELDWIDTH lJust : (optional, false by default) if true, strip leading spaces to left-justify the value in the field. (resulting string may be less than fWidth) sign : (optional, false by default) 'false' : only negative values are signed 'true' : always prepend a '+' or '-' sign. kibi : (optional, false by default) 'false' : calculate as a decimal value (powers of 10) kilobyte, megabyte, gigabyte, terabyte 'true' : calculate as a binary value (powers of 2) kibibyte, mebibyte, gibibyte, tebibyte units : (optional) member of enum fiUnits (fiK by default) specifies the format for the units suffix. Note that if the uncompressed value fits in the field, then this parameter is ignored. Returns: 'true' if successful 'false' if field overflow (field will be filled with '#' chars) See notes below on field overflow.
Convert an integer value into a formatted display string of the specified width. Value is right-justified in the field, with leading spaces added if necessary (but see ’lJust’ parameter).
Maximum field width is FI_MAX_FIELDWIDTH. This is wide enough to display a 18-digit, signed and comma-formatted value: '+9,876,543,210,777'
1) Simple comma formatted output if specified field-width is sufficient. 345 654,345 782,654,345 4,294,967,295 2) Output with values compressed to fit a specified field width. 12.3K 999K 12.345M 1.234G 4.3G gString gs ; // gString object 3) Convert a signed integer value: int iValue = 28954 ; // field width == 8, right justified (note: compression unnecessary) gs.formatInt( iValue, 8 ) ; wcout << ':' << gs << ':' << endl ; - - > : 28,954: // field width == 8, left justified (note: compression unnecessary) gs.formatInt( iValue, 8, true ) ; wcout << ':' << gs << ':' << endl ; - - > :28,954: // field width == 6 gs.formatInt( iValue, 6 ) ; wcout << ':' << gs << ':' << endl ; - - > :28.95K: // field width == 6 with forced sign gs.formatInt( iValue, 6, false, true ) ; wcout << ':' << gs << ':' << endl ; - - > :+29.0K: // field width == 5 gs.formatInt( iValue, 5 ) ; wcout << ':' << gs << ':' << endl ; - - > :29.0K: iValue = -28954 ; // convert negative source value // field width == 8, right justified (note: compression unnecessary) gs.formatInt( iValue, 8 ) ; wcout << ':' << gs << ':' << endl ; - - > : -28,954: // field width == 8, left justified (note: compression unnecessary) gs.formatInt( iValue, 8, true ) ; wcout << ':' << gs << ':' << endl ; - - > :-28,954: // field width == 6 gs.formatInt( iValue, 6 ) ; wcout << ':' << gs << ':' << endl ; - - > :-29.0K: // field width == 5 gs.formatInt( iValue, 5 ) ; wcout << ':' << gs << ':' << endl ; - - > : -29K: 4) Convert an unsigned long long integer value (field width == 11): unsigned long long int qValue = 39000009995 ; // decimal compression (gigabytes) with "official" IEC suffix gs.formatInt( qValue, 11, false, false, false, fikB ) ; wcout << ':' << gs << ':' << endl ; - - > :39.000010gB: // binary compression (gibibytes) with "official" IEC suffix gs.formatInt( qValue, 11, false, false, true, fiKiB ) ; wcout << ':' << gs << ':' << endl ; - - > :38.08595GiB:
Please see (NcDialog test application, ’Dialogw’ for more examples.)
See Dialogw App.
The IEC (International System of Quantities) recommends lower-case for
metric (powers of 10) and upper-case for binary (powers of 2).
However, unless you must be accurate in presenting the data according to
IEC standard, it is recommended that you choose the format according to:
your space requirements, visual appeal, and clear communication with your
users.
If you blindly follow style standards against your own better
judgement, then be forever labelled as a weenie.
As described above, the actual formatting of a fixed-width integer field depends on a number of factors. Every effort is made to compress the data to fit within the field while retaining an accurate representation of the numeric value.
There are cases, however, where it is not possible to represent the data within the specified field width. When this occurs, the entire field will be filled with HASH characters '#'.
The specified field must be wide enough to accomodate either the entire, uncompressed value, or the combination of compressed value, units designator and sign (if any). The following situations may cause field overflow.
Fields of seven(7) or more columns can display any formatted value without danger of overflow.
Next: Copying Data, Previous: Integer Formatting, Up: gString Text Tool [Contents][Index]
Input : none Returns: const pointer to array of wchar_t characters
Return a const pointer to the wchar_t (wide) character array.
Input : charCount : (by reference, initial value ignored) receives number of characters in array, including null terminator Returns: const pointer to array of wchar_t characters
Return a const pointer to the wchar_t (wide) character array, along with the number of characters in the array (including the null terminator).
Input : none Returns: const pointer to array of UTF-8 characters
Return a const pointer to the char (UTF-8) character array.
Input : charCount : (by reference, initial value ignored) receives number of characters in array, including null terminator byteCount : (by reference, initial value ignored) receives number of bytes in array, including null terminator Returns: const pointer to array of UTF-8 characters
Return a const pointer to the char (UTF-8) character array, along with the number of characters and the number of bytes in the array (including the null terminator).
short charCount, byteCount ; gString gs( "Wherever you go, there you are!" ) ; const wchar_t* wPtr = gs.gstr() ; const wchar_t* wPtr = gs.gstr( charCount ) ; const char* utf8Ptr = gs.ustr() ; const char* utf8Ptr = gs.ustr( charCount, byteCount ) ;
Next: Modifying Existing Data, Previous: Data Access, Up: gString Text Tool [Contents][Index]
Input : uTarget : pointer to target array to receive UTF-8-encoded text maxBytes : maximum number of bytes to copy (incl. NULL terminator) maxCols : (optional, default == gsMAXCHARS*2) maximum number of display-columns to copy Returns: number of bytes copied (incl. NULL terminator)
Copy gString text to specified target buffer.
Input : wTarget : pointer to target array to receive wchar_t 'wide' text maxChars : maximum number of characters to copy (incl. NULL) maxCols : (optional, default == gsMAXCHARS*2) maximum number of display-columns to copy Returns: number of characters copied (incl. NULL terminator)
Copy gString text to specified target buffer.
Input : IMPLIED reference to the output stream IMPLIED reference to the gString object Returns: reference to the specified output stream
!! NON-MEMBER METHOD !!
Insertion operator: Copies the contents of the gString object into
the ’wcout’ (wide) standard output stream.
Input : IMPLIED reference to the output stream IMPLIED reference to the gString object Returns: reference to the specified output stream
!! NON-MEMBER METHOD !!
Insertion operator: Copies the contents of the gString object into
the ’cout’ (narrow) standard output stream.
Input : targ : (by reference, initial contents ignored) receives null-terminated contents of specified character range -- If target buffer is a char*, then data returned is a UTF-8 text string. -- If target buffer is a wchar_t*, then data returned is a wchar_t (wide) text string. IMPORTANT NOTE: It is the caller's responsibility to specify a target buffer large enough to hold the data. Recommended: wchar_t wbuff[gsMAXCHARS]; or char ubuff[gsMAXBYTES]; -- If target buffer is a gString object, then both UTF-8 and wchar_t data are returned (with no chance of target buffer overflow). offset : character index at which substring begins (this IS NOT a byte index) charCnt : number of characters to copy (not incl. NULL terminator) Returns: if target is a wchar_t* or gString object, then returns number of characters written to target (not including the NULL terminator) if target is a char*, then returns number of bytes written to target (not including the NULL terminator) Note: returns ZERO if either 'offset' or 'charCnt' out of range Note: If 'charCnt' extends beyond the end of the source data, then returns the available data.
Copy the specified character range to target buffer.
These methods copy the indicated substring (null terminated) to
the target buffer, leaving the original data unchanged.
If you have a fixed-format field, then the offset and character count will be known in advance. Otherwise you can use the ’find()’ method to locate the substring to be copied.
Please Note: The number of bytes can NEVER be assumed to be the same as the number of characters.
Please see Multi-language Support.
gString gs( "That's not flying, that's falling -- with style!\n" "Buzz Lightyear" ) ; char utf8Data[gsMAXBYTES] ; wchar_t wideData[gsMAXCHARS] ; gs.copy( utf8Data, gs.utfbytes() ) ; gs.copy( wideData, gs.gschars() ) ; gString gstream( "You're a child's TOY! -- Woody" ) ; wcout << gstream << endl ; // get a copy of the first word starting with 'c' gString AusAnimal( "Aardvark Kangaroo Cockatoo Dingo Wombat " ) ; gString gsc ; short b = AusAnimal.find( " c" ) ; if ( b >= 0 ) { short e = AusAnimal.find( L' ', b + 1 ) ; if ( e > b ) { AusAnimal.substr( gsc, (b + 1), (e - b - 1) ) ; wcout << gsc << endl ; } } - - -> Cockatoo
Next: Comparisons, Previous: Copying Data, Up: gString Text Tool [Contents][Index]
Input : wPtr : pointer to array of wchar_t 'wide' text to be appended OR uPtr : pointer to array of char UTF-8 text to be appended OR wChar : a single, 'wide' character Returns: number of characters in resulting string (incl. NULL terminator) Note: if value returned equals gsMAXCHARS, then some data MAY HAVE BEEN discarded.
Append text to existing gString text data up to a combined length of gsMAXCHARS. Characters in excess of the maximum will not be appended.
gString gs( L"Be kind to your manager." ) ; gs.limitChars( gs.gschars() - 2 ) ; gs.append( L", and other lower forms of life." ) ; wcout << gs << endl ; - - -> Be kind to your manager, and other lower forms of life.
Input : fmt : a format specification string in the style of sprintf(), swprintf() and related formatting C/C++ functions. arg1 : pointer to first value to be converted by 'fmt' ... : optional arguments (between ZERO and gsfMAXARGS - 1) Each optional argument is a POINTER (address of) the value to be formatted. Returns: number of characters in resulting string (incl. NULL terminator) Note: if return equals gsMAXCHARS, then some data MAY HAVE BEEN discarded.
Append formatted text data to existing gString text data up to a combined length of gsMAXCHARS. Characters in excess of the maxmum will not be appended.
Please refer to the ’compose’ method (see Formatted Assignments) for more information on converting data using a format specification string.
short gaddress = 2840 ; wchar_t gdirection = L'E' ; const wchar_t* gstreet = L"Colorado Blvd." ; double gcost = 29.95 ; gString gs( "Gorilla Men's Clothing" ) ; // existing text gs.append( ", %hd %C %S\n Dress shirts on sale, $%.2lf.", &gaddress, &gdirection, gstreet, &gcost ) ; wcout << gs << endl ; - - -> Gorilla Men's Clothing, 2840 E Colorado Blvd. Dress shirts on sale, $29.95.
Input : wPtr : pointer to array of wchar_t 'wide' text to be inserted OR uPtr : pointer to array of char UTF-8 text to be inserted OR wChar : a single wchar_t 'wide' character offset: (optional, ZERO by default) character offset at which to insert specified text into existing text. Note: if specified 'offset' > number of characters in existing text, then acts like 'append' method. Returns: number of characters in resulting string (incl. NULL terminator) Note: if value returned equals gsMAXCHARS, then some data MAY HAVE BEEN discarded.
Insert text into existing gString text data up to a combined length of gsMAXCHARS. Characters in excess of the maximum will be truncated.
gString gs( L"Remember to hurt people!" ) ; gs.insert( L"NOT ", 9 ) ; wcout << gs << endl ; - - -> Remember NOT to hurt people!
Input : charCount : maximum number of characters allowed in formatted data (not including NULL) Range: 1 to gsMAXCHARS-1 Returns: number of characters in the adjusted data (including NULL)
Truncate the data to no more than charCount display characters.
Insert a null terminator after the specified number of characters.
gString gs( "This shirt is available in yellow or red." ) ; gs.limitChars( 34 ) ; gs.append( "only." ) ; wcout << gs << endl ; - - -> This shirt is available in yellow only.
Input : colCount : maximum number of display columns allowed in formatted data Range: 1 to (gsMAXCHARS * 2) Returns: number of columns needed to display the adjusted data Note: If specified column count occurs in mid-character, then the partial character will be removed from the string.
Truncate the data to no more than colCount display columns. Insert a null terminator after the number of characters required to fill the specified number of display columns.
gString gs( "The manual is located at:\n" "http://cdn.funcom.com/aoc/pdf/aoc_manual.pdf" ) ; gs.limitCols( 55 ) ; wcout << gs << endl ; - - -> The manual is located at: http://cdn.funcom.com/aoc/pdf/ Note that there are 25 display columns for the first line, (the newline character requires no column), and 30 columns remain on the second line.
Input : shiftCount: < ZERO: shift data to the left, discarding the specified number of characters from the beginning of the array > ZERO: shift data to the right, padding the vacated positions on the left with 'padChar' ==ZERO: do nothing padChar : (optional, SPACE character, 0x20 by default) when shifting data to the right, use this character to fill the vacated character positions NOTE: Specify a one-column character ONLY as the padding character. (multi-column characters ignored) Returns: number of characters in adjusted array
Shift text data by the specified number of characters.
Note for writers of RTL (right-to-left) languages: In the above descriptions, the terms 'left' and 'right' are used for convenience, but actually 'left' refers to the head of the data and 'right' refers to the tail.
gString gs( "Your balance is: 2,521,697.56 USD" ) ; gs.shiftChars( -17 ) ; wcout << gs << endl ; - - -> 2,521,697.56 USD gs.shiftChars( 5, L'#' ) ; wcout << gs << endl ; - - -> #####2,521,697.56 USD Note: For this example, the optional fill character used for right-shift is L'#'. The default fill character is space (L' ').
Input : shiftCount: < ZERO: shift data to the left, discarding the number of characters equivalent to the specified number of display columns NOTE: May discard one extra column if count falls within a multi-column character. > ZERO: shift data to the right, padding the vacated positions on the left with 'padChar' ==ZERO: do nothing padChar : (optional, SPACE character, U+0020 by default) when shifting data to the right, use this character to fill the vacated column positions NOTE: Specify a one-column character ONLY as the padding character. (multi-column characters ignored) Returns: number of display columns in adjusted array
Shift text data by the specified number of display columns.
Note for writers of RTL (right-to-left) languages: In the above descriptions, the terms 'left' and 'right' are used for convenience, but actually 'left' refers to the head of the data and 'right' refers to the tail.
gString gs( "您的帐户余额是500元" ) ; // "Your account balance is 500 yuan" gs.shiftCols( -14 ) ; wcout << gs << endl ; - - -> 500元 gs.shiftCols( 5, L'.' ) ; wcout << gs << endl ; - - -> .....500元 Note: Most Chinese characters are two display columns wide, therefore we shift 14 columns (7 characters) out on the left. For this example, the optional fill character used for right-shift is L'.' (U+002E, ASCII full stop). The Chinese full-stop (U+3002) MAY NOT be used as a fill character because it is a two-column character.
Input : fieldWidth: number of columns for the adjusted data array padChar : (optional, ASCII space 0x20 by default) character with which to pad the data Note: Specify a one-column character ONLY. Multi-column characters will be ignored. centered : (optional, 'false' by default) if 'false', all padding will be appended at the end of the existing data if 'true', padding will be equally divided between the beginning and end of the existing data Returns: number of display columns in the adjusted array
Append padding to the existing string data to achieve the specified number of display columns.
If the 'centered' flag is set, the padding will be divided equally between the beginning and end of the data to achieve the specified field width. Note that if an odd number of columns is to be added, then the odd column will be placed at the end of the data.
The ‘padCols’ method calculates the number of padding characters needed to fill out the specified field width.
The default padding character is the ASCII space character (20 hex).
Any single-column character may be specified as an alternate padding
character.
Padding will be added until either the specified number of columns is reached, OR until the array contains the maximum number of characters (gsMAXCHARS).
If the fieldWidth specified is <= the current width of the data, then the data will not be modified.
gString gs( "This is a test." ); gs.padCols( 30 ); ==> "This is a test. " gs.padCols( 30, L'#' ); ==> "This is a test.###############" gs.padCols( 30, L'#', true ); ==> "#######This is a test.########" // To create a right-justified field, use 'shiftCols' (see above): gs.shiftCols( (30 - gs.gscols()) ); ==> " This is a test." gs.shiftCols( (30 - gs.gscols()), L'#' ); ==> "###############This is a test."
Input : leading : (optional, 'true' by default) if 'true', strip leading whitespace if 'false', leading whitespace unchanged trailing : (optional, 'true' by default) if 'true', strip trailing whitespace if 'false', trailing whitespace unchanged Returns: number of characters in modified string (incl. NULL terminator)
Strip (remove) leading and/or trailing whitespace from the string data.
Whitespace characters are defined as:
0x0020 single-column ASCII space
0x3000 two-column CJK space
0x0A linefeed character
0x0D carriage-return character
0x09 horizontal-tab character
0x0B vertical-tab character
0x0C formfeed character
“Leading” whitespace is space characters from the beginning of the data to the first non-space character. “Trailing” whitespace is from after the last non-space character through the end of the data.
By default, both leading and trailing whitespace will be removed; however, this action may be modified by resetting the appropriate parameter to ‘false’.
Input : src : source data to be matched, one of the following: -- pointer to a UTF-8 string (max length==gsMAXBYTES) -- pointer to a wchar_t string (max length==gsMAXCHARS) -- a gString object containing the source (by reference) -- a single, wchar_t character offset : (optional, ZERO by default) character index at which to begin search NOTE: This is a character index, NOT a byte offset. casesen: (optional, 'false' by default) if 'false', then scan IS NOT case sensitive if 'true, then scan IS case sensitive The way upper/lowercase are related is locale dependent; Returns: index of first character following the deleted sequence Note: This is the wchar_t character index, NOT a byte index Returns (-1) if: a) no matching substring found b) 'offset' out-of-range c) 'src' is an empty string or a NULL character
Scan the data for a matching substring, and if found, erase (delete) the first occurance of the substring.
Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character IS NOT included in the comparison. These comparisons ARE locale dependent.
Input : offset : (optional, ZERO by default) index of first character of sequence to be erased NOTE: This is a character index, NOT a byte offset. length : (optional, gsMAXCHARS by default) if not specified, then erase all characters from 'offset' to end of data if specified, then erase the specified number of characters beginning at 'offset' Returns: index of first character following the deleted sequence Note: This is the wchar_t character index, NOT a byte index Returns (-1) if: a) offset < ZERO b) offset >= number of characters in data c) length <= ZERO (data will not be modified)
Erase (delete) the data sequence specified by ’offset’ and ’length’.
’offset’ is the index of the first character to be deleted, and ’length’ specifies the number of characters to delete.
For the gString object containing the following verbal exchange, erase all occurances of the word 'crapweasel'. gString gs( "Ross : Are you familiar with the word crapweasel?\n" "Paolo: No, I don't know crapweasel.\n" "Ross : You're a huge crapweasel!" ); short index = ZERO ; while ( (index = gs.erase( " crapweasel", index )) >= ZERO ) ; Yields: "Ross : Are you familiar with the word?\n" "Paolo: No, I don't know.\n" "Ross : You're a huge!" Find the substring, "the the" and erase the extra "the". gString gs1( L"There are seven candidates in the the Primary Election." ); gString gs2( L"the " ); short index = gs1.find( "the the" ); gs1.erase( index, (gs2.gschars() - 1) ); Yields: "There are seven candidates in the Primary Election."
Input : src : source data to be matched -- pointer to a UTF-8 string -- pointer to a wchar_t string -- a single, wchar_t character newtxt : data to overwrite existing text -- pointer to a UTF-8 string -- pointer to a wchar_t string -- a single, wchar_t character offset : (optional, ZERO by default) character index at which to begin search NOTE: This is a character index, NOT a byte offset. casesen: (optional, 'false' by default) if 'false', then scan IS NOT case sensitive if 'true, then scan IS case sensitive The way upper/lowercase are related is locale dependent; all : (optional, 'false' by default) if 'false', then replace only the first occurance found if 'true', then replace all occurances of the specified substring Returns: 'true' if successful returns 'false' if error (existing data not modified): a) no matching source substring found b) 'src' is a empty string or a null character c) offset < ZERO or offset is beyond existing data d) modifying the data would cause buffer overflow (>gsMAXCHARS)
Replace the specified source substring, or optionally all matching substrings with the provided substring.
Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character IS NOT included in the comparison. These comparisons ARE locale dependent.
Correct the spelling errors in the following data: gString gs( "The land near hare is full of Heres, hoping her and ther." ) ; bool okiday = gs.replace( L"hare", L"here" ) ; Yields: "The land near here is full of Heres, hoping her and ther." okiday = gs.replace( "Here", "Hare", ZERO, true ) ; Yields: "The land near here is full of Hares, hoping her and ther." okiday = gs.replace( L'p', L"pp" ) ; Yields: "The land near here is full of Hares, hopping her and ther." short index = gs.find( "her " ) ; okiday = gs.replace( "her", L"here", index, true, true ) ; Yields: "The land near here is full of Hares, hopping here and there." Then, replace all spaces ' ' with underscores '_'. okiday = gs.replace( L' ', L'_', ZERO, false, true ) ; Yields: "The_land_near_here_is_full_of_Hares,_hopping_here_and_there."
Load the specified number of characters from the source data.
This is useful for extracting data from fixed-width fields when
the contents of the field is unknown.
gs.loadChars( StreetAddress1, 48 );
By default, the new text REPLACES the existing text; however, the ’append’ parameter allows the new text to be appended to the existing text.
The functionality is equivalent to the gString constructor which loads
only the specified number of characters.
See gString Instantiation.
Input : usrc : pointer to a UTF-8 encoded string wsrc : pointer to a wchar_t encoded string charLimit: maximum number of characters (not bytes) from source array to load. Range: 1 through gsMAXCHARS. The count should not include the NULL terminator append : (optional, 'false' by default) if 'false', replace existing text with specified text if 'true', append new text to existing text Returns: number of characters in modified string (incl. NULL terminator)
Replace the existing text with the specified number of characters from the source text. const char* Piggy = // (56 characters) "Spider-pig, Spider-pig does whatever a Spider-pig does." ; gString gs( "Existing text." ) ; gs.loadChars( Piggy, 36 ) ; Yields: "Spider-pig, Spider-pig does whatever" Append specified number of characters from the source text to the existing text. gs.loadChars( " it's told, because it's stupid.", 11, true ) ; Yields: "Spider-pig, Spider-pig does whatever it's told,"
Reverse the order of characters in the text string.
If RTL text data displayed by your application is not formatted as desired, then this method may be used to reverse the character order before writing to the display. This is useful for manipulating both RTL (Right-To-Left) language text and mixed RTL/LTR text.
The ’para’ parameter is useful for outputting columns of numeric data or when the column labels are in an RTL language (see example below).
Although modern web browsers (Firefox, Opera, Chromium, etc.) usually handle RTL text correctly, other applications often do not. This is especially true of terminal emulator software.
See also a discussion of multiple-language support in the NcDialog API.
see Multi-language Support.
Input : punct : (optional, 'false' by default) if 'false', invert entire string if 'true' AND if a punctuation mark is seen at either end of the string, invert everything except the punctuation mark(s). typically one of the following: '.' ',' '?' '!' ';' ':' but see note below. para : (optional, 'false' by default) if 'false', invert data as a single character stream if 'true', invert data separately for each logical line (line data are separated by newlines ('\n') rjust : (optional, 'false' by default) if 'false', do not insert right-justification padding if 'true', insert padding for each logical line to right-justify the data (used to right-justify LTR output) Note that right-justification is performed ONLY if the 'para' parameter is true. Otherwise, 'rjust' will be ignored. Returns: number of wchar_t characters in gString object (if return value >= gsMAXCHARS, data may have been truncated)
Note that the const Hebrew strings are written canonically in the source, but are displayed incorrectly in the terminal window by the info reader and by the HTML browser (sorry about that).
// Hebrew: "Are you ready for lunch?" // Sometimes the terminal will inappropriately move the punctuation // to the opposite end of the string. // To prevent this, use the 'punct' option. const wchar_t* const Lunch = L"?םיירהצ תחוראל ןכומ התא םאה" ; gString gs( Lunch ) ; gs.textReverse() ; wcout << gs.gstr() << endl ; OUTPUT (correct except punctuation) : האם אתה מוכן לארוחת צהריים? gs = Lunch ; gs.textReverse( true ) ; wcout << gs.gstr() << endl ; OUTPUT (correct): ?האם אתה מוכן לארוחת צהריים // When the 'punct' flag is set, both leading and trailing punctuation // are identified. // Questions in Spanish use a leading inverted question mark (U+00BF), // and a trailing ASCII question mark (U+003F). // Reverse the internal text but do not reverse the terminal punctuation. gs = "¿ozreumla le arap atsil sátsE?" ; gs.textReverse( true ) ; wcout << gs.gstr() << endl ; OUTPUT : ¿Estás lista para el almuerzo? = = = = = // Reverse multi-line text (paragraph formatting). // Ordinary ASCII text is used for this example // to demonstrate the reversal. // The example outputs to an NcDialog window referenced by NcDialog *dp const char* Vaccine = "Have you received your covid-19 vaccination yet?\n "Protect yourself and others,\n" "get your vaccination today!" ; gs = Vaccine ; // Write unmodified text as LTR data: dp->WriteParagraph ( 1, 1, gs, nc.grR, true, false ) ; OUTPUT: Have you received your covid-19 vaccination yet? Protect yourself and others, get your vaccination today! // Reverse the data, without punctuation processing or // right-justification. (Note: all parameters are optional, // but are shown here for clarity.) gs.textReverse( false, true, false ) ; // Write reversed text as LTR data: dp->WriteParagraph ( 1, 1, gs, nc.grR, true, false ) ; OUTPUT: ?tey noitaniccav 91-divoc ruoy deviecer uoy evaH ,srehto dna flesruoy tcetorP !yadot noitaniccav ruoy teg // Write the same data as RTL (note the X origin of 48): dp->WriteParagraph ( 1, 48, gs, nc.grR, true, true ) ; OUTPUT: ?tey noitaniccav 91-divoc ruoy deviecer uoy evaH ,srehto dna flesruoy tcetorP !yadot noitaniccav ruoy teg // Reload the source data and reverse it without punctuation processing, // but WITH right-justification padding. gs = Vaccine ; gs.textReverse( false, true, true ) ; // Write reversed text as LTR data. // Note that the padding character is ASCII space ' ', // however the '-' character is used here to show the padding position. dp->WriteParagraph ( 1, 1, gs, nc.grR, true, false ) ; OUTPUT: ?tey noitaniccav 91-divoc ruoy deviecer uoy evaH --------------------,srehto dna flesruoy tcetorP ---------------------!yadot noitaniccav ruoy teg // Write the same data as RTL (note the X origin of 48): dp->WriteParagraph ( 1, 48, gs, nc.grR, true, true ) ; OUTPUT: ?tey noitaniccav 91-divoc ruoy deviecer uoy evaH --------------------,srehto dna flesruoy tcetorP ---------------------!yadot noitaniccav ruoy teg // Combine RTL text with numeric (LTR) data. // Create an ASCII numeric time string. // Reverse the numeric string. // Insert a Hebrew label: "The current time is: " const wchar_t *timeLabel = L"השעה הנוכחית היא: " ; //(displayed incorrectly) short hours = 12, minutes = 32, seconds = 45 ; gs.compose( "%02hd:%02hd:%02hd", &hours, &minutes, &seconds ) ; gs.textReverse( false, true, false ) ; gs.insert( timeLabel ) ; // Write the data as RTL (note the X origin of 26): dp->WriteParagraph ( 1, 26, gs, nc.grR, true, true ) ; OUTPUT: 12:32:45 :השעה הנוכחית היא
Determining which characters are and are not punctuation is locale specific
(see the 'ispunct()' C-language function).
Rather than rely on the locale used by the application calling this method,
we test against a list of the most common punctuation characters used in
modern languages. If a punctuation character used by your application is
not recognized as punctuation, please send us a note including the Unicode
codepoint and we will add it to the list.
Next: Extract Formatted Data, Previous: Modifying Existing Data, Up: gString Text Tool [Contents][Index]
Input : uStr : (UTF-8 string) to be compared OR wStr : (wchar_t string) to be compared casesen : (optional, 'true' by default) if 'true' perform case-sensitive comparison if 'false' perform case-insensitive comparison length : (optional, gsMAXCHARS by default. i.e. compare to end) maximum number of characters to compare offset : (optional, ZERO by default) If specified, equals the character offset into the gString character array at which to begin comparison. Returns: return value uses the rules of the 'wcsncmp' (or 'wcsncasecmp') library function (see string.h): ZERO, text data are identical > ZERO, first differing char of gString object is numerically larger. < ZERO, first differing char of gString object is numerically smaller.
Compares the text content of the gString object with the specified text.
The comparison is performed against the gString object’s wchar_t character array. The relationship between upper-case and lower-case characters is locale dependent.
Input : gs : (by reference) object whose text is to be compared casesen : (optional, 'true' by default) if 'true' perform case-sensitive comparison if 'false' perform case-insensitive comparison Returns: return value uses the rules of the 'wcsncmp' (or 'wcsncasecmp') library function (see string.h): ZERO, text data are identical > ZERO, first differing char of gString object is numerically larger. < ZERO, first differing char of gString object is numerically smaller.
Compares the text content of two gString objects.
The comparison is performed against the gString objects’ wchar_t character arrays. The relationship between upper-case and lower-case characters is locale dependent.
Input : gs2 : (by reference) gString object containing string to be compared Returns: 'true' if the strings are identical, else 'false'
Comparison operator: Compares the text content of two gString objects.
The comparison is performed against the wchar_t character arrays of the two objects. The comparison is is case-sensitive.
Input : gs2 : (by reference) gString object containing string to be compared Returns: 'true' if the strings are different, else 'false'
Comparison operator: Compares the text content of two gString objects.
The comparison is performed against the wchar_t character arrays of the two objects. The comparison is is case-sensitive.
Input : src : source data to be matched, one of the following: -- pointer to a UTF-8 string (max length==gsMAXBYTES) -- pointer to a wchar_t string (max length==gsMAXCHARS) -- a gString object containing the source (by reference) -- a single, wchar_t character offset : (optional, ZERO by default) character index at which to begin search -- if out-of-range, then same as if not specified casesen: (optional, 'false' by default) if 'false', then scan IS NOT case sensitive if 'true, then scan IS case sensitive The way upper/lowercase are related is locale dependent; maxcmp : (optional, (-1) by default) -- if not specified, then scan for a match of all characters in 'src' (not including null terminator) -- if specified, then scan for a match of only the first 'maxcmp' characters of 'src' -- if out-of-range, then same as if not specified Returns: index of matching substring or (-1) if no match found Note: This is the wchar_t character index, NOT a byte index
Scan the data for a matching substring and if found, return the index at which the first substring match begins.
Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character IS NOT included in the comparison. These comparisons ARE locale dependent.
Input : src : source data to be matched, one of the following: -- pointer to a UTF-8 string (max length==gsMAXBYTES) -- pointer to a wchar_t string (max length==gsMAXCHARS) -- a gString object containing the source (by reference) -- a single, wchar_t character casesen: (optional, 'false' by default) if 'false', then scan IS NOT case sensitive if 'true, then scan IS case sensitive The way upper/lowercase are related is locale dependent; Returns: index of last matching substring or (-1) if no match found Note: This is the wchar_t character index, NOT a byte index
Scan the data for the last occurance of the matching substring and if found, return the index at which the substring match occurs.
Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character IS NOT included in the comparison. These comparisons ARE locale dependent.
Input : src : source data to be matched, one of the following: -- pointer to a UTF-8 string (max length==gsMAXBYTES) -- pointer to a wchar_t string (max length==gsMAXCHARS) -- a gString object containing the source (by reference) offset : (optional, ZERO by default) character index at which to begin search -- if out-of-range, then same as if not specified casesen: (optional, 'false' by default) if 'false', then scan IS NOT case sensitive if 'true, then scan IS case sensitive The way upper/lowercase are related is locale dependent; Returns: index of the character which follows the matching substring or (-1) if no match found Note: This is the wchar_t character index, NOT a byte index
This method is very similar to the ’find()’ method above, but instead of returning the index to the beginning of the substring, returns the index of the character which FOLLOWS the substring.
Input : srcChar: (optional, L' ' by default) character to be skipped over offset : (optional, ZERO by default) if specified, equals the character offset into the character array at which to begin the scan. Returns: a) If successful, returns the index of first character which DOES NOT match specified character. b) If the scan finds no character which is different from the specified character, OR if 'offset' is out of range, OR if the specified character is the null character, the return value indexes the null terminator of the array. Note: This is the wchar_t character index, NOT a byte index
Scan the text and locate the first character which DOES NOT match the specified character.
This method is used primarily to scan past the end of a sequence of space (' ') characters (0x0020), but may be used to skip over any sequence of a single, repeated character. Note that the character specified must be a ‘wide’ (wchar_t) character.
See also the ’scan’ method below which scans to the first non-whitespace character.
Input : offset : (optional, ZERO by default) if specified, equals the character offset into the character array at which to begin the scan. Returns: a) If successful, returns the index of first non-whitespace character b) If the scan finds no non-whitespace character OR if 'offset' is out of range, the return value indexes the null terminator of the array. Note: This is the wchar_t character index, NOT a byte index.
Scans the text array and returns the index of the first non-whitespace character found.
Whitespace characters are defined as:
0x0020 single-column ASCII space
0x3000 two-column CJK space
0x0A linefeed character
0x0D carriage-return character
0x09 horizontal-tab character
0x0B vertical-tab character
0x0C formfeed character
gString str1( "Toys for Tots" ) ; gString str2( "The Tin Drum" ) ; // compare with UTF-8 string short result = str1.compare( "Toys for Tots" ) ; // compare with wchar_t string short result = str2.compare( L"The Tin Drum" ) ; // compare gString objects if ( str1 == str2 ) { /* do stuff */ } if ( str1 != str2 ) { /* do stuff */ } gString gs( L"Tiny Tim had a titillating tour of Times Square." ) ; // find first instance of substring "tim" (not case sensitive) short tIndex = gs.find( "tim" ) ; wcout << &gs.gstr()[tIndex] << endl ; - - -> Tim had a titillating tour of Times Square. // find the next instance of "tim" gString gsSub( "tim" ) ; // search string in a gString object tIndex = gs.find( gsSub, tIndex + 1 ) ; wcout << &gs.gstr()[tIndex] << endl ; - - -> Times Square. // find first instance of substring "ti" (case sensitive) tIndex = gs.find( L"ti", 0, true ) ; wcout << &gs.gstr()[tIndex] << endl ; - - -> titillating tour of Times Square. // match the first three characters of the search string tIndex = gs.find( L"squirrel", 0, false, 3 ) ; wcout << &gs.gstr()[tIndex] << endl ; - - -> Square. // find first instance of L'R' (not case sensitive) tIndex = gs.find( L'R' ) ; wcout << &gs.gstr()[tIndex] << endl ; - - -> r of Times Square. // extract the filename from path/filename string gString gs( "/home/sam/SoftwareDesign/NcDialog/Dialog1/gString.hpp" ) ; if ( (tIndex = gs.findlast( L'/' )) >= 0 ) wcout << &gs.gstr()[tIndex + 1] << endl ; - - -> gString.hpp // insert text after first instance of substring gString gs( "I think that a parrot would be an ideal pet." ) ; short pIndex = gs.after( L"would" ) ; gs.insert( " NOT", pIndex ) ; - - -> I think that a parrot would NOT be an ideal pet.
For more examples of using gString-class methods, please refer to
Test #6 of the ’Dialogw’ test application.
See Dialogw App.
Next: Statistical Info, Previous: Comparisons, Up: gString Text Tool [Contents][Index]
Input : fmt : a format specification template in the style of swscanf() or sscanf() and related C/C++ functions Template may be either a const char* OR a const wchar_t* ... : optional arguments Each optional argument is a POINTER to (address of) the variable to receive the formatted data. - Important Note: There must be AT LEAST as many optional arguments as the number of format specifiers defined in the formatting template. Excess arguments will be ignored; however, too few arguments will return an error condition. (see below) Returns: number of items captured and converted returns 0 if: a) number of format specifications in 'fmt' > gsFormMAXARGS b) number of format specifications in 'fmt' > number of optional arguments (pointers to target variables) provided
Scan the text data contained in the gString object and extract data
according to the specified formatting template.
(This is an implementation of the standard C-library ’swscanf’ function.)
The formatting template may be either a 'const wchar_t*' as in a call to 'swscanf', or a 'const char*' as in a call to 'sscanf'.
The formatting template may contain between zero(0) and gsFormMAXARGS format specifiers.
The optional arguments are pointers to the target variables which will receive the formatted data.
As with 'swscanf', the number of optional arguments must be equal
to or greater than the number of format specifiers:
(%d, %63s, %X %lld, %24lls, %[, etc.).
Excess arguments will be ignored; however, unlike the 'swscanf' function,
'gscanf' counts the number of format specifiers and optional arguments,
and if there are too few arguments, the scan will be aborted to avoid an
application crash due to memory-access violation. (You’re welcome :-)
Input : offset: wide-character offset at which to begin the scan Important Note: This IS NOT a byte offset. If offset < 0 || offset > length of data, offset will be silently set to 0. fmt : a format specification template in the style of swscanf() or sscanf() and related C/C++ functions Template may be either a const char* OR a const wchar_t* ... : optional arguments Each optional argument is a POINTER to (address of) the variable to receive the formatted data. - Important Note: There must be AT LEAST as many optional arguments as the number of format specifiers defined in the formatting template. Excess arguments will be ignored; however, too few arguments will return an error condition. (see below) Returns: number of items captured and converted returns 0 if: a) number of format specifications in 'fmt' > gsFormMAXARGS b) number of format specifications in 'fmt' > number of optional arguments (pointers to target variables) provided
This is the same method as described above except that the scan of the data begins at the specified character offset.
short sval1, sval2, sval3, sval4 ; int ival ; long long int llval ; double dval ; char str1[64], str2[16], str3[16], ch1 ; gString gs( "17 % 18 21 22 48A2B 720451 24.325 A country song " "is three chords and the truth. - Willie Nelson" ) ; short cnt = gs.gscanf( L"%hd %% %hd %hd %hd %X %lld %lf %63[^-] %c %16s %16s", &sval1, &sval2, &sval3, &sval4, &ival, &llval, &dval, str1, &ch1, str2, str3 ) ; gString gsOut( "items : %hd\n" "numeric : %hd %hd %hd %hd 0x%04X %lld %4.6lf\n" "text data: \"%s\" %c %s %s\n", &cnt, &sval1, &sval2, &sval3, &sval4, &ival, &llval, &dval, str1, &ch1, str2, str3 ) ; dp->WriteParagraph ( 1, 1, gsOut, dColor ) ; This yields: items : 11 numeric : 17 18 21 22 0x48A2B 720451 24.325000 text data: "A country song is three chords and the truth. " - Willie Nelson A working example may be found in the NcDialog API package, (Dialogw test application, Test #6). - - - - - To begin the scan from a particular offset into the text, the unneeded initial data may either be scanned into a throw-away buffer or the scan offset may be specified directly. For example, to discard the first sixteen(16) characters: wchar_t junk[gsMAXCHARS] ; gs = "Useless garbage: 17 21 34" ; gs.gscanf( L"%16C %hd %hd %hd", junk, &sval1, &svan2, &sval3 ) ; _or_ gs.gscanf ( 16, L"%hd %hd %hd", &sval1, &svan2, &sval3 ) ;
Next: gString Miscellaneous, Previous: Extract Formatted Data, Up: gString Text Tool [Contents][Index]
Input : none Returns: number of characters in the string
Returns the number of characters in the string including the null terminator.
Input : none Returns: number of bytes in UTF-8 string
Returns the number of bytes in the UTF-8-encoded string including the null terminator.
Input : none Returns: number of columns needed to display the data
Returns the number of columns required to display the string.
Input : charCount : (by reference, initial value ignored) on return, contains number of characters in the string including the null terminator. Returns: pointer to number of columns needed for display of each character
Returns a pointer to an array of column counts, one for each character of the text data. Note that number of array elements equals number of characters (plus meta-characters, if any).
This example is from the FileMangler utility. It trims the head of the provided path/filename string to fit within a dialog window. void FmConfig::ecoPathFit ( gString& gsPath, short colsAvail ) { if ( (gsPath.gscols()) > colsAvail ) { gString gst = gsPath ; short width = gst.gscols(), offset = ZERO, charCount ; const short* colArray = gst.gscols( charCount ) ; while ( width > (colsAvail - 3) ) width -= colArray[offset++] ; gsPath.compose( L"...%S", &gst.gstr()[offset] ) ; } } //* End ecoPathFit() *
Input : none Returns: 'true' if data are pure, 7-bit ASCII, else 'false'
Scan the data to determine whether it is pure, 7-bit ASCII.
Next: gString Examples, Previous: Statistical Info, Up: gString Text Tool [Contents][Index]
Input : none Returns: nothing
Reset contents to an empty string i.e. "". The data will consist of a single, NULLCHAR character. The character and byte counts are set to 1 (one), and the column count is zero.
Input : none Returns: pointer to version string
Return a pointer to gString class version number string.
Input : gsmsg : (caller's object, by reference) receives most recent debug message Returns: nothing
FOR DEBUGGING ONLY! Application can retrieve most recent debug message.
Note: This method is visible only if the ENABLE_GS_DEBUG flag is set
in gString.hpp.
Previous: gString Miscellaneous, Up: gString Text Tool [Contents][Index]
The NcDialog API test application ’Dialogw’ contains extensive
examples of gString usage, including working copies of the examples
used in this chapter.
See Dialogw App.
The other NcDialog API test applications also use gString in various ways.
Here, we show just a sample of some basic uses for the gString class.
const char* some_UTF-8_data = "I want to buy an hamburger." ; wchar_t some_wide_data[gsMAXCHARS] ; gString gs( some_UTF-8_data ) ; gs.copy( some_wide_data, gsMAXCHARS ) ;
const wchar_t* some_wide_data = L"I want to buy an hamburger." ; char some_UTF-8_data[gsMAXBYTES] ; gString gs( some_wide_data ) ; gs.copy( some_UTF-8_data, gsMAXBYTES ) ;
const char* Head = "Where" ; const wchar_t* Tail = L"is Carmen Sandiego?" ; gString gs( L" in the world " ) ; gs.insert( Head, ZERO ) ; gs.append( Tail ) ; wcout << gs << endl ; - - -> Where in the world is Carmen Sandiego?
const char* utf8String = "We present" ; const wchar_t* wideString = L"for your enjoyment:" ; const char utf8Char = 'W' ; const wchar_t wideChar = L'C' ; short int ways = 100 ; double dish = 17.57 ; gString gs ; gs.compose( "%s %S %hd %cays to %Cook %Chicken,\n" "and %.2lf side dishes and beverages!", utf8String, wideString, &ways, &utf8Char, &wideChar, &wideChar, &dish ) ; wcout << gs << endl ; - - -> We present for your enjoyment: 100 Ways to Cook Chicken, and 17.57 side dishes and beverages!
Important Note: All parameters are pointers to the data: For strings (and pointers), the address is the name of the variable. For all other data types, including single characters, use the address-of ('&') operator.
This is a formatting method taken from the ’Dialogx’ test application. It breaks a text stream into lines which fit within the dianostic window. It’s not speedy (or particularly smart), but it demonstrates the use of ’gString’ to calculate the space needed to display text data and then formatting the data to fit the space.
//* FormatOutput * //* Input : gsOut : semi-formatted source data //* wpos : start position for display //* lineCount : maximum display lines before truncation //* Returns: nothing void dXClip::FormatOutput ( const gString& gsOut, winPos& wpos, short lineCount ) { short tWidth = (ddCOLS - 2), // inside width of target window maxWidth = tWidth * lineCount,// max columns for message tLines = ZERO ; // loop counter gString gsw( gsOut.gstr() ), gso ; if ( gsw.gscols() > maxWidth ) { // truncate the string if necessary gsw.limitCols ( maxWidth - 3 ) ; gsw.append( L"..." ) ; } do { // break the source into convenient widths gso = gsw ; gso.limitCols( tWidth ) ; gso.append( L'\n' ) ; gsw.shiftCols( -tWidth ) ; this->dpd->ClearLine ( wpos.ypos ) ; // clear target display line wpos = this->dpd->WriteParagraph ( wpos, gso, dxPtr->dColor, true ) ; } while ( ++tLines <= lineCount && gsw.gschars() > 1 ) ; } //* End FormatOutput() *
The example above is just a simple one. To see it in action, please
refer to the ’Dialogw’ NcDialog API Test Application, test seven (7).
See Dialogw App,
For a more sophisticated example, see the
’DialogTextbox::mlFmtDisplay’ automatic word-wrapping method
in the NcDialog API source code.
Next: Installation, Previous: gString Text Tool, Up: NcDialog Library API [Contents][Index]
"It’s not code until it is documented and tested code!
and it’s not documented-and-tested code until it is
thoroughly understood by someone else."
— Software Sam, 2014
Next: Sandbox, Up: Application Examples [Contents][Index]
These applications are written to support the development and testing process. They have been cleaned up, expanded and internally documented, so that nearly everything that can be done with the NcDialog library is clearly demonstrated in one or more of these apps. Additions will be made to these applications whenever new functionality is added to the NcDialog library.
Next: Dialog1 App, Up: Test Applications [Contents][Index]
The NcDialog source code includes simple applications that demonstrate all the
functionality of the NCurses, NcWindow, NcDialog and gString classes.
For details on each test method contained in the following applications,
please refer to the following chapters for the individual test applications.
To find a specific example of how a particular API method is called,
run the ’grep’ command on the source files of the test applications,
but not on the API source code itself.
For example, if you want to find all instances of the ’DisplayLineDrawingSet’ method, you would navigate to the ’NcDialog’ source code directory, which is the container directory for the test applications. Then enter the following command:
grep -n 'DisplayLineDrawingSet' Dialog1/Dialog1.cpp Dialog[234wx]/*.cpp
In this case, your search will result in the following:
Dialog2/Dialog2.cpp:3008: dp->DisplayLineDrawingSet ( wPos, callColor );
indicating that the target method is called on line 3008 of Dialog2.cpp.
Testing for thread-safe input/output within an NcDialog-based application is performed here. For this reason, Dialog4 is linked with the ’pthread’ library.
Also included is the ’Sandbox’, a full-sized dialog window with only a ’DONE’
Pushbutton control. You may find the Sandbox useful for doing quick tests
because the dialog structure and input loop are already in place.
Please see See Sandbox, for further information.
Please see Dialog4 App for test application details.
Please see Dialogw App for test application details.
Dialogx is built around the WaylandCB class which provides access to the GNOME/Wayland clipboards.
Within an NcDialog application, the clipboard is needed only for Textbox controls (DialogTextbox class objects). For may applications, the NcDialog local clipboard is sufficient, and access to the system clipboard will be unnecessary.
However, for applications which require it, the WaylandCB class may be built into the application for painless access to the system clipboard.
The NcDialog API does not directly interact with the system clipboard, but provides this method for system access at the application level.
Please see Dialogx App for test application details.
The generated map may be used to customize the NcDialog API for the keycodes available in the target environment.
Please see Keymap App for test application details.
Next: Dialog2 App, Previous: Overview, Up: Test Applications [Contents][Index]
Dialog1 is the application against which the NcDialog API library is built, and it demonstrates the most basic of the API functionality.
All test applications described in this chapter share a set of basic command-line options.
Please see Multi-language Support for a further discussion of locale settings.
The test applications also have command-line options specific to the tests they contain. See the individual applications for details.
In addition to the common options, the following are defined for this application.
(please also see DisplayTextboxMessage method)
Sub-options:
Test01
======
This dialog demonstrates the following user interface control types:
Class name Control-type designation ........................ ........................ DialogTextbox class dctTEXTBOX DialogRadiobutton class dctRADIOBUTTON DialogPushbutton class dctPUSHBUTTONThe Textbox examples show output-formatting options, input filtering options, and multi-language support.
The Radiobutton examples show stand-alone Radiobuttons, Radiobutton groups and some of the different visual formats available for radiobuttons.
The Pushbutton examples show the basic functionality of pushbuttons and how to capture and respond to user interactions.
Test01 also demonstrates a simple, annotated example of an NcDialog API user interface loop showing how the input focus is shifted among the input-control objects. For more detailed information on the user-interface loop, please refer to See User Interface Loop.
Also included is the T1_ControlUpdate() method. This demonstrates the NcDialog API’s ’callback’ functionality, including how to establish a callback method which can be used to monitor user activity while the user is interacting directly with the user interface of various control types.
This callback method performs some simple monitoring tasks:
- − Monitoring the state of the ‘Insert/Overstrike Mode’ flag and displaying the status.
- − Capture and display (in near-real-time) the state of a Radiobutton control.
If the “wl-clipboard” (Wayland Clipboard) utilities are installed on your system, then Test01 establishes communications between the application’s Textbox controls and the system clipboard, enabling full copy/cut/paste functionality. If the “wl-clipboard” utilities are not installed on your system, copy/cut/paste operations are available only among the dialog window’s local Textbox controls.
Please see Clipboard Interface for a discussion of application access to the system clipboard.
Please see Local NcDialog Clipboard for a discussion of the internal application clipboard.
Test02
======
This dialog demonstrates the following user interface control types:
Class name Control-type designation ........................ ........................ DialogScrollbox class dctSCROLLBOXTwo varieties of Scrollbox controls are demonstrated: one with the contents in a monochrome color, and the other with a different color for each displayed item.
Also included is the T2_ControlUpdate() method. This demonstrates how to capture the user’s actions and his/her selection within the Scrollbox controls.
Test03
======
Demonstrates the internal working of an NcDialog Scrollbox control by showing how to manually build a scrollbox using NcWindow-class primitives.
Test04
======
Demonstrates the internal working of an NcDialog window object by showing how to manually open, manipulate and close a window object using NcWindow-class primitives.
Test05
======
Demonstrates how to call the ’DisplayRadiobuttonTypes’ method. This is a method which can be used during application development to help you select the type of Radiobutton which is most visually appealing for your dialog.
Test06
======
This dialog demonstrates the following user interface control types:
Class name Control-type designation ........................ ........................ DialogRadiobutton class dctRADIOBUTTON
This test shows how to create a Radiobutton group, i.e. an exclusive-OR group of Radiobutton controls, so the user can select one, and only one option from the option list.
Also included is the T6_ControlUpdate() method. This demonstrates how to dynamically use the value contained in one control object to update the contents of another control object.
Test07
======
Demonstrates how to design a user interface using ’hotkeys’ which allow the user to move quickly among the controls in the dialog.
- − A ’hotkey’ is a key sequence that allows the user to move directly to the target control object without having to sequentially select each control until the target is reached.
- − ’Hotkeys’ may optionally be specified for all control types.
Please see Select Control via Hotkey for more information.
- − The user interface loop is modified slightly to accomodate these non-sequential control selections.
Also included is the T7_ControlUpdate() method. This method provides additional examples of using the contents of one control object to update the contents of another control object.
Test08
======
This test case contains a variety of control types and was created to test the ability of the NcDialog API to move an entire dialog window from one place to another within the terminal window. This is actually more cool than it sounds, because it is not a simple matter of erasing the window and drawing it somewhere else.
This test also includes a facility to capture the entire display area of the dialog to a file (in color), either to a plain text file, or to an HTML file. Note that the current HTML standard has some trouble with alignment of multi-column characters, but we hope those issues will be resolved soon. The capture functionality may be of limited use except in creating lovely diagrams for illustrating the documentation for your own applications, but it was a lot of fun to write.
Test09
======
Demonstrates the following:
Class name Control-type designation ........................ ........................ DialogDropdown class dctDROPDOWN
Dropdown controls may expand either upward or downward and their extent is automagically limited to the boundaries of the parent NcDialog window. This test was written to verify that Dropdown controls expand and contract as designed.
See Dropdown Controls.
Test10
======
Demonstrates the following:
Class name Control-type designation ........................ ........................ DialogMenuwin class dctMENUWINMenus may be defined either as independent controls or as members of a menu group known as a ’Menu Bar’. In addition, menus may include any reasonable sequence of sub-menus, sub-sub-menus, etc. Context menus (menus which are normally invisible) are also demonstrated here.
See Menuwin Controls.
'About' Dialog
==============
Good programming practice dictates that every non-trivial application have and ’About’ dialog which gives information on the application: name, author, version, release date, etc.
(Traditional console applications under Linux have an equivalent functionality invoked through --help, --version or similar command-line switches.)
This sub-dialog implements a typical ’About’ dialog with the addition of discriptions for all application command-line options.
The 'About' sub-dialog for Dialog1.
┌────────────────────────────────────────────────────────────────────┐ │Dialog1, Version: 0.1.07 │ │Copyright (c) 2006-2021 Mahlon R. Smith, The Software Samurai │ │ Beijing University of Technology │ │ │ │A simple utility for development and testing of the NcDialog family │ │of classes based on the Linux/UNIX ncurses library. │ │ │ │Command Line arguments (optional): │ │ -n where 'n' is a test number │ │ -A, -a specify alternate 'locale' Ex: -Awo_SN.utf8 │ │ -d[c , m , r , [0|1|2|3]] Exercise special options for Test01 │ │ -H, -h Help (this dialog) │ │ │ │The API behind this utility provides a means of easily designing │ │applications for curses, while in a modern, C++ environment. │ │For bugs, suggestions, possible praise: http://www.SoftwareSam.us │ │ │ │Tools: GNU G++ (Gcc v:4.8.0+) under Fedora and Ubuntu Linux. │ │ Requires ncurses library v:5.9+ │ │ │ │ CLOSE DISPLAY CLASS VERSIONS │ └────────────────────────────────────────────────────────────────────┘
Two Pushbutton controls are defined for this dialog: ’CLOSE’ which will close the sub-dialog, and ’DISPLAY CLASS VERSIONS’ which will open a sub-sub-dialog to display the version numbers of the application’s component classes and libraries.
The 'About' sub-dialog with the Class Info' sub-sub-dialog.
┌────────────────────────────────────────────────────────────────────┐ │Dialog1, Version: 0.1.07 │ │Copyright (c) 2006-2021 Mahlon R. Smith, The Software Samurai │ │ Beijing University of Technology │ │ ┌───────────┤ Class Info ├───────────┐ │ │A simple utili│NcDialog class : 0.0.30 │Dialog family │ │of classes bas│ │ │ │ │NcWindow class : 0.0.24 │ │ │Command line a│ │ │ │ -n wh│NCurses class : 0.0.22 │ │ │ -A, -a sp│ │8 │ │ -d[c , m ,│gString class : 0.0.27 │ for Test01 │ │ -H, -h He│ │ │ │ │ncurses library: 6.1.20180923 │ │ │The API behind│ │ designing │ │applications f│Locale setting : en_US.utf8 │nment. │ │For bugs, sugg│ │twareSam.us │ │ │ CLOSE │ │ │Tools: GNU G++└──────────────────────────────────────┘Linux. │ │ Requires ncurses library v:5.9+ │ │ │ │ CLOSE DISPLAY CLASS VERSIONS │ └────────────────────────────────────────────────────────────────────┘The ’Class Info’ sub-sub-dialog simply displays additional information. This is one way to make it easier for the user to find the information that you, the software developer, may need if the user contacts you with a technical-support issue.
Next: Dialog3 App, Previous: Dialog1 App, Up: Test Applications [Contents][Index]
In addition to the common options, the following are defined for this application.
Because Dialog2 contains several tests for configuration and modification of the color palette, this option is provided to aid those tests. Note, however, that using monochrome mode to run an application that was designed for multi-color data results in major ugliness, bordering on the unusable.
Test01
======
This test is a skeleton of the main window for the ’FileMangler’ utility. It demonstrates some complex examples of Scrollext and Menuwin user interface controls, including dynamic data update and the MenuBar construct which links together a multi-level group of individual menus into a single, complex user interface structure.
As an historical note, in the early days of this project, this test used live directory/file data, but over time the FileMangler’s management sequences became too complex for such a simple demonstration app. Download the full FileMangler package (see Technical Support), and dig into its guts! It’s not for the timid, but you may find one or two interesting programming techniques and C++ constructs.
Test02
======
The Scrollbox and Scrollext user interface controls often span the full width or height of a dialog window. For this reason we provide a way to visually ’connect’ these controls with the border of the dialog window. Please see ConnectControl2Border method for information on how to connect these controls to the dialog border.
Test03
======
This dialog demonstrates several different flavours of Spinner user interface controls, how to initialize them, and how use them to gather fully range-checked nummeric data from the user.
Please see Spinner Controls for more information.
Test04
======
This dialog contains a rather ambitious test of color mapping, including editing of the RGB registers and customizing the foreground/background color pairs that are defined in the low-level ’ncursesw’ C-language library.
Tne NcDialog API takes color mapping far beyond the modest support provided by the C library — including saving the color map to a plain text file and support for loading a custom color map during startup. Please see Color Attributes for a full discusson of using color attributes in the NcDialog API.
Test05
======
This dialog contains a useful test of keyboard input which can be used to determine your system’s keyboard mapping as well as the key combinations which are available to console applications.
This test can also temporarily disable keycode translation so you can see the actual Escape Sequences transmitted through the terminal’s key input stream.
Please see Keycode Constants for a discussion of keyboard input.
For a more comprehensive keycode test please see Keymap App which tests all of the keycodes that are likely to vary from system to system.
Test06
======
This test is a simple invocation of the development methods which display the color attributes available to the ’ncursesw’ C-language library (DisplayColorOptions method), as well as a list of the foreground/background color combinations defined as public data members of the NCurses class (DisplayDefinedColors method).
Please see Color Attributes for a full discusson of using color attributes in the NcDialog API.
Test07
======
This pair of dialog windows shows a more complete and sophisticated rendering of the available color attributes than those in Test06, AND provides a comprehensive test of capturing an NcDialog window in either plain text or full-color HTML formats.
Please see CaptureDialog method for additional information.
Test08
======
This set of dialogs displays the available line-drawing characters and example figures, drawn in the colors of your choice. Use this test to help you decide which color combinations will look best in your own applications.
Test09
======
This test is a simple invocation of the development method which displays the contents of the so-called Alternate Character Set.
Please see Line Drawing Characters for notes on the Alternate Character Set (and why it should never be used).
Test10
======
This set of dialogs displays the built-in GNU/Linux Alternate Character Set (see Test09), and the Unicode/UTF-8 equivalent characters which should be used for all new development.
Please see Line Drawing Characters for more information.
Test11
======
This is a special test of the NCurses-class unformatted stream output. This test is invoked from ’main’ (before the NCurses Engine is started), and the code for the test is located in StreamTest.cpp. For more information:
See WriteStream method, and
See OutputStreamScrolling method.
'About' Dialog
==============
‘Help About’ sub-dialog providing application info to the user.
See example ‘About’ dialog in previous chapter, see Dialog1 App.
Next: Dialog4 App, Previous: Dialog2 App, Up: Test Applications [Contents][Index]
In addition to the common options, the following are defined for this application.
The Dialog3 test application is a template application.
Each test dialog is simply a template dialog which you can modify to create
your own test scenarios.
┌┤ Generic Dialog Window ├┐ │ │ │ Modify this dialog │ │ for your testing needs. │ │ │ │ │ │ Press Any Key │ └───────────────────────────┘
Next: Dialogw App, Previous: Dialog3 App, Up: Test Applications [Contents][Index]
In addition to the common options, the following are defined for this application.
The Dialog4 test application is linked to the ’pthread’ library for testing of thread safety and other issues related to multitasking applications.
Test01
======
This dialog is implemented as a ’Sandbox’, a safe and convenient place to create quick tests.
Please see Sandbox for additional information.
Test02
======
This dialog tests the functionality of the NcDialog-class ’UserAlert’ method to produce a sequence of sounds that can be used to get the user’s attention.
While the low-level NCurses-class ’UserAlert’ method produces a single ping sound, the NcDialog UserAlert method offers a number of configuration options so that you can customize your audible alert for each event.
The actual ping sound produced is system dependent, and can often be specified or customized as part of your desktop software configuration. For the GNOME desktop, this configuration is located in the ’Sound’ utility under the ’Sound Effects’ tab. Note also that your desktop configuration may also allow for flashing the screen instead of, or in addition to the audible alert, but this isn’t so impressive as it sounds, and is really hard on the eyes.
Please see UserAlert method for more information.
Test03
======
This dialog exercises the low-level NCurses-class mouse interface.
While no one in his or her right mind would implement an application using the low-level interface directly, it does provide the basis for the higher-level NcDialog API mouse interface (see Test04 below).
Please see NCurses Mouse Access for more information.
Test04
======
This dialog demonstrates the use of the NcDialog API mouse interface.
While native (xterm/ncursesw) support for mouse input in console applications is rudimentary at best, this test provides a taste of what is possible at the NcDialog API level. At the application level, there is almost no need for direct interaction with the mouse interface beyond enabling the mouse-input stream because mouse events are interpreted and converted to the equivalent keycodes.
Please see Mouse Configuration for more information.
Test05
======
This dialog demonstrates the use of the Billboard-class user interface control. Billboard controls are read-only objects from the user’s point-of-view; however, they have a rich programatic interface that allows the application programmer a variety of ways to present and to dynamically update information the user may need.
This is a rather complex test because it exercises all facets of the Billboard class, but with some study, you will discover the full range of Billboard-class functionality.
Please see Billboard Controls for more information.
Test06
======
This dialog uses all the standard user interface controls to demonstrate how the NcDialog API may be used to write an application in an RTL (Right-to-Left) language.
RTL-language applications are generally quite difficult to implement because computers are designed from the ground up for LTR (Left-to-Right) languages. However, the NcDialog API is build around the idea that everyone, regardless of their native language, should have access to applications that provide a comfortable and enjoyable computing experience.
All data output methods (see NcDialog Display Output),
all NcDialog control objects (see Using Dialog Controls),
and most configuration options (see Multi-language Support),
and formatting methods (see gString Text Tool),
include direct support for RTL languages.(Mouse support is enabled within this dialog.)
Test07
======
This dialog provides an over-the-top stress test for multithreading in an NcDialog-based application. While no real-world application would simultaneously produce so much input/output from so many execution threads, we are happy to report that beyond all our initial expectations, thread-safe operation is bedrock solid. Check it out! :-)
For more information on multithreading, please see Multi-threading.
Test08
======
This dialog demonstrates the procdure and options for temporarily putting the NCurses Engine to sleep and returning to the command line. Traditionally, this operation is called a ’shell-out’.
One of the great strengths of a console application is its direct access to all the system’s command-line utilities.
Take that, you simpering, sanctimonious GUI mavens!The NcDialog API provides tools for easy access to these utilities, and the Shell-out operation is at the top of the list.
Please see ShellOut method for more information.
Test09
======
This dialog demonstrates the functionality and options of the Progress Bar widget. The test dialog creates a Progbar-class object for tracking the progress of some application-level activity, either manually or independently through an optional secondary execution thread.
Please see Progress Bar for further details.
Test10
======
This is a container for miscellaneous tests to support new NcDialog API functionality as it is created. The interface is implemented as a menu of the new tests in no particular order.
- Pinwheel Widget, describes the functionality of the Pinwheel class which may be used to visually indicate that the application is busy.
- Chart Widget, describes the functionality of the Chart class which is used to format and display data sets, either as various standard bar charts or as a Cartesian coordinate chart.
- Slider Controls, displays working examples of the new (2021) dctSLIDER user-interface control type. The examples show both vertical and horizontal sliders in various sizes and color combinations.
'About' Dialog
==============
’Help About’ sub-dialog providing application info to the user.
See example ’About’ dialog in previous chapter, see Dialog1 App.
Next: Dialogx App, Previous: Dialog4 App, Up: Test Applications [Contents][Index]
In addition to the common options, the following are defined for this application.
NOTE: The ncurses(w) library, when it is running, redirects the standard-output stream; therefore, the NCurses Engine is not running during this test.
Sub-options:
Examples: ./Dialogw -w // use locale from environment ./Dialogw -wl // use locale from environment ./Dialogw -wl wo_SN.utf8 // use the specified locale ./Dialogw -wn // use the 'default' (C language) locale ./Dialogw -wh // display help for this test
IMPORTANT NOTE: To function properly, this test requires a locale that supports UTF-8 character encoding. Run the command: 'locale -a' for a complete list of locales available on your system.
The Dialogw test application performs many of the same tests found in the other test apps, but performs the tests with a variety of languages.
While your author make no claim of true multilingual competence, the example code at least verifies that the NcDialog API can smoothy handle your choice of language(s).
In addition to internationalization within NcDialog-based applications, Dialogw exercises:
Test01
======
This test writes multi-language, multi-colored text directly to the terminal window using the ’ncursesw’ C-language library primitives.
Don’t worry — your application doesn’t need to know anything about these horrible little beasts. We exercise them here only to be sure they are reliable.
Test02
======
This test writes to the terminal window using the same data set as Test01, but it uses the NCurses-class output methods instead of the primitive C functions.
Test03
======
This test uses the same data set as Test01 and Test02, but writes the data into an NcWindow-class meta-layer window. The NcWindow class is the parent class for all the NcDialog-class objects, but lacks the sophistication of its descendants.
Test04
======
This test uses the same data set as the first three tests, but writes the data into a real NcDialog-class dialog window.
Test05
======
This dialog implements an edge-detection test to verify that the output methods can properly detect the limits of the dialog window. The NcDialog output methods truncate the output at the window edge to retain control over formatting.
In contrast, the ’ncursesw’ C-language library primitives all wrap the text output to the next line when the edge of the window is reached; however, this produces surprisingly ugly and unplanned-looking output.
Test06
======
This test is actually a whole suite of NcDialog windows which contain examples for all the gString-class data-analysis and text formatting methods.
gString is our own implementation for producing well-formatted output of text in any language. The gString class is a compromise between the full internationalization power of Glib::ustring and the meaningless garbage that is the C++ std::string and std::wstring classes. Please see gString Text Tool for more information.
Test07
======
This test contains a collection of the working examples that are used within this document, the NcDialog API User’s Guide. The examples are in no particular order, and are added as we update the documentation.
Individual examples may be selected from the Dropdown-class user interface control which conveniently expands each time a new test is added, BUT without taking up any additional display space. Please see Dropdown Controls for more information on packing a virtually-unlimited number of selections into a limited amout of display space.
Test08
======
This dialog tests Radiobutton and Textbox control titles, labels and contents in both English and Chinese. Note that the Chinese language is used heavily during testing because the characters are two(2) columns wide. This verifies that the formatting routines are aware not only of character counts, but also column counts.
Test09
======
This dialog is a traveller. You can move the entire dialog window anywhere within the terminal window. The dialog contains at least one instance of each user interface control type, which allows for verification of the dialog’s save-and-restore methods.
Please see MoveWin method for additional information.
Test10
======
This dialog tests multi-language text input using an IME (Input Method Editor) such as ’iBus’, ’scim’ or whatever IME you normally use for non-English input.
Please see Textbox Controls for information on getting text input from the user.
Please see Introduction to gString for more information on multi-language support.If the “wl-clipboard” (Wayland Clipboard) utilities are installed on your system, then Test10 establishes communications between the application’s Textbox controls and the system clipboard, enabling full copy/cut/paste functionality. If the “wl-clipboard” utilities are not installed on your system, copy/cut/paste operations are available only among the dialog window’s local Textbox controls.
Please see Clipboard Interface for a discussion of application access to the system clipboard.
Please see Local NcDialog Clipboard for a discussion of the internal application clipboard.
'About' Dialog
==============
’Help About’ sub-dialog providing application info to the user.
See example ’About’ dialog in previous chapter, see Dialog1 App.
Next: Keymap App, Previous: Dialogw App, Up: Test Applications [Contents][Index]
The Dialogx test application is designed to exercise both the NcDialog API’s Local Clipboard and the system clipboard, as well as the communications channel between the two.
Please see Local NcDialog Clipboard for more information.
Please note that the current release of the API implements access only to the two standard Wayland clipboards. Please see Wayland Clipboard for a full description of the Wayland interface. |
The design of the Dialogx application differs substantially from the other NcDialog API test applications. The primary controls defined for the application are a group of four(4) Textbox controls, two single-line controls and two multi-line controls. Radiobutton controls enable/disable various test options and Pushbutton controls execute various tests.
Available command-line options configure the application for a number of different test scenarios.
Developer’s Note: While Software Sam reads a bit of Yiddish,
he is inexperienced with RTL languages in general, so during development,
most testing was done by simply writing LTR data backward into the
RTL fields. If you are fluent in an RTL language, please post us a note
about your experiences in testing copy-and-paste operations for RTL data.
See Technical Support.
Right-justified fields are primarily for numeric input; however, for this test, all printing characters are allowed in the field.
If the system clipboard is inaccessible during application startup, a warning will be displayed.
┌───────────┤ Warning! Warning! ├────────────┐ │ │ │ Unable to establish a connection with the │ │ Wayland clipboard. │ │ The most likely cause of failure would be │ │ that the "wl-copy" and "wl-paste" utilities │ │ are not installed or are out-of-date. Try: │ │ sudo dnf install 'wl-clipboard' │ │ │ │ Continuing with NcDialog local clipboard only.│ │ │ │ OK │ └───────────────────────────────────────────────┘
The application is designed to test copy/cut/paste operations both for the local NcDialog API clipboard and for the GNOME/Wayland clipboard.
These controls will accept all printing characters, but will reject all control characters except ‘newline’.
The NcDialog API allows any key combination not otherwise assigned
to a function to be used for the cut-and-paste operations, however
this application binds the most familiar key combinations to these
operations:
Copy CTRL+C
Cut CTRL+X
Paste CTRL+V
Select All CTRL+A
Select Leftward SHIFT+LeftArrow
Select Rightward SHIFT+RightArrow
Please see clipboard keycodes for details on binding keycodes
to cut-and-paste operations.
Additional messages to the Billboard control are generated by the
application methods:
ClearClipboard() (CLEAR Pushbutton)
ReportFormats() (REPORT Pushbutton)
TestConnection() (TEST Pushbutton)
ReinitWaylandCB() (REINIT Pushbutton)
to indicate the status of those operations.
Please see Wayland Clipboard for a discussion of the Wayland clipboards. Please see Local NcDialog Clipboard for a discussion of the local clipboard.
The “Wayland Clipboard Active” button is set if communications with the system clipboard were established on application startup.
The “Overstrike Mode” button reflects the current state of the 'INSERT' key, (Insert-Mode or Overstrike-Mode) for writing data into the Textbox controls.
Within a given application, it is likely that only one of these text formats will be used, but because this is a test application, all three formats may be exercised.
Technical Note: Although the application may communicate using any combination of these text encodings, all direct communication between the WaylandCB class and the Wayland clipboard uses UTF-8 encoding which is the default encoding for all GNU/Linux platforms. MIME Type: "text/plain;charset=UTF-8"
Please see Wayland Clipboard for further information.
Previous: Dialogx App, Up: Test Applications [Contents][Index]
The ‘Keymap’ utility is used to generate a keycode map for key combinations that are typically system-specific.
Keymap Utility Documentation Keymap Introduction Using the Keymap Utility Invoking Keymap Keymap Main Menu Running a Test Sequence Integrate Key Definitions
During development, always test your NcDialogAPI-based applications to verify that the keycodes used are actually available to your application and that the key-combinations produce the expected result. This testing can be done using the “Dialog2” test application, test #5 (see Dialog2 App). ./Dialog2 -5
If keycodes appear to be different from what the API is expecting, run the “Keymap” application to get a detailed report on the keycodes which do not match the defaults. These key combinations fall into three general categories:
The basic keys in these groups when combined with the key modifiers 'Alt' 'Ctrl' and 'Shift' yield variable keycodes (or no translation) based on several factors such as:
The “default” keycode definitions included with the NcDialogAPI are generated based on U.S. English keyboard hardware (with numeric keypad), and with the following software configuration. These defaults may be updated when there is a significant change in any of these packages.
_______________________________________________________________________
The set of default keycode definitions, generated for version 0.0.31
of the NcDialogAPI was based upon the following system configuration.
The keycode map generated under this configuration is included in the
current release as "NCursesKeyDef(F30).hpp".
- Fedora Linux : v:30
- ncurses C library: v:6.1.20180923
- GNOME terminal : v:3.32.2
- Konsole : v:19.04.2
- XTerm : v:334-2.fc30
- terminfo database: 01-Feb-2019
Technical Note: The implementation of the keyboard’s left-side ALT key when used in combination with other keys produces the expected output. However, by default the keyboard’s right-side ALT key is configured as the AltGr (ALT + Grapheme) key. Depending on the “locale” specified in your system configuration, this key is used in combination with other keys to produce non-ASCII symbols or non-English graphemes (characters, meta-characters and ideographs). If desired, the right-side ALT key may be reconfigured to mirror the functionality of the left-side ALT key. Please refer to your system documentation for further details. |
Keymap, unlike the other test/demonstration applications distributed with the NcDialogAPI, does not use a dialog-based user interface. Instead, it uses a low-level NCurses-class window (see OutputStreamScrolling method) to emulate a generic terminal window, except with full control over cursor positioning and text color attributes. This ensures that the API has minimal effect on the reported keycodes and their associated raw escape sequences.
Authors Note: We admit that the user interface for this application is primitive,
and we are sorry about that, but the functionality is also very simple,
so a sophisticated user interface did not seem like a good use of our time.
很抱歉成为这样的黑客。
–t Lookup table generation.Generate a C++ header file using the default keycodes and escape sequence data.
The name of this header file is 'NCursesKeyDef_auto.hpp'. It will be “#include’d” in the header “NCursesKeyDef.hpp” and it provides alternate keycode definitions for the NcDialogAPI.
Custom versions of the header file for specific system configurations may be generated from within the Keymap application (see below).
–b Brief output mode.The NcDialogAPI includes three tables containing the human-readable versions of the keycode names. For example: nckAINSERT (Alt+Insert). Two of these tables contain stable data. The third table contains keycode names corresponding to the key combinations generated dynamically by the “Keymap” application.
The 't' option generates a copy of this translation table which corresponds to the test results captured by the application. If specified, the table will be created immediately after the C++ header file is generated. Note that the table will only be useful if all tests are complete (or if generating a header file with all default values).
After the table is created, it must then be manually inserted into 'TransTable2' which is located in the 'NcKey.cpp' source code module. This table is used by 'Dialog2, test #5' to interactively report keycodes.
While it is not technically necessary to update this translation table, it is beneficial to keep the table synchronized with the keycode definitions. This is because the Dialog2 diagnostic program and any applications that display the keycode names (see our ‘FileMangler’ application for example) should be able to report accurate keycode names.
–p Pause for diagnostic data.The 'Brief' mode is used for casual testing and requires only one keypress for each test, as opposed to 'Standard' mode which requires two keypresses for each test and which produces raw escape sequence data as part of the output.
It is recommended that Brief mode not be used when creating a full set of test data.
––version Version and copyright message.Before the main application opens, certain start-up diagnostic messages are displayed in the console window. Normally, it is unnecessary to read these messages, but if the application is not behaving as you think it should on a given system, pausing the application for a few seconds during start-up may provide an indication of the corrective action needed.
––help (or –h) Help for application.Display the application version number and the basic copyright notice.
Display a list of available command-line options.
All commands are single-character commands.
This file may be generated with all default values by invoking “keymap” with the ’g’ option: keymap -g
Alternatively, the file may be generated after all keycodes have been interactively tested.
Note: While the file may also be generated using data from incomplete testing of the keycodes, the resulting keycode definitions may not be reliable.
If a key combination remains untested, either because it was captured by
the system or because the test was skipped, then the default keycode and
escape sequence for that record will be used.
If such errors occur during testing please consult the \"keymap\" log file
for details; then, disable as many of the system \"accelerator keys\" as
possible and run the tests again.
The session log records all keycode tests performed during the current session. The log is written to a temporary file which is deleted when the application closes.
The log is viewed by invoking the “less” utility.
To save the log in the current working directory: After the view closes,
answer 'y' when prompted to save; then, when the Keymap
application exits, the log file will be moved to the current working
directory with the name:
Keymap.log
Please note that the log file uses embedded ANSI color sequences to
distinguish the different types of test results. For this reason, when
viewing the log outside the Keymap application, use the “less”
utility and invoke using the '-R' option:
less -R Keymap.log
After selecting a keycode test group, a prompt will be displayed for each key combination to be pressed.
There are two response modes for testing:
Three(3) special user-interface keys are defined:
When testing is complete, a summary report will be displayed.
To integrate new keycode definitions into the NcDialogAPI source code, one source file must be update and the API library “NcDialog.a” must be recompiled.
A copy of this file, using default keycode definitions is embedded within the NcDialogAPI header file: \"NCursesKeyDef.hpp\" which defines the keyboard keycodes available within the terminal window (gnome-terminal, konsole, xterm, etc.).
The default key map was generated on a clean Fedora30 system with: U.S. English keyboard (with numeric keypad) ncurses C library: v:6.1.20180923 GNOME terminal : v:3.32.2 and Konsole : v:19.04.2 and XTerm : v:334-2.fc30 (2019-09-28)
For systems which report non-default keycode definitions during testing, a customized version of this file may be included within the “NCursesKeyDef.hpp” header file. The “#include” statement is under a conditional compilation flag as shown below which allows for easily switching between default and custom keycodes.
Next: User Interface Loop, Previous: Test Applications, Up: Application Examples [Contents][Index]
The ’Sandbox’ concept provides a low-stress, low-effort, low-consequence environment for performing quick testing.
For each new control you add to the dialog, just add a bit of code after return from the control’s ’Edit’ method to handle the user’s input. See the example just below the call to the EditPushbutton( Info ); method.
//* Interact with user * 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 ) // arrived via hotkey Info.HotData2Primary () ; // unpack the data else icIndex = dp->EditPushbutton ( Info ) ; if ( Info.dataMod != false ) { if ( Info.ctrlIndex == T1donePB ) done = true ; } } else if ( ic[icIndex].type == dctTEXTBOX ) { if ( Info.viaHotkey ) // arrived via hotkey Info.viaHotkey = false ; // ignore hotkey data icIndex = dp->EditTextbox ( Info ) ; } else if ( ic[icIndex].type == dctBILLBOARD ) { if ( Info.viaHotkey ) // arrived via hotkey Info.viaHotkey = false ; // ignore hotkey data icIndex = dp->EditBillboard ( Info ) ; } else if ( ic[icIndex].type == dctRADIOBUTTON ) { if ( Info.viaHotkey ) // arrived via hotkey Info.HotData2Primary () ; // unpack the data else icIndex = dp->EditRadiobutton ( Info ) ; } else if ( ic[icIndex].type == dctSCROLLBOX ) { if ( Info.viaHotkey ) // arrived via hotkey Info.viaHotkey = false ; // ignore hotkey data icIndex = dp->EditScrollbox ( Info ) ; } else if ( ic[icIndex].type == dctDROPDOWN ) { if ( Info.viaHotkey ) // arrived via hotkey Info.viaHotkey = false ; // ignore hotkey data icIndex = dp->EditDropdown ( Info ) ; } else if ( ic[icIndex].type == dctMENUWIN ) { if ( Info.viaHotkey ) // arrived via hotkey Info.viaHotkey = false ; // ignore hotkey data icIndex = dp->EditMenuwin ( Info ) ; } else if ( ic[icIndex].type == dctSCROLLEXT ) { if ( Info.viaHotkey ) // arrived via hotkey Info.viaHotkey = false ; // ignore hotkey data icIndex = dp->EditScrollext ( Info ) ; } else if ( ic[icIndex].type == dctSPINNER ) { if ( Info.viaHotkey ) // arrived via hotkey Info.viaHotkey = false ; // ignore hotkey data icIndex = dp->EditSpinner ( Info ) ; } //* Move input focus to next/previous control.* if ( done == false && Info.viaHotkey == false ) { if ( Info.keyIn == nckSTAB ) icIndex = dp->PrevControl () ; else icIndex = dp->NextControl () ; } } // while()
Next: Multi-threading, Previous: Sandbox, Up: Application Examples [Contents][Index]
The user interface loop designates which control object currently has the input focus and determines what happens when the user issues a command or provides information via that control object.
The ’input focus’ is the target of any keyboard data received from the user. The target of this focus will be one of the user interface control objects defined for the dialog.
It is important to note that little or no input is directly capured within the user input loop. All (or nearly all) keyboard or mouse input is captured and processed by the user-input method for the type of control which currently has the input focus. That input is returned to the main loop in a ’uiInfo-class’ object when the user requests that the input focus be moved to another control, then the application can decide how to use that information.
Each defined control type has an associated user-input method:
These methods interact with the user, gathering information and then place the results of the edit in the specified uiInfo-class object. Please see uiInfo class for details on the data returned by the user-input methods.
The return value for these methods is the index of the control which currently has the input focus.
As an example, let’s look at a typical input loop. This example is somewhat simplified for clarity.
The application’s main loop can retrieve information about user activity
while the user is interacting with the control object. This is done by
specifying a callback method which is called every time a keyboard or
mouse event occurs within the user-input method.
For further information on callbacks, please see EstablishCallback method.
A typical callback method monitors the contents of one or more control objects while the user is in the process of modifying those contents. Thus, optional and immediate action can be taken, depending on what the user is doing.
For a simple callback example, please see the Dialog4 test application, Test05. The callback method ’btControlUpdate’ displays context-sensitive help to the user depending on the active control object. It also monitors the keyboard input stream for special characters which the control objects’ edit methods are not able to handle. This method is located in the BillboardTest.cpp source module.
Next: Tabbed Dialogs, Previous: User Interface Loop, Up: Application Examples [Contents][Index]
While the NcDialog API does not use multi-threaded execution internally, it is fully prepared for thread-safe operation within applications that do.
Many inexperienced programmers avoid multithreading because it requires more effort and care during development and testing, but in our view, this reluctance is often a mistake.
Launching multiple threads to perform specific tasks within your application not only speeds up execution through multitasking, it also provides a much more responsive user interface.
As an example of how NOT TO write an application, we refer you to the video player ’PowerDVD’(tm) which is often bundled with that other operating system. While PowerDVD’s actual video playback is rather good, it is a single-threaded application, which means that in the case of a disc error, the user may have to wait several seconds (or minutes) after a mouse click or key input before the application responds. There is little wonder why the application is marketed as "free" software. Who would want to pay actual money for an application that ignores you?
In general, if a task may block (go to sleep) or may go into an infinite loop while waiting for a response from some external device, then launch a separate thread to do the job, and if it doesn’t return within a reasonable amount of time, then kill the secondary thread and report failure to the user. While failure is always embarrassing, it is much less embarrassing to intelligently report the nature of the failure, rather than simply going off into some alternate universe without so much as a goodbye.
Quite often, accessing external media or a remote system is mostly a matter of waiting for some mechanical process to finish. For this reason, if there are several items you want to retrieve from the media, then launch a thread for each item. Since they will spend most of their time sleeping anyway, why not do that sleeping in parallel, rather than as a serialized sequence of non-productive naps?
In the following example, we use two(2) threads; one to interact with the user, and the other to asynchronously write data to a Billboard-class user interface control object. This example is somewhat simplified for clarity, but the working code may be found in Test05 of the Dialog4 test application (see BillboardTest.cpp).
void BillboardTest::btInteract ( void ) { bool done = false ; . . . // The main thread creates a secondary thread which will begin // execution in the 'btBreakingNews' method of the parent class. // Note the odd syntax needed to use a member method as the target. // a) The name of the secondary thread is 'BNews'. // b) The first parameter is the address of the target method: // &BillboardTest::btBreakingNews // c) The second parameter is a pointer to the instance of // the parent class: 'this' // d) The third parameter (and any additional parameters) become // the parameters for the call to the target method and are // used to pass information which the new thread can use to // perform its task. In this case, the only parameter is the // address of a flag, 'done' to be monitored, which will signal // the secondary thread when it is time to re-join its parent. thread BNews( &BillboardTest::btBreakingNews, this, &done ) ; // The primary thread now interacts with the user until the // user is ready to exit. while ( ! done ) { . . . if ( ic[icIndex].type == dctPUSHBUTTON ) { icIndex = this->dp->EditPushbutton ( Info ) ; if ( Info.dataMod != false ) { if ( Info.ctrlIndex == btDonePB ) { // user has signalled that it is time to // exit the dialog. (The secondary thread // is monitoring this flag.) done = true ; // Wait for secondary thread to return BNews.join() ; } } } . . . } // while() . . . } //* End btInteract() * // This is home method for the secondary thread. The thread // may call various other methods, but it does not return // from its home method until the primary thread signals // for its return. void BillboardTest::btBreakingNews ( bool quittingTime ) { // Data to be written const short MAX_nIndex = 39 ; const char* bbb_uData[MAX_nIndex] = { " Breaking News ", "Muggles are vastly better educated", "than witches and wizards, fortu- ", "nately, magic compensates nicely. ", " --- ", . . . } ; short nIndex = 1 ; do { if ( ! btBN_Pause ) // (module-scope flag to pause output) { this->dp->Append2Billboard ( btBilbBB, bbb_uData[nIndex++] ) ; if ( nIndex >= MAX_nIndex ) nIndex = ZERO ; } chrono::duration<short, std::milli>aMoment( 950 ) ; this_thread::sleep_for( aMoment ) ; } while ( *quittingTime == false ) ; } //* End btBreakingNews() *
For more complex examples of multithreading, please see Test07 of the Dialog4
test application, or see the source code for our ’FileMangler’ file-management
utility available for download from the website:
See Technical Support.
Next: Creating Widgets, Previous: Multi-threading, Up: Application Examples [Contents][Index]
One of the common ways to present data to the user is through a group of tabbed objects, each of which takes the user to a separate window, page, document or application. In fact, your terminal window or browser relies heavily on this construct to help reduce clutter on your desktop.
The NcDialog API supports easy creation of Tabbed Dialog stacks.
What follows is an overview of how to create a simple, 4-tab stack.
For a more detailed explanation, the working code for this example can
be found in the Dialogw test application, Test07, ’Tabbed Data Presentation’.
Please see HideWin method for information on making a dialog invisible without actually closing it.
In this way, the user sees what appears to be a single, static set of Tabs from which to select any dialog in the stack regardless of which dialog is currently displayed.
The ’Done’ Pushbutton is also defined in the default dialog and passed to the other dialogs. This control is present in each dialog; however, it may be repositioned, resized or renamed by the dialog according to particular need, (but such changes should be small enough that they won’t confuse the user).
When adding controls special to a dialog window, give particular attention in your user-interface loop to indexing of basic versus customized arrays.
Note that for demonstration purposes, we define different types of controls for each individual dialog. However, keep in mind that users are simple creatures and need consistency wherever it is possible to provide it.
Of course, Hotkeys can be defined for additional controls in the different dialogs so long as they don’t interfere with the hotkeys for the Tabs.
Please see Select Control via Hotkey for more information on defining and using Hotkeys.
Disclaimer:
Software Sam is not fluent in ANY language, not even his native one,
so if a translation offends you, please post us a better one. :-)
Next: Multi-language Support, Previous: Tabbed Dialogs, Up: Application Examples [Contents][Index]
A "widget" is a small, portable, single-function device that can be easily integrated into variety of situations. As a software designer, you may enjoy the challenge of creating these little software tools.
In this chapter we lay out a template for creating widgets based on the NcDialog API. In general, a widget is a device that is too specialized to be implemented within the NcDialog API itself, but which many software designers may find useful.
Our main example is a Progress Bar widget. From time to time. we may add more widgets to this chapter.
Next: Pinwheel Widget, Up: Creating Widgets [Contents][Index]
Progbar Setup Parameters
Progbar Class Methods
Progbar Class Data
Progbar Integration
A Progress Bar is a handy tool for amusing the user while some time-consuming task is underway. It gives the user comfort to know that the operation is still making progress, and is not just stuck in some infinite loop that will eventually require a hard reset of their system.
Progress bars are seen in many everyday activities such as downloading or uploading data through FTP or HTTP connections, or while an operating system is loading.
Our Progress Bar widget is implemented as a small dialog window whose function is to visually indicate the progress of some time-consuming activity that could take anywhere from several seconds to several hours.
The working code for the following discussion is in the Dialog4 test application, Test09 (see Dialog4 App). Please note that this test application and the examples used in this chapter make significant use of multithreading. If you aren’t yet familiar with multithreading, please take this opportunity to become acquainted with the C++ ’thread’ class.
The design criteria for a first-class widget are that it be flexible enough to be adaptable for many uses, but not so flexible that it becomes difficult to use.
In addition, the design must be robust and reliable, and the only way to accomplish this is to control the input.
The Progbar class is instantiated using parameters passed in a pbarInit-class object. pbarInit is a simple class that takes four(4) required parameters, with all optional parameters having functional default values.
The Progbar widget will run quite happily with only the required fields specified, but the optional parameters offer extended functionality.
class pbarInit { public: //* Initialization Constructor * pbarInit ( attr_t dialogColor, attr_t progbarColor, short characterCells, bool horizontalLayout ) ; //** Optional Fields - default values are calculated ** //** and may be updated after instantiation. ** //** - - - - - - - - - - - - - - - - - - - - - - - - ** // Text to display at 0% end of the progress bar // (default: NULL pointer) const char* beginText ; // Text to display at 100% end of the progress bar // (default: NULL pointer) const char* endText ; // Title text: useful for horizontal layout with border only // (ignored for vertical layout) // (default: NULL pointer) const char* titleText ; // Text for optional Pushbutton control (in 'Cancel' mode) // (default: NULL pointer) // if 'enableCancel' flag set, then " Cancel " is default text const char* cancelText ; // Text for optional Pushbutton control (in 'Close' mode) // (default: NULL pointer) // if 'enableClose' flag set, then " Close " is default text const char* closeText ; // Border color (default: same as dialog interior) attr_t borderColor ; // Number of discrete steps across the bar // min: same as 'cells' parameter (default) // max: 'cells * cellDIV' // (cellDIV==number of divisions per cell) // Note that calculating the number of cell divisions per step // requires integer division, so for smooth operation: // ((cells * cellDIV) / steps) // should be an integer value, or to put it another way: // ((cells * cellDIV) % steps) should be ZERO // Example: cells==10, steps==20: // (10 * 8) / 20 == 4 i.e. half cell per step // If the modulus is not ZERO, then the number of steps is // automatically increased as necessary to fill the bar. short steps ; // Optional Pushbutton control. // Both 'Cancel' and 'Close' are the same physical button which // displays 'Cancel' while the operation is in progress, and // displays 'Close' when the operation is complete. // See below for notes on specifying this control. bool enableCancel ; bool enableClose ; // Enable dialog border (default: true) bool border ; // Y offset from terminal origin (default: centered in window) short yOffset ; // X offset from terminal origin (default: centered in window) short xOffset ; // Address of callback method used by the optional secondary // execution thread to monitor progress (default: NULL pointer) // Note that this parameter is required if 'enableCancel' // has been specified. PBMON threadCb ; //** Required Fields are set on instantiation. ** //** - - - - - - - - - - - - - - - - - - - - - - - - ** private: // Dialog interior and text color attr_t dlgColor ; // Color of progress bar (should contrast with interior color) attr_t barColor ; // Number of character cells in progress bar // if 'horiz' , then this is column count // if !'horiz' , then this is row count // min: 1 // maX: size of terminal, however, staying within // the parent dialog is recommended short cells ; // Dialog layout: // 'true' for horizontal layout, or // 'false' for vertical layout bool horiz ; friend class Progbar ;
The interface to the Progbar class is a very simple one, with only a few methods.
Input : init : an initialized instance of the pbarInit class containing setup parameters Returns: implicitly returns a pointer to object
Constructor. See discription of the pbarInit class above.
Input : none Returns: 'true' if successful 'false' if unable to open the window due to invalid setup a) dimension extends beyond terminal window boundary b) memory-allocation error (unlikely)
Make the Progbar window visible.
If an auto-update thread was specified, but the Pushbutton control was not specified, then the auto-update thread is launched here.
Input : abort : (optional, NULL pointer by default) pointer to a boolean flag monitored during the operation. If set ('true') it indicates that the thread should immediately return to caller. Returns: percentage completion: 100 : operation complete 0-99 : user aborted operation before completion OR calling thread signalled abort ERR : method called inappropriately: a) dialog not open b) no auto-update thread established c) no Pushbutton control defined, OR window too small to include controls
If you configure the Progbar widget to use the optional Pushbutton user-interface control, AND if you define an auto-update callback method for the secondary execution thread, then call this method to interact directly with the user.
The auto-update thread is launched, and then user input is monitored. Control returns to the main application when either the operation being tracked has completed, OR if the user signals an abort of the operation by selecting the ’Cancel’ Pushbutton, OR if calling thread sets the optional ’abort’ flag.
Note that the acceptable user input to select the Pushbutton include:
the ENTER key, SPACE key, ESCAPE key, or a mouse click if your
application has enabled the mouse interface.
(See meEnableStableMouse method.)
Input : none Returns: percentage of steps completed (integer value: 0 - 100)
Move the progress bar forward by one step.
A ’step’ is a discrete increment in the length (height) of the progress-indicator bar. By default, one step equals one character cell, but this is adjustable during setup.
If all steps have been previously completed, then this method has no effect.
Input : inc : number of steps to increment or decrement the progress indicator Returns: percentage of steps completed (integer value: 0 - 100)
Move the progress bar forward or backward by the specified number of steps.
Sometimes an operation in progress will skip some unnecessary step, or will need to go back to a previous step, or may need to restart the operation from the beginning. Call this method to fast-forward or to rewind the progress indicator.
Any request to move beyond the defined step limits will be ignored.
Input : none Returns: nothing
Refresh (redraw) the window. Call ’refresh’ if activity in the parent dialog has potentially obscured all or part of the Progbar object window.
Note that the window is refreshed automatically with every call to the ’update’ methods.
It is generally good practice to keep all data members of a widget private; that is, only the class methods have access to the class data. This makes debugging, error checking and overall performance smoother and faster.
Although the data are private, a quick peek at the kind of data needed to implement a widget can be instructive.
One of the most important design decisions when creating a widget class is which methods to make public and which to keep private. These decisions protect your data and your functionality, as well as determining the complexity of the user interface.
Most public methods of a class call one or more private methods to actually accomplish the requested task. Because this is a simple class, the number of private methods is small.
Note also the contrast between the descriptive names of public methods and the terse, simple names given to our private methods. The NcDialog API, for instance has descriptive names like ’GetSpinnerValue’ for its public methods to make using the API as self-explanatory as possible. For a large project such as the NcDialog API (27,000 lines of code) , even the private methods have descriptve names; however, for the simple Progbar class (850 lines), we can afford to be a bit more relaxed about naming conventions.
The secondary thread has a very simple job, it periodically requests information from the callback method which lives in application space. For each call, it provides the callback method with the number of steps remaining for the operation.
The interval between information requests is nominally 200 milliseconds, which is fast enough to be responsive, but doesn’t eat too many of your CPU cycles.
The value returned by the callback is the number of steps to increment or decrement the progress indicator bar. Note that if the callback method returns a ZERO value, it indicates that no progress has been made since the previous call.
The secondary thread terminates in response to the following:
Note that this kind of calculation is tedious and error prone, so remember: the number of character cells specified determines the basic width (height) of the Progbar dialog, so specify a number of character cells large enough to fit all defined text and the width (height) of the Pushbutton control.
Our experience is that retaining the best of our debugging code (conditionally compiled), even after the product has shipped, allows for easy review of and enhancements to our code base. Highly recommended coding practice!
All data members of the Progbar class are private data.
Editorial Note: For all the C-language programmers in the crowd who have dozens of global variables in you applications because it’s "easier," that is why your applications crash randomly and without warning. PROTECT YOUR DATA!
Most of the data members are self-explanatory, but a discussion of a few critical items may be helpful.
This pointer is tested by the destructor, and if memory has been allocated to it, the destructor releases it.
Because there is a finite period of time between instantiation of our class object and actually opening the dialog for use, we need to know whether the application can safely call our public methods. For instance, if the application called the public ’update’ method BEFORE calling ’open’, all kinds of nastiness would occur. Guard your borders!
For instance, if the application requests the ’Cancel’ Pushbutton control, but the defined dialog is too small to hold it, then we would set this flag to indicate that our working environment has gone all gǎo zále tiān fān.
Integration of the Progbar widget into your application requires the following steps:
Create the Progbar object without user-interface controls and without specifying an auto-update callback method.
This is the most straightforward option. From your application’s main user-interface loop, call an application method which will directly monitor the progress of the activity and then call the Progbar-class ’update’ method periodically to update the Progbar display. When finished, return to your main user-interface loop, close (delete) the Progbar object and continue with your application.
Create the Progbar object with an auto-update callback method specified and with the optional Pushbutton user-interface control (either single- or dual-function mode).
This is the recommended option. After opening the Progbar dialog, call the ’UserInteract’ method, so user input goes directly to the Progbar’s internally defined Pushbutton control.
The Progbar object will create a secondary thread to periodically access the specified callback method until the operation completes (or until user aborts operation).
Your application will effectively be asleep until this method returns.
However, your application could create a new thread with which to call the ’UserInteract’ method so that the application can continue to do work in the background. If you do this, there are some technical issues related to display updates - which we leave as an exercise in program logic.
Notes on specifying the Pushbutton user-interface control:
Create the Progbar object with an auto-update callback method specified, but without user-interface controls.
The Progbar object will create a secondary thread to periodically access the specified callback method until the operation completes (or until user aborts operation).
Your main application thread can continue to interact with the user if the Progbar object is not obscuring any active user-interface controls in your application. For instance, our test application, Dialog4, Test09 does this, but in a real-world application this is rather dangerous because users can often be very un-aware and may do something you aren’t anticipating.
Under controlled circumstances, however, letting the Progbar continue while the application does something else can be quite useful, although it is recommended that the user not have access to your application’s user-interface controls during this time.
The test dialog shown below provides a range of options for setting the call parameters to create a Progbar widget and then to track its function throughout the progress cycle. The first screenshot shows the Progbar widget in horizontal layout, and the second screenshot shows the vertical layout.
Note that in the finished version of this test, we limit the the range of the call parameters somewhat to keep the widget within the parent dialog’s display area. Note also that for testing purposes, we allow some invalid parameter combinations, which will not keep the widget from opening, but will result in a "PARM ERROR!" message.
For details, see the source code for test application Dialog4, Test09.
When you configure the Progbar widget for passive input, you will need a method that polls the operation in progress and calls the 'Progbar::update' method at appropriate intervals to show the progress of the operation to the user.
Here, we are recovering data from a damaged DVD disc. Because this operation could take up to an hour per gigabyte, we update our report to the user at intervals. This example is adapted from our ’DvdRepair’ utility.
Starting with the above example, we can modify the Progbar setup parameters slightly to implement the dialog with a auto-update callback method and a ’Cancel’ Pushbutton.
Because we need to keep processing data while the auto-update is running, we split our application thread, sending one thread to the ’Progbar::UserInteract’ method, while the other thread reads our damaged DVD disc.
The primary differences between this example and the previous one:
To do this, we specify a local member method as the target for the user-interface thread and pass a pointer to a local flag which acts as a semaphore between the processing thread and the user-interface thread.
Next: Chart Widget, Previous: Progress Bar, Up: Creating Widgets [Contents][Index]
A pinwheel is a child’s toy which is a fan-shaped wheel attached to a stick by a pin which acts as an axis. As the breeze blows against the wheel, it spins around the axis.
The Pinwheel class implements a visualization of that pinwheel, spinning as the application performs some task in the background. This indicates “Please Wait”, so the user doesn’t get nervous or frustrated. This is conceptually similar to the Progress Bar presented in the previous chapter, but rather than indicating the percentage of a task completed, the Pinwheel simply displays color and motion. (Users are even more simple that a child with a pinwheel toy.)
Pinwheels and similar visual indicators are seen in many visual styles, and are most commonly found when a local computer is waiting for data download or upload from a remote server.
Pinwheels rely on the multi-threading capabilities of the system.
A new thread is created to manage the Pinwheel motion while the main
thread continues with the task at hand. Management of the new execution
thread is handled entirely within the Pinwheel class. The only
requirement is that the application be linked with the pthread library.
Please see Dialog4 App for a discussion of linking this library
into your application.
The Pinwheel class is lightweight, and is implemented in Pinwheel.hpp. The test code for the class consists of various methods in the PinwheelTest.cpp source module of the Dialog4 test application (Test #10).
Adding a Pinwheel-class object is a simple operation:
— Create an instance of the Pinwheel class.
— Launch a thread to manage the visual display.
— Deactivate the thread when finished with the underlying task.
— Delete the class instance.
Note that the test code in PinwheelTest.cpp is vastly more complex than anything a real-world application would need. This is because the test implements multiple Pinwheel objects to demonstrate all possible combinations of setup parameters.
The visual styles for the Pinwheel class are defined in an enumerated type:
enum PinwheelStyle : short { pwsWheelC = ZERO, // display travels in a clockwise circle pwsWheelA, // display travels in an anti-clockwise circle pwsVertiU, // display grows Upward, from bottom-to-top pwsVertiD, // display grows Downward, from top-to-bottom pwsHorizR, // display grows Rightward, from left-to-right pwsHorizL, // display grows Leftward, from right-to-left } ;
These styles may be customized in various ways.
Study the selection and sequencing of foreground/background color attributes used in the Pinwheel test code. Refer to the Dialog4 test application, PinwheelTest.cpp module, PinwheelTest::AdvancedAttrInit() method.
To create a Pinwheel object, use one of the full-initialization constructors to define all the operational parameters. There are three versions of the full-initialization constructor. The first two have exactly the same structure and functionality except for the way the Y/X position is specified.
The third constructor takes as its only argument an initialized PinwheelInit-class object. The names of the PinwheelInit class data members are consistent with argument names of the other constructors. The ’ncdPtr’ must contain a valid NcDialog pointer. Initialization of other data members are optional, but STRONGLY recommended.
Pinwheel ( NcDialog *ncdPtr, PinwheelStyle dispStyle, const attr_t *colorPtr, short colorCount, const winPos& yxPos, short msTick, short rows, short cols, bool *exitFlag, wchar_t origChar, attr_t origAttr ); Pinwheel ( NcDialog *ncdPtr, PinwheelStyle dispStyle, const attr_t *colorPtr, short colorCount, short yPos, short xPos, short msTick, short rows, short cols, bool *exitFlag, wchar_t origChar, attr_t origAttr ); Pinwheel ( const PinwheelInit& pwInit ) ;
The PinwheelInit class provides the same parameters as the the individual parameters of the other constructors:
For all constructors, the parameters provide the following information.
After instantiation, each of these parameters may be modified individually
via a call to the corresponding 'setXXX' method described in the
following section: see Public Methods of the Pinwheel Class.
Validation: This is assumed to be a valid pointer.
If this is not a valid NcDialog pointer, or if the window
is not open when the child thread is launched, the likely
result would be an embarrassing application crash.
Validation: If the specied value is not a member of the PinwheelStyle enumerated type, the default value (pwsWheelC) will be used.
The data of this array are not used directly. Instead, it is copied to a dynamically-allocated array of ‘attr_t’ values within the Pinwheel object.
Validation: If this is a NULL pointer, then the default color scheme (single-color, terminal default) will be used.
Validation: If this value is less-than-or-equal-to ZERO, then the default color scheme (single-color, terminal default) will be used.
Validation: The origin must specify a Y/X offset within the target dialog window. Note that Y/X coordinates are zero-based. If either value is beyond the edge of the dialog window, the position is adjusted to bring it within the dialog window.
Validation: The specified value must fall between ‘minTick’ and ‘maxTick’, inclusive. As of this writing, ‘minTick’ is defined as 50 milliseconds (0.05 seconds), and ‘maxTick’ is defined as 5000 milliseconds (5.0 seconds). If the value is out-of-range, the value ‘dfltTick’, currently 500 milliseconds (0.5 seconds) will be used.
Validation: The Pinwheel object must stay within the target dialog window. If the height of the object would cause it to extend beyond the window, the number of rows is reduced to ensure that the object lies entirely within the dialog window.
Validation: The Pinwheel object must stay within the target dialog window. If the width of the object would cause it to extend beyond the window, the number of columns is reduced to ensure that the object lies entirely within the dialog window.
Validation: If the pointer is a non-NULL value, it is assumed to
point to a boolean target in application space that is initially reset
(‘false’).
If ‘exitFlag’ is a NULL pointer, then an internal boolean
value will be the target of the pointer. If the internal flag is used,
the ’deactivate’ method must be called to set the flag
which will terminate the loop and set the internal parameters to
a known state.
(See below for a description of the ’deactivate’ method.)
Validation: This character value cannot conveniently be validated, but is assumed to be the Unicode codepoint for a single-column displayable character. If it is not a valid character, then your clue will be an ugly dialog window after the object is terminated.
Validation: As with ‘origChar’, this value cannot
conveniently be validated, but is assumed to be a valid NcDialog API
color-attribute code.
Example: nc.blR (blue with reversed foreground/background).
Again, if this is not a valid color attribute, then your clue will
be an ugly dialog window after the object is terminated.
The Pinwheel interface is quite simple. In addition to the usual C++ constructors and destructor, the child thread may be “launched” or “deactivated” as may times as desired. The current configuration parameters may be retrieved or set as a group, or the parameters may be set individually.
While parameters may be retrieved asynchronously at any time, modifying one or more parameters requires that the object be deactivated before modification, then re-activated after the parameter(s) have been modified. See See Pinwheel Example Code, below.
The full-initialization constructors are described in the previous section. See Pinwheel-class Constructor.
Important Note: The default constructor, (a constructor with no parameters) is private within the Pinwheel class, to prevent creation of a Pinwheel object with invalid setup data.
Pinwheel ( NcDialog *ncdPtr, const winPos& yxPos ) ;
The partial-initialization constructor requires only two parameters:
NcDialog *ncdPtr This is a pointer to an open NcDialog window
in which the Pinwheel object will be displayed.
const winPos& yxPos This specifies the Y/X position in the dialog
window at which the Pinwheel object will be displayed.
Validation: same as for the full-initialization constructors.
This constructor is fully functional, but will execute using default values (which may not be the parameters you want).
This constructor is intended a placeholder to be used during application development, and should be replaced by a full-initialization constructor in the finished application code.
~Pinwheel ( void );
The destructor returns all allocated resources to the system and removes the Pinwheel object from application memory.
For an automatic-variable object:
Pinwheel pw( . . . );
the destructor will be called automatically when the variable goes
out-of-scope.
For a dynamically-allocated object:
Pinwheel *pwPtr = new Pinwheel( . . . );
the destructor will be called when the object is explicity deleted:
delete pwPtr;
If the object is already under the control of an active thread, this call will have no effect, and the existing thread will continue.
The calling thread immediately returns to the main application.
Returns:
’true’ if launch is successful (or object is already active)
’false’ if system calls for thread allocation or thread launch fails.
Important Note: Although the calling application could simply set the application-space flag to terminate execution of the loop, that would not perform the necessary cleanup, consisting of a call to 'join()' which alerts the system that the resources allocated to the child thread are no longer needed. After alerting the system, the Pinwheel object returns its internal parameters to a stable state.
If the object is already inactive, simply perform the necessary clean-up.
Returns:
’true’ if successful (or if object is already inactive)
’false’ if deactivation fails (this is unlikely)
Special Note: The 'colorPtr' value is returned as a NULL pointer to avoid compromising the internal color-attribute array. Similarly, if the 'exitFlag' pointer references the internal loop-control flag, it is returned as a NULL pointer. If 'exitFlag' references an address in the application space, however, then the actual pointer value is returned.
The states of the audible-alert flag and the bidirectional-output flag are not returned as part of this data group, but they may be obtained by calling the ’getAudible’ and ’getBidir’ methods described below.
The audible alert uses the default alert sound set up in the terminal
configuration.
See the NcDialog-class UserAlert method for more information.
Call with ’true’ to enable the beep, or with ’false’ to disable the beep.
Technical Note: Unlike most methods of the Pinwheel class, the ’setAudible( method may be called asynchronously; that is, it is not necessary to deactivate the object before setting or resetting the audible-alert parameter.
Returns the current state of the audible alert:
true if alert is enabled.
false of alert is disabled.
Call with ’true’ to enable bidirectional output, or with ’false’ to disable bidirectional output.
Unidirectional output steps through the sequence from the beginning, and then starts again from the beginning. In contrast, bidirectional output steps forward from the beginning of the sequence, then reverses direction and steps backward toward the beginning of the sequence.
Returns 'true' if modification is successful.
Returns 'false' if child thread is currently active.
This command is recognized only when thread is inactive.
Set 'dispStyle' as one of the following:
pwsWheelC display travels in a clockwise circle
pwsWheelA display travels in an anti-clockwise circle
pwsVertiU display grows Upward, from bottom-to-top
pwsVertiD display grows Downward, from top-to-bottom
pwsHorizR display grows Rightward, from left-to-right
pwsHorizL display grows Leftward, from right-to-left
Returns 'true' if modification is successful.
Returns 'false' if child thread is currently active.
This command is recognized only when thread is inactive.
'colorPtr' is a pointer to an array of color attributes.
'colorCount' is the number of elements in the array.
Returns 'true' if modification is successful.
Returns 'false' if child thread is currently active.
This command is recognized only when thread is inactive.
'yxPos' specifies the offset in the dialog window
'origChar' specifies the obscured character
'origAttr' specifies color attribute for the obscured character
Technical Note: It is assumed that all obscured characters/attributes are the same character and attribute. While this may not be true for multi-cell Pinwheel objects, the design decision is that the Pinwheel object will usually be positioned in an empty area of the dialog window.
Returns 'true' if modification is successful.
Returns 'false' if child thread is currently active.
This command is recognized only when thread is inactive.
'rows' height of the object in rows
'cols' width of the object in columns
The minimum value for each dimension is one (1). The maximum value for each dimension is the available space between the Pinwheel object’s origin (see setPosition() above), and the edge of the dialog window.
Returns 'true' if modification is successful.
Returns 'false' if child thread is currently active.
This command is recognized only when thread is inactive.
'msTick' interval in milliseconds between display updates.
The range of valid values is between “minTick” and
“maxTick”, currently defined as 50ms through 5000ms,
(0.05 seconds through 5.00 seconds), inclusive.
Returns 'true' if modification is successful.
Returns 'false' if child thread is currently active.
This command is recognized only when thread is inactive.
The loop-control flag is a boolean value which is monitored by the Pinwheel control thread to determine when to terminate the loop. The flag is initially reset (’false’). When this flag is set (’true’), the control thread terminates the update loop and stops executing.
The loop-control flag may be a boolean value in the application space, OR the Pinwheel object can reference an internal flag.
'exitFlag' is a pointer to a boolean value in application space, or if a NULL pointer is specified, the internal flag of the Pinwheel object will be used for loop control.
Please refer to the description of the ’deactivate’ method, above for more information about the Pinwheel control loop.
Returns 'true' if modification is successful.
Returns 'false' if child thread is currently active.
This command is recognized only when thread is inactive.
Please refer to the ’setPosition’ method, above for a more practical way of specifying the obscured character/attribute.
'origChar' specifies the obscured character
'origAttr' specifies color attribute for the obscured character
Returns 'true' if modification is successful.
Returns 'false' if child thread is currently active.
This command is recognized only when thread is inactive.
The 'deactivate' parameter specifies whether to force
deactivation of the object before attempting the reset.
'false' If the Pinwheel object is currently active, do not
perform the reset. Returns ’false’ to indicate the error.
'true' If the Pinwheel object is currently active, deactivate
it before performing the reset.
The audible alert, if enabled is disabled.
Bidirectional output, if enabled is disabled.
Returns 'true' if all modifications are successful.
Returns 'false' if child thread is currently active,
but the 'deactivate' argument not set.
This command is recognized only when thread is inactive.
After a successful reset, call the ’launch’ method (see above) to reactivate the object.
winPos pinPos( 14, 10 ); // position in dialog window const short pinCount = pwTicks; // number of colors (one per tick i.e. 8) attr_t pinColors[pinCount] = { nc.grbk, nc.regr, nc.brre, nc.blbr, nc.bmabl, nc.cyma, nc.gycy, nc.bkgy } ; // Define the Pinwheel configuration. PinwheelInit pwi { dlgPtr, // pointer to open NcDialog window pinPos.ypos, // position (offset) in Y pinPos.xpos, // position (offset) in X pwsWheelC, // pinwheel style (spins clockwise) pinColors, // pointer to array of colors pinCount, // number of elements in pinColors[] 500, // interval between ticks (500 ms == 0.5seconds) 1, // rows (object occupies a single character cell) 1, // columns NULL, // use object's internal flag to control the loop L' ', // obscured character (SPACE) nc.blR, // obscured character's color attribute (white-on-blue) } ; // Create an instance of the Pinwheel class. Pinwheel *pwPtr = new Pinwheel( pwi ); // dynamic allocation OR Pinwheel pw( pwi ); // automatic variable // Launch the child thread to manage the object pwPtr->launch(); OR pw.launch(); // Deactivate the child thread pwPtr->deactivate(); OR pw.deactivate(); // Double the tick rate. (divide by 2: 500 / 2 == 250ms) pwi.msTick /= 2; pwPtr->setTickRate( pwi.msTick ); OR pw.setTickRate( pwi.msTick ); // Enable bidirectional display. pwPtr->setBidir( true ); OR pw.setBidir( true ); // Re-launch the Pinwheel object. pwPtr->launch(); OR pw.launch(); // Deactivate and delete the Pinwheel object. pwPtr->deactivate(); delete pwPtr; OR pw.deactivate(); // (automatic variable will be deleted when it goes out-of-scope)
Previous: Pinwheel Widget, Up: Creating Widgets [Contents][Index]
Chart, Overview Chart, Test Program Chart, Defining the Chart Object Chart, Public Methods Chart, Technical Description
The bar chart is a common tool for visualizing data of various kinds. The Chart class implements a highly configurable bar-chart object which can be used to display any set of decimal (floating-point) values. Integer data can be dynamically converted to floating-point for display.
The Chart object is built using the tools of the author’s NcDialog API which provides formatting and display of the Chart-class area as well as displaying the chart data.
The Chart object may be created inside the calling application’s dialog window, or may be launched as an independent dialog window.
There are currently eight(8) types of bar charts defined, plus a Cartesian chart for plotting X/Y data points.
Color attributes may be selected for the chart axes, data bars, axis labels, header/footer/margin text and optional borders.
The range of the data set (maximum bar length) is automatically scaled
to fit within the specified size of the chart. Any reasonable number of
data items (2^30 items) may be displayed, one page at a time, and
the user may shift the data laterally to bring any page into view.
see Chart, User Interface for details.
Three text areas are defined:
Header This is the area above the graph.
Footer This is the area below the graph.
Margin This is the area to the left of the graph.
Each of these areas may be sized independently to hold the desired text.
The test data for these areas are a few paragraph of foolish text which
are designed to test area boundaries. Be aware that text written into
these areas is monitored carefully to prevent it from obscuring the
graph itself.
The next section describes the interactive adjustment of the Chart parameters.
Configuring the Chart class to display the source data in an efficient and appealing way may require some experimentation. To assist with this, the NcDialog API, Dialog4 test application, Test #10 provides a flexible way to adjust each setup parameter.
Parameters are passed to the Chart-class constructor via an initialized ChartDef object. (See Chart, Defining the Chart Object, below for details.) Each major parameter of the Chart class may be adjusted individually to better understand the interaction among parameters.
The ChartTest dialog controls provide access to all the major parameters needed to create the Chart-class object. Details on the way NcDialog controls work is covered in Dialog Control Objects.
The controls of this dialog are arranged on the left side of the dialog, while the right half of the dialog is an open area for use by the Chart object when creating the bar chart (or Cartesian coordinate grid).
Each control is associated with a data member of the ChartDef class which defines the Chart object. The following is a description of each control and the functionality it represents along with a reference to the associated ChartDef member variable(s).
The settings of the various controls are placed into the associated members of the ChartDef object, and the constructor is called.
The specified post-instantiation adjustments are also made during this sequence.
Note that the default constructor for the Chart class is a private method which may not be invoked by an application. This is done to prevent the almost-certain application crash that would occur if the object were created with incomplete setup information.
╔═══╣ Launch Application Help ╠════╗ ║ ║ ║ Please select Help document format.║ ║ ║ ║ INFO HTML CANCEL ║ ╚════════════════════════════════════╝
For the info-reader version of the document, the application is
temporarily put into hibernation mode and the info reader is called:
info -f ../Texinfo/ncdialogapi.info -n 'Chart Widget'
For the HTML version of the document, the application calls the
system’s default browser with the address of the document:
xdg-open "file:///[CWD]Texinfo/ncdialogapi.html#Chart-Widget"
(“CWD” is actually the parent of the Current-Working-Directory.)
These documents are located in the "Texinfo" subdirectory of the NcDialog API.
Chart types with the origin at the corners of the grid are used to display both positive and negative values as a continuous sequence from the minumum value to the maximum value.
Chart types with the origin at the center position in the X direction, Y direction (or both) are used to display positive values on one side of the centered axis and negative values on the other side of the axis.
Please see Chart, Defining the Chart Object, below for
examples of each chart type.
Please see ChartDef, chType.
If the Chart object is drawn in the application’s dialog window, this represents the number of rows reserved in the target dialog.
If the Chart object is drawn in a stand-alone dialog window created
by the Chart object, this represents the number of text rows (including
top and bottom borders) of that dialog window.
Please see ChartDef, rows.
If the Chart object is drawn in the application’s dialog window, this represents the number of columns reserved in the target dialog.
If the Chart object is drawn in a stand-alone dialog window created
by the Chart object, this represents the number of text columns
(including left and right borders) of that dialog window.
Please see ChartDef, cols.
The width of the Footer Area is the full width of the Chart Area.
Chart Area borders, if specified are not included as part
of the Footer Area.
Please see ChartDef, footRows.
The Margin Area is between the left edge of the Chart Area and the left edge of the coordinate grid, and the height of the Margin Area is the height of the grid. The Margin Area does not extend into either the Header or Footer areas.
Chart Area borders, if specified are not included as part
of the Margin Area.
Please see ChartDef, xOffset.
Border “styles” are specified internally as members of the ncLineType enumerated type (excluding ncltHORIZ and ncltVERT) as defined in the NcWindow.hpp module of the NcDialog API.
Please see Line Drawing Characters or run the Dialog2 test
application, Test #8 for examples of the line-drawing styles.
Please see ChartDef, borderStyle.
The dividing line may be positioned on any line of the footer area. An offset of zero(0) will position the divider on the first line of the Footer Area.
Note that if no footer area is defined (footer rows equals zero(0)),
or if the specified offset is out-of-range, the line will not
be drawn. See the “Footer Area Rows” control described
above.
Please see Chart, DrawDivider method.
The height of the header area may be specified directly by the
'yOffset' member of the ChartDef class described below.
For purposes of this test application, however, the height of the
Header Area is automatically set to two, three or four text rows,
depending upon the data which will be written to it.
Please see ChartDef, headText.
Please see ChartDef, yOffset.
Note that vertical bars may not be specified for chart types
and .
Note that horizontal bars may not be specified for chart types
ctCenterLeft and ctCenterRight.
Please see ChartDef, horizBars.
Note that the Cartesian coordinate grid plots the data as X/Y datapoints rather than data bars; therefore, this control does not apply to Cartesian charts.
If desired, a separate color attribute for each data bar may be
specified. This test application provides an array of color
attributes in a repeating pattern which may be used to demonstrate
this option.
Please see ChartDef, attrPtr.
For a discussion of scrolling through the displayed data, please see Chart, ShiftData method.
The test application defines a set of alphabetic keycodes for
the alternate user-interface keycodes.
'f' first page
'l' last page
'n' next page
'p' previous page
'a' scroll forward by one
'a' scroll backward by one
'b' scroll forward by five
'B' scroll backward by five
'c' scroll forward by ten
'C' scroll backward by ten
Note that if the dataset is small enough that all data are
simultaneously displayed for any chart type, calling the
ShiftData method is redundant, and will return immediately
without waiting for user input. Because the Cartesian chart
type always displays the entire dataset simultaneously,
the UI instructions will not be displayed for Cartesian charts.
Please see Chart, User Interface for additional
information.
The design of the chart type indicates whether the alternate color
attribute may be applied. In general, if positive and negative
values are displayed on opposite sides of the axis, then the
alternate attribute applies. These chart types are: ctCenterLeft,
ctCenterRight, ctLowerCenter and ctUpperCenter.
Please see ChartDef, negColor.
This test instructs the application to retrieve these statistics and to display them in the Header Area.
For the test application, both the color attribute and the
datpoint character contrast with those of the existing dataset.
The Alt Datapoint Character test, below may be used to modify
the character used for each dataset.
Please see Chart, OverlayCartesianDataset method.
The dataset used by the test application is laid out as an array of X/Y pairs. This is the default pair ordering. An application may however specify the source data as an array of Y/X pairs, so long as the Chart class is notified that the pair order is reversed. This notification is done by setting the 'horizBars' flag of the ChartDef object. The test application actually uses the same, simple dataset for both pair orderings, which produces a different pattern for each pair ordering.
Important Note: This special meaning for the 'horizBars' flag
applies to the ctCartesian chart type only.
Please see ChartDef, horizBars.
These tests attempt to violate the area boundaries to verify that the positioning and truncation methods are functioning properly.
Each test consists of a series of sub-tests. After each sub-test there is a short pause and a single beep to indicate that the test was successful. If the test fails, a series of three(3) beeps will indicate the error.
The available dataset are:
Internally, the Chart class uses double-precision floating-point values exclusively; however, source data in all the above formats can be automatically converted by the Chart class for use in mapping the data to the coordinate grid.
Note that these datasets may be used with all chart types except the Cartesian chart which uses X/Y coordinate pairs rather that value arrays.
The Chart class presents a wide array of configuration options for customizing the chart display. These options are passed to the Chart-object constructor using a fully-initialized ChartDef object. Because the function of each ChartDef variable and the interaction among variables may be confusing, this section defines each option and describes its use.
The 'dPtr' parameter receives a pointer to the target NcDialog object.
Initializing 'dPtr' to the NULL pointer instructs the Chart object to create its own, independent NcDialog window during instantiation.
If the Chart object is to be drawn in a new, independent dialog window (see 'dPtr' parameter), this parameter specifies the absolute offset in Y from the origin (upper left corner) of the terminal window.
If the Chart object is to be drawn in a new, independent dialog window (see 'dPtr' parameter), this parameter specifies the absolute offset in X from the origin (upper left corner) of the terminal window.
Logically, the value must be large enough to display the coordinate grid, so in practice this value should be at least four(4) rows.
Note that if the Chart object is to be opened in a new, independent dialog window (see 'dPtr' parameter), the available space will be reduced by two(2) rows to accomodate the top and bottom borders of the dialog window.
Logically, the value must be large enough to display the coordinate grid, so in practice this value should be at least twelve(12) columns.
Note that if the Chart object is to be opened in a new, independent dialog window (see 'dPtr' parameter), the available space will be reduced by two(2) columns to accomodate the left and right borders of the dialog window.
This value must be at least one(1) which is reserved for the upper-axis label. The remaining rows constitute the Header Area which is a text display area above the chart grid.
Keep in mind that the space reserved for the Header Area reduces the number of rows available for the coordinate grid.
A value of zero(0) indicates that the grid begins in the leftmost column of the display area. A positive value indicates the number of columns reserved for the Margin Area which is a text display area to the left of the chart grid.
Keep in mind that the space reserved for the Margin Area reduces the number of columns available for the coordinate grid.
A value of zero(0) indicates that the grid (including the lower axis label) extends to the bottom row of the display area. A positive value indicates the number of rows reserved for the Footer Area which is a text display area below the chart grid.
Keep in mind that the space reserved for the Footer Area reduces the number of rows available for the coordinate grid.
The default is to draw the bars the full width of the character cell (8 divisions). Using fewer divisions to draw the bars produces a small space between the bars.
Technical Note: If the data bar terminates in a partially-filled character cell, that cell will be written with a full-width character. While this may lead to an unattractive display, it is unavoidable because the Unicode standard does not provide the characters needed to display a narrow terminating cell.
Special Case: If the 'barWidth' parameter is set to zero(0), then the data will not be displayed as the usual bars, but as a single character for each data item located at the point where the bar would otherwise terminate. This results in something similar to a line which tracks the value of each item.
Be aware that there is a certain loss of accuracy when plotting the data in this way because the Unicode character set does not provide the characters needed to display the data accurately. In addition, this option may result in an unattractive representation of some data, but is quite adequate for other data sets. Feel free to experiment.
Spacing between bars can be useful if there are only a few data values or if the additional space makes it easier for the user to visualize the data.
┌──────────────────────────┐ ┌──────────────────────────┐ │ctLowerLeft │ │ ctLowerRight│ │├ │ │ ┤│ │├ │ │ ┤│ │├ │ │ ┤│ │├ │ │ ┤│ │└┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴ │ │ ┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘│ │ Origin at Lower Left │ │ Origin at Lower Right │ └──────────────────────────┘ └──────────────────────────┘ ┌──────────────────────────┐ ┌──────────────────────────┐ │ctUpperLeft │ │ ctUpperRight│ │┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬ │ │ ┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐│ │├ │ │ ┤│ │├ │ │ ┤│ │├ │ │ ┤│ │├ │ │ ┤│ │ Origin at Upper Left │ │ Origin at Upper Right │ └──────────────────────────┘ └──────────────────────────┘ ┌──────────────────────────┐ ┌──────────────────────────┐ │ ctLowerCenter │ │ ctUpperCenter │ │ ┼ │ │ ┼ │ │ ┼ │ │ ┼ │ │ ┼ │ │ ┼ │ │ ┼ │ │ ┼ │ │┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴ │ │ ┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴│ │ Origin at Lower Center │ │ Origin at Upper Center │ └──────────────────────────┘ └──────────────────────────┘ ┌──────────────────────────┐ ┌──────────────────────────┐ │ctCenterLeft │ │ ctCenterRight│ │├ │ │ ┤│ │├ │ │ ┤│ │├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼ │ │ ┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤│ │├ │ │ ┤│ │├ │ │ ┤│ │ Origin at Left Center │ │ Origin at Right Center │ └──────────────────────────┘ └──────────────────────────┘ ┌──────────────────────────┐ │ ctCartesian │ │ ┼ │ │ ┼ │ │┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼ │ │ ┼ │ │ ┼ │ │ Origin at Center of Grid │ └──────────────────────────┘
Writing text to these areas after instantiation is done using various Chart-class public methods, all of which have independent color parameters. For example, see Chart, DrawHeaderText method.
For certain chart types, negative values can be displayed in an alternate color. See 'negColor' parameter, below.
Important Note: The dataset for Cartesian charts is configured as X/Y pairs rather than individual data values; however, 'dataCount' specifies the number of individual values, NOT the number of X/Y pairs.
Technical Note: For Cartesian charts, if 'dataCount' is an odd number, the last value in the array will be ignored so that only value pairs will be processed.
For Cartesian charts only, this parameter is ignored because all Cartesian data points are displayed simultaneously.
Please note that this is a “void pointer” which can point to any supported source data type. The 'dataType' parameter (see below) indicates the type of data being referenced.
The supported source-data types are:
Internally, the source data are automatically converted to double-precision floating point data for internal use by the Chart object.
Important Note: Please be sure that the data type specified accurately reflects the data actually referenced by 'dataPtr'. A mismatch between these parameters will, at minimum, result in garbage being displayed in the chart, and will very likely result in a memory-access violation.
The 'attrPtr' parameter may be used to specify an array of color attributes to be used to display the data, one attribute per data value.
Note that for Cartesian charts, 'attrPtr' provides one color attribute for each coordinate pair (dataCount / 2 color values).
Please keep in mind that the character specified must be a single-width character, that is it must occupy exactly one character cell.
By default, the Chart object uses the Unicode codepoint 0x25C8 (’◈’ defined in Chart.hpp as 'dblDiamond'); however, any single-width character may be specified to plot the data points. For instance, the Unicode codepoints commonly used in bullet lists are a good substitute. These characters generally fall into the range of 0x2500 to 0x26FF. Examples of the most common bullet characters may be found in the documentation file: NcDialog/Texinfo/texi_macros.texi.
The full list of Unicode codepoints may be found at: https://www.utf8-chartable.de/unicode-utf8-table.pl
ncltSINGLE ┌─────────────── ncltSINGLEBOLD ┏━━━━━━━━━━━━━━━ ncltDUAL ╔═══════════════ ncltDASH2 ┌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ncltDASH2BOLD, ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍ ncltDASH3 ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ ncltDASH3BOLD ┌┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ ncltDASH4 ┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ ncltDASH4BOLD ┌┉┉┉┉┉┉┉┉┉┉┉┉┉┉┉
The border is enabled or disabled by the 'drawBorder' parameter
(see below).
The border color is specified by the 'borderColor' parameter
(see above).
Please see Line Drawing Characters or run the Dialog2 test application, Test #8 for additional examples of the line-drawing styles.
┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬ ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╗ ├ ╢ ├ ncltSINGLE ncltDUAL ╢ ├ ╢ ├ ╢ ├ ╢ ├ ╢
If a Header Area is defined (see 'yOffset' parameter, above), the specified text will be written. If the header is not large enough to hold all the text, the excess will be truncated.
Header text may also be written after the Chart object is created
through a call to the 'DrawHeaderText' method.
Please see Chart, DrawHeaderText.
In addition, the 'Add2HeaderText' method may be used to modify
the Header Area text.
Please see Chart, Add2HeaderText.
If a Footer Area is defined (see 'footRows' parameter, above), the specified text will be written. If the footer is not large enough to hold all the text, the excess will be truncated.
Footer text may also be written after the Chart object is created
through a call to the 'DrawFooterText' method.
Please see Chart, DrawFooterText.
In addition, the 'Add2FooterText' method may be used to modify
the Footer Area text.
Please see Chart, Add2FooterText.
If a Margin Area is defined (see 'xOffset' parameter, above), the specified text will be written. If the margin area is not large enough to hold all the text, the excess will be truncated.
Margin text may also be written after the Chart object is created
through a call to the 'DrawMarginText' method.
Please see Chart, DrawMarginText.
In addition, the 'Add2MarginText' method may be used to modify
the Margin Area text.
Please see Chart, Add2MarginText.
Vertical data bars are the default for these chart types because more data values may be displayed simultaneously. This is based on the fact that the width of character cells is significantly less than cell height. The ratio of cell height to width depends on the font used by the terminal program, but in general the ratio is between 1.5 and 1.7 vertical-to-horizontal. This translates to approximately 2 vertical cells to 3 horizontal cells.
Horizontal bars may be specified to provide finer resolution for representation of value amplitude.
The remaining chart types accept only horizontal bars OR vertical bars, but not both. For these chart types, the 'horizBars' parameter is ignored.
ctLowerCenter horizontal bars only
ctUpperCenter horizontal bars only
ctCenterLeft vertical bars only
ctCenterRight vertical bars only
Special Case: For Cartesian charts (ctCartesian) only,
the interpretation of this parameter is redefined. For Cartesian charts,
this parameter specifies the ordering of the coordinate pairs:
'false' indicates X/Y pairs
'true' indicates Y/X pairs
If reset, ('false'), no border will be drawn.
This parameter applies only to chart areas defined within application dialog windows. If the Chart object is created within its own independent dialog window, (see 'dPtr'), then the new dialog window will define its own border, so the 'drawBorder' parameter will be ignored.
These screenshots show typical chart layouts with various features
enabled. These screen captures were taken directly from the Dialog4 test
application, Test #10. The first example shows a Chart object drawn in
the application dialog window.
The next screenshot shows an independent dialog window created within the
Chart object itself. This dialog temporarily obscures the application dialog.
After the Chart object is deleted the application dialog is restored.
┌───────────────────────┤ Local Chart Dialog Window ├────────────────────────┐ │ Statistics: dataItems:200 minValue:-7.50 maxValue:7.50 │ │ meanValue(avg):-0.36 medianValue:6.00 │ ├──────────────────────────────────────────────────────────────────────────────┤ │ Vertical-axis Label │ │┌──────────────────────────────────┐ ║ │ ││Definition of "marplotter": │ ╢ │ ││One who, by meddling, mars or │ ╢ │ ││frustrates the designs or plans │ ╢ │ ││of others. │ ╢ │ ││ │ ▂ ╢ │ ││ │ ▃█ ╢ │ ││Synonyms: │▅▂ ██▅ ╢ │ ││ Douchbag, Duckhead, Uranus. │██▇▅▁ ▇███ ╢ │ ││ │█████▇▅▁ ▃█████ ╢ │ ││Example: │████████▇▄▁ ██████▃ ╢ │ ││"The Franklins, and other │███████████▇▄▁ ▂████████ ╢ │ ││marplotters in the Potomac Army, │▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄═▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄╣ │ ││menace to resign if Hooker is put │ ▇▃████████ ████╢ │ ││in command. The sooner the better │ ▇▁█████▂ ███╢ │ ││for the army to get rid of such │ ▃███▅ ▅██╢ │ ││trash. But the imbeciles and the │ ▁▇ ██╢ │ ││intriguers in power think not so; │ ██╢ │ ││and all may remain as it was, and │ ▆█╢ │ ││a new slaughter of our heroes may │ ▅╢ │ ││loom in the future." │ ╢ │ ││ -- Adam Gurowski (1863) │ ╢ │ ││ │ ╢ │ │└──────────────────────────────────┘ ╢ │ │ Horizontal-axis Label │ ├──────────────────────────────────────────────────────────────────────────────┤ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘The quotation above is taken from the diary of a U.S. soldier during the U.S. Civil War.
This diary is part of the National Archive.
This screenshot captures a Cartesian plot of X/Y data pairs.
┌─────────────────────────────────────────────────────────────────────┐ │ Statistics: minX:-30.00 maxX:30.00 meanX:0.00 medianX:0.00 │ │ pairs:204 minY:-8.00 maxY: 8.00 meanY:0.00 medianY:0.00 │ ├─────────────────────────────────────────────────────────────────────┤ │ Vertical-axis Label │ │ ◈ ◈ ◈ ▪┼▪ ◈ │ │ ◈ ◈ ◈ ◈ ▪ ┼ ▪ ◈ ◈ ◈◈ ◈ ◈ ◈ │ │ ◈◈ ◈ ◈◈ ◈◈ ◈ ◈ ▪ ┼ ▪ ◈◈ ◈ ◈ ◈ ◈◈ ◈ ◈ │ │ ▪ ◈ ◈ ◈ ◈ ◈ ◈ ◈ ▪ ┼ ▪ ◈ ◈◈ ◈◈ ◈ ◈ ▪ │ │ ▪ ▪◈ ◈ ◈ ◈ ◈ ◈ ▪┼▪ ◈ ◈◈ ◈ ◈ ◈▪ ▪ │ │ ▪ ◈ ▪◈ ◈ ◈ ◈ ◈◈ ◈ ◈◈ ◈ ◈ ◈┼◈◈ ◈◈ ◈ ◈◈ ◈ ◈ ◈ ◈ ◈ ▪◈ ▪ │ │ ┼┼◈┼┼▪┼┼┼┼◈┼┼┼◈◈┼◈┼◈◈┼◈┼◈┼┼◈┼◈┼┼◈┼◈◈┼◈┼◈┼┼◈┼◈◈┼◈◈┼◈┼◈┼┼◈┼┼┼┼◈▪┼◈┼┼┼ │ │ ▪ ◈ ▪◈ ◈ ◈ ◈ ◈◈ ◈ ◈┼ ◈ ◈ ◈ ◈ ◈ ◈ ◈ ▪◈ ▪ │ │ ▪ ▪◈ ◈ ◈ ◈ ◈ ◈ ┼ ◈ ◈◈ ◈ ◈ ◈▪ ▪ │ │ ▪ ◈ ◈ ◈ ◈ ◈ ◈ ◈ ▪┼▪ ◈ ◈◈ ◈◈ ◈ ◈ ▪ │ │ ◈ ◈◈ ◈◈ ◈ ▪ ┼ ▪ ◈ ◈ ◈ ◈ ◈ ◈ │ │ ◈ ◈ ◈ ◈ ◈ ▪ ┼ ▪ ◈ ◈ ◈ ◈ ◈ │ │ ◈ ◈◈ ◈ ◈ ◈ ◈ ▪ ┼ ▪ ◈ ◈◈ ◈ │ │ ◈ ▪┼▪ ◈ ◈ ◈ │ │ Horizontal-axis Label │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘
If a Chart object is created using only the default values for the ChartDef class, a small (9x28), fully functional (but useless) dialog will be generated using the default terminal color attribute.
┌──────────────────────────┐ │Vertical Axis Label │ ││ │ │├ │ │├ │ │├ │ │└┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴ │ │ Horizontal Axis Label │ └──────────────────────────┘
Chart ( const ChartDef& cdef, bool refresh = false ) ;
The Chart-class constructor takes one mandatory parameter, an initialized 'ChartDef' structure. The Chart may optionally be made visible immediately using the 'refresh' argument, or the refresh can be delayed until any post-instantiation adjustments have been made.
Please see Chart, Defining the Chart Object, above for a detailed discussion of the configuration parameters.
For additional code examples, please study the instantiation sequence in the test application: ChartTest::BlastOff() and the setup sequence: ChartTest::SetChartDefinition(). Because this is a test application, these examples are much more complex than anything a real life application would need, but they demonstrate the use of all Chart-class functionality.
void RefreshDisplay ( void ) const ;
Make all changes to the display data visible.
The display may be automatically refreshed by the constructor (see above), but if desired, the refresh may be delayed until additions and adjustments to the Chart object have been completed. When all desired adjustments have been made, call this method to make the changes visible. An example is shown in the code sequence, above.
Unnecessary or duplicated refreshes will appear to cause the display to flash and stutter, especially on slow video hardware; therefore, in general it is best to refresh the display only when you are ready for the user to see the changes.
Note that many of the methods described in the next section include an optional 'refresh' parameter which will accomplish the same task.
bool DrawHeaderText ( const char* txt, attr_t txtAttr,
bool border = false, bool refresh = false ) ;
Input : txt : text to be written attr : color attribute for text border : (optional, 'false' by default) if 'true', draw a horizontal line across the bottom row of the header area. This creates a visual division between the header and the chart grid. refresh: (optional, 'false' by default) if 'false', do not refresh the display after writing if 'true', refresh the display (make changes visible) Returns: 'true' if successful 'false' if target area not defined (header rows == ZERO)
Clear the header-text area and write the specified text.
Note: To clear the area without writing new text, set the 'txt'
argument to an empty string ("").
winPos Add2HeaderText ( const winPos& pos, const char* txt,
attr_t txtAttr, bool refresh = false ) ;
Input : pos : (by reference) Y/X offset from header base position Y offset must be >= ZERO and within the header area X offset Must be >= ZERO and within the header area txt : text to be written. Line breaks are indicated by newline '\n' characters. attr : color attribute for text refresh: (optional, 'false' by default) if 'false', do not refresh the display after writing if 'true', refresh the display (make changes visible) Returns: Y/X offset at end of text written. Returns Y/X==0/0 if 'pos' is out-of-range OR if end position is out-of-range (unlikely)
Add text to the header area at the specified offset. For example,
display of instructions or explanations at different positions or
in different colors.
See Chart, GetHeaderDimensions, for obtaining the dimensions of
the header area.
bool GetHeaderDimensions ( short& rows, short& cols ) const ;
Input : rows : (by reference) receives number of display rows cols : (by reference) receives number of display columns Returns: 'true' if successful 'false' if target area not defined (rows == ZERO)
Get the dimensions of the Header Area. This is the number of rows and columns reserved for the header area. If the number of rows returned is zero(0), no header area has been defined.
The height of the header area is specified by the 'yOffset' member
of the ChartDef class.
Please see ChartDef, yOffset.
The width of the header is the full width of the defined chart area minus the left and right borders, if specified.
bool DrawFooterText ( const char* txt, attr_t txtAttr,
bool border = false, bool refresh = false ) ;
Input : txt : text to be written attr : color attribute for text border : (optional, 'false' by default) if 'true', draw a horizontal line across the top row of the footer area. This creates a visual division between the footer and the chart grid. refresh: (optional, 'false' by default) if 'false', do not refresh the display after writing if 'true', refresh the display (make changes visible) Returns: 'true' if successful 'false' if target area not defined (header rows == ZERO)
Clear the footer-text area and write the specified text.
Note: To clear the area without writing new text, set the 'txt'
argument to an empty string ("").
winPos Add2FooterText ( const winPos& pos, const char* txt,
attr_t txtAttr, bool refresh = false ) ;
Input : pos : (by reference) Y/X offset from footer base position Y offset must be >= ZERO and within the footer area X offset Must be >= ZERO and within the footer area txt : text to be written. Line breaks are indicated by newline '\n' characters. attr : color attribute for text refresh: (optional, 'false' by default) if 'false', do not refresh the display after writing if 'true', refresh the display (make changes visible) Returns: Y/X offset at end of text written. Returns Y/X==0/0 if 'pos' is out-of-range OR if end position is out-of-range (unlikely)
Add text to the footer area at the specified offset. For example, display of instructions or explanations at different positions or in different colors.
See Chart, GetFooterDimensions, for obtaining the dimensions of the footer area.
bool GetFooterDimensions ( short& rows, short& cols ) const ;
Input : rows : (by reference) receives number of display rows cols : (by reference) receives number of display columns Returns: 'true' if successful 'false' if target area not defined (rows == ZERO)
Get the dimensions of the Footer Area. This is the number of rows and columns reserved for the footer area. If the number of rows returned is zero(0), no footer area has been defined.
The height of the footer area is specified by the 'footRows' member
of the ChartDef class.
Please see ChartDef, footRows.
The width of the footer is the full width of the defined chart area minus the left and right borders, if specified.
bool DrawMarginText ( const char* txt, attr_t txtAttr,
bool border = false, bool refresh = false ) ;
Input : txt : text to be written attr : color attribute for text border : (optional, 'false' by default) draw an interior border around the Margin area. refresh: (optional, 'false' by default) if 'false', do not refresh the display after writing if 'true', refresh the display (make changes visible) Returns: 'true' if successful 'false' if target area not defined (cols == ZERO)
Clear the margin-text area and write the specified text to the margin area. Note: To clear the area without writing new text, set 'txt' to an empty string ("").
winPos Add2MarginText ( const winPos& pos, const char* txt,
attr_t txtAttr, bool refresh = false ) ;
Input : pos : (by reference) Y/X offset from margin base position Y offset must be >= ZERO and within the margin area X offset Must be >= ZERO and within the margin area txt : text to be written. Line breaks are indicated by newline '\n' characters. attr : color attribute for text refresh: (optional, 'false' by default) if 'false', do not refresh the display after writing if 'true', refresh the display (make changes visible) Returns: Y/X offset at end of text written. Returns Y/X==0/0 if 'pos' is out-of-range OR if end position is out-of-range (unlikely)
Add text to the margin area at the specified offset. For example, display of instructions or explanations at different positions or in different colors.
See Chart, GetMarginDimensions, for obtaining the dimensions of the margin area.
bool GetMarginDimensions ( short& rows, short& cols ) const ;
Input : rows : (by reference) receives number of display rows cols : (by reference) receives number of display columns Returns: 'true' if successful 'false' if target area not defined (rows == ZERO)
Get the dimensions of the Margin Area. This is the number of rows and columns reserved for the margin area. If the number of columns returned is zero(0), no margin area has been defined.
The width of the margin area is specified by the 'xOffset' member
of the ChartDef class.
Please see ChartDef, xOffset.
The height of the margin area is the height of the coordinate grid.
bool DrawDivider ( ncLineType lineStyle, short offset,
attr_t lineAttr, bool refresh = false ) ;
Input : lineStyle: line style (member of enum ncLineType, ) (excluding ncltHORIZ and ncltVERT) offset : offset from top of target area Range: >= 0 and <= last row of target area Note that if a border has been specified, the bottom border is outside the footer area. lineAttr : color attribute for line refresh : (optional, 'false' by default) if 'false', do not refresh the display after writing if 'true', refresh the display (make changes visible) Returns: 'true' if successful 'false' if 'offset' is out-of-range or if target area is not defined (target rows == ZERO)
Draw a horizontal line across the Footer Area. Line position is specified
as an OFFSET, and must fall within the footer area.
Minumum Offset: 0 == top line of footer area.
Maximum Offset: footer_rows - 1 == bottom line of footer area.
Please see Chart, GetFooterDimensions method.
The line is drawn the full width of the target area.
If the line intersects another line (e.g. the border), a visual connection will be made.
bool AudibleShift ( bool enable ) ;
Input : enable: 'true' to enable alert 'false' to disable alert Returns: 'true' if alert enabled, 'false' if disabled
Enable or disable audible alert in the 'ShiftData' method.
Please see Chart, ShiftData method for more information.
Alert Enabled:
If the data cannot be shifted further in the specified direction, for example, if already at the end of dataset, then a beep will sound to indicate that it is not possible to shift further in that direction. To put it another way, a beep will sound only for defined shift keycodes which cannot be honored. An unhandled keycode will silently cause the 'ShiftData' method to return to caller.
Alert Disabled:
Audible alert is disabled for all keycodes. If user presses a shift keycode which cannot be honored, it (the keycode, not the user) will be silently discarded, and user will continue to believe that she is a genius and that the application is broken because it will not perform the requested (but impossible) task. Are you, the designer getting the subtle message we’re sending here?
bool SetCartesianChar ( wchar_t cartChar ) ;
Input : cartchar : character to be displayed at each datapoint Returns: 'true' if success 'false' if not a single-column printing character
Set the display character for the datapoints of a Cartesian chart.
Any single-column, printable, non-whitespace character may be specified,
but be aware that for best results, the character should relatively small
compared to the size of the character cell, and should be centered in the
cell. By default, the '◈' character, codepoint U+25C8 is used and
is specified using the 'cartChar' member of the 'ChartDef' class.
Please see ChartDef, cartChar.
The standard bullet characters and similar would be good substitutes.
A few examples are shown here. These, and most bullet-type characters fall
into the Unicode range of codepoints U+2500 through U+26FF.
Unicode codepoint: U+25AA '▪'
Unicode codepoint: U+26AC '⚬'
Unicode codepoint: U+25C9 '◉'
The full list of Unicode codepoints may be found at: https://www.utf8-chartable.de/unicode-utf8-table.pl
bool OverlayCartesianDataset ( const void* cartData,
int32_t cartCount, attr_t cartAttr,
idataType dType = idtDouble,
wchar_t cartChar = dblDiamond,
bool refresh = false ) ;
Input : cartData : pointer to array of data values to be plotted, arranged as X/Y pairs (or as Y/X pairs) cartCount: number of elements in 'cartData' array cartAttr : color attribute for datapoint display dType : (optional, idtDouble by default) type of data referenced by 'cartData' cartChar : (optional, "dblDiamond" (0x25C8) by default) character to be displayed at each datapoint refresh: (optional, 'false' by default) if 'false', setup is performed, but display not updated if 'true', after setup, update display immediately Returns: 'true' if success, 'false' if invalid parameter(s)
Superimpose an additional dataset onto an existing Cartesian chart.
To see an example of this data overaly, please refer to the screenshot above of a Cartesian chart with a data overlay.
void GetStats ( ChartStats& cStats ) const ;
Input : cStats : (by reference) an instance of the ChartStats class to receive the statistical information Note: 'dataItems' member == number of data values EXCEPT for the ctCartesian chart type where 'dataItems' == number of coordinate pairs. Returns: nothing
Get basic statistics on the displayeddataset.
Bar-graph data consists of an array of values to be displayed using one bar for each value. One set of statistical values is returned which describes the data in this array.
In contrast, Cartesian-chart data consists of an array of X/Y coordinate pairs. Separate statistical values are calculated for X coordinates and for Y coordinates. Be aware that source data may have been specified as Y/X pairs rather than X/Y pairs, but the calculated statistics correctly identify the X and Y coordinates.
The ChartStats Class
The statistical data are returned in a 'ChartStats' object which is initialized according to the type of data displayed.
For bar charts, the 'dataItems' member receives the number of items in the data array. For Cartesian charts, 'dataItems' receives the number of X/Y (or Y/X) pairs (i.e. the number of individual X values and Y values.).
Bar-chart data are written to the 'minValue', 'maxValue', 'meanValue' and 'medianValue' members.
Data for Cartesian charts are written to the 'cartRange' member which is a sub-class of the 'ChartStats' class.
All unused data members are set to zeros.
bool ReloadDataset ( const void *dataPtr, int32_t dataCount,
idataType dataType, bool YX_pairs = false ) ;
Input : dPtr : pointer to new dataset dCount : number of items in 'dataPtr' array dType : data type (member of enum idataType) YX_pairs : (optional, 'false' by default) (for Cartesian chart type only) 'false' == X/Y pairs 'true' == Y/X pairs Returns: 'true' if data successfully updated 'false' if invalid parameter
Replace the currently-displayed dataset with a new dataset.
Use this method to refresh the data displayed in the Chart object when the data are dynamically changing in application space, or to alternately display different datasets.
Note that only the dataset will be updated. Header, Footer and Margin areas are not affected. The coordinate-grid style and dimensions are not affected. Data-bar orientation is not affected.
The application must make a judgement call when changing datasets: whether to update the existing Chart object, or to close the existing Chart object and launch a new Chart object to display the new data. It is also possible to have multiple, independent Chart objects and simply bring them into the foregroud on a rotating basis.
From a performance point-of-view, it is somewhat faster to update the data in an existing Chart object because it cuts the number of calculations and system calls by about 40%, but use your best judgement.
Only four(4) parameters are updated by the 'ReloadDataset' call:
void ProtectDialog ( void ) const ;
Input : none Returns: nothing
Save the display data for the independent dialog window.
If the application’s main dialog or another dialog window may obscure the independent dialog window opened locally within the Chart dialog, call 'ProtectDialog' to protect the dialog.
This implements a call to the local NcDialog object’s 'SetDialogObscured' method.
If the dialog in which the Chart data are drawn was not created by the Chart object itself, then 'ProtectDialog' will return without taking action.
void RestoreDialog ( void ) const ;
Input : none Returns: nothing
Restore display data for the independent dialog window which was saved by a previous call to 'ProtectDialog'.
This implements a call to the local NcDialog object’s 'RefreshWin' method.
If the dialog in which the Chart data are drawn was not created by the Chart object itself, then 'RestoreDialog' will return without taking action.
const char* GetVersion ( void ) const ;
Input : none Returns: pointer to const string
Returns the version number of the Chart class.
The version number is returned as a string with the format: x.y.zz,
where 'x' is the major version, 'y' is the minor version and
'zz' is the release number. Example: 0.0.04
The internal Chart-class user interface is extremely simple. It provides the mechanism for users to scroll through the dataset in discrete steps. The default set of user-interface keys are simply a subset of the generally-available cursor keys. Alternate keycodes may be assigned to each scrolling function to provide for maximum portability across hardware platforms.
int32_t ShiftData ( wkeyCode& wkey, short sdCnt = ZERO,
ShiftDef *sdPtr = NULL ) ;
Input : wkey : (by reference) receives the unhandled keycode that triggered return sdCnt: (optional, ZERO by default) If specified, this is the number of objects in the 'sdPtr' array. sdPtr: (optional, NULL pointer by default) If specifed, this is a pointer to an array of ShiftDef objects which define the valid shift options and associated keycodes. See documentation for examples. Returns: index of first currently-displayed data item 'wkey' contains the unhandled key input. Note: if all data currently displayed, wkey.key==nullchar
Interact with user to shift the data visible in the chart window forward
and backward through the data array.
An audible alert (beep) is generated if unable to perform user-specified)
specified shift. The audible alert can be disabled via AudibleShift().
If all data are currently displayed, returns immediately. Otherwise, returns when an un-handled keycode is received.
This method translates the defined keycodes (defaults listed below) into parameters used by the private ShiftData() method, below.
If the ’sdPtr’ argument is not provided, then the following default shift-operation/keycode combinations are used.
Two additional user-interface keycodes are defined within the
'ChartTest' application. These keycodes are handled within the
ChartTest application, not in the Chart class itself.
'Ctrl+R' : which replaces the displayed dataset with another
dataset. Please see Chart, ReloadDataset method.
'ALT+SHIFT+P' : which is used only during development. This
command captures a screenshot of the target dialog and is used for
creating the documentation.
The following example is taken from the 'ChartTest' module of the Dialog4 test application. The first while() loop is based on the Chart-class default UI keycodes. The second while() loop defines a custom set of UI keycodes.
The Chart class is written in pure C++. It requires a minimum of C++11 support, specifically for typing, array initialization, timing methods and other minor functionality which was not available under previous versions of the C++ standard. The code was developed on a system using the GNU C++ compiler v:10.3.1 (C++17) although none of the features specific to this later version are referenced.
The Chart class consists of approximately 2,800 lines of source code
which compiles to about 92kb of binary data.
The source also includes over 2,400 lines of comments. The author
is a teacher, after all. The students call this programming style
“qiǎngpò zhèng C++” (OCD C++). It is not entirely
clear whether this is a complement or slander.
☺
The essence of any graphing function is scaling the data to fit the graph. The Chart class does this in a straightforward way by calculating the overall range of the source data and mapping it to the range of discrete steps available on the coordinate grid for representing that range. This is basically the same calculation regardless of the resolution of the coordinate grid. For data displayed in the terminal window, the resolution is modulo-8, that is, each character cell is divisible into eight separate segments. The amplitude of a data value is scaled to fit the number of available character cells i.e. rows or columns times eight divisions per cell.
For maximum resolution, all internal calculations are performed using double-precision floating-point values which are converted to the integer number of character-cell divisions at the last possible moment in order to maintain accurate resolution.
Conceptually any widget including the Chart Widget is what we nerds call a “white-box” or “glass-box” object. This means that we know what is being done inside the widget and can design tests for each function within it, but we take no direct action to modify its internal parameters. All Chart-class data are private data, and all tests are performed through the public methods of the object. Tests are designed to throw bad data or ambiguous data at the object to determine whether these stressful situations are handled smoothly.
For instance, there are four(4) autonomous regions within the Chart object’s display area: Header, Footer, Margin and Grid. The methods which control each area have no knowledge of, or interaction with the other areas. Testing is done to ensure that this is, in fact the case.
One of the often-overlooked features of C++ is the ability to declare
methods as "const". This key indicates that the specified
method does not modify any internal settings of the object.
Example: const char* GetVersion ( void ) const ;
which simply returns a pointer to a constant string without modifying
any internal data.
It is good practice, especially for portable widgets like the Chart
class to declare as many methods as possible to be "const"
methods. This reduces the scope of testing required when bugs are
inevitably found. (Of course our code will never have any bugs.
哈哈! :-)
The default constructor: Chart::Chart ( void ) ; is defined
as private to prevent creation of an uninitialized Chart object.
See Chart, Launch the Chart Object, for a description
of the full-initialization constructor.
The chart class contains three debugging methods which are controlled by conditional-compilation flags. These methods have no value in production code and are therefore disabled by default. The first two simply display a snapshot of the internal parameters at key moments during configuration. These are private methods.
DumpCfg ( bool refresh ) ;
WriteYOffsets ( const winPos gridTop, bool clear ) ;
The third debugging method is public and is simply a pass-through method to the underlying NcDialog API, and is used to capture screenshots for use in documentation. (See CaptureDialog method, for details.)
Previous: Creating Widgets, Up: Application Examples [Contents][Index]
Internationalization of a user interface is a non-trivial task, but necessary in the modern world. All the English-only UNIX dinosaurs (of which your author was one) must adapt or become fossil fuels.
The NcDialog library provides all the basic tools for input and output of the full UTF-8 character set and in nearly any language. Some languages, of course will require more work than others.
Aside from the character codes (’codepoints’) themselves, there are a few additional issues that need to be addressed when designing a user interface with the flexibility to support multiple languages.
The NcDialog library directly supports both LTR and RTL written languages.
Top-to-bottom languages are not directly supported by the dialog controls.
Specifically, textbox controls accept only horizontal (LTR or RTL) text.
However, vertical text may be written in a window using some minor trickery.
(See top-to-bottom/right-to-left example below.)
The NcDialog API does not perform automatic language detection of any kind. It is the application’s responsibility to indicate when text data are to be drawn/processed as RTL text. Please see below for configuring the NcDialog API to process Right-to-Left text.
Please Note: RTL languages may be displayed backward within this document. The Texinfo (makeinfo) documentation suite does not understand RTL, and the HTML-formatted version of the document suffers from too much "help" from the browser’s rendering engine in the form of automatic RTL-language recognition. We have done our best, but if RTL characters appear out-of-order, please mentally substitute the correct character order. Our appologies....
Left-to-right (LTR) text output is the default. Unless otherwise specified,
the NcDialog output group of methods: ’WriteString’, ’WriteChar’ and
’WriteParagraph’ will assume LTR data. On return from the call, the cursor will
be on the first free space to the right of the output.
To output data as RTL, the ’rtl’ flag of the output method call must be
set (’true’), and on return from the call, the cursor will be on the
first free space to the left of the output.
For more information, please see descriptions of the output method group. See NcDialog Display Output.
While writing RTL data directly to the dialog window is straightforward,
as shown above, in order to display the contents of user-interface controls
and control labels as RTL, you must specifically configure the NcDialog API
to do so. For more information, please see the configuration methods:
see DrawContentsAsRTL method
see DrawLabelsAsRTL method
Newer versions of terminal programs such as GNOME Terminal and KDE Konsole now include direct support for BiDi (bi-directional) text. The terminal software monitors the text output, and if the codepoints belong to an RTL language, the data are written leftward from the current cursor position. While this is an excellent new feature for pure console applications which write directly to 'stdout' and 'stderr', this automatic BiDi support interferes with console applications which display pre-formatted RTL text. This includes all applications which incorporate 'ncurses' including applications built on the NcDialog API.
Instead of writing the specified character at the specified position, the terminal software tries to be “helpful” by shifting the displayed RTL text toward the left as each character is written.
The documentation calls this “shuffling” the data, which is some combination of horizontal shifting, reversing character order and mirroring individual characters. It is actually even messier than that because the terminal recognizes RTL Unicode codepoints and tries to manipulate the punctuation at either end of the RTL data without actually understanding how the data should be formatted.
Programmer‘s Note: Within the NcDialog API, the terminal’s automatic BiDi support is explicitly disabled before the NCurses Engine takes control of console I/O. This prevents interference when RTL data are displayed. BiDi support is then re-enabled just before the application exits. BiDi support is also re-enabled, when the NCurses Engine hibernates (temporarily returns control to the shell program). Unfortunately, not all terminal software recognizes the standardized commands for enabling/disabling automatic BiDi support. The Gnome Terminal and others based on the VTE terminal emulation widget of the GTK+ library (xfe4-term, Sakura, etc.) will correctly interpret the enable/disable escape sequences ("\e[8l" and "\e[8h"). KDE Konsole, however, does not recognize these programatic commands, so it may be necessary to disable BiDi support in the Konsole terminal settings by editing the current profile (Advanced Options, “Bi-Directional text rendering.”) XTerm, of course, remains blissfully unaware of all this 21st-century foolishness, and continues to render text exactly as it is received. (Good old XTerm :) |
Important Note on display of RTL languages within this document:
Screen captures of dialog windows capture RTL-language text characters
in the order displayed which is presumed to be correct. These screenshots
in the info-format version of this document are generated assuming that
the terminal’s BiDi support is enabled (which is the default). The info
reader then displays the RTL data according to whether the terminal’s
automatic BiDi support is currently enabled. If the RTL text is displayed
incorrectly, then re-enable the terminal’s BiDi support. At the command
line, enter the command:
printf "\e[8h"
XTerm will display the RTL data in info-reader documents incorrectly
because it knows nothing about BiDi text.
For the HTML-format version of this document, the browser’s rendering
engine will generally present the RTL data correctly, but may sometimes
try to be "helpful" by inappropriately reversing the direction
of the captured RTL text. We have tried to compensate for this, but our
Yiddish is weak, and your browser may be smarter than we are. All we can
claim is that this screenshot displays correctly in Firefox 83.
(Opera 73 displays the Yiddish correctly, but refuses to do it in
monospace text.)
מיר זענען נעבעכדיק פֿאַר די ינקאַנוויניאַנס
This screenshot is from test application Dialog4, Test06.
Under most circumstances, a character sequence will be written either as LTR or as RTL; however, some cases require mixed LTR/RTL data.
Mixed left-to-right (LTR) and right-to-left (RTL) text output is not directly
supported by the NcDialog class. To write mixed LTR/RTL text, you have two
primary choices:
1) Write the sections individually, adjusting the cursor position
after each section.
2) Reverse the order of characters in your data for one of the
directions (usually the LTR text), and then write the data as
one block, in the non-reversed direction (usually RTL).
Example: The following sequence demonstrates the formatting necessary for
display of mixed LTR/RTL data.
This code is included as a test case in one of the test applications.
Please see See Application Examples, for more
information.
wchar_t mCost[] = { L"$123,456.78usd" } ; dp->WriteParagraph ( 2, 2, L"This is a test of mixed LTR and RTL output:\n" " First, the unmodified data output as RTL :\n\n" " Next, output separately with cursor mods :\n\n" " Last, output as RTL with reversed LTR data: ", dColor ) ; winPos wp( 4, 51 ) ; // cursor position gString gsOut ; // work buffer // (Incorrectly) output the unmodified data. gsOut.compose( "%S%S%S\n\n", mHead, mCost, mTail ) ; wp = dp->WriteParagraph ( wp, gsOut, nc.brbl, false, true ) ; // Output sections separately, adjusting cursor position as necessary. winPos wx = dp->WriteString ( wp, mHead, nc.brbl, false, true ) ; gsOut = mCost ; wx.xpos -= gsOut.gscols() - 1 ; short mCostIndex = gsOut.gschars() - 2 ; // index last string character dp->WriteString ( wx, gsOut, nc.brbl ) ; --wx.xpos ; dp->WriteString ( wx, mTail, nc.brbl, false, true ) ; // Contatenate the modified data and output as RTL. wp.ypos += 2 ; gsOut = mCost ; gsOut.textReverse() ; // reverse the LTR text gsOut.insert( mHead ) ; // beginning of sentence gsOut.append( mTail ) ; // end of sentence dp->WriteParagraph ( wp, gsOut, nc.brbl, false, true ) ; dp->RefreshWin () ; // make everything visible
This example demonstrates output of text data in the traditional, Chinese
top-to-bottom/right-to-left format. This is seldom needed in daily life, but
it’s fun!
This code is included as a test case in one of the test applications.
Please see See Application Examples, for more
information.
const short pLines = 5, pCols = 8 ; const wchar_t aPoem[pLines][pCols] = { // (yes, my teachers and I agree that my Chinese is abysmal.) L"我的静的花园", // In my quiet garden L"鱼是很有礼貌,", // the fish are so polite, L"他们很少说话", // they seldom speak L"打岔我的梦想。", // to interrupt my reverie. L"马伦" // Software Sam } ; wchar_t outBuff[] = { nckNULLCHAR, nckNEWLINE, nckNULLCHAR } ; attr_t outColor[] = { nc.gr, nc.br, nc.bl, nc.ma, nc.reG, nc.cy } ; dp->WriteString ( 1, 2, "A (bad) poem output as top-to-bottom, right-to-left.", dColor ) ; const short startY = 3 ; winPos wp( startY, 20 ) ; for ( short i = ZERO ; i < pLines ; i++ ) { winPos wx = wp ; for ( short j = ZERO ; aPoem[i][j] != nckNULLCHAR ; j++ ) { outBuff[ZERO] = aPoem[i][j] ; wx = dp->WriteParagraph ( wx, outBuff, outColor[i], false, true ) ; } wp.xpos -= 2 ; if ( i == 3 ) { wp.ypos += 5 ; --wp.xpos ; } } dp->RefreshWin () ; // make everything visibleThis yields:
打 他 鱼 我 岔 们 是 的 我 很 很 静 的 少 有 的 梦 说 礼 花 马 想 话 貌 园 伦 。 ,
Next: Technical Support, Previous: Application Examples, Up: NcDialog Library API [Contents][Index]
Next: Building the API Library, Up: Installation [Contents][Index]
• Unpack using the ’tar’ utility:
tar -xjvf ncdialogapi-n.n.nn.tar.bz2
• If your archive arrived in a different format, please unpack
using the appropriate archive manager.
This will unpack all files in the archive into the current working directory (CWD), using the correct directory hierarchy, and listing each file as it is unpacked.
NcDialog/ // API Main directory README // Package description, release notes VERSION_HISTORY // Change log /Dialog1 // Base directory where NcDialog API is built Dialog1.cpp // Test and demonstration application (basic tests) NcDialog.hpp // NcDialog class definition NcWindow.hpp // NcWindow class definition NCurses.hpp // NCurses class definition NCursesKeyDef.hpp // Keycode definitions gString.hpp // gString class definition WaylandCB.hpp // WaylandCB dlass definition GlobalDef.hpp // Global defs and includes NcDialog.cpp // NcDialog class methods (constructor) NcdControl.cpp // Methods share among all DialogControl classes NcdControlBB.cpp // DialogBillboard class methods NcdControlDD.cpp // DialogDropdown class methods NcdControlMW.cpp // DialogMenuwin class methods NcdControlPB.cpp // DialogPushbutton class methods NcdControlRB.cpp // DialogRadiobutton class methods NcdControlSB.cpp // DialogScrollbox class methods NcdControlSE.cpp // DialogScrollext class methods NcdControlSL.cpp // DialogSlider class methods NcdControlSP.cpp // DialogSpinner class methods NcdControlTB.cpp // DialogTextbox class methods NcdKey.cpp // NcDialog keyboard/mouse interface methods NCurses.cpp // NCurses class methods (constructor) NcKey.cpp // NCurses class keyboard/mouse input methods (primitives) NcWindow.cpp // NcWindow class methods (constructor) NcwKey.cpp // NcWindow class keyboard/mouse input methods (thread safe layer) NcwScroll.cpp // NcWindow class data scrolling methods gString.cpp // gString class methods WaylandCB.cpp // WaylandCB class methods DialogAppShared.hpp // Startup data shared by all test applications Makefile // Build NcDialog API and Dialog1 test application /Dialog2 // Test and demonstration app (keyboard and display tests) Dialog2.cpp // Test application main() ColorTest.cpp // NcDialog color map testing (init. and modification) ColorTest.hpp // NcDialog color map test support data KeyTest.cpp // NcDialog keyboard and mouse input testing KeyTest.hpp // NcDialog keyboard and mouse test support data CapTest.cpp // NcDialog screen capture testing MenuTest.cpp // DialogMenuwin class testing MenuTest.hpp // DialogMenuwin testing support data Makefile // Build Dialog2 test application /Dialog3 // Test and demonstration application (template for testing) Dialog3.cpp // Test application main() Makefile // Build Dialog3 test application /Dialog4 // Test and demonstration app (thread safety) Dialog4.cpp // Test application main() BillboardTest.cpp // Tests for the DialogBillboard class BillboardTest.hpp // DialogBillboard test support data Chart.cpp // Source for the Chart widget Chart.hpp // Definitions for the Chart widget ChartTest.cpp // Tests for the Chart class ChartTest.hpp // Chart test support data CMouseTest.cpp // Tests for the NCurses mouse interface CMouseTest.hpp // NCurses mouse test support data DMouseTest.cpp // Tests for the NcDialog mouse interface DMouseTest.hpp // NcDialog mouse test support data ExpandTest.cpp // Source for Test #10 selection dialog ExpandTest.hpp // Definitions for the Test #10 selection dialog Pinwheel.hpp // Source and definitions for the Pinwheel widget PinwheelTest.cpp // Tests for the Pinwheel widget PinwheelTest.hpp // Pinwheel test support data Progbar.cpp // Source for the Progbar widget Progbar.hpp // Definitions for the Progbar widget ProgbarTest.cpp // Tests for the Progbar widget ProgbarTest.hpp // Progbar test support data RTL_ContentTest.cpp // Tests for RTL (right-to-left) text implementation RTL_ContentTest.hpp // RTL test support data ShellTest.cpp // Tests for shell-out to command line ShelTest.hpp // Shell-out test support data SliderTest.cpp // Tests for the Slider controls SliderTest.hpp // Slider test support data ThreadTest.cpp // NcDialog thread safety tests ThreadTest.hpp // Thread safety test support data Makefile // Build Dialog4 test application /Dialogw // Test and demonstration app (multi-language support) Dialogw.cpp // Test application main() gStringTest.cpp // Comprehensive tests for the gString class gStringTest.hpp // gString test support data infoDocTest.cpp // Working examples from Texinfo documentation infoDocTest.hpp // Example code support data Makefile // Build Dialogw test application /Dialogx // Test and demonstration app (system clipboard interface) Dialogx.cpp // NcDialog-based test application Dialogx.hpp // Dialogx definitions and data Makefile // Build Dialogx test application Wayclip.cpp // Console-based test application Wayclip.hpp // Wayclip definitions and data wMakefile // Build Wayclip test application (gmake -f wMakefile) /Keymap // Generate and test the application keymap Keymap.cpp // Test application main() Keymap.hpp // Definition of Keymap class KeymapAuto.cpp // Auto-generation source code Makefile // Build Keymap test application NCursesKeyDef_auto.hpp // Automatically generated keycode definitions TransTable2.hpp // Automatically generated table of keycode names NCursesKeyDef(F30).hpp // Generated keycode definitions from Fedora30 /Texinfo // API documentation in Texinfo format ncdialogapi.info // NcDialog API documentation in 'info' format ncdialogapi.html // NcDialog API documentation in HTML format infodoc-styles.css // CSS style definition required by the HTML docs // Texinfo documentation source files (by chapter) Ch00_NcDialogAPI.texi Ch01_Introduction.texi Ch02_OperationalOverview.texi Ch03_YourFirstApplication.texi Ch04_NCursesEngine.texi Ch05_NcWindowMeta-layer.texi Ch06_NcDialogClassDefinition.texi Ch06w_WaylandCB.texi Ch07_gStringTextTool.texi Ch08_ApplicationExamples.texi Ch09_Installation.texi Ch10_TechnicalSupport.texi same_author.texi // Description of additional software by same author texi_macros.texi // Macro definitions for Texinfo documentation gpl-3.0.texi // GNU General Public License fdl-1.3.texi // Free Documentation License Makefile // Build the NcDialog API documentation applycss // Apply CSS style to the HTML-format documentation applycss_response.txt gsBase.texi // Stand-alone documentation for gString class only gstring.html gstring.info gstring_response.txt wcBase.texi // Stand-alone documentation for WaylandCB class only waylandcb.html waylandcb.info Note: Post-processing of the HTML-format documentation requires the "Infodoc" package, available as a separate download. /Misc // Additional examples, and other trivia
Each of these is a plain-text file which can be read with any text editor, or a text reader such as ’less’. Type the following command:
This will open the Help file and bring you to the parent node of this page.
Follow the instructions for installing, building and testing the NcDialog API,
and for installing the online documentation.
Alternatively, you can use the HTML version of the documentation by loading ’NcDialog/Texinfo/ncdialogapi.html’ into your favorite browser.
Next: Online Documentation, Previous: Unpack the Archive, Up: Installation [Contents][Index]
Example: g++ --version You should see something like: g++ (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1) Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Example: ls -l /usr/include/ncurses.h lrwxrwxrwx. 1 root root 8 Feb 1 2019 /usr/include/ncurses.h -> curses.h grep 'NCURSES_VERSION_' /usr/include/ncurses.h Depending on your installed version, you should see something similar to the following, with the appropriate major and minor version numbers. #define NCURSES_VERSION_MAJOR 5 #define NCURSES_VERSION_MINOR 9 #define NCURSES_VERSION_PATCH 20130511 Or: #define NCURSES_VERSION_MAJOR 6 #define NCURSES_VERSION_MINOR 2 #define NCURSES_VERSION_PATCH 20200212 Example: ls -l /usr/lib64/libncursesw* You should see something like: /usr/lib64/libncursesw.so /usr/lib64/libncursesw.so.6 -> libncursesw.so.6.2 /usr/lib64/libncursesw.so.6.2
If the indicated files are not present or if the installed version is not up-to-date please see Libraries for ncurses.
The “terminfo” database used, as well as the system’s (deprecated) “termcap” file can also affect these keycode definitions.
Please see Keymap App for a detailed discussion of the affected keycodes.
gmake
The build should be clean with no errors and no warnings.
If there are errors, then the most likely cause would be that the compiler cannot find some necessary headers or cannot find the ’ncursesw’ library. Check your LIB_PATH and other environment variables.
./Dialog1
If the application opens smoothly, then you are ready to begin using the NcDialog API library in your own applications.
If the application does not run, then verify that all necessary libraries are installed on your system.
This will report all the libraries needed by the application.
If one or more of these libraries is not installed, you will need to update
your C++ compiler installation.
Next: Libraries for ncurses, Previous: Building the API Library, Up: Installation [Contents][Index]
The NcDialog API is distributed with full documentation created using Texinfo, the standard documentation engine for GNU/Linux.
The documentation is distributed in two formats:
If the documentation has been integrated into the ’info’ documentation
database, then the documentation may be accessed from any directory.
See Integrating the Documentation.
Note: The HTML version of this document is optimized for
Firefox(tm) version 71 and higher, Chromium(tm) v:71, and Opera(tm) 65.0.
All of these browsers do an acceptable job of rendering the document.
(If you are using IE-11 or MS-Edge(tm), you need therapy.)
The HTML documentation is generated directly by the ’makeinfo’ utility and receives post-processing and CSS style from Software Sam’s ’Infodoc’ utility (available as a separate package download).
The only requirement for using the HTML documentation is that the CSS style definitions ’infodoc-styles.css’ be in the same directory as the HTML document.
Adding an ’info’ document to the info-reader database (or removing a document from the database) is easy, but it does require ’SUPERUSER’ (’root’) user privilege. If this makes you nervous, please make a backup copy of the ’dir’ (info directory) file before modifying it.
Note that installation of the API documentation is not necessary, but is recommended. Not only is it convenient to have the API documentation always available, but one day, you will be installing the documentation for your own applications, and you will already know how to do it. How cool is that!
For global system users, this is typically: /usr/share/info/dir
This will open the top-level menu of the Info system.
Verify that your new entry is beautifully displayed and that
the new Info document is accessible:
First, press the forward-slash key ’/’ (search)
Then, type: NcDialog Library API (and press ENTER)
The highlight should now be on the menu entry.
Press ENTER (RET) key again, and verify that the main page of the NcDialog
documentation is displayed.
Then, exit the Info system: ’q’ (quit).
If you want to remove the menu entry, use the command:
Next: Updating Texinfo Docs, Previous: Online Documentation, Up: Installation [Contents][Index]
The NcDialog API requires version 6.4 or higher of the 'ncursesw' developer’s libraries and header files.
The 'ncurses' runtime (dynamic-load) libraries are very likely installed by default in your Linux distribution package because many standard applications and utility programs rely upon them. However, the header files and link libraries needed to build an ncurses-based application or the NcDialog library itself, as well as the 'ncurses' online documentation may not have been installed by default.
The easiest way to determine whether the needed libraries and other files have been installed is to attempt a build of one of the NcDialog test applications. Navigate to the ’NcDialog/Dialog1’ directory and type the following:
If you get a clean compile and the application runs, you’re ready to go, but if you get a message that some needed file was not found (probably ’ncurses.h’), then you will need to install the developer’s version of 'ncursesw'.
There are three primary ways to do this:
ncurses-6.4*.rpm (package probably already installed)
ncurses-devel-6.4*.rpm (install this one (double-click it))
ncurses-base-6.4*.rpm (a dependency of the others)
ncurses-libs-6.4*.rpm (a dependency of the others)
ncurses-6.4(your flavor).rpm
Example: ncurses-6.2-4.20200222.fc34.x86_64.rpm
Specifically, if the '.h' files are not seen by the compiler, or
if the link library specified during link with the '-lncursesw'
switch is not seen by your linker, you may need to:
Official Download:
ftp://ftp.gnu.org/gnu/ncurses/
Download from Maintainer:
ftp://ftp.invisible-island.net/ncurses/ncurses.tar.gz
https://invisible-mirror.net/archives/ncurses/
Unless you enjoy living on the bleeding edge of software development,
it is strongly recommended that you download the latest stable
version of the software. The archive name format should be something like:
ncurses-6.2_2020_02_12.tar.gz or
ncurses-6.2.tar.gz
Technical Note: The source archive may be double-zipped—that is, the zipped tar archive may be zipped again by the internet transport layer. If so, the 'tar' utility may not be able to unpack the archive directly. If 'tar' reports that it is not a valid archive format, then first use 'gunzip' to expand the outer archive and then use the 'tar' utility normally. Note that the GUI Archive Manager is accustomed to this kind of foolishness and will correctly unpack a double-zipped archive without complaint.
The configuration and build options for the ncurses libraries, header files and various support utilities are designed for installation on multiple platforms. There are dozens of options for specific circumstances. While the instructions are well written, the first exposure to all these options can be quite overwhelming. Fortunately, most of the options can simply be ignored by most developers.
To ease you into the ncurses world, the following explanation is for a common set of build options for a standard Linux distro on a vanilla, Wintel x86-64 system. While this sequence should work for a majority of systems, it should be seen as an example, not as definitive configuration and installation instructions.
— Unpack the archive in a clean temporary directory.
tar -xjvf ncurses-6.2.tar.gz
(See note above about possible double-zipped archives.)The archive will be unpacked to a subdirectory in the current directory:
ncurses-6.2
Go to that directory:
cd ncurses-6.2
— Read the 'INSTALL' file for detailed instructions:
less INSTALL
— Configure the build for the specific target system.
(all on one line)
./configure --prefix="/usr" --enable-widec --with-shared
--without-debug --enable-overwrite --with-xterm-kbs=DEL
Explanation of options used
--prefix="/usr"
The "--prefix" option specifies the base target directory for installation, which overrides the default target-directory assignment.
If the system includes previously-installed ncurses libraries, then by default the configuration utility will try to find them and configure installation for that directory. This will usually be the '/usr' directory. Note however that if no existing ncurses libraries are found, then '/usr/local' will be the default base target directory.--enable-widec
Build the libraries to support “wide” characters, i.e. the full UTF-8 character set.
Please note that libraries built for the “standard” (narrow, 8-bit i.e. English-only) character set are no longer relevant for modern development, and the NcDialog API does not use them. If, however, you have legacy ncurses applications installed on your system, you may need to perform a separate build and a separate install for the narrow shared libraries. See the ncurses package 'INSTALL' file for details on how to do this.--with-shared
Build the shared (dynamic-load libraries). These libraries are loaded when the application is invoked.
While it is possible to compile the application as a “static build”, which does not reference the shared libraries, the binary executable will run only on target systems with the same hardware as the system which compiled the application.--without-debug
Do not build libraries that include ncurses debugging information.
Debugging libraries are used by those developers who assist the maintainer of the ncurses package, Thomas E. Dickey, in debugging pre-release versions of the ncurses libraries.--enable-overwrite
Enable overwrite of existing file versions by the newly-created files.--with-xterm-kbs=DEL
Specify that the Backspace key is to be defined as the ASCII Delete key.
Definition of the Backspace key under UNIX/Linux has been a problem since the days of punched-paper-tape inputs. Most terminal emulation programs define the Backspace key as the ASCII DEL control character (0x1F). By default, the ncurses build defines the Backspace key as 0x08 (Ctrl+H) for the old-timers who still use Emacs and Vim.
— Build all files from source using the specified configuration.
make
This command processes the master ncurses makefile, "Makefile.in".
— Install the compiled files.
This includes support utilities, header files, static (link) and dynamic (shared) libraries, the terminfo database and documentation (man pages). This can be done either as a single operation OR as a seperate operation for each target directory.
Note that access to the target directory(s) requires root access, so the command is executed with supervisor privilege using “sudo”. See Vocabulary, for a description of the “sudo” command.Simultaneous installation to all target directories:
sudo make installInstall to each target directory individually:
sudo make install.progs
sudo make install.includes
sudo make install.libs
sudo make install.data
sudo make install.man
Previous: Libraries for ncurses, Up: Installation [Contents][Index]
All Linux distributions include the ’info’ (Texinfo) documentation reader; however, if you want to update the NcDialog API’s documentation, you will also need the ’makeinfo’ application to translate the documentation source text (’.texi’ format) into the format needed by the ’info’ reader (’.info’ format), or into other output formats, such as HTML.
’makeinfo’ (and related utilities) may, or may not be installed by
default on your system. ’Texinfo’ is almost certainly installed on your
system, and will be reported as installed, but the ’makeinfo’ program
may be mysteriously missing. (The folks at Fedora love their little jokes.)
Open a terminal window and type makeinfo --version
. If ’makeinfo’ is
installed, it will respond.
If you get a message: ’makeinfo: command not found’, don’t worry. Simply
reinstall the Texinfo package using your command-line update manager. The
command-line update manager is necessary in this case because the GUI
application, (’Software’ under Fedora) will simply tell you that the package
is already installed.
Fedora, CentOS, RedHat: ’sudo dnf install texinfo’
Ubuntu, Debian, Mint : ’sudo apt-get install texinfo’
Official Download: ftp://ftp.gnu.org/gnu/texinfo/
Whether you are rebuilding the NcDialog API documentation or creating documentation for your own applications, you will need to invoke the ’makeinfo’ utility. (See the previous section for installing makeinfo.)
For the NcDialog API, the documentation is built in two formats: ’info’ format and HTML format.
ncdialogapi.info
ncdialogapi.html
NOTE: To rebuild the HTML document, you must have previously installed the ’idpp’ utility which performs post-processing on the raw HTML document generated by ’makeinfo’. Please see below for more information on applying CSS style.
Navigate to the directory which contains the documentation source.
cd NcDialog/Texinfo
Build the documents.
gmake
./applycss
This will build the documentation in both ’info’ and HTML formats,
and will apply CSS styling to the HTML document.
If you want to rebuild only the standalone gString-class documentation,
use the following command:
gmake gsdoc
Note that this also requires the ’idpp’ post-processing utility.
If you want to rebuild only the standalone WaylandCB-class documentation,
use the following command:
gmake wcdoc
Note that this also requires the ’idpp’ post-processing utility.
Post-processing and CSS style definitions must be applied to the raw (and ugly) HTML document generated by ’makeinfo’. This HTML post-processing is performed using ’idpp’, the InfoDoc Post-Processing utility.
Download the ‘infodoc-styles’ package from the author’s website. Then build and install the executable file. This is not painful, and can usually be accomplished in about ten minutes.
This installation is also recommended so you can style your own Texinfo documentation.
Post-processing consists of compensating for the uninspired HTML formatting of the raw document, AND applying CSS style in the form of an external style definition file: infodoc-styles.css.
Applying CSS style:
Please visit www.SoftwareSam.us to download the ’infodoc-styles’ package. (see Technical Support)
Next: Copyright Notice, Previous: Installation, Up: NcDialog Library API [Contents][Index]
The NcDialog API grew from an experiment in accessing the low-level ’ncurses’ primitive (and we do mean primitive) functions.
In the past, your author had written a similar library for System V(tm) UNIX, and another for DOS(tm) in C and x86 assembler; however, UNIX is so 1970s, and DOS(tm) died a merciful death shortly after the release of Windows NT(tm), so we moved on to the Linux world.
Your author had used ’curses’ under System V(tm) and Solaris(tm), so we thought it would be an easy transition. Oh, how easily we are lulled into a sense of our own infallibility. The first version of NcDialog supported only ASCII (English) text, and was rather straightforward. The move to Beijing in 2009, however, forced us to reevaluate our xenophobic arrogance and to make the necessary modifications to support the entire UTF-8 character set.
"Internationalization of user interfaces is not for the timid, nor for the impatient." -- The Software Samurai - 06 August, 2011
All class methods have been tested with the languages the author knows:
English, Spanish, Vietnamese, and Chinese (simplified).
(We didn’t bother with Latin, Classical Greek or Sanskrit because very
few people who are over 1,000 years old use computers anyway.)
Snippets of other languages such as Russian, Polish, Japanese, Korean, Arabic, Hebrew, and especially Yiddish, (as an accessible RTL language) were used in the interface testing. Comprehensive support for every language would require more expertise than your author can claim; however, the basic display and editing functionality has been tested to the limits of our modest education. If the NcDialog class does not support your language as well as you would hope, please let us know, and we can work together for improvements.
NcDialog has gone through several major iterations on its way to the present release. If you are using an older version, it is strongly recommended that you update your source to the latest release. Many squashed bugs, additional functionality and improved documentation will be your reward.
FileMangler performs all basic file management tasks, as well as performing scheduled and ad-hoc file backup and synchronization activities.
FileMangler runs in a console window, and thus provides access to many system tools not available to a GUI application. FileMangler also provides full support for accessing the local Trashcan.
FileMangler is based on the NcDialog API, and thus will run in almost any GNU/Linux or UNIX terminal environment.
The HTML version of this document was formatted using ‘idpp’ and is displayed using the ‘infodoc-styles.css‘ definition file. Many more examples are available on the author’s website.
The gString class is lightweight, consisting of one C++ source
module and one header file. The gString class may be directly
integrated into an application, or may be built as a link library.
The gString class is also embedded within the NcDialog API library
(see above).
Conceptually, Taggit is an audio-file tag editor (metadata editor), and is album oriented rather than file oriented so that all audio files in an album may be edited simultaneously.
Taggit is not intended as a full-featured tag editor; for instance, Taggit does not access online databases of audio tag information. Taggit fully supports tag editing for audio formats: MP3, M4A, OGG/Vorbis and WMA.
The OGG/Vorbis I specification is supported for all text tags in '.ogg' and '.oga' audio files.
For MP3 audio files, all tag frames of the ID3v2.3 standard are supported, along with some features of ID3v2.4, such as support for UTF-8 text encoding which enables writing text tags in any language.
Taggit is implemented in four(4) user interface languages: Español (Spanish), Zhōngwén (中文) (Chinese, simplified), Tiếng Việt (Vietnamese) and English (U.S.). Additional user interface languages (both LTR and RTL) may be added with minimum effort.
ANSI escape sequences are available for setting foreground and background color, including 3-bit and 4-bit color, 8-bit color, 24-bit (RGB) color, greyscale color, and the aixterm (IBM) extensions.
Text modifiers include bold/faint, italic, underline, double-underline, overline, strikethrough, blinking text (fast/slow), reversed fgnd/bkgnd, and invisible text; as well as commands to disable each of these modifiers.
A suite of cursor-positioning commands and text erasure commands are also supported.
The standard also specifies escape sequences for little-used and seldom-supported options such as Fractur, Ideogram, Framed, Encircled and Alternate-font. The AnsiCmd library implements these escape sequence commands; however, most modern terminal emulators do not support them.
AnsiCmd also provides some common terminal configuration operations such as flexible input buffering options and capture of the Panic Button (break signal).
Also included in the AnsiCmd library are application-level functions such as line-drawing, creation of windowed objects, direct control of the cursor-movent keys and reasonably sophisticated user input methods.
Because this is primarily an experimental project, comprehensive testing of all functionality is integrated into the AnsiCmd library.
‘srcprof’ can be used to profile source code for high-level languages such as C, C++ and Java, as well as various assembly languages and scripting languages such as Python, Perl and Ruby. For a complete list of currently-supported source languages, please see the Source Profiler documentation.
’srcprof’ can be used both as a productivity-measurement tool and as a tool for testing source code quality based on an evaluation of its ‘maintainability’.
Source Profiler is a console-based utility, which runs as either a pure, command-line utility, OR as a dialog application based on the NcDialog API.
WaylandCB is a simple C++ class definition which provides console applications with seemless access to the system clipboard.
The application is specifically designed to be a student exercise in creating applications which incorporate a multi-language user interface. Exercalc is implemented in four(4) user interface languages: Español (Spanish), Zhōngwén (中文) (Chinese, simplified), Tiếng Việt (Vietnamese) and English (U.S.). Additional user interface languages (both LTR and RTL) may be added with minimum effort.
‘dvdrep’ can be used to rescue data from any non-encrypted DVD video source disc that is formatted using the Universal Disc Format (UDF) filesystem (as all commercially produced DVD movies are).
‘dvdrep’ takes a layered approach to the analysis of the source disc. A detailed log file is maintained for each step of the process in case manual intervention is needed at a later step.
DVD Repair is based on the NcDialog API, and thus will run in almost any GNU/Linux or UNIX terminal environment.
NOTE: If you are successfully (or not so successfully) using NcDialog under another Linux/UNIX distribution, please send the author a note about your experiences.
Next: Index, Previous: Technical Support, Up: NcDialog Library API [Contents][Index]
Next: GNU Free Documentation License, Up: Copyright Notice [Contents][Index]
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program—to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
For the developers’ and authors’ protection, the GPL clearly explains that there is no warranty for this free software. For both users’ and authors’ sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users’ freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on the Program.
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work’s System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work’s users, your or third parties’ legal rights to forbid circumvention of technological measures.
You may convey verbatim copies of the Program’s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation’s users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party’s predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor’s “contributor version”.
A contributor’s “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor’s essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient’s use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
The hypothetical commands ‘show w’ and ‘show c’ should show the appropriate parts of the General Public License. Of course, your program’s commands might be different; for a GUI interface, you would use an “about box”.
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see http://www.gnu.org/licenses/.
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read http://www.gnu.org/philosophy/why-not-lgpl.html.
Previous: GNU General Public License, Up: Copyright Notice [Contents][Index]
The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.
The “publisher” means any person or entity that distributes copies of the Document to the public.
A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.
You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.
“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.
“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.
An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
Previous: Copyright Notice, Up: NcDialog Library API [Contents][Index]
Jump to: | 0
1
A B C D E F G H I K L M N O P R S T U V W |
---|
Jump to: | 0
1
A B C D E F G H I K L M N O P R S T U V W |
---|