Closed cmorganBE closed 3 years ago
Alright, so I've found an example of updating the text at runtime but it involves reading from a variable outside of the scope of the renderer handler function. When doing this I noticed the screen doesn't refresh unless I move the mouse or hit a key. Is there a way to invalidate the screen so the refresh occurs? From a structural standpoint should elements have a way to notify their container when their value is altered?
If you want to write it in a functional way, you don't "modify" at runtime. Instead the function return the right value every time it is called.
For instance: https://github.com/ArthurSonzogni/FTXUI/blob/master/examples/component/slider_rgb.cpp#L19 Gives: https://arthursonzogni.com/FTXUI/examples/?file=./component/slider_rgb.js
(See the text RGB=(125, 125, 125)
)
The ScreenInteractive::Loop() is an event loop. I cause a new frame to be renderer everytime it receives an event. You may want to react to events that aren't handled by this loop, for instance a network fetch. To do this, you can post events yourself to the loop, potentially from a different thread.
screen.PostEvent(Event::Custom)
This is what the homescreen example does: https://github.com/ArthurSonzogni/FTXUI/blob/master/examples/component/homescreen.cpp#L363 https://arthursonzogni.com/FTXUI/examples/?file=./component/homescreen.js
@ArthurSonzogni sending a message was actually what I was thinking in terms of causing the screen redraw loop to run. in my case I have data coming in from an outside source and the UI is static now until I interact with it. Would you accept a PR if I created an example for 'how to cause a refresh' that shows the technique of sending a custom event from a background thread to cause the loop to re-render the screen? Assuming of course the code meets your requirements.
On the same vein, would you accept a PR showing how to compose Components? The use case I have are three columns, each of which has some interactive elements for a particular area of the system. I figured it out pretty quickly from an example that did it and some trial and error but it could be helpful to the next person since it was a big question as to how to group together Elements and Components and have the components work but also not have to put all Components into one physical group.
I am always happy for getting PR!
Either writting some examples/ or updating the documentation: https://arthursonzogni.com/FTXUI/doc/ would be greatly appreciated!
The approach I ended up using was to rebuild the Text() entry using the variable content. In the cases when the content changed without user input a screen.PostEvent(Event::Custom); used to trigger a refresh.
A bit of a beginner question, but how would I do this with a variable from a different class? This is the code I have:
namespace timer {
class Renderer {
...
// Wraps a split into a renderer, with a predetermined layout.
ftxui::Component splitRenderer(timer::Split segment) {
auto split = ftxui::Renderer([=] (bool focused) {
auto _split{ftxui::hbox({
ftxui::text(segment.name),
ftxui::filler() | ftxui::flex,
ftxui::text(segment.pbTime)
})};
if (focused)
_split = _split | ftxui::bgcolor(ftxui::Color::Grey23); // ftxui does not support the `|=` operator
return _split;
});
return split;
};
};
}
And here is the (rather simple) timer::Split
class:
namespace timer {
class Split { public:
// Allows for simpler type declaration, `Split foo("splitName", "splitTime");`
Split(std::string name, std::string pbTime) : name(name), pbTime(pbTime) { }
std::string name;
std::string pbTime;
bool isAhead;
};
}
When setting a text field to a variable in the Renderer
class, it gets updated at runtime just fine.
However, when updating an element in the segment
object, nothing seems to happen. Redrawing manually with screen.PostEvent(Event::Custom)
also does not seem to fix the issue. Does anyone know how I could fix this? I would like to update the segment
object, and have these changes be reflected in the UI.
@IvarWithoutBones, I am not 100% sure understanding the question. My best guess is that you are passing timer::Split by value in Renderer::splitRenderer. As a result, the generated component is working on a copy. Updating the original data, do not affect to copy.
I don't see any examples doing this, which leads me to believe that maybe it isn't possible currently, or maybe I'm missing how to do it. Is it possible?