import { commandIds } from "@commands/ids"; import type { GenerationCandidate, GenerationCompareMode, GenerationState } from "@editor/state"; import type { GenerateSettings } from "@editor/tools"; import type { AppStore } from "@editor/store"; import type { GenerationWorkflow } from "@operations/generation/workflow"; import { currentGenerationJob, GenerationJobStatus } from "../GenerationJobStatus"; export type GenerateActionControlsProps = { settings: GenerateSettings; generation: GenerationState; dispatch: AppStore["dispatch"]; workflow: GenerationWorkflow; generate: () => Promise; }; export function GenerateActionControls({ settings, generation, dispatch, workflow, generate }: GenerateActionControlsProps) { const job = currentGenerationJob(generation); const busy = job?.status === "running"; const candidate = selectedCandidate(generation); const precondition = workflow.precondition(); const canGenerate = precondition.ready && !busy; const preconditionMessage = precondition.ready ? undefined : precondition.message; const repair = precondition.ready ? undefined : precondition.repair; return (
{preconditionMessage ? ( {preconditionMessage} {repair === "add-mask" ? ( ) : repair === "set-outpaint-padding" ? ( ) : null} ) : null} {busy ? : null} {candidate ? ( <> ) : null}
); } function CandidatePicker({ generation, dispatch }: { generation: GenerationState; dispatch: AppStore["dispatch"] }) { return (
{generation.candidates.map((candidate) => { const selected = candidate.id === (generation.selectedCandidateId ?? generation.candidates[0]?.id); return ( ); })}
); } function CandidateControls({ candidate, compareMode, settings, busy, dispatch, workflow, }: { candidate: GenerationCandidate; compareMode: GenerationCompareMode; settings: GenerateSettings; busy: boolean; dispatch: AppStore["dispatch"]; workflow: GenerationWorkflow; }) { const rerun = (label: string, nextSettings: GenerateSettings) => { void workflow.regenerate(candidate.id, nextSettings, label); }; const disabled = busy; return (
Provisional resultSeed {candidate.seed} rerun("Regenerate", candidate.settings)} /> rerun("Lower", { ...candidate.settings, strength: Math.max(0, candidate.settings.strength - 10), seed: candidate.seed })} /> rerun("Reuse seed", { ...candidate.settings, seed: candidate.seed })} /> rerun("New seed", { ...candidate.settings, seed: -1 })} /> dispatch(commandIds.generationReuseCandidateSettings, { candidateId: candidate.id })} /> workflow.applyCandidateAsLayer(candidate.id)} /> { void workflow.applyCandidateAsRefinementLayer(candidate.id); }} /> { void workflow.replaceCandidatePixels(candidate.id); }} /> { if (!candidate.inpaint) return; dispatch(commandIds.selectionSet, { artboardId: candidate.placement.artboardId, layerIds: [candidate.inpaint.targetLayerId] }); dispatch(commandIds.toolEnterMaskEdit, { targetLayerId: candidate.inpaint.targetLayerId, maskLayerId: candidate.inpaint.maskLayerId }); }} /> dispatch(commandIds.generationRemoveCandidate, { candidateId: candidate.id })} /> {settings.seed !== candidate.seed ? null : Current settings use this candidate's resolved seed}
); } function CandidateCompareControls({ compareMode, disabled, dispatch }: { compareMode: GenerationCompareMode; disabled: boolean; dispatch: AppStore["dispatch"] }) { return ( {generationCompareOptions.map((option) => { const active = compareMode === option.mode; return ( ); })} ); } const generationCompareOptions: Array<{ mode: GenerationCompareMode; label: string; title: string }> = [ { mode: "result", label: "After", title: "Show the generated result over the document" }, { mode: "before", label: "Before", title: "Hide the generated result and show the source document" }, { mode: "split", label: "Split", title: "Compare source on the left with result on the right" }, ]; function CandidatePreview({ candidate }: { candidate: GenerationCandidate }) { if (!candidate.inputImage) { return ; } return ( {candidate.maskImage ? : null} ); } function CandidateButton({ label, title, disabled, busy, onClick }: { label: string; title: string; disabled?: boolean; busy?: boolean; onClick: () => void }) { return ( ); } function selectedCandidate(generation: GenerationState): GenerationCandidate | undefined { return generation.candidates.find((candidate) => candidate.id === generation.selectedCandidateId) ?? generation.candidates[0]; }