OmaPhoto 1.0.0: the Linux port of Compositor
Release / deb (push) Canceled after 0s
Release / rpm (push) Canceled after 0s
Release / arch (push) Canceled after 0s
Release / publish (push) Canceled after 0s

A layered image editor for Linux and Omarchy, ported from Compositor
(github.com/robbietilton/Compositor), whose Swift source is its
specification. It reads and writes Compositor's .comp projects.

Packages for Ubuntu, Fedora and Arch come from the release workflow;
scripts/install/ holds one install script per distribution family,
and flake.nix serves NixOS.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
雷电芽衣andClaude committed 2026-09-26 00:44:52 -04:00
commit c864304695
564 files changed
+100804

No files matched your search

+178
View File
@@ -0,0 +1,178 @@
#include "Document/LayerEffects.h"
#include <cmath>
#include <stdexcept>
namespace {
bool within(double value, double low, double high)
{
return value >= low && value <= high;
}
bool colourIsValid(double red, double green, double blue)
{
return within(red, 0, 1) && within(green, 0, 1) && within(blue, 0, 1);
}
// Away from the light; a layer's pixels count y downward.
QSizeF fallingFrom(double angle, double distance)
{
const double radians = angle * M_PI / 180;
return QSizeF(-std::cos(radians) * distance, std::sin(radians) * distance);
}
bool shadowIsValid(double angle, double distance, double blur, double opacity)
{
return within(angle, -360, 360) && within(distance, 0, 5000) && within(blur, 0, 500) && within(opacity, 0, 1);
}
}
bool StrokeEffect::isValid() const
{
return within(size, 0, maxSize) && within(opacity, 0, 1) && colourIsValid(red, green, blue);
}
QSizeF ShadowEffect::offset() const
{
return fallingFrom(angle, distance);
}
bool ShadowEffect::isValid() const
{
return shadowIsValid(angle, distance, blur, opacity) && colourIsValid(red, green, blue);
}
bool ColorOverlayEffect::isValid() const
{
return within(opacity, 0, 1) && colourIsValid(red, green, blue);
}
QSizeF InnerShadowEffect::offset() const
{
return fallingFrom(angle, distance);
}
bool InnerShadowEffect::isValid() const
{
return shadowIsValid(angle, distance, blur, opacity) && colourIsValid(red, green, blue);
}
QString rawValue(LayerEffectKind kind)
{
switch (kind) {
case LayerEffectKind::stroke: return QStringLiteral("Stroke");
case LayerEffectKind::shadow: return QStringLiteral("Drop Shadow");
case LayerEffectKind::colorOverlay: return QStringLiteral("Color Overlay");
case LayerEffectKind::innerShadow: return QStringLiteral("Inner Shadow");
}
throw std::logic_error("unknown effect kind");
}
bool LayerEffects::isValid() const
{
return (!stroke || stroke->isValid()) && (!shadow || shadow->isValid()) && (!colorOverlay || colorOverlay->isValid())
&& (!innerShadow || innerShadow->isValid());
}
std::vector<LayerEffectKind> LayerEffects::kinds() const
{
std::vector<LayerEffectKind> result;
for (const LayerEffectKind kind : allLayerEffectKinds) {
if (contains(kind))
result.push_back(kind);
}
return result;
}
bool LayerEffects::contains(LayerEffectKind kind) const
{
switch (kind) {
case LayerEffectKind::stroke: return stroke.has_value();
case LayerEffectKind::shadow: return shadow.has_value();
case LayerEffectKind::colorOverlay: return colorOverlay.has_value();
case LayerEffectKind::innerShadow: return innerShadow.has_value();
}
throw std::logic_error("unknown effect kind");
}
bool LayerEffects::isEnabled(LayerEffectKind kind) const
{
switch (kind) {
case LayerEffectKind::stroke: return stroke && stroke->isEnabled();
case LayerEffectKind::shadow: return shadow && shadow->isEnabled();
case LayerEffectKind::colorOverlay: return colorOverlay && colorOverlay->isEnabled();
case LayerEffectKind::innerShadow: return innerShadow && innerShadow->isEnabled();
}
throw std::logic_error("unknown effect kind");
}
std::optional<PaletteColor> LayerEffects::color(LayerEffectKind kind) const
{
switch (kind) {
case LayerEffectKind::stroke: return stroke ? std::optional(stroke->color()) : std::nullopt;
case LayerEffectKind::shadow: return shadow ? std::optional(shadow->color()) : std::nullopt;
case LayerEffectKind::colorOverlay: return colorOverlay ? std::optional(colorOverlay->color()) : std::nullopt;
case LayerEffectKind::innerShadow: return innerShadow ? std::optional(innerShadow->color()) : std::nullopt;
}
throw std::logic_error("unknown effect kind");
}
namespace {
// Swift's optional chaining: a missing effect takes nothing.
template <typename Effect> void paint(std::optional<Effect> &effect, const PaletteColor &color)
{
if (!effect)
return;
effect->red = color.red;
effect->green = color.green;
effect->blue = color.blue;
}
template <typename Effect> void enable(std::optional<Effect> &effect, bool enabled)
{
if (effect)
effect->enabled = enabled;
}
template <typename Effect> std::optional<Effect> shown(const std::optional<Effect> &effect)
{
return effect && effect->isEnabled() ? effect : std::nullopt;
}
}
void LayerEffects::setColor(const PaletteColor &color, LayerEffectKind kind)
{
switch (kind) {
case LayerEffectKind::stroke: paint(stroke, color); return;
case LayerEffectKind::shadow: paint(shadow, color); return;
case LayerEffectKind::colorOverlay: paint(colorOverlay, color); return;
case LayerEffectKind::innerShadow: paint(innerShadow, color); return;
}
throw std::logic_error("unknown effect kind");
}
void LayerEffects::remove(LayerEffectKind kind)
{
switch (kind) {
case LayerEffectKind::stroke: stroke.reset(); return;
case LayerEffectKind::shadow: shadow.reset(); return;
case LayerEffectKind::colorOverlay: colorOverlay.reset(); return;
case LayerEffectKind::innerShadow: innerShadow.reset(); return;
}
throw std::logic_error("unknown effect kind");
}
void LayerEffects::setEnabled(bool enabled, LayerEffectKind kind)
{
switch (kind) {
case LayerEffectKind::stroke: enable(stroke, enabled); return;
case LayerEffectKind::shadow: enable(shadow, enabled); return;
case LayerEffectKind::colorOverlay: enable(colorOverlay, enabled); return;
case LayerEffectKind::innerShadow: enable(innerShadow, enabled); return;
}
throw std::logic_error("unknown effect kind");
}
LayerEffects LayerEffects::visible() const
{
return LayerEffects{shown(stroke), shown(shadow), shown(colorOverlay), shown(innerShadow)};
}