Merge 13.11 (cc9bf95); Blur pieces and per-tile clone pieces on its grid sampling (13.16, part two)
This commit is contained in:
commit
c7e8bdfe8e
30 files changed
+910
-173
No files matched your search
@@ -2,20 +2,10 @@
|
||||
#include "IO/RecentProjects.h"
|
||||
#include "Logging.h"
|
||||
#include "UI/KeyboardShortcuts.h"
|
||||
#include "UI/NativeLayerList.h"
|
||||
#include <QApplication>
|
||||
#include <QMenu>
|
||||
|
||||
namespace {
|
||||
// The layer list holding the keys, as Swift's table.
|
||||
NativeLayerList *focusedList()
|
||||
{
|
||||
for (QWidget *widget = QApplication::focusWidget(); widget; widget = widget->parentWidget())
|
||||
if (auto *list = qobject_cast<NativeLayerList *>(widget))
|
||||
return list;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// An entry's name: Hue/Saturation is newHueSaturationAdjustment.
|
||||
QString adjustmentName(AdjustmentKind kind)
|
||||
{
|
||||
@@ -186,8 +176,6 @@ CompositorMenus::CompositorMenus(ProjectWorkspace &workspace, QMenuBar &bar, QWi
|
||||
m_field->selectAll();
|
||||
else if (InlineTextEditor *text = typedText())
|
||||
text->selectAll();
|
||||
else if (NativeLayerList *list = focusedList())
|
||||
list->selectAllRows();
|
||||
else
|
||||
session().selectAll();
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <QApplication>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QLocale>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
@@ -115,7 +116,7 @@ void LayerCell::configure(const ImageLayer &layer, bool enabled, int depth, bool
|
||||
m_dimensions->setText(m_editableText ? QStringLiteral("Text · Double-click to edit")
|
||||
: m_isAdjustment ? QStringLiteral("Adjustment · Double-click to edit")
|
||||
: layer.isGroup ? QStringLiteral("Folder")
|
||||
: QStringLiteral("%1 × %2 px").arg(std::lround(layer.size().width())).arg(std::lround(layer.size().height())));
|
||||
: sizeLabel(layer));
|
||||
m_dimensions->setToolTip(QString());
|
||||
if (layer.maskSourceID && session.document()) {
|
||||
const int source = indexOf(session.document()->layers, layer.maskSourceID);
|
||||
@@ -335,3 +336,18 @@ bool LayerCell::eventFilter(QObject *watched, QEvent *event)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString sizeLabel(const ImageLayer &layer)
|
||||
{
|
||||
const QString text = QStringLiteral("%1 × %2 px").arg(std::lround(layer.size().width())).arg(std::lround(layer.size().height()));
|
||||
const int pixels = layer.asset ? layer.asset->size().width() : 0;
|
||||
if (pixels <= 0)
|
||||
return text;
|
||||
// Across the width, as the Move bar's Scale field.
|
||||
const double percent = layer.size().width() / pixels * 100;
|
||||
if (std::abs(percent - 100) < 0.05)
|
||||
return text;
|
||||
// Swift's .number to one place at most, ties to even.
|
||||
const double rounded = std::nearbyint(percent * 10) / 10;
|
||||
return text + QStringLiteral(" · ") + QLocale().toString(rounded, 'f', rounded == std::trunc(rounded) ? 0 : 1) + QStringLiteral("%");
|
||||
}
|
||||
@@ -261,13 +261,3 @@ void NativeLayerList::changeEvent(QEvent *event)
|
||||
if (event->type() == QEvent::PaletteChange)
|
||||
QMetaObject::invokeMethod(this, &NativeLayerList::update, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void NativeLayerList::selectAllRows()
|
||||
{
|
||||
if (m_rows.empty())
|
||||
return;
|
||||
QSet<QUuid> ids;
|
||||
for (const ImageLayer &row : m_rows)
|
||||
ids.insert(row.id);
|
||||
m_session.selectLayers(ids, m_rows.front().id);
|
||||
}
|
||||
@@ -215,8 +215,6 @@ public:
|
||||
QString dragToken() const { return m_dragToken; }
|
||||
|
||||
EditorSession &session() const { return m_session; }
|
||||
// The table's Select All: every row, the top one primary.
|
||||
void selectAllRows();
|
||||
void update();
|
||||
std::vector<LayerCell *> cells() const { return m_cells; }
|
||||
// The row under a point of this list, or -1.
|
||||
@@ -281,3 +279,6 @@ private:
|
||||
const QMimeData *m_dragData = nullptr;
|
||||
Qt::DropActions m_dragActions;
|
||||
};
|
||||
|
||||
// The size on the canvas and, once scaled, how much.
|
||||
QString sizeLabel(const ImageLayer &layer);
|
||||
@@ -109,7 +109,8 @@ TransformInspector::TransformInspector(EditorSession &session, QWidget *parent)
|
||||
m_rotation(new TransformValueField(QStringLiteral("°"), QString(), -360, 360, session, [this] { finish(); }, [this](double number) {
|
||||
change([number](LayerTransform &value) { value.rotation = std::fmod(number, 360.0); });
|
||||
})),
|
||||
m_sampling(new QComboBox(this)), m_cancel(new QPushButton(QStringLiteral("Cancel"), this)), m_apply(new QPushButton(QStringLiteral("Apply"), this))
|
||||
m_sampling(new QComboBox(this)), m_cancel(new QPushButton(QStringLiteral("Cancel"), this)), m_apply(new QPushButton(QStringLiteral("Apply"), this)),
|
||||
m_pendingButtons(new QWidget(this)), m_fade(new QGraphicsOpacityEffect(m_pendingButtons)), m_fadeIn(new QPropertyAnimation(m_fade, "opacity", this))
|
||||
{
|
||||
m_autoSelect->setObjectName(QStringLiteral("transformAutoSelect"));
|
||||
m_autoSelect->setToolTip(QStringLiteral("Select layers by clicking the canvas. Hold Ctrl to turn it the other way while you click."));
|
||||
@@ -176,8 +177,25 @@ TransformInspector::TransformInspector(EditorSession &session, QWidget *parent)
|
||||
// Swift's configuredNativeShortcut: Return and Escape, as remapped.
|
||||
NativeShortcut::bind(*this, m_apply, m_cancel);
|
||||
connect(m_apply, &QPushButton::clicked, this, [this] { m_session.commitTransform(); });
|
||||
m_pendingButtons->setObjectName(QStringLiteral("pendingTransform"));
|
||||
auto *pending = new QHBoxLayout(m_pendingButtons);
|
||||
pending->setContentsMargins(0, 0, 0, 0);
|
||||
pending->setSpacing(12);
|
||||
pending->addWidget(m_cancel);
|
||||
pending->addWidget(m_apply);
|
||||
// Unseen, not hidden: Return and Escape still reach a drag.
|
||||
m_pendingButtons->setGraphicsEffect(m_fade);
|
||||
m_fade->setOpacity(0);
|
||||
m_pendingButtons->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
m_cancel->setFocusPolicy(Qt::NoFocus);
|
||||
m_apply->setFocusPolicy(Qt::NoFocus);
|
||||
// SwiftUI's easeOut over 0.12 seconds.
|
||||
QEasingCurve easeOut(QEasingCurve::BezierSpline);
|
||||
easeOut.addCubicBezierSegment(QPointF(0, 0), QPointF(0.58, 1), QPointF(1, 1));
|
||||
m_fadeIn->setEasingCurve(easeOut);
|
||||
m_fadeIn->setDuration(120);
|
||||
// Before the stretch ending the row, in Swift's order.
|
||||
for (QWidget *widget : std::initializer_list<QWidget *>{m_autoSelect, m_showControls, m_fields, m_cancel, m_apply})
|
||||
for (QWidget *widget : std::initializer_list<QWidget *>{m_autoSelect, m_showControls, m_fields, m_pendingButtons})
|
||||
row->insertWidget(row->count() - 1, widget, widget == m_fields ? 1 : 0);
|
||||
// The scroll view takes the spare room, as SwiftUI's does.
|
||||
row->setStretch(row->count() - 1, 0);
|
||||
@@ -301,4 +319,16 @@ void TransformInspector::synchronize()
|
||||
m_fields->widget()->setEnabled((m_session.canTransform() || editing) && !distorted);
|
||||
m_cancel->setEnabled(editing);
|
||||
m_apply->setEnabled(editing);
|
||||
// Typed values, Ctrl+T, a distortion wait; a handle drag applies.
|
||||
const bool pending = editing && m_session.transformEdit()->persistent;
|
||||
if (pending == m_pending)
|
||||
return;
|
||||
m_pending = pending;
|
||||
m_pendingButtons->setAttribute(Qt::WA_TransparentForMouseEvents, !pending);
|
||||
m_cancel->setFocusPolicy(pending ? Qt::StrongFocus : Qt::NoFocus);
|
||||
m_apply->setFocusPolicy(pending ? Qt::StrongFocus : Qt::NoFocus);
|
||||
m_fadeIn->stop();
|
||||
m_fadeIn->setStartValue(m_fade->opacity());
|
||||
m_fadeIn->setEndValue(pending ? 1.0 : 0.0);
|
||||
m_fadeIn->start();
|
||||
}
|
||||
@@ -3,7 +3,9 @@
|
||||
#include "UI/ToolHeaderStyle.h"
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QLineEdit>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QToolButton>
|
||||
@@ -80,4 +82,9 @@ private:
|
||||
QComboBox *const m_sampling;
|
||||
QPushButton *const m_cancel;
|
||||
QPushButton *const m_apply;
|
||||
// Cancel and Apply, seen only while an edit waits.
|
||||
QWidget *const m_pendingButtons;
|
||||
QGraphicsOpacityEffect *const m_fade;
|
||||
QPropertyAnimation *const m_fadeIn;
|
||||
bool m_pending = false;
|
||||
};
|
||||
Reference in new issue
Block a user