484 lines
24 KiB
C++
484 lines
24 KiB
C++
#pragma once
|
||
#include "Document/BrushStroke.h"
|
||
#include "Document/CloneStamp.h"
|
||
#include "Document/ColorPalette.h"
|
||
#include "Document/ColorRangeSelection.h"
|
||
#include "Document/Gradient.h"
|
||
#include "Document/Distort.h"
|
||
#include "Document/DocumentLimits.h"
|
||
#include "Document/Filters.h"
|
||
#include "Document/LevelsAutomatic.h"
|
||
#include "Document/FloatingSelection.h"
|
||
#include "Document/MagicWand.h"
|
||
#include "Document/ObjectSelection.h"
|
||
#include "Document/SelectionClipboard.h"
|
||
#include "Document/SelectionEdits.h"
|
||
#include "Document/SmudgeLiquify.h"
|
||
#include "Document/ToolDefaults.h"
|
||
#include "Document/DocumentHistory.h"
|
||
#include "Document/EditorSession+Jobs.h"
|
||
#include "Document/EditorSession+Model.h"
|
||
#include "IO/ProjectStore.h"
|
||
#include "IO/PSD/PSDDocumentBuilder.h"
|
||
#include "IO/RawImporter.h"
|
||
#include "UI/PSDConversionSheet.h"
|
||
#include "Rendering/CanvasViewport.h"
|
||
#include "Rendering/EffectsPreviewCache.h"
|
||
#include <QFutureWatcher>
|
||
#include <QObject>
|
||
#include <QSet>
|
||
#include <QTimer>
|
||
#include <QUrl>
|
||
#include <deque>
|
||
#include <map>
|
||
#include <functional>
|
||
#include <set>
|
||
|
||
class QPainter;
|
||
|
||
// The one editor state; `changed` stands in for Swift's observation.
|
||
class EditorSession : public QObject, private SessionJobs {
|
||
Q_OBJECT
|
||
public:
|
||
explicit EditorSession(QObject *parent = nullptr);
|
||
|
||
// The canvas edits this in place, then calls notify().
|
||
CanvasViewport viewport;
|
||
DocumentHistory history;
|
||
// Swift's @ObservationIgnored tuple: the canvas draws it unannounced.
|
||
SnapGuides snapGuides;
|
||
// The canvas's effects previews, rendered off the UI thread.
|
||
EffectsPreviewCache effectsPreviews;
|
||
|
||
const std::optional<CanvasDocument> &document() const { return m_document; }
|
||
NavigationTool tool() const { return m_tool; }
|
||
const QSet<QUuid> &collapsedGroupIDs() const { return m_collapsedGroupIDs; }
|
||
const QSet<QUuid> &selectedLayerIDs() const { return m_selectedLayerIDs; }
|
||
std::optional<QUuid> activeLayerID() const { return m_activeLayerID; }
|
||
void setActiveLayerID(std::optional<QUuid> id);
|
||
std::optional<ImageLayer> activeLayer() const;
|
||
|
||
// Blocks overlapping edits at once.
|
||
bool isProjectBusy() const { return m_isProjectBusy; }
|
||
void setIsProjectBusy(bool busy);
|
||
// Busy this long, in milliseconds, before the controls dim.
|
||
static constexpr int busyIndicatorDelay = 250;
|
||
bool showsBusy() const { return m_showsBusy; }
|
||
bool showsNewDocument() const { return m_showsNewDocument; }
|
||
void setShowsNewDocument(bool shows);
|
||
bool showsImporter() const { return m_showsImporter; }
|
||
void setShowsImporter(bool shows);
|
||
bool isImporting() const { return m_isImporting; }
|
||
void setIsImporting(bool importing);
|
||
std::optional<QString> importError() const { return m_importError; }
|
||
void setImportError(std::optional<QString> error);
|
||
bool showsConversionSheet() const { return m_showsConversionSheet; }
|
||
const std::optional<PSDConversionRequest> &conversionRequest() const { return m_conversionRequest; }
|
||
std::optional<QUuid> renamingLayerID() const { return m_renamingLayerID; }
|
||
void setRenamingLayerID(std::optional<QUuid> id);
|
||
|
||
// The first tab's first canvas sheet skips the clipboard.
|
||
bool skipsInitialClipboardCanvasSize = false;
|
||
// Where the project lives on disk, once opened or saved.
|
||
const std::optional<QString> &projectPath() const { return m_projectPath; }
|
||
void setProjectPath(std::optional<QString> path);
|
||
bool canStartProjectOperation() const;
|
||
// `ready` runs at once, or when the session allows.
|
||
void waitForFileRequest(std::function<void()> ready);
|
||
void waitForProjectAccess(std::function<void()> ready);
|
||
void selectLayer(std::optional<QUuid> id);
|
||
void selectTool(NavigationTool value);
|
||
// Tab: the current tool's next mode.
|
||
void cycleToolMode();
|
||
// Whether the mask thumbnail, not the layer's, is the target.
|
||
bool isMaskSelected() const { return m_isMaskSelected; }
|
||
// Alt-click: the targeted mask alone, gray, on the canvas.
|
||
bool viewsMaskAlone() const { return m_viewsMaskAlone; }
|
||
void setViewsMaskAlone(bool value);
|
||
// A blend mode tried on by hovering; nothing is saved.
|
||
struct BlendPreview {
|
||
QUuid layerID;
|
||
LayerBlendMode mode;
|
||
friend bool operator==(const BlendPreview &, const BlendPreview &) = default;
|
||
};
|
||
const std::optional<BlendPreview> &blendPreview() const { return m_blendPreview; }
|
||
|
||
// A pending transform; layers change when it is committed.
|
||
const std::optional<TransformEdit> &transformEdit() const { return m_transformEdit; }
|
||
bool canTransform() const;
|
||
// Several layers, or a folder's contents, move in one box.
|
||
bool transformsAsGroup() const;
|
||
std::vector<ImageLayer> groupTransformMembers() const;
|
||
std::optional<LayerTransform> groupTransformBox() const;
|
||
void beginTransform(bool persistent = true, bool fromFields = false);
|
||
// Alt-drag: the selection's copies move, one step.
|
||
void beginDuplicateTransform();
|
||
// The Move tool's settings (TransformInspector, Ctrl+H).
|
||
bool transformAutoSelect() const { return m_transformAutoSelect; }
|
||
void setTransformAutoSelect(bool picks);
|
||
bool showsTransformControls() const { return m_showsTransformControls; }
|
||
void setShowsTransformControls(bool shows);
|
||
bool locksTransformRatio() const { return m_locksTransformRatio; }
|
||
void setLocksTransformRatio(bool locks);
|
||
void previewTransform(const LayerTransform &value);
|
||
void commitTransform();
|
||
void cancelTransform();
|
||
std::optional<QSizeF> transformPixelSize() const;
|
||
LayerTransform displayedTransform(const ImageLayer &layer) const;
|
||
LayerTransform editedTransform(const ImageLayer &layer) const;
|
||
std::optional<LayerTransform> pendingTransform(const ImageLayer &layer) const;
|
||
// An unlinked mask, selected, transforms without its layer.
|
||
bool transformTargetsMask() const;
|
||
void nudgeLayer(double dx, double dy);
|
||
const std::optional<LassoDraft> &lassoDraft() const { return m_lassoDraft; }
|
||
LassoKind lassoKind() const { return m_lassoKind; }
|
||
void setLassoKind(LassoKind kind);
|
||
LassoKind marqueeKind() const { return m_marqueeKind; }
|
||
void setMarqueeKind(LassoKind kind);
|
||
// The options bar's mode; Shift adds, Alt subtracts.
|
||
SelectionMode selectionModeChoice() const { return m_selectionModeChoice; }
|
||
void setSelectionModeChoice(SelectionMode mode);
|
||
std::optional<SelectionMode> heldSelectionMode() const { return m_heldSelectionMode; }
|
||
bool selectionAntialiased() const { return m_selectionAntialiased; }
|
||
void setSelectionAntialiased(bool antialiased);
|
||
// Pixels Expand and Contract grow or shrink by.
|
||
int selectionExpandAmount() const { return m_selectionExpandAmount; }
|
||
void setSelectionExpandAmount(int amount);
|
||
int selectionContractAmount() const { return m_selectionContractAmount; }
|
||
void setSelectionContractAmount(int amount);
|
||
int selectionFeatherAmount() const { return m_selectionFeatherAmount; }
|
||
void setSelectionFeatherAmount(int amount);
|
||
// The amount sheet's question, open while set.
|
||
std::optional<SelectionAmountOperation> selectionAmountOperation() const { return m_selectionAmountOperation; }
|
||
void setSelectionAmountOperation(std::optional<SelectionAmountOperation> operation);
|
||
const std::optional<DocumentSelection> &selectionMoveOrigin() const { return m_selectionMoveOrigin; }
|
||
const WandSettings &wandSettings() const { return m_wandSettings; }
|
||
void setWandSettings(const WandSettings &settings);
|
||
const BrushStroke *brushStroke() const { return m_brushStroke.get(); }
|
||
const BrushSettings &brushSettings() const { return m_brushSettings; }
|
||
void setBrushSettings(const BrushSettings &settings);
|
||
BrushToolMode brushMode() const { return m_brushMode; }
|
||
void setBrushMode(BrushToolMode mode);
|
||
BlurToolMode blurMode() const { return m_blurMode; }
|
||
void setBlurMode(BlurToolMode mode);
|
||
// Smudge or Liquify under way; the canvas shows its copy.
|
||
const WarpStroke *warpStroke() const { return m_warpStroke.get(); }
|
||
SpotHealingMode spotHealingMode() const { return m_spotHealingMode; }
|
||
void setSpotHealingMode(SpotHealingMode mode);
|
||
bool maskPaintWhite() const { return m_maskPaintWhite; }
|
||
void setMaskPaintWhite(bool white);
|
||
const PaletteColor &backgroundColor() const { return m_backgroundColor; }
|
||
void setBackgroundColor(const PaletteColor &color);
|
||
// The open colour picker; the session notifies its changes.
|
||
const std::optional<ColorPickerState> &colorPicker() const { return m_colorPicker; }
|
||
const GradientSettings &gradientSettings() const { return m_gradientSettings; }
|
||
void setGradientSettings(const GradientSettings &settings);
|
||
// A gradient drawn and not yet applied.
|
||
const std::optional<GradientEdit> &gradientEdit() const { return m_gradientEdit; }
|
||
// Clone Stamp's Alt-clicked source, in document pixels, and options.
|
||
const std::optional<QPointF> &cloneSource() const { return m_cloneSource; }
|
||
const CloneSettings &cloneSettings() const { return m_cloneSettings; }
|
||
void setCloneSettings(const CloneSettings &settings);
|
||
// Counts every change to a stroke, so the canvas redraws.
|
||
int brushRevision() const { return m_brushRevision; }
|
||
// Selected pixels on the move, from a Ctrl-drag or Ctrl-arrow.
|
||
const PixelMove *pixelMove() const { return m_pixelMove.get(); }
|
||
// The one filter open; its sheet shows while it lasts.
|
||
const std::optional<FilterEdit> &filterEdit() const { return m_filterEdit; }
|
||
// The last committed filter's settings, where the next one starts.
|
||
const FilterSettings &filterSettings() const { return m_filterSettings; }
|
||
const std::optional<LevelsEdit> &levels() const { return m_levels; }
|
||
const std::optional<HueSaturationEdit> &hueSaturation() const { return m_hueSaturation; }
|
||
// The newest preview, waiting for the running one.
|
||
const std::optional<HueSaturationJob> &hueSaturationPending() const { return m_hueSaturationPending; }
|
||
std::optional<HueSampleMode> hueSampleMode() const { return m_hueSampleMode; }
|
||
bool hueTargeting() const { return m_hueTargeting; }
|
||
// The adjustment layer the colour editors write to.
|
||
std::optional<QUuid> adjustmentEditingID() const { return m_adjustmentEditingID; }
|
||
void setAdjustmentEditingID(std::optional<QUuid> id);
|
||
// Its settings as its editor opened, for Cancel.
|
||
const std::optional<LayerAdjustment> &adjustmentOriginal() const { return m_adjustmentOriginal; }
|
||
// The effect whose panel is open, bound to its layer.
|
||
const std::optional<LayerEffectSelection> &effectsEditing() const { return m_effectsEditing; }
|
||
void setEffectsEditing(std::optional<LayerEffectSelection> selection);
|
||
// Its layer's effects as the panel opened, for Cancel.
|
||
const std::optional<LayerEffects> &effectsEditingOriginal() const { return m_effectsEditingOriginal; }
|
||
void setEffectsEditingOriginal(std::optional<LayerEffects> original);
|
||
// The effect chosen in the list; see selectedEffect.
|
||
const std::optional<LayerEffectSelection> &effectSelection() const { return m_effectSelection; }
|
||
bool isModified() const { return history.isModified(); }
|
||
bool canUseHistory() const;
|
||
// Undo's first press discards a pending gradient.
|
||
bool canUndo() const { return canUseHistory() && (history.canUndo() || m_gradientEdit); }
|
||
bool canRedo() const { return canUseHistory() && history.canRedo(); }
|
||
void undo();
|
||
void redo();
|
||
// A transaction that nests; a whole gesture is one entry.
|
||
void beginEdit(const QString &name);
|
||
void endEdit();
|
||
bool canEditLayers() const;
|
||
void addBlankLayer();
|
||
void deleteLayer(QUuid id);
|
||
void deleteActiveLayer();
|
||
// Every selected layer, folders with their contents: one step.
|
||
void deleteSelectedLayers();
|
||
void renameLayer(QUuid id, const QString &name);
|
||
void toggleLayerVisibility(QUuid id);
|
||
// Pressing an eye, then dragging over others: one undo step.
|
||
std::optional<bool> beginVisibilitySwipe(QUuid id);
|
||
void setVisibilityInSwipe(QUuid id, bool visible);
|
||
void endVisibilitySwipe();
|
||
// The list runs top down; the document stores bottom up.
|
||
void reorderLayers(const std::set<int> &offsets, int destination);
|
||
bool canMoveActiveLayer(int offset) const;
|
||
void moveActiveLayer(int offset);
|
||
|
||
void insert(const ImportedImage &asset, std::optional<QPointF> centeredAt = std::nullopt);
|
||
// White or black fills a Background layer; none stays clear.
|
||
void createDocument(int width, int height, bool emptyLayer = false, double resolution = 72, std::optional<QColor> background = std::nullopt);
|
||
void fit();
|
||
void zoom(double value, std::optional<QPointF> anchor = std::nullopt);
|
||
// Swift's stepped keyboard zoom about the view's centre.
|
||
void zoomKeyboard(int step);
|
||
// The View menu's grid, shown from 800%.
|
||
bool showsPixelGrid() const { return m_showsPixelGrid; }
|
||
void setShowsPixelGrid(bool shows);
|
||
// Swift's alias of View › Snap: moves, crops, drawing.
|
||
bool snappingEnabled() const { return m_snapEnabled; }
|
||
// The Eyedropper's ring: the sampled colour over the original.
|
||
bool showsSampleRing() const { return m_showsSampleRing; }
|
||
void setShowsSampleRing(bool shows);
|
||
// The Crop tool's frame in document pixels, once drawn.
|
||
const std::optional<QRectF> &cropRect() const { return m_cropRect; }
|
||
void setCropRect(std::optional<QRectF> rect);
|
||
// Swift's ratio names: Free, Original, 1:1, 4:3 and 16:9.
|
||
const QString &cropRatioChoice() const { return m_cropRatioChoice; }
|
||
void setCropRatioChoice(const QString &choice);
|
||
const std::optional<QString> &cropError() const { return m_cropError; }
|
||
void setCropError(std::optional<QString> error);
|
||
// Counted requests; the canvas takes focus on each new one.
|
||
int canvasFocusRequest() const { return m_canvasFocusRequest; }
|
||
void requestCanvasFocus();
|
||
|
||
// What went wrong in a tool; the window shows it.
|
||
const std::optional<QString> &brushError() const { return m_brushError; }
|
||
void setBrushError(std::optional<QString> error);
|
||
|
||
void notify() { emit changed(); }
|
||
// Swift's extensions, each declared in its twin's header.
|
||
#include "Document/EditorSession+Projects.h"
|
||
#include "Document/EditorSession+Imports.h"
|
||
#include "IO/ImageResizer+Session.h"
|
||
#include "Document/LayerMask+Session.h"
|
||
#include "Document/LayerAppearance+Session.h"
|
||
#include "Document/Crop+Session.h"
|
||
#include "Document/Distort+Session.h"
|
||
#include "Document/LayerMerge+Session.h"
|
||
#include "Document/LayerFlip+Session.h"
|
||
#include "Document/CanvasRotation+Session.h"
|
||
#include "Document/Selection+Session.h"
|
||
#include "Document/MagicWand+Session.h"
|
||
#include "Document/SubjectRemoval+Session.h"
|
||
#include "Document/EditorSession+Brush.h"
|
||
#include "Document/CloneStamp+Session.h"
|
||
#include "Document/ColorPalette+Session.h"
|
||
#include "Document/Gradient+Session.h"
|
||
#include "Document/ShapeTool+Session.h"
|
||
#include "Document/TypeTool+Session.h"
|
||
#include "Document/SmudgeLiquify+Session.h"
|
||
#include "Document/BlurTool+Session.h"
|
||
#include "Document/SelectionEdits+Session.h"
|
||
#include "Document/SelectionClipboard+Session.h"
|
||
#include "Document/FloatingSelection+Session.h"
|
||
#include "Document/Filters+Session.h"
|
||
#include "Document/Levels+Session.h"
|
||
#include "Document/LevelsAutomatic+Session.h"
|
||
#include "Document/HueSaturation+Session.h"
|
||
#include "Document/MaskTracing+Session.h"
|
||
#include "Document/LayerGroups+Session.h"
|
||
#include "Document/LiveLayerMask+Session.h"
|
||
#include "Document/LayerAdjustment+Session.h"
|
||
#include "Document/AdjustmentEditing+Session.h"
|
||
#include "Document/LayerEffects+Session.h"
|
||
#include "Document/CameraRaw+Session.h"
|
||
#include "Document/Guides+Session.h"
|
||
#include "Document/ObjectSelection+Session.h"
|
||
#include "Document/ColorRangeSelection+Session.h"
|
||
signals:
|
||
void changed();
|
||
|
||
private:
|
||
// Copies layers into this document in place, as Swift does.
|
||
friend class ProjectWorkspace;
|
||
void restore(const DocumentHistory::Snapshot &snapshot);
|
||
void resumeFileRequests();
|
||
void updateBusyIndicator();
|
||
void endDuplicateTransform();
|
||
static ImageLayer firstLayer(QSizeF size, const std::optional<QColor> &background);
|
||
// Clone Stamp is family 1, the Smear 2, others 0.
|
||
static int tipFamily(NavigationTool tool);
|
||
|
||
std::optional<CanvasDocument> m_document;
|
||
NavigationTool m_tool = NavigationTool::move;
|
||
QSet<QUuid> m_collapsedGroupIDs;
|
||
QSet<QUuid> m_selectedLayerIDs;
|
||
// The canvas reads previews from a const session: mutable caches.
|
||
mutable std::map<QUuid, DistortPreviewCache> m_distortPreviewCache;
|
||
mutable std::map<QUuid, DistortEffectsCache> m_distortEffectsCache;
|
||
mutable std::optional<MaskDistortPreviewCache> m_maskDistortPreviewCache;
|
||
std::optional<TransformEdit> m_transformEdit;
|
||
std::optional<TransformDuplicate> m_transformDuplicate;
|
||
bool m_transformAutoSelect = ToolDefaults::boolean(QStringLiteral("autoSelect"), false);
|
||
bool m_showsTransformControls = ToolDefaults::boolean(QStringLiteral("transformControls"), true);
|
||
bool m_locksTransformRatio = true;
|
||
std::optional<BlendPreview> m_blendPreview;
|
||
std::optional<QUuid> m_opacityEditLayerID;
|
||
bool m_isMaskSelected = false;
|
||
bool m_viewsMaskAlone = false;
|
||
std::optional<QUuid> m_activeLayerID;
|
||
bool m_isProjectBusy = false;
|
||
bool m_showsNewDocument = false;
|
||
bool m_showsImporter = false;
|
||
bool m_isImporting = false;
|
||
std::optional<QString> m_importError;
|
||
std::optional<QUuid> m_renamingLayerID;
|
||
std::optional<QString> m_projectPath;
|
||
bool m_showsPixelGrid = ToolDefaults::boolean(QStringLiteral("pixelGrid"), true);
|
||
// The layout grid starts off; guides show; rulers hide.
|
||
bool m_showsGrid = ToolDefaults::boolean(QStringLiteral("grid"), false);
|
||
LayoutGrid m_layoutGrid = LayoutGrid::stored();
|
||
GridAppearance m_gridAppearance = GridAppearance::stored();
|
||
bool m_showsGuides = ToolDefaults::boolean(QStringLiteral("guides"), true);
|
||
bool m_showsRulers = ToolDefaults::boolean(QStringLiteral("rulers"), false);
|
||
bool m_snapEnabled = ToolDefaults::boolean(QStringLiteral("snap"), true);
|
||
bool m_snapToGuides = ToolDefaults::boolean(QStringLiteral("snapGuides"), true);
|
||
bool m_snapToGrid = ToolDefaults::boolean(QStringLiteral("snapGrid"), false);
|
||
bool m_snapToLayers = ToolDefaults::boolean(QStringLiteral("snapLayers"), true);
|
||
bool m_snapToDocumentBounds = ToolDefaults::boolean(QStringLiteral("snapBounds"), true);
|
||
bool m_locksGuides = ToolDefaults::boolean(QStringLiteral("lockGuides"), false);
|
||
std::optional<GuideDrag> m_guideDrag;
|
||
bool m_showsSampleRing = true;
|
||
std::optional<QRectF> m_cropRect;
|
||
QString m_cropRatioChoice = QStringLiteral("Free");
|
||
std::optional<QString> m_cropError;
|
||
QFutureWatcher<Cropped> m_cropCommit;
|
||
std::function<void()> m_committingCrop;
|
||
int m_canvasFocusRequest = 0;
|
||
bool m_showsBusy = false;
|
||
QTimer m_busyTimer;
|
||
std::vector<std::function<void()>> m_projectWaiters;
|
||
std::vector<std::function<void()>> m_fileRequestWaiters;
|
||
std::deque<ImportRequest> m_pendingImports;
|
||
// Where the request now decoding stands.
|
||
qsizetype m_importIndex = 0;
|
||
std::optional<QPointF> m_importPoint;
|
||
QStringList m_importFailures;
|
||
QFutureWatcher<Decoded> m_decoder;
|
||
QFutureWatcher<PhotoshopRead> m_photoshopReader;
|
||
bool m_showsConversionSheet = false;
|
||
std::optional<PSDConversionRequest> m_conversionRequest;
|
||
std::function<void(bool)> m_conversionAnswer;
|
||
std::optional<RawDevelopRequest> m_rawDevelop;
|
||
std::function<void(std::optional<RawDevelopSettings>)> m_rawAnswer;
|
||
bool m_rawImporting = false;
|
||
// Cancel pressed while the file was still read.
|
||
bool m_conversionCancelled = false;
|
||
std::optional<QString> m_brushError;
|
||
// The layers a bake under way will delete.
|
||
std::vector<QUuid> m_bakingIDs;
|
||
QFutureWatcher<Baked> m_baker;
|
||
std::optional<Inverting> m_inverting;
|
||
QFutureWatcher<Inverted> m_inverter;
|
||
WandSettings m_wandSettings;
|
||
WandMode m_wandMode = WandMode::wand;
|
||
ObjectSelectionSettings m_objectSelectionSettings;
|
||
std::optional<Wanding> m_wanding;
|
||
QFutureWatcher<Wanded> m_wand;
|
||
std::optional<Subjecting> m_subjecting;
|
||
QFutureWatcher<Subjected> m_subject;
|
||
std::unique_ptr<BrushStroke> m_brushStroke;
|
||
std::unique_ptr<PixelMove> m_pixelMove;
|
||
BrushSettings m_brushSettings;
|
||
BrushToolMode m_brushMode = BrushToolMode::paint;
|
||
BlurToolMode m_blurMode = BlurToolMode::liquify;
|
||
std::unique_ptr<WarpStroke> m_warpStroke;
|
||
SpotHealingMode m_spotHealingMode = SpotHealingMode::contentAware;
|
||
bool m_maskPaintWhite = false;
|
||
PaletteColor m_backgroundColor = PaletteColor::white();
|
||
std::optional<ColorPickerState> m_colorPicker;
|
||
GradientSettings m_gradientSettings;
|
||
std::optional<GradientEdit> m_gradientEdit;
|
||
ShapeKind m_shapeKind = ShapeKind::rectangle;
|
||
double m_shapeCornerRadius = 0;
|
||
double m_shapeLineWidth = 4;
|
||
std::optional<ShapeDraft> m_shapeDraft;
|
||
mutable std::map<QUuid, ShapePreview> m_shapeTransformPreviewCache;
|
||
std::optional<TextDraft> m_textDraft;
|
||
LayerTextStyle m_textDefaults;
|
||
// The text's style before the font menu previewed faces.
|
||
std::optional<LayerTextStyle> m_fontPreviewOriginal;
|
||
std::optional<QPointF> m_cloneSource;
|
||
CloneSettings m_cloneSettings;
|
||
// The offset aligned strokes keep, fixed as a stroke begins.
|
||
std::optional<QSizeF> m_cloneOffset;
|
||
// Clone Stamp and the Smear keep their own soft tips.
|
||
std::map<int, ParkedTip> m_parkedBrushTips{{1, {40, 0, 1}}, {2, {40, 0, 1}}};
|
||
std::optional<LastBrushPoint> m_lastBrushPoint;
|
||
// Smoothing's brush, and the pointer it trails.
|
||
std::optional<QPointF> m_brushAnchor;
|
||
std::optional<QPointF> m_brushPointer;
|
||
int m_brushRevision = 0;
|
||
std::optional<PendingOpacityDigit> m_pendingOpacityDigit;
|
||
std::optional<CommittingRaster> m_committingRaster;
|
||
QFutureWatcher<RasterMade> m_rasterCommit;
|
||
std::optional<FilterEdit> m_filterEdit;
|
||
FilterSettings m_filterSettings;
|
||
QFutureWatcher<Filtered> m_filterPreview;
|
||
// Out until its finish runs: setFuture drops a pending signal.
|
||
bool m_filterRendering = false;
|
||
// Which edit's preview is being made; a cancelled edit's drops.
|
||
QUuid m_filterPreviewFor;
|
||
std::vector<Committing> m_filterCommitWaiting;
|
||
std::optional<Committing> m_committingFilter;
|
||
QFutureWatcher<FilterMade> m_filterCommit;
|
||
std::optional<LevelsEdit> m_levels;
|
||
// Which edit a running preview serves; others drop.
|
||
QUuid m_levelsPreviewFor;
|
||
QFutureWatcher<std::optional<QImage>> m_levelsPreview;
|
||
bool m_levelsRendering = false;
|
||
QFutureWatcher<std::optional<LevelsHistogram>> m_levelsHistogram;
|
||
std::optional<Committing> m_committingLevels;
|
||
QFutureWatcher<Leveled> m_levelsCommit;
|
||
std::optional<HueSaturationEdit> m_hueSaturation;
|
||
std::optional<HueSaturationJob> m_hueSaturationPending;
|
||
// Which edit a running preview serves; others drop.
|
||
QUuid m_hueSaturationPreviewFor;
|
||
QFutureWatcher<Adjusted> m_hueSaturationTask;
|
||
bool m_hueSaturationRendering = false;
|
||
std::optional<CommittingHue> m_committingHueSaturation;
|
||
QFutureWatcher<Adjusted> m_hueSaturationCommit;
|
||
std::optional<HueSampleMode> m_hueSampleMode;
|
||
bool m_hueTargeting = false;
|
||
std::optional<HueTargetDrag> m_hueTargetDrag;
|
||
std::optional<QUuid> m_adjustmentEditingID;
|
||
std::optional<LayerAdjustment> m_adjustmentOriginal;
|
||
std::optional<LayerEffectSelection> m_effectsEditing;
|
||
std::optional<LayerEffects> m_effectsEditingOriginal;
|
||
std::optional<LayerEffectSelection> m_effectSelection;
|
||
std::optional<PixelClipboard> m_pixelClipboard;
|
||
std::optional<CopiedLayer> m_copiedLayer;
|
||
std::optional<LassoDraft> m_lassoDraft;
|
||
LassoKind m_lassoKind = LassoKind::freehand;
|
||
LassoKind m_marqueeKind = LassoKind::rectangle;
|
||
SelectionMode m_selectionModeChoice = SelectionMode::replace;
|
||
std::optional<SelectionMode> m_heldSelectionMode;
|
||
// The selection as a drag began; one step per drag.
|
||
std::optional<DocumentSelection> m_selectionMoveOrigin;
|
||
bool m_selectionAntialiased = true;
|
||
int m_selectionExpandAmount = 1;
|
||
int m_selectionContractAmount = 1;
|
||
int m_selectionFeatherAmount = 2;
|
||
std::optional<SelectionAmountOperation> m_selectionAmountOperation;
|
||
std::optional<ColorRangeEdit> m_colorRange;
|
||
};
|