diff --git a/src/component/EditableContent/index.js b/src/component/EditableContent/index.js index c847879..5e81a2f 100644 --- a/src/component/EditableContent/index.js +++ b/src/component/EditableContent/index.js @@ -104,7 +104,7 @@ const EditableContent = function ( ))} ); - }, [initialValue, options, handleConfirm]); + }, [initialValue, options, handleConfirm, handleHideContextMenu, overlay]); let renderContent, renderPopover; switch (inputType) { case "select": diff --git a/src/menu/editor.js b/src/menu/editor.js index 5f935fd..f254a57 100644 --- a/src/menu/editor.js +++ b/src/menu/editor.js @@ -1,4 +1,3 @@ -import { Button, Menu, Upload } from "antd"; import { FolderOpenOutlined, HighlightOutlined, @@ -8,10 +7,14 @@ import { SaveOutlined, UndoOutlined, } from "@ant-design/icons"; +import { Menu } from "antd"; import state from "../store/state"; import store from "../store/global"; import { createNotation, isNote, notations as N } from "../util/notation"; -import { createParagraph } from "../util/paragraph"; +import { + createParagraph, + createParagraphWithNotations, +} from "../util/paragraph"; import { exportFile, loadFile, saveFile } from "../util/file"; import { findParagraphAndNotation } from "../util/editor"; import { @@ -55,19 +58,11 @@ const handleEditMenu = wrappedAction(({ key }) => { ]; break; case "add-paragraph": { - store.paragraphs.push( - createParagraph({ - notations: [ - createNotation({ note: "0" }), - createNotation({ note: "0" }), - createNotation({ note: "0" }), - createNotation({ note: "0" }), - createNotation({ note: N.separator }), - ], - }) - ); + store.paragraphs.push(createParagraphWithNotations()); break; } + default: + break; } }); const handleConvertMenu = wrappedAction(() => { @@ -176,8 +171,19 @@ const handleKeyPress = wrappedAction((ev) => { } case inputKey === "enter" && ctrl && !shift: { const newNotation = createNotation(); - paragraph.notations.splice(notationIndex + 1, 0, newNotation); - state.selectedNotationKey = newNotation.key; + if ( + notationIndex === paragraph.notations.length - 1 && + paragraphIndex === store.paragraphs.length - 1 + ) { + // 在最后一个音符时ctrl+enter插入新段落并创建符号 + store.paragraphs.push(createParagraph({ notations: [newNotation] })); + state.selectedNotationKey = store.paragraphs + .at(-1) + .notations.at(0).key; + } else { + paragraph.notations.splice(notationIndex + 1, 0, newNotation); + state.selectedNotationKey = newNotation.key; + } break; } case inputKey === "j" && !ctrl && !shift: { @@ -218,6 +224,8 @@ const handleKeyPress = wrappedAction((ev) => { paragraph.alignJustify = !paragraph.alignJustify; break; } + default: + break; } } else { // 仅未选中符号时 @@ -226,7 +234,10 @@ const handleKeyPress = wrappedAction((ev) => { state.selectedNotationKey = state.lastSelectedNotationKey || store.paragraphs?.at(0)?.notations?.at(0).key; + break; } + default: + break; } } // 全局 @@ -261,6 +272,8 @@ const handleKeyPress = wrappedAction((ev) => { } break; } + default: + break; } }); diff --git a/src/menu/notation.js b/src/menu/notation.js index 2850e5b..dfdf795 100644 --- a/src/menu/notation.js +++ b/src/menu/notation.js @@ -1,25 +1,19 @@ import { - ArrowDownOutlined, - ArrowUpOutlined, DeleteOutlined, - FontColorsOutlined, - MinusOutlined, - PauseOutlined, - PlusOutlined, RadiusSettingOutlined, StopOutlined, } from "@ant-design/icons"; -import { Menu, message } from "antd"; +import { Menu } from "antd"; import state from "../store/state"; import { findParagraphAndNotation } from "../util/editor"; -import { isNote, isSeparator } from "../util/notation"; +import { isNote } from "../util/notation"; import { runInWrappedAction, wrappedAction } from "../store/history"; const getNotationContextMenu = (notation, paragraph) => { const hasTie = notation.tieTo; const handleMenu = wrappedAction(function ({ key }) { switch (true) { - case key === "tie": + case key === "tie": { if (!hasTie) { state.tieSourceKey = notation.key; return; @@ -30,6 +24,7 @@ const getNotationContextMenu = (notation, paragraph) => { } notation.tieTo = null; break; + } case key === "break-underline": notation.breakUnderline = !notation.breakUnderline; break; @@ -38,76 +33,35 @@ const getNotationContextMenu = (notation, paragraph) => { notation.note = separator; break; } + default: + break; } }); return ( // ENHANCE: 分音符类型显示菜单项
); - - return [ - { - key: "octaveUp", - text: "升高一个八度(8)", - visible: isNote(notation), - onClick: wrappedAction(() => { - notation.octave += 1; - }), - }, - { - key: "octaveDown", - text: "降低一个八度(Shift + 8)", - visible: isNote(notation), - onClick: wrappedAction(() => { - notation.octave -= 1; - }), - }, - { - key: "tie", - text: notation.tieTo ? "删除连音线" : "从此处添加连音线到...", - visible: isNote(notation), - onClick: wrappedAction(() => {}), - }, - { - key: "break-underline", - text: notation.breakUnderline - ? "在此处延续增减时线" - : "在此处打断增减时线", - visible: isNote(notation), - onClick: wrappedAction(() => { - notation.breakUnderline = !notation.breakUnderline; - }), - }, - { - key: "delete", - text: "删除", - onClick: wrappedAction(() => { - const index = paragraph.notations.indexOf(notation); - if (index !== -1) { - paragraph.notations.splice(index, 1); - } else { - message.error("符号不存在"); - } - }), - }, - ]; }; // ENHANCE: 使用EditableContent组件的overlay属性传入菜单 diff --git a/src/menu/paragraph.js b/src/menu/paragraph.js index f1edb12..eafe4da 100644 --- a/src/menu/paragraph.js +++ b/src/menu/paragraph.js @@ -32,6 +32,8 @@ function getParagraphMenuOptions(paragraph) { store.paragraphs.splice(idx, 1); } break; + default: + break; } }); diff --git a/src/store/history.js b/src/store/history.js index 419a4ec..5e2eb8b 100644 --- a/src/store/history.js +++ b/src/store/history.js @@ -1,4 +1,4 @@ -import { action, intercept, keys, runInAction, toJS } from "mobx"; +import { action, runInAction, toJS } from "mobx"; import globalStore from "./global"; const storeHistory = []; @@ -43,12 +43,10 @@ function go(span) { Math.max(0, cursor + span), storeHistory.length - 1 ); - console.log("go ", span); if (newCursor === cursor) { return; } cursor = newCursor; - console.log("gone to ", newCursor); Object.assign(globalStore, storeHistory[newCursor]); } @@ -64,11 +62,6 @@ function executeAction(actionFunc, ...args) { if (!_isEqual(storeHistory[cursor], current)) { storeHistory[++cursor] = current; storeHistory.length = cursor + 1; - console.log( - "pushed history, length & cursor: ", - storeHistory.length, - cursor - ); if (storeHistory.length > 256) { storeHistory.splice(0, 256 - storeHistory.length); } diff --git a/src/util/editor.js b/src/util/editor.js index 361170c..65f8f88 100644 --- a/src/util/editor.js +++ b/src/util/editor.js @@ -1,6 +1,5 @@ import store from "../store/global"; -import { createNotation, notations } from "../util/notation"; -import { createParagraph } from "../util/paragraph"; +import { createParagraphWithNotations } from "../util/paragraph"; import { VERSION } from "./version"; const initialData = { @@ -16,7 +15,7 @@ const initialData = { gapAfterTitle: 16, gapAfterHeader: 32, gapBetweenParagraph: 32, - gapBetweenNotation: 8, + gapBetweenNotation: 16, beat: [4, 4], speed: 75, authors: ["佚名 作词", "简谱编辑器 制谱"], @@ -28,17 +27,7 @@ function getDefaultGlobalData() { } function getDefaultGlobalDataWidthNotations() { const d = getDefaultGlobalData(); - d.paragraphs = [ - createParagraph({ - notations: [ - createNotation({ note: "0" }), - createNotation({ note: "0" }), - createNotation({ note: "0" }), - createNotation({ note: "0" }), - createNotation({ note: notations.separator }), - ], - }), - ]; + d.paragraphs = [createParagraphWithNotations()]; return d; } @@ -55,6 +44,7 @@ function findParagraphAndNotation(key) { res.paragraphIndex = i; return true; } + return false; }); return res; } diff --git a/src/util/file.js b/src/util/file.js index 0ca1ce0..551306b 100644 --- a/src/util/file.js +++ b/src/util/file.js @@ -1,6 +1,7 @@ import { message } from "antd"; import { remove, transaction } from "mobx"; import { toJS } from "mobx"; +import globalState from "../store/state"; import store from "../store/global"; import { clearHistory } from "../store/history"; import domtoimage from "./dom-to-image"; @@ -20,9 +21,9 @@ async function loadFile(file) { const data = await read(file); if (!(data.version <= VERSION)) { message.error("不支持的文件格式,请使用最新版本"); - console.log(data); return; } + globalState.lastSelectedNotationKey = globalState.selectedNotationKey = null; clearHistory(); transaction(() => { for (const key of Object.keys(store)) { @@ -44,12 +45,6 @@ function saveFile() { } function exportFile() { - // const canvas = document.createElement("canvas"); - // const ctx = canvas.getContext("2d"); - // const dpi = window.devicePixelRatio || 1; - // canvas.style.width = store.canvasWidth; - // canvas.style.height = store.canvasHeight; - // ctx.scale(dpi, dpi); domtoimage.toPng(document.querySelector("#temp_svg")).then((dataUrl) => { const downloadLink = document.createElement("a"); downloadLink.download = (store.title || "未标题") + ".png"; diff --git a/src/util/paragraph.js b/src/util/paragraph.js index 04cf667..ef6b2d2 100644 --- a/src/util/paragraph.js +++ b/src/util/paragraph.js @@ -1,3 +1,5 @@ +import { createNotation, notations as N } from "./notation"; + // 新建段落 function createParagraph(initial) { const p = { @@ -12,5 +14,16 @@ function createParagraph(initial) { } return p; } +function createParagraphWithNotations() { + return createParagraph({ + notations: [ + createNotation({ note: "0" }), + createNotation({ note: "0" }), + createNotation({ note: "0" }), + createNotation({ note: "0" }), + createNotation({ note: N.separator }), + ], + }); +} -export { createParagraph }; +export { createParagraph, createParagraphWithNotations }; diff --git a/src/util/placement.js b/src/util/placement.js index ce453b9..f96707e 100644 --- a/src/util/placement.js +++ b/src/util/placement.js @@ -6,22 +6,6 @@ import store from "../store/global"; let canvas, context2D, defaultFontFamily; let measureSvgEl, measureTextEl; -function _calcFontData(fontSize) { - const span = document.createElement("span"); - span.style.fontFamily = window.getComputedStyle(document.body).fontFamily; - span.style.fontSize = `${fontSize}px`; - span.style.visibility = "hidden"; - span.style.position = "absolute"; - span.style.display = "inline-block"; - span.textContent = "x"; - document.body.appendChild(span); - const data = span.getBoundingClientRect(); - return { - xWidth: data.width, - xHeight: data.height, - }; -} - function _initializeCanvas(fontSize) { if (!canvas) { canvas = document.createElement("canvas"); @@ -151,7 +135,8 @@ function calcParagraphContentHeight(paragraph) { } let tieHeight = 0; if (_hasTie(paragraph)) { - tieHeight = placement.maxTieHeight; + // FIXME: 应该计算连音线高度 + // tieHeight = placement.maxTieHeight; } // 段落高度不是最高的音符的高度,而是上边偏移最大的音符的上部分偏移量+下边偏移最 // 大的音符的下部分偏移量 @@ -184,7 +169,8 @@ function calcParagraphAboveOffset(paragraph) { } let tieHeight = 0; if (_hasTie(paragraph)) { - tieHeight = placement.maxTieHeight; + // FIXME: 应该计算连音线高度 + // tieHeight = placement.maxTieHeight; } const notationOffset = notations .map((n) => calcNotationAboveOffset(n)) diff --git a/src/view/ConfigModal/index.js b/src/view/ConfigModal/index.js index 40baa09..a5c0bd9 100644 --- a/src/view/ConfigModal/index.js +++ b/src/view/ConfigModal/index.js @@ -1,4 +1,4 @@ -import { Button, Form, Input, InputNumber, Modal } from "antd"; +import { Button, Form, Input, Modal } from "antd"; import { observer } from "mobx-react-lite"; import { useCallback } from "react"; import store from "../../store/global"; @@ -26,25 +26,28 @@ function ConfigModal({ visible, onVisibleChange }) { const handleClose = useCallback(() => { onVisibleChange?.call(null, false); }, [onVisibleChange]); - const resetConfig = useCallback( - unwrappedAction(() => { - const { - canvasWidth, - canvasHeight, - marginTop, - marginHorizontal, - } = getDefaultGlobalData(); - Object.assign(store, { - canvasWidth, - canvasHeight, - marginTop, - marginHorizontal, - }); - }) - ); + const resetConfig = unwrappedAction(() => { + const { + canvasWidth, + canvasHeight, + marginTop, + marginHorizontal, + gapBetweenParagraph, + gapBetweenNotation, + } = getDefaultGlobalData(); + Object.assign(store, { + canvasWidth, + canvasHeight, + marginTop, + marginHorizontal, + gapBetweenParagraph, + gapBetweenNotation, + }); + }); return (