From 6f8e91ed5f6ed34a527553ec4c04b9e5b8316524 Mon Sep 17 00:00:00 2001 From: Aria Minaei Date: Fri, 3 Feb 2023 12:48:19 +0100 Subject: [PATCH] Make default and static overrides distinguishable Right now it's easy for the user to distinguish between a sequenced prop and non-sequenced props. However, among the non-sequenced ones, it's not possible to distinguish between those that have a static override, and those that don't. The goal of this commit is to make it easy to distinguish between the two. --- .../src/sheetObjects/SheetObjectTemplate.ts | 26 +++++---- theatre/shared/src/propTypes/utils.ts | 56 ++++++------------- .../src/propEditors/DefaultValueIndicator.tsx | 35 +++++++----- .../useEditingToolsForCompoundProp.tsx | 21 +++++-- .../useEditingToolsForSimpleProp.tsx | 26 +++++---- 5 files changed, 85 insertions(+), 79 deletions(-) diff --git a/theatre/core/src/sheetObjects/SheetObjectTemplate.ts b/theatre/core/src/sheetObjects/SheetObjectTemplate.ts index afaf263..3b3ffbf 100644 --- a/theatre/core/src/sheetObjects/SheetObjectTemplate.ts +++ b/theatre/core/src/sheetObjects/SheetObjectTemplate.ts @@ -18,6 +18,7 @@ import type { $FixMe, $IntentionalAny, SerializableMap, + SerializablePrimitive, SerializableValue, } from '@theatre/shared/utils/types' import type {Prism, Pointer} from '@theatre/dataverse' @@ -31,6 +32,7 @@ import { isPropConfSequencable, } from '@theatre/shared/propTypes/utils' import getOrderingOfPropTypeConfig from './getOrderingOfPropTypeConfig' +import type {SheetState_Historic} from '@theatre/core/projects/store/types/SheetState_Historic' /** * Given an object like: `{transform: {type: 'absolute', position: {x: 0}}}`, @@ -64,6 +66,10 @@ export default class SheetObjectTemplate { readonly _temp_actions_atom: Atom readonly _cache = new SimpleCache() readonly project: Project + readonly pointerToSheetState: Pointer + readonly pointerToStaticOverrides: Pointer< + SerializableMap | undefined + > get staticConfig() { return this._config.get() @@ -92,6 +98,14 @@ export default class SheetObjectTemplate { this._config = new Atom(config) this._temp_actions_atom = new Atom(_temp_actions) this.project = sheetTemplate.project + + this.pointerToSheetState = + this.sheetTemplate.project.pointers.historic.sheetsById[ + this.address.sheetId + ] + + this.pointerToStaticOverrides = + this.pointerToSheetState.staticOverrides.byObject[this.address.objectKey] } createInstance( @@ -132,17 +146,7 @@ export default class SheetObjectTemplate { getStaticValues(): Prism { return this._cache.get('getStaticValues', () => prism(() => { - const pointerToSheetState = - this.sheetTemplate.project.pointers.historic.sheetsById[ - this.address.sheetId - ] - - const json = - val( - pointerToSheetState.staticOverrides.byObject[ - this.address.objectKey - ], - ) ?? {} + const json = val(this.pointerToStaticOverrides) ?? {} const config = val(this.configPointer) const deserialized = config.deserializeAndSanitize(json) || {} diff --git a/theatre/shared/src/propTypes/utils.ts b/theatre/shared/src/propTypes/utils.ts index 5b48601..b1ac4b0 100644 --- a/theatre/shared/src/propTypes/utils.ts +++ b/theatre/shared/src/propTypes/utils.ts @@ -7,6 +7,7 @@ import type { } from '@theatre/core/propTypes' import type {PathToProp} from '@theatre/shared/utils/addresses' import type {$IntentionalAny} from '@theatre/shared/utils/types' +import memoizeFn from '@theatre/shared/utils/memoizeFn' /** * Either compound or enum properties can be considered "composite" @@ -70,53 +71,32 @@ export function isPropConfSequencable( return !isPropConfigComposite(conf) // now all non-compounds are sequencable } -const compoundPropSequenceabilityCache = new WeakMap< - PropTypeConfig_Compound<{}> | PropTypeConfig_Enum, - boolean ->() - -/** - * See {@link compoundHasSimpleDescendantsImpl} - */ -export function compoundHasSimpleDescendants( - conf: PropTypeConfig_Compound<{}> | PropTypeConfig_Enum, -): boolean { - if (!compoundPropSequenceabilityCache.has(conf)) { - compoundPropSequenceabilityCache.set( - conf, - compoundHasSimpleDescendantsImpl(conf), - ) - } - - return compoundPropSequenceabilityCache.get(conf)! -} - /** * This basically checks of the compound prop has at least one simple prop in its descendants. * In other words, if the compound props has no subs, or its subs are only compounds that eventually * don't have simple subs, this will return false. */ -function compoundHasSimpleDescendantsImpl( - conf: PropTypeConfig_Compound<{}> | PropTypeConfig_Enum, -): boolean { - if (conf.type === 'enum') { - throw new Error(`Not implemented yet for enums`) - } +export const compoundHasSimpleDescendants = memoizeFn( + (conf: PropTypeConfig_Compound<{}> | PropTypeConfig_Enum): boolean => { + if (conf.type === 'enum') { + throw new Error(`Not implemented yet for enums`) + } - for (const key in conf.props) { - const subConf = conf.props[ - key as $IntentionalAny as keyof typeof conf.props - ] as PropTypeConfig - if (isPropConfigComposite(subConf)) { - if (compoundHasSimpleDescendants(subConf)) { + for (const key in conf.props) { + const subConf = conf.props[ + key as $IntentionalAny as keyof typeof conf.props + ] as PropTypeConfig + if (isPropConfigComposite(subConf)) { + if (compoundHasSimpleDescendants(subConf)) { + return true + } + } else { return true } - } else { - return true } - } - return false -} + return false + }, +) /** * Iterates recursively over the simple props of a compound prop. Returns a generator. diff --git a/theatre/studio/src/propEditors/DefaultValueIndicator.tsx b/theatre/studio/src/propEditors/DefaultValueIndicator.tsx index 2fea6ed..c4f7cb5 100644 --- a/theatre/studio/src/propEditors/DefaultValueIndicator.tsx +++ b/theatre/studio/src/propEditors/DefaultValueIndicator.tsx @@ -2,9 +2,9 @@ import {transparentize} from 'polished' import React from 'react' import styled from 'styled-components' -export const theme = { +const theme = { defaultState: { - color: transparentize(0.85, `#C4C4C4`), + color: transparentize(0.95, `#C4C4C4`), }, withStaticOverride: { color: transparentize(0.85, `#C4C4C4`), @@ -28,24 +28,31 @@ const Rect = styled.rect` fill: currentColor; ` -const Icon = () => ( - - - -) +const DefaultIcon = styled.div` + width: 5px; + height: 5px; + border-radius: 1px; + /* border: 1px solid currentColor; */ + background-color: currentColor; +` + +const FilledIcon = styled.div` + width: 5px; + height: 5px; + background-color: currentColor; + border-radius: 1px; +` const DefaultOrStaticValueIndicator: React.FC<{hasStaticOverride: boolean}> = ( props, ) => { return ( - + {props.hasStaticOverride ? ( + + ) : ( + + )} ) } diff --git a/theatre/studio/src/propEditors/useEditingToolsForCompoundProp.tsx b/theatre/studio/src/propEditors/useEditingToolsForCompoundProp.tsx index 4de5cf3..ed34192 100644 --- a/theatre/studio/src/propEditors/useEditingToolsForCompoundProp.tsx +++ b/theatre/studio/src/propEditors/useEditingToolsForCompoundProp.tsx @@ -54,6 +54,13 @@ export function useEditingToolsForCompoundProp( obj: SheetObject, propConfig: PropTypeConfig_Compound<{}>, ): Stuff { + const pathToProp = getPointerParts(pointerToProp).path + + const pointerToStaticOverrides = pointerDeep( + obj.template.pointerToStaticOverrides, + pathToProp, + ) + return usePrism((): Stuff => { // if the compound has no simple descendants, then there isn't much the user can do with it if (!compoundHasSimpleDescendants(propConfig)) { @@ -67,8 +74,6 @@ export function useEditingToolsForCompoundProp( } } - const pathToProp = getPointerParts(pointerToProp).path - /** * TODO This implementation is wrong because {@link stateEditors.studio.ephemeral.projects.stateByProjectId.stateBySheetId.stateByObjectKey.propsBeingScrubbed.flag} * does not prune empty objects @@ -96,6 +101,11 @@ export function useEditingToolsForCompoundProp( obj.template.getMapOfValidSequenceTracks_forStudio(), ) + const staticOverrides = getDeep( + val(obj.template.getStaticValues()), + pathToProp, + ) + const possibleSequenceTrackIds = getDeep( validSequencedTracks, pathToProp, @@ -106,9 +116,8 @@ export function useEditingToolsForCompoundProp( Object.keys(possibleSequenceTrackIds).length !== 0 // check if object is empty or undefined const listOfDescendantTrackIds: SequenceTrackId[] = [] - let hasOneOrMoreStatics = true + let hasOneOrMoreStatics = staticOverrides !== undefined if (hasOneOrMoreSequencedTracks) { - hasOneOrMoreStatics = false for (const descendant of iteratePropType(propConfig, [])) { if (isPropConfigComposite(descendant.conf)) continue const sequencedTrackIdBelongingToDescendant = getDeep( @@ -214,7 +223,9 @@ export function useEditingToolsForCompoundProp( ...common, type: 'AllStatic', controlIndicators: ( - + ), } } diff --git a/theatre/studio/src/propEditors/useEditingToolsForSimpleProp.tsx b/theatre/studio/src/propEditors/useEditingToolsForSimpleProp.tsx index 872f313..9c0293a 100644 --- a/theatre/studio/src/propEditors/useEditingToolsForSimpleProp.tsx +++ b/theatre/studio/src/propEditors/useEditingToolsForSimpleProp.tsx @@ -272,14 +272,20 @@ function createPrism( } } - contextMenuItems.push({ - label: 'Reset to default', - callback: () => { - getStudio()!.transaction(({unset: unset}) => { - unset(pointerToProp) - }) - }, - }) + const allStaticOverrides = val(obj.template.getStaticValues()) + + const staticOverride = getDeep(allStaticOverrides, pathToProp) + + if (typeof staticOverride !== 'undefined') { + contextMenuItems.push({ + label: 'Reset to default', + callback: () => { + getStudio()!.transaction(({unset: unset}) => { + unset(pointerToProp) + }) + }, + }) + } if (isSequencable) { contextMenuItems.push({ @@ -297,9 +303,7 @@ function createPrism( }) } - const statics = val(obj.template.getStaticValues()) - - if (typeof getDeep(statics, pathToProp) !== 'undefined') { + if (typeof staticOverride !== 'undefined') { const ret: EditingToolsStatic = { ...common, type: 'Static',