merges all the recent awesome, adds stamp vertical flip too because I'M HELPING
This commit is contained in:
commit
a71b52464d
15 changed files with 598 additions and 77 deletions
|
@ -46,6 +46,18 @@
|
||||||
mask-image: url("../res/icons/file-plus.svg");
|
mask-image: url("../res/icons/file-plus.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ui.inline-icon.icon-flip-horizontal::after,
|
||||||
|
.ui.icon > .icon-flip-horizontal {
|
||||||
|
-webkit-mask-image: url("../res/icons/flip-horizontal.svg");
|
||||||
|
mask-image: url("../res/icons/flip-horizontal.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.inline-icon.icon-flip-vertical::after,
|
||||||
|
.ui.icon > .icon-flip-vertical {
|
||||||
|
-webkit-mask-image: url("../res/icons/flip-vertical.svg");
|
||||||
|
mask-image: url("../res/icons/flip-vertical.svg");
|
||||||
|
}
|
||||||
|
|
||||||
.ui.icon > .icon-file-x {
|
.ui.icon > .icon-file-x {
|
||||||
-webkit-mask-image: url("../res/icons/file-x.svg");
|
-webkit-mask-image: url("../res/icons/file-x.svg");
|
||||||
mask-image: url("../res/icons/file-x.svg");
|
mask-image: url("../res/icons/file-x.svg");
|
||||||
|
|
213
css/ui/notifications.css
Normal file
213
css/ui/notifications.css
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/** Notification area */
|
||||||
|
.notification-area {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
width: 250px;
|
||||||
|
min-width: 200px;
|
||||||
|
|
||||||
|
z-index: 25;
|
||||||
|
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area > * {
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area.bottom-left {
|
||||||
|
left: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Notifications */
|
||||||
|
.notification-area .notification {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
border-radius: 5px;
|
||||||
|
border: solid 1px;
|
||||||
|
|
||||||
|
padding: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area .notification:hover {
|
||||||
|
filter: brightness(110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area .notification:active {
|
||||||
|
filter: brightness(90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area .notification-content {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area .notification.expanded .notification-content {
|
||||||
|
white-space: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-closebtn {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
flex: 0;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
|
||||||
|
min-width: 20px;
|
||||||
|
max-width: 20px;
|
||||||
|
min-height: 20px;
|
||||||
|
max-height: 20px;
|
||||||
|
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
background-color: #0002;
|
||||||
|
|
||||||
|
transition-duration: 20ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-closebtn:hover {
|
||||||
|
background-color: #fff2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-closebtn:active {
|
||||||
|
background-color: #fff4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-closebtn::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
margin: 2px;
|
||||||
|
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
|
-webkit-mask-size: contain;
|
||||||
|
mask-size: contain;
|
||||||
|
|
||||||
|
-webkit-mask-image: url("../../res/icons/x.svg");
|
||||||
|
mask-image: url("../../res/icons/x.svg");
|
||||||
|
|
||||||
|
background-color: var(--c-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Notification Types */
|
||||||
|
.notification-area .notification.info {
|
||||||
|
background-color: #3976b399;
|
||||||
|
border-color: #12375c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area .notification.success {
|
||||||
|
background-color: #39b34999;
|
||||||
|
border-color: #1b5c12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area .notification.error {
|
||||||
|
background-color: #b3393999;
|
||||||
|
border-color: #5c1212;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-area .notification.warn {
|
||||||
|
background-color: #b3a13999;
|
||||||
|
border-color: #5c4e12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dialog */
|
||||||
|
.dialog-bg {
|
||||||
|
position: fixed;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
background-color: #fff6;
|
||||||
|
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-bg .dialog {
|
||||||
|
background-color: var(--c-primary);
|
||||||
|
color: var(--c-text);
|
||||||
|
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
min-width: 200px;
|
||||||
|
min-height: 20px;
|
||||||
|
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .dialog-title {
|
||||||
|
margin: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .dialog-content {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .dialog-choices {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .dialog-choices > *:first-child {
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
}
|
||||||
|
.dialog .dialog-choices > *:last-child {
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .dialog-choices > * {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--c-text);
|
||||||
|
|
||||||
|
border: 0px;
|
||||||
|
border-top: solid 1px var(--c-hover);
|
||||||
|
|
||||||
|
transition-duration: 50ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .dialog-choices > *:not(:first-child) {
|
||||||
|
border-left: solid 1px var(--c-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .dialog-choices > *:hover {
|
||||||
|
background-color: var(--c-hover);
|
||||||
|
}
|
22
index.html
22
index.html
|
@ -5,13 +5,14 @@
|
||||||
<title>openOutpaint 🐠</title>
|
<title>openOutpaint 🐠</title>
|
||||||
<!-- CSS Variables -->
|
<!-- CSS Variables -->
|
||||||
<link href="css/colors.css?v=f732f19" rel="stylesheet" />
|
<link href="css/colors.css?v=f732f19" rel="stylesheet" />
|
||||||
<link href="css/icons.css?v=599e732" rel="stylesheet" />
|
<link href="css/icons.css?v=2b76310" rel="stylesheet" />
|
||||||
|
|
||||||
<link href="css/index.css?v=cf21c6a" rel="stylesheet" />
|
<link href="css/index.css?v=cf21c6a" rel="stylesheet" />
|
||||||
<link href="css/layers.css?v=92c0352" rel="stylesheet" />
|
<link href="css/layers.css?v=92c0352" rel="stylesheet" />
|
||||||
|
|
||||||
<link href="css/ui/generic.css?v=30837f8" rel="stylesheet" />
|
<link href="css/ui/generic.css?v=30837f8" rel="stylesheet" />
|
||||||
|
|
||||||
|
<link href="css/ui/notifications.css?v=0419b4b" rel="stylesheet" />
|
||||||
<link href="css/ui/workspace.css?v=2a9fdf7" rel="stylesheet" />
|
<link href="css/ui/workspace.css?v=2a9fdf7" rel="stylesheet" />
|
||||||
<link href="css/ui/history.css?v=0b03861" rel="stylesheet" />
|
<link href="css/ui/history.css?v=0b03861" rel="stylesheet" />
|
||||||
<link href="css/ui/layers.css?v=1d66c2b" rel="stylesheet" />
|
<link href="css/ui/layers.css?v=1d66c2b" rel="stylesheet" />
|
||||||
|
@ -428,13 +429,16 @@
|
||||||
|
|
||||||
<!-- Base Libs -->
|
<!-- Base Libs -->
|
||||||
<script src="js/lib/util.js?v=24130a5" type="text/javascript"></script>
|
<script src="js/lib/util.js?v=24130a5" type="text/javascript"></script>
|
||||||
|
<script
|
||||||
|
src="js/lib/notifications.js?v=80eb976"
|
||||||
|
type="text/javascript"></script>
|
||||||
<script src="js/lib/events.js?v=2ab7933" type="text/javascript"></script>
|
<script src="js/lib/events.js?v=2ab7933" type="text/javascript"></script>
|
||||||
<script src="js/lib/db.js?v=434363b" type="text/javascript"></script>
|
<script src="js/lib/db.js?v=434363b" type="text/javascript"></script>
|
||||||
<script src="js/lib/input.js?v=769485c" type="text/javascript"></script>
|
<script src="js/lib/input.js?v=769485c" type="text/javascript"></script>
|
||||||
<script src="js/lib/layers.js?v=1a452a1" type="text/javascript"></script>
|
<script src="js/lib/layers.js?v=1a452a1" type="text/javascript"></script>
|
||||||
<script src="js/lib/commands.js?v=ad60afc" type="text/javascript"></script>
|
<script src="js/lib/commands.js?v=ad60afc" type="text/javascript"></script>
|
||||||
|
|
||||||
<script src="js/lib/toolbar.js?v=306d637" type="text/javascript"></script>
|
<script src="js/lib/toolbar.js?v=fb3f261" type="text/javascript"></script>
|
||||||
<script src="js/lib/ui.js?v=17014b3" type="text/javascript"></script>
|
<script src="js/lib/ui.js?v=17014b3" type="text/javascript"></script>
|
||||||
|
|
||||||
<script
|
<script
|
||||||
|
@ -442,12 +446,12 @@
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
|
|
||||||
<!-- Configuration -->
|
<!-- Configuration -->
|
||||||
<script src="js/config.js?v=e0345e0" type="text/javascript"></script>
|
<script src="js/config.js?v=63598bc" type="text/javascript"></script>
|
||||||
<script src="js/theme.js?v=435cc1b" type="text/javascript"></script>
|
<script src="js/theme.js?v=435cc1b" type="text/javascript"></script>
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<script src="js/prompt.js?v=7a1c68c" type="text/javascript"></script>
|
<script src="js/prompt.js?v=7a1c68c" type="text/javascript"></script>
|
||||||
<script src="js/index.js?v=c113c17" type="text/javascript"></script>
|
<script src="js/index.js?v=017d927" type="text/javascript"></script>
|
||||||
|
|
||||||
<script
|
<script
|
||||||
src="js/ui/floating/history.js?v=4f29db4"
|
src="js/ui/floating/history.js?v=4f29db4"
|
||||||
|
@ -461,7 +465,7 @@
|
||||||
src="js/ui/tool/generic.js?v=3e678e0"
|
src="js/ui/tool/generic.js?v=3e678e0"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
|
|
||||||
<script src="js/ui/tool/dream.js?v=991f6c4" type="text/javascript"></script>
|
<script src="js/ui/tool/dream.js?v=b52bb0e" type="text/javascript"></script>
|
||||||
<script
|
<script
|
||||||
src="js/ui/tool/maskbrush.js?v=d88810f"
|
src="js/ui/tool/maskbrush.js?v=d88810f"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
|
@ -469,16 +473,16 @@
|
||||||
src="js/ui/tool/colorbrush.js?v=46011ee"
|
src="js/ui/tool/colorbrush.js?v=46011ee"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
<script
|
<script
|
||||||
src="js/ui/tool/select.js?v=39911b2"
|
src="js/ui/tool/select.js?v=c05e65a"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
<script src="js/ui/tool/stamp.js?v=455f9fe" type="text/javascript"></script>
|
<script src="js/ui/tool/stamp.js?v=c7818cb" type="text/javascript"></script>
|
||||||
<script
|
<script
|
||||||
src="js/ui/tool/interrogate.js?v=e579ff1"
|
src="js/ui/tool/interrogate.js?v=e579ff1"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
|
|
||||||
<!-- Initialize -->
|
<!-- Initialize -->
|
||||||
<script
|
<script
|
||||||
src="js/initalize/workspace.populate.js?v=e5586da"
|
src="js/initalize/workspace.populate.js?v=4e0a607"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
<script
|
<script
|
||||||
src="js/initalize/shortcuts.populate.js?v=e68546f"
|
src="js/initalize/shortcuts.populate.js?v=e68546f"
|
||||||
|
@ -494,6 +498,6 @@
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
|
|
||||||
<!-- Deals with webui communication -->
|
<!-- Deals with webui communication -->
|
||||||
<script src="js/webui.js?v=8edac89" type="text/javascript"></script>
|
<script src="js/webui.js?v=ccd423a" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -38,6 +38,9 @@ const config = makeReadOnly(
|
||||||
|
|
||||||
// Endpoint
|
// Endpoint
|
||||||
api: makeReadOnly({path: "/sdapi/v1/"}),
|
api: makeReadOnly({path: "/sdapi/v1/"}),
|
||||||
|
|
||||||
|
// Default notification timeout
|
||||||
|
notificationTimeout: 8000,
|
||||||
},
|
},
|
||||||
"config"
|
"config"
|
||||||
);
|
);
|
||||||
|
|
77
js/index.js
77
js/index.js
|
@ -182,8 +182,8 @@ function setFixedHost(h, changePromptMessage) {
|
||||||
hostInput.readOnly = true;
|
hostInput.readOnly = true;
|
||||||
hostInput.style.cursor = "default";
|
hostInput.style.cursor = "default";
|
||||||
hostInput.style.backgroundColor = "#ddd";
|
hostInput.style.backgroundColor = "#ddd";
|
||||||
hostInput.addEventListener("dblclick", () => {
|
hostInput.addEventListener("dblclick", async () => {
|
||||||
if (confirm(changePromptMessage)) {
|
if (await notifications.dialog("Host is Locked", changePromptMessage)) {
|
||||||
hostInput.style.backgroundColor = null;
|
hostInput.style.backgroundColor = null;
|
||||||
hostInput.style.cursor = null;
|
hostInput.style.cursor = null;
|
||||||
hostInput.readOnly = false;
|
hostInput.readOnly = false;
|
||||||
|
@ -343,16 +343,24 @@ async function testHostConnection() {
|
||||||
) => {
|
) => {
|
||||||
const apiIssueResult = () => {
|
const apiIssueResult = () => {
|
||||||
setConnectionStatus("apiissue");
|
setConnectionStatus("apiissue");
|
||||||
const message = `The host is online, but the API seems to be disabled.\nHave you run the webui with the flag '--api', or is the flag '--gradio-debug' currently active?`;
|
const message = `The host is online, but the API seems to be disabled.<br>Have you run the webui with the flag '--api', or is the flag '--gradio-debug' currently active?`;
|
||||||
console.error(message);
|
console.error(message);
|
||||||
if (notify) alert(message);
|
if (notify)
|
||||||
|
notifications.notify(message, {
|
||||||
|
type: NotificationType.ERROR,
|
||||||
|
timeout: config.notificationTimeout * 2,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const offlineResult = () => {
|
const offlineResult = () => {
|
||||||
setConnectionStatus("offline");
|
setConnectionStatus("offline");
|
||||||
const message = `The connection with the host returned an error: ${response.status} - ${response.statusText}`;
|
const message = `The connection with the host returned an error: ${response.status} - ${response.statusText}`;
|
||||||
console.error(message);
|
console.error(message);
|
||||||
if (notify) alert(message);
|
if (notify)
|
||||||
|
notifications.notify(message, {
|
||||||
|
type: NotificationType.ERROR,
|
||||||
|
timeout: config.notificationTimeout * 2,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
if (checkInProgress)
|
if (checkInProgress)
|
||||||
throw new CheckInProgressError(
|
throw new CheckInProgressError(
|
||||||
|
@ -386,9 +394,13 @@ async function testHostConnection() {
|
||||||
);
|
);
|
||||||
const optionsdata = await response.json();
|
const optionsdata = await response.json();
|
||||||
if (optionsdata["use_scale_latent_for_hires_fix"]) {
|
if (optionsdata["use_scale_latent_for_hires_fix"]) {
|
||||||
const message = `You are using an outdated version of A1111 webUI.\nThe HRfix options will not work until you update to at least commit ef27a18 or newer.\n(https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/ef27a18b6b7cb1a8eebdc9b2e88d25baf2c2414d)\nHRfix will fallback to half-resolution only.`;
|
const message = `You are using an outdated version of A1111 webUI.<br>The HRfix options will not work until you update to at least commit ef27a18 or newer.<br>(https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/ef27a18b6b7cb1a8eebdc9b2e88d25baf2c2414d)<br>HRfix will fallback to half-resolution only.`;
|
||||||
console.warn(message);
|
console.warn(message);
|
||||||
if (notify) alert(message);
|
if (notify)
|
||||||
|
notifications.notify(message, {
|
||||||
|
type: NotificationType.WARN,
|
||||||
|
timeout: config.notificationTimeout * 4,
|
||||||
|
});
|
||||||
// Hide all new hrfix options
|
// Hide all new hrfix options
|
||||||
document
|
document
|
||||||
.querySelectorAll(".hrfix")
|
.querySelectorAll(".hrfix")
|
||||||
|
@ -430,14 +442,22 @@ async function testHostConnection() {
|
||||||
setConnectionStatus("corsissue");
|
setConnectionStatus("corsissue");
|
||||||
const message = `CORS is blocking our requests. Try running the webui with the flag '--cors-allow-origins=${window.location.protocol}//${window.location.host}/'`;
|
const message = `CORS is blocking our requests. Try running the webui with the flag '--cors-allow-origins=${window.location.protocol}//${window.location.host}/'`;
|
||||||
console.error(message);
|
console.error(message);
|
||||||
if (notify) alert(message);
|
if (notify)
|
||||||
|
notifications.notify(message, {
|
||||||
|
type: NotificationType.ERROR,
|
||||||
|
timeout: config.notificationTimeout * 2,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setConnectionStatus("offline");
|
setConnectionStatus("offline");
|
||||||
const message = `The server seems to be offline. Is host '${
|
const message = `The server seems to be offline. Is host '${
|
||||||
document.getElementById("host").value
|
document.getElementById("host").value
|
||||||
}' correct?`;
|
}' correct?`;
|
||||||
console.error(message);
|
console.error(message);
|
||||||
if (notify) alert(message);
|
if (notify)
|
||||||
|
notifications.notify(message, {
|
||||||
|
type: NotificationType.ERROR,
|
||||||
|
timeout: config.notificationTimeout * 2,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkInProgress = false;
|
checkInProgress = false;
|
||||||
|
@ -1071,13 +1091,17 @@ async function getModels(refresh = false) {
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
});
|
});
|
||||||
|
|
||||||
alert(`Model changed to [${value}]`);
|
notifications.notify(`Model changed to [${value}]`, {type: "success"});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("[index] Error changing model");
|
console.warn("[index] Error changing model");
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
|
|
||||||
alert(
|
notifications.notify(
|
||||||
"Error changing model, please check console for additional information"
|
"Error changing model, please check console for additional information",
|
||||||
|
{
|
||||||
|
type: NotificationType.ERROR,
|
||||||
|
timeout: config.notificationTimeout * 2,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1091,13 +1115,16 @@ async function getModels(refresh = false) {
|
||||||
These are highlighted as green in the model selector.";
|
These are highlighted as green in the model selector.";
|
||||||
|
|
||||||
if (inpainting) {
|
if (inpainting) {
|
||||||
message += `\n\nWe have found the inpainting model\n\n - ${inpainting.name}\n\navailable in the webui. Do you want to switch to it?`;
|
message += `<br><br>We have found the inpainting model<br><br> - ${inpainting.name}<br><br>available in the webui. Do you want to switch to it?`;
|
||||||
if (confirm(message)) {
|
if (await notifications.dialog("Automatic Model Switch", message)) {
|
||||||
modelAutoComplete.value = inpainting.value;
|
modelAutoComplete.value = inpainting.value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
message += `\n\nNo inpainting model seems to be available in the webui. It is recommended that you download an inpainting model, or outpainting results may not be optimal.`;
|
message += `<br><br>No inpainting model seems to be available in the webui. It is recommended that you download an inpainting model, or outpainting results may not be optimal.`;
|
||||||
alert(message);
|
notifications.notify(message, {
|
||||||
|
type: NotificationType.WARN,
|
||||||
|
timeout: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1118,16 +1145,17 @@ async function getConfig() {
|
||||||
// Check if img2img color correction is disabled and inpainting mask weight is set to one
|
// Check if img2img color correction is disabled and inpainting mask weight is set to one
|
||||||
// TODO: API Seems bugged for retrieving inpainting mask weight - returning 0 for all values different than 1.0
|
// TODO: API Seems bugged for retrieving inpainting mask weight - returning 0 for all values different than 1.0
|
||||||
if (data.img2img_color_correction) {
|
if (data.img2img_color_correction) {
|
||||||
message += "\n - Image to Image Color Correction: false recommended";
|
message += "<br> - Image to Image Color Correction: false recommended";
|
||||||
wrong = true;
|
wrong = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.inpainting_mask_weight < 1.0) {
|
if (data.inpainting_mask_weight < 1.0) {
|
||||||
message += `\n - Inpainting Conditioning Mask Strength: 1.0 recommended`;
|
message += `<br> - Inpainting Conditioning Mask Strength: 1.0 recommended`;
|
||||||
wrong = true;
|
wrong = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
message += "\n\nShould these values be changed to the recommended ones?";
|
message +=
|
||||||
|
"<br><br>Should these values be changed to the recommended ones?";
|
||||||
|
|
||||||
if (!wrong) {
|
if (!wrong) {
|
||||||
console.info("[index] WebUI Settings set as recommended.");
|
console.info("[index] WebUI Settings set as recommended.");
|
||||||
|
@ -1138,7 +1166,7 @@ async function getConfig() {
|
||||||
"[index] WebUI Settings not set as recommended. Prompting for changing settings automatically."
|
"[index] WebUI Settings not set as recommended. Prompting for changing settings automatically."
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!confirm(message)) return;
|
if (!(await notifications.dialog("Recommended Settings", message))) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fetch(url, {
|
await fetch(url, {
|
||||||
|
@ -1340,8 +1368,13 @@ imageCollection.element.addEventListener(
|
||||||
{passive: false}
|
{passive: false}
|
||||||
);
|
);
|
||||||
|
|
||||||
function resetToDefaults() {
|
async function resetToDefaults() {
|
||||||
if (confirm("Are you sure you want to clear your settings?")) {
|
if (
|
||||||
|
await notifications.dialog(
|
||||||
|
"Clear Settings",
|
||||||
|
"Are you sure you want to clear your settings?"
|
||||||
|
)
|
||||||
|
) {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,9 @@
|
||||||
id = guid();
|
id = guid();
|
||||||
workspaces.add({id, name, workspace}).onsuccess = () => {
|
workspaces.add({id, name, workspace}).onsuccess = () => {
|
||||||
listWorkspaces(id);
|
listWorkspaces(id);
|
||||||
alert(`Workspace saved as '${name}'`);
|
notifications.notify(`Workspace saved as '${name}'`, {
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,7 +95,9 @@
|
||||||
const ws = e.target.result;
|
const ws = e.target.result;
|
||||||
if (ws) {
|
if (ws) {
|
||||||
workspaces.put({id, workspace}).onsuccess = () => {
|
workspaces.put({id, workspace}).onsuccess = () => {
|
||||||
alert(`Workspace saved as '${ws.value.name}'`);
|
notifications.notify(`Workspace saved as '${ws.value.name}'`, {
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
listWorkspaces();
|
listWorkspaces();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -137,7 +141,7 @@
|
||||||
workspaces.get(id).onsuccess = (e) => {
|
workspaces.get(id).onsuccess = (e) => {
|
||||||
const workspace = e.target.result;
|
const workspace = e.target.result;
|
||||||
const name = prompt(
|
const name = prompt(
|
||||||
`Please enter the new workspace name.\nOriginal is '${workspace.name}'`
|
`Please enter the new workspace name.<br>Original is '${workspace.name}'`
|
||||||
).trim();
|
).trim();
|
||||||
|
|
||||||
if (!name) return;
|
if (!name) return;
|
||||||
|
@ -157,11 +161,12 @@
|
||||||
|
|
||||||
let id = workspaceAutocomplete.value;
|
let id = workspaceAutocomplete.value;
|
||||||
|
|
||||||
workspaces.get(id).onsuccess = (e) => {
|
workspaces.get(id).onsuccess = async (e) => {
|
||||||
const workspace = e.target.result;
|
const workspace = e.target.result;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
confirm(
|
await notifications.dialog(
|
||||||
|
"Delete Workspace",
|
||||||
`Do you really want to delete the workspace '${workspace.name}'?`
|
`Do you really want to delete the workspace '${workspace.name}'?`
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
180
js/lib/notifications.js
Normal file
180
js/lib/notifications.js
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/**
|
||||||
|
* Enum representing the location of the notifications
|
||||||
|
* @readonly
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
const NotificationLocation = {
|
||||||
|
TOPLEFT: "top-left",
|
||||||
|
TOPCENTER: "top-center",
|
||||||
|
TOPRIGHT: "top-right",
|
||||||
|
BOTTOMLEFT: "bottom-left",
|
||||||
|
BOTTOMCENTER: "bottom-center",
|
||||||
|
BOTTOMRIGHT: "bottom-right",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing notification types
|
||||||
|
* @readonly
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
const NotificationType = {
|
||||||
|
INFO: "info",
|
||||||
|
ERROR: "error",
|
||||||
|
WARN: "warn",
|
||||||
|
SUCCESS: "success",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for the notification system
|
||||||
|
*/
|
||||||
|
const notifications = {
|
||||||
|
/** @type {NotificationLocation} */
|
||||||
|
_location: NotificationLocation.BOTTOMLEFT,
|
||||||
|
/** @type {NotificationLocation} */
|
||||||
|
get location() {
|
||||||
|
return this.location;
|
||||||
|
},
|
||||||
|
/** @type {NotificationLocation} */
|
||||||
|
set location(location) {
|
||||||
|
this._location = location;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Notification Area Element
|
||||||
|
_areaEl: null,
|
||||||
|
|
||||||
|
// Dialog BG Element
|
||||||
|
_dialogBGEl: null,
|
||||||
|
// Dialog Element
|
||||||
|
_dialogEl: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a simple notification for the user. Equivalent to alert()
|
||||||
|
*
|
||||||
|
* @param {string | HTMLElement} message Message to display to the user.
|
||||||
|
* @param {Object} options Extra options for the notification.
|
||||||
|
* @param {NotificationType} type Notification type
|
||||||
|
*/
|
||||||
|
notify(message, options = {}) {
|
||||||
|
defaultOpt(options, {
|
||||||
|
type: NotificationType.INFO,
|
||||||
|
timeout: config.notificationTimeout,
|
||||||
|
});
|
||||||
|
|
||||||
|
const notificationEl = document.createElement("div");
|
||||||
|
notificationEl.classList.add("notification", "expanded", options.type);
|
||||||
|
notificationEl.title = new Date().toISOString();
|
||||||
|
notificationEl.addEventListener("click", () =>
|
||||||
|
notificationEl.classList.toggle("expanded")
|
||||||
|
);
|
||||||
|
|
||||||
|
const contentEl = document.createElement("div");
|
||||||
|
contentEl.classList.add("notification-content");
|
||||||
|
contentEl.innerHTML = message;
|
||||||
|
|
||||||
|
notificationEl.append(contentEl);
|
||||||
|
|
||||||
|
const closeBtn = document.createElement("button");
|
||||||
|
closeBtn.classList.add("notification-closebtn");
|
||||||
|
closeBtn.addEventListener("click", () => notificationEl.remove());
|
||||||
|
|
||||||
|
notificationEl.append(closeBtn);
|
||||||
|
|
||||||
|
this._areaEl.prepend(notificationEl);
|
||||||
|
if (options.timeout)
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this._areaEl.contains(notificationEl)) {
|
||||||
|
notificationEl.remove();
|
||||||
|
}
|
||||||
|
}, options.timeout);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a dialog box for the user with set options.
|
||||||
|
*
|
||||||
|
* @param {string} title The title of the dialog box to be displayed to the user.
|
||||||
|
* @param {string | HTMLElement} message The message to be displayed to the user.
|
||||||
|
* @param {Object} options Extra options for the dialog.
|
||||||
|
* @param {Array<{label: string, value: any}>} options.choices The choices to be displayed to the user.
|
||||||
|
*/
|
||||||
|
async dialog(title, message, options = {}) {
|
||||||
|
defaultOpt(options, {
|
||||||
|
// By default, it is a await notifications.dialogation dialog
|
||||||
|
choices: [
|
||||||
|
{label: "No", value: false},
|
||||||
|
{label: "Yes", value: true},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const titleEl = this._dialogEl.querySelector(".dialog-title");
|
||||||
|
titleEl.textContent = title;
|
||||||
|
|
||||||
|
const contentEl = this._dialogEl.querySelector(".dialog-content");
|
||||||
|
contentEl.innerHTML = message;
|
||||||
|
|
||||||
|
const choicesEl = this._dialogEl.querySelector(".dialog-choices");
|
||||||
|
while (choicesEl.firstChild) {
|
||||||
|
choicesEl.firstChild.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
options.choices.forEach((choice) => {
|
||||||
|
const choiceBtn = document.createElement("button");
|
||||||
|
choiceBtn.textContent = choice.label;
|
||||||
|
choiceBtn.addEventListener("click", () => {
|
||||||
|
this._dialogBGEl.style.display = "none";
|
||||||
|
this._dialogEl.style.display = "none";
|
||||||
|
|
||||||
|
resolve(choice.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
choicesEl.append(choiceBtn);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._dialogBGEl.style.display = "flex";
|
||||||
|
this._dialogEl.style.display = "block";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var k = 0;
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
// Creates the notification area
|
||||||
|
const notificationArea = document.createElement("div");
|
||||||
|
notificationArea.classList.add(
|
||||||
|
"notification-area",
|
||||||
|
NotificationLocation.BOTTOMLEFT
|
||||||
|
);
|
||||||
|
|
||||||
|
notifications._areaEl = notificationArea;
|
||||||
|
|
||||||
|
document.body.appendChild(notificationArea);
|
||||||
|
|
||||||
|
// Creates the dialog box element
|
||||||
|
const dialogBG = document.createElement("div");
|
||||||
|
dialogBG.classList.add("dialog-bg");
|
||||||
|
dialogBG.style.display = "none";
|
||||||
|
|
||||||
|
const dialogEl = document.createElement("div");
|
||||||
|
dialogEl.classList.add("dialog");
|
||||||
|
dialogEl.style.display = "none";
|
||||||
|
|
||||||
|
const titleEl = document.createElement("div");
|
||||||
|
titleEl.classList.add("dialog-title");
|
||||||
|
|
||||||
|
const contentEl = document.createElement("div");
|
||||||
|
contentEl.classList.add("dialog-content");
|
||||||
|
|
||||||
|
const choicesEl = document.createElement("div");
|
||||||
|
choicesEl.classList.add("dialog-choices");
|
||||||
|
|
||||||
|
dialogEl.append(titleEl);
|
||||||
|
dialogEl.append(contentEl);
|
||||||
|
dialogEl.append(choicesEl);
|
||||||
|
|
||||||
|
dialogBG.append(dialogEl);
|
||||||
|
|
||||||
|
notifications._dialogEl = dialogEl;
|
||||||
|
notifications._dialogBGEl = dialogBG;
|
||||||
|
|
||||||
|
document.body.appendChild(dialogBG);
|
||||||
|
});
|
|
@ -173,7 +173,16 @@ const _toolbar_input = {
|
||||||
label.appendChild(checkbox);
|
label.appendChild(checkbox);
|
||||||
label.appendChild(new Text(text));
|
label.appendChild(new Text(text));
|
||||||
|
|
||||||
return {checkbox, label};
|
return {
|
||||||
|
checkbox,
|
||||||
|
label,
|
||||||
|
setValue(v) {
|
||||||
|
checkbox.checked = v;
|
||||||
|
state[dataKey] = checkbox.checked;
|
||||||
|
cb && cb();
|
||||||
|
return checkbox.checked;
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
slider: (state, dataKey, text, options = {}) => {
|
slider: (state, dataKey, text, options = {}) => {
|
||||||
|
|
|
@ -459,8 +459,12 @@ const _generate = async (endpoint, request, bb, options = {}) => {
|
||||||
stopDrawingStatus = true;
|
stopDrawingStatus = true;
|
||||||
at = 1;
|
at = 1;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert(
|
notifications.notify(
|
||||||
`Error generating images. Please try again or see console for more details`
|
`Error generating images. Please try again or see console for more details`,
|
||||||
|
{
|
||||||
|
type: NotificationType.ERROR,
|
||||||
|
timeout: config.notificationTimeout * 2,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
console.warn(`[dream] Error generating images:`);
|
console.warn(`[dream] Error generating images:`);
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
|
@ -614,8 +618,12 @@ const _generate = async (endpoint, request, bb, options = {}) => {
|
||||||
imageindextxt.textContent = `${at}/${images.length - 1}`;
|
imageindextxt.textContent = `${at}/${images.length - 1}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (alertCount < 2) {
|
if (alertCount < 2) {
|
||||||
alert(
|
notifications.notify(
|
||||||
`Error generating images. Please try again or see console for more details`
|
`Error generating images. Please try again or see console for more details`,
|
||||||
|
{
|
||||||
|
type: NotificationType.ERROR,
|
||||||
|
timeout: config.notificationTimeout * 2,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
eagerGenerateCount = 0;
|
eagerGenerateCount = 0;
|
||||||
|
|
|
@ -735,21 +735,11 @@ const selectTransformTool = () =>
|
||||||
saveVisibleSelectionButton.textContent = "Save Vis.";
|
saveVisibleSelectionButton.textContent = "Save Vis.";
|
||||||
saveVisibleSelectionButton.title = "Saves Visible Selection";
|
saveVisibleSelectionButton.title = "Saves Visible Selection";
|
||||||
saveVisibleSelectionButton.onclick = () => {
|
saveVisibleSelectionButton.onclick = () => {
|
||||||
const canvas = uil.getVisible(
|
console.debug(state.selected);
|
||||||
{
|
console.debug(state.selected.bb);
|
||||||
x:
|
const canvas = uil.getVisible(state._selected.bb, {
|
||||||
state._selected._position.x -
|
|
||||||
state._selected.canvas.width / 2,
|
|
||||||
y:
|
|
||||||
state._selected._position.y -
|
|
||||||
state._selected.canvas.height / 2,
|
|
||||||
w: state._selected.canvas.width,
|
|
||||||
h: state._selected.canvas.height,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
categories: ["image", "user", "select-display"],
|
categories: ["image", "user", "select-display"],
|
||||||
}
|
});
|
||||||
);
|
|
||||||
downloadCanvas({
|
downloadCanvas({
|
||||||
cropToContent: false,
|
cropToContent: false,
|
||||||
canvas,
|
canvas,
|
||||||
|
@ -763,21 +753,9 @@ const selectTransformTool = () =>
|
||||||
createVisibleResourceButton.title =
|
createVisibleResourceButton.title =
|
||||||
"Saves Visible Selection as a Resource";
|
"Saves Visible Selection as a Resource";
|
||||||
createVisibleResourceButton.onclick = () => {
|
createVisibleResourceButton.onclick = () => {
|
||||||
const canvas = uil.getVisible(
|
const canvas = uil.getVisible(state._selected.bb, {
|
||||||
{
|
|
||||||
x:
|
|
||||||
state._selected._position.x -
|
|
||||||
state._selected.canvas.width / 2,
|
|
||||||
y:
|
|
||||||
state._selected._position.y -
|
|
||||||
state._selected.canvas.height / 2,
|
|
||||||
w: state._selected.canvas.width,
|
|
||||||
h: state._selected.canvas.height,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
categories: ["image", "user", "select-display"],
|
categories: ["image", "user", "select-display"],
|
||||||
}
|
});
|
||||||
);
|
|
||||||
const image = document.createElement("img");
|
const image = document.createElement("img");
|
||||||
image.src = canvas.toDataURL();
|
image.src = canvas.toDataURL();
|
||||||
image.onload = () => {
|
image.onload = () => {
|
||||||
|
|
|
@ -57,6 +57,8 @@ const stampTool = () =>
|
||||||
mouse.listen.world.btn.left.ondragend.on(state.dragendcb);
|
mouse.listen.world.btn.left.ondragend.on(state.dragendcb);
|
||||||
|
|
||||||
mouse.listen.world.onwheel.on(state.onwheelcb);
|
mouse.listen.world.onwheel.on(state.onwheelcb);
|
||||||
|
keyboard.onShortcut({key: "Minus"}, state.toggleflip);
|
||||||
|
keyboard.onShortcut({key: "Equal"}, state.togglemirror);
|
||||||
|
|
||||||
// For calls from other tools to paste image
|
// For calls from other tools to paste image
|
||||||
if (opt && opt.image) {
|
if (opt && opt.image) {
|
||||||
|
@ -90,6 +92,8 @@ const stampTool = () =>
|
||||||
mouse.listen.world.btn.left.ondragend.clear(state.dragendcb);
|
mouse.listen.world.btn.left.ondragend.clear(state.dragendcb);
|
||||||
|
|
||||||
mouse.listen.world.onwheel.clear(state.onwheelcb);
|
mouse.listen.world.onwheel.clear(state.onwheelcb);
|
||||||
|
keyboard.deleteShortcut(state.togglemirror, "Delete");
|
||||||
|
keyboard.deleteShortcut(state.toggleflip, "Delete");
|
||||||
|
|
||||||
ovLayer.clear();
|
ovLayer.clear();
|
||||||
},
|
},
|
||||||
|
@ -110,11 +114,24 @@ const stampTool = () =>
|
||||||
// Current Scale
|
// Current Scale
|
||||||
state.scale = 1;
|
state.scale = 1;
|
||||||
|
|
||||||
|
state.togglemirror = () => {
|
||||||
|
state.mirrorSetValue(!state.mirrorStamp);
|
||||||
|
state.redraw();
|
||||||
|
};
|
||||||
|
|
||||||
|
state.toggleflip = () => {
|
||||||
|
state.flipSetValue(!state.flipStamp);
|
||||||
|
state.redraw();
|
||||||
|
};
|
||||||
|
|
||||||
state.selectResource = (resource, nolock = true, deselect = true) => {
|
state.selectResource = (resource, nolock = true, deselect = true) => {
|
||||||
rotation = 0;
|
rotation = 0;
|
||||||
state.setScale(1);
|
state.setScale(1);
|
||||||
if (nolock && state.ctxmenu.uploadButton.disabled) return;
|
if (nolock && state.ctxmenu.uploadButton.disabled) return;
|
||||||
|
|
||||||
|
state.mirrorSetValue(false);
|
||||||
|
state.flipSetValue(false);
|
||||||
|
|
||||||
console.debug(
|
console.debug(
|
||||||
`[stamp] Selecting Resource '${resource && resource.name}'[${
|
`[stamp] Selecting Resource '${resource && resource.name}'[${
|
||||||
resource && resource.id
|
resource && resource.id
|
||||||
|
@ -394,8 +411,11 @@ const stampTool = () =>
|
||||||
if (state.selected) {
|
if (state.selected) {
|
||||||
ovCtx.save();
|
ovCtx.save();
|
||||||
ovCtx.translate(px, py);
|
ovCtx.translate(px, py);
|
||||||
ovCtx.scale(state.scale, state.scale);
|
ovCtx.scale(
|
||||||
ovCtx.rotate(rotation);
|
state.scale * (state.mirrorStamp ? -1 : 1),
|
||||||
|
state.scale * (state.flipStamp ? -1 : 1) //flip vertical?????
|
||||||
|
);
|
||||||
|
ovCtx.rotate(rotation * (state.mirrorStamp ? -1 : 1));
|
||||||
|
|
||||||
ovCtx.drawImage(state.selected.image, 0, 0);
|
ovCtx.drawImage(state.selected.image, 0, 0);
|
||||||
ovCtx.restore();
|
ovCtx.restore();
|
||||||
|
@ -493,7 +513,30 @@ const stampTool = () =>
|
||||||
"icon-grid"
|
"icon-grid"
|
||||||
).checkbox
|
).checkbox
|
||||||
);
|
);
|
||||||
state.ctxmenu.snapToGridLabel = array;
|
|
||||||
|
// Flip Stamp Checkbox
|
||||||
|
const {checkbox: flipCheckbox, setValue: flipSetValue} =
|
||||||
|
_toolbar_input.checkbox(
|
||||||
|
state,
|
||||||
|
"flipStamp",
|
||||||
|
"Flip Stamp",
|
||||||
|
"icon-flip-vertical"
|
||||||
|
);
|
||||||
|
array.appendChild(flipCheckbox);
|
||||||
|
state.flipSetValue = flipSetValue;
|
||||||
|
|
||||||
|
// Mirror Stamp Checkbox
|
||||||
|
const {checkbox: mirrorCheckbox, setValue: mirrorSetValue} =
|
||||||
|
_toolbar_input.checkbox(
|
||||||
|
state,
|
||||||
|
"mirrorStamp",
|
||||||
|
"Mirror Stamp",
|
||||||
|
"icon-flip-horizontal"
|
||||||
|
);
|
||||||
|
array.appendChild(mirrorCheckbox);
|
||||||
|
state.mirrorSetValue = mirrorSetValue;
|
||||||
|
|
||||||
|
state.ctxmenu.buttonArray = array;
|
||||||
|
|
||||||
// Scale Slider
|
// Scale Slider
|
||||||
const scaleSlider = _toolbar_input.slider(state, "scale", "Scale", {
|
const scaleSlider = _toolbar_input.slider(state, "scale", "Scale", {
|
||||||
|
@ -629,7 +672,7 @@ const stampTool = () =>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
populateContextMenu: (menu, state) => {
|
populateContextMenu: (menu, state) => {
|
||||||
menu.appendChild(state.ctxmenu.snapToGridLabel);
|
menu.appendChild(state.ctxmenu.buttonArray);
|
||||||
menu.appendChild(state.ctxmenu.scaleSlider);
|
menu.appendChild(state.ctxmenu.scaleSlider);
|
||||||
menu.appendChild(state.ctxmenu.resourceManager);
|
menu.appendChild(state.ctxmenu.resourceManager);
|
||||||
},
|
},
|
||||||
|
|
15
js/webui.js
15
js/webui.js
|
@ -104,7 +104,7 @@
|
||||||
if (data.host)
|
if (data.host)
|
||||||
setFixedHost(
|
setFixedHost(
|
||||||
data.host,
|
data.host,
|
||||||
`Are you sure you want to modify the host?\nThis configuration was provided by the hosting page\n - ${parentWindow.document.title} (${origin})`
|
`Are you sure you want to modify the host?<br>This configuration was provided by the hosting page:<br> - ${parentWindow.document.title} (${origin})`
|
||||||
);
|
);
|
||||||
if (data.destinations) webui.destinations = data.destinations;
|
if (data.destinations) webui.destinations = data.destinations;
|
||||||
|
|
||||||
|
@ -118,6 +118,19 @@
|
||||||
data.image.resourceName || "External Resource",
|
data.image.resourceName || "External Resource",
|
||||||
image
|
image
|
||||||
);
|
);
|
||||||
|
// Fit image on screen if too big
|
||||||
|
const wr = image.width / window.innerWidth;
|
||||||
|
const hr = image.height / window.innerHeight;
|
||||||
|
const mr = Math.max(wr, hr);
|
||||||
|
|
||||||
|
if (mr > viewport.zoom) {
|
||||||
|
viewport.zoom = mr * 1.3;
|
||||||
|
viewport.transform(imageCollection.element);
|
||||||
|
|
||||||
|
toolbar._current_tool.redrawui &&
|
||||||
|
toolbar._current_tool.redrawui();
|
||||||
|
}
|
||||||
|
|
||||||
tools.stamp.enable();
|
tools.stamp.enable();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
<title>openOutpaint 🐠</title>
|
<title>openOutpaint 🐠</title>
|
||||||
<!-- CSS Variables -->
|
<!-- CSS Variables -->
|
||||||
<link href="../css/colors.css?v=f732f19" rel="stylesheet" />
|
<link href="../css/colors.css?v=f732f19" rel="stylesheet" />
|
||||||
<link href="../css/icons.css?v=599e732" rel="stylesheet" />
|
<link href="../css/icons.css?v=2b76310" rel="stylesheet" />
|
||||||
|
|
||||||
|
<link href="../css/index.css?v=cf21c6a" rel="stylesheet" />
|
||||||
<link href="../css/layers.css?v=92c0352" rel="stylesheet" />
|
<link href="../css/layers.css?v=92c0352" rel="stylesheet" />
|
||||||
|
|
||||||
<link href="../css/ui/generic.css?v=30837f8" rel="stylesheet" />
|
<link href="../css/ui/generic.css?v=30837f8" rel="stylesheet" />
|
||||||
|
|
9
res/icons/flip-horizontal.svg
Normal file
9
res/icons/flip-horizontal.svg
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M8 3H5a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h3"></path>
|
||||||
|
<path d="M16 3h3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-3"></path>
|
||||||
|
<path d="M12 20v2"></path>
|
||||||
|
<path d="M12 14v2"></path>
|
||||||
|
<path d="M12 8v2"></path>
|
||||||
|
<path d="M12 2v2"></path>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 425 B |
9
res/icons/flip-vertical.svg
Normal file
9
res/icons/flip-vertical.svg
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M21 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v3"></path>
|
||||||
|
<path d="M21 16v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-3"></path>
|
||||||
|
<path d="M4 12H2"></path>
|
||||||
|
<path d="M10 12H8"></path>
|
||||||
|
<path d="M16 12h-2"></path>
|
||||||
|
<path d="M22 12h-2"></path>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 428 B |
Loading…
Reference in a new issue