Skip to content

Commit

Permalink
allow zooming/panning while drawing
Browse files Browse the repository at this point in the history
  • Loading branch information
Moebits committed Sep 23, 2024
1 parent 02026f8 commit 7c063b3
Show file tree
Hide file tree
Showing 24 changed files with 231 additions and 41 deletions.
Binary file modified assets/.DS_Store
Binary file not shown.
Binary file added assets/icons/draw-clear-hover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/draw-clear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/draw-decrease-hover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/draw-decrease.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/draw-increase-hover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/draw-increase.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions components/BinarizeDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ const BinarizeDialog: React.FunctionComponent = (props) => {
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedBinarize = await ipcRenderer.invoke("get-temp", "binarize")
if (savedBinarize) changeState("binarize", Number(savedBinarize))
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -62,6 +67,7 @@ const BinarizeDialog: React.FunctionComponent = (props) => {
return {...prev, binarize: value}
})
ipcRenderer.invoke("apply-binarize", {...state, binarize: value, realTime: true})
ipcRenderer.invoke("save-temp", "binarize", String(value))
break
}
}
Expand Down
9 changes: 9 additions & 0 deletions components/BlurDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ const BlurDialog: React.FunctionComponent = (props) => {
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedBlur= await ipcRenderer.invoke("get-temp", "blur")
const savedSharpen = await ipcRenderer.invoke("get-temp", "sharpen")
if (savedBlur) changeState("blur", Number(savedBlur))
if (savedSharpen) changeState("sharpen", Number(savedSharpen))
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -61,12 +68,14 @@ const BlurDialog: React.FunctionComponent = (props) => {
return {...prev, blur: value}
})
ipcRenderer.invoke("apply-blur", {...state, blur: value, realTime: true})
ipcRenderer.invoke("save-temp", "blur", String(value))
break
case "sharpen":
setState((prev) => {
return {...prev, sharpen: value}
})
ipcRenderer.invoke("apply-blur", {...state, sharpen: value, realTime: true})
ipcRenderer.invoke("save-temp", "sharoen", String(value))
break
}
}
Expand Down
9 changes: 9 additions & 0 deletions components/BrightnessDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ const BrightnessDialog: React.FunctionComponent = (props) => {
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedBrightness = await ipcRenderer.invoke("get-temp", "brightness")
const savedContrast = await ipcRenderer.invoke("get-temp", "contrast")
if (savedBrightness) changeState("brightness", Number(savedBrightness))
if (savedContrast) changeState("contrast", Number(savedContrast))
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -61,12 +68,14 @@ const BrightnessDialog: React.FunctionComponent = (props) => {
return {...prev, brightness: value}
})
ipcRenderer.invoke("apply-brightness", {...state, brightness: value, realTime: true})
ipcRenderer.invoke("save-temp", "brightness", String(value))
break
case "contrast":
setState((prev) => {
return {...prev, contrast: value}
})
ipcRenderer.invoke("apply-brightness", {...state, contrast: value, realTime: true})
ipcRenderer.invoke("save-temp", "contrast", String(value))
break
}
}
Expand Down
5 changes: 5 additions & 0 deletions components/ContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ const ContextMenu: React.FunctionComponent = (props) => {
ipcRenderer.invoke("copy-address", image)
}

const clearCache = () => {
ipcRenderer.invoke("clear-temp")
}


