How do tabs work for text boxes? - c++

I'm making a game gui api and I'm wondering how to implement tabs. I'm using freetype for text. When I try to render '\t' It looks like a square. I'm wondering how tabs are implemented because they are not a fixed width.
Thanks

For a fixed-width font you could compute how many spaces to the next tab stop, but the general solution is to stop rendering when you hit a tab, move to the next tabstop, and then render the text that comes after the tab character starting from there. Where the tabstops are is up to you, but a good default is probably something like every 8 ems.

The simplest strategy is to swap a tab out for a some number of spaces. I.e. when the user pushes tab, pretend they pushed tab four times instead. (Or just print out four spaces, whatever works for you)

Related

Adding new lines and spaces to the old Qt PieMenu

I need to use the old Qt pieMenu, I know it's deprecated, But I've found the source code here, and the installations instructions here(they are in the zip file as well)
I've successfully compiled and ran the examples, but my problem is that I need to add spaces and manipulate the font in the text of the pie menu
for example in the editor.cpp example, these lines insert items to the pie menu with the first parameter as the displayed text :
markMenu->insertItem("Cut", this, SLOT(cut()));
markMenu->insertItem("Del", this, SLOT(del()));
markMenu->insertItem("Copy", this, SLOT(copy()));
I tried setting the lines like this as a test :
markMenu->insertItem("item cut", this, SLOT(cut()));
markMenu->insertItem(tr("Del item"), this, SLOT(del()));
markMenu->insertItem("test on item", this, SLOT(copy()));
and the results are like in the photo(everything after the space character is not displayed)
then I used the '\t' instead of using space directly, it worked as one space instead of a tab.
markMenu->insertItem("test\ton\titem", this, SLOT(copy()));
but when trying to add a new line to the text things didn't work right.
I tried using '\n' but didn't work for me.
Another issue, I was trying to change the font settings of the menu, I tried :
markMenu->setFont(QFont("Arial", 9, 5, true)); // size 9, weight 5, italic
but this didn't affect the font, I tried styleSheets as well but no success.
Any ideas how can I display the new liens and adjust the font of the text?
In the link provided by OP, scrolling to bottom, the source code can be found:
painter.drawText(center.x() + x
- metrics.width(itemText(i)) / 2,
center.y() + y, itemText(i));
Now, a look into the Qt doc. of QPainter::drawText() provides the explanation:
This function does not handle the newline character (\n), as it cannot break text into multiple lines, and it cannot display the newline character. Use the QPainter::drawText() overload that takes a rectangle instead if you want to draw multiple lines of text with the newline character, or if you want the text to be wrapped.
...and a possible fix as well. (Emphasize by me.)
As the source code is available, this can be fixed.
To achieve a proper pre-calculation of boundary rectangle, QFontMetrics can be used.
The answer to How to automatically increase/decrease text size in label in Qt shows an example for text boundary determining with QFontMetrics which even considers automatic word-wrapping.

Tab '\t' has inconsistent spacing

I am using \t to space out my output, but it produces inconsistent spaces.
For example, the following code produces
#include <iostream>
int main()
{
std::cout << "Terms\tResults\tet(%)\tea(%)\n";
return 0;
}
Terms Results et(%) ea(%)
Note the difference in space
Why is this so?
Tab ends each 8th column.
v v v v v
1234567812345678123456781234567812345678
Terms Results et(%) ea(%)
The word "tab" is a prefix from "table" or "tabulate". The purpose of tabs is to generate vertical alignment, such as arrangement of text into table columns, or achieving consistent leading indentation for each paragraph. The purpose of tabs isn't to generate equal horizontal spacing. How much space is generated by a tab depends on how close it is to the next tab stop. That's why you're seeing the "difference in space".
The tab character, and its interpretation on terminal devices, originates with the Tab key on typewriters. The Tab key on a typewriter triggers the motion of the carriage, which comes to rest at at the next tab stop. Typewriter tab stops are configurable by the typist by moving mechanical sliders.
On character display devices, the ASCII TAB character works similarly: it advances to the next tab position. Tab stops are commonly every eight characters. (On some terminals they are configurable via menus in the firmware, or even escape sequences that the host computer can generate).
Modern word processing programs still imitate the typewriter tab stop sliders as wedge-shaped elements that can be added to a "ruler" and moved around.
Try this:
std::cout << "Terms\tResults\tet(%)\tea(%)\n";
std<<cout << "a\tb\t\tc\n"
You should see tabular alignment:
Terms Results et(%) ea(%)
a b c
Note we had to use two tabs after b because the Results et ... field overflowed a tab position.
Ideally, we should move the tab stops around based on the width requirements of the columns in our table. But moving tabs stops around is quite non-portable. For this reason, using tabs for vertical alignment in the output of computer programs is basically not very feasible; columnar formatting is better achieved using spaces. A good formatting function can provide for arbitrary field widths, with left, center or right alignment within a field.

