allow stamp rotation(drag) and scaling(wheel)
also adds shift as a 'finetune' for wheel. works for dream and stamp. if shift is pressed, wheel will scale slower (not snapping to 128 for dream, or 0.1 for stamp) Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
parent
b2e28e77c0
commit
e198cf9af4
5 changed files with 147 additions and 37 deletions
|
@ -355,7 +355,7 @@
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
|
|
||||||
<!-- Configuration -->
|
<!-- Configuration -->
|
||||||
<script src="js/config.js?v=36739c9" type="text/javascript"></script>
|
<script src="js/config.js?v=e0345e0" 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>
|
||||||
|
@ -373,7 +373,7 @@
|
||||||
src="js/ui/tool/generic.js?v=f5ad9d7"
|
src="js/ui/tool/generic.js?v=f5ad9d7"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
|
|
||||||
<script src="js/ui/tool/dream.js?v=3db7d6c" type="text/javascript"></script>
|
<script src="js/ui/tool/dream.js?v=f20dd01" type="text/javascript"></script>
|
||||||
<script
|
<script
|
||||||
src="js/ui/tool/maskbrush.js?v=1e8a893"
|
src="js/ui/tool/maskbrush.js?v=1e8a893"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
|
@ -381,9 +381,9 @@
|
||||||
src="js/ui/tool/colorbrush.js?v=3f8c01a"
|
src="js/ui/tool/colorbrush.js?v=3f8c01a"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
<script
|
<script
|
||||||
src="js/ui/tool/select.js?v=fae1b04"
|
src="js/ui/tool/select.js?v=95eba41"
|
||||||
type="text/javascript"></script>
|
type="text/javascript"></script>
|
||||||
<script src="js/ui/tool/stamp.js?v=3c07ac8" type="text/javascript"></script>
|
<script src="js/ui/tool/stamp.js?v=1bba5f4" 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>
|
||||||
|
|
14
js/config.js
14
js/config.js
|
@ -25,15 +25,15 @@ const config = makeReadOnly(
|
||||||
rotationSnappingDistance: (10 * Math.PI) / 180,
|
rotationSnappingDistance: (10 * Math.PI) / 180,
|
||||||
// Rotation Snapping Angles
|
// Rotation Snapping Angles
|
||||||
rotationSnappingAngles: [
|
rotationSnappingAngles: [
|
||||||
|
(-Math.PI * 4) / 4,
|
||||||
|
(-Math.PI * 3) / 4,
|
||||||
|
(-Math.PI * 2) / 4,
|
||||||
|
(-Math.PI * 1) / 4,
|
||||||
0,
|
0,
|
||||||
Math.PI / 4,
|
(Math.PI * 1) / 4,
|
||||||
Math.PI / 2,
|
(Math.PI * 2) / 4,
|
||||||
(Math.PI * 3) / 4,
|
(Math.PI * 3) / 4,
|
||||||
Math.PI,
|
(Math.PI * 4) / 4,
|
||||||
(Math.PI * 5) / 4,
|
|
||||||
(Math.PI * 6) / 4,
|
|
||||||
(Math.PI * 7) / 4,
|
|
||||||
Math.PI * 2,
|
|
||||||
],
|
],
|
||||||
|
|
||||||
// Endpoint
|
// Endpoint
|
||||||
|
|
|
@ -1255,10 +1255,16 @@ const _dream_onwheel = (evn, state) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A simple but (I hope) effective fix for mouse wheel behavior
|
let delta = evn.delta;
|
||||||
_dream_wheel_accum += evn.delta;
|
if (evn.evn.shiftKey) delta *= 0.01;
|
||||||
|
|
||||||
if (Math.abs(_dream_wheel_accum) > config.wheelTickSize) {
|
// A simple but (I hope) effective fix for mouse wheel behavior
|
||||||
|
_dream_wheel_accum += delta;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!evn.evn.shiftKey &&
|
||||||
|
Math.abs(_dream_wheel_accum) > config.wheelTickSize
|
||||||
|
) {
|
||||||
// Snap to next or previous position
|
// Snap to next or previous position
|
||||||
const v =
|
const v =
|
||||||
state.cursorSize -
|
state.cursorSize -
|
||||||
|
@ -1267,6 +1273,12 @@ const _dream_onwheel = (evn, state) => {
|
||||||
state.cursorSize = state.setCursorSize(v + snap(v, 0, 128));
|
state.cursorSize = state.setCursorSize(v + snap(v, 0, 128));
|
||||||
state.mousemovecb(evn);
|
state.mousemovecb(evn);
|
||||||
|
|
||||||
|
_dream_wheel_accum = 0; // Zero accumulation
|
||||||
|
} else if (evn.evn.shiftKey && Math.abs(_dream_wheel_accum) >= 1) {
|
||||||
|
const v = state.cursorSize - _dream_wheel_accum;
|
||||||
|
state.cursorSize = state.setCursorSize(v);
|
||||||
|
state.mousemovecb(evn);
|
||||||
|
|
||||||
_dream_wheel_accum = 0; // Zero accumulation
|
_dream_wheel_accum = 0; // Zero accumulation
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -375,7 +375,7 @@ const selectTransformTool = () =>
|
||||||
angle =
|
angle =
|
||||||
config.rotationSnappingAngles.find(
|
config.rotationSnappingAngles.find(
|
||||||
(v) => Math.abs(v - angle) < config.rotationSnappingDistance
|
(v) => Math.abs(v - angle) < config.rotationSnappingDistance
|
||||||
) || angle;
|
) ?? angle;
|
||||||
|
|
||||||
state.selected.rotation = angle;
|
state.selected.rotation = angle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,41 @@
|
||||||
|
/**
|
||||||
|
* Generic wheel handler
|
||||||
|
*/
|
||||||
|
let _stamp_wheel_accum = 0;
|
||||||
|
|
||||||
|
const _stamp_onwheel = (evn, state) => {
|
||||||
|
if (evn.mode !== WheelEvent.DOM_DELTA_PIXEL) {
|
||||||
|
// We don't really handle non-pixel scrolling
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let delta = evn.delta;
|
||||||
|
if (evn.evn.shiftKey) delta *= 0.01;
|
||||||
|
|
||||||
|
// A simple but (I hope) effective fix for mouse wheel behavior
|
||||||
|
_stamp_wheel_accum += delta;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!evn.evn.shiftKey &&
|
||||||
|
Math.abs(_stamp_wheel_accum) > config.wheelTickSize
|
||||||
|
) {
|
||||||
|
// Snap to next or previous position
|
||||||
|
const v =
|
||||||
|
state.scale - 0.1 * (_stamp_wheel_accum / Math.abs(_stamp_wheel_accum));
|
||||||
|
|
||||||
|
state.setScale(v + snap(v, 0, 0.1));
|
||||||
|
state.redraw(evn);
|
||||||
|
|
||||||
|
_stamp_wheel_accum = 0; // Zero accumulation
|
||||||
|
} else if (evn.evn.shiftKey && Math.abs(_stamp_wheel_accum) >= 1) {
|
||||||
|
const v = state.scale - _stamp_wheel_accum * 0.01;
|
||||||
|
state.setScale(v);
|
||||||
|
state.redraw(evn);
|
||||||
|
|
||||||
|
_stamp_wheel_accum = 0; // Zero accumulation
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const stampTool = () =>
|
const stampTool = () =>
|
||||||
toolbar.registerTool(
|
toolbar.registerTool(
|
||||||
"./res/icons/file-up.svg",
|
"./res/icons/file-up.svg",
|
||||||
|
@ -14,6 +52,12 @@ const stampTool = () =>
|
||||||
mouse.listen.world.btn.left.onclick.on(state.drawcb);
|
mouse.listen.world.btn.left.onclick.on(state.drawcb);
|
||||||
mouse.listen.world.btn.right.onclick.on(state.cancelcb);
|
mouse.listen.world.btn.right.onclick.on(state.cancelcb);
|
||||||
|
|
||||||
|
mouse.listen.world.btn.left.ondragstart.on(state.dragstartcb);
|
||||||
|
mouse.listen.world.btn.left.ondrag.on(state.dragcb);
|
||||||
|
mouse.listen.world.btn.left.ondragend.on(state.dragendcb);
|
||||||
|
|
||||||
|
mouse.listen.world.onwheel.on(state.onwheelcb);
|
||||||
|
|
||||||
// For calls from other tools to paste image
|
// For calls from other tools to paste image
|
||||||
if (opt && opt.image) {
|
if (opt && opt.image) {
|
||||||
state.addResource(
|
state.addResource(
|
||||||
|
@ -41,6 +85,12 @@ const stampTool = () =>
|
||||||
mouse.listen.world.btn.left.onclick.clear(state.drawcb);
|
mouse.listen.world.btn.left.onclick.clear(state.drawcb);
|
||||||
mouse.listen.world.btn.right.onclick.clear(state.cancelcb);
|
mouse.listen.world.btn.right.onclick.clear(state.cancelcb);
|
||||||
|
|
||||||
|
mouse.listen.world.btn.left.ondragstart.clear(state.dragstartcb);
|
||||||
|
mouse.listen.world.btn.left.ondrag.clear(state.dragcb);
|
||||||
|
mouse.listen.world.btn.left.ondragend.clear(state.dragendcb);
|
||||||
|
|
||||||
|
mouse.listen.world.onwheel.clear(state.onwheelcb);
|
||||||
|
|
||||||
ovLayer.clear();
|
ovLayer.clear();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -54,7 +104,15 @@ const stampTool = () =>
|
||||||
state.lastMouseMove = {x: 0, y: 0};
|
state.lastMouseMove = {x: 0, y: 0};
|
||||||
state.block_res_change = true;
|
state.block_res_change = true;
|
||||||
|
|
||||||
|
// Current Rotation
|
||||||
|
let rotation = 0;
|
||||||
|
let rotating = null;
|
||||||
|
// Current Scale
|
||||||
|
state.scale = 1;
|
||||||
|
|
||||||
state.selectResource = (resource, nolock = true, deselect = true) => {
|
state.selectResource = (resource, nolock = true, deselect = true) => {
|
||||||
|
rotation = 0;
|
||||||
|
state.setScale(1);
|
||||||
if (nolock && state.ctxmenu.uploadButton.disabled) return;
|
if (nolock && state.ctxmenu.uploadButton.disabled) return;
|
||||||
|
|
||||||
console.debug(
|
console.debug(
|
||||||
|
@ -290,32 +348,65 @@ const stampTool = () =>
|
||||||
syncResources();
|
syncResources();
|
||||||
};
|
};
|
||||||
|
|
||||||
state.movecb = (evn) => {
|
state.onwheelcb = (evn) => {
|
||||||
let x = evn.x;
|
_stamp_onwheel(evn, state);
|
||||||
let y = evn.y;
|
};
|
||||||
if (state.snapToGrid) {
|
|
||||||
x += snap(evn.x, 0, 64);
|
state.dragstartcb = (evn) => {
|
||||||
y += snap(evn.y, 0, 64);
|
const {x, y, sx, sy} = _tool._process_cursor(evn, state.snapToGrid);
|
||||||
|
rotating = {x: sx, y: sy};
|
||||||
|
};
|
||||||
|
|
||||||
|
state.dragcb = (evn) => {
|
||||||
|
if (rotating) {
|
||||||
|
rotation = Math.atan2(rotating.x - evn.x, evn.y - rotating.y);
|
||||||
|
|
||||||
|
if (evn.evn.shiftKey)
|
||||||
|
rotation =
|
||||||
|
config.rotationSnappingAngles.find(
|
||||||
|
(v) =>
|
||||||
|
Math.abs(v - rotation) < config.rotationSnappingDistance
|
||||||
|
) ?? rotation;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const vpc = viewport.canvasToView(x, y);
|
state.dragendcb = (evn) => {
|
||||||
uiCtx.clearRect(0, 0, uiCanvas.width, uiCanvas.height);
|
rotating = null;
|
||||||
state.erasePrevCursor && state.erasePrevCursor();
|
};
|
||||||
|
|
||||||
uiCtx.save();
|
let erasePrevCursor = () => null;
|
||||||
|
|
||||||
|
state.movecb = (evn) => {
|
||||||
|
const {x, y, sx, sy} = _tool._process_cursor(evn, state.snapToGrid);
|
||||||
|
|
||||||
|
// Erase Previous Cursors
|
||||||
|
erasePrevCursor();
|
||||||
|
|
||||||
state.lastMouseMove = evn;
|
state.lastMouseMove = evn;
|
||||||
|
|
||||||
ovLayer.clear();
|
ovLayer.clear();
|
||||||
|
|
||||||
|
let px = sx;
|
||||||
|
let py = sy;
|
||||||
|
|
||||||
|
if (rotating) {
|
||||||
|
px = rotating.x;
|
||||||
|
py = rotating.y;
|
||||||
|
}
|
||||||
|
|
||||||
// Draw selected image
|
// Draw selected image
|
||||||
if (state.selected) {
|
if (state.selected) {
|
||||||
ovCtx.drawImage(state.selected.image, x, y);
|
ovCtx.save();
|
||||||
|
ovCtx.translate(px, py);
|
||||||
|
ovCtx.scale(state.scale, state.scale);
|
||||||
|
ovCtx.rotate(rotation);
|
||||||
|
|
||||||
|
ovCtx.drawImage(state.selected.image, 0, 0);
|
||||||
|
ovCtx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw current cursor location
|
// Draw current cursor location
|
||||||
state.erasePrevCursor = _tool._cursor_draw(x, y);
|
erasePrevCursor = _tool._cursor_draw(px, py);
|
||||||
uiCtx.restore();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
state.redraw = () => {
|
state.redraw = () => {
|
||||||
|
@ -323,20 +414,16 @@ const stampTool = () =>
|
||||||
};
|
};
|
||||||
|
|
||||||
state.drawcb = (evn) => {
|
state.drawcb = (evn) => {
|
||||||
let x = evn.x;
|
const {x, y, sx, sy} = _tool._process_cursor(evn, state.snapToGrid);
|
||||||
let y = evn.y;
|
|
||||||
if (state.snapToGrid) {
|
|
||||||
x += snap(evn.x, 0, 64);
|
|
||||||
y += snap(evn.y, 0, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
const resource = state.selected;
|
const resource = state.selected;
|
||||||
|
|
||||||
if (resource) {
|
if (resource) {
|
||||||
|
const {canvas, bb} = cropCanvas(ovCanvas, {border: 10});
|
||||||
commands.runCommand("drawImage", "Image Stamp", {
|
commands.runCommand("drawImage", "Image Stamp", {
|
||||||
image: resource.image,
|
image: canvas,
|
||||||
x,
|
x: bb.x,
|
||||||
y,
|
y: bb.y,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (resource.temporary) {
|
if (resource.temporary) {
|
||||||
|
@ -380,6 +467,16 @@ const stampTool = () =>
|
||||||
);
|
);
|
||||||
state.ctxmenu.snapToGridLabel = array;
|
state.ctxmenu.snapToGridLabel = array;
|
||||||
|
|
||||||
|
// Scale Slider
|
||||||
|
const scaleSlider = _toolbar_input.slider(state, "scale", "Scale", {
|
||||||
|
min: 0.01,
|
||||||
|
max: 10,
|
||||||
|
step: 0.1,
|
||||||
|
textStep: 0.01,
|
||||||
|
});
|
||||||
|
state.ctxmenu.scaleSlider = scaleSlider.slider;
|
||||||
|
state.setScale = scaleSlider.setValue;
|
||||||
|
|
||||||
// Create resource list
|
// Create resource list
|
||||||
const uploadButtonId = `upload-btn-${guid()}`;
|
const uploadButtonId = `upload-btn-${guid()}`;
|
||||||
|
|
||||||
|
@ -528,6 +625,7 @@ const stampTool = () =>
|
||||||
},
|
},
|
||||||
populateContextMenu: (menu, state) => {
|
populateContextMenu: (menu, state) => {
|
||||||
menu.appendChild(state.ctxmenu.snapToGridLabel);
|
menu.appendChild(state.ctxmenu.snapToGridLabel);
|
||||||
|
menu.appendChild(state.ctxmenu.scaleSlider);
|
||||||
menu.appendChild(state.ctxmenu.resourceManager);
|
menu.appendChild(state.ctxmenu.resourceManager);
|
||||||
},
|
},
|
||||||
shortcut: "U",
|
shortcut: "U",
|
||||||
|
|
Loading…
Reference in a new issue