From 8168d60ed9eaa42982c9dd6677a148916e1d7c42 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Mon, 13 Apr 2020 17:45:44 +0300 Subject: [PATCH] feat: internal checkbox for prop gates --- src/common/lang/record/map.ts | 11 +++ .../components/GatePropertiesModal.tsx | 84 +++++++++++++------ .../logic-gates/helpers/completeTemplate.ts | 2 +- src/modules/simulation/classes/Gate.ts | 10 +-- src/modules/simulation/constants.ts | 13 ++- src/modules/simulation/types/GateTemplate.ts | 5 ++ 6 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 src/common/lang/record/map.ts diff --git a/src/common/lang/record/map.ts b/src/common/lang/record/map.ts new file mode 100644 index 0000000..fe8858f --- /dev/null +++ b/src/common/lang/record/map.ts @@ -0,0 +1,11 @@ +// Like Array.map but for records +export const mapRecord = ( + record: Record, + mapper: (a: A) => B +): Record => + Object.fromEntries( + Object.entries(record).map(([key, value]: [T, A]) => [ + key, + mapper(value) + ]) + ) diff --git a/src/modules/logic-gates/components/GatePropertiesModal.tsx b/src/modules/logic-gates/components/GatePropertiesModal.tsx index 1a167d0..e9c1d27 100644 --- a/src/modules/logic-gates/components/GatePropertiesModal.tsx +++ b/src/modules/logic-gates/components/GatePropertiesModal.tsx @@ -8,12 +8,17 @@ import TextField from '@material-ui/core/TextField' import CheckBox from '@material-ui/core/Checkbox' import { open, id } from '../subjects/LogicGatePropsSubjects' import { Gate } from '../../simulation/classes/Gate' +import { mapRecord } from '../../../common/lang/record/map' +import { BehaviorSubject } from 'rxjs' +import { map } from 'rxjs/operators' export interface GatePropertyProps { raw: Property gate: Gate } +const emptyInput = <> + /** * Renders a single props of the gate * @@ -24,7 +29,18 @@ export const GatePropery = ({ raw, gate }: GatePropertyProps) => { const prop = gate.props[name] const outputSnapshot = useObservable(() => prop, '') - const displayableName = `${name[0].toUpperCase()}${name.slice(1)}:` + // rerender when the internal checkbox changes + const internal = useObservable( + () => + gate.props.internal.pipe( + map((value) => value && name !== 'internal') + ), + false + ) + + const displayableName = `${name[0].toUpperCase()}${name.slice(1)} ${ + internal ? '(default value)' : '' + }:` const handleChange = (e: ChangeEvent) => { const target = e.target as HTMLInputElement @@ -45,33 +61,47 @@ export const GatePropery = ({ raw, gate }: GatePropertyProps) => { } } - let input = <> + let input = (() => { + if ( + raw.show && + !raw.show( + mapRecord(gate.props, (subject) => subject.value), + gate + ) + ) { + return emptyInput + } - if (raw.type === 'number' || raw.type === 'text' || raw.type === 'string') { - input = ( - - ) - } else if (raw.type === 'boolean') { - input = ( - <> - {displayableName} - { - prop.next(!outputSnapshot) - }} + if ( + raw.type === 'number' || + raw.type === 'text' || + raw.type === 'string' + ) { + return (input = ( + {' '} - - ) - } + label={displayableName} + value={outputSnapshot} + type={raw.type} + multiline={raw.type === 'string'} + rowsMax={7} + /> + )) + } else if (raw.type === 'boolean') { + return (input = ( + <> + {displayableName} + { + prop.next(!outputSnapshot) + }} + onChange={handleChange} + checked={!!outputSnapshot} + />{' '} + + )) + } + })() return
{input}
} @@ -104,7 +134,7 @@ const GateProperties = () => { >
{ + onClick={(e) => { e.stopPropagation() }} > diff --git a/src/modules/logic-gates/helpers/completeTemplate.ts b/src/modules/logic-gates/helpers/completeTemplate.ts index 98b43d8..b2f0e3a 100644 --- a/src/modules/logic-gates/helpers/completeTemplate.ts +++ b/src/modules/logic-gates/helpers/completeTemplate.ts @@ -4,6 +4,6 @@ import { DefaultGateTemplate } from '../../simulation/constants' export const completeTemplate = (template: DeepPartial) => { return merge(DefaultGateTemplate, template, { - arrayMerge: (a: unknown[], b: unknown[]) => b + arrayMerge: (a: unknown[], b: unknown[]) => a.concat(b) }) as GateTemplate } diff --git a/src/modules/simulation/classes/Gate.ts b/src/modules/simulation/classes/Gate.ts index 4fc4067..a9561f0 100644 --- a/src/modules/simulation/classes/Gate.ts +++ b/src/modules/simulation/classes/Gate.ts @@ -4,7 +4,7 @@ import { GateTemplate, PinCount } from '../types/GateTemplate' import { idStore } from '../stores/idStore' import { Context, InitialisationContext } from '../../activation/types/Context' import { toFunction } from '../../activation/helpers/toFunction' -import { Subscription, BehaviorSubject } from 'rxjs' +import { Subscription, BehaviorSubject, asapScheduler, animationFrameScheduler } from 'rxjs' import { SimulationError } from '../../errors/classes/SimulationError' import { getGateTimePipes } from '../helpers/getGateTimePipes' import { ImageStore } from '../../simulationRenderer/stores/imageStore' @@ -15,7 +15,7 @@ import { saveStore } from '../../saving/stores/saveStore' import { Wire } from './Wire' import { cleanSimulation } from '../../simulation-actions/helpers/clean' import { ExecutionQueue } from '../../activation/classes/ExecutionQueue' -import { tap } from 'rxjs/operators' +import { tap, observeOn } from 'rxjs/operators' /** * The interface for the pins of a gate @@ -205,7 +205,7 @@ export class Gate { if (!state) { throw new SimulationError( `Cannot run ic ${ - this.template.metadata.name + this.template.metadata.name } - save not found` ) } @@ -233,7 +233,7 @@ export class Gate { if (inputs.length !== this._pins.inputs.length) { throw new SimulationError( `Input count needs to match with the container gate: ${ - inputs.length + inputs.length } !== ${this._pins.inputs.length}` ) } @@ -241,7 +241,7 @@ export class Gate { if (outputs.length !== this._pins.outputs.length) { throw new SimulationError( `Output count needs to match with the container gate: ${ - outputs.length + outputs.length } !== ${this._pins.outputs.length}` ) } diff --git a/src/modules/simulation/constants.ts b/src/modules/simulation/constants.ts index 83ce040..a19e712 100644 --- a/src/modules/simulation/constants.ts +++ b/src/modules/simulation/constants.ts @@ -53,7 +53,18 @@ export const DefaultGateTemplate: GateTemplate = { tags: ['base'], properties: { enabled: false, - data: [] + data: [ + { + type: 'boolean', + base: false, + name: 'internal', + show: (_, gate) => + gate.env === 'global' && + !gate.template.properties.data.some( + (prop) => prop.needsUpdate + ) + } + ] }, innerText: { enabled: false, diff --git a/src/modules/simulation/types/GateTemplate.ts b/src/modules/simulation/types/GateTemplate.ts index 07e8ff3..3a38357 100644 --- a/src/modules/simulation/types/GateTemplate.ts +++ b/src/modules/simulation/types/GateTemplate.ts @@ -1,4 +1,5 @@ import { vector2 } from '../../../common/math/types/vector2' +import { Gate } from '../classes/Gate' export interface PinCount { variable: boolean @@ -12,6 +13,10 @@ export interface Property< base: T name: string needsUpdate?: boolean + show?: ( + obj: Record, + gate: Gate + ) => boolean } export interface Material {