clipboard manipuation
This commit is contained in:
parent
9f1463f410
commit
ce325167c2
|
@ -12,5 +12,7 @@ body {
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
@include page-width();
|
@include page-width();
|
||||||
|
|
||||||
background-color: $bg;
|
background-color: $bg;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,7 @@ import Language from './Language'
|
||||||
import SimulationActions from '../../simulation-actions/components/SimulationActions'
|
import SimulationActions from '../../simulation-actions/components/SimulationActions'
|
||||||
import { Route, Switch } from 'react-router'
|
import { Route, Switch } from 'react-router'
|
||||||
import BackToSimulation from './BackToSimulation'
|
import BackToSimulation from './BackToSimulation'
|
||||||
/**
|
import { sidebarWidth } from '../constants'
|
||||||
* The width of the sidebar
|
|
||||||
*/
|
|
||||||
export const sidebarWidth = 240
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The z-index of the sidebar.
|
* The z-index of the sidebar.
|
||||||
|
|
|
@ -26,3 +26,8 @@ export const icons: IconInterface = {
|
||||||
ic: 'memory'
|
ic: 'memory'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of the sidebar
|
||||||
|
*/
|
||||||
|
export const sidebarWidth = 240
|
||||||
|
|
|
@ -30,6 +30,10 @@ export const EnglishTranslation: Translation = {
|
||||||
clean: 'Clean',
|
clean: 'Clean',
|
||||||
refresh: 'Refresh',
|
refresh: 'Refresh',
|
||||||
undo: 'Undo',
|
undo: 'Undo',
|
||||||
|
paste: 'Paste',
|
||||||
|
copy: 'Copy',
|
||||||
|
duplicate: 'Duplicate',
|
||||||
|
cut: 'Cut',
|
||||||
'select all': 'Select all',
|
'select all': 'Select all',
|
||||||
'delete selection': 'Delete selection',
|
'delete selection': 'Delete selection',
|
||||||
'delete simulation': 'Delete simulation'
|
'delete simulation': 'Delete simulation'
|
||||||
|
|
|
@ -20,7 +20,11 @@ export const DutchTranslation: Translation = {
|
||||||
refresh: 'Todo',
|
refresh: 'Todo',
|
||||||
save: 'Todo',
|
save: 'Todo',
|
||||||
undo: 'Todo',
|
undo: 'Todo',
|
||||||
'delete simulation': `Todo`
|
'delete simulation': `Todo`,
|
||||||
|
copy: 'Todo',
|
||||||
|
cut: 'Todo',
|
||||||
|
duplicate: 'Todo',
|
||||||
|
paste: 'Todo'
|
||||||
},
|
},
|
||||||
createSimulation: {
|
createSimulation: {
|
||||||
mode: {
|
mode: {
|
||||||
|
@ -44,6 +48,7 @@ export const DutchTranslation: Translation = {
|
||||||
cleaned: name => `${name} gewist`,
|
cleaned: name => `${name} gewist`,
|
||||||
refreshed: name => `${name} ververst`,
|
refreshed: name => `${name} ververst`,
|
||||||
undone: name => `${name} ongedaan gemaakt`,
|
undone: name => `${name} ongedaan gemaakt`,
|
||||||
deletedSimulation: name => `Todo`
|
deletedSimulation: name => `Todo`,
|
||||||
|
addedGate: name => 'Todo'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,11 @@ export const RomanianTranslation: Translation = {
|
||||||
clean: 'Curăță',
|
clean: 'Curăță',
|
||||||
refresh: 'Reîncarcă',
|
refresh: 'Reîncarcă',
|
||||||
undo: 'Întoarce',
|
undo: 'Întoarce',
|
||||||
'delete simulation': 'Șterge simulația'
|
'delete simulation': 'Șterge simulația',
|
||||||
|
copy: 'Copiază',
|
||||||
|
paste: 'Lipește',
|
||||||
|
cut: 'Taie',
|
||||||
|
duplicate: 'Clonează'
|
||||||
},
|
},
|
||||||
messages: {
|
messages: {
|
||||||
createdSimulation: name =>
|
createdSimulation: name =>
|
||||||
|
|
0
src/modules/logic-gates/components/GatePreview.tsx
Normal file
0
src/modules/logic-gates/components/GatePreview.tsx
Normal file
|
@ -2,18 +2,19 @@
|
||||||
|
|
||||||
$gate-margin: 1em;
|
$gate-margin: 1em;
|
||||||
|
|
||||||
.gate > section > .gate-preview > * {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gate > section > .gate-preview > * {
|
.gate > section > .gate-preview > * {
|
||||||
display: block;
|
display: block;
|
||||||
height: 10em;
|
height: 10em;
|
||||||
width: 10em;
|
width: 10em;
|
||||||
|
border-radius: 1em;
|
||||||
|
|
||||||
margin: $gate-margin;
|
margin: $gate-margin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gate:hover {
|
||||||
|
border: 2px solid white !important;
|
||||||
|
}
|
||||||
|
|
||||||
.gate > section > .gate-name {
|
.gate > section > .gate-name {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -4,19 +4,31 @@ import { GateTemplate } from '../../simulation/types/GateTemplate'
|
||||||
import GateInfo from './GateInfo'
|
import GateInfo from './GateInfo'
|
||||||
import GateSettings from './GateSettings'
|
import GateSettings from './GateSettings'
|
||||||
import AddGate from './AddGate'
|
import AddGate from './AddGate'
|
||||||
|
import { addGateFromTemplate } from '../helpers/addGateFromTemplate'
|
||||||
|
import { repeat } from '../../vector2/helpers/repeat'
|
||||||
|
|
||||||
export interface LogicGateProps {
|
export interface LogicGateProps {
|
||||||
template: GateTemplate
|
template: GateTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gradientSmoothness = 10
|
||||||
|
|
||||||
const LogicGate = ({ template }: LogicGateProps) => {
|
const LogicGate = ({ template }: LogicGateProps) => {
|
||||||
|
const { fill } = template.material
|
||||||
|
|
||||||
const gatePreview =
|
const gatePreview =
|
||||||
template.material.type === 'image' ? (
|
template.material.type === 'image' ? (
|
||||||
<img src={template.material.fill} alt={template.metadata.name} />
|
<img src={fill} alt={template.metadata.name} />
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: template.material.fill
|
backgroundColor: fill,
|
||||||
|
backgroundImage: `linear-gradient(-60deg,${[
|
||||||
|
...Object.values(template.material.colors)
|
||||||
|
.map(color => repeat(color, gradientSmoothness))
|
||||||
|
.flat(),
|
||||||
|
...repeat(fill, gradientSmoothness)
|
||||||
|
].join(',')})`
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -27,7 +39,12 @@ const LogicGate = ({ template }: LogicGateProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="gate">
|
<div className="gate">
|
||||||
<section>
|
<section>
|
||||||
<div className="gate-preview">{gatePreview}</div>
|
<div
|
||||||
|
className="gate-preview"
|
||||||
|
onClick={() => addGateFromTemplate(template)}
|
||||||
|
>
|
||||||
|
{gatePreview}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<div className="gate-name">{name}</div>
|
<div className="gate-name">{name}</div>
|
||||||
|
|
|
@ -201,6 +201,48 @@ export const baseTemplates: DeepPartial<GateTemplate>[] = [
|
||||||
count: 0
|
count: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
metadata: {
|
||||||
|
name: 'rgb light'
|
||||||
|
},
|
||||||
|
material: {
|
||||||
|
fill: '#1C1C1C',
|
||||||
|
colors: {
|
||||||
|
1: '#00f',
|
||||||
|
2: `#0f0`,
|
||||||
|
3: `#0ff`,
|
||||||
|
4: `#f00`,
|
||||||
|
5: `#f0f`,
|
||||||
|
6: `#ff0`,
|
||||||
|
7: `#fff`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
activation: `
|
||||||
|
const color = (context.get(0) << 2) + (context.get(1) << 1) + context.get(2)
|
||||||
|
|
||||||
|
if (color === 0){
|
||||||
|
context.color(context.colors.main)
|
||||||
|
}
|
||||||
|
|
||||||
|
else{
|
||||||
|
context.color(context.colors[color])
|
||||||
|
}
|
||||||
|
`
|
||||||
|
},
|
||||||
|
integration: {
|
||||||
|
output: true
|
||||||
|
},
|
||||||
|
info: ['https://en.wikipedia.org/wiki/Incandescent_light_bulb'],
|
||||||
|
pins: {
|
||||||
|
outputs: {
|
||||||
|
count: 0
|
||||||
|
},
|
||||||
|
inputs: {
|
||||||
|
count: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Transform } from '../../../common/math/classes/Transform'
|
||||||
import { BehaviorSubject, fromEvent } from 'rxjs'
|
import { BehaviorSubject, fromEvent } from 'rxjs'
|
||||||
import { map } from 'rxjs/operators'
|
import { map } from 'rxjs/operators'
|
||||||
import { getWidth } from '../helpers/getWidth'
|
import { getWidth } from '../helpers/getWidth'
|
||||||
|
import { sidebarWidth } from '../../core/constants'
|
||||||
|
|
||||||
const width = new BehaviorSubject(getWidth())
|
const width = new BehaviorSubject(getWidth())
|
||||||
const height = new BehaviorSubject(window.innerHeight)
|
const height = new BehaviorSubject(window.innerHeight)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { sidebarWidth } from '../../core/components/Sidebar'
|
import { sidebarWidth } from '../../core/constants'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to get the width of the canvas
|
* Helper to get the width of the canvas
|
||||||
|
|
|
@ -8,12 +8,19 @@ import { selectAll } from './helpers/selectAll'
|
||||||
import { deleteSelection } from './helpers/deleteSelection'
|
import { deleteSelection } from './helpers/deleteSelection'
|
||||||
import { cleanRenderer } from './helpers/clean'
|
import { cleanRenderer } from './helpers/clean'
|
||||||
import { deleteSimulation } from './helpers/deleteSimulation'
|
import { deleteSimulation } from './helpers/deleteSimulation'
|
||||||
|
import { copy, cut } from './helpers/copy'
|
||||||
|
import { paste } from './helpers/paste'
|
||||||
|
import { duplicate } from './helpers/duplicate'
|
||||||
|
|
||||||
export const actionIcons: Record<possibleAction, string> = {
|
export const actionIcons: Record<possibleAction, string> = {
|
||||||
clean: 'clear',
|
clean: 'clear',
|
||||||
refresh: 'refresh',
|
refresh: 'refresh',
|
||||||
save: 'save',
|
save: 'save',
|
||||||
undo: 'undo',
|
undo: 'undo',
|
||||||
|
copy: 'file_copy',
|
||||||
|
cut: 'file_copy',
|
||||||
|
paste: 'unarchive',
|
||||||
|
duplicate: 'view_module',
|
||||||
'select all': 'select_all',
|
'select all': 'select_all',
|
||||||
'delete selection': 'delete',
|
'delete selection': 'delete',
|
||||||
'delete simulation': 'delete_forever'
|
'delete simulation': 'delete_forever'
|
||||||
|
@ -52,6 +59,10 @@ export const SidebarActions: Record<possibleAction, SidebarAction> = {
|
||||||
},
|
},
|
||||||
['ctrl', 'shift', 'delete']
|
['ctrl', 'shift', 'delete']
|
||||||
),
|
),
|
||||||
|
...createActionConfig('cut', cut, ['ctrl', 'x']),
|
||||||
|
...createActionConfig('paste', paste, ['ctrl', 'v']),
|
||||||
|
...createActionConfig('duplicate', duplicate, ['ctrl', 'd']),
|
||||||
|
...createActionConfig('copy', copy, ['ctrl', 'c']),
|
||||||
...createActionConfig('select all', selectAll, ['ctrl', 'a']),
|
...createActionConfig('select all', selectAll, ['ctrl', 'a']),
|
||||||
...createActionConfig('delete selection', deleteSelection, ['delete'])
|
...createActionConfig('delete selection', deleteSelection, ['delete'])
|
||||||
}
|
}
|
||||||
|
|
57
src/modules/simulation-actions/helpers/copy.ts
Normal file
57
src/modules/simulation-actions/helpers/copy.ts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
|
||||||
|
import { idStore } from '../../simulation/stores/idStore'
|
||||||
|
import { deleteGate } from '../../simulationRenderer/helpers/deleteGate'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to copy the selection of a renderer
|
||||||
|
*
|
||||||
|
* @param renderer The renderer to copy the selection of
|
||||||
|
*/
|
||||||
|
export const copy = (renderer: SimulationRenderer) => {
|
||||||
|
const selected = renderer.getSelected()
|
||||||
|
|
||||||
|
renderer.wireClipboard = []
|
||||||
|
renderer.clipboard = selected.map(gate => ({
|
||||||
|
name: gate.template.metadata.name,
|
||||||
|
position: gate.transform.position
|
||||||
|
}))
|
||||||
|
|
||||||
|
for (const wire of renderer.simulation.wires) {
|
||||||
|
const start = selected.find(gate => gate === wire.start.value.gate)
|
||||||
|
const end = selected.find(gate => gate === wire.end.value.gate)
|
||||||
|
|
||||||
|
if (start && end) {
|
||||||
|
const startIndex = selected.indexOf(start)
|
||||||
|
const endIndex = selected.indexOf(end)
|
||||||
|
|
||||||
|
renderer.wireClipboard.push({
|
||||||
|
id: idStore.generate(),
|
||||||
|
from: {
|
||||||
|
id: startIndex,
|
||||||
|
total: wire.start.total,
|
||||||
|
index: wire.start.index
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
id: endIndex,
|
||||||
|
total: wire.end.total,
|
||||||
|
index: wire.end.index
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as copy but deletes the selected gates
|
||||||
|
*
|
||||||
|
* @param renderer The renderer to cut the selected gates of
|
||||||
|
*/
|
||||||
|
export const cut = (renderer: SimulationRenderer) => {
|
||||||
|
copy(renderer)
|
||||||
|
|
||||||
|
for (const gate of renderer.getSelected()) {
|
||||||
|
deleteGate(renderer.simulation, gate, renderer)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.clearSelection()
|
||||||
|
}
|
13
src/modules/simulation-actions/helpers/duplicate.ts
Normal file
13
src/modules/simulation-actions/helpers/duplicate.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
|
||||||
|
import { copy } from './copy'
|
||||||
|
import { paste } from './paste'
|
||||||
|
|
||||||
|
export const duplicate = (renderer: SimulationRenderer) => {
|
||||||
|
const { clipboard, wireClipboard } = renderer
|
||||||
|
|
||||||
|
copy(renderer)
|
||||||
|
paste(renderer)
|
||||||
|
|
||||||
|
renderer.clipboard = clipboard
|
||||||
|
renderer.wireClipboard = wireClipboard
|
||||||
|
}
|
46
src/modules/simulation-actions/helpers/paste.ts
Normal file
46
src/modules/simulation-actions/helpers/paste.ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { SimulationRenderer } from '../../simulationRenderer/classes/SimulationRenderer'
|
||||||
|
import { instantiateGateInitter } from '../../simulation/helpers/addGate'
|
||||||
|
import { Wire } from '../../simulation/classes/Wire'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pastes the content of the clipboard
|
||||||
|
*
|
||||||
|
* @param renderer The renderer to use
|
||||||
|
*/
|
||||||
|
export const paste = (renderer: SimulationRenderer) => {
|
||||||
|
const { clipboard, wireClipboard } = renderer
|
||||||
|
|
||||||
|
const ids: number[] = []
|
||||||
|
|
||||||
|
for (const initter of clipboard) {
|
||||||
|
ids.push(instantiateGateInitter(renderer, initter, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const wire of wireClipboard) {
|
||||||
|
const start = renderer.simulation.gates.get(ids[wire.from.id])
|
||||||
|
const end = renderer.simulation.gates.get(ids[wire.to.id])
|
||||||
|
|
||||||
|
if (start && end && start.data && end.data) {
|
||||||
|
const startPin = start.data._pins.outputs[wire.from.index]
|
||||||
|
const endPin = end.data._pins.inputs[wire.to.index]
|
||||||
|
|
||||||
|
renderer.simulation.wires.push(
|
||||||
|
new Wire(
|
||||||
|
{
|
||||||
|
value: startPin,
|
||||||
|
index: wire.from.index,
|
||||||
|
total: wire.from.total
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: endPin,
|
||||||
|
index: wire.to.index,
|
||||||
|
total: wire.to.total
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.clearSelection()
|
||||||
|
renderer.selectedGates.permanent = new Set(ids)
|
||||||
|
}
|
|
@ -9,3 +9,7 @@ export type possibleAction =
|
||||||
| 'select all'
|
| 'select all'
|
||||||
| 'delete selection'
|
| 'delete selection'
|
||||||
| 'delete simulation'
|
| 'delete simulation'
|
||||||
|
| 'copy'
|
||||||
|
| 'paste'
|
||||||
|
| 'duplicate'
|
||||||
|
| 'cut'
|
||||||
|
|
|
@ -9,10 +9,20 @@ import { Screen } from '../../screen/helpers/Screen'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
import { createToastArguments } from '../../toasts/helpers/createToastArguments'
|
||||||
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
|
||||||
|
import { GateInitter } from '../../simulationRenderer/types/GateInitter'
|
||||||
|
|
||||||
export const addGate = (renderer: SimulationRenderer, templateName: string) => {
|
/**
|
||||||
|
* Adds a gate to a renderer
|
||||||
|
*
|
||||||
|
* @param renderer The renderer to add the gate to
|
||||||
|
* @param templateName The name of the template to add
|
||||||
|
*/
|
||||||
|
export const addGate = (
|
||||||
|
renderer: SimulationRenderer,
|
||||||
|
templateName: string,
|
||||||
|
log = true
|
||||||
|
) => {
|
||||||
const template = templateStore.get(templateName)
|
const template = templateStore.get(templateName)
|
||||||
const translation = CurrentLanguage.getTranslation()
|
|
||||||
|
|
||||||
if (!template)
|
if (!template)
|
||||||
throw new SimulationError(`Cannot find template ${templateName}`)
|
throw new SimulationError(`Cannot find template ${templateName}`)
|
||||||
|
@ -37,10 +47,38 @@ export const addGate = (renderer: SimulationRenderer, templateName: string) => {
|
||||||
renderer.simulation.push(gate)
|
renderer.simulation.push(gate)
|
||||||
renderer.spawnCount++
|
renderer.spawnCount++
|
||||||
|
|
||||||
toast(
|
if (log) {
|
||||||
...createToastArguments(
|
const translation = CurrentLanguage.getTranslation()
|
||||||
translation.messages.addedGate(templateName),
|
|
||||||
'add_circle_outline'
|
toast(
|
||||||
|
...createToastArguments(
|
||||||
|
translation.messages.addedGate(templateName),
|
||||||
|
'add_circle_outline'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
|
return gate.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a gate to a renderer and sets its position
|
||||||
|
*
|
||||||
|
* @param renderer The renderer to add the gate to
|
||||||
|
* @param initter The initter to use
|
||||||
|
*/
|
||||||
|
export const instantiateGateInitter = (
|
||||||
|
renderer: SimulationRenderer,
|
||||||
|
initter: GateInitter,
|
||||||
|
log = true
|
||||||
|
) => {
|
||||||
|
const id = addGate(renderer, initter.name, log)
|
||||||
|
|
||||||
|
const gate = renderer.simulation.gates.get(id)
|
||||||
|
|
||||||
|
if (gate && gate.data) {
|
||||||
|
gate.data.transform.position = initter.position
|
||||||
|
}
|
||||||
|
|
||||||
|
return id
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,13 @@ import { dumpSimulation } from '../../saving/helpers/dumpSimulation'
|
||||||
import { modalIsOpen } from '../../modals/helpers/modalIsOpen'
|
import { modalIsOpen } from '../../modals/helpers/modalIsOpen'
|
||||||
import { SimulationError } from '../../errors/classes/SimulationError'
|
import { SimulationError } from '../../errors/classes/SimulationError'
|
||||||
import { deleteWire } from '../../simulation/helpers/deleteWire'
|
import { deleteWire } from '../../simulation/helpers/deleteWire'
|
||||||
import { RendererState } from '../../saving/types/SimulationSave'
|
import { RendererState, WireState } from '../../saving/types/SimulationSave'
|
||||||
import { setToArray } from '../../../common/lang/arrays/helpers/setToArray'
|
import { setToArray } from '../../../common/lang/arrays/helpers/setToArray'
|
||||||
import { Transform } from '../../../common/math/classes/Transform'
|
import { Transform } from '../../../common/math/classes/Transform'
|
||||||
import { gatesInSelection } from '../helpers/gatesInSelection'
|
import { gatesInSelection } from '../helpers/gatesInSelection'
|
||||||
import { selectionType } from '../types/selectionType'
|
import { selectionType } from '../types/selectionType'
|
||||||
import { addIdToSelection, idIsSelected } from '../helpers/idIsSelected'
|
import { addIdToSelection, idIsSelected } from '../helpers/idIsSelected'
|
||||||
|
import { GateInitter } from '../types/GateInitter'
|
||||||
|
|
||||||
export class SimulationRenderer {
|
export class SimulationRenderer {
|
||||||
public mouseDownOutput = new Subject<MouseEventInfo>()
|
public mouseDownOutput = new Subject<MouseEventInfo>()
|
||||||
|
@ -50,6 +51,8 @@ export class SimulationRenderer {
|
||||||
public camera = new Camera()
|
public camera = new Camera()
|
||||||
|
|
||||||
public selectedArea = new Transform()
|
public selectedArea = new Transform()
|
||||||
|
public clipboard: GateInitter[] = []
|
||||||
|
public wireClipboard: WireState[] = []
|
||||||
|
|
||||||
// first bit = dragging
|
// first bit = dragging
|
||||||
// second bit = panning around
|
// second bit = panning around
|
||||||
|
@ -82,8 +85,6 @@ export class SimulationRenderer {
|
||||||
|
|
||||||
this.lastMousePosition = worldPosition
|
this.lastMousePosition = worldPosition
|
||||||
|
|
||||||
console.log('click')
|
|
||||||
|
|
||||||
// We need to iterate from the last to the first
|
// We need to iterate from the last to the first
|
||||||
// because if we have 2 overlapping gates,
|
// because if we have 2 overlapping gates,
|
||||||
// we want to select the one on top
|
// we want to select the one on top
|
||||||
|
@ -294,7 +295,7 @@ export class SimulationRenderer {
|
||||||
public updateWheelListener(ref: RefObject<HTMLCanvasElement>) {
|
public updateWheelListener(ref: RefObject<HTMLCanvasElement>) {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
ref.current.addEventListener('wheel', event => {
|
ref.current.addEventListener('wheel', event => {
|
||||||
if (!modalIsOpen()) {
|
if (!modalIsOpen() && location.pathname === '/') {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
handleScroll(event, this.camera)
|
handleScroll(event, this.camera)
|
||||||
|
|
9
src/modules/simulationRenderer/types/GateInitter.ts
Normal file
9
src/modules/simulationRenderer/types/GateInitter.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { vector2 } from '../../../common/math/classes/Transform'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to init a gate at a certain position
|
||||||
|
*/
|
||||||
|
export interface GateInitter {
|
||||||
|
name: string
|
||||||
|
position: vector2
|
||||||
|
}
|
8
src/modules/vector2/helpers/repeat.ts
Normal file
8
src/modules/vector2/helpers/repeat.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Repeats an element a number of times
|
||||||
|
*
|
||||||
|
* @param element The element to repeat a number of times
|
||||||
|
* @param count The number of times to repeat the element
|
||||||
|
*/
|
||||||
|
export const repeat = <T>(element: T, count = 1): T[] =>
|
||||||
|
[...Array(count)].fill(element)
|
Loading…
Reference in a new issue