ContextMenu.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <template>
  2. <t-menu class="context-menu" @change="onMenu">
  3. <template v-if="props.type === 'anchor'">
  4. <t-menu-item value="addAnchorHand">
  5. <div class="flex">添加手柄 <span class="flex-grow"></span> H</div>
  6. </t-menu-item>
  7. <t-menu-item value="removeAnchorHand">
  8. <div class="flex">删除手柄 <span class="flex-grow"></span> D</div>
  9. </t-menu-item>
  10. <t-menu-item value="toggleAnchorHand">
  11. <div class="flex">切换手柄 <span class="flex-grow"></span> Shift</div>
  12. </t-menu-item>
  13. </template>
  14. <template v-if="props.type === 'pen'">
  15. <t-menu-item :disabled="!selections.mode" value="top"> 置顶 </t-menu-item>
  16. <t-menu-item :disabled="!selections.mode" value="bottom">
  17. 置底
  18. </t-menu-item>
  19. <t-menu-item :disabled="!selections.mode" value="up">
  20. 上一个图层
  21. </t-menu-item>
  22. <t-menu-item :disabled="!selections.mode" value="down">
  23. 下一个图层
  24. </t-menu-item>
  25. <t-divider />
  26. <template v-if="selections.mode === SelectionMode.Pens">
  27. <t-menu-item value="group"> 组合 </t-menu-item>
  28. <t-menu-item value="states"> 组合为状态 </t-menu-item>
  29. </template>
  30. <t-menu-item v-if="hasChildren" value="unGroup"> 取消组合 </t-menu-item>
  31. <t-menu-item :disabled="!selections.mode" value="lock">
  32. {{ locked ? '解锁' : '锁定' }}
  33. </t-menu-item>
  34. <t-divider />
  35. <t-menu-item :disabled="!selections.mode" value="del"> 删除 </t-menu-item>
  36. <template v-if="isNameLine">
  37. <t-menu-item value="changeType">
  38. {{ isLine ? '变成节点' : '变成连线' }}
  39. </t-menu-item>
  40. </template>
  41. <t-divider />
  42. <t-menu-item :disabled="cantUndo" value="undo">
  43. <div class="flex">撤销<span class="flex-grow"></span>Ctrl + Z</div>
  44. </t-menu-item>
  45. <t-menu-item :disabled="cantRedo" value="redo">
  46. <div class="flex">恢复<span class="flex-grow"></span>Shift + Z</div>
  47. </t-menu-item>
  48. <t-divider />
  49. <t-menu-item :disabled="!selections.mode" value="cut">
  50. <div class="flex">剪切<span class="flex-grow"></span>Ctrl + X</div>
  51. </t-menu-item>
  52. <t-menu-item :disabled="!selections.mode" value="copy">
  53. <div class="flex">复制<span class="flex-grow"></span>Ctrl + C</div>
  54. </t-menu-item>
  55. <t-menu-item value="paste">
  56. <div class="flex">粘贴<span class="flex-grow"></span>Ctrl + V</div>
  57. </t-menu-item>
  58. </template>
  59. </t-menu>
  60. </template>
  61. <script setup lang="ts">
  62. import { onMounted, ref } from 'vue';
  63. import { LockState, Pen, PenType } from '@meta2d/core';
  64. import { useSelection, SelectionMode } from '@/services/selections';
  65. const props = defineProps({
  66. type: String,
  67. });
  68. const emit = defineEmits(['changeVisible']);
  69. const { selections } = useSelection();
  70. const hasChildren = ref(false);
  71. const locked = ref(false);
  72. const isNameLine = ref(false);
  73. const isLine = ref(false);
  74. const cantUndo = ref(false);
  75. const cantRedo = ref(false);
  76. onMounted(() => {
  77. if (selections.mode === SelectionMode.Pen) {
  78. hasChildren.value = meta2d?.store.active[0]?.children?.length > 0;
  79. isNameLine.value = meta2d?.store.active[0]?.name === 'line';
  80. isLine.value = meta2d?.store.active[0]?.type === PenType.Line;
  81. }
  82. if (selections.mode) {
  83. locked.value = meta2d?.store.active?.some((pen: Pen) => pen.locked);
  84. }
  85. cantUndo.value =
  86. !!meta2d?.store.data.locked ||
  87. meta2d?.store.histories.length == 0 ||
  88. meta2d?.store.historyIndex == null ||
  89. meta2d?.store.historyIndex < 0;
  90. cantRedo.value =
  91. !!meta2d?.store.data.locked ||
  92. meta2d?.store.histories.length == 0 ||
  93. meta2d?.store.historyIndex == null ||
  94. meta2d?.store.historyIndex > meta2d?.store.histories.length - 2;
  95. });
  96. const onMenu = (val: string) => {
  97. switch (val) {
  98. case 'addAnchorHand':
  99. meta2d.addAnchorHand();
  100. break;
  101. case 'removeAnchorHand':
  102. meta2d.removeAnchorHand();
  103. break;
  104. case 'toggleAnchorHand':
  105. meta2d.toggleAnchorHand();
  106. break;
  107. case 'top':
  108. case 'bottom':
  109. case 'up':
  110. case 'down':
  111. case 'undo':
  112. case 'redo':
  113. case 'cut':
  114. case 'copy':
  115. case 'paste':
  116. (meta2d as any)[val]();
  117. break;
  118. case 'group':
  119. meta2d.combine(meta2d.store.active);
  120. break;
  121. case 'states':
  122. meta2d.combine(meta2d.store.active, 0);
  123. break;
  124. case 'unGroup':
  125. meta2d.uncombine();
  126. break;
  127. case 'lock':
  128. {
  129. const pens = meta2d.store.active;
  130. if (Array.isArray(pens)) {
  131. for (const pen of pens) {
  132. pen.locked = locked.value ? LockState.DisableMove : LockState.None;
  133. }
  134. }
  135. meta2d.render();
  136. }
  137. break;
  138. case 'del':
  139. meta2d.delete();
  140. break;
  141. case 'changeType':
  142. meta2d.setValue(
  143. {
  144. id: meta2d.store.active[0].id,
  145. type: isLine ? 0 : 1,
  146. },
  147. {
  148. history: true,
  149. }
  150. );
  151. break;
  152. }
  153. emit('changeVisible', false);
  154. };
  155. </script>
  156. <style lang="postcss" scoped>
  157. .context-menu {
  158. height: auto !important;
  159. }
  160. </style>