mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-12-22 05:19:48 +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
|
||||
#include "../helpers/Log.hpp"
|
||||
#include "../helpers/Color.hpp"
|
||||
#include <hyprutils/math/Vector2D.hpp>
|
||||
#include <hyprutils/string/VarList.hpp>
|
||||
#include <any>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
enum eConfigValueDataTypes {
|
||||
CVD_TYPE_INVALID = -1,
|
||||
CVD_TYPE_LAYOUT = 0,
|
||||
CVD_TYPE_GRADIENT = 1,
|
||||
};
|
||||
|
||||
class ICustomConfigValueData {
|
||||
|
@ -51,3 +58,57 @@ class CLayoutValueData : public ICustomConfigValueData {
|
|||
bool y = false;
|
||||
} 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/Log.hpp"
|
||||
#include "../config/ConfigDataValues.hpp"
|
||||
#include <hyprlang.hpp>
|
||||
#include <hyprutils/path/Path.hpp>
|
||||
#include <filesystem>
|
||||
#include <glob.h>
|
||||
|
@ -69,6 +70,65 @@ static void configHandleLayoutOptionDestroy(void** 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 const auto paths = Hyprutils::Path::findConfig("hyprlock");
|
||||
if (paths.first.has_value())
|
||||
|
@ -82,6 +142,14 @@ CConfigManager::CConfigManager(std::string 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() {
|
||||
|
||||
#define SHADOWABLE(name) \
|
||||
|
@ -118,12 +186,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", 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", "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", "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", "valign", Hyprlang::STRING{"center"});
|
||||
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", "rounding", Hyprlang::INT{-1});
|
||||
m_config.addSpecialConfigValue("image", "border_size", Hyprlang::INT{4});
|
||||
m_config.addSpecialConfigValue("image", "border_color", Hyprlang::INT{0xFFDDDDDD});
|
||||
m_config.addSpecialConfigValue("image", "position", Hyprlang::CUSTOMTYPE{&configHandleLayoutOption, configHandleLayoutOptionDestroy, "0,0"});
|
||||
m_config.addSpecialConfigValue("image", "border_color", GRADIENTCONFIG("0xFFDDDDDD"));
|
||||
m_config.addSpecialConfigValue("image", "position", LAYOUTCONFIG("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});
|
||||
|
@ -149,9 +217,9 @@ 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", 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", "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", "dots_size", Hyprlang::FLOAT{0.25});
|
||||
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", "halign", 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", "hide_input", Hyprlang::INT{0});
|
||||
m_config.addSpecialConfigValue("input-field", "rounding", Hyprlang::INT{-1});
|
||||
m_config.addSpecialConfigValue("input-field", "check_color", Hyprlang::INT{0xFFCC8822});
|
||||
m_config.addSpecialConfigValue("input-field", "fail_color", Hyprlang::INT{0xFFCC2222});
|
||||
m_config.addSpecialConfigValue("input-field", "check_color", GRADIENTCONFIG("0xFF22CC88"));
|
||||
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_timeout", Hyprlang::INT{2000});
|
||||
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", "numlock_color", Hyprlang::INT{-1});
|
||||
m_config.addSpecialConfigValue("input-field", "bothlock_color", Hyprlang::INT{-1});
|
||||
m_config.addSpecialConfigValue("input-field", "capslock_color", GRADIENTCONFIG(""));
|
||||
m_config.addSpecialConfigValue("input-field", "numlock_color", GRADIENTCONFIG(""));
|
||||
m_config.addSpecialConfigValue("input-field", "bothlock_color", GRADIENTCONFIG(""));
|
||||
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", "zindex", Hyprlang::INT{0});
|
||||
|
@ -184,7 +252,7 @@ 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", 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", "font_size", Hyprlang::INT{16});
|
||||
m_config.addSpecialConfigValue("label", "text", Hyprlang::STRING{"Sample Text"});
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#include <filesystem>
|
||||
#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::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);
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
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.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>();
|
||||
}
|
||||
|
||||
|
@ -250,6 +267,43 @@ void CRenderer::renderRect(const CBox& box, const CColor& col, int rounding) {
|
|||
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) {
|
||||
Mat3x3 matrix = projMatrix.projectBox(box, tr.value_or(HYPRUTILS_TRANSFORM_FLIPPED_180), box.rot);
|
||||
Mat3x3 glMatrix = projection.copy().multiply(matrix);
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#include "Shader.hpp"
|
||||
#include "../core/LockSurface.hpp"
|
||||
#include "../helpers/Color.hpp"
|
||||
#include "../helpers/Math.hpp"
|
||||
#include "AsyncResourceGatherer.hpp"
|
||||
#include "../config/ConfigDataValues.hpp"
|
||||
#include "widgets/IWidget.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
|
||||
|
@ -31,6 +31,7 @@ class CRenderer {
|
|||
SRenderFeedback renderLock(const CSessionLockSurface& surface);
|
||||
|
||||
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 blurFB(const CFramebuffer& outfb, SBlurParams params);
|
||||
|
||||
|
@ -53,6 +54,7 @@ class CRenderer {
|
|||
CShader blurShader2;
|
||||
CShader blurPrepareShader;
|
||||
CShader blurFinishShader;
|
||||
CShader borderShader;
|
||||
|
||||
Mat3x3 projMatrix = Mat3x3::identity();
|
||||
Mat3x3 projection;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#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 {
|
||||
return R"#(
|
||||
|
@ -12,17 +16,21 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar
|
|||
pixCoord -= fullSize * 0.5 - radius;
|
||||
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) {
|
||||
|
||||
float dist = length(pixCoord);
|
||||
|
||||
if (dist > radius + 1.0)
|
||||
if (dist > radius + SMOOTHING_CONSTANT * 2.0)
|
||||
discard;
|
||||
|
||||
if (dist > radius - 1.0) {
|
||||
if (dist > radius - SMOOTHING_CONSTANT * 2.0) {
|
||||
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;
|
||||
|
@ -362,3 +370,124 @@ void main() {
|
|||
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"));
|
||||
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("border_color"));
|
||||
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
|
@ -156,7 +156,8 @@ bool CImage::draw(const SRenderData& data) {
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
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();
|
||||
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 "../../helpers/Color.hpp"
|
||||
#include "../../helpers/Math.hpp"
|
||||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include "../../core/Timer.hpp"
|
||||
#include "../AsyncResourceGatherer.hpp"
|
||||
#include "Shadowable.hpp"
|
||||
|
@ -32,7 +33,7 @@ class CImage : public IWidget {
|
|||
int rounding;
|
||||
double border;
|
||||
double angle;
|
||||
CColor color;
|
||||
CGradientValueData color;
|
||||
Vector2D pos;
|
||||
|
||||
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"));
|
||||
fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
||||
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.font = std::any_cast<Hyprlang::INT>(props.at("font_color"));
|
||||
colorConfig.fail = std::any_cast<Hyprlang::INT>(props.at("fail_color"));
|
||||
colorConfig.check = std::any_cast<Hyprlang::INT>(props.at("check_color"));
|
||||
colorConfig.both = std::any_cast<Hyprlang::INT>(props.at("bothlock_color"));
|
||||
colorConfig.caps = std::any_cast<Hyprlang::INT>(props.at("capslock_color"));
|
||||
colorConfig.num = std::any_cast<Hyprlang::INT>(props.at("numlock_color"));
|
||||
colorConfig.fail = CGradientValueData::fromAnyPv(props.at("fail_color"));
|
||||
colorConfig.check = CGradientValueData::fromAnyPv(props.at("check_color"));
|
||||
colorConfig.both = CGradientValueData::fromAnyPv(props.at("bothlock_color"));
|
||||
colorConfig.caps = CGradientValueData::fromAnyPv(props.at("capslock_color"));
|
||||
colorConfig.num = CGradientValueData::fromAnyPv(props.at("numlock_color"));
|
||||
colorConfig.invertNum = std::any_cast<Hyprlang::INT>(props.at("invert_numlock"));
|
||||
colorConfig.swapFont = std::any_cast<Hyprlang::INT>(props.at("swap_font_color"));
|
||||
} 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);
|
||||
colorConfig.transitionMs = std::clamp(colorConfig.transitionMs, 0, 1000);
|
||||
|
||||
colorConfig.both = colorConfig.both == -1 ? colorConfig.outer : colorConfig.both;
|
||||
colorConfig.caps = colorConfig.caps == -1 ? colorConfig.outer : colorConfig.caps;
|
||||
colorConfig.num = colorConfig.num == -1 ? colorConfig.outer : colorConfig.num;
|
||||
colorConfig.both = colorConfig.both->m_vColors.empty() ? colorConfig.outer : colorConfig.both;
|
||||
colorConfig.caps = colorConfig.caps->m_vColors.empty() ? colorConfig.outer : colorConfig.caps;
|
||||
colorConfig.num = colorConfig.num->m_vColors.empty() ? colorConfig.outer : colorConfig.num;
|
||||
|
||||
colorState.inner = colorConfig.inner;
|
||||
colorState.outer = colorConfig.outer;
|
||||
colorState.outer = *colorConfig.outer;
|
||||
colorState.font = colorConfig.font;
|
||||
colorState.outerSource = colorConfig.outer;
|
||||
|
||||
if (!dots.textFormat.empty()) {
|
||||
dots.textResourceID = std::format("input:{}-{}", (uintptr_t)this, dots.textFormat);
|
||||
|
@ -218,15 +219,18 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
shadowData.opacity *= fade.a;
|
||||
shadow.draw(shadowData);
|
||||
|
||||
CColor outerCol = colorState.outer;
|
||||
outerCol.a *= fade.a * data.opacity;
|
||||
CGradientValueData outerGrad = colorState.outer;
|
||||
for (auto& c : outerGrad.m_vColors)
|
||||
c.a *= fade.a * data.opacity;
|
||||
|
||||
CColor innerCol = colorState.inner;
|
||||
innerCol.a *= fade.a * data.opacity;
|
||||
CColor fontCol = colorState.font;
|
||||
fontCol.a *= fade.a * data.opacity;
|
||||
|
||||
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) {
|
||||
CBox outerBoxScaled = outerBox;
|
||||
|
@ -238,13 +242,13 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
outerBoxScaled.x += outerBoxScaled.w;
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
const bool BORDERLESS = outThick == 0;
|
||||
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,
|
||||
0.0016, 0.5);
|
||||
|
||||
CColor targetColor;
|
||||
//
|
||||
CGradientValueData* targetGrad = nullptr;
|
||||
|
||||
if (checkWaiting) {
|
||||
targetColor = colorConfig.check;
|
||||
} else if (displayFail) {
|
||||
targetColor = colorConfig.fail;
|
||||
}
|
||||
if (checkWaiting)
|
||||
targetGrad = colorConfig.check;
|
||||
else if (displayFail)
|
||||
targetGrad = colorConfig.fail;
|
||||
|
||||
if (g_pHyprlock->m_bCapsLock && NUMLOCK) {
|
||||
targetColor = colorConfig.both;
|
||||
} else if (g_pHyprlock->m_bCapsLock) {
|
||||
targetColor = colorConfig.caps;
|
||||
} else if (NUMLOCK) {
|
||||
targetColor = colorConfig.num;
|
||||
}
|
||||
if (g_pHyprlock->m_bCapsLock && NUMLOCK)
|
||||
targetGrad = colorConfig.both;
|
||||
else if (g_pHyprlock->m_bCapsLock)
|
||||
targetGrad = colorConfig.caps;
|
||||
else if (NUMLOCK)
|
||||
targetGrad = colorConfig.num;
|
||||
|
||||
CColor outerTarget = colorConfig.outer;
|
||||
CGradientValueData* outerTarget = colorConfig.outer;
|
||||
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 (BORDERLESS && colorConfig.swapFont) {
|
||||
fontTarget = targetColor;
|
||||
fontTarget = colorConfig.fail->m_vColors.front();
|
||||
} else if (BORDERLESS && !colorConfig.swapFont) {
|
||||
innerTarget = targetColor;
|
||||
innerTarget = colorConfig.fail->m_vColors.front();
|
||||
// When changing the inner color the font cannot be fail_color
|
||||
fontTarget = colorConfig.font;
|
||||
} else {
|
||||
outerTarget = targetColor;
|
||||
outerTarget = targetGrad;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetColor != colorState.currentTarget) {
|
||||
colorState.outerSource = colorState.outer;
|
||||
if (targetGrad != colorState.currentTarget) {
|
||||
colorState.outerSource = &colorState.outer;
|
||||
colorState.innerSource = colorState.inner;
|
||||
|
||||
colorState.currentTarget = targetColor;
|
||||
colorState.currentTarget = targetGrad;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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.
|
||||
colorState.font = fontTarget;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../../helpers/Math.hpp"
|
||||
#include "../../core/Timer.hpp"
|
||||
#include "Shadowable.hpp"
|
||||
#include "src/config/ConfigDataValues.hpp"
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <any>
|
||||
|
@ -89,14 +90,14 @@ class CPasswordInputField : public IWidget {
|
|||
} hiddenInputState;
|
||||
|
||||
struct {
|
||||
CColor outer;
|
||||
CGradientValueData* outer = nullptr;
|
||||
CColor inner;
|
||||
CColor font;
|
||||
CColor fail;
|
||||
CColor check;
|
||||
CColor caps;
|
||||
CColor num;
|
||||
CColor both;
|
||||
CGradientValueData* fail = nullptr;
|
||||
CGradientValueData* check = nullptr;
|
||||
CGradientValueData* caps = nullptr;
|
||||
CGradientValueData* num = nullptr;
|
||||
CGradientValueData* both = nullptr;
|
||||
|
||||
int transitionMs = 0;
|
||||
bool invertNum = false;
|
||||
|
@ -104,14 +105,14 @@ class CPasswordInputField : public IWidget {
|
|||
} colorConfig;
|
||||
|
||||
struct {
|
||||
CColor outer;
|
||||
CGradientValueData outer;
|
||||
CColor inner;
|
||||
CColor font;
|
||||
|
||||
CColor outerSource;
|
||||
CGradientValueData* outerSource = nullptr;
|
||||
CColor innerSource;
|
||||
|
||||
CColor currentTarget;
|
||||
CGradientValueData* currentTarget = nullptr;
|
||||
|
||||
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"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
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_);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
|
@ -55,9 +55,7 @@ bool CShape::draw(const SRenderData& data) {
|
|||
if (xray) {
|
||||
if (border > 0) {
|
||||
const int PIROUND = std::min(MINHALFBORDER, std::round(border * M_PI));
|
||||
CColor borderCol = borderColor;
|
||||
borderCol.a *= data.opacity;
|
||||
g_pRenderer->renderRect(borderBox, borderCol, rounding == -1 ? PIROUND : std::clamp(rounding, 0, PIROUND));
|
||||
g_pRenderer->renderBorder(borderBox, borderGrad, border, rounding == -1 ? PIROUND : std::clamp(rounding, 0, PIROUND), data.opacity);
|
||||
}
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
@ -79,7 +77,7 @@ bool CShape::draw(const SRenderData& data) {
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
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->popFb();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "IWidget.hpp"
|
||||
#include "../../helpers/Color.hpp"
|
||||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include "Shadowable.hpp"
|
||||
#include <hyprutils/math/Box.hpp>
|
||||
#include <string>
|
||||
|
@ -21,7 +22,7 @@ class CShape : public IWidget {
|
|||
double border;
|
||||
double angle;
|
||||
CColor color;
|
||||
CColor borderColor;
|
||||
CGradientValueData borderGrad;
|
||||
Vector2D size;
|
||||
Vector2D pos;
|
||||
CBox shapeBox;
|
||||
|
|
Loading…
Reference in a new issue