Should mostly solve #94

Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
Victor Seiji Hariki 2022-12-14 15:12:44 -03:00
parent 0c5ed4a17e
commit 5e6b18503b
2 changed files with 127 additions and 33 deletions

View file

@ -2,15 +2,27 @@
* Some type definitions before the actual code * Some type definitions before the actual code
*/ */
/** /**
* Represents a simple bounding box * Represents a simple bouding box
*
* @typedef BoundingBox
* @type {Object}
* @property {number} x - Leftmost coordinate of the box
* @property {number} y - Topmost coordinate of the box
* @property {number} w - The bounding box Width
* @property {number} h - The bounding box Height
*/ */
class BoundingBox {
x = 0;
y = 0;
w = 0;
h = 0;
constructor({x, y, w, h} = {x: 0, y: 0, w: 0, h: 0}) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
contains(x, y) {
return (
this.x < x && this.y < y && x < this.x + this.w && y < this.y + this.h
);
}
}
/** /**
* A simple implementation of the Observer programming pattern * A simple implementation of the Observer programming pattern
@ -19,28 +31,34 @@
class Observer { class Observer {
/** /**
* List of handlers * List of handlers
* @type {Set<(msg: T) => void | Promise<void>>} * @type {Array<{handler: (msg: T) => void | Promise<void>, priority: number}>}
*/ */
_handlers = new Set(); _handlers = [];
/** /**
* Adds a observer to the events * Adds a observer to the events
* *
* @param {(msg: T) => void | Promise<void>} callback The function to run when receiving a message * @param {(msg: T, state?: any) => void | Promise<void>} callback The function to run when receiving a message
* @returns {(msg:T) => void | Promise<void>} The callback we received * @param {number} priority The priority level of the observer
* @param {boolean} wait If the handler must be waited for before continuing
* @returns {(msg:T, state?: any) => void | Promise<void>} The callback we received
*/ */
on(callback) { on(callback, priority = 0, wait = false) {
this._handlers.add(callback); this._handlers.push({handler: callback, priority, wait});
this._handlers.sort((a, b) => b.priority - a.priority);
return callback; return callback;
} }
/** /**
* Removes a observer * Removes a observer
* *
* @param {(msg: T) => void | Promise<void>} callback The function used to register the callback * @param {(msg: T, state?: any) => void | Promise<void>} callback The function used to register the callback
* @returns {boolean} Whether the handler existed * @returns {boolean} Whether the handler existed
*/ */
clear(callback) { clear(callback) {
return this._handlers.delete(callback); const index = this._handlers.findIndex((v) => v.handler === callback);
if (index === -1) return false;
this._handlers.splice(index, 1);
return true;
} }
/** /**
* Sends a message to all observers * Sends a message to all observers
@ -48,16 +66,23 @@ class Observer {
* @param {T} msg The message to send to the observers * @param {T} msg The message to send to the observers
*/ */
async emit(msg) { async emit(msg) {
return Promise.all( const state = {};
Array.from(this._handlers).map(async (handler) => { const promises = [];
for (const {handler, wait} of this._handlers) {
const run = async () => {
try { try {
await handler(msg); await handler(msg, state);
} catch (e) { } catch (e) {
console.warn("Observer failed to run handler"); console.warn("Observer failed to run handler");
console.warn(e); console.warn(e);
} }
}) };
);
if (wait) await run();
else promises.push(run());
}
return Promise.all(promises);
} }
} }
@ -211,12 +236,12 @@ function getBoundingBox(cx, cy, w, h, gridSnap = null, offset = 0) {
box.x = Math.round(offs.x + cx); box.x = Math.round(offs.x + cx);
box.y = Math.round(offs.y + cy); box.y = Math.round(offs.y + cy);
return { return new BoundingBox({
x: Math.floor(box.x - w / 2), x: Math.floor(box.x - w / 2),
y: Math.floor(box.y - h / 2), y: Math.floor(box.y - h / 2),
w: Math.round(w), w: Math.round(w),
h: Math.round(h), h: Math.round(h),
}; });
} }
class NoContentError extends Error {} class NoContentError extends Error {}
@ -236,7 +261,7 @@ function cropCanvas(sourceCanvas, options = {}) {
const h = sourceCanvas.height; const h = sourceCanvas.height;
var imageData = sourceCanvas.getContext("2d").getImageData(0, 0, w, h); var imageData = sourceCanvas.getContext("2d").getImageData(0, 0, w, h);
/** @type {BoundingBox} */ /** @type {BoundingBox} */
const bb = {x: 0, y: 0, w: 0, h: 0}; const bb = new BoundingBox();
let minx = w; let minx = w;
let maxx = -1; let maxx = -1;

View file

@ -291,7 +291,8 @@ const _generate = async (endpoint, request, bb, options = {}) => {
fetch(`${host}${url}interrupt`, {method: "POST"}); fetch(`${host}${url}interrupt`, {method: "POST"});
interruptButton.disabled = true; interruptButton.disabled = true;
}); });
const stopMarchingAnts = march(bb); const marchingOptions = {};
const stopMarchingAnts = march(bb, marchingOptions);
// First Dream Run // First Dream Run
console.info(`[dream] Generating images for prompt '${request.prompt}'`); console.info(`[dream] Generating images for prompt '${request.prompt}'`);
@ -471,6 +472,62 @@ const _generate = async (endpoint, request, bb, options = {}) => {
keyboard.listen.onkeyclick.on(onarrow); keyboard.listen.onkeyclick.on(onarrow);
// For handling mouse events for navigation
const onmovehandler = mouse.listen.world.onmousemove.on(
(evn, state) => {
const contains = bb.contains(evn.x, evn.y);
if (!contains && !state.dream_processed)
imageCollection.inputElement.style.cursor = "auto";
if (!contains || state.dream_processed) marchingOptions.style = "#FFF";
if (!state.dream_processed && contains) {
marchingOptions.style = "#F55";
imageCollection.inputElement.style.cursor = "pointer";
state.dream_processed = true;
}
},
0,
true
);
const onclickhandler = mouse.listen.world.btn.left.onclick.on(
(evn, state) => {
if (!state.dream_processed && bb.contains(evn.x, evn.y)) {
applyImg();
imageCollection.inputElement.style.cursor = "auto";
state.dream_processed = true;
}
},
1,
true
);
const oncancelhandler = mouse.listen.world.btn.right.onclick.on(
(evn, state) => {
if (!state.dream_processed && bb.contains(evn.x, evn.y)) {
discardImg();
imageCollection.inputElement.style.cursor = "auto";
state.dream_processed = true;
}
},
1,
true
);
const onwheelhandler = mouse.listen.world.onwheel.on(
(evn, state) => {
console.debug(evn, state);
if (!state.dream_processed && bb.contains(evn.x, evn.y)) {
if (evn.delta < 0) nextImg();
else prevImg();
state.dream_processed = true;
}
},
1,
true
);
// Cleans up // Cleans up
const clean = (removeBrushMask = false) => { const clean = (removeBrushMask = false) => {
if (removeBrushMask) { if (removeBrushMask) {
@ -482,6 +539,12 @@ const _generate = async (endpoint, request, bb, options = {}) => {
keyboard.listen.onkeyclick.clear(onarrow); keyboard.listen.onkeyclick.clear(onarrow);
// Remove area from no-generate list // Remove area from no-generate list
generationAreas.delete(areaid); generationAreas.delete(areaid);
// Stop handling inputs
mouse.listen.world.onmousemove.clear(onmovehandler);
mouse.listen.world.onwheel.clear(onwheelhandler);
mouse.listen.world.btn.left.onclick.clear(onclickhandler);
mouse.listen.world.btn.right.onclick.clear(oncancelhandler);
}; };
redraw(); redraw();
@ -1097,7 +1160,7 @@ const dreamTool = () =>
}; };
if (state.selected) { if (state.selected) {
const bb = {x: 0, y: 0, w: 0, h: 0}; const bb = new BoundingBox();
const minx = Math.min(state.selected.now.x, state.selected.start.x); const minx = Math.min(state.selected.now.x, state.selected.start.x);
const miny = Math.min(state.selected.now.y, state.selected.start.y); const miny = Math.min(state.selected.now.y, state.selected.start.y);
@ -1167,10 +1230,12 @@ const dreamTool = () =>
state.mousemovecb(state.lastMouseMove); state.mousemovecb(state.lastMouseMove);
}; };
state.wheelcb = (evn) => { state.wheelcb = (evn, estate) => {
if (estate.dream_processed) return;
_dream_onwheel(evn, state); _dream_onwheel(evn, state);
}; };
state.dreamcb = (evn) => { state.dreamcb = (evn, estate) => {
if (estate.dream_processed) return;
const bb = const bb =
(state.selected && state.selected.bb) || (state.selected && state.selected.bb) ||
getBoundingBox( getBoundingBox(
@ -1187,12 +1252,13 @@ const dreamTool = () =>
dream_generate_callback(bb, resolution, state); dream_generate_callback(bb, resolution, state);
state.selected = null; state.selected = null;
}; };
state.erasecb = (evn) => { state.erasecb = (evn, estate) => {
if (state.selected) { if (state.selected) {
state.selected = null; state.selected = null;
state.redraw(); state.redraw();
return; return;
} }
if (estate.dream_processed) return;
const bb = getBoundingBox( const bb = getBoundingBox(
evn.x, evn.x,
evn.y, evn.y,
@ -1419,7 +1485,7 @@ const img2imgTool = () =>
let request = null; let request = null;
if (state.selected) { if (state.selected) {
bb = {x: 0, y: 0, w: 0, h: 0}; bb = new BoundingBox();
const minx = Math.min(state.selected.now.x, state.selected.start.x); const minx = Math.min(state.selected.now.x, state.selected.start.x);
const miny = Math.min(state.selected.now.y, state.selected.start.y); const miny = Math.min(state.selected.now.y, state.selected.start.y);
@ -1580,10 +1646,12 @@ const img2imgTool = () =>
state.mousemovecb(state.lastMouseMove); state.mousemovecb(state.lastMouseMove);
}; };
state.wheelcb = (evn) => { state.wheelcb = (evn, estate) => {
if (estate.dream_processed) return;
_dream_onwheel(evn, state); _dream_onwheel(evn, state);
}; };
state.dreamcb = (evn) => { state.dreamcb = (evn, estate) => {
if (estate.dream_processed) return;
const bb = const bb =
(state.selected && state.selected.bb) || (state.selected && state.selected.bb) ||
getBoundingBox( getBoundingBox(
@ -1601,7 +1669,8 @@ const img2imgTool = () =>
state.selected = null; state.selected = null;
state.redraw(); state.redraw();
}; };
state.erasecb = (evn) => { state.erasecb = (evn, estate) => {
if (estate.dream_processed) return;
if (state.selected) { if (state.selected) {
state.selected = null; state.selected = null;
state.redraw(); state.redraw();