Files
esDashboard/src/display/ui/hostblock/HostBlock.cpp
T
2026-01-09 21:58:48 +00:00

231 lines
10 KiB
C++

#include "display/ui/hostblock/HostBlock.h"
#include <algorithm>
#include <chrono>
#include "display/ui/bar/Orientation.h"
#include "display/ui/bar/Style.h"
#include "display/ui/theme/Theme.h"
#include "display/ui/text/Helpers.h"
#include "display/graphics/Color.h"
namespace display::ui::hostblock
{
HostBlock::HostBlock(config::server::StyleConfig &config)
: config(config),
cpuBar(
config.hostblock.cpu.width,
config.hostblock.cpu.height,
display::ui::bar::Orientation::Vertical,
display::ui::bar::Style{display::graphics::Color{40, 40, 40}, display::graphics::Color{0, 180, 0}, display::graphics::Color{80, 80, 80}, true}),
cpuTempBar(
config.hostblock.cpu.temperature.width,
config.hostblock.cpu.height,
display::ui::bar::Orientation::Vertical,
display::ui::bar::Style{display::graphics::Color{40, 40, 40}, display::graphics::Color{0, 180, 0}, display::graphics::Color{80, 80, 80}, true}),
memBar(
config.hostblock.width - config.hostblock.padding * 2,
config.hostblock.memory.height,
display::ui::bar::Orientation::Horizontal,
display::ui::bar::Style{display::graphics::Color{40, 40, 40}, display::graphics::Color{0, 120, 200}, display::graphics::Color{80, 80, 80}, true})
{
}
void HostBlock::draw(
display::graphics::Framebuffer &fb,
display::ui::text::Renderer &text,
int x, int y,
const std::string &hostname,
const metrics::Host &metrics)
{
bool online = std::chrono::high_resolution_clock::now() - metrics.packetTimepoint < std::chrono::seconds(5);
// ===== Block background =====
fb.fillRect(x, y, config.hostblock.width, config.hostblock.height, display::ui::theme::hostblock::BACKGROUND);
fb.drawRect(x, y, config.hostblock.width, config.hostblock.height, display::ui::theme::hostblock::BORDER);
int cursorY = y + config.hostblock.padding;
// ===== Header =====
fb.fillRect(
x + config.hostblock.padding,
cursorY,
config.hostblock.width - config.hostblock.padding * 2,
config.hostblock.header.height,
online ? display::ui::theme::hostblock::HEADER : display::graphics::Red());
text.drawTextOutlined(
fb,
x + config.hostblock.padding + 2,
cursorY + config.hostblock.header.height - 1,
hostname,
display::ui::theme::text::TEXT,
display::ui::theme::text::OUTLINE,
display::ui::text::Font{config.hostblock.header.font.name, config.hostblock.header.font.size});
cursorY += config.hostblock.header.height + config.hostblock.gap;
// ===== CPU bars =====
int cpuCount = std::min<int>(metrics.cpu.coreLoads.size(),
config.hostblock.cpu.max_per_row * config.hostblock.cpu.rows);
for (int i = 0; i < cpuCount; ++i)
{
int row = i / config.hostblock.cpu.max_per_row;
int col = i % config.hostblock.cpu.max_per_row;
int bx = x + config.hostblock.padding +
col * (config.hostblock.cpu.width + config.hostblock.cpu.temperature.width - 1 + config.hostblock.cpu.gap_h);
int by = cursorY +
row * (config.hostblock.cpu.height + config.hostblock.cpu.gap_v);
float value = std::clamp(metrics.cpu.coreLoads[i] / 100.0f, 0.0f, 1.0f);
cpuBar.draw(fb, bx, by, value, 0, online);
value = std::clamp((metrics.cpu.coreTemps[i].current - config.hostblock.cpu.temperature.min) / ((metrics.cpu.coreTemps[i].max == 0 ? static_cast<float>(config.hostblock.cpu.temperature.max) : metrics.cpu.coreTemps[i].max) - config.hostblock.cpu.temperature.min), 0.0f, 1.0f);
cpuTempBar.draw(fb, bx + config.hostblock.cpu.width - 1, by, value, 0, online);
}
cursorY += config.hostblock.cpu.rows * config.hostblock.cpu.height +
(config.hostblock.cpu.rows - 1) * config.hostblock.cpu.gap_v +
config.hostblock.gap;
// ===== Memory bar =====
float memValue, swapValue = 0.0f, hugepagesValue = 0.0f;
if (metrics.memory.memory.total > 0)
memValue = static_cast<float>(metrics.memory.memory.used) / static_cast<float>(metrics.memory.memory.total);
if (metrics.memory.hugepages.total > 0)
hugepagesValue = static_cast<float>(metrics.memory.hugepages.total) / static_cast<float>(metrics.memory.memory.total);
memBar.draw(
fb,
x + config.hostblock.padding,
cursorY,
std::clamp(memValue, 0.0f, 1.0f), std::clamp(hugepagesValue, 0.0f, 1.0f), online);
text.drawTextOutlined(fb,
x + config.hostblock.memory.font.padding,
cursorY + 8,
"MEM: " + display::ui::text::formatFloat(static_cast<float>(metrics.memory.memory.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.memory.memory.total) / 1073741824),
display::ui::theme::text::TEXT,
display::ui::theme::text::OUTLINE,
display::ui::text::Font{config.hostblock.memory.font.name, config.hostblock.memory.font.size});
cursorY += config.hostblock.memory.height + config.hostblock.memory.gap;
if (metrics.memory.swap.total > 0)
{
swapValue = static_cast<float>(metrics.memory.swap.used) / static_cast<float>(metrics.memory.swap.total);
memBar.draw(
fb,
x + config.hostblock.padding,
cursorY,
std::clamp(swapValue, 0.0f, 1.0f), 0, online);
text.drawTextOutlined(fb,
x + config.hostblock.memory.font.padding,
cursorY + 8,
"SWP: " + display::ui::text::formatFloat(static_cast<float>(metrics.memory.swap.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.memory.swap.total) / 1073741824),
display::ui::theme::text::TEXT,
display::ui::theme::text::OUTLINE,
display::ui::text::Font{config.hostblock.memory.font.name, config.hostblock.memory.font.size});
cursorY += config.hostblock.memory.height + config.hostblock.gap;
}
// ===== Disk bar =====
int diskCount = metrics.disks.size();
for (int i = 0; i < diskCount; ++i)
{
int by = cursorY +
i * (config.hostblock.disks.height + config.hostblock.disks.gap);
float value = std::clamp(static_cast<float>(metrics.disks[i].metrics.used) / metrics.disks[i].metrics.total, 0.0f, 1.0f);
memBar.draw(fb, x + config.hostblock.padding, by, value, 0, online);
text.drawTextOutlined(fb,
x + config.hostblock.disks.font.padding,
by + 8,
"D/" + metrics.disks[i].name + ": " + display::ui::text::formatFloat(static_cast<float>(metrics.disks[i].metrics.used) / 1073741824) + "/" + display::ui::text::formatFloat(static_cast<float>(metrics.disks[i].metrics.total) / 1073741824),
display::ui::theme::text::TEXT,
display::ui::theme::text::OUTLINE,
display::ui::text::Font{config.hostblock.disks.font.name, config.hostblock.disks.font.size});
}
cursorY += diskCount * (config.hostblock.disks.height + config.hostblock.disks.gap);
// ===== Network bar =====
for (const auto &iface : metrics.networks)
{
int by = cursorY;
float rxNorm = 0.0f;
float txNorm = 0.0f;
if (iface.online)
{
if (iface.rxMaxBps > 0)
rxNorm = std::clamp(static_cast<float>(iface.rxBps / iface.rxMaxBps), 0.0f, 1.0f);
if (iface.txMaxBps > 0)
txNorm = std::clamp(static_cast<float>(iface.txBps / iface.txMaxBps), 0.0f, 1.0f);
}
// background bar
memBar.draw(
fb,
x + config.hostblock.padding,
by,
0.0f,
0.0f,
iface.online && online);
int barX = x + config.hostblock.padding;
int barW = config.hostblock.width - config.hostblock.padding * 2;
int barH = config.hostblock.networks.height;
// RX overlay
fb.fillRect(
barX,
by,
static_cast<int>(barW * rxNorm),
barH,
{0, 180, 0});
// TX overlay
fb.fillRect(
barX,
by,
static_cast<int>(barW * txNorm),
barH,
{200, 200, 0});
// border
fb.drawRect(barX, by, barW, barH, display::ui::theme::hostblock::BORDER);
// interface name + speeds
std::string label =
iface.name + " " +
display::ui::text::formatSpeed(iface.rxBps) + "" +
display::ui::text::formatSpeed(iface.txBps) + "";
text.drawTextOutlined(
fb,
barX + config.hostblock.networks.font.padding,
by + barH - 1,
label,
display::ui::theme::text::TEXT,
display::ui::theme::text::OUTLINE,
display::ui::text::Font{
config.hostblock.networks.font.name,
config.hostblock.networks.font.size});
cursorY += config.hostblock.networks.height + config.hostblock.networks.gap;
}
}
}