瀏覽代碼

perfect_contextMenu

ananzhusen 2 年之前
父節點
當前提交
f538f2d9d4
共有 3 個文件被更改,包括 494 次插入209 次删除
  1. 180 203
      pnpm-lock.yaml
  2. 313 6
      src/views/components/ContextMenu.vue
  3. 1 0
      src/views/components/View.vue

文件差異過大導致無法顯示
+ 180 - 203
pnpm-lock.yaml


+ 313 - 6
src/views/components/ContextMenu.vue

@@ -17,31 +17,327 @@
         </a>
       </t-dropdown-item>
     </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>
 </template>
 
 <script setup lang="ts">
-import { ref } from "vue";
+import { ref } from 'vue';
+import { LockState, Pen, PenType, Meta2d } from '@meta2d/core';
 
 const props = defineProps({
   type: String,
 });
-const emit = defineEmits(["changeVisible"]);
-
+const emit = defineEmits(['changeVisible']);
+function closeMenu() {
+  emit('changeVisible', false);
+}
 const onAddAnchorHand = () => {
   meta2d.addAnchorHand();
-  emit("changeVisible", false);
+  closeMenu();
 };
 
 const onRemoveAnchorHand = () => {
   meta2d.removeAnchorHand();
-  emit("changeVisible", false);
+  closeMenu();
 };
 
 const onToggleAnchorHand = () => {
   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>
 
 <style lang="postcss" scoped>
@@ -68,6 +364,7 @@ const onToggleAnchorHand = () => {
       display: block;
       text-decoration: none;
       color: var(--color);
+      margin-left: 8px;
 
       label {
         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>

+ 1 - 0
src/views/components/View.vue

@@ -880,6 +880,7 @@ const contextmenu = ({ e, rect }: { e: any; rect: any }) => {
     contextMenuType.value = 'anchor';
   } else {
     //其他右键菜单
+    contextMenuType.value = 'pen';
   }
 
   if (!contextMenuVisible.value && contextMenuType.value) {

部分文件因文件數量過多而無法顯示