Layer › Ungroup Layers (Ctrl+Shift+G), in a folder's menu too; Alt over a mask shows the eye pointer (13.15)
This commit is contained in:
1 parent
3f2b99f045
commit
6ea248367d
12 files changed
+271
-12
No files matched your search
@@ -255,6 +255,7 @@ CompositorMenus::CompositorMenus(ProjectWorkspace &workspace, QMenuBar &bar, QWi
|
||||
});
|
||||
layer->addSeparator();
|
||||
add(layer, QStringLiteral("groupLayers"), QStringLiteral("Group Selected Layers"), QKeySequence(Qt::CTRL | Qt::Key_G), [this] { session().groupSelectedLayers(); });
|
||||
add(layer, QStringLiteral("ungroupLayers"), QStringLiteral("Ungroup Layers"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_G), [this] { session().ungroupLayers(); });
|
||||
add(layer, QStringLiteral("moveOutOfFolder"), QStringLiteral("Move Out of Folder"), QKeySequence(), [this] { session().moveActiveLayerOutOfGroup(); });
|
||||
add(layer, QStringLiteral("newBlankLayer"), QStringLiteral("New Blank Layer"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_N), [this] { session().addBlankLayer(); });
|
||||
add(layer, QStringLiteral("renameLayer"), QStringLiteral("Rename Layer…"), QKeySequence(), [this] { session().setRenamingLayerID(session().activeLayerID()); });
|
||||
@@ -407,6 +408,7 @@ void CompositorMenus::synchronize()
|
||||
action(QStringLiteral("clippingMask"))->setText(active && active->maskSourceID ? QStringLiteral("Release Clipping Mask") : QStringLiteral("Create Clipping Mask"));
|
||||
action(QStringLiteral("clippingMask"))->setEnabled(s.activeLayerID() && s.canToggleClippingMask(*s.activeLayerID()));
|
||||
action(QStringLiteral("groupLayers"))->setEnabled(s.canEditLayers());
|
||||
action(QStringLiteral("ungroupLayers"))->setEnabled(s.canUngroupLayers());
|
||||
action(QStringLiteral("moveOutOfFolder"))->setEnabled(s.canEditLayers() && active && active->parentID);
|
||||
action(QStringLiteral("newBlankLayer"))->setEnabled(s.canEditLayers());
|
||||
action(QStringLiteral("renameLayer"))->setEnabled(s.canEditLayers() && active);
|
||||
|
||||
@@ -134,7 +134,7 @@ const std::vector<ShortcutDefinition> &ShortcutDefinition::all()
|
||||
entry("Levels", "l", 1, true), entry("Hue/Saturation", "u", 1, true), entry("Invert Pixels / Mask", "i", 1, true),
|
||||
entry("Canvas Size", "c", 3, true), entry("Image Size", "i", 3, true), entry("Transform Layer / Selection", "t", 1, true),
|
||||
entry("Duplicate / Layer via Copy", "j", 1, true), entry("Toggle Clipping Mask", "g", 3, true),
|
||||
entry("Group Layers", "g", 1, true), entry("New Blank Layer", "n", 9, true), entry("Move Layer Up", "]", 1, true),
|
||||
entry("Group Layers", "g", 1, true), entry("Ungroup Layers", "g", 9, true), entry("New Blank Layer", "n", 9, true), entry("Move Layer Up", "]", 1, true),
|
||||
entry("Move Layer Down", "[", 1, true), entry("Merge Layers", "e", 1, true), entry("Show Grid", "'", 1, true),
|
||||
entry("Show Guides", ";", 1, true), entry("Show Rulers", "r", 1, true), entry("Snap", ";", 9, true), entry("Lock Guides", ";", 3, true)};
|
||||
const std::vector<std::pair<const char *, QString>> tools{
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QScrollBar>
|
||||
#include <cmath>
|
||||
|
||||
const QString NativeLayerList::maskType = QStringLiteral("com.compositor.layer-mask");
|
||||
const QString NativeLayerList::sourceType = QStringLiteral("com.compositor.layer-list");
|
||||
@@ -299,6 +300,37 @@ QCursor NativeLayerList::clippingCursor(bool releasing, double ratio)
|
||||
return QCursor(pixmap, 3, 3);
|
||||
}
|
||||
|
||||
// Swift's eye.fill: an almond, a ring round the pupil.
|
||||
QCursor NativeLayerList::showMaskCursor(double ratio)
|
||||
{
|
||||
const QCursor base = CanvasView::duplicateCursor(ratio);
|
||||
const QPointF hotSpot = base.hotSpot();
|
||||
const QRectF eye(hotSpot + QPointF(15, 18), QSizeF(7.5, 5.5));
|
||||
const QSizeF baseSize = base.pixmap().deviceIndependentSize();
|
||||
const QSize size(int(std::ceil(std::max(baseSize.width(), eye.right() + 2))), int(std::ceil(std::max(baseSize.height(), eye.bottom() + 2))));
|
||||
QPixmap pixmap(size * ratio);
|
||||
pixmap.setDevicePixelRatio(ratio);
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
QPainterPath shape;
|
||||
shape.setFillRule(Qt::OddEvenFill);
|
||||
shape.moveTo(eye.left(), eye.center().y());
|
||||
shape.quadTo(eye.center().x(), eye.top() - eye.height() / 2, eye.right(), eye.center().y());
|
||||
shape.quadTo(eye.center().x(), eye.bottom() + eye.height() / 2, eye.left(), eye.center().y());
|
||||
shape.addEllipse(eye.center(), 1.9, 1.9);
|
||||
shape.addEllipse(eye.center(), 1.1, 1.1);
|
||||
// The eye first, haloed, so the arrows sit in front.
|
||||
for (int step = 0; step < 16; ++step) {
|
||||
const double angle = step * M_PI / 8;
|
||||
painter.fillPath(shape.translated(std::cos(angle), std::sin(angle)), Qt::white);
|
||||
}
|
||||
painter.fillPath(shape, Qt::black);
|
||||
painter.drawPixmap(QPointF(0, 0), base.pixmap());
|
||||
painter.end();
|
||||
return QCursor(pixmap, int(hotSpot.x()), int(hotSpot.y()));
|
||||
}
|
||||
|
||||
QCursor NativeLayerList::cursorFor(QPoint listPoint, Qt::KeyboardModifiers modifiers) const
|
||||
{
|
||||
const int row = rowAt(listPoint);
|
||||
@@ -317,9 +349,9 @@ QCursor NativeLayerList::cursorFor(QPoint listPoint, Qt::KeyboardModifiers modif
|
||||
return QCursor(Qt::ArrowCursor);
|
||||
}
|
||||
const bool editable = m_session.canEditLayers();
|
||||
// A mask copies, the row duplicates, the strip clips.
|
||||
// A mask shows alone, the row duplicates, the strip clips.
|
||||
if (cell.maskThumbnail().isVisible() && cell.maskThumbnail().geometry().contains(inCell))
|
||||
return editable ? CanvasView::duplicateCursor(ratio) : QCursor(Qt::ArrowCursor);
|
||||
return showMaskCursor(ratio);
|
||||
if (!isClippingZone(cell, inCell))
|
||||
return editable ? CanvasView::duplicateCursor(ratio) : QCursor(Qt::ArrowCursor);
|
||||
if (!m_session.canToggleClippingMask(layer.id))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "UI/NativeLayerList.h"
|
||||
#include <QMenu>
|
||||
#include <algorithm>
|
||||
|
||||
// Swift's table-level context menu (1.2.5): entries and validation.
|
||||
std::unique_ptr<QMenu> NativeLayerList::contextMenu(QUuid id)
|
||||
@@ -40,6 +41,9 @@ std::unique_ptr<QMenu> NativeLayerList::contextMenu(QUuid id)
|
||||
entry(*menu, "groupLayers", QStringLiteral("Group Selected Layers"),
|
||||
session.canEditLayers() && session.document() && session.document()->layers.size() < 10'000 && !session.selectedLayerIDs().isEmpty(),
|
||||
[&session] { session.groupSelectedLayers(); });
|
||||
// A folder right-clicked can be ungrouped.
|
||||
if (std::ranges::any_of(session.document()->layers, [id](const ImageLayer &layer) { return layer.id == id && layer.isGroup; }))
|
||||
entry(*menu, "ungroupLayers", QStringLiteral("Ungroup Layers"), session.canUngroupLayers(), [&session] { session.ungroupLayers(); });
|
||||
entry(*menu, "moveOut", QStringLiteral("Move Out of Folder"), session.canEditLayers() && active && active->parentID,
|
||||
[&session] { session.moveActiveLayerOutOfGroup(); });
|
||||
entry(*menu, "mergeLayers", session.mergeTitle(), session.canMergeLayers(), [&session] { session.mergeLayers(); });
|
||||
|
||||
@@ -242,6 +242,8 @@ public:
|
||||
// The cursor Alt asks for here: clip, duplicate, arrow.
|
||||
QCursor cursorFor(QPoint listPoint, Qt::KeyboardModifiers modifiers) const;
|
||||
static QCursor clippingCursor(bool releasing, double ratio);
|
||||
// Alt over a mask: the duplicate pointer, an eye behind.
|
||||
static QCursor showMaskCursor(double ratio);
|
||||
|
||||
protected:
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
Reference in new issue
Block a user