diff --git a/css/colors.css b/css/colors.css
index 1dba78a..984592d 100644
--- a/css/colors.css
+++ b/css/colors.css
@@ -2,6 +2,7 @@
--c-primary: #2c3333;
--c-hover: hsl(180, 7%, 30%);
--c-active: hsl(180, 7%, 25%);
+ --c-primary-accent: hsl(180, 7%, 40%);
--c-secondary: #395b64;
--c-accent: #a5c9ca;
--c-text: #e7f6f2;
diff --git a/css/ui/generic.css b/css/ui/generic.css
index b8c4556..deed60d 100644
--- a/css/ui/generic.css
+++ b/css/ui/generic.css
@@ -30,3 +30,68 @@
.draggable {
cursor: move;
}
+
+/* Slider Input */
+div.slider-wrapper {
+ margin: 5px;
+}
+
+div.slider-wrapper {
+ position: relative;
+ height: 20px;
+ border-radius: 5px;
+}
+
+div.slider-wrapper * {
+ height: 20px;
+ border-radius: 5px;
+ margin: 0;
+}
+
+div.slider-wrapper > * {
+ position: absolute;
+ padding: inherit;
+ width: 100%;
+
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+
+ overflow: hidden;
+}
+
+div.slider-wrapper > div.under {
+ display: flex;
+ background-color: var(--c-primary-accent);
+}
+div.slider-wrapper > div.under > div:first-child {
+ background-color: var(--c-primary);
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+div.slider-wrapper > div.under > div:last-child {
+ flex: 1;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+div.slider-wrapper > div.under > * {
+ height: 100%;
+}
+
+div.slider-wrapper > div.over {
+ cursor: pointer;
+}
+
+div.slider-wrapper > input.text {
+ color: var(--c-text);
+
+ flex: 1;
+ appearance: textfield;
+ border: 0px;
+
+ padding-top: 5px;
+ height: 15px;
+ text-align: center;
+ background-color: transparent;
+}
diff --git a/index.html b/index.html
index dadf004..9296222 100644
--- a/index.html
+++ b/index.html
@@ -68,66 +68,19 @@ people, person, humans, human, divers, diver, glitch, error, text, watermark, ba
value="-1"
step="1" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
+
+
+ type="checkbox"
+ id="cbxSnap"
+ onchange="changeSnapMode()"
+ checked="checked" />
diff --git a/js/index.js b/js/index.js
index ee88c30..9ef9059 100644
--- a/js/index.js
+++ b/js/index.js
@@ -47,62 +47,6 @@ var stableDiffusionData = {
// "include_init_images": false // ??????
};
-/**
- * Some Utility Functions
- */
-function sliderChangeHandlerFactory(
- sliderId,
- textBoxId,
- dataKey,
- defaultV,
- save = true,
- setter = (k, v) => (stableDiffusionData[k] = v),
- getter = (k) => stableDiffusionData[k]
-) {
- return sliderChangeHandlerFactoryEl(
- document.getElementById(sliderId),
- document.getElementById(textBoxId),
- dataKey,
- defaultV,
- save,
- setter,
- getter
- );
-}
-
-function sliderChangeHandlerFactoryEl(
- sliderEl,
- textBoxEl,
- dataKey,
- defaultV,
- save = true,
- setter = (k, v) => (stableDiffusionData[k] = v),
- getter = (k) => stableDiffusionData[k]
-) {
- const savedValue = save && localStorage.getItem(dataKey);
-
- if (savedValue) setter(dataKey, savedValue || defaultV);
-
- function changeHandler(evn) {
- const eventSource = evn && evn.srcElement;
- const value = eventSource && Number(eventSource.value);
-
- if (value) setter(dataKey, value);
-
- if (!eventSource || eventSource === textBoxEl)
- sliderEl.value = getter(dataKey);
- setter(dataKey, Number(sliderEl.value));
- textBoxEl.value = getter(dataKey);
-
- if (save) localStorage.setItem(dataKey, getter(dataKey));
- }
-
- textBoxEl.onchange = changeHandler;
- sliderEl.oninput = changeHandler;
-
- return changeHandler;
-}
-
// stuff things use
var blockNewImages = false;
var returnedImages;
@@ -175,12 +119,8 @@ function startup() {
getUpscalers();
getModels();
drawBackground();
- changeScaleFactor();
changeSampler();
- changeSteps();
- changeCfgScale();
- changeBatchCount();
- changeBatchSize();
+ changeSnapMode();
changeMaskBlur();
changeSeed();
changeOverMaskPx();
@@ -542,39 +482,77 @@ function changeSampler() {
}
}
-const changeCfgScale = sliderChangeHandlerFactory(
- "cfgScale",
- "cfgScaleTxt",
+const makeSlider = (
+ label,
+ el,
+ lsKey,
+ min,
+ max,
+ step,
+ defaultValue,
+ valuecb = null
+) => {
+ const local = localStorage.getItem(lsKey);
+ const def = parseFloat(local === null ? defaultValue : local);
+ return createSlider(label, el, {
+ valuecb:
+ valuecb ||
+ ((v) => {
+ stableDiffusionData[lsKey] = v;
+ localStorage.setItem(lsKey, v);
+ }),
+ min,
+ max,
+ step,
+ defaultValue: def,
+ });
+};
+
+makeSlider(
+ "CFG Scale",
+ document.getElementById("cfgScale"),
"cfg_scale",
+ -1,
+ 25,
+ 0.5,
7.0
);
-const changeBatchSize = sliderChangeHandlerFactory(
- "batchSize",
- "batchSizeText",
+makeSlider(
+ "Batch Size",
+ document.getElementById("batchSize"),
"batch_size",
- 2
-);
-const changeBatchCount = sliderChangeHandlerFactory(
- "batchCount",
- "batchCountText",
- "n_iter",
- 2
-);
-const changeScaleFactor = sliderChangeHandlerFactory(
- "scaleFactor",
- "scaleFactorTxt",
- "scaleFactor",
+ 1,
8,
- true,
- (k, v) => (scaleFactor = v),
- (k) => scaleFactor
+ 1,
+ 2
);
-const changeSteps = sliderChangeHandlerFactory(
- "steps",
- "stepsTxt",
- "steps",
- 30
+makeSlider(
+ "Iterations",
+ document.getElementById("batchCount"),
+ "n_iter",
+ 1,
+ 8,
+ 1,
+ 2
);
+makeSlider(
+ "Scale Factor",
+ document.getElementById("scaleFactor"),
+ "scale_factor",
+ 1,
+ 16,
+ 1,
+ 8,
+ (v) => {
+ scaleFactor = v;
+ }
+);
+
+makeSlider("Steps", document.getElementById("steps"), "steps", 1, 70, 1, 30);
+
+function changeSnapMode() {
+ snapToGrid = document.getElementById("cbxSnap").checked;
+}
function changeMaskBlur() {
stableDiffusionData.mask_blur = document.getElementById("maskBlur").value;
diff --git a/js/input.js b/js/input.js
index 20d4888..ba1ed32 100644
--- a/js/input.js
+++ b/js/input.js
@@ -3,32 +3,13 @@ const inputConfig = {
clickTiming: 500, // Timing window to be considered a click (ms). If longer, turns into a drag
dClickTiming: 500, // Timing window to be considered a double click (ms).
- keyboardHoldTiming: 100, // Timing window after which to consider holding a key (ms)
+ keyboardHoldTiming: 1000, // Timing window after which to consider holding a key (ms)
};
/**
* Mouse input processing
*/
// Base object generator functions
-function _context_coords() {
- return {
- dragging: {
- left: null,
- middle: null,
- right: null,
- },
-
- prev: {
- x: 0,
- y: 0,
- },
-
- pos: {
- x: 0,
- y: 0,
- },
- };
-}
function _mouse_observers() {
return {
// Simple click handler
@@ -46,229 +27,286 @@ function _mouse_observers() {
};
}
-function _context_observers() {
- return {
- onwheel: new Observer(),
- onmousemove: new Observer(),
- left: _mouse_observers(),
- middle: _mouse_observers(),
- right: _mouse_observers(),
- };
-}
-
const mouse = {
- buttons: {
- right: null,
- left: null,
- middle: null,
- },
+ contexts: [],
+ buttons: {},
+ coords: {},
- // Mouse Actions in Window Coordinates
- window: _context_coords(),
+ listen: {},
- // Mouse Actions in Canvas Coordinates
- canvas: _context_coords(),
+ // Register Context
+ registerContext: (name, onmove, options = {}) => {
+ // Options
+ defaultOpt(options, {
+ target: null,
+ buttons: {0: "left", 1: "middle", 2: "right"},
+ });
- // Mouse Actions in World Coordinates
- world: _context_coords(),
+ // Context information
+ const context = {
+ id: guid(),
+ name,
+ onmove,
+ target: options.target,
+ buttons: options.buttons,
+ };
- listen: {
- window: _context_observers(),
- canvas: _context_observers(),
- world: _context_observers(),
+ // Coordinate information
+ mouse.coords[name] = {
+ dragging: {},
+
+ prev: {
+ x: 0,
+ y: 0,
+ },
+
+ pos: {
+ x: 0,
+ y: 0,
+ },
+ };
+
+ // Listeners
+ mouse.listen[name] = {
+ onwheel: new Observer(),
+ onmousemove: new Observer(),
+ };
+
+ // Button specific items
+ Object.keys(options.buttons).forEach((index) => {
+ const button = options.buttons[index];
+ mouse.coords[name].dragging[button] = null;
+ mouse.listen[name][button] = _mouse_observers();
+ });
+
+ // Add to context
+ context.coords = mouse.coords[name];
+ context.listen = mouse.listen[name];
+
+ // Add to list
+ mouse.contexts.push(context);
+
+ return context;
},
};
-function _mouse_state_snapshot() {
- return {
- buttons: window.structuredClone(mouse.buttons),
- window: window.structuredClone(mouse.window),
- canvas: window.structuredClone(mouse.canvas),
- world: window.structuredClone(mouse.world),
- };
-}
-
const _double_click_timeout = {};
const _drag_start_timeout = {};
window.onmousedown = (evn) => {
- const time = new Date();
+ const time = performance.now();
- // Processes for a named button
- const onhold = (key) => () => {
- if (_double_click_timeout[key]) {
- // ondclick event
- ["window", "canvas", "world"].forEach((ctx) =>
- mouse.listen[ctx][key].ondclick.emit({
+ if (_double_click_timeout[evn.button]) {
+ // ondclick event
+ mouse.contexts.forEach(({target, name, buttons}) => {
+ if ((!target || target === evn.target) && buttons[evn.button])
+ mouse.listen[name][buttons[evn.button]].ondclick.emit({
target: evn.target,
buttonId: evn.button,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
- })
- );
- } else {
- // Start timer
- _double_click_timeout[key] = setTimeout(
- () => delete _double_click_timeout[key],
- inputConfig.dClickTiming
- );
- }
-
- // Set drag start timeout
- _drag_start_timeout[key] = setTimeout(() => {
- ["window", "canvas", "world"].forEach((ctx) => {
- mouse.listen[ctx][key].ondragstart.emit({
- target: evn.target,
- buttonId: evn.button,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: time,
});
- if (mouse[ctx].dragging[key]) mouse[ctx].dragging[key].drag = true;
+ });
+ } else {
+ // Start timer
+ _double_click_timeout[evn.button] = setTimeout(
+ () => delete _double_click_timeout[evn.button],
+ inputConfig.dClickTiming
+ );
+ }
- delete _drag_start_timeout[key];
- });
- }, inputConfig.clickTiming);
+ // Set drag start timeout
+ _drag_start_timeout[evn.button] = setTimeout(() => {
+ mouse.contexts.forEach(({target, name, buttons}) => {
+ const key = buttons[evn.button];
+ if (
+ (!target || target === evn.target) &&
+ !mouse.coords[name].dragging[key].drag &&
+ key
+ ) {
+ mouse.listen[name][key].ondragstart.emit({
+ target: evn.target,
+ buttonId: evn.button,
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: time,
+ });
- ["window", "canvas", "world"].forEach((ctx) => {
- mouse.buttons[key] = time;
- mouse[ctx].dragging[key] = {target: evn.target};
- Object.assign(mouse[ctx].dragging[key], mouse[ctx].pos);
+ mouse.coords[name].dragging[key].drag = true;
+ }
+ });
+ delete _drag_start_timeout[evn.button];
+ }, inputConfig.clickTiming);
+
+ mouse.buttons[evn.button] = time;
+
+ mouse.contexts.forEach(({target, name, buttons}) => {
+ const key = buttons[evn.button];
+ if ((!target || target === evn.target) && key) {
+ mouse.coords[name].dragging[key] = {};
+ mouse.coords[name].dragging[key].target = evn.target;
+ Object.assign(mouse.coords[name].dragging[key], mouse.coords[name].pos);
// onpaintstart event
- mouse.listen[ctx][key].onpaintstart.emit({
+ mouse.listen[name][key].onpaintstart.emit({
target: evn.target,
buttonId: evn.button,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
});
- });
- };
-
- // Runs the correct handler
- const buttons = [onhold("left"), onhold("middle"), onhold("right")];
-
- buttons[evn.button] && buttons[evn.button]();
+ }
+ });
};
window.onmouseup = (evn) => {
- const time = new Date();
+ const time = performance.now();
- // Processes for a named button
- const onrelease = (key) => () => {
- ["window", "canvas", "world"].forEach((ctx) => {
+ mouse.contexts.forEach(({target, name, buttons}) => {
+ const key = buttons[evn.button];
+ if (
+ (!target || target === evn.target) &&
+ key &&
+ mouse.coords[name].dragging[key]
+ ) {
const start = {
- x: mouse[ctx].dragging[key].x,
- y: mouse[ctx].dragging[key].y,
+ x: mouse.coords[name].dragging[key].x,
+ y: mouse.coords[name].dragging[key].y,
};
// onclick event
- const dx = mouse[ctx].pos.x - start.x;
- const dy = mouse[ctx].pos.y - start.y;
+ const dx = mouse.coords[name].pos.x - start.x;
+ const dy = mouse.coords[name].pos.y - start.y;
if (
- time.getTime() - mouse.buttons[key].getTime() <
- inputConfig.clickTiming &&
+ mouse.buttons[evn.button] &&
+ time - mouse.buttons[evn.button] < inputConfig.clickTiming &&
dx * dx + dy * dy < inputConfig.clickRadius * inputConfig.clickRadius
)
- mouse.listen[ctx][key].onclick.emit({
+ mouse.listen[name][key].onclick.emit({
target: evn.target,
buttonId: evn.button,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
});
// onpaintend event
- mouse.listen[ctx][key].onpaintend.emit({
+ mouse.listen[name][key].onpaintend.emit({
target: evn.target,
- initialTarget: mouse[ctx].dragging[key].target,
+ initialTarget: mouse.coords[name].dragging[key].target,
buttonId: evn.button,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
});
// ondragend event
- if (mouse[ctx].dragging[key].drag)
- mouse.listen[ctx][key].ondragend.emit({
+ if (mouse.coords[name].dragging[key].drag)
+ mouse.listen[name][key].ondragend.emit({
target: evn.target,
- initialTarget: mouse[ctx].dragging[key].target,
+ initialTarget: mouse.coords[name].dragging[key].target,
buttonId: evn.button,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
});
- mouse[ctx].dragging[key] = null;
- });
-
- if (_drag_start_timeout[key] !== undefined) {
- clearTimeout(_drag_start_timeout[key]);
- delete _drag_start_timeout[key];
+ mouse.coords[name].dragging[key] = null;
}
- mouse.buttons[key] = null;
- };
+ });
- // Runs the correct handler
- const buttons = [onrelease("left"), onrelease("middle"), onrelease("right")];
-
- buttons[evn.button] && buttons[evn.button]();
+ if (_drag_start_timeout[evn.button] !== undefined) {
+ clearTimeout(_drag_start_timeout[evn.button]);
+ delete _drag_start_timeout[evn.button];
+ }
+ mouse.buttons[evn.button] = null;
};
window.onmousemove = (evn) => {
- // Set Window Coordinates
- Object.assign(mouse.window.prev, mouse.window.pos);
- mouse.window.pos = {x: evn.clientX, y: evn.clientY};
+ mouse.contexts.forEach((context) => {
+ const target = context.target;
+ const name = context.name;
- // Set Canvas Coordinates (using overlay canvas as reference)
- if (evn.target.id === "overlayCanvas") {
- Object.assign(mouse.canvas.prev, mouse.canvas.pos);
- mouse.canvas.pos = {x: evn.layerX, y: evn.layerY};
- }
+ if (!target || target === evn.target) {
+ context.onmove(evn, context);
- // Set World Coordinates (For now the same as canvas coords; Will be useful with infinite canvas)
- if (evn.target.id === "overlayCanvas") {
- Object.assign(mouse.world.prev, mouse.world.pos);
- mouse.world.pos = {x: evn.layerX, y: evn.layerY};
- }
+ mouse.listen[name].onmousemove.emit({
+ target: evn.target,
+ px: mouse.coords[name].prev.x,
+ py: mouse.coords[name].prev.y,
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
+ });
- ["window", "canvas", "world"].forEach((ctx) => {
- mouse.listen[ctx].onmousemove.emit({
- target: evn.target,
- px: mouse[ctx].prev.x,
- py: mouse[ctx].prev.y,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
- });
- ["left", "middle", "right"].forEach((key) => {
- // ondrag event
- if (mouse[ctx].dragging[key] && mouse[ctx].dragging[key].drag)
- mouse.listen[ctx][key].ondrag.emit({
- target: evn.target,
- initialTarget: mouse[ctx].dragging[key].target,
- px: mouse[ctx].prev.x,
- py: mouse[ctx].prev.y,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
- });
+ Object.keys(context.buttons).forEach((index) => {
+ const key = context.buttons[index];
+ // ondragstart event (2)
+ if (mouse.coords[name].dragging[key]) {
+ const dx =
+ mouse.coords[name].pos.x - mouse.coords[name].dragging[key].x;
+ const dy =
+ mouse.coords[name].pos.y - mouse.coords[name].dragging[key].y;
+ if (
+ !mouse.coords[name].dragging[key].drag &&
+ dx * dx + dy * dy >=
+ inputConfig.clickRadius * inputConfig.clickRadius
+ ) {
+ mouse.listen[name][key].ondragstart.emit({
+ target: evn.target,
+ buttonId: evn.button,
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
+ });
- // onpaint event
- if (mouse[ctx].dragging[key])
- mouse.listen[ctx][key].onpaint.emit({
- target: evn.target,
- initialTarget: mouse[ctx].dragging[key].target,
- px: mouse[ctx].prev.x,
- py: mouse[ctx].prev.y,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
- });
- });
+ mouse.coords[name].dragging[key].drag = true;
+ }
+ }
+
+ // ondrag event
+ if (
+ mouse.coords[name].dragging[key] &&
+ mouse.coords[name].dragging[key].drag
+ )
+ mouse.listen[name][key].ondrag.emit({
+ target: evn.target,
+ initialTarget: mouse.coords[name].dragging[key].target,
+ button: index,
+ px: mouse.coords[name].prev.x,
+ py: mouse.coords[name].prev.y,
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
+ });
+
+ // onpaint event
+ if (mouse.coords[name].dragging[key]) {
+ mouse.listen[name][key].onpaint.emit({
+ target: evn.target,
+ initialTarget: mouse.coords[name].dragging[key].target,
+ button: index,
+ px: mouse.coords[name].prev.x,
+ py: mouse.coords[name].prev.y,
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
+ });
+ }
+ });
+ }
});
};
@@ -276,22 +314,41 @@ window.addEventListener(
"wheel",
(evn) => {
evn.preventDefault();
- ["window", "canvas", "world"].forEach((ctx) => {
- mouse.listen[ctx].onwheel.emit({
+ mouse.contexts.forEach(({name}) => {
+ mouse.listen[name].onwheel.emit({
target: evn.target,
delta: evn.deltaY,
deltaX: evn.deltaX,
deltaY: evn.deltaY,
deltaZ: evn.deltaZ,
mode: evn.deltaMode,
- x: mouse[ctx].pos.x,
- y: mouse[ctx].pos.y,
- timestamp: new Date(),
+ x: mouse.coords[name].pos.x,
+ y: mouse.coords[name].pos.y,
+ evn,
+ timestamp: performance.now(),
});
});
},
{passive: false}
);
+
+mouse.registerContext("window", (evn, ctx) => {
+ ctx.coords.prev.x = ctx.coords.pos.x;
+ ctx.coords.prev.y = ctx.coords.pos.y;
+ ctx.coords.pos.x = evn.clientX;
+ ctx.coords.pos.y = evn.clientY;
+});
+
+mouse.registerContext(
+ "canvas",
+ (evn, ctx) => {
+ ctx.coords.prev.x = ctx.coords.pos.x;
+ ctx.coords.prev.y = ctx.coords.pos.y;
+ ctx.coords.pos.x = evn.layerX;
+ ctx.coords.pos.y = evn.layerY;
+ },
+ document.getElementById("overlayCanvas")
+);
/**
* Keyboard input processing
*/
@@ -342,7 +399,9 @@ const keyboard = {
};
window.onkeydown = (evn) => {
+ // onkeydown event
keyboard.listen.onkeydown.emit({
+ target: evn.target,
code: evn.code,
key: evn.key,
evn,
@@ -354,7 +413,9 @@ window.onkeydown = (evn) => {
_hold_to: setTimeout(() => {
keyboard.keys[evn.code].held = true;
delete keyboard.keys[evn.code]._hold_to;
+ // onkeyholdstart event
keyboard.listen.onkeyholdstart.emit({
+ target: evn.target,
code: evn.code,
key: evn.key,
evn,
@@ -383,7 +444,9 @@ window.onkeydown = (evn) => {
!!callback.alt === evn.altKey &&
!!callback.shift === evn.shiftKey
) {
+ // onshortcut event
keyboard.listen.onshortcut.emit({
+ target: evn.target,
code: evn.code,
key: evn.key,
id: callback.id,
@@ -395,19 +458,25 @@ window.onkeydown = (evn) => {
};
window.onkeyup = (evn) => {
+ // onkeyup event
keyboard.listen.onkeyup.emit({
+ target: evn.target,
code: evn.code,
key: evn.key,
evn,
});
if (keyboard.keys[evn.code] && keyboard.keys[evn.code].held) {
+ // onkeyholdend event
keyboard.listen.onkeyholdend.emit({
+ target: evn.target,
code: evn.code,
key: evn.key,
evn,
});
} else {
+ // onkeyclick event
keyboard.listen.onkeyclick.emit({
+ target: evn.target,
code: evn.code,
key: evn.key,
evn,
diff --git a/js/settingsbar.js b/js/settingsbar.js
index bfb60c3..895eaae 100644
--- a/js/settingsbar.js
+++ b/js/settingsbar.js
@@ -46,3 +46,113 @@ for (var i = 0; i < coll.length; i++) {
}
});
}
+
+/**
+ * Slider Inputs
+ */
+function createSlider(name, wrapper, options = {}) {
+ defaultOpt(options, {
+ valuecb: null,
+ min: 0,
+ max: 1,
+ step: 0.1,
+ defaultValue: 0.7,
+ });
+
+ let value = options.defaultValue;
+
+ // Use phantom range element for rounding
+ const phantomRange = document.createElement("input");
+ phantomRange.type = "range";
+ phantomRange.min = options.min;
+ phantomRange.max = options.max;
+ phantomRange.step = options.step;
+
+ // Build slider element
+ const underEl = document.createElement("div");
+ underEl.classList.add("under");
+ const textEl = document.createElement("input");
+ textEl.type = "text";
+ textEl.classList.add("text");
+
+ const overEl = document.createElement("div");
+ overEl.classList.add("over");
+
+ wrapper.classList.add("slider-wrapper");
+ wrapper.appendChild(underEl);
+ wrapper.appendChild(textEl);
+ wrapper.appendChild(overEl);
+
+ const bar = document.createElement("div");
+ bar.classList.add("slider-bar");
+ underEl.appendChild(bar);
+ underEl.appendChild(document.createElement("div"));
+
+ // Set value
+ const setValue = (val) => {
+ phantomRange.value = val;
+ value = parseFloat(phantomRange.value);
+ bar.style.width = `${
+ wrapper.offsetWidth *
+ ((value - options.min) / (options.max - options.min))
+ }px`;
+ textEl.value = `${name}: ${value}`;
+ options.valuecb && options.valuecb(value);
+ };
+
+ setValue(options.defaultValue);
+
+ // Events
+ textEl.addEventListener("blur", () => {
+ overEl.style.pointerEvents = "auto";
+ textEl.value = `${name}: ${value}`;
+ });
+ textEl.addEventListener("focus", () => {
+ textEl.value = value;
+ });
+
+ textEl.addEventListener("change", () => {
+ try {
+ if (Number.isNaN(parseFloat(textEl.value))) setValue(value);
+ else setValue(parseFloat(textEl.value));
+ } catch (e) {}
+ });
+
+ keyboard.listen.onkeyclick.on((evn) => {
+ if (evn.target === textEl && evn.code === "Enter") {
+ textEl.blur();
+ }
+ });
+
+ mouse.listen.window.left.onclick.on((evn) => {
+ if (evn.target === overEl) {
+ overEl.style.pointerEvents = "none";
+ textEl.select();
+ }
+ });
+
+ mouse.listen.window.left.ondrag.on((evn) => {
+ if (evn.target === overEl) {
+ setValue(
+ Math.max(
+ options.min,
+ Math.min(
+ options.max,
+ (evn.evn.layerX / wrapper.offsetWidth) *
+ (options.max - options.min) +
+ options.min
+ )
+ )
+ );
+ }
+ });
+
+ return {
+ set value(val) {
+ setValue(val);
+ },
+ get value() {
+ return value;
+ },
+ };
+}
diff --git a/js/ui/toolbar.js b/js/ui/toolbar.js
index ea7cbac..0aa31c4 100644
--- a/js/ui/toolbar.js
+++ b/js/ui/toolbar.js
@@ -135,42 +135,22 @@ const _toolbar_input = {
},
slider: (state, dataKey, text, min = 0, max = 1, step = 0.1) => {
- const slider = document.createElement("input");
- slider.type = "range";
- slider.max = max;
- slider.step = step;
- slider.min = min;
- slider.value = state[dataKey];
+ const slider = document.createElement("div");
- const textEl = document.createElement("input");
- textEl.type = "number";
- textEl.value = state[dataKey];
-
- console.log(state[dataKey]);
-
- sliderChangeHandlerFactoryEl(
- slider,
- textEl,
- dataKey,
- state[dataKey],
- false,
- (k, v) => (state[dataKey] = v),
- (k) => state[dataKey]
- );
-
- const label = document.createElement("label");
- label.appendChild(new Text(text));
- label.appendChild(textEl);
- label.appendChild(slider);
+ const value = createSlider(text, slider, {
+ min,
+ max,
+ step,
+ valuecb: (v) => {
+ state[dataKey] = v;
+ },
+ });
return {
slider,
- text: textEl,
- label,
setValue(v) {
- slider.value = v;
- textEl.value = slider.value;
- return parseInt(slider.value);
+ value.value = v;
+ return value.value;
},
};
},
@@ -206,7 +186,10 @@ tools.dream = toolbar.registerTool(
(state, opt) => {
// Draw new cursor immediately
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
- state.mousemovecb({...mouse.canvas.pos, target: {id: "overlayCanvas"}});
+ state.mousemovecb({
+ ...mouse.coords.canvas.pos,
+ target: {id: "overlayCanvas"},
+ });
// Start Listeners
mouse.listen.canvas.onmousemove.on(state.mousemovecb);
@@ -261,7 +244,10 @@ tools.img2img = toolbar.registerTool(
(state, opt) => {
// Draw new cursor immediately
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
- state.mousemovecb({...mouse.canvas.pos, target: {id: "overlayCanvas"}});
+ state.mousemovecb({
+ ...mouse.coords.canvas.pos,
+ target: {id: "overlayCanvas"},
+ });
// Start Listeners
mouse.listen.canvas.onmousemove.on(state.mousemovecb);
@@ -337,17 +323,17 @@ tools.img2img = toolbar.registerTool(
).label;
// Denoising Strength Slider
- state.ctxmenu.denoisingStrengthLabel = _toolbar_input.slider(
+ state.ctxmenu.denoisingStrengthSlider = _toolbar_input.slider(
state,
"denoisingStrength",
"Denoising Strength",
0,
1,
0.05
- ).label;
+ ).slider;
// Use Border Mask Checkbox
- state.ctxmenu.useBorderMaskLabel = _toolbar_input.checkbox(
+ state.ctxmenu.useBorderMaskSlider = _toolbar_input.checkbox(
state,
"useBorderMask",
"Use Border Mask"
@@ -360,16 +346,16 @@ tools.img2img = toolbar.registerTool(
0,
128,
1
- ).label;
+ ).slider;
}
menu.appendChild(state.ctxmenu.snapToGridLabel);
menu.appendChild(document.createElement("br"));
- menu.appendChild(state.ctxmenu.denoisingStrengthLabel);
+ menu.appendChild(state.ctxmenu.denoisingStrengthSlider);
menu.appendChild(document.createElement("br"));
menu.appendChild(state.ctxmenu.useBorderMaskLabel);
menu.appendChild(document.createElement("br"));
- menu.appendChild(state.ctxmenu.borderMaskSize);
+ menu.appendChild(state.ctxmenu.borderMaskSlider);
},
shortcut: "I",
}
@@ -389,7 +375,7 @@ tools.maskbrush = toolbar.registerTool(
(state, opt) => {
// Draw new cursor immediately
ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height);
- state.movecb({...mouse.canvas.pos, target: {id: "overlayCanvas"}});
+ state.movecb({...mouse.coords.canvas.pos, target: {id: "overlayCanvas"}});
// Start Listeners
mouse.listen.canvas.onmousemove.on(state.movecb);
@@ -454,11 +440,11 @@ tools.maskbrush = toolbar.registerTool(
state.config.maxBrushSize,
1
);
- state.ctxmenu.brushSizeLabel = brushSizeSlider.label;
+ state.ctxmenu.brushSizeSlider = brushSizeSlider.slider;
state.setBrushSize = brushSizeSlider.setValue;
}
- menu.appendChild(state.ctxmenu.brushSizeLabel);
+ menu.appendChild(state.ctxmenu.brushSizeSlider);
},
shortcut: "M",
}
diff --git a/js/util.js b/js/util.js
index d16e67c..0de261b 100644
--- a/js/util.js
+++ b/js/util.js
@@ -42,6 +42,16 @@ const guid = (size = 3) => {
return id;
};
+/**
+ * Default option set
+ */
+
+function defaultOpt(options, defaults) {
+ Object.keys(defaults).forEach((key) => {
+ if (options[key] === undefined) options[key] = defaults[key];
+ });
+}
+
/**
* Bounding box Calculation
*/