Skip to content
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

TFC TUI #330

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion exes/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ add_subdirectory(operations)
add_subdirectory(tfcctl)
add_subdirectory(ipc-ruler)
add_subdirectory(signal_source)
add_subdirectory(mqtt-bridge)
add_subdirectory(mqtt-bridge)
add_subdirectory(ttui)
36 changes: 36 additions & 0 deletions exes/ttui/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
add_executable(ttui src/ttui.cpp
src/dbus_screen_manager.hpp
src/dbus_screen_manager.cpp)

find_package(Boost REQUIRED COMPONENTS program_options)
find_package(mp-units CONFIG REQUIRED)
find_package(ftxui CONFIG REQUIRED)

target_link_libraries(ttui
PUBLIC
tfc::ipc
tfc::base
tfc::logger
Boost::program_options
mp-units::core
ftxui::dom
ftxui::screen
ftxui::component
)

include(GNUInstallDirs)
install(
TARGETS
ttui
DESTINATION
${CMAKE_INSTALL_BINDIR}
CONFIGURATIONS Release
)

install(
TARGETS
ttui
DESTINATION
${CMAKE_INSTALL_BINDIR}/debug/
CONFIGURATIONS Debug
)
111 changes: 111 additions & 0 deletions exes/ttui/src/dbus_screen_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "dbus_screen_manager.hpp"
#include <boost/asio.hpp>
#include <iostream>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/bus/match.hpp>
#include <tfc/dbus/sd_bus.hpp>

DBusScreenManager::DBusScreenManager() : screen(ftxui::ScreenInteractive::TerminalOutput()) {}

void DBusScreenManager::Run() {
SetupComponents();
SetupDBusConnection();
ftxui::Loop loop(&screen, renderer);
while (!loop.HasQuitted()) {
loop.RunOnce();
ctx.run_for(std::chrono::milliseconds(10));
}
}

void DBusScreenManager::SetupComponents() {
right_menuz = right_menu();
left_menuz = left_menu();
container = ftxui::Container::Horizontal({ left_menuz, right_menuz });
renderer = Renderer(container, [&] {
return ftxui::vbox({
// -------- Top panel --------------
ftxui::hbox({
// -------- Left Menu --------------
ftxui::vbox({
ftxui::hcenter(ftxui::bold(ftxui::text("Percentage by 10%"))),
ftxui::separator(),
left_menuz->Render(),
}),
ftxui::separator(),
// -------- Right Menu --------------
ftxui::vbox({
ftxui::hcenter(ftxui::bold(ftxui::text("Percentage by 1%"))),
ftxui::separator(),
right_menuz->Render(),
}) | ftxui::flex,
ftxui::separator(),
}),
}) |
ftxui::border | ftxui::flex;
});
}

void DBusScreenManager::SetupDBusConnection() {
connection = std::make_shared<sdbusplus::asio::connection>(ctx, tfc::dbus::sd_bus_open_system_mon());
match = std::make_unique<sdbusplus::bus::match::match>(*connection, "",
[this](sdbusplus::message_t& msg) { this->match_callback(msg); });
auto mc = connection->new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring",
"BecomeMonitor");
mc.append<std::vector<std::string>, uint32_t>({ "path=/com/skaginn3x/Signals" }, 0);
auto reply = connection->call(mc);
if (reply.is_method_error()) {
if (reply.get_error() != nullptr)
throw std::runtime_error(reply.get_error()->message);
throw std::runtime_error("Unknown error");
}
}

void DBusScreenManager::match_callback(sdbusplus::message_t& msg) {
if (msg.get_member() && std::string(msg.get_member()) == "PropertiesChanged") {
std::tuple<std::string, std::vector<std::pair<std::string, std::variant<bool, uint64_t>>>, std::vector<std::string>>
container{};
if (sdbusplus::utility::read_into_tuple(container, msg)) {
std::string const& interface = std::get<0>(container);
auto position = std::find(noticed_interfaces.begin(), noticed_interfaces.end(), interface);
auto value = std::get<1>(container)[0].second;
if (position == noticed_interfaces.end()) {
noticed_interfaces.emplace_back(interface);
values.emplace_back(value);
right_menuz->Render();
} else {
auto index = position - noticed_interfaces.begin();
if (values[index] != value) {
if (index == left_menu_selected) {
values[index] = value;

std::string current_value = std::visit(VariantToString(), values[index]);
entries = { current_value };
right_menuz->Render();
screen.Post(ftxui::Event::Custom);
}
}
}
// std::visit([&interface](auto& value) { std::cout << interface << ": " << value << std::endl; },
// std::get<1>(container)[0].second);
}
}
}

