wip
This commit is contained in:
parent
ef1179a858
commit
53aea791c5
@ -84,7 +84,6 @@
|
|||||||
"socket.io-client": "^4.5.4",
|
"socket.io-client": "^4.5.4",
|
||||||
"source-map-loader": "^3.0.0",
|
"source-map-loader": "^3.0.0",
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"tailwindcss": "^3.0.2",
|
|
||||||
"terser-webpack-plugin": "^5.2.5",
|
"terser-webpack-plugin": "^5.2.5",
|
||||||
"typescript": "4.x",
|
"typescript": "4.x",
|
||||||
"webpack": "^5.64.4",
|
"webpack": "^5.64.4",
|
||||||
|
File diff suppressed because it is too large
Load Diff
166
lama_cleaner/app/src/components/Extender/Extender.scss
Normal file
166
lama_cleaner/app/src/components/Extender/Extender.scss
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
@use 'sass:math';
|
||||||
|
|
||||||
|
$drag-handle-shortside: 12px;
|
||||||
|
$drag-handle-longside: 40px;
|
||||||
|
$drag-bar-size: 12px;
|
||||||
|
|
||||||
|
$half-handle-shortside: math.div($drag-handle-shortside, 2);
|
||||||
|
$half-handle-longside: math.div($drag-handle-longside, 2);
|
||||||
|
$half-drag-bar-size: math.div($drag-bar-size, 2);
|
||||||
|
|
||||||
|
.extender-border {
|
||||||
|
outline-color: var(--yellow-accent);
|
||||||
|
outline-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-bar {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: auto;
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 0.2rem 0.8rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
color: var(--text-color);
|
||||||
|
background-color: var(--page-bg);
|
||||||
|
border-radius: 9999px;
|
||||||
|
|
||||||
|
border: var(--editor-toolkit-panel-border);
|
||||||
|
box-shadow: 0 0 0 1px #0000001a, 0 3px 16px #00000014, 0 2px 6px 1px #00000017;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.extender-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 2;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extender {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
// display: flex;
|
||||||
|
// flex-direction: column;
|
||||||
|
// align-items: center;
|
||||||
|
|
||||||
|
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-bar {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: auto;
|
||||||
|
// display: none;
|
||||||
|
|
||||||
|
&.ord-top {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: $drag-bar-size;
|
||||||
|
margin-top: -$half-drag-bar-size;
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
&.ord-right {
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: $drag-bar-size;
|
||||||
|
height: 100%;
|
||||||
|
margin-right: -$half-drag-bar-size;
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
|
&.ord-bottom {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: $drag-bar-size;
|
||||||
|
margin-bottom: -$half-drag-bar-size;
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
&.ord-left {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: $drag-bar-size;
|
||||||
|
height: 100%;
|
||||||
|
margin-left: -$half-drag-bar-size;
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle {
|
||||||
|
width: $drag-handle-shortside;
|
||||||
|
height: $drag-handle-shortside;
|
||||||
|
z-index: 4;
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
content: '';
|
||||||
|
border: 2px solid var(--yellow-accent);
|
||||||
|
background-color: var(--yellow-accent-light);
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--yellow-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-topleft {
|
||||||
|
cursor: nw-resize;
|
||||||
|
top: (-$half-handle-shortside)-1px;
|
||||||
|
left: (-$half-handle-shortside)-1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-topright {
|
||||||
|
cursor: ne-resize;
|
||||||
|
top: -($half-handle-shortside)-1px;
|
||||||
|
right: -($half-handle-shortside)-1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-bottomright {
|
||||||
|
cursor: se-resize;
|
||||||
|
bottom: -($half-handle-shortside)-1px;
|
||||||
|
right: -($half-handle-shortside)-1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-bottomleft {
|
||||||
|
cursor: sw-resize;
|
||||||
|
bottom: -($half-handle-shortside)-1px;
|
||||||
|
left: -($half-handle-shortside)-1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-top,
|
||||||
|
&.ord-bottom {
|
||||||
|
left: calc(50% - $half-handle-shortside);
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-top {
|
||||||
|
top: (-$half-handle-shortside)-1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-bottom {
|
||||||
|
bottom: -($half-handle-shortside)-1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-left,
|
||||||
|
&.ord-right {
|
||||||
|
top: calc(50% - $half-handle-shortside);
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-left {
|
||||||
|
left: (-$half-handle-shortside)-1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ord-right {
|
||||||
|
right: -($half-handle-shortside)-1px;
|
||||||
|
}
|
||||||
|
}
|
408
lama_cleaner/app/src/components/Extender/Extender.tsx
Normal file
408
lama_cleaner/app/src/components/Extender/Extender.tsx
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
import {
|
||||||
|
extenderX,
|
||||||
|
extenderY,
|
||||||
|
extenderHeight,
|
||||||
|
extenderWidth,
|
||||||
|
isInpaintingState,
|
||||||
|
} from '../../store/Atoms'
|
||||||
|
|
||||||
|
const DOC_MOVE_OPTS = { capture: true, passive: false }
|
||||||
|
|
||||||
|
const DRAG_HANDLE_BORDER = 2
|
||||||
|
const DRAG_HANDLE_SHORT = 12
|
||||||
|
const DRAG_HANDLE_LONG = 40
|
||||||
|
|
||||||
|
interface EVData {
|
||||||
|
initX: number
|
||||||
|
initY: number
|
||||||
|
initHeight: number
|
||||||
|
initWidth: number
|
||||||
|
startResizeX: number
|
||||||
|
startResizeY: number
|
||||||
|
ord: string // top/right/bottom/left
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
maxHeight: number
|
||||||
|
maxWidth: number
|
||||||
|
scale: number
|
||||||
|
minHeight: number
|
||||||
|
minWidth: number
|
||||||
|
show: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const clamp = (
|
||||||
|
newPos: number,
|
||||||
|
newLength: number,
|
||||||
|
oldPos: number,
|
||||||
|
oldLength: number,
|
||||||
|
minLength: number,
|
||||||
|
maxLength: number
|
||||||
|
) => {
|
||||||
|
if (newPos !== oldPos && newLength === oldLength) {
|
||||||
|
if (newPos < 0) {
|
||||||
|
return [0, oldLength]
|
||||||
|
}
|
||||||
|
if (newPos + newLength > maxLength) {
|
||||||
|
return [maxLength - oldLength, oldLength]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (newLength < minLength) {
|
||||||
|
if (newPos === oldPos) {
|
||||||
|
return [newPos, minLength]
|
||||||
|
}
|
||||||
|
return [newPos + newLength - minLength, minLength]
|
||||||
|
}
|
||||||
|
if (newPos < 0) {
|
||||||
|
return [0, newPos + newLength]
|
||||||
|
}
|
||||||
|
if (newPos + newLength > maxLength) {
|
||||||
|
return [newPos, maxLength - newPos]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [newPos, newLength]
|
||||||
|
}
|
||||||
|
|
||||||
|
const Extender = (props: Props) => {
|
||||||
|
const { minHeight, minWidth, maxHeight, maxWidth, scale, show } = props
|
||||||
|
const [x, setX] = useRecoilState(extenderX)
|
||||||
|
const [y, setY] = useRecoilState(extenderY)
|
||||||
|
const [height, setHeight] = useRecoilState(extenderHeight)
|
||||||
|
const [width, setWidth] = useRecoilState(extenderWidth)
|
||||||
|
const isInpainting = useRecoilValue(isInpaintingState)
|
||||||
|
|
||||||
|
const [isResizing, setIsResizing] = useState(false)
|
||||||
|
const [isMoving, setIsMoving] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setX(Math.round((maxWidth - 512) / 2))
|
||||||
|
setY(Math.round((maxHeight - 512) / 2))
|
||||||
|
}, [maxHeight, maxWidth])
|
||||||
|
|
||||||
|
const [evData, setEVData] = useState<EVData>({
|
||||||
|
initX: 0,
|
||||||
|
initY: 0,
|
||||||
|
initHeight: 0,
|
||||||
|
initWidth: 0,
|
||||||
|
startResizeX: 0,
|
||||||
|
startResizeY: 0,
|
||||||
|
ord: 'top',
|
||||||
|
})
|
||||||
|
|
||||||
|
const onDragFocus = () => {
|
||||||
|
console.log('focus')
|
||||||
|
}
|
||||||
|
|
||||||
|
const clampLeftRight = (newX: number, newWidth: number) => {
|
||||||
|
return clamp(newX, newWidth, x, width, minWidth, maxWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
const clampTopBottom = (newY: number, newHeight: number) => {
|
||||||
|
return clamp(newY, newHeight, y, height, minHeight, maxHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPointerMove = (e: PointerEvent) => {
|
||||||
|
if (isInpainting) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const curX = e.clientX
|
||||||
|
const curY = e.clientY
|
||||||
|
|
||||||
|
const offsetY = Math.round((curY - evData.startResizeY) / scale)
|
||||||
|
const offsetX = Math.round((curX - evData.startResizeX) / scale)
|
||||||
|
|
||||||
|
const moveTop = () => {
|
||||||
|
const newHeight = evData.initHeight - offsetY
|
||||||
|
const newY = evData.initY + offsetY
|
||||||
|
const [clampedY, clampedHeight] = clampTopBottom(newY, newHeight)
|
||||||
|
setHeight(clampedHeight)
|
||||||
|
setY(clampedY)
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveBottom = () => {
|
||||||
|
const newHeight = evData.initHeight + offsetY
|
||||||
|
const [clampedY, clampedHeight] = clampTopBottom(evData.initY, newHeight)
|
||||||
|
setHeight(clampedHeight)
|
||||||
|
setY(clampedY)
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveLeft = () => {
|
||||||
|
const newWidth = evData.initWidth - offsetX
|
||||||
|
const newX = evData.initX + offsetX
|
||||||
|
const [clampedX, clampedWidth] = clampLeftRight(newX, newWidth)
|
||||||
|
setWidth(clampedWidth)
|
||||||
|
setX(clampedX)
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveRight = () => {
|
||||||
|
const newWidth = evData.initWidth + offsetX
|
||||||
|
const [clampedX, clampedWidth] = clampLeftRight(evData.initX, newWidth)
|
||||||
|
setWidth(clampedWidth)
|
||||||
|
setX(clampedX)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isResizing) {
|
||||||
|
switch (evData.ord) {
|
||||||
|
case 'topleft': {
|
||||||
|
moveTop()
|
||||||
|
moveLeft()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'topright': {
|
||||||
|
moveTop()
|
||||||
|
moveRight()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'bottomleft': {
|
||||||
|
moveBottom()
|
||||||
|
moveLeft()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'bottomright': {
|
||||||
|
moveBottom()
|
||||||
|
moveRight()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'top': {
|
||||||
|
moveTop()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'right': {
|
||||||
|
moveRight()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'bottom': {
|
||||||
|
moveBottom()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'left': {
|
||||||
|
moveLeft()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMoving) {
|
||||||
|
const newX = evData.initX + offsetX
|
||||||
|
const newY = evData.initY + offsetY
|
||||||
|
const [clampedX, clampedWidth] = clampLeftRight(newX, evData.initWidth)
|
||||||
|
const [clampedY, clampedHeight] = clampTopBottom(newY, evData.initHeight)
|
||||||
|
setWidth(clampedWidth)
|
||||||
|
setHeight(clampedHeight)
|
||||||
|
setX(clampedX)
|
||||||
|
setY(clampedY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPointerDone = (e: PointerEvent) => {
|
||||||
|
if (isResizing) {
|
||||||
|
setIsResizing(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMoving) {
|
||||||
|
setIsMoving(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isResizing || isMoving) {
|
||||||
|
document.addEventListener('pointermove', onPointerMove, DOC_MOVE_OPTS)
|
||||||
|
document.addEventListener('pointerup', onPointerDone, DOC_MOVE_OPTS)
|
||||||
|
document.addEventListener('pointercancel', onPointerDone, DOC_MOVE_OPTS)
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener(
|
||||||
|
'pointermove',
|
||||||
|
onPointerMove,
|
||||||
|
DOC_MOVE_OPTS
|
||||||
|
)
|
||||||
|
document.removeEventListener('pointerup', onPointerDone, DOC_MOVE_OPTS)
|
||||||
|
document.removeEventListener(
|
||||||
|
'pointercancel',
|
||||||
|
onPointerDone,
|
||||||
|
DOC_MOVE_OPTS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isResizing, isMoving, width, height, evData])
|
||||||
|
|
||||||
|
const onCropPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
|
||||||
|
const { ord } = (e.target as HTMLElement).dataset
|
||||||
|
if (ord) {
|
||||||
|
setIsResizing(true)
|
||||||
|
setEVData({
|
||||||
|
initX: x,
|
||||||
|
initY: y,
|
||||||
|
initHeight: height,
|
||||||
|
initWidth: width,
|
||||||
|
startResizeX: e.clientX,
|
||||||
|
startResizeY: e.clientY,
|
||||||
|
ord,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCropSelection = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="drag-elements"
|
||||||
|
onFocus={onDragFocus}
|
||||||
|
onPointerDown={onCropPointerDown}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="drag-bar ord-top"
|
||||||
|
data-ord="top"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="drag-bar ord-right"
|
||||||
|
data-ord="right"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="drag-bar ord-bottom"
|
||||||
|
data-ord="bottom"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="drag-bar ord-left"
|
||||||
|
data-ord="left"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="drag-handle ord-topleft"
|
||||||
|
data-ord="topleft"
|
||||||
|
aria-label="topleft"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="drag-handle ord-topright"
|
||||||
|
data-ord="topright"
|
||||||
|
aria-label="topright"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="drag-handle ord-bottomleft"
|
||||||
|
data-ord="bottomleft"
|
||||||
|
aria-label="bottomleft"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="drag-handle ord-bottomright"
|
||||||
|
data-ord="bottomright"
|
||||||
|
aria-label="bottomright"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="drag-handle ord-top"
|
||||||
|
data-ord="top"
|
||||||
|
aria-label="top"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="drag-handle ord-right"
|
||||||
|
data-ord="right"
|
||||||
|
aria-label="right"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="drag-handle ord-bottom"
|
||||||
|
data-ord="bottom"
|
||||||
|
aria-label="bottom"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="drag-handle ord-left"
|
||||||
|
data-ord="left"
|
||||||
|
aria-label="left"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
style={{ transform: `scale(${1 / scale})` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onInfoBarPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
|
||||||
|
setIsMoving(true)
|
||||||
|
setEVData({
|
||||||
|
initX: x,
|
||||||
|
initY: y,
|
||||||
|
initHeight: height,
|
||||||
|
initWidth: width,
|
||||||
|
startResizeX: e.clientX,
|
||||||
|
startResizeY: e.clientY,
|
||||||
|
ord: '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const createInfoBar = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="info-bar"
|
||||||
|
onPointerDown={onInfoBarPointerDown}
|
||||||
|
style={{
|
||||||
|
transform: `scale(${1 / scale})`,
|
||||||
|
top: `${10 / scale}px`,
|
||||||
|
left: `${10 / scale}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="crop-size">
|
||||||
|
{width} x {height}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createBorder = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="extender-border"
|
||||||
|
style={{
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
outlineWidth: `${DRAG_HANDLE_BORDER / scale}px`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="extender-wrapper"
|
||||||
|
style={{ visibility: show ? 'visible' : 'hidden' }}
|
||||||
|
>
|
||||||
|
<div className="extender" style={{ height, width, left: x, top: y }}>
|
||||||
|
{createBorder()}
|
||||||
|
{createInfoBar()}
|
||||||
|
{createCropSelection()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Extender
|
@ -1,5 +1,6 @@
|
|||||||
import React, { ReactNode, useEffect, useState } from 'react'
|
import React, { ReactNode, useState } from 'react'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
import * as Tabs from '@radix-ui/react-tabs'
|
||||||
import {
|
import {
|
||||||
AIModel,
|
AIModel,
|
||||||
CV2Flag,
|
CV2Flag,
|
||||||
@ -9,13 +10,21 @@ import {
|
|||||||
import Selector from '../shared/Selector'
|
import Selector from '../shared/Selector'
|
||||||
import { Switch, SwitchThumb } from '../shared/Switch'
|
import { Switch, SwitchThumb } from '../shared/Switch'
|
||||||
import Tooltip from '../shared/Tooltip'
|
import Tooltip from '../shared/Tooltip'
|
||||||
import { LDMSampler } from './HDSettingBlock'
|
import HDSettingBlock, { LDMSampler } from './HDSettingBlock'
|
||||||
import NumberInputSetting from './NumberInputSetting'
|
import NumberInputSetting from './NumberInputSetting'
|
||||||
import SettingBlock from './SettingBlock'
|
import SettingBlock from './SettingBlock'
|
||||||
|
import Flex from '../shared/Layout'
|
||||||
|
import ManualRunInpaintingSettingBlock from './ManualRunInpaintingSettingBlock'
|
||||||
|
|
||||||
|
const ERASE_TAB = 'erase_tab'
|
||||||
|
const INPAINTING_DIFFUSION_TAB = 'inpainting_diffusion_tab'
|
||||||
|
const DIFFUSION_TAB = 'diffusion_tab'
|
||||||
|
const OTHER_TAB = 'other_tab'
|
||||||
|
|
||||||
function ModelSettingBlock() {
|
function ModelSettingBlock() {
|
||||||
const [setting, setSettingState] = useRecoilState(settingState)
|
const [setting, setSettingState] = useRecoilState(settingState)
|
||||||
const isDisableModelSwitch = useRecoilValue(isDisableModelSwitchState)
|
const isDisableModelSwitch = useRecoilValue(isDisableModelSwitchState)
|
||||||
|
const [tab, setTab] = useState(ERASE_TAB)
|
||||||
|
|
||||||
const onModelChange = (value: AIModel) => {
|
const onModelChange = (value: AIModel) => {
|
||||||
setSettingState(old => {
|
setSettingState(old => {
|
||||||
@ -190,112 +199,63 @@ function ModelSettingBlock() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderPaperCodeBadge = (): ReactNode => {
|
|
||||||
switch (setting.model) {
|
|
||||||
case AIModel.LAMA:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Resolution-robust Large Mask Inpainting with Fourier Convolutions',
|
|
||||||
'https://arxiv.org/abs/2109.07161',
|
|
||||||
'https://github.com/saic-mdal/lama'
|
|
||||||
)
|
|
||||||
case AIModel.LDM:
|
|
||||||
return renderModelDesc(
|
|
||||||
'High-Resolution Image Synthesis with Latent Diffusion Models',
|
|
||||||
'https://arxiv.org/abs/2112.10752',
|
|
||||||
'https://github.com/CompVis/latent-diffusion'
|
|
||||||
)
|
|
||||||
case AIModel.ZITS:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Incremental Transformer Structure Enhanced Image Inpainting with Masking Positional Encoding',
|
|
||||||
'https://arxiv.org/abs/2203.00867',
|
|
||||||
'https://github.com/DQiaole/ZITS_inpainting'
|
|
||||||
)
|
|
||||||
case AIModel.MAT:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Mask-Aware Transformer for Large Hole Image Inpainting',
|
|
||||||
'https://arxiv.org/abs/2203.15270',
|
|
||||||
'https://github.com/fenglinglwb/MAT'
|
|
||||||
)
|
|
||||||
case AIModel.FCF:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Keys to Better Image Inpainting: Structure and Texture Go Hand in Hand',
|
|
||||||
'https://arxiv.org/abs/2208.03382',
|
|
||||||
'https://github.com/SHI-Labs/FcF-Inpainting'
|
|
||||||
)
|
|
||||||
case AIModel.SD15:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Stable Diffusion 1.5',
|
|
||||||
'https://ommer-lab.com/research/latent-diffusion-models/',
|
|
||||||
'https://github.com/CompVis/stable-diffusion'
|
|
||||||
)
|
|
||||||
case AIModel.ANYTHING4:
|
|
||||||
return renderModelDesc(
|
|
||||||
'andite/anything-v4.0',
|
|
||||||
'https://huggingface.co/andite/anything-v4.0',
|
|
||||||
'https://huggingface.co/andite/anything-v4.0'
|
|
||||||
)
|
|
||||||
case AIModel.REALISTIC_VISION_1_4:
|
|
||||||
return renderModelDesc(
|
|
||||||
'SG161222/Realistic_Vision_V1.4',
|
|
||||||
'https://huggingface.co/SG161222/Realistic_Vision_V1.4',
|
|
||||||
'https://huggingface.co/SG161222/Realistic_Vision_V1.4'
|
|
||||||
)
|
|
||||||
case AIModel.SD2:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Stable Diffusion 2',
|
|
||||||
'https://ommer-lab.com/research/latent-diffusion-models/',
|
|
||||||
'https://github.com/Stability-AI/stablediffusion'
|
|
||||||
)
|
|
||||||
case AIModel.Mange:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Manga Inpainting',
|
|
||||||
'https://www.cse.cuhk.edu.hk/~ttwong/papers/mangainpaint/mangainpaint.html',
|
|
||||||
'https://github.com/msxie92/MangaInpainting'
|
|
||||||
)
|
|
||||||
case AIModel.CV2:
|
|
||||||
return renderModelDesc(
|
|
||||||
'OpenCV Image Inpainting',
|
|
||||||
'https://docs.opencv.org/4.6.0/df/d3d/tutorial_py_inpainting.html',
|
|
||||||
'https://docs.opencv.org/4.6.0/df/d3d/tutorial_py_inpainting.html'
|
|
||||||
)
|
|
||||||
case AIModel.PAINT_BY_EXAMPLE:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Paint by Example',
|
|
||||||
'https://arxiv.org/abs/2211.13227',
|
|
||||||
'https://github.com/Fantasy-Studio/Paint-by-Example'
|
|
||||||
)
|
|
||||||
case AIModel.PIX2PIX:
|
|
||||||
return renderModelDesc(
|
|
||||||
'InstructPix2Pix',
|
|
||||||
'https://arxiv.org/abs/2211.09800',
|
|
||||||
'https://github.com/timothybrooks/instruct-pix2pix'
|
|
||||||
)
|
|
||||||
case AIModel.KANDINSKY21:
|
|
||||||
return renderModelDesc(
|
|
||||||
'Kandinsky 2.1',
|
|
||||||
'https://huggingface.co/kandinsky-community/kandinsky-2-1-inpaint',
|
|
||||||
'https://huggingface.co/kandinsky-community/kandinsky-2-1-inpaint'
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
return <></>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingBlock
|
// <SettingBlock
|
||||||
className="model-setting-block"
|
// className="model-setting-block"
|
||||||
title="Model"
|
// title="Model"
|
||||||
titleSuffix={renderPaperCodeBadge()}
|
// input={
|
||||||
input={
|
// <Selector
|
||||||
<Selector
|
// value={setting.model as string}
|
||||||
value={setting.model as string}
|
// options={Object.values(AIModel)}
|
||||||
options={Object.values(AIModel)}
|
// onChange={val => onModelChange(val as AIModel)}
|
||||||
onChange={val => onModelChange(val as AIModel)}
|
// disabled={isDisableModelSwitch}
|
||||||
disabled={isDisableModelSwitch}
|
// />
|
||||||
/>
|
// }
|
||||||
}
|
// optionDesc={renderOptionDesc()}
|
||||||
optionDesc={renderOptionDesc()}
|
// />
|
||||||
/>
|
<Flex
|
||||||
|
style={{
|
||||||
|
justifyContent: 'start',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: 10,
|
||||||
|
alignItems: 'start',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex style={{ justifyContent: 'space-between', width: '100%' }}>
|
||||||
|
<div>Current Model</div>
|
||||||
|
<div>{setting.model}</div>
|
||||||
|
</Flex>
|
||||||
|
<Tabs.Root
|
||||||
|
className="TabsRoot"
|
||||||
|
defaultValue={ERASE_TAB}
|
||||||
|
onValueChange={val => setTab(val)}
|
||||||
|
>
|
||||||
|
<Tabs.List className="TabsList" aria-label="Object remove model">
|
||||||
|
<Tabs.Trigger className="TabsTrigger" value={ERASE_TAB}>
|
||||||
|
Erase
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger
|
||||||
|
className="TabsTrigger"
|
||||||
|
value={INPAINTING_DIFFUSION_TAB}
|
||||||
|
>
|
||||||
|
Inpainting Diffusion
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger className="TabsTrigger" value={DIFFUSION_TAB}>
|
||||||
|
Diffusion
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger className="TabsTrigger" value={OTHER_TAB}>
|
||||||
|
Other
|
||||||
|
</Tabs.Trigger>
|
||||||
|
</Tabs.List>
|
||||||
|
<Tabs.Content value={ERASE_TAB}>
|
||||||
|
<ManualRunInpaintingSettingBlock />
|
||||||
|
<HDSettingBlock />
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value={INPAINTING_DIFFUSION_TAB}>123</Tabs.Content>
|
||||||
|
<Tabs.Content value={DIFFUSION_TAB}>123</Tabs.Content>
|
||||||
|
<Tabs.Content value={OTHER_TAB}>123</Tabs.Content>
|
||||||
|
</Tabs.Root>
|
||||||
|
</Flex>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ interface SettingModalProps {
|
|||||||
export default function SettingModal(props: SettingModalProps) {
|
export default function SettingModal(props: SettingModalProps) {
|
||||||
const { onClose } = props
|
const { onClose } = props
|
||||||
const [setting, setSettingState] = useRecoilState(settingState)
|
const [setting, setSettingState] = useRecoilState(settingState)
|
||||||
const isSD = useRecoilValue(isSDState)
|
|
||||||
const isDiffusionModels = useRecoilValue(isDiffusionModelsState)
|
const isDiffusionModels = useRecoilValue(isDiffusionModelsState)
|
||||||
|
|
||||||
const handleOnClose = () => {
|
const handleOnClose = () => {
|
||||||
@ -57,9 +56,8 @@ export default function SettingModal(props: SettingModalProps) {
|
|||||||
show={setting.show}
|
show={setting.show}
|
||||||
>
|
>
|
||||||
<DownloadMaskSettingBlock />
|
<DownloadMaskSettingBlock />
|
||||||
{isDiffusionModels ? <></> : <ManualRunInpaintingSettingBlock />}
|
<ManualRunInpaintingSettingBlock />
|
||||||
<ModelSettingBlock />
|
<ModelSettingBlock />
|
||||||
{isDiffusionModels ? <></> : <HDSettingBlock />}
|
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.resize-title-tile {
|
.resize-title-tile {
|
||||||
width: 86px;
|
width: 60px;
|
||||||
font-size: 0.5rem;
|
font-size: 0.5rem;
|
||||||
color: var(--text-color-gray);
|
color: var(--text-color-gray);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { FormEvent } from 'react'
|
import React, { FormEvent, useState } from 'react'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import * as PopoverPrimitive from '@radix-ui/react-popover'
|
import * as PopoverPrimitive from '@radix-ui/react-popover'
|
||||||
|
import * as Tabs from '@radix-ui/react-tabs'
|
||||||
import { useToggle } from 'react-use'
|
import { useToggle } from 'react-use'
|
||||||
import {
|
import {
|
||||||
ControlNetMethod,
|
ControlNetMethod,
|
||||||
@ -10,6 +11,8 @@ import {
|
|||||||
propmtState,
|
propmtState,
|
||||||
SDSampler,
|
SDSampler,
|
||||||
settingState,
|
settingState,
|
||||||
|
SIDE_PANEL_TAB,
|
||||||
|
SIDE_PANEL_TAB_TYPE,
|
||||||
} from '../../store/Atoms'
|
} from '../../store/Atoms'
|
||||||
import NumberInputSetting from '../Settings/NumberInputSetting'
|
import NumberInputSetting from '../Settings/NumberInputSetting'
|
||||||
import SettingBlock from '../Settings/SettingBlock'
|
import SettingBlock from '../Settings/SettingBlock'
|
||||||
@ -23,6 +26,7 @@ const INPUT_WIDTH = 30
|
|||||||
|
|
||||||
const SidePanel = () => {
|
const SidePanel = () => {
|
||||||
const [open, toggleOpen] = useToggle(true)
|
const [open, toggleOpen] = useToggle(true)
|
||||||
|
const [tab, setTab] = useState<SIDE_PANEL_TAB_TYPE>(SIDE_PANEL_TAB.inpainting)
|
||||||
const [setting, setSettingState] = useRecoilState(settingState)
|
const [setting, setSettingState] = useRecoilState(settingState)
|
||||||
const [negativePrompt, setNegativePrompt] =
|
const [negativePrompt, setNegativePrompt] =
|
||||||
useRecoilState(negativePropmtState)
|
useRecoilState(negativePropmtState)
|
||||||
@ -95,27 +99,58 @@ const SidePanel = () => {
|
|||||||
>
|
>
|
||||||
Config
|
Config
|
||||||
</PopoverPrimitive.Trigger>
|
</PopoverPrimitive.Trigger>
|
||||||
|
|
||||||
<PopoverPrimitive.Portal>
|
<PopoverPrimitive.Portal>
|
||||||
<PopoverPrimitive.Content className="side-panel-content">
|
<PopoverPrimitive.Content className="side-panel-content">
|
||||||
{isControlNet && renderConterNetSetting()}
|
<Tabs.Root
|
||||||
|
className="TabsRoot"
|
||||||
<SettingBlock
|
style={{ alignSelf: 'center' }}
|
||||||
title="Croper"
|
defaultValue={tab}
|
||||||
input={
|
onValueChange={val => setTab(val as SIDE_PANEL_TAB_TYPE)}
|
||||||
<Switch
|
>
|
||||||
checked={setting.showCroper}
|
<Tabs.List className="TabsList">
|
||||||
onCheckedChange={value => {
|
<Tabs.Trigger
|
||||||
setSettingState(old => {
|
className="TabsTrigger"
|
||||||
return { ...old, showCroper: value }
|
value={SIDE_PANEL_TAB.inpainting}
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<SwitchThumb />
|
In Painting
|
||||||
</Switch>
|
</Tabs.Trigger>
|
||||||
}
|
<Tabs.Trigger
|
||||||
/>
|
className="TabsTrigger"
|
||||||
|
value={SIDE_PANEL_TAB.outpainting}
|
||||||
|
>
|
||||||
|
Out Painting
|
||||||
|
</Tabs.Trigger>
|
||||||
|
</Tabs.List>
|
||||||
|
</Tabs.Root>
|
||||||
|
|
||||||
<ImageResizeScale />
|
{isControlNet && tab === SIDE_PANEL_TAB.inpainting ? (
|
||||||
|
renderConterNetSetting()
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tab === SIDE_PANEL_TAB.inpainting ? (
|
||||||
|
<SettingBlock
|
||||||
|
title="Croper"
|
||||||
|
input={
|
||||||
|
<Switch
|
||||||
|
checked={setting.showCroper}
|
||||||
|
onCheckedChange={value => {
|
||||||
|
setSettingState(old => {
|
||||||
|
return { ...old, showCroper: value }
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SwitchThumb />
|
||||||
|
</Switch>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tab === SIDE_PANEL_TAB.inpainting ? <ImageResizeScale /> : <></>}
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
<NumberInputSetting
|
<NumberInputSetting
|
||||||
@ -158,35 +193,43 @@ const SidePanel = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<NumberInputSetting
|
{tab === SIDE_PANEL_TAB.inpainting ? (
|
||||||
title="Mask Blur"
|
<NumberInputSetting
|
||||||
width={INPUT_WIDTH}
|
title="Mask Blur"
|
||||||
value={`${setting.sdMaskBlur}`}
|
width={INPUT_WIDTH}
|
||||||
desc="Blur the edge of mask area. The higher the number the smoother blend with the original image"
|
value={`${setting.sdMaskBlur}`}
|
||||||
onValue={value => {
|
desc="Blur the edge of mask area. The higher the number the smoother blend with the original image"
|
||||||
const val = value.length === 0 ? 0 : parseInt(value, 10)
|
onValue={value => {
|
||||||
setSettingState(old => {
|
const val = value.length === 0 ? 0 : parseInt(value, 10)
|
||||||
return { ...old, sdMaskBlur: val }
|
setSettingState(old => {
|
||||||
})
|
return { ...old, sdMaskBlur: val }
|
||||||
}}
|
})
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
|
||||||
<SettingBlock
|
{tab === SIDE_PANEL_TAB.outpainting ? (
|
||||||
title="Match Histograms"
|
<SettingBlock
|
||||||
desc="Match the inpainting result histogram to the source image histogram, will improves the inpainting quality for some images."
|
title="Match Histograms"
|
||||||
input={
|
desc="Match the inpainting result histogram to the source image histogram, will improves the inpainting quality for some images."
|
||||||
<Switch
|
input={
|
||||||
checked={setting.sdMatchHistograms}
|
<Switch
|
||||||
onCheckedChange={value => {
|
checked={setting.sdMatchHistograms}
|
||||||
setSettingState(old => {
|
onCheckedChange={value => {
|
||||||
return { ...old, sdMatchHistograms: value }
|
setSettingState(old => {
|
||||||
})
|
return { ...old, sdMatchHistograms: value }
|
||||||
}}
|
})
|
||||||
>
|
}}
|
||||||
<SwitchThumb />
|
>
|
||||||
</Switch>
|
<SwitchThumb />
|
||||||
}
|
</Switch>
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
|
||||||
<SettingBlock
|
<SettingBlock
|
||||||
className="sub-setting-block"
|
className="sub-setting-block"
|
||||||
|
@ -3,6 +3,13 @@ import _ from 'lodash'
|
|||||||
import { HDStrategy, LDMSampler } from '../components/Settings/HDSettingBlock'
|
import { HDStrategy, LDMSampler } from '../components/Settings/HDSettingBlock'
|
||||||
import { ToastState } from '../components/shared/Toast'
|
import { ToastState } from '../components/shared/Toast'
|
||||||
|
|
||||||
|
function strEnum<T extends string>(o: Array<T>): { [K in T]: K } {
|
||||||
|
return o.reduce((res, key) => {
|
||||||
|
res[key] = key
|
||||||
|
return res
|
||||||
|
}, Object.create(null))
|
||||||
|
}
|
||||||
|
|
||||||
export enum AIModel {
|
export enum AIModel {
|
||||||
LAMA = 'lama',
|
LAMA = 'lama',
|
||||||
LDM = 'ldm',
|
LDM = 'ldm',
|
||||||
@ -17,7 +24,7 @@ export enum AIModel {
|
|||||||
Mange = 'manga',
|
Mange = 'manga',
|
||||||
PAINT_BY_EXAMPLE = 'paint_by_example',
|
PAINT_BY_EXAMPLE = 'paint_by_example',
|
||||||
PIX2PIX = 'instruct_pix2pix',
|
PIX2PIX = 'instruct_pix2pix',
|
||||||
KANDINSKY21 = 'kandinsky2.1',
|
KANDINSKY22 = 'kandinsky2.2',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ControlNetMethod {
|
export enum ControlNetMethod {
|
||||||
@ -351,6 +358,20 @@ export const croperState = atom<Rect>({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const SIDE_PANEL_TAB = strEnum(['inpainting', 'outpainting'])
|
||||||
|
export type SIDE_PANEL_TAB_TYPE = keyof typeof SIDE_PANEL_TAB
|
||||||
|
|
||||||
|
export interface SidePanelState {
|
||||||
|
tab: SIDE_PANEL_TAB_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sidePanelTabState = atom<SidePanelState>({
|
||||||
|
key: 'sidePanelTabState',
|
||||||
|
default: {
|
||||||
|
tab: SIDE_PANEL_TAB.inpainting,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export const croperX = selector({
|
export const croperX = selector({
|
||||||
key: 'croperX',
|
key: 'croperX',
|
||||||
get: ({ get }) => get(croperState).x,
|
get: ({ get }) => get(croperState).x,
|
||||||
@ -387,6 +408,52 @@ export const croperWidth = selector({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const extenderState = atom<Rect>({
|
||||||
|
key: 'extenderState',
|
||||||
|
default: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 512,
|
||||||
|
height: 512,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const extenderX = selector({
|
||||||
|
key: 'extenderX',
|
||||||
|
get: ({ get }) => get(extenderState).x,
|
||||||
|
set: ({ get, set }, newValue: any) => {
|
||||||
|
const rect = get(extenderState)
|
||||||
|
set(extenderState, { ...rect, x: newValue })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const extenderY = selector({
|
||||||
|
key: 'extenderY',
|
||||||
|
get: ({ get }) => get(extenderState).y,
|
||||||
|
set: ({ get, set }, newValue: any) => {
|
||||||
|
const rect = get(extenderState)
|
||||||
|
set(extenderState, { ...rect, y: newValue })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const extenderHeight = selector({
|
||||||
|
key: 'extenderHeight',
|
||||||
|
get: ({ get }) => get(extenderState).height,
|
||||||
|
set: ({ get, set }, newValue: any) => {
|
||||||
|
const rect = get(extenderState)
|
||||||
|
set(extenderState, { ...rect, height: newValue })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const extenderWidth = selector({
|
||||||
|
key: 'extenderWidth',
|
||||||
|
get: ({ get }) => get(extenderState).width,
|
||||||
|
set: ({ get, set }, newValue: any) => {
|
||||||
|
const rect = get(extenderState)
|
||||||
|
set(extenderState, { ...rect, width: newValue })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
interface ToastAtomState {
|
interface ToastAtomState {
|
||||||
open: boolean
|
open: boolean
|
||||||
desc: string
|
desc: string
|
||||||
@ -567,7 +634,7 @@ const defaultHDSettings: ModelsHDSettings = {
|
|||||||
hdStrategyCropMargin: 128,
|
hdStrategyCropMargin: 128,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
[AIModel.KANDINSKY21]: {
|
[AIModel.KANDINSKY22]: {
|
||||||
hdStrategy: HDStrategy.ORIGINAL,
|
hdStrategy: HDStrategy.ORIGINAL,
|
||||||
hdStrategyResizeLimit: 768,
|
hdStrategyResizeLimit: 768,
|
||||||
hdStrategyCropTrigerSize: 512,
|
hdStrategyCropTrigerSize: 512,
|
||||||
@ -728,7 +795,7 @@ export const isSDState = selector({
|
|||||||
settings.model === AIModel.SD2 ||
|
settings.model === AIModel.SD2 ||
|
||||||
settings.model === AIModel.ANYTHING4 ||
|
settings.model === AIModel.ANYTHING4 ||
|
||||||
settings.model === AIModel.REALISTIC_VISION_1_4 ||
|
settings.model === AIModel.REALISTIC_VISION_1_4 ||
|
||||||
settings.model === AIModel.KANDINSKY21
|
settings.model === AIModel.KANDINSKY22
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user