Strikethrough text in ncurses - c++

I am developing a terminal TUI application for myself using the ncurses library. (Running on Linux)
I cannot seem to find much info regarding the use of a "strikethrough/strikeout" text attribute when adding a string to a ncurses window using addstr and friends.
The only information I've found online was on this site:
https://midnight-commander.org/ticket/3264
Ncurses will not add [strikethrough text] because the bitfield is already fully packed.
I was wondering if there are any workarounds to this, or any official way to do this.
Any help would be appreciated.
Thanks.

ncurses has 16 bits allocated for video-attributes. SVr4 curses used 8; XOpen Curses added 7. Those 15 are defined for X/Open Curses compatibility.
Referring to the X/Open Curses documentation, there are two sets of definitions:
A_ALTCHARSET Alternate character set
A_BLINK Blinking
A_BOLD Extra bright or bold
A_DIM Half bright
A_INVIS Invisible
A_PROTECT Protected
A_REVERSE Reverse video
A_STANDOUT Best highlighting mode of the terminal
A_UNDERLINE Underlining
and
WA_ALTCHARSET Alternate character set
WA_BLINK Blinking
WA_BOLD Extra bright or bold
WA_DIM Half bright
WA_HORIZONTAL Horizontal highlight
WA_INVIS Invisible
WA_LEFT Left highlight
WA_LOW Low highlight
WA_PROTECT Protected
WA_REVERSE Reverse video
WA_RIGHT Right highlight
WA_STANDOUT Best highlighting mode of the terminal
WA_TOP Top highlight
WA_UNDERLINE Underlining
WA_VERTICAL Vertical highlight
depending on whether the bits are stored in a attr_t or a chtype (X/Open and SVr4 respectively). In ncurses, those are the same (see the manual page), so that it does not matter if one refers to A_BOLD or WA_BOLD (Solaris xpg4 curses does store those differently).
Discounting the A_ vs WA_, the two lists are different. The newer ones from X/Open Curses are rarely used. Since ncurses doesn't know what it looks like on the screen, someone could add the corresponding terminfo capability to a terminal description and ncurses would handle it.
The terminfo manual page mentions these:
The XSI Curses standard added these hardcopy capabilities. They were
used in some post-4.1 versions of System V curses, e.g., Solaris 2.5
and IRIX 6.x. Except for YI, the ncurses termcap names for them are
invented. According to the XSI Curses standard, they have no termcap
names. If your compiled terminfo entries use these, they may not be
binary-compatible with System V terminfo entries after SVr4.1; beware!
(Explaining how to modify a terminal description can be found in thousands of webpages, and is off-topic for this forum).

Possible attributes in ncurses are:
A_NORMAL Normal display (no highlight)
A_STANDOUT Best highlighting mode of the terminal.
A_UNDERLINE Underlining
A_REVERSE Reverse video
A_BLINK Blinking
A_DIM Half bright
A_BOLD Extra bright or bold
A_PROTECT Protected mode
A_INVIS Invisible or blank mode
A_ALTCHARSET Alternate character set
A_CHARTEXT Bit−mask to extract a character
COLOR_PAIR(n) Color−pair number n
Functions like attron(), attroff(), attrset() may be used to work with attributes,
Strikethrough is not and will not be available.
If you know your terminal and want your software to be able to to work just on such an terminal type AND the terminal supports strikethrough, then you can use control characters or escape sequences to activate such a funcionality.

