mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-12-22 21:39:47 +01:00
core: add border shader and border gradients (#548)
* renderer: add renderBorder function * config: add CGradientValueData from Hyprland * input-field: change outer to take gradients Added gradient support to the following color options: - `outer_color` - `fail_color` - `check_color` - `capslock_color` - `numlock_color` - `bothlock_color`` * image: add gradient border * shape: add gradient border * shaders: adapt the new rounded smoothing factor from Hyprland
This commit is contained in:
parent
4fc133c96f
commit
6c3c444136
13 changed files with 499 additions and 112 deletions
|
@ -1,12 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../helpers/Log.hpp"
|
#include "../helpers/Log.hpp"
|
||||||
|
#include "../helpers/Color.hpp"
|
||||||
#include <hyprutils/math/Vector2D.hpp>
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
#include <hyprutils/string/VarList.hpp>
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
using namespace Hyprutils::String;
|
||||||
|
|
||||||
enum eConfigValueDataTypes {
|
enum eConfigValueDataTypes {
|
||||||
CVD_TYPE_INVALID = -1,
|
CVD_TYPE_INVALID = -1,
|
||||||
CVD_TYPE_LAYOUT = 0,
|
CVD_TYPE_LAYOUT = 0,
|
||||||
|
CVD_TYPE_GRADIENT = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICustomConfigValueData {
|
class ICustomConfigValueData {
|
||||||
|
@ -51,3 +58,57 @@ class CLayoutValueData : public ICustomConfigValueData {
|
||||||
bool y = false;
|
bool y = false;
|
||||||
} m_sIsRelative;
|
} m_sIsRelative;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CGradientValueData : public ICustomConfigValueData {
|
||||||
|
public:
|
||||||
|
CGradientValueData() {};
|
||||||
|
CGradientValueData(CColor col) {
|
||||||
|
m_vColors.push_back(col);
|
||||||
|
};
|
||||||
|
virtual ~CGradientValueData() {};
|
||||||
|
|
||||||
|
virtual eConfigValueDataTypes getDataType() {
|
||||||
|
return CVD_TYPE_GRADIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(CColor col) {
|
||||||
|
m_vColors.clear();
|
||||||
|
m_vColors.emplace_back(col);
|
||||||
|
m_fAngle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vector containing the colors */
|
||||||
|
std::vector<CColor> m_vColors;
|
||||||
|
|
||||||
|
/* Float corresponding to the angle (rad) */
|
||||||
|
float m_fAngle = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
bool operator==(const CGradientValueData& other) const {
|
||||||
|
if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_vColors.size(); ++i)
|
||||||
|
if (m_vColors[i] != other.m_vColors[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string toString() {
|
||||||
|
std::string result;
|
||||||
|
for (auto& c : m_vColors) {
|
||||||
|
result += std::format("{:x} ", c.getAsHex());
|
||||||
|
}
|
||||||
|
|
||||||
|
result += std::format("{}deg", (int)(m_fAngle * 180.0 / M_PI));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CGradientValueData* fromAnyPv(const std::any& v) {
|
||||||
|
RASSERT(v.type() == typeid(void*), "Invalid config value type");
|
||||||
|
const auto P = (CGradientValueData*)std::any_cast<void*>(v);
|
||||||
|
RASSERT(P, "Empty config value");
|
||||||
|
return P;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "../helpers/MiscFunctions.hpp"
|
#include "../helpers/MiscFunctions.hpp"
|
||||||
#include "../helpers/Log.hpp"
|
#include "../helpers/Log.hpp"
|
||||||
#include "../config/ConfigDataValues.hpp"
|
#include "../config/ConfigDataValues.hpp"
|
||||||
|
#include <hyprlang.hpp>
|
||||||
#include <hyprutils/path/Path.hpp>
|
#include <hyprutils/path/Path.hpp>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
@ -69,6 +70,65 @@ static void configHandleLayoutOptionDestroy(void** data) {
|
||||||
delete reinterpret_cast<CLayoutValueData*>(*data);
|
delete reinterpret_cast<CLayoutValueData*>(*data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** data) {
|
||||||
|
std::string V = VALUE;
|
||||||
|
|
||||||
|
if (!*data)
|
||||||
|
*data = new CGradientValueData();
|
||||||
|
|
||||||
|
const auto DATA = reinterpret_cast<CGradientValueData*>(*data);
|
||||||
|
|
||||||
|
CVarList varlist(V, 0, ' ');
|
||||||
|
DATA->m_vColors.clear();
|
||||||
|
|
||||||
|
std::string parseError = "";
|
||||||
|
|
||||||
|
for (auto const& var : varlist) {
|
||||||
|
if (var.find("deg") != std::string::npos) {
|
||||||
|
// last arg
|
||||||
|
try {
|
||||||
|
DATA->m_fAngle = std::stoi(var.substr(0, var.find("deg"))) * (M_PI / 180.0); // radians
|
||||||
|
} catch (...) {
|
||||||
|
Debug::log(WARN, "Error parsing gradient {}", V);
|
||||||
|
parseError = "Error parsing gradient " + V;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DATA->m_vColors.size() >= 10) {
|
||||||
|
Debug::log(WARN, "Error parsing gradient {}: max colors is 10.", V);
|
||||||
|
parseError = "Error parsing gradient " + V + ": max colors is 10.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DATA->m_vColors.push_back(CColor(configStringToInt(var)));
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
Debug::log(WARN, "Error parsing gradient {}", V);
|
||||||
|
parseError = "Error parsing gradient " + V + ": " + e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DATA->m_vColors.size() == 0) {
|
||||||
|
Debug::log(WARN, "Error parsing gradient {}", V);
|
||||||
|
parseError = "Error parsing gradient " + V + ": No colors?";
|
||||||
|
|
||||||
|
DATA->m_vColors.push_back(0); // transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
Hyprlang::CParseResult result;
|
||||||
|
if (!parseError.empty())
|
||||||
|
result.setError(parseError.c_str());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configHandleGradientDestroy(void** data) {
|
||||||
|
if (*data)
|
||||||
|
delete reinterpret_cast<CGradientValueData*>(*data);
|
||||||
|
}
|
||||||
|
|
||||||
static std::string getMainConfigPath() {
|
static std::string getMainConfigPath() {
|
||||||
static const auto paths = Hyprutils::Path::findConfig("hyprlock");
|
static const auto paths = Hyprutils::Path::findConfig("hyprlock");
|
||||||
if (paths.first.has_value())
|
if (paths.first.has_value())
|
||||||
|
@ -82,6 +142,14 @@ CConfigManager::CConfigManager(std::string configPath) :
|
||||||
configCurrentPath = configPath.empty() ? getMainConfigPath() : configPath;
|
configCurrentPath = configPath.empty() ? getMainConfigPath() : configPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static constexpr auto GRADIENTCONFIG = [](const char* default_value) -> Hyprlang::CUSTOMTYPE {
|
||||||
|
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};
|
||||||
|
};
|
||||||
|
|
||||||
void CConfigManager::init() {
|
void CConfigManager::init() {
|
||||||
|
|
||||||
#define SHADOWABLE(name) \
|
#define SHADOWABLE(name) \
|
||||||
|
@ -118,12 +186,12 @@ void CConfigManager::init() {
|
||||||
|
|
||||||
m_config.addSpecialCategory("shape", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
m_config.addSpecialCategory("shape", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||||
m_config.addSpecialConfigValue("shape", "monitor", Hyprlang::STRING{""});
|
m_config.addSpecialConfigValue("shape", "monitor", Hyprlang::STRING{""});
|
||||||
m_config.addSpecialConfigValue("shape", "size", Hyprlang::CUSTOMTYPE{&configHandleLayoutOption, configHandleLayoutOptionDestroy, "100,100"});
|
m_config.addSpecialConfigValue("shape", "size", LAYOUTCONFIG("100,100"));
|
||||||
m_config.addSpecialConfigValue("shape", "rounding", Hyprlang::INT{0});
|
m_config.addSpecialConfigValue("shape", "rounding", Hyprlang::INT{0});
|
||||||
m_config.addSpecialConfigValue("shape", "border_size", Hyprlang::INT{0});
|
m_config.addSpecialConfigValue("shape", "border_size", Hyprlang::INT{0});
|
||||||
m_config.addSpecialConfigValue("shape", "border_color", Hyprlang::INT{0xFF00CFE6});
|
m_config.addSpecialConfigValue("shape", "border_color", GRADIENTCONFIG("0xFF00CFE6"));
|
||||||
m_config.addSpecialConfigValue("shape", "color", Hyprlang::INT{0xFF111111});
|
m_config.addSpecialConfigValue("shape", "color", Hyprlang::INT{0xFF111111});
|
||||||
m_config.addSpecialConfigValue("shape", "position", Hyprlang::CUSTOMTYPE{&configHandleLayoutOption, configHandleLayoutOptionDestroy, "0,0"});
|
m_config.addSpecialConfigValue("shape", "position", LAYOUTCONFIG("0,0"));
|
||||||
m_config.addSpecialConfigValue("shape", "halign", Hyprlang::STRING{"center"});
|
m_config.addSpecialConfigValue("shape", "halign", Hyprlang::STRING{"center"});
|
||||||
m_config.addSpecialConfigValue("shape", "valign", Hyprlang::STRING{"center"});
|
m_config.addSpecialConfigValue("shape", "valign", Hyprlang::STRING{"center"});
|
||||||
m_config.addSpecialConfigValue("shape", "rotate", Hyprlang::FLOAT{0});
|
m_config.addSpecialConfigValue("shape", "rotate", Hyprlang::FLOAT{0});
|
||||||
|
@ -137,8 +205,8 @@ void CConfigManager::init() {
|
||||||
m_config.addSpecialConfigValue("image", "size", Hyprlang::INT{150});
|
m_config.addSpecialConfigValue("image", "size", Hyprlang::INT{150});
|
||||||
m_config.addSpecialConfigValue("image", "rounding", Hyprlang::INT{-1});
|
m_config.addSpecialConfigValue("image", "rounding", Hyprlang::INT{-1});
|
||||||
m_config.addSpecialConfigValue("image", "border_size", Hyprlang::INT{4});
|
m_config.addSpecialConfigValue("image", "border_size", Hyprlang::INT{4});
|
||||||
m_config.addSpecialConfigValue("image", "border_color", Hyprlang::INT{0xFFDDDDDD});
|
m_config.addSpecialConfigValue("image", "border_color", GRADIENTCONFIG("0xFFDDDDDD"));
|
||||||
m_config.addSpecialConfigValue("image", "position", Hyprlang::CUSTOMTYPE{&configHandleLayoutOption, configHandleLayoutOptionDestroy, "0,0"});
|
m_config.addSpecialConfigValue("image", "position", LAYOUTCONFIG("0,0"));
|
||||||
m_config.addSpecialConfigValue("image", "halign", Hyprlang::STRING{"center"});
|
m_config.addSpecialConfigValue("image", "halign", Hyprlang::STRING{"center"});
|
||||||
m_config.addSpecialConfigValue("image", "valign", Hyprlang::STRING{"center"});
|
m_config.addSpecialConfigValue("image", "valign", Hyprlang::STRING{"center"});
|
||||||
m_config.addSpecialConfigValue("image", "rotate", Hyprlang::FLOAT{0});
|
m_config.addSpecialConfigValue("image", "rotate", Hyprlang::FLOAT{0});
|
||||||
|
@ -149,9 +217,9 @@ void CConfigManager::init() {
|
||||||
|
|
||||||
m_config.addSpecialCategory("input-field", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
m_config.addSpecialCategory("input-field", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||||
m_config.addSpecialConfigValue("input-field", "monitor", Hyprlang::STRING{""});
|
m_config.addSpecialConfigValue("input-field", "monitor", Hyprlang::STRING{""});
|
||||||
m_config.addSpecialConfigValue("input-field", "size", Hyprlang::CUSTOMTYPE{&configHandleLayoutOption, configHandleLayoutOptionDestroy, "400,90"});
|
m_config.addSpecialConfigValue("input-field", "size", LAYOUTCONFIG("400,90"));
|
||||||
m_config.addSpecialConfigValue("input-field", "inner_color", Hyprlang::INT{0xFFDDDDDD});
|
m_config.addSpecialConfigValue("input-field", "inner_color", Hyprlang::INT{0xFFDDDDDD});
|
||||||
m_config.addSpecialConfigValue("input-field", "outer_color", Hyprlang::INT{0xFF111111});
|
m_config.addSpecialConfigValue("input-field", "outer_color", GRADIENTCONFIG("0xFF111111"));
|
||||||
m_config.addSpecialConfigValue("input-field", "outline_thickness", Hyprlang::INT{4});
|
m_config.addSpecialConfigValue("input-field", "outline_thickness", Hyprlang::INT{4});
|
||||||
m_config.addSpecialConfigValue("input-field", "dots_size", Hyprlang::FLOAT{0.25});
|
m_config.addSpecialConfigValue("input-field", "dots_size", Hyprlang::FLOAT{0.25});
|
||||||
m_config.addSpecialConfigValue("input-field", "dots_center", Hyprlang::INT{1});
|
m_config.addSpecialConfigValue("input-field", "dots_center", Hyprlang::INT{1});
|
||||||
|
@ -165,18 +233,18 @@ void CConfigManager::init() {
|
||||||
m_config.addSpecialConfigValue("input-field", "font_family", Hyprlang::STRING{"Sans"});
|
m_config.addSpecialConfigValue("input-field", "font_family", Hyprlang::STRING{"Sans"});
|
||||||
m_config.addSpecialConfigValue("input-field", "halign", Hyprlang::STRING{"center"});
|
m_config.addSpecialConfigValue("input-field", "halign", Hyprlang::STRING{"center"});
|
||||||
m_config.addSpecialConfigValue("input-field", "valign", Hyprlang::STRING{"center"});
|
m_config.addSpecialConfigValue("input-field", "valign", Hyprlang::STRING{"center"});
|
||||||
m_config.addSpecialConfigValue("input-field", "position", Hyprlang::CUSTOMTYPE{&configHandleLayoutOption, configHandleLayoutOptionDestroy, "0,0"});
|
m_config.addSpecialConfigValue("input-field", "position", LAYOUTCONFIG("0,0"));
|
||||||
m_config.addSpecialConfigValue("input-field", "placeholder_text", Hyprlang::STRING{"<i>Input Password</i>"});
|
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", "hide_input", Hyprlang::INT{0});
|
||||||
m_config.addSpecialConfigValue("input-field", "rounding", Hyprlang::INT{-1});
|
m_config.addSpecialConfigValue("input-field", "rounding", Hyprlang::INT{-1});
|
||||||
m_config.addSpecialConfigValue("input-field", "check_color", Hyprlang::INT{0xFFCC8822});
|
m_config.addSpecialConfigValue("input-field", "check_color", GRADIENTCONFIG("0xFF22CC88"));
|
||||||
m_config.addSpecialConfigValue("input-field", "fail_color", Hyprlang::INT{0xFFCC2222});
|
m_config.addSpecialConfigValue("input-field", "fail_color", GRADIENTCONFIG("0xFFCC2222"));
|
||||||
m_config.addSpecialConfigValue("input-field", "fail_text", Hyprlang::STRING{"<i>$FAIL</i>"});
|
m_config.addSpecialConfigValue("input-field", "fail_text", Hyprlang::STRING{"<i>$FAIL</i>"});
|
||||||
m_config.addSpecialConfigValue("input-field", "fail_timeout", Hyprlang::INT{2000});
|
m_config.addSpecialConfigValue("input-field", "fail_timeout", Hyprlang::INT{2000});
|
||||||
m_config.addSpecialConfigValue("input-field", "fail_transition", Hyprlang::INT{300});
|
m_config.addSpecialConfigValue("input-field", "fail_transition", Hyprlang::INT{300});
|
||||||
m_config.addSpecialConfigValue("input-field", "capslock_color", Hyprlang::INT{-1});
|
m_config.addSpecialConfigValue("input-field", "capslock_color", GRADIENTCONFIG(""));
|
||||||
m_config.addSpecialConfigValue("input-field", "numlock_color", Hyprlang::INT{-1});
|
m_config.addSpecialConfigValue("input-field", "numlock_color", GRADIENTCONFIG(""));
|
||||||
m_config.addSpecialConfigValue("input-field", "bothlock_color", Hyprlang::INT{-1});
|
m_config.addSpecialConfigValue("input-field", "bothlock_color", GRADIENTCONFIG(""));
|
||||||
m_config.addSpecialConfigValue("input-field", "invert_numlock", Hyprlang::INT{0});
|
m_config.addSpecialConfigValue("input-field", "invert_numlock", Hyprlang::INT{0});
|
||||||
m_config.addSpecialConfigValue("input-field", "swap_font_color", Hyprlang::INT{0});
|
m_config.addSpecialConfigValue("input-field", "swap_font_color", Hyprlang::INT{0});
|
||||||
m_config.addSpecialConfigValue("input-field", "zindex", Hyprlang::INT{0});
|
m_config.addSpecialConfigValue("input-field", "zindex", Hyprlang::INT{0});
|
||||||
|
@ -184,7 +252,7 @@ void CConfigManager::init() {
|
||||||
|
|
||||||
m_config.addSpecialCategory("label", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
m_config.addSpecialCategory("label", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||||
m_config.addSpecialConfigValue("label", "monitor", Hyprlang::STRING{""});
|
m_config.addSpecialConfigValue("label", "monitor", Hyprlang::STRING{""});
|
||||||
m_config.addSpecialConfigValue("label", "position", Hyprlang::CUSTOMTYPE{&configHandleLayoutOption, configHandleLayoutOptionDestroy, "0,0"});
|
m_config.addSpecialConfigValue("label", "position", LAYOUTCONFIG("0,0"));
|
||||||
m_config.addSpecialConfigValue("label", "color", Hyprlang::INT{0xFFFFFFFF});
|
m_config.addSpecialConfigValue("label", "color", Hyprlang::INT{0xFFFFFFFF});
|
||||||
m_config.addSpecialConfigValue("label", "font_size", Hyprlang::INT{16});
|
m_config.addSpecialConfigValue("label", "font_size", Hyprlang::INT{16});
|
||||||
m_config.addSpecialConfigValue("label", "text", Hyprlang::STRING{"Sample Text"});
|
m_config.addSpecialConfigValue("label", "text", Hyprlang::STRING{"Sample Text"});
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include "MiscFunctions.hpp"
|
#include "MiscFunctions.hpp"
|
||||||
|
#include "../helpers/Log.hpp"
|
||||||
|
#include <hyprutils/string/String.hpp>
|
||||||
|
|
||||||
|
using namespace Hyprutils::String;
|
||||||
|
|
||||||
std::string absolutePath(const std::string& rawpath, const std::string& currentDir) {
|
std::string absolutePath(const std::string& rawpath, const std::string& currentDir) {
|
||||||
std::filesystem::path path(rawpath);
|
std::filesystem::path path(rawpath);
|
||||||
|
@ -16,3 +20,43 @@ std::string absolutePath(const std::string& rawpath, const std::string& currentD
|
||||||
return std::filesystem::weakly_canonical(path);
|
return std::filesystem::weakly_canonical(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t configStringToInt(const std::string& VALUE) {
|
||||||
|
if (VALUE.starts_with("0x")) {
|
||||||
|
// Values with 0x are hex
|
||||||
|
const auto VALUEWITHOUTHEX = VALUE.substr(2);
|
||||||
|
return stol(VALUEWITHOUTHEX, nullptr, 16);
|
||||||
|
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
|
||||||
|
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
|
||||||
|
|
||||||
|
if (trim(VALUEWITHOUTFUNC).length() != 8) {
|
||||||
|
Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length());
|
||||||
|
throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
||||||
|
|
||||||
|
// now we need to RGBA -> ARGB. The config holds ARGB only.
|
||||||
|
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
|
||||||
|
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
|
||||||
|
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
|
||||||
|
|
||||||
|
if (trim(VALUEWITHOUTFUNC).length() != 6) {
|
||||||
|
Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length());
|
||||||
|
throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
||||||
|
|
||||||
|
return RGB + 0xFF000000; // 0xFF for opaque
|
||||||
|
} else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) {
|
||||||
|
return 1;
|
||||||
|
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VALUE.empty() || !isNumber(VALUE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return std::stoll(VALUE);
|
||||||
|
}
|
|
@ -5,3 +5,4 @@
|
||||||
#include <hyprutils/math/Vector2D.hpp>
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
std::string absolutePath(const std::string&, const std::string&);
|
std::string absolutePath(const std::string&, const std::string&);
|
||||||
|
int64_t configStringToInt(const std::string& VALUE);
|
||||||
|
|
|
@ -150,6 +150,23 @@ CRenderer::CRenderer() {
|
||||||
blurFinishShader.colorizeTint = glGetUniformLocation(prog, "colorizeTint");
|
blurFinishShader.colorizeTint = glGetUniformLocation(prog, "colorizeTint");
|
||||||
blurFinishShader.boostA = glGetUniformLocation(prog, "boostA");
|
blurFinishShader.boostA = glGetUniformLocation(prog, "boostA");
|
||||||
|
|
||||||
|
prog = createProgram(QUADVERTSRC, FRAGBORDER);
|
||||||
|
borderShader.program = prog;
|
||||||
|
borderShader.proj = glGetUniformLocation(prog, "proj");
|
||||||
|
borderShader.thick = glGetUniformLocation(prog, "thick");
|
||||||
|
borderShader.posAttrib = glGetAttribLocation(prog, "pos");
|
||||||
|
borderShader.texAttrib = glGetAttribLocation(prog, "texcoord");
|
||||||
|
borderShader.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||||
|
borderShader.bottomRight = glGetUniformLocation(prog, "bottomRight");
|
||||||
|
borderShader.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||||
|
borderShader.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed");
|
||||||
|
borderShader.radius = glGetUniformLocation(prog, "radius");
|
||||||
|
borderShader.radiusOuter = glGetUniformLocation(prog, "radiusOuter");
|
||||||
|
borderShader.gradient = glGetUniformLocation(prog, "gradient");
|
||||||
|
borderShader.gradientLength = glGetUniformLocation(prog, "gradientLength");
|
||||||
|
borderShader.angle = glGetUniformLocation(prog, "angle");
|
||||||
|
borderShader.alpha = glGetUniformLocation(prog, "alpha");
|
||||||
|
|
||||||
asyncResourceGatherer = std::make_unique<CAsyncResourceGatherer>();
|
asyncResourceGatherer = std::make_unique<CAsyncResourceGatherer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +267,43 @@ void CRenderer::renderRect(const CBox& box, const CColor& col, int rounding) {
|
||||||
glDisableVertexAttribArray(rectShader.posAttrib);
|
glDisableVertexAttribArray(rectShader.posAttrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CRenderer::renderBorder(const CBox& box, const CGradientValueData& gradient, int thickness, int rounding, float alpha) {
|
||||||
|
Mat3x3 matrix = projMatrix.projectBox(box, HYPRUTILS_TRANSFORM_NORMAL, box.rot);
|
||||||
|
Mat3x3 glMatrix = projection.copy().multiply(matrix);
|
||||||
|
|
||||||
|
glUseProgram(borderShader.program);
|
||||||
|
|
||||||
|
glUniformMatrix3fv(borderShader.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
|
||||||
|
|
||||||
|
static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail
|
||||||
|
|
||||||
|
glUniform4fv(borderShader.gradient, gradient.m_vColors.size(), (float*)gradient.m_vColors.data());
|
||||||
|
glUniform1i(borderShader.gradientLength, gradient.m_vColors.size());
|
||||||
|
glUniform1f(borderShader.angle, (int)(gradient.m_fAngle / (M_PI / 180.0)) % 360 * (M_PI / 180.0));
|
||||||
|
glUniform1f(borderShader.alpha, alpha);
|
||||||
|
|
||||||
|
const auto TOPLEFT = Vector2D(box.x, box.y);
|
||||||
|
const auto FULLSIZE = Vector2D(box.width, box.height);
|
||||||
|
|
||||||
|
glUniform2f(borderShader.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
|
||||||
|
glUniform2f(borderShader.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
|
||||||
|
glUniform2f(borderShader.fullSizeUntransformed, (float)box.width, (float)box.height);
|
||||||
|
glUniform1f(borderShader.radius, rounding);
|
||||||
|
glUniform1f(borderShader.radiusOuter, rounding);
|
||||||
|
glUniform1f(borderShader.thick, thickness);
|
||||||
|
|
||||||
|
glVertexAttribPointer(borderShader.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||||
|
glVertexAttribPointer(borderShader.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(borderShader.posAttrib);
|
||||||
|
glEnableVertexAttribArray(borderShader.texAttrib);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(borderShader.posAttrib);
|
||||||
|
glDisableVertexAttribArray(borderShader.texAttrib);
|
||||||
|
}
|
||||||
|
|
||||||
void CRenderer::renderTexture(const CBox& box, const CTexture& tex, float a, int rounding, std::optional<eTransform> tr) {
|
void CRenderer::renderTexture(const CBox& box, const CTexture& tex, float a, int rounding, std::optional<eTransform> tr) {
|
||||||
Mat3x3 matrix = projMatrix.projectBox(box, tr.value_or(HYPRUTILS_TRANSFORM_FLIPPED_180), box.rot);
|
Mat3x3 matrix = projMatrix.projectBox(box, tr.value_or(HYPRUTILS_TRANSFORM_FLIPPED_180), box.rot);
|
||||||
Mat3x3 glMatrix = projection.copy().multiply(matrix);
|
Mat3x3 glMatrix = projection.copy().multiply(matrix);
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
#include "Shader.hpp"
|
#include "Shader.hpp"
|
||||||
#include "../core/LockSurface.hpp"
|
#include "../core/LockSurface.hpp"
|
||||||
#include "../helpers/Color.hpp"
|
#include "../helpers/Color.hpp"
|
||||||
#include "../helpers/Math.hpp"
|
|
||||||
#include "AsyncResourceGatherer.hpp"
|
#include "AsyncResourceGatherer.hpp"
|
||||||
|
#include "../config/ConfigDataValues.hpp"
|
||||||
#include "widgets/IWidget.hpp"
|
#include "widgets/IWidget.hpp"
|
||||||
#include "Framebuffer.hpp"
|
#include "Framebuffer.hpp"
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ class CRenderer {
|
||||||
SRenderFeedback renderLock(const CSessionLockSurface& surface);
|
SRenderFeedback renderLock(const CSessionLockSurface& surface);
|
||||||
|
|
||||||
void renderRect(const CBox& box, const CColor& col, int rounding = 0);
|
void renderRect(const CBox& box, const CColor& col, int rounding = 0);
|
||||||
|
void renderBorder(const CBox& box, const CGradientValueData& gradient, int thickness, int rounding = 0, float alpha = 1.0);
|
||||||
void renderTexture(const CBox& box, const CTexture& tex, float a = 1.0, int rounding = 0, std::optional<eTransform> tr = {});
|
void renderTexture(const CBox& box, const CTexture& tex, float a = 1.0, int rounding = 0, std::optional<eTransform> tr = {});
|
||||||
void blurFB(const CFramebuffer& outfb, SBlurParams params);
|
void blurFB(const CFramebuffer& outfb, SBlurParams params);
|
||||||
|
|
||||||
|
@ -53,6 +54,7 @@ class CRenderer {
|
||||||
CShader blurShader2;
|
CShader blurShader2;
|
||||||
CShader blurPrepareShader;
|
CShader blurPrepareShader;
|
||||||
CShader blurFinishShader;
|
CShader blurFinishShader;
|
||||||
|
CShader borderShader;
|
||||||
|
|
||||||
Mat3x3 projMatrix = Mat3x3::identity();
|
Mat3x3 projMatrix = Mat3x3::identity();
|
||||||
Mat3x3 projection;
|
Mat3x3 projection;
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <format>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
constexpr float SHADER_ROUNDED_SMOOTHING_FACTOR = M_PI / 5.34665792551;
|
||||||
|
|
||||||
inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string {
|
inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string {
|
||||||
return R"#(
|
return R"#(
|
||||||
|
@ -12,17 +16,21 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar
|
||||||
pixCoord -= fullSize * 0.5 - radius;
|
pixCoord -= fullSize * 0.5 - radius;
|
||||||
pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left
|
pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left
|
||||||
|
|
||||||
|
// smoothing constant for the edge: more = blurrier, but smoother
|
||||||
|
const float SMOOTHING_CONSTANT = )#" +
|
||||||
|
std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(;
|
||||||
|
|
||||||
if (pixCoord.x + pixCoord.y > radius) {
|
if (pixCoord.x + pixCoord.y > radius) {
|
||||||
|
|
||||||
float dist = length(pixCoord);
|
float dist = length(pixCoord);
|
||||||
|
|
||||||
if (dist > radius + 1.0)
|
if (dist > radius + SMOOTHING_CONSTANT * 2.0)
|
||||||
discard;
|
discard;
|
||||||
|
|
||||||
if (dist > radius - 1.0) {
|
if (dist > radius - SMOOTHING_CONSTANT * 2.0) {
|
||||||
float dist = length(pixCoord);
|
float dist = length(pixCoord);
|
||||||
|
|
||||||
float normalized = 1.0 - smoothstep(0.0, 1.0, dist - radius + 0.5);
|
float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0));
|
||||||
|
|
||||||
)#" +
|
)#" +
|
||||||
colorVarName + R"#( = )#" + colorVarName + R"#( * normalized;
|
colorVarName + R"#( = )#" + colorVarName + R"#( * normalized;
|
||||||
|
@ -362,3 +370,124 @@ void main() {
|
||||||
gl_FragColor = pixColor;
|
gl_FragColor = pixColor;
|
||||||
}
|
}
|
||||||
)#";
|
)#";
|
||||||
|
|
||||||
|
// makes a stencil without corners
|
||||||
|
inline const std::string FRAGBORDER = R"#(
|
||||||
|
precision highp float;
|
||||||
|
varying vec4 v_color;
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
|
||||||
|
uniform vec2 topLeft;
|
||||||
|
uniform vec2 fullSize;
|
||||||
|
uniform vec2 fullSizeUntransformed;
|
||||||
|
uniform float radius;
|
||||||
|
uniform float radiusOuter;
|
||||||
|
uniform float thick;
|
||||||
|
|
||||||
|
uniform vec4 gradient[10];
|
||||||
|
uniform int gradientLength;
|
||||||
|
uniform float angle;
|
||||||
|
uniform float alpha;
|
||||||
|
|
||||||
|
vec4 getColorForCoord(vec2 normalizedCoord) {
|
||||||
|
if (gradientLength < 2)
|
||||||
|
return gradient[0];
|
||||||
|
|
||||||
|
float finalAng = 0.0;
|
||||||
|
|
||||||
|
if (angle > 4.71 /* 270 deg */) {
|
||||||
|
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||||
|
finalAng = 6.28 - angle;
|
||||||
|
} else if (angle > 3.14 /* 180 deg */) {
|
||||||
|
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||||
|
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||||
|
finalAng = angle - 3.14;
|
||||||
|
} else if (angle > 1.57 /* 90 deg */) {
|
||||||
|
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||||
|
finalAng = 3.14 - angle;
|
||||||
|
} else {
|
||||||
|
finalAng = angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sine = sin(finalAng);
|
||||||
|
|
||||||
|
float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradientLength - 1);
|
||||||
|
int bottom = int(floor(progress));
|
||||||
|
int top = bottom + 1;
|
||||||
|
|
||||||
|
return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
highp vec2 pixCoord = vec2(gl_FragCoord);
|
||||||
|
highp vec2 pixCoordOuter = pixCoord;
|
||||||
|
highp vec2 originalPixCoord = v_texcoord;
|
||||||
|
originalPixCoord *= fullSizeUntransformed;
|
||||||
|
float additionalAlpha = 1.0;
|
||||||
|
|
||||||
|
vec4 pixColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
pixCoord -= topLeft + fullSize * 0.5;
|
||||||
|
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
||||||
|
pixCoordOuter = pixCoord;
|
||||||
|
pixCoord -= fullSize * 0.5 - radius;
|
||||||
|
pixCoordOuter -= fullSize * 0.5 - radiusOuter;
|
||||||
|
|
||||||
|
// center the pixes dont make it top-left
|
||||||
|
pixCoord += vec2(1.0, 1.0) / fullSize;
|
||||||
|
pixCoordOuter += vec2(1.0, 1.0) / fullSize;
|
||||||
|
|
||||||
|
if (min(pixCoord.x, pixCoord.y) > 0.0 && radius > 0.0) {
|
||||||
|
// smoothing constant for the edge: more = blurrier, but smoother
|
||||||
|
const float SMOOTHING_CONSTANT = )#" +
|
||||||
|
std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(;
|
||||||
|
|
||||||
|
float dist = length(pixCoord);
|
||||||
|
float distOuter = length(pixCoordOuter);
|
||||||
|
float h = (thick / 2.0);
|
||||||
|
|
||||||
|
if (dist < radius - h) {
|
||||||
|
// lower
|
||||||
|
float normalized = smoothstep(0.0, 1.0, (dist - radius + thick + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0));
|
||||||
|
additionalAlpha *= normalized;
|
||||||
|
done = true;
|
||||||
|
} else if (min(pixCoordOuter.x, pixCoordOuter.y) > 0.0) {
|
||||||
|
// higher
|
||||||
|
float normalized = 1.0 - smoothstep(0.0, 1.0, (distOuter - radiusOuter + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0));
|
||||||
|
additionalAlpha *= normalized;
|
||||||
|
done = true;
|
||||||
|
} else if (distOuter < radiusOuter - h) {
|
||||||
|
additionalAlpha = 1.0;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check for other shit
|
||||||
|
if (!done) {
|
||||||
|
// distance to all straight bb borders
|
||||||
|
float distanceT = originalPixCoord[1];
|
||||||
|
float distanceB = fullSizeUntransformed[1] - originalPixCoord[1];
|
||||||
|
float distanceL = originalPixCoord[0];
|
||||||
|
float distanceR = fullSizeUntransformed[0] - originalPixCoord[0];
|
||||||
|
|
||||||
|
// get the smallest
|
||||||
|
float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR));
|
||||||
|
|
||||||
|
if (smallest > thick)
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalAlpha == 0.0)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
pixColor = getColorForCoord(v_texcoord);
|
||||||
|
pixColor.rgb *= pixColor[3];
|
||||||
|
|
||||||
|
pixColor *= alpha * additionalAlpha;
|
||||||
|
|
||||||
|
gl_FragColor = pixColor;
|
||||||
|
}
|
||||||
|
)#";
|
|
@ -86,7 +86,7 @@ CImage::CImage(const Vector2D& viewport_, COutput* output_, const std::string& r
|
||||||
size = std::any_cast<Hyprlang::INT>(props.at("size"));
|
size = std::any_cast<Hyprlang::INT>(props.at("size"));
|
||||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||||
color = std::any_cast<Hyprlang::INT>(props.at("border_color"));
|
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
||||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||||
|
@ -156,7 +156,8 @@ bool CImage::draw(const SRenderData& data) {
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
if (border > 0)
|
if (border > 0)
|
||||||
g_pRenderer->renderRect(borderBox, color, ALLOWROUND ? (rounding == 0 ? 0 : rounding + std::round(border / M_PI)) : std::min(borderBox.w, borderBox.h) / 2.0);
|
g_pRenderer->renderBorder(borderBox, color, border, ALLOWROUND ? (rounding == 0 ? 0 : rounding + std::round(border / M_PI)) : std::min(borderBox.w, borderBox.h) / 2.0,
|
||||||
|
data.opacity);
|
||||||
|
|
||||||
texbox.round();
|
texbox.round();
|
||||||
g_pRenderer->renderTexture(texbox, asset->texture, 1.0, ALLOWROUND ? rounding : std::min(texbox.w, texbox.h) / 2.0, HYPRUTILS_TRANSFORM_NORMAL);
|
g_pRenderer->renderTexture(texbox, asset->texture, 1.0, ALLOWROUND ? rounding : std::min(texbox.w, texbox.h) / 2.0, HYPRUTILS_TRANSFORM_NORMAL);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "IWidget.hpp"
|
#include "IWidget.hpp"
|
||||||
#include "../../helpers/Color.hpp"
|
#include "../../helpers/Color.hpp"
|
||||||
#include "../../helpers/Math.hpp"
|
#include "../../helpers/Math.hpp"
|
||||||
|
#include "../../config/ConfigDataValues.hpp"
|
||||||
#include "../../core/Timer.hpp"
|
#include "../../core/Timer.hpp"
|
||||||
#include "../AsyncResourceGatherer.hpp"
|
#include "../AsyncResourceGatherer.hpp"
|
||||||
#include "Shadowable.hpp"
|
#include "Shadowable.hpp"
|
||||||
|
@ -32,7 +33,7 @@ class CImage : public IWidget {
|
||||||
int rounding;
|
int rounding;
|
||||||
double border;
|
double border;
|
||||||
double angle;
|
double angle;
|
||||||
CColor color;
|
CGradientValueData color;
|
||||||
Vector2D pos;
|
Vector2D pos;
|
||||||
|
|
||||||
std::string halign, valign, path;
|
std::string halign, valign, path;
|
||||||
|
|
|
@ -33,14 +33,14 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
||||||
configFailTimeoutMs = std::any_cast<Hyprlang::INT>(props.at("fail_timeout"));
|
configFailTimeoutMs = std::any_cast<Hyprlang::INT>(props.at("fail_timeout"));
|
||||||
fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
||||||
colorConfig.transitionMs = std::any_cast<Hyprlang::INT>(props.at("fail_transition"));
|
colorConfig.transitionMs = std::any_cast<Hyprlang::INT>(props.at("fail_transition"));
|
||||||
colorConfig.outer = std::any_cast<Hyprlang::INT>(props.at("outer_color"));
|
colorConfig.outer = CGradientValueData::fromAnyPv(props.at("outer_color"));
|
||||||
colorConfig.inner = std::any_cast<Hyprlang::INT>(props.at("inner_color"));
|
colorConfig.inner = std::any_cast<Hyprlang::INT>(props.at("inner_color"));
|
||||||
colorConfig.font = std::any_cast<Hyprlang::INT>(props.at("font_color"));
|
colorConfig.font = std::any_cast<Hyprlang::INT>(props.at("font_color"));
|
||||||
colorConfig.fail = std::any_cast<Hyprlang::INT>(props.at("fail_color"));
|
colorConfig.fail = CGradientValueData::fromAnyPv(props.at("fail_color"));
|
||||||
colorConfig.check = std::any_cast<Hyprlang::INT>(props.at("check_color"));
|
colorConfig.check = CGradientValueData::fromAnyPv(props.at("check_color"));
|
||||||
colorConfig.both = std::any_cast<Hyprlang::INT>(props.at("bothlock_color"));
|
colorConfig.both = CGradientValueData::fromAnyPv(props.at("bothlock_color"));
|
||||||
colorConfig.caps = std::any_cast<Hyprlang::INT>(props.at("capslock_color"));
|
colorConfig.caps = CGradientValueData::fromAnyPv(props.at("capslock_color"));
|
||||||
colorConfig.num = std::any_cast<Hyprlang::INT>(props.at("numlock_color"));
|
colorConfig.num = CGradientValueData::fromAnyPv(props.at("numlock_color"));
|
||||||
colorConfig.invertNum = std::any_cast<Hyprlang::INT>(props.at("invert_numlock"));
|
colorConfig.invertNum = std::any_cast<Hyprlang::INT>(props.at("invert_numlock"));
|
||||||
colorConfig.swapFont = std::any_cast<Hyprlang::INT>(props.at("swap_font_color"));
|
colorConfig.swapFont = std::any_cast<Hyprlang::INT>(props.at("swap_font_color"));
|
||||||
} catch (const std::bad_any_cast& e) {
|
} catch (const std::bad_any_cast& e) {
|
||||||
|
@ -57,13 +57,14 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
||||||
dots.spacing = std::clamp(dots.spacing, -1.f, 1.f);
|
dots.spacing = std::clamp(dots.spacing, -1.f, 1.f);
|
||||||
colorConfig.transitionMs = std::clamp(colorConfig.transitionMs, 0, 1000);
|
colorConfig.transitionMs = std::clamp(colorConfig.transitionMs, 0, 1000);
|
||||||
|
|
||||||
colorConfig.both = colorConfig.both == -1 ? colorConfig.outer : colorConfig.both;
|
colorConfig.both = colorConfig.both->m_vColors.empty() ? colorConfig.outer : colorConfig.both;
|
||||||
colorConfig.caps = colorConfig.caps == -1 ? colorConfig.outer : colorConfig.caps;
|
colorConfig.caps = colorConfig.caps->m_vColors.empty() ? colorConfig.outer : colorConfig.caps;
|
||||||
colorConfig.num = colorConfig.num == -1 ? colorConfig.outer : colorConfig.num;
|
colorConfig.num = colorConfig.num->m_vColors.empty() ? colorConfig.outer : colorConfig.num;
|
||||||
|
|
||||||
colorState.inner = colorConfig.inner;
|
colorState.inner = colorConfig.inner;
|
||||||
colorState.outer = colorConfig.outer;
|
colorState.outer = *colorConfig.outer;
|
||||||
colorState.font = colorConfig.font;
|
colorState.font = colorConfig.font;
|
||||||
|
colorState.outerSource = colorConfig.outer;
|
||||||
|
|
||||||
if (!dots.textFormat.empty()) {
|
if (!dots.textFormat.empty()) {
|
||||||
dots.textResourceID = std::format("input:{}-{}", (uintptr_t)this, dots.textFormat);
|
dots.textResourceID = std::format("input:{}-{}", (uintptr_t)this, dots.textFormat);
|
||||||
|
@ -218,15 +219,18 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
||||||
shadowData.opacity *= fade.a;
|
shadowData.opacity *= fade.a;
|
||||||
shadow.draw(shadowData);
|
shadow.draw(shadowData);
|
||||||
|
|
||||||
CColor outerCol = colorState.outer;
|
CGradientValueData outerGrad = colorState.outer;
|
||||||
outerCol.a *= fade.a * data.opacity;
|
for (auto& c : outerGrad.m_vColors)
|
||||||
|
c.a *= fade.a * data.opacity;
|
||||||
|
|
||||||
CColor innerCol = colorState.inner;
|
CColor innerCol = colorState.inner;
|
||||||
innerCol.a *= fade.a * data.opacity;
|
innerCol.a *= fade.a * data.opacity;
|
||||||
CColor fontCol = colorState.font;
|
CColor fontCol = colorState.font;
|
||||||
fontCol.a *= fade.a * data.opacity;
|
fontCol.a *= fade.a * data.opacity;
|
||||||
|
|
||||||
if (outThick > 0) {
|
if (outThick > 0) {
|
||||||
g_pRenderer->renderRect(outerBox, outerCol, rounding == -1 ? outerBox.h / 2.0 : rounding);
|
const auto OUTERROUND = rounding == -1 ? outerBox.h / 2.0 : rounding;
|
||||||
|
g_pRenderer->renderBorder(outerBox, outerGrad, outThick, OUTERROUND, fade.a * data.opacity);
|
||||||
|
|
||||||
if (passwordLength != 0 && hiddenInputState.enabled && !fade.animated && data.opacity == 1.0) {
|
if (passwordLength != 0 && hiddenInputState.enabled && !fade.animated && data.opacity == 1.0) {
|
||||||
CBox outerBoxScaled = outerBox;
|
CBox outerBoxScaled = outerBox;
|
||||||
|
@ -238,13 +242,13 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
||||||
outerBoxScaled.x += outerBoxScaled.w;
|
outerBoxScaled.x += outerBoxScaled.w;
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
glScissor(outerBoxScaled.x, outerBoxScaled.y, outerBoxScaled.w, outerBoxScaled.h);
|
glScissor(outerBoxScaled.x, outerBoxScaled.y, outerBoxScaled.w, outerBoxScaled.h);
|
||||||
g_pRenderer->renderRect(outerBox, hiddenInputState.lastColor, rounding == -1 ? outerBox.h / 2.0 : rounding);
|
g_pRenderer->renderBorder(outerBox, hiddenInputState.lastColor, outThick, OUTERROUND, fade.a * data.opacity);
|
||||||
glScissor(0, 0, viewport.x, viewport.y);
|
glScissor(0, 0, viewport.x, viewport.y);
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pRenderer->renderRect(inputFieldBox, innerCol, rounding == -1 ? inputFieldBox.h / 2.0 : rounding - outThick);
|
g_pRenderer->renderRect(inputFieldBox, innerCol, rounding == -1 ? inputFieldBox.h / 2.0 : rounding - outThick - 1);
|
||||||
|
|
||||||
if (!hiddenInputState.enabled && !g_pHyprlock->m_bFadeStarted) {
|
if (!hiddenInputState.enabled && !g_pHyprlock->m_bFadeStarted) {
|
||||||
const int RECTPASSSIZE = std::nearbyint(inputFieldBox.h * dots.size * 0.5f) * 2.f;
|
const int RECTPASSSIZE = std::nearbyint(inputFieldBox.h * dots.size * 0.5f) * 2.f;
|
||||||
|
@ -434,6 +438,28 @@ static void changeColor(const CColor& source, const CColor& target, CColor& subj
|
||||||
changeChannel(source.a, target.a, subject.a, multi, animated);
|
changeChannel(source.a, target.a, subject.a, multi, animated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void changeGrad(CGradientValueData* psource, CGradientValueData* ptarget, CGradientValueData& subject, const double& multi, bool& animated) {
|
||||||
|
if (!psource || !ptarget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
subject.m_vColors.resize(ptarget->m_vColors.size(), subject.m_vColors.back());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < subject.m_vColors.size(); ++i) {
|
||||||
|
const CColor& sourceCol = (i < psource->m_vColors.size()) ? psource->m_vColors[i] : psource->m_vColors.back();
|
||||||
|
const CColor& targetCol = (i < ptarget->m_vColors.size()) ? ptarget->m_vColors[i] : ptarget->m_vColors.back();
|
||||||
|
changeColor(sourceCol, targetCol, subject.m_vColors[i], multi, animated);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (psource->m_fAngle != ptarget->m_fAngle) {
|
||||||
|
const float DELTA = ptarget->m_fAngle - psource->m_fAngle;
|
||||||
|
subject.m_fAngle += DELTA * multi;
|
||||||
|
animated = true;
|
||||||
|
|
||||||
|
if ((psource->m_fAngle < ptarget->m_fAngle && subject.m_fAngle > ptarget->m_fAngle) || (psource->m_fAngle > ptarget->m_fAngle && subject.m_fAngle < ptarget->m_fAngle))
|
||||||
|
subject.m_fAngle = ptarget->m_fAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CPasswordInputField::updateColors() {
|
void CPasswordInputField::updateColors() {
|
||||||
const bool BORDERLESS = outThick == 0;
|
const bool BORDERLESS = outThick == 0;
|
||||||
const bool NUMLOCK = (colorConfig.invertNum) ? !g_pHyprlock->m_bNumLock : g_pHyprlock->m_bNumLock;
|
const bool NUMLOCK = (colorConfig.invertNum) ? !g_pHyprlock->m_bNumLock : g_pHyprlock->m_bNumLock;
|
||||||
|
@ -442,51 +468,51 @@ void CPasswordInputField::updateColors() {
|
||||||
std::clamp(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - colorState.lastFrame).count() / (double)colorConfig.transitionMs,
|
std::clamp(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - colorState.lastFrame).count() / (double)colorConfig.transitionMs,
|
||||||
0.0016, 0.5);
|
0.0016, 0.5);
|
||||||
|
|
||||||
CColor targetColor;
|
//
|
||||||
|
CGradientValueData* targetGrad = nullptr;
|
||||||
|
|
||||||
if (checkWaiting) {
|
if (checkWaiting)
|
||||||
targetColor = colorConfig.check;
|
targetGrad = colorConfig.check;
|
||||||
} else if (displayFail) {
|
else if (displayFail)
|
||||||
targetColor = colorConfig.fail;
|
targetGrad = colorConfig.fail;
|
||||||
}
|
|
||||||
|
|
||||||
if (g_pHyprlock->m_bCapsLock && NUMLOCK) {
|
if (g_pHyprlock->m_bCapsLock && NUMLOCK)
|
||||||
targetColor = colorConfig.both;
|
targetGrad = colorConfig.both;
|
||||||
} else if (g_pHyprlock->m_bCapsLock) {
|
else if (g_pHyprlock->m_bCapsLock)
|
||||||
targetColor = colorConfig.caps;
|
targetGrad = colorConfig.caps;
|
||||||
} else if (NUMLOCK) {
|
else if (NUMLOCK)
|
||||||
targetColor = colorConfig.num;
|
targetGrad = colorConfig.num;
|
||||||
}
|
|
||||||
|
|
||||||
CColor outerTarget = colorConfig.outer;
|
CGradientValueData* outerTarget = colorConfig.outer;
|
||||||
CColor innerTarget = colorConfig.inner;
|
CColor innerTarget = colorConfig.inner;
|
||||||
CColor fontTarget = (displayFail) ? colorConfig.fail : colorConfig.font;
|
CColor fontTarget = (displayFail) ? colorConfig.fail->m_vColors.front() : colorConfig.font;
|
||||||
|
|
||||||
if (checkWaiting || displayFail || g_pHyprlock->m_bCapsLock || NUMLOCK) {
|
if (checkWaiting || displayFail || g_pHyprlock->m_bCapsLock || NUMLOCK) {
|
||||||
if (BORDERLESS && colorConfig.swapFont) {
|
if (BORDERLESS && colorConfig.swapFont) {
|
||||||
fontTarget = targetColor;
|
fontTarget = colorConfig.fail->m_vColors.front();
|
||||||
} else if (BORDERLESS && !colorConfig.swapFont) {
|
} else if (BORDERLESS && !colorConfig.swapFont) {
|
||||||
innerTarget = targetColor;
|
innerTarget = colorConfig.fail->m_vColors.front();
|
||||||
// When changing the inner color the font cannot be fail_color
|
// When changing the inner color the font cannot be fail_color
|
||||||
fontTarget = colorConfig.font;
|
fontTarget = colorConfig.font;
|
||||||
} else {
|
} else {
|
||||||
outerTarget = targetColor;
|
outerTarget = targetGrad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetColor != colorState.currentTarget) {
|
if (targetGrad != colorState.currentTarget) {
|
||||||
colorState.outerSource = colorState.outer;
|
colorState.outerSource = &colorState.outer;
|
||||||
colorState.innerSource = colorState.inner;
|
colorState.innerSource = colorState.inner;
|
||||||
|
|
||||||
colorState.currentTarget = targetColor;
|
colorState.currentTarget = targetGrad;
|
||||||
}
|
}
|
||||||
|
|
||||||
colorState.animated = false;
|
colorState.animated = false;
|
||||||
|
|
||||||
changeColor(colorState.outerSource, outerTarget, colorState.outer, MULTI, colorState.animated);
|
if (!BORDERLESS)
|
||||||
|
changeGrad(colorState.outerSource, outerTarget, colorState.outer, MULTI, colorState.animated);
|
||||||
changeColor(colorState.innerSource, innerTarget, colorState.inner, MULTI, colorState.animated);
|
changeColor(colorState.innerSource, innerTarget, colorState.inner, MULTI, colorState.animated);
|
||||||
|
|
||||||
// Font color is only chaned, when `swap_font_color` is set to true and no boarder is present.
|
// Font color is only chaned, when `swap_font_color` is set to true and no border is present.
|
||||||
// It is not animated, because that does not look good and we would need to rerender the text for each frame.
|
// It is not animated, because that does not look good and we would need to rerender the text for each frame.
|
||||||
colorState.font = fontTarget;
|
colorState.font = fontTarget;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "../../helpers/Math.hpp"
|
#include "../../helpers/Math.hpp"
|
||||||
#include "../../core/Timer.hpp"
|
#include "../../core/Timer.hpp"
|
||||||
#include "Shadowable.hpp"
|
#include "Shadowable.hpp"
|
||||||
|
#include "src/config/ConfigDataValues.hpp"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <any>
|
#include <any>
|
||||||
|
@ -89,14 +90,14 @@ class CPasswordInputField : public IWidget {
|
||||||
} hiddenInputState;
|
} hiddenInputState;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
CColor outer;
|
CGradientValueData* outer = nullptr;
|
||||||
CColor inner;
|
CColor inner;
|
||||||
CColor font;
|
CColor font;
|
||||||
CColor fail;
|
CGradientValueData* fail = nullptr;
|
||||||
CColor check;
|
CGradientValueData* check = nullptr;
|
||||||
CColor caps;
|
CGradientValueData* caps = nullptr;
|
||||||
CColor num;
|
CGradientValueData* num = nullptr;
|
||||||
CColor both;
|
CGradientValueData* both = nullptr;
|
||||||
|
|
||||||
int transitionMs = 0;
|
int transitionMs = 0;
|
||||||
bool invertNum = false;
|
bool invertNum = false;
|
||||||
|
@ -104,14 +105,14 @@ class CPasswordInputField : public IWidget {
|
||||||
} colorConfig;
|
} colorConfig;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
CColor outer;
|
CGradientValueData outer;
|
||||||
CColor inner;
|
CColor inner;
|
||||||
CColor font;
|
CColor font;
|
||||||
|
|
||||||
CColor outerSource;
|
CGradientValueData* outerSource = nullptr;
|
||||||
CColor innerSource;
|
CColor innerSource;
|
||||||
|
|
||||||
CColor currentTarget;
|
CGradientValueData* currentTarget = nullptr;
|
||||||
|
|
||||||
bool animated = false;
|
bool animated = false;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ CShape::CShape(const Vector2D& viewport_, const std::unordered_map<std::string,
|
||||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||||
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||||
borderColor = std::any_cast<Hyprlang::INT>(props.at("border_color"));
|
borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
||||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||||
|
@ -55,9 +55,7 @@ bool CShape::draw(const SRenderData& data) {
|
||||||
if (xray) {
|
if (xray) {
|
||||||
if (border > 0) {
|
if (border > 0) {
|
||||||
const int PIROUND = std::min(MINHALFBORDER, std::round(border * M_PI));
|
const int PIROUND = std::min(MINHALFBORDER, std::round(border * M_PI));
|
||||||
CColor borderCol = borderColor;
|
g_pRenderer->renderBorder(borderBox, borderGrad, border, rounding == -1 ? PIROUND : std::clamp(rounding, 0, PIROUND), data.opacity);
|
||||||
borderCol.a *= data.opacity;
|
|
||||||
g_pRenderer->renderRect(borderBox, borderCol, rounding == -1 ? PIROUND : std::clamp(rounding, 0, PIROUND));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
@ -79,7 +77,7 @@ bool CShape::draw(const SRenderData& data) {
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
if (border > 0)
|
if (border > 0)
|
||||||
g_pRenderer->renderRect(borderBox, borderColor, ALLOWROUND ? (rounding == 0 ? 0 : rounding + std::round(border / M_PI)) : MINHALFBORDER);
|
g_pRenderer->renderBorder(borderBox, borderGrad, border, ALLOWROUND ? (rounding == 0 ? 0 : rounding + std::round(border / M_PI)) : MINHALFBORDER, data.opacity);
|
||||||
|
|
||||||
g_pRenderer->renderRect(shapeBox, color, ALLOWROUND ? rounding : MINHALFSHAPE);
|
g_pRenderer->renderRect(shapeBox, color, ALLOWROUND ? rounding : MINHALFSHAPE);
|
||||||
g_pRenderer->popFb();
|
g_pRenderer->popFb();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "IWidget.hpp"
|
#include "IWidget.hpp"
|
||||||
#include "../../helpers/Color.hpp"
|
#include "../../helpers/Color.hpp"
|
||||||
|
#include "../../config/ConfigDataValues.hpp"
|
||||||
#include "Shadowable.hpp"
|
#include "Shadowable.hpp"
|
||||||
#include <hyprutils/math/Box.hpp>
|
#include <hyprutils/math/Box.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -21,7 +22,7 @@ class CShape : public IWidget {
|
||||||
double border;
|
double border;
|
||||||
double angle;
|
double angle;
|
||||||
CColor color;
|
CColor color;
|
||||||
CColor borderColor;
|
CGradientValueData borderGrad;
|
||||||
Vector2D size;
|
Vector2D size;
|
||||||
Vector2D pos;
|
Vector2D pos;
|
||||||
CBox shapeBox;
|
CBox shapeBox;
|
||||||
|
|
Loading…
Reference in a new issue