-
-
Notifications
You must be signed in to change notification settings - Fork 390
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FTXUI multiple logging windows #14
Comments
Hi, thank for using the library! I am not sure to understand what you call a windows. If you want to put several element together vertically, you can use a vertical box => vbox Maybe the "package manager" example could be what you want: Maybe the starter project could be close to what you want: |
@ArthurSonzogni Thanks for the fast response. |
I see! I think you can keep track in "n" vector of the lines you want draw. Let call this your "model": std::vector<std::wstring> data_box_1;
std::vector<std::wstring> data_box_2;
std::vector<std::wstring> data_box_3 Let's create a function to render your model: auto render = [&](){
std::vector<Element> box_1;
for(auto& line : data_box_1)
entries.push_back(text(line))
// [...] Same for box_2 and box_3.
return
hbox(
window(text(L" box_1 "), vbox(std::move(box_1))),
window(text(L" box_2 "), vbox(std::move(box_2))),
window(text(L" box_3 "), vbox(std::move(box_3)))
);
}; Then let' create a function to refresh the screen. You can call it everytime you update your model. std::string reset_position;
auto refresh = [&](){
auto document = render();
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << reset_position << screen.ToString() << std::flush;
reset_position = screen.ResetPosition();
}; You can use the example: |
If you want your application to respond to the user event you have to use the components from the "component" directory. |
@ArthurSonzogni Thanks a lot. I had to extend such a template to create a generic logger. Check the result in asciinema: https://asciinema.org/a/318630 or in the gif below. This sort of reactiveness could be useful for more real-time or dynamic components on FTXUI. Particularly for applications which do not have user interaction, but you need APIs to easily interact with the UI components. The full code with this custom component is shown below. Regards and thanks again. #include <chrono>
#include <iostream>
#include <thread>
#include <vector>
#include <string>
#include <sstream>
#include <iomanip>
#include "ftxui/dom/elements.hpp"
#include "ftxui/screen/screen.hpp"
#include "ftxui/screen/string.hpp"
using namespace std::chrono_literals;
using namespace ftxui;
using namespace std;
class WindowLogger
{
private:
struct MSGS
{
wstring msg;
Color msg_color;
};
vector<Element> line_elements;
vector<MSGS> line_msgs;
wstringstream string_converter;
wstring name;
uint16_t max_lines;
bool enable_flex;
inline auto text_element(wstring msg, Color text_color)
{
if (text_color != Color::Default)
return hbox(text(msg) | color(text_color));
else
return text(msg);
}
template <class... T>
inline void add_msg(Color msg_color, T &&... args)
{
string_converter.seekp(ios::beg); // Reset string stream
((string_converter << forward<T>(args)), ...);
if (line_msgs.size() < max_lines)
{
line_msgs.push_back({string_converter.str(), msg_color});
}
else
{
rotate(line_msgs.begin(), line_msgs.begin() + 1, line_msgs.end());
// insert new text at the last line
line_msgs[line_msgs.size() - 1] = {string_converter.str(), msg_color};
}
}
public:
WindowLogger(const char *window_name, uint16_t max_lines = 1, bool fill_lines = false, bool enable_flex = false)
{
wstringstream s;
s << window_name;
name = s.str();
this->max_lines = max_lines;
line_elements.reserve(max_lines);
line_msgs.reserve(max_lines);
if (fill_lines)
{
// Fill blank lines to keep maximum heigth at start
for (size_t i = 0; i < max_lines; i++)
{
line_msgs.push_back({string_converter.str(), Color::Default});
}
}
this->enable_flex = enable_flex;
};
inline auto element()
{
for (auto &el : line_msgs)
{
line_elements.push_back(text_element(el.msg, el.msg_color));
}
if (enable_flex)
return hbox(
window(text(name), vbox(std::move(line_elements)) | flex));
else
return hbox(
window(text(name), vbox(std::move(line_elements))));
}
template <class... T>
inline void LOG(T &&... args)
{
add_msg(Color::Default, args...);
}
template <class... T>
inline void LOGC(T &&... args)
{
add_msg(Color::Cyan, args...);
}
template <class... T>
inline void LOGR(T &&... args)
{
add_msg(Color::Red, args...);
}
template <class... T>
inline void LOGG(T &&... args)
{
add_msg(Color::Green, args...);
}
template <class... T>
inline void LOGY(T &&... args)
{
add_msg(Color::Yellow, args...);
}
template <class... T>
inline void LOGM(T &&... args)
{
add_msg(Color::Magenta, args...);
}
};
WindowLogger test1(" Information ", 5, true, true);
WindowLogger test2(" Events ", 5, true, true);
int main(int argc, const char *argv[])
{
thread t([&]() {
std::string reset_position;
uint8_t i = 0;
while (true)
{
auto document = window(text(L" Real Time Logs "),
vbox(hbox(test1.element(), test2.element()),
window(hbox(text(L" "), spinner(15, i) | bold, text(L" Summary ")), text(L" Running ") | color(Color::Green))));
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document.get());
std::cout << reset_position << screen.ToString() << std::flush;
reset_position = screen.ResetPosition();
std::this_thread::sleep_for(0.03s);
i += 1 % 10;
}
});
for (;;)
{
test1.LOG("Value: ", rand());
test1.LOGG("Value: ", rand());
test2.LOGM("[", __FILE__, "] ", rand());
test2.LOGY("[", __FILE__, "] ", rand());
std::this_thread::sleep_for(0.1s);
}
std::cout << std::endl;
}
|
That's beautiful! |
Hi, thanks a lot for the library.
I was looking at the examples and wonder if it's possible to create multiple windows which are used solely show log information.
In short, I want to log multiple information in different windows. Is there an optimal design using this library to achieve that?
The maximum I could find is two use two windows, each one having a generic element inside which I have to keep updating the text:
However, "text" element doesn't seem to support multiple lines with "\n".
Is there a suggestion on how to do that?
Regards.
The text was updated successfully, but these errors were encountered: