OmaPhoto 1.0.0: the Linux port of Compositor
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:
commit
c864304695
564 files changed
+100804
No files matched your search
@@ -0,0 +1,73 @@
|
||||
#include "UI/SliderSnap.h"
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
#include <QSlider>
|
||||
#include <QStyle>
|
||||
#include <QStyleOptionSlider>
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
// Swift's snapValue: the value under a press on the track.
|
||||
class Snap : public QObject {
|
||||
public:
|
||||
using QObject::QObject;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override
|
||||
{
|
||||
auto *slider = qobject_cast<QSlider *>(watched);
|
||||
if (!slider || event->type() != QEvent::MouseButtonPress)
|
||||
return false;
|
||||
const auto *press = static_cast<QMouseEvent *>(event);
|
||||
// Qt refuses a press made with another button held.
|
||||
if (press->buttons() != Qt::LeftButton || slider->orientation() != Qt::Horizontal || !slider->isEnabled()
|
||||
|| slider->maximum() <= slider->minimum())
|
||||
return false;
|
||||
// QSlider's own style option, which it keeps protected.
|
||||
QStyleOptionSlider option;
|
||||
option.initFrom(slider);
|
||||
option.orientation = Qt::Horizontal;
|
||||
option.state |= QStyle::State_Horizontal;
|
||||
option.minimum = slider->minimum();
|
||||
option.maximum = slider->maximum();
|
||||
option.tickPosition = slider->tickPosition();
|
||||
option.tickInterval = slider->tickInterval();
|
||||
option.upsideDown = slider->invertedAppearance() != (option.direction == Qt::RightToLeft);
|
||||
option.direction = Qt::LeftToRight;
|
||||
option.sliderPosition = slider->sliderPosition();
|
||||
option.sliderValue = slider->value();
|
||||
option.singleStep = slider->singleStep();
|
||||
option.pageStep = slider->pageStep();
|
||||
const QRect groove = slider->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, slider);
|
||||
const QRect knob = slider->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, slider);
|
||||
const QPoint point = press->position().toPoint();
|
||||
// The knob itself drags from where it is.
|
||||
if (knob.contains(point) || groove.width() <= knob.width())
|
||||
return false;
|
||||
// Down first, as Swift's editing begins before the value.
|
||||
slider->setSliderDown(true);
|
||||
slider->setValue(QStyle::sliderValueFromPosition(slider->minimum(), slider->maximum(), point.x() - groove.x() - knob.width() / 2,
|
||||
groove.width() - knob.width(), option.upsideDown));
|
||||
// A rounding owner may move the knob: press there.
|
||||
option.sliderPosition = slider->sliderPosition();
|
||||
option.sliderValue = slider->value();
|
||||
const QRect moved = slider->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, slider);
|
||||
const QPoint inside(std::clamp(point.x(), moved.left(), moved.right()), std::clamp(point.y(), moved.top(), moved.bottom()));
|
||||
const QPointF shift = inside - point;
|
||||
QMouseEvent forwarded(QEvent::MouseButtonPress, inside, press->scenePosition() + shift, press->globalPosition() + shift, Qt::LeftButton,
|
||||
Qt::LeftButton, press->modifiers());
|
||||
QCoreApplication::sendEvent(slider, &forwarded);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void SliderSnap::install()
|
||||
{
|
||||
// Once, as Swift's lazy static swaps the method once.
|
||||
static const bool installed = [] {
|
||||
qApp->installEventFilter(new Snap(qApp));
|
||||
return true;
|
||||
}();
|
||||
(void)installed;
|
||||
}
|
||||
Reference in new issue
Block a user