Add correct fonts
This commit is contained in:
@@ -13,6 +13,7 @@ target_link_libraries(DisplayGraphics
|
|||||||
Helpers::All
|
Helpers::All
|
||||||
Display::UI::Text
|
Display::UI::Text
|
||||||
Display::UI::HostBlock
|
Display::UI::HostBlock
|
||||||
|
Display::UI::Header
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(DisplayGraphics
|
target_include_directories(DisplayGraphics
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ namespace Display::Graphics
|
|||||||
{
|
{
|
||||||
framebuffer.clear(Color{0, 0, 0});
|
framebuffer.clear(Color{0, 0, 0});
|
||||||
|
|
||||||
|
header.draw(framebuffer, textRenderer, START_X, START_Y);
|
||||||
|
|
||||||
int blocksPerRow =
|
int blocksPerRow =
|
||||||
(SCREEN_WIDTH + BLOCK_GAP) / (Display::UI::HostBlock::BLOCK_WIDTH + BLOCK_GAP);
|
(SCREEN_WIDTH + BLOCK_GAP) / (Display::UI::HostBlock::BLOCK_WIDTH + BLOCK_GAP);
|
||||||
if (blocksPerRow < 1)
|
if (blocksPerRow < 1)
|
||||||
@@ -25,7 +27,7 @@ namespace Display::Graphics
|
|||||||
int row = index / blocksPerRow;
|
int row = index / blocksPerRow;
|
||||||
|
|
||||||
int x = START_X + col * (Display::UI::HostBlock::BLOCK_WIDTH + BLOCK_GAP);
|
int x = START_X + col * (Display::UI::HostBlock::BLOCK_WIDTH + BLOCK_GAP);
|
||||||
int y = START_Y + row * (Display::UI::HostBlock::BLOCK_HEIGHT + BLOCK_GAP);
|
int y = START_Y + header.height() + BLOCK_GAP + row * (Display::UI::HostBlock::BLOCK_HEIGHT + BLOCK_GAP);
|
||||||
|
|
||||||
hostblock.draw(
|
hostblock.draw(
|
||||||
framebuffer,
|
framebuffer,
|
||||||
|
|||||||
@@ -2,15 +2,16 @@
|
|||||||
#include "Display/Graphics/Framebuffer.h"
|
#include "Display/Graphics/Framebuffer.h"
|
||||||
#include "Model/HostRegistry.h"
|
#include "Model/HostRegistry.h"
|
||||||
#include "Display/UI/Text/Renderer.h"
|
#include "Display/UI/Text/Renderer.h"
|
||||||
|
#include "Display/UI/Header/Header.h"
|
||||||
#include "Display/UI/HostBlock/HostBlock.h"
|
#include "Display/UI/HostBlock/HostBlock.h"
|
||||||
#include "Display/Graphics/Color.h"
|
#include "Display/Graphics/Color.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace Display::Graphics
|
namespace Display::Graphics
|
||||||
{
|
{
|
||||||
static constexpr int START_X = 0;
|
static constexpr int START_X = 0; // 0
|
||||||
static constexpr int START_Y = 10;
|
static constexpr int START_Y = 0; // 20
|
||||||
static constexpr int BLOCK_GAP = 4;
|
static constexpr int BLOCK_GAP = 4; // 4
|
||||||
|
|
||||||
static constexpr int SCREEN_WIDTH = 240;
|
static constexpr int SCREEN_WIDTH = 240;
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ namespace Display::Graphics
|
|||||||
Framebuffer &framebuffer;
|
Framebuffer &framebuffer;
|
||||||
Model::HostRegistry ®istry;
|
Model::HostRegistry ®istry;
|
||||||
Display::UI::Text::Renderer textRenderer;
|
Display::UI::Text::Renderer textRenderer;
|
||||||
|
Display::UI::Header::Header header;
|
||||||
Display::UI::HostBlock::HostBlock hostblock;
|
Display::UI::HostBlock::HostBlock hostblock;
|
||||||
};
|
};
|
||||||
} // namespace Display::Graphics
|
} // namespace Display::Graphics
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Display/Graphics/Color.h"
|
#include "Display/Graphics/Color.h"
|
||||||
|
#include "Display/UI/Theme/Theme.h"
|
||||||
|
|
||||||
namespace Display::UI::Bar
|
namespace Display::UI::Bar
|
||||||
{
|
{
|
||||||
@@ -12,9 +13,9 @@ namespace Display::UI::Bar
|
|||||||
bool drawBorder;
|
bool drawBorder;
|
||||||
|
|
||||||
Style(
|
Style(
|
||||||
Display::Graphics::Color background = Display::Graphics::Color{30, 30, 30},
|
Display::Graphics::Color background = Display::UI::Theme::Bar::BACKGROUND,
|
||||||
Display::Graphics::Color fill = Display::Graphics::Color{0, 180, 0},
|
Display::Graphics::Color fill = Display::UI::Theme::Bar::FILL,
|
||||||
Display::Graphics::Color border = Display::Graphics::Color{80, 80, 80},
|
Display::Graphics::Color border = Display::UI::Theme::Bar::BORDER,
|
||||||
bool drawBorder = true)
|
bool drawBorder = true)
|
||||||
: background(background),
|
: background(background),
|
||||||
fill(fill),
|
fill(fill),
|
||||||
|
|||||||
@@ -2,4 +2,6 @@ message(STATUS "··Configuring UI")
|
|||||||
|
|
||||||
add_subdirectory(Bar)
|
add_subdirectory(Bar)
|
||||||
add_subdirectory(Text)
|
add_subdirectory(Text)
|
||||||
add_subdirectory(HostBlock)
|
add_subdirectory(Header)
|
||||||
|
add_subdirectory(HostBlock)
|
||||||
|
add_subdirectory(Theme)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
message(STATUS "···Configuring Header")
|
||||||
|
|
||||||
|
add_library(DisplayUIHeader
|
||||||
|
Header.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(Display::UI::Header ALIAS DisplayUIHeader)
|
||||||
|
|
||||||
|
target_link_libraries(DisplayUIHeader
|
||||||
|
PUBLIC
|
||||||
|
Display::Graphics
|
||||||
|
Display::UI::Text
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(DisplayUIHeader
|
||||||
|
PUBLIC
|
||||||
|
${INCLUDE_BASE_DIR}
|
||||||
|
)
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#include "Display/UI/Header/Header.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "Display/UI/Bar/Orientation.h"
|
||||||
|
#include "Display/UI/Bar/Style.h"
|
||||||
|
#include "Display/UI/Theme/Theme.h"
|
||||||
|
#include "Display/Graphics/Color.h"
|
||||||
|
|
||||||
|
namespace Display::UI::Header
|
||||||
|
{
|
||||||
|
Header::Header()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Header::draw(
|
||||||
|
Graphics::Framebuffer &fb,
|
||||||
|
UI::Text::Renderer &text,
|
||||||
|
int x, int y)
|
||||||
|
{
|
||||||
|
// ===== Block background =====
|
||||||
|
fb.fillRect(x, y, HEADER_WIDTH, HEADER_HEIGHT, Display::UI::Theme::Header::BACKGROUND);
|
||||||
|
fb.drawRect(x, y, HEADER_WIDTH, HEADER_HEIGHT, Display::UI::Theme::Header::BORDER);
|
||||||
|
|
||||||
|
int cursorY = y + PADDING;
|
||||||
|
|
||||||
|
text.drawTextOutlined(
|
||||||
|
fb,
|
||||||
|
x + PADDING + 120 - 2,
|
||||||
|
cursorY + 8,
|
||||||
|
getCurrentDateTime(),
|
||||||
|
Display::UI::Theme::Text::TEXT,
|
||||||
|
Display::UI::Theme::Text::OUTLINE,
|
||||||
|
Display::UI::Text::Font{std::string(HEADER_FONT_NAME.begin(), HEADER_FONT_NAME.end()), HEADER_FONT_SIZE});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Header::getCurrentDateTime()
|
||||||
|
{
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
std::time_t t = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::tm tm{};
|
||||||
|
localtime_r(&t, &tm);
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::setfill('0')
|
||||||
|
<< std::setw(2) << tm.tm_mday << '/'
|
||||||
|
<< std::setw(2) << tm.tm_mon + 1 << '/'
|
||||||
|
<< tm.tm_year + 1900 << ' '
|
||||||
|
<< std::setw(2) << tm.tm_hour << ':'
|
||||||
|
<< std::setw(2) << tm.tm_min << ':'
|
||||||
|
<< std::setw(2) << tm.tm_sec;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Display/Graphics/Framebuffer.h"
|
||||||
|
#include "Display/Graphics/Color.h"
|
||||||
|
#include "Display/UI/Text/Renderer.h"
|
||||||
|
|
||||||
|
namespace Display::UI::Header
|
||||||
|
{
|
||||||
|
// ===== Layout =====
|
||||||
|
constexpr int HEADER_WIDTH = 240; // 116
|
||||||
|
constexpr int HEADER_HEIGHT = 16; // 116
|
||||||
|
constexpr int PADDING = 4; // 4
|
||||||
|
constexpr std::string_view HEADER_FONT_NAME = "Pixel10";
|
||||||
|
constexpr int HEADER_FONT_SIZE = 14; // 12
|
||||||
|
|
||||||
|
class Header
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Header();
|
||||||
|
|
||||||
|
static constexpr int width() { return HEADER_WIDTH; }
|
||||||
|
static constexpr int height() { return HEADER_HEIGHT; }
|
||||||
|
|
||||||
|
void draw(
|
||||||
|
Graphics::Framebuffer &fb,
|
||||||
|
UI::Text::Renderer &text,
|
||||||
|
int x, int y);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string getCurrentDateTime();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
#include "Display/UI/Bar/Orientation.h"
|
#include "Display/UI/Bar/Orientation.h"
|
||||||
#include "Display/UI/Bar/Style.h"
|
#include "Display/UI/Bar/Style.h"
|
||||||
|
#include "Display/UI/Theme/Theme.h"
|
||||||
#include "Display/Graphics/Color.h"
|
#include "Display/Graphics/Color.h"
|
||||||
|
#include "Display/UI/Text/Helpers.h"
|
||||||
|
|
||||||
namespace Display::UI::HostBlock
|
namespace Display::UI::HostBlock
|
||||||
{
|
{
|
||||||
@@ -19,6 +21,7 @@ namespace Display::UI::HostBlock
|
|||||||
MEM_BAR_HEIGHT,
|
MEM_BAR_HEIGHT,
|
||||||
Display::UI::Bar::Orientation::Horizontal,
|
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})
|
Display::UI::Bar::Style{Display::Graphics::Color{40, 40, 40}, Display::Graphics::Color{0, 120, 200}, Display::Graphics::Color{80, 80, 80}, true})
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,8 +33,8 @@ namespace Display::UI::HostBlock
|
|||||||
const Metrics::Host &metrics)
|
const Metrics::Host &metrics)
|
||||||
{
|
{
|
||||||
// ===== Block background =====
|
// ===== Block background =====
|
||||||
fb.fillRect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT, BG_COLOR);
|
fb.fillRect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT, Display::UI::Theme::HostBlock::BACKGROUND);
|
||||||
fb.drawRect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT, BORDER_COLOR);
|
fb.drawRect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT, Display::UI::Theme::HostBlock::BORDER);
|
||||||
|
|
||||||
int cursorY = y + PADDING;
|
int cursorY = y + PADDING;
|
||||||
|
|
||||||
@@ -41,14 +44,18 @@ namespace Display::UI::HostBlock
|
|||||||
cursorY,
|
cursorY,
|
||||||
BLOCK_WIDTH - PADDING * 2,
|
BLOCK_WIDTH - PADDING * 2,
|
||||||
HEADER_HEIGHT,
|
HEADER_HEIGHT,
|
||||||
HEADER_BG);
|
Display::UI::Theme::HostBlock::HEADER);
|
||||||
|
|
||||||
text.drawText(
|
text.drawTextOutlined(
|
||||||
fb,
|
fb,
|
||||||
x + PADDING + 2,
|
x + PADDING + 2,
|
||||||
cursorY + HEADER_HEIGHT - 3,
|
cursorY + HEADER_HEIGHT - 3,
|
||||||
hostname,
|
hostname,
|
||||||
TEXT_COLOR);
|
Display::UI::Theme::Text::TEXT,
|
||||||
|
Display::UI::Theme::Text::OUTLINE,
|
||||||
|
// Display::UI::Text::Font{"LiberationSans-Regular", HEADER_FONT_SIZE});
|
||||||
|
// Display::UI::Text::Font{"PixelFive-Regular", 5});
|
||||||
|
Display::UI::Text::Font{std::string(HEADER_FONT_NAME.begin(), HEADER_FONT_NAME.end()), HEADER_FONT_SIZE});
|
||||||
|
|
||||||
cursorY += HEADER_HEIGHT + SECTION_GAP;
|
cursorY += HEADER_HEIGHT + SECTION_GAP;
|
||||||
|
|
||||||
@@ -77,17 +84,63 @@ namespace Display::UI::HostBlock
|
|||||||
SECTION_GAP;
|
SECTION_GAP;
|
||||||
|
|
||||||
// ===== Memory bar =====
|
// ===== Memory bar =====
|
||||||
float memValue = 0.0f;
|
float memValue, swapValue = 0.0f;
|
||||||
if (metrics.memory.total > 0)
|
if (metrics.memory.mem_total > 0)
|
||||||
{
|
memValue = metrics.memory.mem_used / metrics.memory.mem_total;
|
||||||
memValue = float(metrics.memory.used) /
|
|
||||||
float(metrics.memory.total);
|
|
||||||
}
|
|
||||||
|
|
||||||
memBar.draw(
|
memBar.draw(
|
||||||
fb,
|
fb,
|
||||||
x + PADDING,
|
x + PADDING,
|
||||||
cursorY,
|
cursorY,
|
||||||
std::clamp(memValue, 0.0f, 1.0f));
|
std::clamp(memValue, 0.0f, 1.0f));
|
||||||
|
text.drawTextOutlined(fb,
|
||||||
|
x + MEM_BAR_TEXT_PADDING_X,
|
||||||
|
cursorY + 8,
|
||||||
|
"M: " + Display::UI::Text::formatFloat(metrics.memory.mem_used / 1073741824) + "/" + Display::UI::Text::formatFloat(metrics.memory.mem_total / 1073741824),
|
||||||
|
Display::UI::Theme::Text::TEXT,
|
||||||
|
Display::UI::Theme::Text::OUTLINE,
|
||||||
|
Display::UI::Text::Font{"PixelFive-Regular", 5});
|
||||||
|
|
||||||
|
cursorY += MEM_BAR_HEIGHT + SECTION_GAP;
|
||||||
|
|
||||||
|
if (metrics.memory.swap_total > 0)
|
||||||
|
{
|
||||||
|
swapValue = metrics.memory.swap_used / metrics.memory.swap_total;
|
||||||
|
|
||||||
|
memBar.draw(
|
||||||
|
fb,
|
||||||
|
x + PADDING,
|
||||||
|
cursorY,
|
||||||
|
std::clamp(swapValue, 0.0f, 1.0f));
|
||||||
|
text.drawTextOutlined(fb,
|
||||||
|
x + MEM_BAR_TEXT_PADDING_X,
|
||||||
|
cursorY + 8,
|
||||||
|
"S: " + Display::UI::Text::formatFloat(metrics.memory.swap_used / 1073741824) + "/" + Display::UI::Text::formatFloat(metrics.memory.swap_total / 1073741824),
|
||||||
|
Display::UI::Theme::Text::TEXT,
|
||||||
|
Display::UI::Theme::Text::OUTLINE,
|
||||||
|
Display::UI::Text::Font{"PixelFive-Regular", 5});
|
||||||
|
|
||||||
|
cursorY += MEM_BAR_HEIGHT + SECTION_GAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Disk bar =====
|
||||||
|
int diskCount = metrics.disks.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < diskCount; ++i)
|
||||||
|
{
|
||||||
|
int by = cursorY +
|
||||||
|
i * (MEM_BAR_HEIGHT + SECTION_GAP);
|
||||||
|
|
||||||
|
float value = std::clamp(metrics.disks[i].used / metrics.disks[i].total, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
memBar.draw(fb, x + PADDING, by, value);
|
||||||
|
text.drawTextOutlined(fb,
|
||||||
|
x + MEM_BAR_TEXT_PADDING_X,
|
||||||
|
by + 8,
|
||||||
|
metrics.disks[i].name + ": " + Display::UI::Text::formatFloat(metrics.disks[i].used / 1073741824) + "/" + Display::UI::Text::formatFloat(metrics.disks[i].total / 1073741824),
|
||||||
|
Display::UI::Theme::Text::TEXT,
|
||||||
|
Display::UI::Theme::Text::OUTLINE,
|
||||||
|
Display::UI::Text::Font{"PixelFive-Regular", 5});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,37 +12,33 @@
|
|||||||
namespace Display::UI::HostBlock
|
namespace Display::UI::HostBlock
|
||||||
{
|
{
|
||||||
// ===== Layout =====
|
// ===== Layout =====
|
||||||
constexpr int BLOCK_WIDTH = 116;
|
constexpr int BLOCK_WIDTH = 118; // 118
|
||||||
constexpr int BLOCK_HEIGHT = 116;
|
constexpr int BLOCK_HEIGHT = 146; // 146
|
||||||
constexpr int PADDING = 4;
|
constexpr int PADDING = 5; // 5
|
||||||
|
|
||||||
constexpr int HEADER_HEIGHT = 16;
|
constexpr int HEADER_HEIGHT = 12; // 12
|
||||||
constexpr int SECTION_GAP = 4;
|
constexpr std::string_view HEADER_FONT_NAME = "PixelFive-Regular";
|
||||||
|
constexpr int HEADER_FONT_SIZE = 5; // 10
|
||||||
|
constexpr int SECTION_GAP = 4; // 4
|
||||||
|
|
||||||
// ===== CPU bars =====
|
// ===== CPU bars =====
|
||||||
constexpr int CPU_BAR_WIDTH = 10;
|
constexpr int CPU_BAR_WIDTH = 10; // 10
|
||||||
constexpr int CPU_BAR_GAP = 4;
|
constexpr int CPU_BAR_GAP = 4; // 4
|
||||||
constexpr int CPU_BAR_HEIGHT = 36;
|
constexpr int CPU_BAR_HEIGHT = 16; // 16
|
||||||
// constexpr int CPU_BAR_HEIGHT = 10;
|
constexpr int CPU_MAX_PER_ROW = 8; // 8
|
||||||
constexpr int CPU_MAX_PER_ROW = 8;
|
constexpr int CPU_ROWS = 2; // 2
|
||||||
constexpr int CPU_ROWS = 2;
|
|
||||||
|
|
||||||
// ===== Memory bar =====
|
// ===== Memory bar =====
|
||||||
constexpr int MEM_BAR_HEIGHT = 8;
|
constexpr int MEM_BAR_HEIGHT = 11; // 8
|
||||||
|
constexpr int MEM_BAR_TEXT_PADDING_X = PADDING + 3;
|
||||||
// ===== Colors =====
|
|
||||||
const Display::Graphics::Color BG_COLOR{20, 20, 20};
|
|
||||||
const Display::Graphics::Color BORDER_COLOR{60, 60, 60};
|
|
||||||
const Display::Graphics::Color TEXT_COLOR{220, 220, 220};
|
|
||||||
const Display::Graphics::Color HEADER_BG{30, 30, 30};
|
|
||||||
|
|
||||||
class HostBlock
|
class HostBlock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HostBlock();
|
HostBlock();
|
||||||
|
|
||||||
static constexpr int width() { return 116; }
|
static constexpr int width() { return BLOCK_WIDTH; }
|
||||||
static constexpr int height() { return 116; }
|
static constexpr int height() { return BLOCK_HEIGHT; }
|
||||||
|
|
||||||
void draw(
|
void draw(
|
||||||
Graphics::Framebuffer &fb,
|
Graphics::Framebuffer &fb,
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
#include "Display/UI/Text/BitmapFont.h"
|
|
||||||
|
|
||||||
namespace Display::UI::Text
|
|
||||||
{
|
|
||||||
// 5x7 bitmap digits (0–9)
|
|
||||||
static const uint8_t digits[10][7] = {
|
|
||||||
{0x1E, 0x29, 0x25, 0x23, 0x21, 0x29, 0x1E}, // 0
|
|
||||||
{0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E}, // 1
|
|
||||||
{0x1E, 0x21, 0x01, 0x0E, 0x10, 0x20, 0x3F}, // 2
|
|
||||||
{0x1E, 0x21, 0x02, 0x06, 0x01, 0x21, 0x1E}, // 3
|
|
||||||
{0x02, 0x06, 0x0A, 0x12, 0x3F, 0x02, 0x02}, // 4
|
|
||||||
{0x3F, 0x20, 0x3E, 0x01, 0x01, 0x21, 0x1E}, // 5
|
|
||||||
{0x0E, 0x10, 0x20, 0x3E, 0x21, 0x21, 0x1E}, // 6
|
|
||||||
{0x3F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08}, // 7
|
|
||||||
{0x1E, 0x21, 0x21, 0x1E, 0x21, 0x21, 0x1E}, // 8
|
|
||||||
{0x1E, 0x21, 0x21, 0x1F, 0x01, 0x02, 0x1C} // 9
|
|
||||||
};
|
|
||||||
|
|
||||||
void BitmapFont::drawDigit(Display::Graphics::Framebuffer &fb, int x, int y, int d, const Display::Graphics::Color &color)
|
|
||||||
{
|
|
||||||
if (d < 0 || d > 9)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int row = 0; row < 7; ++row)
|
|
||||||
{
|
|
||||||
for (int col = 0; col < 5; ++col)
|
|
||||||
{
|
|
||||||
if (digits[d][row] & (1 << (4 - col)))
|
|
||||||
{
|
|
||||||
// Рисуем пиксель как 2x2 квадрат для читаемости
|
|
||||||
fb.fillRect(x + col * 2, y + row * 2, 2, 2, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace Display::UI::Text
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <cstdint>
|
|
||||||
#include "Display/Graphics/Framebuffer.h"
|
|
||||||
#include "Display/Graphics/Color.h"
|
|
||||||
|
|
||||||
namespace Display::UI::Text
|
|
||||||
{
|
|
||||||
class BitmapFont
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void drawDigit(Display::Graphics::Framebuffer &fb, int x, int y, int d, const Display::Graphics::Color &color);
|
|
||||||
};
|
|
||||||
} // namespace Display::UI::Text
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
message(STATUS "···Configuring Text")
|
message(STATUS "···Configuring Text")
|
||||||
|
|
||||||
add_library(DisplayUIText
|
add_library(DisplayUIText
|
||||||
BitmapFont.cpp
|
Fonts.cpp
|
||||||
FontFace.cpp
|
Helpers.cpp
|
||||||
GlyphCache.cpp
|
|
||||||
Renderer.cpp
|
Renderer.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,6 +14,7 @@ find_package(Freetype REQUIRED)
|
|||||||
target_link_libraries(DisplayUIText
|
target_link_libraries(DisplayUIText
|
||||||
PRIVATE
|
PRIVATE
|
||||||
Display::Graphics
|
Display::Graphics
|
||||||
|
Helpers::All
|
||||||
${FREETYPE_LIBRARIES}
|
${FREETYPE_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Display::UI::Text
|
||||||
|
{
|
||||||
|
struct Font
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
int size; // размер шрифта
|
||||||
|
bool operator==(const Font &other) const
|
||||||
|
{
|
||||||
|
return name == other.name && size == other.size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FontHash
|
||||||
|
{
|
||||||
|
std::size_t operator()(const Font &k) const
|
||||||
|
{
|
||||||
|
return std::hash<std::string>()(k.name) ^ std::hash<int>()(k.size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Display::UI::Text
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#include "Display/UI/Text/FontFace.h"
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace Display::UI::Text
|
|
||||||
{
|
|
||||||
struct FontFace::FreeType
|
|
||||||
{
|
|
||||||
FT_Library library = nullptr;
|
|
||||||
FT_Face face = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
FontFace::FontFace(const std::string &path, int pixelSize)
|
|
||||||
: freetype(std::make_unique<FreeType>())
|
|
||||||
{
|
|
||||||
if (FT_Init_FreeType(&freetype->library))
|
|
||||||
throw std::runtime_error("FT_Init_FreeType failed");
|
|
||||||
|
|
||||||
if (FT_New_Face(freetype->library, path.c_str(), 0, &freetype->face))
|
|
||||||
throw std::runtime_error("FT_New_Face failed");
|
|
||||||
|
|
||||||
FT_Set_Pixel_Sizes(freetype->face, 0, pixelSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
FontFace::~FontFace()
|
|
||||||
{
|
|
||||||
if (freetype->face)
|
|
||||||
FT_Done_Face(freetype->face);
|
|
||||||
if (freetype->library)
|
|
||||||
FT_Done_FreeType(freetype->library);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *FontFace::getFace() const
|
|
||||||
{
|
|
||||||
return freetype->face;
|
|
||||||
}
|
|
||||||
} // namespace Display::UI::Text
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Display::UI::Text
|
|
||||||
{
|
|
||||||
class FontFace
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FontFace(const std::string &path, int pixelSize);
|
|
||||||
~FontFace();
|
|
||||||
|
|
||||||
FontFace(const FontFace &) = delete;
|
|
||||||
FontFace &operator=(const FontFace &) = delete;
|
|
||||||
|
|
||||||
FontFace(FontFace &&) = delete;
|
|
||||||
FontFace &operator=(FontFace &&) = delete;
|
|
||||||
|
|
||||||
void *getFace() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct FreeType;
|
|
||||||
std::unique_ptr<FreeType> freetype;
|
|
||||||
};
|
|
||||||
} // namespace Display::UI::Text
|
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
#include "Display/UI/Text/Fonts.h"
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include "Helpers/Paths.h"
|
||||||
|
|
||||||
|
namespace Display::UI::Text
|
||||||
|
{
|
||||||
|
struct Fonts::Library
|
||||||
|
{
|
||||||
|
FT_Library library = nullptr;
|
||||||
|
};
|
||||||
|
struct Fonts::Face
|
||||||
|
{
|
||||||
|
FT_Face face = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
Fonts::Fonts()
|
||||||
|
: library(std::make_unique<Library>())
|
||||||
|
{
|
||||||
|
if (FT_Init_FreeType(&library->library))
|
||||||
|
throw std::runtime_error("FT_Init_FreeType failed");
|
||||||
|
|
||||||
|
loadAllFonts();
|
||||||
|
}
|
||||||
|
|
||||||
|
Fonts::~Fonts()
|
||||||
|
{
|
||||||
|
for (auto &[k, v] : fonts)
|
||||||
|
if (v->face)
|
||||||
|
FT_Done_Face(v->face);
|
||||||
|
if (library->library)
|
||||||
|
FT_Done_FreeType(library->library);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fonts::loadAllFonts()
|
||||||
|
{
|
||||||
|
loadFonts("/usr/share/fonts/truetype");
|
||||||
|
loadFonts(Helpers::initPaths().exeDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fonts::loadFonts(const std::string &path)
|
||||||
|
{
|
||||||
|
if (std::filesystem::exists(path))
|
||||||
|
{
|
||||||
|
for (auto &p : std::filesystem::recursive_directory_iterator(path))
|
||||||
|
{
|
||||||
|
if (p.path().extension() == ".ttf" || p.path().extension() == ".otf")
|
||||||
|
{
|
||||||
|
std::string path = p.path().string();
|
||||||
|
std::string filename = p.path().stem().string();
|
||||||
|
|
||||||
|
// Можно сразу создавать Fonts для стандартных размеров, например: 10,12,14,16,18,24
|
||||||
|
for (int sz : {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 24, 36, 72})
|
||||||
|
{
|
||||||
|
Font key{filename, sz};
|
||||||
|
|
||||||
|
std::unique_ptr<Face> face = std::make_unique<Face>();
|
||||||
|
if (FT_New_Face(library->library, path.c_str(), 0, &face->face))
|
||||||
|
throw std::runtime_error("FT_New_Face failed");
|
||||||
|
FT_Set_Pixel_Sizes(face->face, 0, sz);
|
||||||
|
|
||||||
|
fonts.emplace(key, std::move(face));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Glyph &Fonts::getGlyph(char ch, const Font &font)
|
||||||
|
{
|
||||||
|
|
||||||
|
GlyphKey key{ch, font};
|
||||||
|
|
||||||
|
auto gph = glyphs.find(key);
|
||||||
|
if (gph != glyphs.end())
|
||||||
|
return gph->second;
|
||||||
|
|
||||||
|
auto fnt = fonts.find(font);
|
||||||
|
if (fnt == fonts.end())
|
||||||
|
{
|
||||||
|
// Если нет, можно использовать какой-нибудь дефолтный шрифт
|
||||||
|
fnt = fonts.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Face face = fnt->second->face;
|
||||||
|
|
||||||
|
if (!face)
|
||||||
|
throw std::runtime_error("Fonts not initialized!");
|
||||||
|
if (FT_Load_Char(face, ch, FT_LOAD_RENDER | FT_LOAD_TARGET_MONO))
|
||||||
|
throw std::runtime_error("FT_Load_Char failed");
|
||||||
|
FT_GlyphSlot g = face->glyph;
|
||||||
|
|
||||||
|
Glyph glyph;
|
||||||
|
glyph.width = g->bitmap.width;
|
||||||
|
glyph.height = g->bitmap.rows;
|
||||||
|
glyph.bearingX = g->bitmap_left;
|
||||||
|
glyph.bearingY = g->bitmap_top;
|
||||||
|
glyph.advance = g->advance.x >> 6;
|
||||||
|
// glyph.buffer.assign(g->bitmap.buffer, g->bitmap.buffer + g->bitmap.width * g->bitmap.rows);
|
||||||
|
|
||||||
|
glyph.buffer.resize(glyph.width * glyph.height, 0);
|
||||||
|
|
||||||
|
const FT_Bitmap &bm = g->bitmap;
|
||||||
|
for (int y = 0; y < bm.rows; ++y)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < bm.width; ++x)
|
||||||
|
{
|
||||||
|
int byteIndex = y * bm.pitch + x / 8;
|
||||||
|
int bitIndex = 7 - (x % 8);
|
||||||
|
uint8_t bit = (bm.buffer[byteIndex] >> bitIndex) & 1;
|
||||||
|
glyph.buffer[y * bm.width + x] = bit ? 255 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glyphs.emplace(key, std::move(glyph)).first->second;
|
||||||
|
}
|
||||||
|
} // namespace Display::UI::Text
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "Display/UI/Text/Font.h"
|
||||||
|
#include "Display/UI/Text/Glyph.h"
|
||||||
|
#include "Display/UI/Text/GlyphKey.h"
|
||||||
|
|
||||||
|
namespace Display::UI::Text
|
||||||
|
{
|
||||||
|
class Fonts
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Fonts();
|
||||||
|
~Fonts();
|
||||||
|
|
||||||
|
const Glyph &getGlyph(char ch, const Font &key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Library;
|
||||||
|
struct Face;
|
||||||
|
std::unique_ptr<Library> library;
|
||||||
|
std::unordered_map<Font, std::unique_ptr<Face>, FontHash> fonts;
|
||||||
|
std::unordered_map<GlyphKey, Glyph, GlyphKeyHash> glyphs;
|
||||||
|
void loadAllFonts();
|
||||||
|
void loadFonts(const std::string &path);
|
||||||
|
};
|
||||||
|
} // namespace Display::UI::Text
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#include "Display/UI/Text/GlyphCache.h"
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <iostream>
|
|
||||||
#include "Display/UI/Text/FontFace.h"
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
|
|
||||||
namespace Display::UI::Text
|
|
||||||
{
|
|
||||||
GlyphCache::GlyphCache(const FontFace &fontFace) : fontFace(fontFace) {}
|
|
||||||
|
|
||||||
const Glyph &GlyphCache::getGlyph(char c)
|
|
||||||
{
|
|
||||||
FT_Face face = static_cast<FT_Face>(fontFace.getFace());
|
|
||||||
auto it = cache.find(c);
|
|
||||||
if (it != cache.end())
|
|
||||||
return it->second;
|
|
||||||
|
|
||||||
if (!face)
|
|
||||||
throw std::runtime_error("FontFace not initialized!");
|
|
||||||
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
|
|
||||||
throw std::runtime_error("FT_Load_Char failed");
|
|
||||||
FT_GlyphSlot g = face->glyph;
|
|
||||||
|
|
||||||
Glyph glyph;
|
|
||||||
glyph.width = g->bitmap.width;
|
|
||||||
glyph.height = g->bitmap.rows;
|
|
||||||
glyph.bearingX = g->bitmap_left;
|
|
||||||
glyph.bearingY = g->bitmap_top;
|
|
||||||
glyph.advance = g->advance.x >> 6;
|
|
||||||
glyph.buffer.assign(g->bitmap.buffer, g->bitmap.buffer + g->bitmap.width * g->bitmap.rows);
|
|
||||||
|
|
||||||
return cache.emplace(c, std::move(glyph)).first->second;
|
|
||||||
}
|
|
||||||
} // namespace Display::UI::Text
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Display/UI/Text/Glyph.h"
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Display::UI::Text
|
|
||||||
{
|
|
||||||
class FontFace;
|
|
||||||
class GlyphCache
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GlyphCache(const FontFace &fontFace);
|
|
||||||
|
|
||||||
GlyphCache(const GlyphCache &) = delete;
|
|
||||||
GlyphCache &operator=(const GlyphCache &) = delete;
|
|
||||||
|
|
||||||
GlyphCache(GlyphCache &&) = delete;
|
|
||||||
GlyphCache &operator=(GlyphCache &&) = delete;
|
|
||||||
|
|
||||||
const Glyph &getGlyph(char c);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const FontFace &fontFace;
|
|
||||||
std::unordered_map<char, Glyph> cache;
|
|
||||||
};
|
|
||||||
} // namespace Display::UI::Text
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "Font.h"
|
||||||
|
|
||||||
|
namespace Display::UI::Text
|
||||||
|
{
|
||||||
|
struct GlyphKey
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
Font font;
|
||||||
|
|
||||||
|
bool operator==(const GlyphKey &other) const
|
||||||
|
{
|
||||||
|
return ch == other.ch && font == other.font;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GlyphKeyHash
|
||||||
|
{
|
||||||
|
std::size_t operator()(const GlyphKey &k) const
|
||||||
|
{
|
||||||
|
std::size_t h1 = std::hash<char>()(k.ch);
|
||||||
|
std::size_t h2 = FontHash{}(k.font);
|
||||||
|
return h1 ^ (h2 << 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Display::UI::Text
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "Display/UI/Text/Helpers.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace Display::UI::Text
|
||||||
|
{
|
||||||
|
std::string formatFloat(float value, int decimals)
|
||||||
|
{
|
||||||
|
char buffer[64];
|
||||||
|
std::snprintf(buffer, sizeof(buffer), "%.*f", decimals, value);
|
||||||
|
return std::string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string formatDouble(double value, int decimals)
|
||||||
|
{
|
||||||
|
char buffer[64];
|
||||||
|
std::snprintf(buffer, sizeof(buffer), "%.*f", decimals, value);
|
||||||
|
return std::string(buffer);
|
||||||
|
}
|
||||||
|
} // namespace Display::UI::Text
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Display::UI::Text
|
||||||
|
{
|
||||||
|
std::string formatFloat(float value, int decimals = 1);
|
||||||
|
std::string formatDouble(double value, int decimals = 1);
|
||||||
|
} // namespace Display::UI::Text
|
||||||
@@ -5,18 +5,15 @@
|
|||||||
|
|
||||||
namespace Display::UI::Text
|
namespace Display::UI::Text
|
||||||
{
|
{
|
||||||
|
|
||||||
Renderer::Renderer() : fontFace("/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf", 12), glyphCache(fontFace) {}
|
|
||||||
|
|
||||||
void Renderer::drawText(Display::Graphics::Framebuffer &fb, int x, int y,
|
void Renderer::drawText(Display::Graphics::Framebuffer &fb, int x, int y,
|
||||||
const std::string &text, const Display::Graphics::Color &color)
|
const std::string &text, const Display::Graphics::Color &color, const Font &font)
|
||||||
{
|
{
|
||||||
int penX = x;
|
int penX = x;
|
||||||
int baseline = y;
|
int baseline = y;
|
||||||
|
|
||||||
for (char ch : text)
|
for (char ch : text)
|
||||||
{
|
{
|
||||||
const Glyph &g = glyphCache.getGlyph(ch);
|
const Glyph &g = fonts.getGlyph(ch, font);
|
||||||
|
|
||||||
for (int row = 0; row < g.height; ++row)
|
for (int row = 0; row < g.height; ++row)
|
||||||
{
|
{
|
||||||
@@ -44,4 +41,46 @@ namespace Display::UI::Text
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::drawTextOutlined(Display::Graphics::Framebuffer &fb,
|
||||||
|
int x, int y,
|
||||||
|
const std::string &text,
|
||||||
|
const Display::Graphics::Color &colorText,
|
||||||
|
const Display::Graphics::Color &colorOutline,
|
||||||
|
const Font &font)
|
||||||
|
{
|
||||||
|
// outline
|
||||||
|
for (int dx = -1; dx <= 1; ++dx)
|
||||||
|
for (int dy = -1; dy <= 1; ++dy)
|
||||||
|
if (dx != 0 || dy != 0)
|
||||||
|
drawText(fb, x + dx, y + dy, text, colorOutline, font);
|
||||||
|
|
||||||
|
// main text
|
||||||
|
drawText(fb, x, y, text, colorText, font);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* int Renderer::measureWidth(const std::string &text)
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
for (char ch : text)
|
||||||
|
{
|
||||||
|
const Glyph &g = glyphCache.getGlyph(ch, face);
|
||||||
|
width += g.advance;
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Renderer::measureHeight(const std::string &text)
|
||||||
|
{
|
||||||
|
int height = 0;
|
||||||
|
for (char ch : text)
|
||||||
|
{
|
||||||
|
const Glyph &g = glyphCache.getGlyph(ch, face);
|
||||||
|
int glyphHeight = g.height - g.bearingY + g.bearingY; // можно уточнить по высоте глифа
|
||||||
|
if (glyphHeight > height)
|
||||||
|
height = glyphHeight;
|
||||||
|
}
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
} // namespace Display::UI::Text
|
} // namespace Display::UI::Text
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Display/Graphics/Framebuffer.h"
|
#include "Display/Graphics/Framebuffer.h"
|
||||||
#include "Display/UI/Text/FontFace.h"
|
#include "Display/UI/Text/Fonts.h"
|
||||||
#include "Display/UI/Text/GlyphCache.h"
|
#include "Display/UI/Text/Font.h"
|
||||||
#include "Display/Graphics/Color.h"
|
#include "Display/Graphics/Color.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace Display::UI::Text
|
namespace Display::UI::Text
|
||||||
{
|
{
|
||||||
@@ -13,16 +14,14 @@ namespace Display::UI::Text
|
|||||||
class Renderer
|
class Renderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Renderer();
|
void drawText(Display::Graphics::Framebuffer &fb, int x, int y, const std::string &text, const Display::Graphics::Color &color = Display::Graphics::Color{255, 255, 255}, const Font &font = {"LiberationSans-Regular", 12});
|
||||||
|
void drawTextOutlined(Display::Graphics::Framebuffer &fb, int x, int y, const std::string &text, const Display::Graphics::Color &colorText = Display::Graphics::Color{255, 255, 255}, const Display::Graphics::Color &colorOutline = Display::Graphics::Color{0, 0, 0}, const Font &font = {"LiberationSans-Regular", 12});
|
||||||
|
|
||||||
Renderer(const Renderer &) = delete;
|
// int measureWidth(const std::string &text);
|
||||||
Renderer &operator=(const Renderer &) = delete;
|
// int measureHeight(const std::string &text);
|
||||||
|
|
||||||
void drawText(Display::Graphics::Framebuffer &fb, int x, int y, const std::string &text, const Display::Graphics::Color &color);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FontFace fontFace;
|
Fonts fonts;
|
||||||
GlyphCache glyphCache;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Display::UI::Text
|
} // namespace Display::UI::Text
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
message(STATUS "···Configuring Theme")
|
||||||
|
|
||||||
|
add_library(Theme INTERFACE)
|
||||||
|
|
||||||
|
add_library(Display::UI::Theme ALIAS Theme)
|
||||||
|
|
||||||
|
target_link_libraries(Theme
|
||||||
|
INTERFACE
|
||||||
|
Display::Graphics
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(Theme
|
||||||
|
INTERFACE
|
||||||
|
${INCLUDE_BASE_DIR}
|
||||||
|
)
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Display/Graphics/Color.h"
|
||||||
|
|
||||||
|
namespace Display::UI::Theme
|
||||||
|
{
|
||||||
|
namespace Text
|
||||||
|
{
|
||||||
|
const Display::Graphics::Color TEXT{220, 220, 220};
|
||||||
|
const Display::Graphics::Color OUTLINE{20, 20, 20};
|
||||||
|
} // namespace Text
|
||||||
|
|
||||||
|
namespace Header
|
||||||
|
{
|
||||||
|
// ===== Header =====
|
||||||
|
const Display::Graphics::Color BACKGROUND{20, 20, 20};
|
||||||
|
const Display::Graphics::Color BORDER{60, 60, 60};
|
||||||
|
const Display::Graphics::Color HEADER{30, 30, 30};
|
||||||
|
} // namespace Header
|
||||||
|
|
||||||
|
namespace HostBlock
|
||||||
|
{
|
||||||
|
// ===== HostBlock =====
|
||||||
|
const Display::Graphics::Color BACKGROUND{20, 20, 20};
|
||||||
|
const Display::Graphics::Color BORDER{60, 60, 60};
|
||||||
|
const Display::Graphics::Color HEADER{30, 30, 30};
|
||||||
|
} // namespace HostBlock
|
||||||
|
|
||||||
|
namespace Bar
|
||||||
|
{
|
||||||
|
const Display::Graphics::Color BACKGROUND{30, 30, 30};
|
||||||
|
const Display::Graphics::Color FILL{0, 180, 0};
|
||||||
|
const Display::Graphics::Color BORDER{80, 80, 80};
|
||||||
|
} // namespace Bar
|
||||||
|
} // namespace Display::UI::Theme
|
||||||
@@ -5,12 +5,12 @@ configure_file(
|
|||||||
${CMAKE_CURRENT_BINARY_DIR}/Version.h
|
${CMAKE_CURRENT_BINARY_DIR}/Version.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(Helpers INTERFACE)
|
add_library(Helpers Paths.cpp)
|
||||||
|
|
||||||
add_library(Helpers::All ALIAS Helpers)
|
add_library(Helpers::All ALIAS Helpers)
|
||||||
|
|
||||||
target_include_directories(Helpers
|
target_include_directories(Helpers
|
||||||
INTERFACE
|
PUBLIC
|
||||||
${INCLUDE_BASE_DIR}
|
${INCLUDE_BASE_DIR}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
namespace Helpers
|
||||||
|
{
|
||||||
|
std::filesystem::path getExecutablePath()
|
||||||
|
{
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
|
||||||
|
if (len == -1)
|
||||||
|
throw std::runtime_error("readlink(/proc/self/exe) failed");
|
||||||
|
|
||||||
|
buf[len] = '\0';
|
||||||
|
return std::filesystem::path(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Paths
|
||||||
|
{
|
||||||
|
std::filesystem::path exe;
|
||||||
|
std::filesystem::path exeDir;
|
||||||
|
std::filesystem::path configDir;
|
||||||
|
std::filesystem::path assetsDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
Paths initPaths()
|
||||||
|
{
|
||||||
|
Paths p;
|
||||||
|
p.exe = getExecutablePath();
|
||||||
|
p.exeDir = p.exe.parent_path();
|
||||||
|
p.configDir = p.exeDir / "config";
|
||||||
|
p.assetsDir = p.exeDir / "assets";
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
} // namespace Helpers
|
||||||
+26
-11
@@ -5,6 +5,8 @@
|
|||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace Metrics
|
namespace Metrics
|
||||||
{
|
{
|
||||||
@@ -99,36 +101,49 @@ namespace Metrics
|
|||||||
uint64_t value;
|
uint64_t value;
|
||||||
std::string unit;
|
std::string unit;
|
||||||
|
|
||||||
uint64_t total = 0, available = 0;
|
uint64_t mem_total = 0, mem_available = 0, swap_total = 0, swap_available = 0;
|
||||||
|
|
||||||
while (f >> key >> value >> unit)
|
while (f >> key >> value >> unit)
|
||||||
{
|
{
|
||||||
if (key == "MemTotal:")
|
if (key == "MemTotal:")
|
||||||
total = value * 1024;
|
mem_total = value * 1024;
|
||||||
else if (key == "MemAvailable:")
|
else if (key == "MemAvailable:")
|
||||||
available = value * 1024;
|
mem_available = value * 1024;
|
||||||
|
else if (key == "SwapTotal:")
|
||||||
|
swap_total = value * 1024;
|
||||||
|
else if (key == "SwapFree:")
|
||||||
|
swap_available = value * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory memory;
|
Memory memory;
|
||||||
memory.total = total;
|
memory.mem_total = mem_total;
|
||||||
memory.available = available;
|
memory.mem_available = mem_available;
|
||||||
memory.used = total - available;
|
memory.mem_used = mem_total - mem_available;
|
||||||
|
memory.swap_total = swap_total;
|
||||||
|
memory.swap_available = swap_available;
|
||||||
|
memory.swap_used = swap_total - swap_available;
|
||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
Disk Collector::readDisk(const char *path)
|
Disk Collector::readDisk(const char *path)
|
||||||
{
|
{
|
||||||
struct statvfs vfs{};
|
struct statvfs vfs;
|
||||||
statvfs(path, &vfs);
|
if (statvfs(path, &vfs) != 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("statvfs failed for ") + path + ": " +
|
||||||
|
std::strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t total = vfs.f_blocks * vfs.f_frsize;
|
uint64_t total = static_cast<uint64_t>(vfs.f_blocks) * vfs.f_frsize;
|
||||||
uint64_t free = vfs.f_bavail * vfs.f_frsize;
|
uint64_t free = static_cast<uint64_t>(vfs.f_bavail) * vfs.f_frsize;
|
||||||
|
uint64_t used = total - free;
|
||||||
|
|
||||||
Disk d;
|
Disk d;
|
||||||
d.name = path;
|
d.name = path;
|
||||||
d.total = total;
|
d.total = total;
|
||||||
d.free = free;
|
d.free = free;
|
||||||
d.used = total - free;
|
d.used = used;
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,10 @@ namespace Metrics
|
|||||||
buf.writeFloat(f);
|
buf.writeFloat(f);
|
||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
buf.writeFloat(memory.used);
|
buf.writeFloat(memory.mem_used);
|
||||||
buf.writeFloat(memory.total);
|
buf.writeFloat(memory.mem_total);
|
||||||
|
buf.writeFloat(memory.swap_used);
|
||||||
|
buf.writeFloat(memory.swap_total);
|
||||||
|
|
||||||
// Disks
|
// Disks
|
||||||
buf.writeUint8(static_cast<uint8_t>(disks.size()));
|
buf.writeUint8(static_cast<uint8_t>(disks.size()));
|
||||||
@@ -77,8 +79,10 @@ namespace Metrics
|
|||||||
h.cpu.coreLoads.push_back(buf.readFloat());
|
h.cpu.coreLoads.push_back(buf.readFloat());
|
||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
h.memory.used = buf.readFloat();
|
h.memory.mem_used = buf.readFloat();
|
||||||
h.memory.total = buf.readFloat();
|
h.memory.mem_total = buf.readFloat();
|
||||||
|
h.memory.swap_used = buf.readFloat();
|
||||||
|
h.memory.swap_total = buf.readFloat();
|
||||||
|
|
||||||
// Disks
|
// Disks
|
||||||
uint8_t numDisks = buf.readUint8();
|
uint8_t numDisks = buf.readUint8();
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ namespace Metrics
|
|||||||
{
|
{
|
||||||
struct Memory
|
struct Memory
|
||||||
{
|
{
|
||||||
float used;
|
float mem_used;
|
||||||
float available;
|
float mem_available;
|
||||||
float total;
|
float mem_total;
|
||||||
|
float swap_used;
|
||||||
|
float swap_total;
|
||||||
|
float swap_available;
|
||||||
};
|
};
|
||||||
} // namespace Metrics
|
} // namespace Metrics
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ namespace Model
|
|||||||
{
|
{
|
||||||
void HostRegistry::update(const std::string &host, const Metrics::Host &m)
|
void HostRegistry::update(const std::string &host, const Metrics::Host &m)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
hosts_[host] = m;
|
hosts[host] = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, Metrics::Host> HostRegistry::snapshot()
|
std::map<std::string, Metrics::Host> HostRegistry::snapshot()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
return hosts_;
|
return hosts;
|
||||||
}
|
}
|
||||||
} // namespace Model
|
} // namespace Model
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Model
|
|||||||
std::map<std::string, Metrics::Host> snapshot();
|
std::map<std::string, Metrics::Host> snapshot();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, Metrics::Host> hosts_;
|
std::map<std::string, Metrics::Host> hosts;
|
||||||
std::mutex mutex_;
|
std::mutex mutex;
|
||||||
};
|
};
|
||||||
} // namespace Model
|
} // namespace Model
|
||||||
|
|||||||
Reference in New Issue
Block a user