2024-06-13 03:23 AM - edited 2024-06-13 03:48 AM
I'm updating a text field (textArea with wild card) every tick (only for testing, in practice it will be updated less, and only when invalidated when changed). It updates the field just fine, however the old value remains in the other frame buffer. So the value alternates between the new value and the old value. But only if new text is smaller than old text.
Here was my initial code:
void Screen1View::updatePowerState(const char* str)
{
touchgfx::Unicode::strncpy(textAreaPowerControlStateBuffer, str, TEXTAREAPOWERCONTROLSTATE_SIZE -1);
textAreaPowerControlState.resizeToCurrentText();
textAreaPowerControlState.invalidate()
}
But this code didn't work when increasing the size. So I tried to invalidate by rectangle instead:
void Screen1View::updatePowerState(const char* str)
{
Rect invalidatedArea = textAreaPowerControlState.getRect();
invalidatedArea.x=0; // convert to relative rect
invalidatedArea.y=0; // convert to relative rect
touchgfx::Unicode::strncpy(textAreaPowerControlStateBuffer, str, TEXTAREAPOWERCONTROLSTATE_SIZE -1);
textAreaPowerControlState.resizeToCurrentText();
Rect invalidatedArea2 = textAreaPowerControlState.getRect();
invalidatedArea2.x=0; // convert to relative rect
invalidatedArea2.y=0; // convert to relative rect
invalidatedArea.expandToFit(invalidatedArea2);
textAreaPowerControlState.invalidateRect(invalidatedArea);
}
Even invalidating a very large size doesn't work:
void Screen1View::updatePowerState(const char* str)
{
touchgfx::Unicode::strncpy(textAreaPowerControlStateBuffer, str, TEXTAREAPOWERCONTROLSTATE_SIZE -1);
textAreaPowerControlState.resizeToCurrentText();
//textAreaPowerControlState.invalidate();
Rect invalidatedArea;
invalidatedArea.width = 500;
invalidatedArea.height = 24;
invalidatedArea.x=0;
invalidatedArea.y=0;
textAreaPowerControlState.invalidateRect(invalidatedArea);
}
This does expand, but when shrinking the older text that was to the right of the newer text remains in the other frame buffer.
I invalidate the d-cache by address and use the address of the current frame buffer and the area that has changed. This works flawlessly with animations and clock widget etc. So I don't know why it is not working with a text field.
I was wondering if it is also possible to invalidate only the wildcard area without too much work? It seems pointless to invalidate the entire text when only the wildcard part is updated.
I'm using TouchGFX 4.23.2
I've attached a video.
Solved! Go to Solution.
2024-06-13 04:26 AM
Hello @unsigned_char_array ,
When changing the content of the textArea, the content might be bigger or smaller.
In the case it is smaller, the invalidated area will be smaller, so you won't invalidate the very right part of the text area.
This issue can also happen when moving widgets.
For instance, if you have a box and every ticks you move it down by 1 pixel and then invalidate, the invalidate area will be the new position of the box so the pixel above won't disappear.
To fix the wildcard issue, try to invalidate the textArea before changing the content as well as after invalidating the content like so :
void Screen1View::updatePowerState(const char* str)
{
textAreaPowerControlState.invalidate()
touchgfx::Unicode::strncpy(textAreaPowerControlStateBuffer, str, TEXTAREAPOWERCONTROLSTATE_SIZE -1);
textAreaPowerControlState.resizeToCurrentText();
textAreaPowerControlState.invalidate()
}
If this solves your issue, I invite you to select this comment as "best answer".
Regards,
2024-06-13 04:01 AM
I've found a half working work around. If I append the string with spaces it clears most of the old text. However since the font is not monospaced it sometimes doesn't clear part of the last character. Obviously not the solution.
2024-06-13 04:26 AM
Hello @unsigned_char_array ,
When changing the content of the textArea, the content might be bigger or smaller.
In the case it is smaller, the invalidated area will be smaller, so you won't invalidate the very right part of the text area.
This issue can also happen when moving widgets.
For instance, if you have a box and every ticks you move it down by 1 pixel and then invalidate, the invalidate area will be the new position of the box so the pixel above won't disappear.
To fix the wildcard issue, try to invalidate the textArea before changing the content as well as after invalidating the content like so :
void Screen1View::updatePowerState(const char* str)
{
textAreaPowerControlState.invalidate()
touchgfx::Unicode::strncpy(textAreaPowerControlStateBuffer, str, TEXTAREAPOWERCONTROLSTATE_SIZE -1);
textAreaPowerControlState.resizeToCurrentText();
textAreaPowerControlState.invalidate()
}
If this solves your issue, I invite you to select this comment as "best answer".
Regards,
2024-06-13 05:31 AM
I swear I tried that before, but it wasn't working then (I think I had a typo then and accidentally invalidated a different text field). Now it works! Thanks! I modified your code a bit and use invalidateContent() instead of invalidate() and it still works:
void Screen1View::updatePowerState(const char* str)
{
textAreaPowerControlState.invalidateContent()
touchgfx::Unicode::strncpy(textAreaPowerControlStateBuffer, str, TEXTAREAPOWERCONTROLSTATE_SIZE -1);
textAreaPowerControlState.resizeToCurrentText();
textAreaPowerControlState.invalidateContent()
}
2024-06-13 06:48 AM
It happens to the best of us! ;)
2024-06-13 07:01 AM - edited 2024-06-14 10:00 AM
@GaetanGodart I've made an improvement. I learned a trick from @Martin KJELDSEN of pressing F2 while in the simulator to visualize areas that are invalidated. This showed me the entire text area was invalidated, not just the wildcard part. I actually expected only the wildcard to be updated. I modified the code so it only refreshes the part that changed:
void Screen1View::updatePowerState(const char* str)
{
static int16_t xOffset = -1;
if (xOffset < 0) //first time
{
auto wildcardTemp = textAreaPowerControlState.getWildcard1();
textAreaPowerControlState.setWildcard1(nullptr);
xOffset = textAreaPowerControlState.getTextWidth();
textAreaPowerControlState.setWildcard1(wildcardTemp);
}
Rect invalidatedArea;
invalidatedArea = textAreaPowerControlState.getRect();
invalidatedArea.x = xOffset;
invalidatedArea.y = 0;
invalidatedArea.width -= xOffset;
textAreaPowerControlState.invalidateRect(invalidatedArea);
touchgfx::Unicode::strncpy(textAreaPowerControlStateBuffer, str, TEXTAREAPOWERCONTROLSTATE_SIZE -1);
textAreaPowerControlState.resizeToCurrentText();
invalidatedArea = textAreaPowerControlState.getRect();
invalidatedArea.x = xOffset;
invalidatedArea.y = 0;
invalidatedArea.width -= xOffset;
textAreaPowerControlState.invalidateRect(invalidatedArea);
}
Should be easy to add a method invalidateWildcard() to textArea. If saves redrawing an entire fixed text field when only a small part has actually changed. This is a suggestion for a new feature.
EDIT: invalidateWildcard() would only be simple if the wildcard is the last part of the string and there is only one wildcard. Otherwise the length of the area before and after the wildcard(s) is hard to determine. If it is a multi line string it won't work at all. Better to use fixed strings for fixed parts.
2024-06-13 07:50 AM
That is a great solution indeed.
Here you can find all the features of the simulator : simulator-features
Regards,