|
@@ -17,31 +17,327 @@
|
|
</a>
|
|
</a>
|
|
</t-dropdown-item>
|
|
</t-dropdown-item>
|
|
</template>
|
|
</template>
|
|
|
|
+ <template v-if="props.type === 'pen'">
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="layerMove('top')">
|
|
|
|
+ <div class="flex">置顶 <span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="layerMove('bottom')">
|
|
|
|
+ <div class="flex">置底 <span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="layerMove('up')">
|
|
|
|
+ <div class="flex">上一个图层 <span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="layerMove('down')">
|
|
|
|
+ <div class="flex">下一个图层 <span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-divider />
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="layerMove('down')">
|
|
|
|
+ <div class="flex">下一个图层 <span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <template v-if="choosePens()">
|
|
|
|
+ <t-dropdown-item>
|
|
|
|
+ <a @click="combine()">
|
|
|
|
+ <div class="flex">组合 <span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item>
|
|
|
|
+ <a @click="combine(0)">
|
|
|
|
+ <div class="flex">组合为状态 <span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ </template>
|
|
|
|
+ <t-dropdown-item v-if="hasChildren()">
|
|
|
|
+ <a @click="unCombine()">
|
|
|
|
+ <div class="flex">取消组合 <span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="onLock">
|
|
|
|
+ <div class="flex">
|
|
|
|
+ {{ getLocked() ? '解锁' : '锁定' }} <span class="flex-grow"></span>
|
|
|
|
+ </div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-divider />
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="onDel">
|
|
|
|
+ <div class="flex">删除<span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <template v-if="isLine()">
|
|
|
|
+ <t-dropdown-item v-if="isLineType()">
|
|
|
|
+ <a @click="changeType(0)">
|
|
|
|
+ <div class="flex">变成节点<span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item v-else>
|
|
|
|
+ <a @click="changeType(1)">
|
|
|
|
+ <div class="flex">变成连线<span class="flex-grow"></span></div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ </template>
|
|
|
|
+ <t-divider />
|
|
|
|
+ <t-dropdown-item :class="cantUndo() ? 'item-diabled' : ''">
|
|
|
|
+ <a @click="onUndo">
|
|
|
|
+ <div class="flex">撤销<span class="flex-grow"></span>Ctrl + Z</div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item :class="cantRedo() ? 'item-diabled' : ''">
|
|
|
|
+ <a @click="onRedo">
|
|
|
|
+ <div class="flex">恢复<span class="flex-grow"></span>Shift + Z</div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-divider />
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="onCut">
|
|
|
|
+ <div class="flex">剪切<span class="flex-grow"></span>Ctrl + X</div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item
|
|
|
|
+ :class="!choosePens() && !choosePen() ? 'item-diabled' : ''"
|
|
|
|
+ >
|
|
|
|
+ <a @click="onCopy">
|
|
|
|
+ <div class="flex">复制<span class="flex-grow"></span>Ctrl + C</div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ <t-dropdown-item>
|
|
|
|
+ <a @click="onPaste">
|
|
|
|
+ <div class="flex">粘贴<span class="flex-grow"></span>Ctrl + V</div>
|
|
|
|
+ </a>
|
|
|
|
+ </t-dropdown-item>
|
|
|
|
+ </template>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
-import { ref } from "vue";
|
|
|
|
|
|
+import { ref } from 'vue';
|
|
|
|
+import { LockState, Pen, PenType, Meta2d } from '@meta2d/core';
|
|
|
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
type: String,
|
|
type: String,
|
|
});
|
|
});
|
|
-const emit = defineEmits(["changeVisible"]);
|
|
|
|
-
|
|
|
|
|
|
+const emit = defineEmits(['changeVisible']);
|
|
|
|
+function closeMenu() {
|
|
|
|
+ emit('changeVisible', false);
|
|
|
|
+}
|
|
const onAddAnchorHand = () => {
|
|
const onAddAnchorHand = () => {
|
|
meta2d.addAnchorHand();
|
|
meta2d.addAnchorHand();
|
|
- emit("changeVisible", false);
|
|
|
|
|
|
+ closeMenu();
|
|
};
|
|
};
|
|
|
|
|
|
const onRemoveAnchorHand = () => {
|
|
const onRemoveAnchorHand = () => {
|
|
meta2d.removeAnchorHand();
|
|
meta2d.removeAnchorHand();
|
|
- emit("changeVisible", false);
|
|
|
|
|
|
+ closeMenu();
|
|
};
|
|
};
|
|
|
|
|
|
const onToggleAnchorHand = () => {
|
|
const onToggleAnchorHand = () => {
|
|
meta2d.toggleAnchorHand();
|
|
meta2d.toggleAnchorHand();
|
|
- emit("changeVisible", false);
|
|
|
|
|
|
+ closeMenu();
|
|
};
|
|
};
|
|
|
|
+
|
|
|
|
+function choosePen(): boolean {
|
|
|
|
+ return meta2d?.store.active?.length === 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function choosePens(): boolean {
|
|
|
|
+ return meta2d?.store.active?.length > 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function layerMove(type: 'top' | 'bottom' | 'up' | 'down') {
|
|
|
|
+ console.log('layer');
|
|
|
|
+ const pens = meta2d.store.active;
|
|
|
|
+ if (hasImage()) {
|
|
|
|
+ if (type === 'top') {
|
|
|
|
+ meta2d.setValue({
|
|
|
|
+ id: pens[0].id,
|
|
|
|
+ isBottom: false,
|
|
|
|
+ });
|
|
|
|
+ meta2d.top(pens[0]);
|
|
|
|
+ } else if (type === 'bottom') {
|
|
|
|
+ meta2d.setValue({
|
|
|
|
+ id: pens[0].id,
|
|
|
|
+ isBottom: true,
|
|
|
|
+ });
|
|
|
|
+ meta2d.bottom(pens[0]);
|
|
|
|
+ } else if (type === 'up') {
|
|
|
|
+ if (pens[0].isBottom) {
|
|
|
|
+ meta2d.setValue({
|
|
|
|
+ id: pens[0].id,
|
|
|
|
+ isBottom: false,
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ meta2d.up(pens[0]);
|
|
|
|
+ }
|
|
|
|
+ } else if (type === 'down') {
|
|
|
|
+ if (!pens[0].isBottom) {
|
|
|
|
+ meta2d.setValue({
|
|
|
|
+ id: pens[0].id,
|
|
|
|
+ isBottom: true,
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ meta2d.down(pens[0]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (pens[0].name === 'gif') {
|
|
|
|
+ let zIndex = pens[0].calculative.zIndex;
|
|
|
|
+ if (type === 'top') {
|
|
|
|
+ zIndex == 999;
|
|
|
|
+ }
|
|
|
|
+ if (type === 'bottom') {
|
|
|
|
+ zIndex == -999;
|
|
|
|
+ }
|
|
|
|
+ if (type === 'up') {
|
|
|
|
+ zIndex++;
|
|
|
|
+ }
|
|
|
|
+ if (type === 'down') {
|
|
|
|
+ zIndex--;
|
|
|
|
+ }
|
|
|
|
+ meta2d.setValue({
|
|
|
|
+ id: pens[0].id,
|
|
|
|
+ zIndex,
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ if (Array.isArray(pens)) {
|
|
|
|
+ for (const pen of pens) {
|
|
|
|
+ meta2d[type](pen);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ meta2d.render();
|
|
|
|
+ }
|
|
|
|
+ emit('changeVisible', false);
|
|
|
|
+}
|
|
|
|
+function hasChildren(): boolean {
|
|
|
|
+ return choosePen() && meta2d?.store.active[0]?.children?.length > 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getLocked() {
|
|
|
|
+ return meta2d?.store.active?.some((pen: Pen) => pen.locked);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function combine(showChild?: number) {
|
|
|
|
+ meta2d.combine(meta2d.store.active, showChild);
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function unCombine() {
|
|
|
|
+ meta2d.uncombine();
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function onLock() {
|
|
|
|
+ const locked = !getLocked();
|
|
|
|
+ const pens = meta2d.store.active;
|
|
|
|
+ if (Array.isArray(pens)) {
|
|
|
|
+ for (const pen of pens) {
|
|
|
|
+ pen.locked = locked ? LockState.DisableMove : LockState.None;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ meta2d.render();
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function onDel() {
|
|
|
|
+ meta2d.delete();
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function onUndo() {
|
|
|
|
+ meta2d.undo();
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function onRedo() {
|
|
|
|
+ meta2d.redo();
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function onCut() {
|
|
|
|
+ meta2d.cut();
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function onCopy() {
|
|
|
|
+ meta2d.copy();
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function onPaste() {
|
|
|
|
+ meta2d.paste();
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function cantUndo(): boolean {
|
|
|
|
+ return (
|
|
|
|
+ !!meta2d?.store.data.locked ||
|
|
|
|
+ meta2d?.store.histories.length == 0 ||
|
|
|
|
+ meta2d?.store.historyIndex == null ||
|
|
|
|
+ meta2d?.store.historyIndex < 0
|
|
|
|
+ );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function cantRedo(): boolean {
|
|
|
|
+ return (
|
|
|
|
+ !!meta2d?.store.data.locked ||
|
|
|
|
+ meta2d?.store.histories.length == 0 ||
|
|
|
|
+ meta2d?.store.historyIndex == null ||
|
|
|
|
+ meta2d?.store.historyIndex > meta2d?.store.histories.length - 2
|
|
|
|
+ );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function isLine(): boolean {
|
|
|
|
+ return choosePen() && meta2d?.store.active[0]?.name === 'line';
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function isLineType(): boolean {
|
|
|
|
+ return meta2d?.store.active[0]?.type === PenType.Line;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function changeType(type: number) {
|
|
|
|
+ const id = meta2d.store.active[0].id;
|
|
|
|
+ meta2d.setValue(
|
|
|
|
+ {
|
|
|
|
+ id,
|
|
|
|
+ type,
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ history: true,
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ closeMenu();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function hasImage(): boolean {
|
|
|
|
+ const pen = meta2d.store.active[0];
|
|
|
|
+ return choosePen() && pen.image && pen.name !== 'gif';
|
|
|
|
+}
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style lang="postcss" scoped>
|
|
<style lang="postcss" scoped>
|
|
@@ -68,6 +364,7 @@ const onToggleAnchorHand = () => {
|
|
display: block;
|
|
display: block;
|
|
text-decoration: none;
|
|
text-decoration: none;
|
|
color: var(--color);
|
|
color: var(--color);
|
|
|
|
+ margin-left: 8px;
|
|
|
|
|
|
label {
|
|
label {
|
|
font-size: 10px;
|
|
font-size: 10px;
|
|
@@ -79,5 +376,15 @@ const onToggleAnchorHand = () => {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ .item-diabled {
|
|
|
|
+ a {
|
|
|
|
+ cursor: not-allowed;
|
|
|
|
+ color: var(--td-text-color-disabled);
|
|
|
|
+ }
|
|
|
|
+ &:hover {
|
|
|
|
+ background-color: #0000;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
</style>
|
|
</style>
|