Moving over tab spaces in ncurses

I am creating a basic text editor using ncurses. It can display text fine, but navigating with arrow keys causes a problem when tabs are encountered. Calling move(y, x) will freely move the cursor onto a tab space, where most text editors will jump to the next character. Is there functionality within ncurses to jump over tab spaces or do I need to find a way to do it myself?
You have to do it yourself: wmove moves to the given coordinates, ignoring the way characters are displayed on the screen.
If a destructive (filling with spaces) tab works for your application, then you could use waddch:
If ch is a tab, newline, carriage return or backspace, the
cursor is moved appropriately within the window:
Tabs are considered to be at every eighth column. The
tab interval may be altered by setting the TABSIZE
variable.
For an editor, you probably do not want that behavior (though it probably would be helpful to use the TABSIZE feature when displaying text).

Standard console output without nextline

I would like to write 80 (standard conole width) characters in one line without the cursor go to next line. It is only problem when I want to print 80 characters in the last line of console. It cases scrolling that I dont want.
Take a look:
I dont want the newline. any way to do this? :/
Im on Windows, DEV-C++, using WinApi for colors and moving the cursor (the window resize too).
Thanx for any answers.
Instead of using standard output functions use the Windows Console API to set the cursor position and draw characters. Specifically, take a look at WriteConsoleOutput.
MSDN Console API Docs
The only reason why you are on a new line is because the console is not big enought to support the eighty stars.
So it pushed the cursor to the next line.
through one or two "\b" at the end it moves the cursor back.
For the system-critical console window, the cursor should always stay visible, and the only way for it to do so after you've reached the max number of chars in a line, is to pop up on the next visible line (without actually making any new lines).
filter the output either in the originating program or with another program through a pipe. When you have outputted too many characters on a single line, do whatever you like (i.e., drop characters, overwrite, etc....).

Change tab stop size in rendered HTML using Qt's QLabel class

I'm rendering some HTML in a QT QLabel. The HTML looks like this:
<pre>foo\tbar</pre>
(note that I've put "\t" where there is a tab chracter in the code).
This renders fine, but the tab character appears to be rendered as eight spaces, whereas I want it to be redered as 4. How can I change this without having to change the source HTML?
According to W3 (HTML4):
The horizontal tab character (decimal 9 in [ISO10646] and [ISO88591]) is usually interpreted by visual user agents as the smallest non-zero number of spaces necessary to line characters up along tab stops that are every 8 characters. We strongly discourage using horizontal tabs in preformatted text since it is common practice, when editing, to set the tab-spacing to other values, leading to misaligned documents.
It's implementation-defined, essencially. Most, if not all, browsers/renderers use eight spaces for tabs. This cannot be configured in Qt.
It is, however somewhat trivial to go through your HTML and replace tabs with however many spaces you wish. Write a simple parser for that. Pseudocode:
for each <pre> block {
for each line in block {
position_in_line = 0
for each character in line {
if character is a tab {
remove tab character
do {
add a space character
++position_in_line
} while position_in_line % 8 != 0
} else {
++position_in_line
}
}
}
}
In case you're curious, HTML3 specifies the use of eight-character tabs:
Within <PRE>, the tab should be interpreted to shift the horizontal column position to the next position which is a multiple of 8 on the same line; that is, col := (col+8) mod 8.
While QLabel uses a QTextDocument internally when rendering rich text, it does not allow access to it in it's API. However, since QTextDocument is a QObject, you can try to use
QTextDocument * tl = label->findChild<QTextDocument>();
to get access to it (will work if the QLabel creates the QTextDocument as a (direct or indirect) child of itself).
Once you have a pointer to the text document, you can use the QTextDocument API, e.g. QTextOption::setTabsStop(), to change the tab stops.
The last step is to somehow make the QLabel repaint itself. Probably a call to QWidget::update() suffices, but caching (or worse, recreating the text document) might thward that. In this case, you can register an event listener on the label to adjust the text document just prior to a paintEvent(), but note that the sizeHint() might also change when the tab stops change, so it might be more complicated still.
That said, it's how I'd approach the problem.
Try this:
<pre style="tab-interval:0.5in">foo\tbar</pre>
Could work