Cursors, Esc to cancel active tool (#946)

* basic drawing cursors

* Esc to cancel tool, I shortcut bug fix

* panel btns hover animation

* minor changes

* Linter fix

* update packages

* remove NYC coverage causing build errors
would be nice to find out a replacement or a fix

---------

Co-authored-by: JFH <20402845+jfhenon@users.noreply.github.com>
This commit is contained in:
olekhshch
2024-01-17 15:19:37 +01:00
committed by GitHub
parent 24f78d3d0f
commit f75d1a83a0
15 changed files with 438 additions and 997 deletions

View File

@@ -96,6 +96,7 @@ class Editor extends EditorStartup {
'zh-CN',
'zh-TW'
]
const modKey = isMac() ? 'meta+' : 'ctrl+'
this.shortcuts = [
// Shortcuts not associated with buttons
@@ -304,6 +305,14 @@ class Editor extends EditorStartup {
fn: () => {
this.pasteInCenter()
}
},
{
key: 'escape',
fn: () => {
if (this.enableToolCancel) {
this.cancelTool()
}
}
}
]
this.leftPanel = new LeftPanel(this)

View File

@@ -122,6 +122,11 @@ class EditorStartup {
this.modeEvent = this.svgCanvas.modeEvent
document.addEventListener('modeChange', (evt) => this.modeListener(evt))
/** if true - selected tool can be cancelled with Esc key
* disables on dragging (mousedown) to avoid changing mode in the middle of drawing
*/
this.enableToolCancel = true
this.leftPanel.init()
this.bottomPanel.init()
this.topPanel.init()
@@ -309,6 +314,7 @@ class EditorStartup {
return false
})
$id('svgcanvas').addEventListener('mousedown', (evt) => {
this.enableToolCancel = false
if (evt.button === 1 || keypan === true) {
// prDefault to avoid firing of browser's panning on mousewheel
evt.preventDefault()
@@ -331,6 +337,7 @@ class EditorStartup {
})
window.addEventListener('mouseup', (evt) => {
this.enableToolCancel = true
if (evt.button === 1) {
this.svgCanvas.setMode(previousMode ?? 'select')
}
@@ -747,12 +754,36 @@ class EditorStartup {
case 'zoom':
cs = 'crosshair'
break
case 'circle':
case 'ellipse':
case 'rect':
case 'square':
case 'star':
case 'polygon':
cs = `url("./images/cursors/${mode}_cursor.svg"), crosshair`
break
case 'text':
// #TODO: Cursor should be changed back to default after text element was created
cs = 'text'
break
default:
cs = 'auto'
}
this.workarea.style.cursor = cs
}
/**
* Listens for Esc key to be pressed to cancel active mode, sets mode to Select
*/
cancelTool () {
const mode = this.svgCanvas.getMode()
// list of modes that are currently save to cancel
const modesToCancel = ['zoom', 'rect', 'square', 'circle', 'ellipse', 'line', 'text', 'star', 'polygon', 'eyedropper']
if (modesToCancel.includes(mode)) {
this.leftPanel.clickSelect()
}
}
}
export default EditorStartup

View File

@@ -3,9 +3,18 @@ import { t } from '../locale.js'
const template = document.createElement('template')
template.innerHTML = `
<style>
@keyframes btnHover {
from {
background-color: var(--main-bg-color);
}
to {
background-color: var(--icon-bg-color-hover);
}
}
:host(:hover) :not(.disabled)
{
background-color: var(--icon-bg-color-hover);
animation: btnHover 0.2s forwards;
}
div
{

View File

@@ -39,9 +39,17 @@ export class FlyingButton extends HTMLElement {
:host {
position:relative;
}
.overall:hover *
{
background-color: var(--icon-bg-color-hover);
@keyframes btnHover {
from {
background-color: transparent;
}
to {
background-color: var(--icon-bg-color-hover);
}
}
.overall .menu-button:hover {
animation: btnHover 0.2s forwards;
}
img {
border: none;

View File

@@ -44,6 +44,23 @@ template.innerHTML = `
margin-top: 2px;
margin-bottom: 1px;
}
#arrow-up, #arrow-down {
user-select: none;
}
@keyframes hover-arrows {
from {
background: transparent;
color: var(--icon-bg-color-hover);
}
to {
background: var(--icon-bg-color-hover);
color: var(--orange-color);
}
}
#arrow-up:hover, #arrow-down:hover {
animation: hover-arrows 0.2s forwards;
}
#down{
width:18px;
height:23px;

