Files
OmaPhoto/src/UI/SliderSnap.cpp
T
雷电芽衣andClaude c864304695
Release / deb (push) Canceled after 0s
Release / rpm (push) Canceled after 0s
Release / arch (push) Canceled after 0s
Release / publish (push) Canceled after 0s
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>
2026-09-26 00:44:52 -04:00

74 lines
3.3 KiB
C++

#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;
}