You can use Unicode for that:
(I know it's an old question, but I had a similar issue, and this is the top result for "curses strikethrough" on Google, so this answer might be helpful to someone.)
I made it work using Python, but the strategy should work in any language:
import curses
def strike(text: str) -> str:
# See <https://stackoverflow.com/a/25244576/4039050>
return "\u0336".join(text) + "\u0336"
def main(stdscr):
message = "The quick brown fox jumps over the lazy dog."
stdscr.addstr(strike(message))
stdscr.refresh()
stdscr.getch()
if __name__ == "__main__":
curses.wrapper(main)

Related

How to move cursor position when printing data in Linux Terminal using C++? [duplicate]

I'm currently designing a CLI interface for linux, and for various reasons I am not able to use ncurses. I am using exclusively C++ and the Qt framework.
Therefore, in order to have a user-friendly interface, I have to run this getch loop in a separate thread:
https://stackoverflow.com/a/912796/3605689
Which basically means I have to implement all basic functionalities (such as backspace) by myself. I have already implemented command completion and command history(like when you press tab or uparrow/downarrow in linux), but I can't figure out how to implement leftarrow/rightarrow (aka seeking through the typeahead).
Normally, I implement it like this: upon every gech which is not equal to -1, I check whether the user has pressed a special key (one that modifies the typeahead somehow). I then clear the stdout using the following function:
void inputobject::clear_line(int nletters)
{
QTextStream(stdout) << "\033[2K";
for(int i = 0; i < nletters;i++){
QTextStream(stdout) << "\b";
}
rewind(stdout);
}
And replace it with something else, effectively simulating the typeahead. For example, in the case of backspace, I would save the command call clear_line, and print the command out again, just with one less letter, behaving exactly as a normal console application would.
My real problem is with the cursor, in the case of left/rightarrow, I need to move the cursor visual in order to be able to indicate where in the text is the user seeking:
Because of the nature of how I rewrite the given stdout line to simulate the typeahead, it does not really matter where the cursor REALLY is, as long as it stays on the same line - it is just the visual that matters. How can I achieve moving the cursor visual on linux?
The answer was provided in the comment by Evilruff:
Cursor Movement
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
Position the Cursor:
\033[;H
Or
\033[L;Cf
puts the cursor at line L and column C.
Move the cursor up N lines:
\033[NA
Move the cursor down N lines:
\033[NB
Move the cursor forward N columns:
\033[NC
Move the cursor backward N columns:
\033[ND
Clear the screen, move to (0,0):
\033[2J
Erase to end of line:
\033[K
Save cursor position:
\033[s
Restore cursor position:
\033[u
Not using ncurses and co is a serious limitation.
It is hell to make correct input/output on shell for displaying anything.
The only others real solutions (I can't think as a solution to reimplement a ncurse-like library) I think of are:
making call to dialog (for some example www.linuxjournal.com/article/2807 and for the doc: http://linux.die.net/man/1/dialog)
using the framebuffer mecanism with Qt4 (here)

What is the argument for Graphics.set_font from the OCaml Graphics package?

I'm trying to use the Ocaml Graphics package. I want to create a GUI for my chat server application. My code is:
let window = Graphics.open_graph "";
Graphics.set_window_title "caml-chat";
Graphics.set_font "ubuntu";
Graphics.set_text_size 12;
Graphics.draw_string "hello!"
However, Graphics.set_font "ubuntu" does not work. The documentation says that the string argument is system dependent, but I cannot find any more information than that. The only mention I found was in the answers to this question, and it didn't work.
Does anyone know anything else about setting the font? (Or can point me in the direction of a simple graphics library with better documentation?)
Although you didn't specify your system, I will assume that it is Linux (I doubt that Windows has an ubuntu font).
On Linux, the set_font function passes the argument to the X Lib's XLoadFont function. You can use the fc-list or xfontsel utilities to query for the available fonts on your system, or call directly to the XListFonts function.
For example,
fc-list | cut -d: -f2 | sort -u
will give you a list of font families, which you can pass to set_font function. Some lines will have more than one family per line, separated with comman (,). There are many more options, you can specify various styles, sizes, etc. But this is all out of the scope. You can the fontconfig guide to learn more about the font subsystem. For example, [here], at the section "Font Names", you can find the explanation of how the font name is constructed.

Terminal mock for unit-testing python curses programs?

I am writing an interactive terminal program using Python curses. I'd like to write unit tests for its functionalities such as drawing custom pads, controlling font colors, scrolling, and resizing responses. But after some tries and searches, I couldn't find a way to write such unit tests without actually invoking the terminal; I couldn't find a function in curses to read the content of the screen, either.
Is there a mock terminal for Python curses that serves these unit testing needs?
You can ask curses what it thinks is on the screen:
inch, winch, mvinch, mvwinch - get a character and
attributes from a curses window
inchstr, inchnstr, winchstr, winchnstr, mvinchstr,
mvinchnstr, mvwinchstr, mvwinchnstr - get a string of
characters (and attributes) from a curses window
instr, innstr, winstr, winnstr, mvinstr, mvinnstr, mvwin-
str, mvwinnstr - get a string of characters from a curses
window
The Python binding provides a way to use those functions (not complete, but sufficient):
window.inch([y, x])
Return the character at the given position in the window. The bottom 8 bits are the character proper, and upper bits are the attributes.
window.instr([n]) window.instr(y, x[, n])
Return a string of characters, extracted from the window starting at the current cursor position, or at y, x if specified. Attributes are stripped from the characters. If n is specified, instr() returns a string at most n characters long (exclusive of the trailing NUL).

Linux - moving the console cursor visual

I'm currently designing a CLI interface for linux, and for various reasons I am not able to use ncurses. I am using exclusively C++ and the Qt framework.
Therefore, in order to have a user-friendly interface, I have to run this getch loop in a separate thread:
https://stackoverflow.com/a/912796/3605689
Which basically means I have to implement all basic functionalities (such as backspace) by myself. I have already implemented command completion and command history(like when you press tab or uparrow/downarrow in linux), but I can't figure out how to implement leftarrow/rightarrow (aka seeking through the typeahead).
Normally, I implement it like this: upon every gech which is not equal to -1, I check whether the user has pressed a special key (one that modifies the typeahead somehow). I then clear the stdout using the following function:
void inputobject::clear_line(int nletters)
{
QTextStream(stdout) << "\033[2K";
for(int i = 0; i < nletters;i++){
QTextStream(stdout) << "\b";
}
rewind(stdout);
}
And replace it with something else, effectively simulating the typeahead. For example, in the case of backspace, I would save the command call clear_line, and print the command out again, just with one less letter, behaving exactly as a normal console application would.
My real problem is with the cursor, in the case of left/rightarrow, I need to move the cursor visual in order to be able to indicate where in the text is the user seeking:
Because of the nature of how I rewrite the given stdout line to simulate the typeahead, it does not really matter where the cursor REALLY is, as long as it stays on the same line - it is just the visual that matters. How can I achieve moving the cursor visual on linux?
The answer was provided in the comment by Evilruff:
Cursor Movement
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
Position the Cursor:
\033[;H
Or
\033[L;Cf
puts the cursor at line L and column C.
Move the cursor up N lines:
\033[NA
Move the cursor down N lines:
\033[NB
Move the cursor forward N columns:
\033[NC
Move the cursor backward N columns:
\033[ND
Clear the screen, move to (0,0):
\033[2J
Erase to end of line:
\033[K
Save cursor position:
\033[s
Restore cursor position:
\033[u
Not using ncurses and co is a serious limitation.
It is hell to make correct input/output on shell for displaying anything.
The only others real solutions (I can't think as a solution to reimplement a ncurse-like library) I think of are:
making call to dialog (for some example www.linuxjournal.com/article/2807 and for the doc: http://linux.die.net/man/1/dialog)
using the framebuffer mecanism with Qt4 (here)

Defining whether the current system locale is RTL or LTR

We develop a Windows API app where there is a context menu with nested submenus. We localize the app in several languages, including Hebrew.
As keyboard support is a must for us, we need to know whether the submenu should be opened upon right arrow (LTR) or left arrow (RTL) keypress.
Our developer does use the TrackPopupMenu() function described here on MSDN, but he needs to know when to set the TPM_LAYOUTRTL flag.
So the question is: how to define whether the current system locale is LTR or RTL to handle the menus properly?
I'm answering since we have found a solution (and a comment confirmed we are on the right way).
In order to define whether the current system locale is RTL or LTR, we should use GetLocaleInfoEx with LOCALE_IREADINGLAYOUT. MSDN says the following about it:
Windows 7 and later: The reading layout for text. Possible values are defined in the following table.
Possible values actually are:
0 — left-to-right (as in English);
1 — right-to-left (as in Hebrew or Arabic);
2 — Either read vertically from top to bottom with columns going from right to left, or read in horizontal rows from left to right (as in Japanese);
3 — Read vertically from top to bottom with columns going from left to right (as in Mongolian).
We use the following in-house code:
bool IsCurrentInputLanguageRTL ( void )
{
bool ret=false;
auto layout = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), NULL));
auto lcid=MAKELCID(LOWORD(layout),SORT_DEFAULT);
LOCALESIGNATURE localesig;
// Windows XP and higher.
// Unicode subset bit fields: https://msdn.microsoft.com/en-us/library/windows/desktop/dd374090(v=vs.85).aspx
// Bit 123: Windows 2000 and later - Layout progress, horizontal from right to left.
if(GetLocaleInfoW(lcid,LOCALE_FONTSIGNATURE,(LPWSTR)&localesig,sizeof(localesig)/sizeof(WCHAR)) != 0)
ret = (localesig.lsUsb[3] & 0x08000000)!=0;
return ret;
}