View File

@@ -83,6 +83,7 @@ export default {
callback () {
// Add the button and its handler(s)
const title = `${name}:buttons.0.title`
// #TODO: Come up with another shortcut (?) because 'I' is reserved for italic
const key = `${name}:buttons.0.key`
const buttonTemplate = `
<se-button id="tool_eyedropper" title="${title}" src="eye_dropper.svg" shortcut=${key}></se-button>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<svg width="20" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1">
<title>circle_cursor</title>
<g class="layer">
<title>Layer 1</title>
<g id="layer2">
<path d="m0.1,7.76l7.7,-7.66l-7.7,0l0,7.66z" fill="#2b3c45" id="path9" stroke="#2b3c45"
stroke-dashoffset="0" stroke-width="0.19" />
</g>
<circle cx="9.44" cy="9.06" display="inline" fill="#ffffff" id="path10" r="5.98" stroke="#2b3c45"
stroke-dashoffset="0" stroke-width="1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 599 B

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<svg width="20" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1">
<title>circle_cursor</title>
<g class="layer">
<title>Layer 1</title>
<g class="layer" id="svg_2">
<g id="layer2">
<path d="m0.1,6.37l6.3,-6.27l-6.3,0l0,6.27z" fill="#2b3c45" id="path9" stroke="#2b3c45"
stroke-dashoffset="0" stroke-width="0.2" />
</g>
<ellipse cx="11.0" cy="7" fill="#ffffff" id="svg_1" rx="7.5" ry="3.43" stroke="#2b3c45" stroke-width="1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 623 B

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<svg width="20" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1">
<title>circle_cursor</title>
<g class="layer">
<title>Layer 1</title>
<g class="layer" id="svg_2">
<path d="m0.1,6.37l6.3,-6.27l-6.3,0l0,6.27z" fill="#2b3c45" id="path9" stroke="#2b3c45"
stroke-dashoffset="0" stroke-width="0.2" />
</g>
<rect fill="#ffffff" height="6.4" id="svg_3" stroke="#2b3c45" width="13.6" x="4.54" y="4.53" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 556 B

View File

@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<svg width="20" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1">
<title>circle_cursor</title>
<g class="layer">
<title>Layer 1</title>
<g class="layer" id="svg_2">
<g id="layer2">
<path d="m0.1,6.37l6.3,-6.27l-6.3,0l0,6.27z" fill="#2b3c45" id="path9" stroke="#2b3c45" stroke-dashoffset="0" stroke-width="0.2"/>
</g>
</g>
<rect fill="#ffffff" height="8" id="svg_3" stroke="#2b3c45" width="8" x="5.04" y="4.43"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 517 B

View File

@@ -764,14 +764,25 @@ class TopPanel {
}
}
/**
* Checks if there are currently selected text elements to avoid firing of bold,italic when no text selected
* @returns {boolean}
*/
get anyTextSelected () {
const selected = this.editor.svgCanvas.getSelectedElements()
return selected.filter(el => el.tagName === 'text').length > 0
}
/**
*
* @returns {false}
*/
clickBold () {
this.editor.svgCanvas.setBold(!this.editor.svgCanvas.getBold())
this.updateContextPanel()
return false
if (this.anyTextSelected) {
this.editor.svgCanvas.setBold(!this.editor.svgCanvas.getBold())
this.updateContextPanel()
return false
}
}
/**
@@ -779,9 +790,11 @@ class TopPanel {
* @returns {false}
*/
clickItalic () {
this.editor.svgCanvas.setItalic(!this.editor.svgCanvas.getItalic())
this.updateContextPanel()
return false
if (this.anyTextSelected) {
this.editor.svgCanvas.setItalic(!this.editor.svgCanvas.getItalic())
this.updateContextPanel()
return false
}
}
/**

View File

@@ -8,6 +8,7 @@
--icon-bg-color: #72797A;
--icon-bg-color-hover: #2B3C45;
--input-color: #B2B2B2;
--orange-color: #f9bc01;
--global-se-spin-input-width: 82px;
}