mirror of
https://github.com/hyprwm/hyprcursor.git
synced 2024-12-22 10:19:48 +01:00
parent
f388aacd22
commit
84203d8126
5 changed files with 48 additions and 29 deletions
|
@ -54,6 +54,7 @@ struct SCursorRawShapeDataC {
|
|||
char* overridenBy;
|
||||
enum eHyprcursorResizeAlgo resizeAlgo;
|
||||
enum eHyprcursorDataType type;
|
||||
float nominalSize;
|
||||
};
|
||||
|
||||
typedef struct SCursorRawShapeDataC hyprcursor_cursor_raw_shape_data;
|
||||
|
|
|
@ -307,13 +307,15 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
|
|||
if (REQUESTEDSHAPE != shape->directory && std::find(shape->overrides.begin(), shape->overrides.end(), REQUESTEDSHAPE) == shape->overrides.end())
|
||||
continue;
|
||||
|
||||
const int PIXELSIDE = std::round(info.size / shape->nominalSize);
|
||||
|
||||
hotX = shape->hotspotX;
|
||||
hotY = shape->hotspotY;
|
||||
|
||||
// matched :)
|
||||
bool foundAny = false;
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (image->side != info.size)
|
||||
if (image->side != PIXELSIDE)
|
||||
continue;
|
||||
|
||||
// found size
|
||||
|
@ -333,7 +335,7 @@ SCursorImageData** CHyprcursorManager::getShapesC(int& outSize, const char* shap
|
|||
// find nearest
|
||||
int leader = 13371337;
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (std::abs((int)(image->side - info.size)) > std::abs((int)(leader - info.size)))
|
||||
if (std::abs((int)(image->side - PIXELSIDE)) > std::abs((int)(leader - PIXELSIDE)))
|
||||
continue;
|
||||
|
||||
leader = image->side;
|
||||
|
@ -392,8 +394,9 @@ SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
|
|||
data->overridenBy = nullptr;
|
||||
data->images = nullptr;
|
||||
data->len = 0;
|
||||
data->hotspotX = 0;
|
||||
data->hotspotY = 0;
|
||||
data->hotspotX = 0.f;
|
||||
data->hotspotY = 0.F;
|
||||
data->nominalSize = 1.F;
|
||||
data->resizeAlgo = eHyprcursorResizeAlgo::HC_RESIZE_NONE;
|
||||
data->type = eHyprcursorDataType::HC_DATA_PNG;
|
||||
|
||||
|
@ -418,9 +421,10 @@ SCursorRawShapeDataC* CHyprcursorManager::getRawShapeDataC(const char* shape_) {
|
|||
resultingImages.push_back(i.get());
|
||||
}
|
||||
|
||||
data->hotspotX = shape->hotspotX;
|
||||
data->hotspotY = shape->hotspotY;
|
||||
data->type = shape->shapeType == SHAPE_PNG ? HC_DATA_PNG : HC_DATA_SVG;
|
||||
data->hotspotX = shape->hotspotX;
|
||||
data->hotspotY = shape->hotspotY;
|
||||
data->nominalSize = shape->nominalSize;
|
||||
data->type = shape->shapeType == SHAPE_PNG ? HC_DATA_PNG : HC_DATA_SVG;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -450,8 +454,10 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
bool sizeFound = false;
|
||||
|
||||
if (shape->shapeType == SHAPE_PNG) {
|
||||
const int IDEALSIDE = std::round(info.size / shape->nominalSize);
|
||||
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (image->side != info.size)
|
||||
if (image->side != IDEALSIDE)
|
||||
continue;
|
||||
|
||||
sizeFound = true;
|
||||
|
@ -465,7 +471,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
SLoadedCursorImage* leader = nullptr;
|
||||
int leaderVal = 1000000;
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (image->side < info.size)
|
||||
if (image->side < IDEALSIDE)
|
||||
continue;
|
||||
|
||||
if (image->side > leaderVal)
|
||||
|
@ -477,7 +483,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
|
||||
if (!leader) {
|
||||
for (auto& image : impl->loadedShapes[shape.get()].images) {
|
||||
if (std::abs((int)(image->side - info.size)) > leaderVal)
|
||||
if (std::abs((int)(image->side - IDEALSIDE)) > leaderVal)
|
||||
continue;
|
||||
|
||||
leaderVal = image->side;
|
||||
|
@ -494,12 +500,16 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
|
||||
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: png shape {} has {} frames", shape->directory, FRAMES.size());
|
||||
|
||||
const int PIXELSIDE = std::round(leader->side / shape->nominalSize);
|
||||
|
||||
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: png shape has nominal {:.2f}, pixel size will be {}x", shape->nominalSize, PIXELSIDE);
|
||||
|
||||
for (auto& f : FRAMES) {
|
||||
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
|
||||
newImage->artificial = true;
|
||||
newImage->side = info.size;
|
||||
newImage->artificialData = new char[info.size * info.size * 4];
|
||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4);
|
||||
newImage->side = PIXELSIDE;
|
||||
newImage->artificialData = new char[PIXELSIDE * PIXELSIDE * 4];
|
||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, PIXELSIDE, PIXELSIDE, PIXELSIDE * 4);
|
||||
newImage->delay = f->delay;
|
||||
|
||||
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
||||
|
@ -513,12 +523,12 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
|
||||
const auto PTN = cairo_pattern_create_for_surface(f->cairoSurface);
|
||||
cairo_pattern_set_extend(PTN, CAIRO_EXTEND_NONE);
|
||||
const float scale = info.size / (float)f->side;
|
||||
const float scale = PIXELSIDE / (float)f->side;
|
||||
cairo_scale(PCAIRO, scale, scale);
|
||||
cairo_pattern_set_filter(PTN, shape->resizeAlgo == HC_RESIZE_BILINEAR ? CAIRO_FILTER_GOOD : CAIRO_FILTER_NEAREST);
|
||||
cairo_set_source(PCAIRO, PTN);
|
||||
|
||||
cairo_rectangle(PCAIRO, 0, 0, info.size, info.size);
|
||||
cairo_rectangle(PCAIRO, 0, 0, PIXELSIDE, PIXELSIDE);
|
||||
|
||||
cairo_fill(PCAIRO);
|
||||
cairo_surface_flush(newImage->cairoSurface);
|
||||
|
@ -531,12 +541,16 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
|
||||
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: svg shape {} has {} frames", shape->directory, FRAMES.size());
|
||||
|
||||
const int PIXELSIDE = std::round(info.size / shape->nominalSize);
|
||||
|
||||
Debug::log(HC_LOG_TRACE, logFn, "loadThemeStyle: svg shape has nominal {:.2f}, pixel size will be {}x", shape->nominalSize, PIXELSIDE);
|
||||
|
||||
for (auto& f : FRAMES) {
|
||||
auto& newImage = impl->loadedShapes[shape.get()].images.emplace_back(std::make_unique<SLoadedCursorImage>());
|
||||
newImage->artificial = true;
|
||||
newImage->side = info.size;
|
||||
newImage->artificialData = new char[info.size * info.size * 4];
|
||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, info.size, info.size, info.size * 4);
|
||||
newImage->side = PIXELSIDE;
|
||||
newImage->artificialData = new char[PIXELSIDE * PIXELSIDE * 4];
|
||||
newImage->cairoSurface = cairo_image_surface_create_for_data((unsigned char*)newImage->artificialData, CAIRO_FORMAT_ARGB32, PIXELSIDE, PIXELSIDE, PIXELSIDE * 4);
|
||||
newImage->delay = f->delay;
|
||||
|
||||
const auto PCAIRO = cairo_create(newImage->cairoSurface);
|
||||
|
@ -554,7 +568,7 @@ bool CHyprcursorManager::loadThemeStyle(const SCursorStyleInfo& info) {
|
|||
return false;
|
||||
}
|
||||
|
||||
RsvgRectangle rect = {0, 0, (double)info.size, (double)info.size};
|
||||
RsvgRectangle rect = {0, 0, (double)PIXELSIDE, (double)PIXELSIDE};
|
||||
|
||||
if (!rsvg_handle_render_document(handle, PCAIRO, &rect, &error)) {
|
||||
Debug::log(HC_LOG_ERR, logFn, "Failed rendering svg: {}", error->message);
|
||||
|
@ -584,7 +598,7 @@ void CHyprcursorManager::cursorSurfaceStyleDone(const SCursorStyleInfo& info) {
|
|||
const bool isArtificial = e->artificial;
|
||||
|
||||
// clean artificial rasters made for this
|
||||
if (isArtificial && e->side == info.size)
|
||||
if (isArtificial && e->side == std::round(info.size / shape->nominalSize))
|
||||
return true;
|
||||
|
||||
// clean invalid non-svg rasters
|
||||
|
@ -766,10 +780,11 @@ std::optional<std::string> CHyprcursorImplementation::loadTheme() {
|
|||
if (SHAPE->images.empty())
|
||||
return "meta invalid: no images for shape " + cursor.path().stem().string();
|
||||
|
||||
SHAPE->directory = cursor.path().stem().string();
|
||||
SHAPE->hotspotX = meta.parsedData.hotspotX;
|
||||
SHAPE->hotspotY = meta.parsedData.hotspotY;
|
||||
SHAPE->resizeAlgo = stringToAlgo(meta.parsedData.resizeAlgo);
|
||||
SHAPE->directory = cursor.path().stem().string();
|
||||
SHAPE->hotspotX = meta.parsedData.hotspotX;
|
||||
SHAPE->hotspotY = meta.parsedData.hotspotY;
|
||||
SHAPE->nominalSize = meta.parsedData.nominalSize;
|
||||
SHAPE->resizeAlgo = stringToAlgo(meta.parsedData.resizeAlgo);
|
||||
|
||||
zip_discard(zip);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ struct SCursorImage {
|
|||
|
||||
struct SCursorShape {
|
||||
std::string directory;
|
||||
float hotspotX = 0, hotspotY = 0;
|
||||
float hotspotX = 0, hotspotY = 0, nominalSize = 1.F;
|
||||
eHyprcursorResizeAlgo resizeAlgo = HC_RESIZE_NEAREST;
|
||||
std::vector<SCursorImage> images;
|
||||
std::vector<std::string> overrides;
|
||||
|
|
|
@ -142,6 +142,7 @@ std::optional<std::string> CMeta::parseHL() {
|
|||
meta = std::make_unique<Hyprlang::CConfig>(rawdata.c_str(), Hyprlang::SConfigOptions{.pathIsStream = !dataPath});
|
||||
meta->addConfigValue("hotspot_x", Hyprlang::FLOAT{0.F});
|
||||
meta->addConfigValue("hotspot_y", Hyprlang::FLOAT{0.F});
|
||||
meta->addConfigValue("nominal_size", Hyprlang::FLOAT{1.F});
|
||||
meta->addConfigValue("resize_algorithm", Hyprlang::STRING{"nearest"});
|
||||
meta->registerHandler(::parseDefineSize, "define_size", {.allowFlags = false});
|
||||
meta->registerHandler(::parseOverride, "define_override", {.allowFlags = false});
|
||||
|
@ -151,9 +152,10 @@ std::optional<std::string> CMeta::parseHL() {
|
|||
return RESULT.getError();
|
||||
} catch (const char* err) { return "failed parsing meta: " + std::string{err}; }
|
||||
|
||||
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
|
||||
parsedData.hotspotY = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_y"));
|
||||
parsedData.resizeAlgo = std::any_cast<Hyprlang::STRING>(meta->getConfigValue("resize_algorithm"));
|
||||
parsedData.hotspotX = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_x"));
|
||||
parsedData.hotspotY = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("hotspot_y"));
|
||||
parsedData.nominalSize = std::any_cast<Hyprlang::FLOAT>(meta->getConfigValue("nominal_size"));
|
||||
parsedData.resizeAlgo = std::any_cast<Hyprlang::STRING>(meta->getConfigValue("resize_algorithm"));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -164,6 +166,7 @@ std::optional<std::string> CMeta::parseTOML() {
|
|||
|
||||
parsedData.hotspotX = MANIFEST["General"]["hotspot_x"].value_or(0.f);
|
||||
parsedData.hotspotY = MANIFEST["General"]["hotspot_y"].value_or(0.f);
|
||||
parsedData.hotspotY = MANIFEST["General"]["nominal_size"].value_or(1.f);
|
||||
|
||||
const std::string OVERRIDES = MANIFEST["General"]["define_override"].value_or("");
|
||||
const std::string SIZES = MANIFEST["General"]["define_size"].value_or("");
|
||||
|
|
|
@ -20,7 +20,7 @@ class CMeta {
|
|||
|
||||
struct {
|
||||
std::string resizeAlgo;
|
||||
float hotspotX = 0, hotspotY = 0;
|
||||
float hotspotX = 0, hotspotY = 0, nominalSize = 1.F;
|
||||
std::vector<std::string> overrides;
|
||||
std::vector<SDefinedSize> definedSizes;
|
||||
} parsedData;
|
||||
|
|
Loading…
Reference in a new issue