feat: add feather brush tool with adjustable settings and blending functionality
- Implemented feather brush tool in the brushRaster module, allowing for feathered edges in brush strokes. - Added new FeatherControls component for UI adjustments of feather settings including size, radius, strength, and smoothing. - Updated brush preview logic to accommodate feather tool alongside existing brush and eraser tools. - Enhanced layer rendering to support feather mask previews and interactions. - Introduced blending logic for feathered strokes to mix blurred mask values with original pixels. - Added unit tests for feather blending functionality and tool keybindings. - Updated cursor handling to reflect feather tool usage.
This commit is contained in:
@@ -2,8 +2,9 @@ import { useMemo } from "react";
|
||||
import type { AppStore } from "@editor/store";
|
||||
import type { ImageDocument } from "@core/document";
|
||||
import type { GenerationState, MaskViewMode, SelectionState, ViewportState } from "@editor/state";
|
||||
import type { BrushSettings, ChromaKeySettings, GenerateSettings, MagicWandSettings, OperationId, ToolId } from "@editor/tools";
|
||||
import type { BrushSettings, ChromaKeySettings, FeatherSettings, GenerateSettings, MagicWandSettings, OperationId, ToolId } from "@editor/tools";
|
||||
import { BrushControls } from "./bottom-controls/BrushControls";
|
||||
import { FeatherControls } from "./bottom-controls/FeatherControls";
|
||||
import { ChromaKeyControls } from "./bottom-controls/ChromaKeyControls";
|
||||
import { MagicWandControls } from "./bottom-controls/MagicWandControls";
|
||||
import { GenerateActionControls } from "./bottom-controls/GenerateActionControls";
|
||||
@@ -26,6 +27,7 @@ export type BottomControlsIslandProps = {
|
||||
activeTool: ToolId;
|
||||
operation?: OperationId;
|
||||
brushSettings: BrushSettings;
|
||||
featherSettings: FeatherSettings;
|
||||
generateSettings: GenerateSettings;
|
||||
generation: GenerationState;
|
||||
chromaKeySettings: ChromaKeySettings;
|
||||
@@ -41,7 +43,7 @@ export type BottomControlsIslandProps = {
|
||||
documentActions: DocumentActions;
|
||||
};
|
||||
|
||||
export function BottomControlsIsland({ document, selection, viewport, visible, action, activeTool, operation, brushSettings, generateSettings, generation, chromaKeySettings, magicWandSettings, editingMask = false, maskKind, maskViewMode = "composite", transformBounds, transformTarget, brushHint, dispatch, generationWorkflow, documentActions }: BottomControlsIslandProps) {
|
||||
export function BottomControlsIsland({ document, selection, viewport, visible, action, activeTool, operation, brushSettings, featherSettings, generateSettings, generation, chromaKeySettings, magicWandSettings, editingMask = false, maskKind, maskViewMode = "composite", transformBounds, transformTarget, brushHint, dispatch, generationWorkflow, documentActions }: BottomControlsIslandProps) {
|
||||
const documentIndex = useMemo(() => createDocumentReadIndex(document), [document]);
|
||||
const selectedLayerInfo = selection.layerIds.length === 1 && selection.layerIds[0] ? documentIndex.layerInfoById.get(selection.layerIds[0]) : undefined;
|
||||
const zoomPercent = Math.round(viewport.zoom * 100);
|
||||
@@ -59,10 +61,12 @@ export function BottomControlsIsland({ document, selection, viewport, visible, a
|
||||
<GenerateActionControls settings={generateSettings} generation={generation} dispatch={dispatch} workflow={generationWorkflow} generate={documentActions.generate} />
|
||||
) : operation === "chromaKey" ? (
|
||||
<ChromaKeyControls document={document} selection={selection} settings={chromaKeySettings} dispatch={dispatch} />
|
||||
) : (activeTool === "brush" || activeTool === "eraser") && brushHint ? (
|
||||
) : (activeTool === "brush" || activeTool === "eraser" || activeTool === "feather") && brushHint ? (
|
||||
<BrushHint tool={activeTool} hint={brushHint} />
|
||||
) : activeTool === "brush" || activeTool === "eraser" ? (
|
||||
<BrushControls tool={activeTool} settings={brushSettings} editingMask={editingMask} maskKind={maskKind} maskViewMode={maskViewMode} dispatch={dispatch} />
|
||||
) : activeTool === "feather" ? (
|
||||
<FeatherControls settings={featherSettings} editingMask={editingMask} dispatch={dispatch} />
|
||||
) : activeTool === "magicWand" ? (
|
||||
<MagicWandControls settings={magicWandSettings} dispatch={dispatch} />
|
||||
) : activeTool === "semanticSelect" ? (
|
||||
@@ -80,7 +84,7 @@ export function BottomControlsIsland({ document, selection, viewport, visible, a
|
||||
);
|
||||
}
|
||||
|
||||
function BrushHint({ tool, hint }: { tool: "brush" | "eraser"; hint: string }) {
|
||||
function BrushHint({ tool, hint }: { tool: "brush" | "eraser" | "feather"; hint: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-3 px-4 text-center">
|
||||
<span className="rounded bg-white/[0.06] px-2 py-0.5 text-[0.65rem] font-semibold uppercase tracking-[0.12em] text-white/45">{tool}</span>
|
||||
|
||||
Reference in New Issue
Block a user