if (visible) {
return (
<section ref={contextMenu} className="context-menu" onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}>
<button className="context-button" onClick={(event) => copy(event)}>Copy</button>
<button className="context-button" onClick={() => paste()}>Paste</button>
<button className="context-button" onClick={(event) => getInfo(event)}>Get Info</button>
<button className="context-button" onClick={() => clearCache()}>Clear Cache</button>
<button className="context-button" onClick={() => saveImage()}>Save Image</button>
<button className="context-button" onClick={(event) => copyAddress(event)}>Copy Address</button>
</section>
Expand Down
15 changes: 15 additions & 0 deletions components/CropDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ const CropDialog: React.FunctionComponent = (props) => {
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedX = await ipcRenderer.invoke("get-temp", "x")
const savedY = await ipcRenderer.invoke("get-temp", "y")
const savedWidth = await ipcRenderer.invoke("get-temp", "width")
const savedHeight = await ipcRenderer.invoke("get-temp", "height")
if (savedX) changeState("x", Number(savedX))
if (savedY) changeState("y", Number(savedY))
if (savedWidth) changeState("width", Number(savedWidth))
if (savedHeight) changeState("height", Number(savedHeight))
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -62,24 +73,28 @@ const CropDialog: React.FunctionComponent = (props) => {
return {...prev, x: value}
})
ipcRenderer.invoke("apply-crop", {...state, x: value, realTime: true})
ipcRenderer.invoke("save-temp", "x", String(value))
break
case "y":
setState((prev) => {
return {...prev, y: value}
})
ipcRenderer.invoke("apply-crop", {...state, y: value, realTime: true})
ipcRenderer.invoke("save-temp", "y", String(value))
break
case "width":
setState((prev) => {
return {...prev, width: value}
})
ipcRenderer.invoke("apply-crop", {...state, width: value, realTime: true})
ipcRenderer.invoke("save-temp", "width", String(value))
break
case "height":
setState((prev) => {
return {...prev, height: value}
})
ipcRenderer.invoke("apply-crop", {...state, height: value, realTime: true})
ipcRenderer.invoke("save-temp", "height", String(value))
break
}
}
Expand Down
15 changes: 15 additions & 0 deletions components/GIFDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ const GIFDialog: React.FunctionComponent = (props) => {
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedSpeed = await ipcRenderer.invoke("get-temp", "speed")
const savedReverse = await ipcRenderer.invoke("get-temp", "reverse")
const savedTransparency = await ipcRenderer.invoke("get-temp", "transparency")
const savedTransparentColor = await ipcRenderer.invoke("get-temp", "transparentColor")
if (savedSpeed) changeState("speed", Number(savedSpeed))
if (savedReverse) changeState("reverse", savedReverse === "true")
if (savedTransparency) changeState("transparency", savedTransparency === "true")
if (savedTransparentColor) changeState("transparentColor", savedTransparentColor)
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -74,21 +85,25 @@ const GIFDialog: React.FunctionComponent = (props) => {
setState((prev) => {
return {...prev, speed: value}
})
ipcRenderer.invoke("save-temp", "speed", String(value))
break
case "reverse":
setState((prev) => {
return {...prev, reverse: value}
})
ipcRenderer.invoke("save-temp", "reverse", String(value))
break
case "transparency":
setState((prev) => {
return {...prev, transparency: value}
})
ipcRenderer.invoke("save-temp", "transparency", String(value))
break
case "transparentColor":
setState((prev) => {
return {...prev, transparentColor: value}
})
ipcRenderer.invoke("save-temp", "transparentColor", String(value))
break
}
}
Expand Down
13 changes: 13 additions & 0 deletions components/HSLDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,23 @@ const HSLDialog: React.FunctionComponent = (props) => {
const [state, setState] = useState(initialState)
const [hover, setHover] = useState(false)


useEffect(() => {
const initTheme = async () => {
const theme = await ipcRenderer.invoke("get-theme")
const transparency = await ipcRenderer.invoke("get-transparency")
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedHue = await ipcRenderer.invoke("get-temp", "hue")
const savedSaturation = await ipcRenderer.invoke("get-temp", "saturation")
const savedLightness = await ipcRenderer.invoke("get-temp", "lightness")
if (savedHue) changeState("hue", Number(savedHue))
if (savedSaturation) changeState("saturation", Number(savedSaturation))
if (savedLightness) changeState("lightness", Number(savedLightness))
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -62,18 +72,21 @@ const HSLDialog: React.FunctionComponent = (props) => {
return {...prev, hue: value}
})
ipcRenderer.invoke("apply-hsl", {...state, hue: value, realTime: true})
ipcRenderer.invoke("save-temp", "hue", String(value))
break
case "saturation":
setState((prev) => {
return {...prev, saturation: value}
})
ipcRenderer.invoke("apply-hsl", {...state, saturation: value, realTime: true})
ipcRenderer.invoke("save-temp", "saturation", String(value))
break
case "lightness":
setState((prev) => {
return {...prev, lightness: value}
})
ipcRenderer.invoke("apply-hsl", {...state, lightness: value, realTime: true})
ipcRenderer.invoke("save-temp", "lightness", String(value))
break
}
}
Expand Down
31 changes: 24 additions & 7 deletions components/PhotoViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ const PhotoViewer: React.FunctionComponent = (props) => {
ipcRenderer.on("bulk-process", bulkProcess)
ipcRenderer.on("draw", draw)
ipcRenderer.on("draw-undo", undoDraw)
ipcRenderer.on("draw-invert", invertDraw)
ipcRenderer.on("draw-clear", clearDraw)
ipcRenderer.on("draw-increase-size", increaseBrushSize)
ipcRenderer.on("draw-decrease-size", decreaseBrushSize)
document.addEventListener("dblclick", doubleClick)
return () => {
ipcRenderer.removeListener("open-file", openFile)
Expand All @@ -185,12 +187,21 @@ const PhotoViewer: React.FunctionComponent = (props) => {
ipcRenderer.removeListener("bulk-process", bulkProcess)
ipcRenderer.removeListener("draw", draw)
ipcRenderer.removeListener("draw-undo", undoDraw)
ipcRenderer.removeListener("draw-invert", invertDraw)
ipcRenderer.removeListener("draw-clear", clearDraw)
ipcRenderer.removeListener("draw-increase-size", increaseBrushSize)
ipcRenderer.removeListener("draw-decrease-size", decreaseBrushSize)
document.removeEventListener("dblclick", doubleClick)
ipcRenderer.removeListener("apply-crop", bulkCrop)
}
}, [])

useEffect(() => {
ipcRenderer.on("draw-invert", invertDraw)
return () => {
ipcRenderer.removeListener("draw-invert", invertDraw)
}
}, [brushColor])

useEffect(() => {
const triggerUndo = () => {
if (drawing) return undoDraw()
Expand Down Expand Up @@ -323,6 +334,7 @@ const PhotoViewer: React.FunctionComponent = (props) => {
document.documentElement.style.setProperty("cursor", "grab", "important")
}
if (event.key === "r") {
if (drawing) return
if (rotateEnabled) {
const selection = document.querySelector(".ReactCrop__crop-selection") as HTMLDivElement
if (selection?.style.opacity === "1") {
Expand Down Expand Up @@ -389,6 +401,7 @@ const PhotoViewer: React.FunctionComponent = (props) => {
setRotateEnabled(false)
}
const wheel = (event: WheelEvent) => {
/*
// @ts-ignore
const trackPad = event.wheelDeltaY ? event.wheelDeltaY === -3 * event.deltaY : event.deltaMode === 0
if (event.deltaY < 0) {
Expand All @@ -403,7 +416,7 @@ const PhotoViewer: React.FunctionComponent = (props) => {
} else {
increaseBrushSize()
}
}
}*/
}
ipcRenderer.on("accept-action-response", acceptActionResponse)
document.addEventListener("wheel", wheel)
Expand Down Expand Up @@ -682,6 +695,10 @@ const PhotoViewer: React.FunctionComponent = (props) => {
}
}

const clearDraw = () => {
drawRef.current.clear()
}

const undoDraw = () => {
drawRef.current.undo()
}
Expand Down Expand Up @@ -755,16 +772,16 @@ const PhotoViewer: React.FunctionComponent = (props) => {
<img className="adjustment-img" src={saveHover ? saveButtonHover : saveButton} onClick={() => save()} width={30} height={30} onMouseEnter={() => setSaveHover(true)} onMouseLeave={() => setSaveHover(false)}/>
<img className="adjustment-img" src={resetHover ? resetButtonHover : resetButton} onClick={() => reset()} width={30} height={30} onMouseEnter={() => setResetHover(true)} onMouseLeave={() => setResetHover(false)}/>
</div>
<TransformWrapper ref={zoomRef} minScale={0.5} limitToBounds={false} minPositionX={-200} maxPositionX={200} minPositionY={-200} maxPositionY={200}
onZoomStop={(ref) => setZoomScale(ref.state.scale)} disabled={drawing} wheel={{step: 0.1}} pinch={{disabled: true}} zoomAnimation={{size: 0}}
<TransformWrapper ref={zoomRef} minScale={0.5} limitToBounds={false} minPositionX={-200} maxPositionX={200} minPositionY={-200} maxPositionY={200} onZoom={(ref) => setZoomScale(ref.state.scale)}
onZoomStop={(ref) => setZoomScale(ref.state.scale)} panning={{allowLeftClickPan: !drawing, allowRightClickPan: false}} wheel={{step: 0.1}} pinch={{disabled: true}} zoomAnimation={{size: 0}}
alignmentAnimation={{disabled: true}} doubleClick={{mode: "reset", animationTime: 0}}>
<TransformComponent>
<div className="rotate-photo-container" style={{transform: `rotate(${rotateDegrees}deg)`}}>
{bulk ? <BulkContainer files={bulkFiles}/> :
<div className="photo-container">
{drawing ? <CanvasDraw ref={drawRef} className="draw-img" lazyRadius={0} brushRadius={brushSize} brushColor={brushColor}
catenaryColor="rgba(21, 133, 252, 0)" hideGrid={true} canvasWidth={width} canvasHeight={height} imgSrc={image} erase={erasing}
loadTimeOffset={0} eraseColor="#000000"/> :
catenaryColor="rgba(0, 0, 0, 0)" hideGrid={true} canvasWidth={width} canvasHeight={height} imgSrc={image} erase={erasing}
loadTimeOffset={0} eraseColor="#000000" zoom={zoomScale} style={{transform: `rotate(${-rotateDegrees}deg)`}}/> :
<ReactCrop className="photo" src={image} zoom={zoomScale} spin={rotateDegrees} crop={cropState as any}
onChange={(crop: any, percentCrop: any) => setCropState(percentCrop as any)} disabled={!cropEnabled} keepSelection={true}/>}
</div>}
Expand Down
6 changes: 6 additions & 0 deletions components/PixelateDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const PixelateDialog: React.FunctionComponent = (props) => {
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedPixelate = await ipcRenderer.invoke("get-temp", "pixelate")
if (savedPixelate) changeState("strength", Number(savedPixelate))
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -60,6 +65,7 @@ const PixelateDialog: React.FunctionComponent = (props) => {
return {...prev, strength: value}
})
ipcRenderer.invoke("apply-pixelate", {...state, strength: value, realTime: true})
ipcRenderer.invoke("save-temp", "pixelate", String(value))
break
}
}
Expand Down
6 changes: 6 additions & 0 deletions components/ResizeDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ const ResizeDialog: React.FunctionComponent = (props) => {
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedResize = await ipcRenderer.invoke("get-temp", "resize")
if (savedResize) changeState("resize", JSON.parse(savedResize))
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -80,6 +85,7 @@ const ResizeDialog: React.FunctionComponent = (props) => {
return {...prev, width: newState.width, height: newState.height}
})
ipcRenderer.invoke("apply-resize", {...state, width: newState.width, height: newState.height, percent: state.percent, realTime: true})
ipcRenderer.invoke("save-temp", "resize", JSON.stringify(newState))
break
}
}
Expand Down
6 changes: 6 additions & 0 deletions components/RotateDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ const RotateDialog: React.FunctionComponent = (props) => {
functions.updateTheme(theme, transparency)
}
initTheme()
const savedValues = async () => {
const savedRotation = await ipcRenderer.invoke("get-temp", "rotation")
if (savedRotation) changeState("degrees", Number(savedRotation))
}
savedValues()
const updateTheme = (event: any, theme: string, transparency: boolean) => {
functions.updateTheme(theme, transparency)
}
Expand Down Expand Up @@ -72,6 +77,7 @@ const RotateDialog: React.FunctionComponent = (props) => {
return {...prev, degrees: value}
})
ipcRenderer.invoke("apply-rotate", {...state, degrees: value, realTime: true})
ipcRenderer.invoke("get-temp", "rotation", String(value))
break
}
}
Expand Down
Loading

0 comments on commit 7c063b3

Please sign in to comment.