132 lines
4.6 KiB
JavaScript
132 lines
4.6 KiB
JavaScript
import React, { useState, useMemo, useLayoutEffect, useRef } from 'react'
|
|
import { ToolbarBlock, ToolbarLine } from './ToolbarElements'
|
|
|
|
const NAME_CATEGORIES = {
|
|
logical: 'Логические',
|
|
arithmetic: 'Арифметические',
|
|
timers: 'Таймеры',
|
|
counters: 'Счётчики',
|
|
comparisons: 'Сравнения',
|
|
other: 'Другие',
|
|
customized: 'Пользовательские'
|
|
};
|
|
|
|
const BLOCK_CATEGORIES = {
|
|
logical: [
|
|
{ type: 'and', label: 'AND', inputCount: 2, outputCount: 1 },
|
|
{ type: 'or', label: 'OR', inputCount: 2, outputCount: 1 },
|
|
{ type: 'not', label: 'NOT', inputCount: 1, outputCount: 1 },
|
|
{ type: 'xor', label: 'XOR', inputCount: 2, outputCount: 1 }],
|
|
arithmetic: [
|
|
{ type: 'add', label: 'ADD', inputCount: 2, outputCount: 1 },
|
|
{ type: 'sub', label: 'SUB', inputCount: 2, outputCount: 1 },
|
|
{ type: 'mul', label: 'MUL', inputCount: 2, outputCount: 1 },
|
|
{ type: 'div', label: 'DIV', inputCount: 2, outputCount: 1 }],
|
|
timers: [
|
|
{ type: 'ton', label: 'TON', inputCount: 2, outputCount: 1 },
|
|
{ type: 'tof', label: 'TOF', inputCount: 2, outputCount: 1 },
|
|
{ type: 'tp', label: 'TP', inputCount: 2, outputCount: 1 }],
|
|
counters: [
|
|
{ type: 'ctu', label: 'CTU', inputCount: 2, outputCount: 1 },
|
|
{ type: 'ctd', label: 'CTD', inputCount: 2, outputCount: 1 },
|
|
{ type: 'ctud', label: 'CTUD',inputCount: 2, outputCount: 1 }],
|
|
comparisons: [
|
|
{ type: 'gt', label: 'GT', inputCount: 2, outputCount: 1 },
|
|
{ type: 'lt', label: 'LT', inputCount: 2, outputCount: 1 },
|
|
{ type: 'eq', label: 'EQ', inputCount: 2, outputCount: 1 }],
|
|
other: [
|
|
{ type: 'sr', label: 'SR', inputCount: 2, outputCount: 1 },
|
|
{ type: 'rs', label: 'RS', inputCount: 2, outputCount: 1 },
|
|
{ type: 'move', label: 'MOVE', inputCount: 2, outputCount: 1 }],
|
|
customized: []
|
|
};
|
|
|
|
const LINES_TYPES = [
|
|
{ type: 'bool', stroke: '#000', dasharray: '0' },
|
|
{ type: 'a', stroke: '#000', dasharray: '4 4' }, // Пунктир
|
|
{ type: 'b', stroke: '#D8000A', dasharray: '0' }, // Красная
|
|
{ type: 'c', stroke: '#000', dasharray: '1 3' }, // Точечная
|
|
{ type: 'd', stroke: '#008000', dasharray: '0' }, // Зеленая
|
|
{ type: 'e', stroke: '#1717D8', dasharray: '0' } // Синяя
|
|
];
|
|
|
|
function Toolbar({ activeEdgeType, onChangeEdgeType }) {
|
|
|
|
const [activeTab, setActiveTab] = useState('logical')
|
|
const containerRef = useRef(null)
|
|
const [caseWidth, setCaseWidth] = useState(0)
|
|
|
|
const tabs = useMemo(() => Object.keys(BLOCK_CATEGORIES), [])
|
|
const activeBlocks = BLOCK_CATEGORIES[activeTab] || []
|
|
|
|
useLayoutEffect(() => {
|
|
if (!containerRef.current)
|
|
return
|
|
|
|
function updateSize() {
|
|
const rect = containerRef.current.getBoundingClientRect()
|
|
setCaseWidth(rect.width / 2)
|
|
}
|
|
|
|
updateSize()
|
|
const observer = new ResizeObserver(() => updateSize())
|
|
observer.observe(containerRef.current)
|
|
return () => observer.disconnect()
|
|
}, [])
|
|
|
|
function onDragStart(event, block) {
|
|
event.dataTransfer.setData('application/reactflow', JSON.stringify({
|
|
type: block.type,
|
|
label: block.label,
|
|
inputCount: block.inputCount,
|
|
outputCount: block.outputCount
|
|
}))
|
|
event.dataTransfer.effectAllowed = 'move'
|
|
}
|
|
|
|
return(
|
|
<div className = "toolbar">
|
|
<h4 style = {{ marginTop: '3px', marginBottom: '15px', textAlign: 'center' }}>Блоки</h4>
|
|
<div className = "toolbarElements">
|
|
{ /*Вкладки*/ }
|
|
<div className = "tabButtons">
|
|
{tabs.map((tab) => (
|
|
<button
|
|
key = {tab}
|
|
className = { activeTab === tab ? 'activeTab' : 'notActiveTab' }
|
|
data-row = { ['customized', 'other', 'comparisons'].includes(tab) ? '2' : '1' }
|
|
onClick = {() => setActiveTab(tab)}
|
|
title = {NAME_CATEGORIES[tab]}
|
|
> { NAME_CATEGORIES[tab] } </button>
|
|
))}
|
|
</div>
|
|
|
|
{ /*Блоки*/ }
|
|
<div className = "toolbarBlocks">
|
|
{activeBlocks.map((block) => (
|
|
<ToolbarBlock
|
|
key = {block.type}
|
|
block = {block}
|
|
onDragStart = {onDragStart}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{/*Линии*/}
|
|
<div className = "toolbarLines" ref = {containerRef}>
|
|
{LINES_TYPES.map((line) => (
|
|
<ToolbarLine
|
|
key = {line.type}
|
|
line = {line}
|
|
caseWidth = {caseWidth}
|
|
isActive = {activeEdgeType === line.type}
|
|
onClick = {onChangeEdgeType}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default Toolbar |