config: add sizex using CLayoutXValueData for reproducible layouting of image and label

BREAKING: removed image:size in favour of image:sizex
This commit is contained in:
Maximilian Seidler 2024-12-19 13:53:49 +01:00
parent d12b4a7fba
commit 8a13e97ee0
9 changed files with 120 additions and 42 deletions

View file

@ -12,8 +12,9 @@ using namespace Hyprutils::String;
enum eConfigValueDataTypes {
CVD_TYPE_INVALID = -1,
CVD_TYPE_LAYOUT = 0,
CVD_TYPE_LAYOUTXY = 0,
CVD_TYPE_GRADIENT = 1,
CVD_TYPE_LAYOUTX = 2,
};
class ICustomConfigValueData {
@ -25,22 +26,22 @@ class ICustomConfigValueData {
virtual std::string toString() = 0;
};
class CLayoutValueData : public ICustomConfigValueData {
class CLayoutXYValueData : public ICustomConfigValueData {
public:
CLayoutValueData() {};
virtual ~CLayoutValueData() {};
CLayoutXYValueData() {};
virtual ~CLayoutXYValueData() {};
virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_LAYOUT;
return CVD_TYPE_LAYOUTXY;
}
virtual std::string toString() {
return std::format("{}{},{}{}", m_vValues.x, (m_sIsRelative.x) ? "%" : "px", m_vValues.y, (m_sIsRelative.y) ? "%" : "px");
}
static CLayoutValueData* fromAnyPv(const std::any& v) {
static CLayoutXYValueData* fromAnyPv(const std::any& v) {
RASSERT(v.type() == typeid(void*), "Invalid config value type");
const auto P = (CLayoutValueData*)std::any_cast<void*>(v);
const auto P = (CLayoutXYValueData*)std::any_cast<void*>(v);
RASSERT(P, "Empty config value");
return P;
}
@ -59,6 +60,34 @@ class CLayoutValueData : public ICustomConfigValueData {
} m_sIsRelative;
};
class CLayoutXValueData : public ICustomConfigValueData {
public:
CLayoutXValueData() {};
virtual ~CLayoutXValueData() {};
virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_LAYOUTXY;
}
virtual std::string toString() {
return std::format("{}{}", m_fValue, (m_sIsRelative) ? "%" : "px");
}
static CLayoutXValueData* fromAnyPv(const std::any& v) {
RASSERT(v.type() == typeid(void*), "Invalid config value type");
const auto P = (CLayoutXValueData*)std::any_cast<void*>(v);
RASSERT(P, "Empty config value");
return P;
}
double getAbsolute(const Hyprutils::Math::Vector2D& viewport) {
return (m_sIsRelative) ? (m_fValue / 100) * viewport.x : m_fValue;
}
double m_fValue = 0;
bool m_sIsRelative = false;
};
class CGradientValueData : public ICustomConfigValueData {
public:
CGradientValueData() {};

View file

@ -25,15 +25,15 @@ static Hyprlang::CParseResult handleSource(const char* c, const char* v) {
return result;
}
static Hyprlang::CParseResult configHandleLayoutOption(const char* v, void** data) {
static Hyprlang::CParseResult configHandleLayoutXYOption(const char* v, void** data) {
const std::string VALUE = v;
Hyprlang::CParseResult result;
if (!*data)
*data = new CLayoutValueData();
*data = new CLayoutXYValueData();
const auto DATA = (CLayoutValueData*)(*data);
const auto DATA = (CLayoutXYValueData*)(*data);
const auto SPLIT = VALUE.find(',');
if (SPLIT == std::string::npos) {
result.setError(std::format("expected two comma seperated values, got {}", VALUE).c_str());
@ -65,9 +65,43 @@ static Hyprlang::CParseResult configHandleLayoutOption(const char* v, void** dat
return result;
}
static void configHandleLayoutOptionDestroy(void** data) {
static void configHandleLayoutXYOptionDestroy(void** data) {
if (*data)
delete reinterpret_cast<CLayoutValueData*>(*data);
delete reinterpret_cast<CLayoutXYValueData*>(*data);
}
static Hyprlang::CParseResult configHandleLayoutXOption(const char* VALUE, void** data) {
std::string V = VALUE;
Hyprlang::CParseResult result;
if (!*data)
*data = new CLayoutXValueData();
const auto DATA = reinterpret_cast<CLayoutXValueData*>(*data);
if (V.ends_with("px")) {
V.pop_back();
V.pop_back();
} else if (V.ends_with("%")) {
V.pop_back();
DATA->m_sIsRelative = true;
}
try {
DATA->m_fValue = configStringToInt(V);
} catch (std::exception& e) {
Debug::log(WARN, "Error parsing layout size {}", V);
result.setError(("Error parsing layout size " + V + ": " + e.what()).c_str());
}
return result;
}
static void configHandleLayoutXOptionDestroy(void** data) {
if (*data)
delete reinterpret_cast<CLayoutXValueData*>(*data);
}
static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** data) {
@ -152,8 +186,12 @@ inline static constexpr auto GRADIENTCONFIG = [](const char* default_value) -> H
return Hyprlang::CUSTOMTYPE{&configHandleGradientSet, configHandleGradientDestroy, default_value};
};
inline static constexpr auto LAYOUTCONFIG = [](const char* default_value) -> Hyprlang::CUSTOMTYPE {
return Hyprlang::CUSTOMTYPE{&configHandleLayoutOption, configHandleLayoutOptionDestroy, default_value};
inline static constexpr auto LAYOUTXYCONFIG = [](const char* default_value) -> Hyprlang::CUSTOMTYPE {
return Hyprlang::CUSTOMTYPE{&configHandleLayoutXYOption, configHandleLayoutXYOptionDestroy, default_value};
};
inline static constexpr auto LAYOUTXCONFIG = [](const char* default_value) -> Hyprlang::CUSTOMTYPE {
return Hyprlang::CUSTOMTYPE{&configHandleLayoutXOption, configHandleLayoutXOptionDestroy, default_value};
};
void CConfigManager::init() {
@ -197,12 +235,12 @@ void CConfigManager::init() {
m_config.addSpecialCategory("shape", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
m_config.addSpecialConfigValue("shape", "monitor", Hyprlang::STRING{""});
m_config.addSpecialConfigValue("shape", "size", LAYOUTCONFIG("100,100"));
m_config.addSpecialConfigValue("shape", "size", LAYOUTXYCONFIG("100,100"));
m_config.addSpecialConfigValue("shape", "rounding", Hyprlang::INT{0});
m_config.addSpecialConfigValue("shape", "border_size", Hyprlang::INT{0});
m_config.addSpecialConfigValue("shape", "border_color", GRADIENTCONFIG("0xFF00CFE6"));
m_config.addSpecialConfigValue("shape", "color", Hyprlang::INT{0xFF111111});
m_config.addSpecialConfigValue("shape", "position", LAYOUTCONFIG("0,0"));
m_config.addSpecialConfigValue("shape", "position", LAYOUTXYCONFIG("0,0"));
m_config.addSpecialConfigValue("shape", "halign", Hyprlang::STRING{"center"});
m_config.addSpecialConfigValue("shape", "valign", Hyprlang::STRING{"center"});
m_config.addSpecialConfigValue("shape", "rotate", Hyprlang::FLOAT{0});
@ -213,11 +251,11 @@ void CConfigManager::init() {
m_config.addSpecialCategory("image", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
m_config.addSpecialConfigValue("image", "monitor", Hyprlang::STRING{""});
m_config.addSpecialConfigValue("image", "path", Hyprlang::STRING{""});
m_config.addSpecialConfigValue("image", "size", Hyprlang::INT{150});
m_config.addSpecialConfigValue("image", "sizex", LAYOUTXCONFIG("10%"));
m_config.addSpecialConfigValue("image", "rounding", Hyprlang::INT{-1});
m_config.addSpecialConfigValue("image", "border_size", Hyprlang::INT{4});
m_config.addSpecialConfigValue("image", "border_color", GRADIENTCONFIG("0xFFDDDDDD"));
m_config.addSpecialConfigValue("image", "position", LAYOUTCONFIG("0,0"));
m_config.addSpecialConfigValue("image", "position", LAYOUTXYCONFIG("0,0"));
m_config.addSpecialConfigValue("image", "halign", Hyprlang::STRING{"center"});
m_config.addSpecialConfigValue("image", "valign", Hyprlang::STRING{"center"});
m_config.addSpecialConfigValue("image", "rotate", Hyprlang::FLOAT{0});
@ -228,7 +266,7 @@ void CConfigManager::init() {
m_config.addSpecialCategory("input-field", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
m_config.addSpecialConfigValue("input-field", "monitor", Hyprlang::STRING{""});
m_config.addSpecialConfigValue("input-field", "size", LAYOUTCONFIG("400,90"));
m_config.addSpecialConfigValue("input-field", "size", LAYOUTXYCONFIG("400,90"));
m_config.addSpecialConfigValue("input-field", "inner_color", Hyprlang::INT{0xFFDDDDDD});
m_config.addSpecialConfigValue("input-field", "outer_color", GRADIENTCONFIG("0xFF111111"));
m_config.addSpecialConfigValue("input-field", "outline_thickness", Hyprlang::INT{4});
@ -244,7 +282,7 @@ void CConfigManager::init() {
m_config.addSpecialConfigValue("input-field", "font_family", Hyprlang::STRING{"Sans"});
m_config.addSpecialConfigValue("input-field", "halign", Hyprlang::STRING{"center"});
m_config.addSpecialConfigValue("input-field", "valign", Hyprlang::STRING{"center"});
m_config.addSpecialConfigValue("input-field", "position", LAYOUTCONFIG("0,0"));
m_config.addSpecialConfigValue("input-field", "position", LAYOUTXYCONFIG("0,0"));
m_config.addSpecialConfigValue("input-field", "placeholder_text", Hyprlang::STRING{"<i>Input Password</i>"});
m_config.addSpecialConfigValue("input-field", "hide_input", Hyprlang::INT{0});
m_config.addSpecialConfigValue("input-field", "rounding", Hyprlang::INT{-1});
@ -263,9 +301,10 @@ void CConfigManager::init() {
m_config.addSpecialCategory("label", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
m_config.addSpecialConfigValue("label", "monitor", Hyprlang::STRING{""});
m_config.addSpecialConfigValue("label", "position", LAYOUTCONFIG("0,0"));
m_config.addSpecialConfigValue("label", "position", LAYOUTXYCONFIG("0,0"));
m_config.addSpecialConfigValue("label", "color", Hyprlang::INT{0xFFFFFFFF});
m_config.addSpecialConfigValue("label", "font_size", Hyprlang::INT{16});
m_config.addSpecialConfigValue("label", "sizex", LAYOUTXCONFIG("0"));
m_config.addSpecialConfigValue("label", "text", Hyprlang::STRING{"Sample Text"});
m_config.addSpecialConfigValue("label", "font_family", Hyprlang::STRING{"Sans"});
m_config.addSpecialConfigValue("label", "halign", Hyprlang::STRING{"none"});
@ -363,7 +402,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
std::any_cast<Hyprlang::STRING>(m_config.getSpecialConfigValue("image", "monitor", k.c_str())),
{
{"path", m_config.getSpecialConfigValue("image", "path", k.c_str())},
{"size", m_config.getSpecialConfigValue("image", "size", k.c_str())},
{"sizex", m_config.getSpecialConfigValue("image", "sizex", k.c_str())},
{"rounding", m_config.getSpecialConfigValue("image", "rounding", k.c_str())},
{"border_size", m_config.getSpecialConfigValue("image", "border_size", k.c_str())},
{"border_color", m_config.getSpecialConfigValue("image", "border_color", k.c_str())},
@ -434,6 +473,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
{"position", m_config.getSpecialConfigValue("label", "position", k.c_str())},
{"color", m_config.getSpecialConfigValue("label", "color", k.c_str())},
{"font_size", m_config.getSpecialConfigValue("label", "font_size", k.c_str())},
{"sizex", m_config.getSpecialConfigValue("label", "sizex", k.c_str())},
{"font_family", m_config.getSpecialConfigValue("label", "font_family", k.c_str())},
{"text", m_config.getSpecialConfigValue("label", "text", k.c_str())},
{"halign", m_config.getSpecialConfigValue("label", "halign", k.c_str())},

View file

@ -53,7 +53,7 @@ Vector2D IWidget::posFromHVAlign(const Vector2D& viewport, const Vector2D& size,
else if (valign != "none")
Debug::log(ERR, "IWidget: invalid valign {}", valign);
return pos;
return pos.round();
}
static void replaceAllAttempts(std::string& str) {

View file

@ -2,6 +2,7 @@
#include "../Renderer.hpp"
#include "../../core/hyprlock.hpp"
#include "../../helpers/Log.hpp"
#include "../../helpers/MiscFunctions.hpp"
#include "../../config/ConfigDataValues.hpp"
#include <cmath>
#include <hyprlang.hpp>
@ -46,7 +47,7 @@ void CImage::onTimerUpdate() {
}
try {
const auto MTIME = std::filesystem::last_write_time(path);
const auto MTIME = std::filesystem::last_write_time(absolutePath(path, "/"));
if (OLDPATH == path && MTIME == modificationTime)
return;
@ -83,11 +84,11 @@ CImage::CImage(const Vector2D& viewport_, COutput* output_, const std::string& r
viewport(viewport_), resourceID(resourceID_), output(output_), shadow(this, props, viewport_) {
try {
size = std::any_cast<Hyprlang::INT>(props.at("size"));
sizex = CLayoutXValueData::fromAnyPv(props.at("sizex"))->getAbsolute(viewport_);
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
pos = CLayoutXYValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
@ -102,7 +103,7 @@ CImage::CImage(const Vector2D& viewport_, COutput* output_, const std::string& r
}
try {
modificationTime = std::filesystem::last_write_time(path);
modificationTime = std::filesystem::last_write_time(absolutePath(path, "/"));
} catch (std::exception& e) { Debug::log(ERR, "{}", e.what()); }
angle = angle * M_PI / 180.0;
@ -132,14 +133,11 @@ bool CImage::draw(const SRenderData& data) {
const Vector2D IMAGEPOS = {border, border};
const Vector2D BORDERPOS = {0.0, 0.0};
const Vector2D TEXSIZE = asset->texture.m_vSize;
const float SCALEX = size / TEXSIZE.x;
const float SCALEY = size / TEXSIZE.y;
const auto XYRATIO = asset->texture.m_vSize.y / asset->texture.m_vSize.x;
const Vector2D SIZE = {sizex, sizex * XYRATIO};
// image with borders offset, with extra pixel for anti-aliasing when rotated
CBox texbox = {angle == 0 ? IMAGEPOS : IMAGEPOS + Vector2D{1.0, 1.0}, TEXSIZE};
texbox.w *= std::max(SCALEX, SCALEY);
texbox.h *= std::max(SCALEX, SCALEY);
CBox texbox = {angle == 0 ? IMAGEPOS : IMAGEPOS + Vector2D{1.0, 1.0}, SIZE.round()};
const bool ALLOWROUND = rounding > -1 && rounding < std::min(texbox.w, texbox.h) / 2.0;

View file

@ -29,7 +29,7 @@ class CImage : public IWidget {
private:
CFramebuffer imageFB;
int size;
double sizex;
int rounding;
double border;
double angle;

View file

@ -5,6 +5,7 @@
#include "../../helpers/Color.hpp"
#include "../../config/ConfigDataValues.hpp"
#include <hyprlang.hpp>
#include <hyprutils/math/Vector2D.hpp>
#include <stdexcept>
CLabel::~CLabel() {
@ -73,7 +74,8 @@ void CLabel::plantTimer() {
CLabel::CLabel(const Vector2D& viewport_, const std::unordered_map<std::string, std::any>& props, const std::string& output) :
outputStringPort(output), shadow(this, props, viewport_) {
try {
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
pos = CLayoutXYValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
sizex = CLayoutXValueData::fromAnyPv(props.at("sizex"))->getAbsolute(viewport_);
labelPreFormat = std::any_cast<Hyprlang::STRING>(props.at("text"));
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
@ -125,10 +127,18 @@ bool CLabel::draw(const SRenderData& data) {
shadow.draw(data);
// calc pos
pos = posFromHVAlign(viewport, asset->texture.m_vSize, configPos, halign, valign, angle);
if (asset->texture.m_vSize.x == 0)
return false;
CBox box = {pos.x, pos.y, asset->texture.m_vSize.x, asset->texture.m_vSize.y};
auto size = asset->texture.m_vSize;
if (sizex != 0) {
const auto XYRATIO = asset->texture.m_vSize.y / asset->texture.m_vSize.x;
size = {sizex, sizex * XYRATIO};
}
// calc pos
pos = posFromHVAlign(viewport, size.round(), configPos, halign, valign, angle);
CBox box = {pos, size};
box.rot = angle;
g_pRenderer->renderTexture(box, asset->texture, data.opacity);

View file

@ -32,6 +32,7 @@ class CLabel : public IWidget {
Vector2D viewport;
Vector2D pos;
Vector2D configPos;
double sizex;
double angle;
std::string resourceID;
std::string pendingResourceID; // if dynamic label

View file

@ -13,8 +13,8 @@ using namespace Hyprutils::String;
CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::unordered_map<std::string, std::any>& props, const std::string& output) :
viewport(viewport_), outputStringPort(output), shadow(this, props, viewport_) {
try {
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport_);
pos = CLayoutXYValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
size = CLayoutXYValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport_);
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
outThick = std::any_cast<Hyprlang::INT>(props.at("outline_thickness"));

View file

@ -7,12 +7,12 @@
CShape::CShape(const Vector2D& viewport_, const std::unordered_map<std::string, std::any>& props) : shadow(this, props, viewport_) {
try {
size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport_);
size = CLayoutXYValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport_);
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
color = std::any_cast<Hyprlang::INT>(props.at("color"));
borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color"));
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
pos = CLayoutXYValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));