355 lines
9.3 KiB
Vue

<template>
<div
v-if="VisibleUserPivotIds.has(props.id)"
@mouseenter="onEnter()"
@mouseleave="onLeave()"
@contextmenu.prevent="handleUserContextMenu($event)"
class="user-pivot"
:style="userPivotStyle"
>
<div
class="vertical-cursor-wrapper"
:style="cursorStyle"
>
<div class="current-display-cursor-up">
<div class="current-time-value" :style="colorStyle">{{ props.label }}</div>
<div class="cursor-down-arrow" :style="borderStyle"></div>
</div>
<div
class="vertical-line"
:style="colorStyle"
:ref="el => vline.element = el"
@mousedown.stop="onVLineMousedown()"
></div>
<div class="current-display-cursor-down">
<div class="current-time-value" :style="colorStyle">{{ props.label }}</div>
<div class="cursor-up-arrow" :style="borderStyle"></div>
</div>
</div>
<teleport to='body'>
<transition name="collapse-from-top">
<div
v-show="UserPivotCtxShows.get(props.id)"
class="user-context-menu"
:style="contextStyle"
>
<div class="menu-container">
<div
class="menu-item-container"
@click="deletePivot(props.time)"
>
<span class="menu-item-icon iconfont icon-delete"></span>
<span class="menu-item-name">{{ t('pivot.context.delete') }}</span>
</div>
<div
class="menu-item-container"
@click="displayRelativeAxis()"
>
<span class="menu-item-icon iconfont icon-axis"></span>
<span class="menu-item-name">{{ t('pivot.context.display-axis') }}</span>
</div>
<div
class="menu-item-container"
:class="{ 'disable': !RelativeAxis.show }"
@click="cancelRelativeAxis()"
>
<span class="menu-item-icon iconfont icon-delete"></span>
<span class="menu-item-name">{{ t('pivot.context.cancel-axis') }}</span>
</div>
</div>
</div>
</transition>
</teleport>
</div>
</template>
<script setup>
import { globalLookup } from '@/hook/global';
import { eventHandler, registerWheelEvent } from '@/hook/wave-view';
import { computed, defineComponent, ref, onMounted, reactive, nextTick } from 'vue';
import { time2cursorX, mousemoveEventPipes, MovingPivot, cursorX2time } from './cursor';
import { boxShift, currentPivotId, deletePivot, getNearestUserPivot, orderedTimes, searchOrderedTimeIndex, UserPivotCtxShows, UserPivots, VisibleUserPivotIds } from './pivot-view';
import formatTime from '@/hook/wave-view/format-time';
import { useI18n } from 'vue-i18n';
import { increaseBrightness, parseColor } from '@/hook/color';
import { RelativeAxis } from './relative-axis';
// import { handleUserContextMenu } from './user-context-menu';
defineComponent({ name: 'user-pivot' });
const { t } = useI18n();
const props = defineProps({
color: {
type: String,
default: 'var(--main-color)'
},
label: {
type: String
},
x: {
type: Number
},
time: {
type: Number
},
id: {
type: Number
}
});
const currentColor = computed(() => {
if (props.id === currentPivotId.value) {
const rgbColor = parseColor(props.color);
const brighterColor = increaseBrightness(rgbColor, 20);
return `rgb(${brighterColor.r}, ${brighterColor.g}, ${brighterColor.b})`;
}
return props.color;
});
const userPivotStyle = computed(() => ({
cursor: vline.dragEnable ? 'ew-resize': 'pointer'
}));
const colorStyle = computed(() => ({
backgroundColor: currentColor.value
}));
const borderStyle = computed(() => ({
borderLeft: '5px solid ' + currentColor.value,
borderTop: '5px solid ' + currentColor.value
}));
const cursorStyle = computed(() => ({
left: props.x - boxShift + 'px'
}));
function onEnter() {
MovingPivot.enterUserPivot = true;
}
function onLeave() {
MovingPivot.show = true;
MovingPivot.currentTakenPivot = undefined;
MovingPivot.enterUserPivot = false;
}
const vline = reactive({
dragEnable: false,
element: undefined,
originTime: 0,
});
function onVLineMousedown() {
const div = vline.element;
if (!(div instanceof HTMLElement)) {
return;
}
vline.dragEnable = true;
MovingPivot.dragEnable = true;
currentPivotId.value = props.id;
vline.originTime = props.time;
const pivot = UserPivots.get(vline.originTime);
if (pivot === undefined) {
return;
}
// 先从 orderTimes 里面拿走
const i = searchOrderedTimeIndex(vline.originTime);
if (i !== undefined) {
orderedTimes.splice(i, 1);
}
mousemoveEventPipes.set(pivot.id, event => {
if (vline.dragEnable === false) {
return;
}
const x = event.clientX || event.x;
pivot.x = x;
const pstate = globalLookup.pstate;
if (pstate) {
const { timescale } = pstate;
const t = cursorX2time(x);
pivot.time = t;
pivot.label = formatTime(t, timescale);
}
});
}
function onVLineMouseup() {
MovingPivot.dragEnable = false;
mousemoveEventPipes.delete(props.id);
const div = vline.element;
if (!(div instanceof HTMLElement)) {
return;
}
const pivot = UserPivots.get(vline.originTime);
if (pivot) {
UserPivots.delete(vline.originTime);
UserPivots.set(pivot.time, pivot);
orderedTimes.push(pivot.time);
orderedTimes.sort((a, b) => a - b);
}
currentPivotId.value = 0;
vline.originTime = 0;
vline.dragEnable = false;
// MovingPivot.currentTakenPivot = pivot;
// MovingPivot.show = false;
}
const contextmenu = reactive({
x: 0,
y: 0,
});
const contextStyle = computed(() => ({
top: contextmenu.y + 'px',
left: contextmenu.x + 20 + 'px'
}));
function handleUserContextMenu(event) {
contextmenu.x = event.x;
contextmenu.y = event.y;
for (const id of UserPivotCtxShows.keys()) {
UserPivotCtxShows.set(id, false);
}
UserPivotCtxShows.set(props.id, true);
currentPivotId.value = props.id;
}
function displayRelativeAxis() {
RelativeAxis.currentPivotId = props.id;
RelativeAxis.show = true;
currentPivotId.value = 0;
UserPivotCtxShows.delete(props.id);
}
function cancelRelativeAxis() {
if (RelativeAxis.show === false) {
return;
}
RelativeAxis.show = false;
currentPivotId.value = 0;
UserPivotCtxShows.set(props.id, false);
}
onMounted(() => {
UserPivotCtxShows.set(props.id, false);
const wrapper = document.getElementById('vcd-render-wrapper');
if (wrapper instanceof HTMLElement) {
wrapper.addEventListener('mouseup', onVLineMouseup);
}
});
</script>
<style scoped>
.user-pivot {
cursor: pointer;
}
.vertical-cursor-wrapper {
position: absolute;
top: 0;
padding: 0;
z-index: 55;
display: flex;
flex-direction: column;
align-items: center; /* 沿着横轴(水平方向)对齐 */
justify-content: center; /* 沿着纵轴(垂直方向)对齐 */
transform: translateY(var(--toolbar-height));
}
.current-display-cursor-up {
height: var(--time-scale-height);
width: 50px;
display: flex;
align-items: center;
justify-content: space-around;
color: var(--vscode-foreground);
font-size: 14px;
position: relative;
}
.current-display-cursor-down {
height: var(--time-scale-height);
width: 50px;
display: flex;
align-items: center;
justify-content: space-around;
color: var(--vscode-foreground);
font-size: 14px;
position: relative;
}
.current-time-value {
border-radius: .4em;
color: var(--vscode-foreground);
padding: 5px;
width: fit-content;
font-family: var(--vcd-value-font-family);
white-space: nowrap;
}
.cursor-down-arrow {
transform: rotate(225deg);
position: absolute;
width: 10px;
height: 10px;
/* 25px - 10 * 2 / \sqrt{2} */
left: 17.93px;
bottom: 0;
}
.vertical-line {
cursor: ew-resize;
width: 2px;
height: calc(100vh - 2 * var(--time-scale-height) - 60px);
}
.cursor-up-arrow {
transform: rotate(45deg);
position: absolute;
width: 10px;
height: 10px;
left: 17.93px;
top: 0;
}
.user-context-menu {
z-index: 200;
border-radius: .5em;
padding: 10px;
position: fixed;
box-shadow: 0 0 10px 1px rgb(16, 16, 16);
background-color: var(--sidebar);
border: solid 1px var(--sidebar-border);
}
.menu-item-container.disable {
opacity: 0.5;
cursor: not-allowed !important;
}
.menu-item-container.disable:hover {
transition: unset;
color: unset !important;
background: unset !important;
animation: unset;
}
</style>