2022-10-15 06:42 PM
The Problem (Initially)
A TextArea with one wildcard is used to display a value centered in its field. When a larger value is overwritten with a smaller value, the new value is centered in the TextArea, but a “residue�? of the previous, larger value, remains visible on both sides.
TGFX Forum Response
The forum response referred to a section of the TGFX 4.20 online documentation (section not present in 4.17 document) regarding invalidation:
Invalidation
When you change the size of a Widget you must invalidate the parts of the screen that needs to be redrawn. If you are making a widget bigger, you can just invalidate the new size. If you are making a Widget smaller, you should invalidate it before changing the size:
// Expand the Box, invalidate after to get the new size redrawn
myBox.expand(10);
myBox.invalidate();
...
// Reduce the Box to small size, invalidate before, to get background redrawn
myBox.invalidate();
myBox.myBox.setPosition(10, 10, 200, 100);
Remember that when you invalidate a Widget, the area on the screen that is occupied by the Widget (at that time) is redrawn in the next draw phase. This means if you invalidate a Widget, and then make it smaller, the parts of other widgets (behind) that are now visible, will be redrawn, not only the Widget that you invalidate.
On reflection, this seems almost obvious, and makes perfect sense.
But What About...
The above works fine when the before and after size of the objects in question are known before an object is resized, in particular for text with a wildcard which is resized by a call to a function such as resizeToCurrentTextWithAlignment(). As the example code above illustrates, the order of resize and invalidate depends on previous knowledge of the before and after sizes. And, for text, the only apparent (unless I missed it in my search of the documentation) means of doing so for a new text replacing and older text would be something like:
uint16_t oldWidth = textArea.getTextWidth();
touchgfx::Unicode::snprintf(textAreaBuffer, TEXTAREA_SIZE, newText);
textAreaBuffer[TEXTAREA_SIZE-1] = 0; // ensure string termination
textArea.resizeToCurrentTextWithAlignment();
uint16_t newWidth = textArea.getTextWidth();
So now we know both the old and new text widths, but the new text has already been resized, so we can't apply the rule to invalidate() before if the new value is smaller, and after if the new value is larger.
And, in the case of text, how are we to know which is the case? One could use the before and after lengths of text in the buffer in some cases, but this would clearly not work in cases where they were the same, or where, with proportional fonts, two strings of the same string length may occupy different screen width, with some strings of lesser string lengths occupy greater widths, as in these cases:
same length, different widths
ABCDEFG
abcdefg
longer string length, shorter width
flows
frills
touchgfx::Unicode::snprintf(textAreaBuffer, TEXTAREA_SIZE, "abcdefg");
textAreaBuffer[TEXTAREA_SIZE-1] = 0; // ensure string termination
textArea.resizeToCurrentTextWithAlignment();
textArea.invalidate();
A Case in Point
We have 2 strings of the same length. Initially the TextArea (one wildcard) in the red box contains “ABCDEFG�?, all caps. When we click the bottom button to execute the following code:
touchgfx::Unicode::snprintf(textAreaBuffer, TEXTAREA_SIZE, "abcdefg");
textAreaBuffer[TEXTAREA_SIZE-1] = 0; // ensure string termination
textArea.resizeToCurrentTextWithAlignment();
textArea.invalidate();
This is the problem outlined in the initial forum post.
When, as suggested, we change the resize/invalidate order:
textArea.invalidate();
textArea.resizeToCurrentTextWithAlignment();
We get the desired result:
Coding for Both Cases
Since we can't know the width of a replacing string until we resize (I welcome any comments indicating something I've missed in the documentation or notes that may provide another, cleaner means of doing so), I've found the following approach to work in both cases:
Case 1: New Text is Narrower
uint16_t oldWidth = textArea.getTextWidth();
textArea.invalidate();
touchgfx::Unicode::snprintf(textAreaBuffer, TEXTAREA_SIZE, "abcdefg");
textAreaBuffer[TEXTAREA_SIZE-1] = 0; // ensure string termination
textArea.resizeToCurrentTextWithAlignment();
uint16_t newWidth = textArea.getTextWidth();
if (newWidth > oldWidth) {
textArea.invalidate();
}
Case 2: New Text is Wider
uint16_t oldWidth = textArea.getTextWidth();
textArea.invalidate();
touchgfx::Unicode::snprintf(textAreaBuffer, TEXTAREA_SIZE, "ABCDEFG");
textAreaBuffer[TEXTAREA_SIZE-1] = 0; // ensure string termination
textArea.resizeToCurrentTextWithAlignment();
uint16_t newWidth = textArea.getTextWidth();
if (newWidth > oldWidth) {
textArea.invalidate();
}
2022-10-16 12:58 AM
I simply use and dont have trouble
textArea1.setWildcard(textArea1Buffer);
textArea1.invalidate();
textArea1.resizeToCurrentTextWithAlignment();
textArea1.invalidate();
2022-10-16 02:25 PM
Yes, that's basically the same approach without the check on width after resizing.
I do think, however, that a discussion of the need for this approach should be added to the online documentation (https://support.touchgfx.com/4.20/docs/development/ui-development/touchgfx-engine-features/position-size#invalidation) which assumes that one knows in advance whether the new size will be larger or smaller, in which case a single a resize and single invalidate, in the right order, is sufficient.
Thanks for your response.