mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-11-16 23:05:58 +01:00
widgets: add Image (#191)
This commit is contained in:
parent
7ee406bf9b
commit
3e38762e84
6 changed files with 237 additions and 3 deletions
|
@ -162,6 +162,77 @@ in {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
images = mkOption {
|
||||||
|
description = "Image configurations";
|
||||||
|
type = listOf (submodule {
|
||||||
|
options = {
|
||||||
|
monitor = mkOption {
|
||||||
|
description = "The monitor to draw an image";
|
||||||
|
type = str;
|
||||||
|
default = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
path = mkOption {
|
||||||
|
description = "The path to source image";
|
||||||
|
type = str;
|
||||||
|
default = "/home/me/cutie.png"; # only png supported for now
|
||||||
|
};
|
||||||
|
|
||||||
|
size = mkOption {
|
||||||
|
description = "Size of the image. Lesser side is chosen if not 1:1 aspect ratio";
|
||||||
|
type = int;
|
||||||
|
default = 150;
|
||||||
|
};
|
||||||
|
|
||||||
|
rounding = mkOption {
|
||||||
|
description = "The rounding of the image";
|
||||||
|
type = int;
|
||||||
|
default = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
border_size = mkOption {
|
||||||
|
description = "Size of image border";
|
||||||
|
type = int;
|
||||||
|
default = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
border_color = mkOption {
|
||||||
|
description = "Color of image border";
|
||||||
|
type = str;
|
||||||
|
default = "rgb(221, 221, 221)";
|
||||||
|
};
|
||||||
|
|
||||||
|
position = {
|
||||||
|
x = mkOption {
|
||||||
|
description = "X position of the image";
|
||||||
|
type = int;
|
||||||
|
default = 0;
|
||||||
|
};
|
||||||
|
y = mkOption {
|
||||||
|
description = "Y position of the image";
|
||||||
|
type = int;
|
||||||
|
default = 200;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
halign = mkOption {
|
||||||
|
description = "Horizontal alignment of the image";
|
||||||
|
type = str;
|
||||||
|
default = "center";
|
||||||
|
};
|
||||||
|
|
||||||
|
valign = mkOption {
|
||||||
|
description = "Vertical alignment of the image";
|
||||||
|
type = str;
|
||||||
|
default = "center";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
default = [
|
||||||
|
{}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
input-fields = mkOption {
|
input-fields = mkOption {
|
||||||
description = "Input field configurations";
|
description = "Input field configurations";
|
||||||
type = listOf (submodule {
|
type = listOf (submodule {
|
||||||
|
@ -441,6 +512,22 @@ in {
|
||||||
'')
|
'')
|
||||||
cfg.backgrounds)}
|
cfg.backgrounds)}
|
||||||
|
|
||||||
|
${builtins.concatStringsSep "\n" (map (image: ''
|
||||||
|
image {
|
||||||
|
monitor = ${image.monitor}
|
||||||
|
path = ${image.path}
|
||||||
|
size = ${toString image.size}
|
||||||
|
rounding = ${toString image.rounding}
|
||||||
|
border_size = ${toString image.border_size}
|
||||||
|
border_color = ${image.border_color}
|
||||||
|
|
||||||
|
position = ${toString image.position.x}, ${toString image.position.y}
|
||||||
|
halign = ${image.halign}
|
||||||
|
valign = ${image.valign}
|
||||||
|
}
|
||||||
|
'')
|
||||||
|
cfg.images)}
|
||||||
|
|
||||||
${builtins.concatStringsSep "\n" (map (input-field: ''
|
${builtins.concatStringsSep "\n" (map (input-field: ''
|
||||||
input-field {
|
input-field {
|
||||||
monitor = ${input-field.monitor}
|
monitor = ${input-field.monitor}
|
||||||
|
|
|
@ -61,6 +61,18 @@ void CConfigManager::init() {
|
||||||
m_config.addSpecialConfigValue("background", "vibrancy", Hyprlang::FLOAT{0.1686});
|
m_config.addSpecialConfigValue("background", "vibrancy", Hyprlang::FLOAT{0.1686});
|
||||||
m_config.addSpecialConfigValue("background", "vibrancy_darkness", Hyprlang::FLOAT{0.05});
|
m_config.addSpecialConfigValue("background", "vibrancy_darkness", Hyprlang::FLOAT{0.05});
|
||||||
|
|
||||||
|
m_config.addSpecialCategory("image", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||||
|
m_config.addSpecialConfigValue("image", "monitor", Hyprlang::STRING{""});
|
||||||
|
m_config.addSpecialConfigValue("image", "path", Hyprlang::STRING{""});
|
||||||
|
m_config.addSpecialConfigValue("image", "size", Hyprlang::INT{150});
|
||||||
|
m_config.addSpecialConfigValue("image", "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::VEC2{0, 200});
|
||||||
|
m_config.addSpecialConfigValue("image", "halign", Hyprlang::STRING{"center"});
|
||||||
|
m_config.addSpecialConfigValue("image", "valign", Hyprlang::STRING{"center"});
|
||||||
|
SHADOWABLE("image");
|
||||||
|
|
||||||
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::VEC2{400, 90});
|
m_config.addSpecialConfigValue("input-field", "size", Hyprlang::VEC2{400, 90});
|
||||||
|
@ -151,6 +163,28 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
keys = m_config.listKeysForSpecialCategory("image");
|
||||||
|
for (auto& k : keys) {
|
||||||
|
// clang-format off
|
||||||
|
result.push_back(CConfigManager::SWidgetConfig{
|
||||||
|
"image",
|
||||||
|
std::any_cast<Hyprlang::STRING>(m_config.getSpecialConfigValue("image", "monitor", k.c_str())),
|
||||||
|
{
|
||||||
|
{"path", m_config.getSpecialConfigValue("image", "path", k.c_str())},
|
||||||
|
{"size", m_config.getSpecialConfigValue("image", "size", k.c_str())},
|
||||||
|
{"rounding", m_config.getSpecialConfigValue("image", "rounding", k.c_str())},
|
||||||
|
{"border_size", m_config.getSpecialConfigValue("image", "border_size", k.c_str())},
|
||||||
|
{"border_color", m_config.getSpecialConfigValue("image", "border_color", k.c_str())},
|
||||||
|
{"position", m_config.getSpecialConfigValue("image", "position", k.c_str())},
|
||||||
|
{"halign", m_config.getSpecialConfigValue("image", "halign", k.c_str())},
|
||||||
|
{"valign", m_config.getSpecialConfigValue("image", "valign", k.c_str())},
|
||||||
|
SHADOWABLE("image"),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
keys = m_config.listKeysForSpecialCategory("input-field");
|
keys = m_config.listKeysForSpecialCategory("input-field");
|
||||||
for (auto& k : keys) {
|
for (auto& k : keys) {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
|
@ -112,13 +112,13 @@ void CAsyncResourceGatherer::gather() {
|
||||||
// gather resources to preload
|
// gather resources to preload
|
||||||
// clang-format off
|
// clang-format off
|
||||||
int preloads = std::count_if(CWIDGETS.begin(), CWIDGETS.end(), [](const auto& w) {
|
int preloads = std::count_if(CWIDGETS.begin(), CWIDGETS.end(), [](const auto& w) {
|
||||||
return w.type == "background";
|
return w.type == "background" || w.type == "image";
|
||||||
});
|
});
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
progress = 0;
|
progress = 0;
|
||||||
for (auto& c : CWIDGETS) {
|
for (auto& c : CWIDGETS) {
|
||||||
if (c.type == "background") {
|
if (c.type == "background" || c.type == "image") {
|
||||||
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 180100
|
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 180100
|
||||||
progress = progress + 1.0 / (preloads + 1.0);
|
progress = progress + 1.0 / (preloads + 1.0);
|
||||||
#else
|
#else
|
||||||
|
@ -130,7 +130,7 @@ void CAsyncResourceGatherer::gather() {
|
||||||
if (path.empty() || path == "screenshot")
|
if (path.empty() || path == "screenshot")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string id = std::string{"background:"} + path;
|
std::string id = (c.type == "background" ? std::string{"background:"} : std::string{"image:"}) + path;
|
||||||
const auto ABSOLUTEPATH = absolutePath(path, "");
|
const auto ABSOLUTEPATH = absolutePath(path, "");
|
||||||
|
|
||||||
// preload bg img
|
// preload bg img
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "widgets/PasswordInputField.hpp"
|
#include "widgets/PasswordInputField.hpp"
|
||||||
#include "widgets/Background.hpp"
|
#include "widgets/Background.hpp"
|
||||||
#include "widgets/Label.hpp"
|
#include "widgets/Label.hpp"
|
||||||
|
#include "widgets/Image.hpp"
|
||||||
|
|
||||||
inline const float fullVerts[] = {
|
inline const float fullVerts[] = {
|
||||||
1, 0, // top right
|
1, 0, // top right
|
||||||
|
@ -323,6 +324,14 @@ std::vector<std::unique_ptr<IWidget>>* CRenderer::getOrCreateWidgetsFor(const CS
|
||||||
widgets[surf].emplace_back(std::make_unique<CPasswordInputField>(surf->size, c.values));
|
widgets[surf].emplace_back(std::make_unique<CPasswordInputField>(surf->size, c.values));
|
||||||
} else if (c.type == "label") {
|
} else if (c.type == "label") {
|
||||||
widgets[surf].emplace_back(std::make_unique<CLabel>(surf->size, c.values, surf->output->stringPort));
|
widgets[surf].emplace_back(std::make_unique<CLabel>(surf->size, c.values, surf->output->stringPort));
|
||||||
|
} else if (c.type == "image") {
|
||||||
|
const std::string PATH = std::any_cast<Hyprlang::STRING>(c.values.at("path"));
|
||||||
|
|
||||||
|
std::string resourceID = "";
|
||||||
|
if (!PATH.empty())
|
||||||
|
resourceID = "image:" + PATH;
|
||||||
|
|
||||||
|
widgets[surf].emplace_back(std::make_unique<CImage>(surf->size, surf->output, resourceID, c.values));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
68
src/renderer/widgets/Image.cpp
Normal file
68
src/renderer/widgets/Image.cpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#include "Image.hpp"
|
||||||
|
#include "../Renderer.hpp"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
CImage::CImage(const Vector2D& viewport_, COutput* output_, const std::string& resourceID_, const std::unordered_map<std::string, std::any>& props) :
|
||||||
|
viewport(viewport_), resourceID(resourceID_), output(output_), shadow(this, props, viewport_) {
|
||||||
|
|
||||||
|
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"));
|
||||||
|
pos = std::any_cast<Hyprlang::VEC2>(props.at("position"));
|
||||||
|
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||||
|
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CImage::draw(const SRenderData& data) {
|
||||||
|
|
||||||
|
if (resourceID.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!asset)
|
||||||
|
asset = g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID);
|
||||||
|
|
||||||
|
if (!asset)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (asset->texture.m_iType == TEXTURE_INVALID) {
|
||||||
|
g_pRenderer->asyncResourceGatherer->unloadAsset(asset);
|
||||||
|
resourceID = "";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CTexture* tex = &asset->texture;
|
||||||
|
CBox texbox = {{}, tex->m_vSize};
|
||||||
|
|
||||||
|
if (firstRender) {
|
||||||
|
firstRender = false;
|
||||||
|
shadow.markShadowDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
const float SCALEX = size / tex->m_vSize.x;
|
||||||
|
const float SCALEY = size / tex->m_vSize.y;
|
||||||
|
|
||||||
|
texbox.w *= std::max(SCALEX, SCALEY);
|
||||||
|
texbox.h *= std::max(SCALEX, SCALEY);
|
||||||
|
|
||||||
|
shadow.draw(data);
|
||||||
|
|
||||||
|
const bool ALLOWROUND = rounding > -1 && rounding < std::min(texbox.w, texbox.h) / 2.0;
|
||||||
|
const auto TEXPOS = posFromHVAlign(viewport, Vector2D{texbox.w, texbox.h}, pos, halign, valign);
|
||||||
|
|
||||||
|
texbox.x = TEXPOS.x;
|
||||||
|
texbox.y = TEXPOS.y;
|
||||||
|
|
||||||
|
if (border > 0) {
|
||||||
|
CBox borderBox = {TEXPOS - Vector2D{(double)border, (double)border}, texbox.size() + Vector2D{(double)border * 2.0, (double)border * 2.0}};
|
||||||
|
CColor borderCol = color;
|
||||||
|
borderCol.a *= data.opacity;
|
||||||
|
borderBox.round();
|
||||||
|
g_pRenderer->renderRect(borderBox, borderCol, ALLOWROUND ? rounding : std::min(borderBox.w, borderBox.h) / 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
texbox.round();
|
||||||
|
g_pRenderer->renderTexture(texbox, *tex, data.opacity, ALLOWROUND ? rounding : std::min(texbox.w, texbox.h) / 2.0, WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
||||||
|
|
||||||
|
return data.opacity < 1.0;
|
||||||
|
}
|
36
src/renderer/widgets/Image.hpp
Normal file
36
src/renderer/widgets/Image.hpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IWidget.hpp"
|
||||||
|
#include "../../helpers/Vector2D.hpp"
|
||||||
|
#include "../../helpers/Color.hpp"
|
||||||
|
#include "Shadowable.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <any>
|
||||||
|
|
||||||
|
struct SPreloadedAsset;
|
||||||
|
class COutput;
|
||||||
|
|
||||||
|
class CImage : public IWidget {
|
||||||
|
public:
|
||||||
|
CImage(const Vector2D& viewport, COutput* output_, const std::string& resourceID, const std::unordered_map<std::string, std::any>& props);
|
||||||
|
|
||||||
|
virtual bool draw(const SRenderData& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int size;
|
||||||
|
int rounding;
|
||||||
|
int border;
|
||||||
|
CColor color;
|
||||||
|
Vector2D pos;
|
||||||
|
|
||||||
|
std::string halign, valign;
|
||||||
|
|
||||||
|
bool firstRender = true;
|
||||||
|
|
||||||
|
Vector2D viewport;
|
||||||
|
std::string resourceID;
|
||||||
|
SPreloadedAsset* asset = nullptr;
|
||||||
|
COutput* output = nullptr;
|
||||||
|
CShadowable shadow;
|
||||||
|
};
|
Loading…
Reference in a new issue