auto DBusScreenManager::left_menu() -> ftxui::Component {
auto option = ftxui::MenuOption::Vertical();

option.on_enter = [this] {
std::string current_value = std::visit(VariantToString(), values[left_menu_selected]);
entries = { current_value };
right_menuz->TakeFocus();
screen.Post(ftxui::Event::Custom);
};

return ftxui::Menu(&noticed_interfaces, &left_menu_selected, option);
}

auto DBusScreenManager::right_menu() -> ftxui::Component {
auto option = ftxui::MenuOption::Vertical();
// option.on_enter = screen.ExitLoopClosure();
return ftxui::Menu(&entries, &right_menu_selected, option);
}
61 changes: 61 additions & 0 deletions exes/ttui/src/dbus_screen_manager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// DBusScreenManager.hpp

#pragma once

#include <boost/asio.hpp>
#include <boost/program_options.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/bus/match.hpp>
#include <string>
#include <variant>
#include <vector>
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Menu, Renderer, ScreenInteractive
#include "ftxui/component/component_options.hpp" // for MenuOption
#include "ftxui/component/loop.hpp" // for Loop
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive

namespace asio = boost::asio;
namespace po = boost::program_options;

class DBusScreenManager {
public:
DBusScreenManager();
void Run();

private:
ftxui::ScreenInteractive screen;
ftxui::Component left_menuz, right_menuz, container;
ftxui::Component renderer;
std::vector<std::string> noticed_interfaces;
std::vector<std::variant<bool, uint64_t>> values;
std::vector<std::string> entries;
int left_menu_selected = 0;
int right_menu_selected = 0;
asio::io_context ctx{};
std::shared_ptr<sdbusplus::asio::connection> connection;
std::__detail::__unique_ptr_t<sdbusplus::bus::match::match> match;

void SetupComponents();
void SetupDBusConnection();
void match_callback(sdbusplus::message_t& msg);
ftxui::Component left_menu();
ftxui::Component right_menu();
struct VariantToString {
std::string operator()(bool v) const { return v ? "true" : "false"; }
std::string operator()(int64_t v) const { return std::to_string(v); }
std::string operator()(uint64_t v) const { return std::to_string(v); }
std::string operator()(double v) const { return std::to_string(v); }
std::string operator()(const std::string& v) const { return v; }
std::string operator()(const std::vector<std::string>& v) const {
std::string result;
for (const auto& elem : v) {
if (!result.empty()) {
result += ", "; // Delimiter between elements
}
result += elem;
}
return result;
}
};
};
28 changes: 28 additions & 0 deletions exes/ttui/src/ttui.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <iostream>
#include <tfc/progbase.hpp>
#include "dbus_screen_manager.hpp"

int main(int argc, char** argv) {
auto description{ tfc::base::default_description() };

std::string signal{};
std::string slot{};
std::vector<std::string> connect;
bool list_signals{};
bool list_slots{};

description.add_options()("signal", po::value<std::string>(&signal), "IPC signal channel (output)")(
"slot", po::value<std::string>(&slot), "IPC slot channel (input)")(
"connect,c", po::value<std::vector<std::string>>(&connect)->multitoken(), "Listen to these slots")(
"list-signals", po::bool_switch(&list_signals), "List all available IPC signals")(
"list-slots", po::bool_switch(&list_slots), "List all available IPC slots");
tfc::base::init(argc, argv, description);
try {
DBusScreenManager sm;
sm.Run();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
9 changes: 9 additions & 0 deletions libs/dbus_util/inc/public/tfc/dbus/sd_bus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,13 @@ static inline auto sd_bus_open_system() -> sd_bus* {
return bus;
}

static inline auto sd_bus_open_system_mon() -> sd_bus* {
sd_bus* bus = nullptr;
if (sd_bus_open_system(&bus) < 0) {
throw std::runtime_error(std::string{ "Unable to open sd-bus, error: " } + strerror(errno));
}
sd_bus_set_monitor(bus, true);
return bus;
}

} // namespace tfc::dbus
1 change: 1 addition & 0 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"boost-program-options",
"boost-stacktrace",
"date",
"ftxui",
"fmt",
{
"name": "glaze",
Expand Down