Skip to content

Commit

Permalink
Merge pull request #854 from legion-labs/editor-client-handle-vectors-ui
Browse files Browse the repository at this point in the history
Editor client: Add/remove vector sub properties (UI only)
  • Loading branch information
kevin-legion authored Jan 14, 2022
2 parents 3610e35 + 408d825 commit d7bca79
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import { PropertyUpdate } from "@/api";
import {
BagResourceProperty,
buildDefaultPrimitiveProperty,
propertyIsGroup,
propertyIsOption,
propertyIsVec,
} from "@/lib/propertyGrid";
import Checkbox from "../inputs/Checkbox.svelte";
import PropertyContainer from "./PropertyContainer.svelte";
Expand All @@ -20,10 +22,27 @@
/** The property path parts */
export let pathParts: string[];
export let withBorder: boolean;
/** Adds a new property to a vector, only useful for vectors */
function addVectorSubProperty() {
// TODO: Dispatch event and use rpc add item
property.subProperties = [
...property.subProperties,
buildDefaultPrimitiveProperty(`[${property.subProperties.length}]`, "u8"),
];
}
/** Removes a new property from a vector, only useful for vectors */
function removeVectorSubProperty({ detail: name }: CustomEvent<string>) {
// TODO: Dispatch event and use rpc remove item
property.subProperties = property.subProperties
.filter((property) => property.name !== name)
.map((property, index) => ({ ...property, name: `[${index}]` }));
}
</script>

<div class="root" class:with-indent={level > 1} class:with-border={withBorder}>
<div class="root" class:with-indent={level > 1}>
{#if property.name}
<div class="property-name" title={property.name}>
<div class="truncate">{property.name}</div>
Expand All @@ -33,16 +52,26 @@
<Checkbox value={true} />
</div>
{/if}
{#if propertyIsVec(property)}
<div
class="add-vector"
on:click={addVectorSubProperty}
title="Add property to vector"
>
+
</div>
{/if}
</div>
{/if}
{#each property.subProperties as subProperty, index (subProperty.name)}
{#each property.subProperties as subProperty (subProperty.name)}
<PropertyContainer
on:input
on:removeVectorProperty={removeVectorSubProperty}
pathParts={propertyIsGroup(property)
? pathParts
: [...pathParts, property.name]}
property={subProperty}
nextProperty={property.subProperties[index + 1]}
on:input
parentProperty={property}
level={level + 1}
/>
{/each}
Expand All @@ -57,15 +86,15 @@
@apply pl-1;
}
.with-border {
@apply border-b border-gray-400 border-opacity-30;
}
.property-name {
@apply flex flex-row items-center justify-between h-7 pl-1 my-1 font-bold bg-gray-800 rounded-sm;
@apply flex flex-row items-center justify-between h-7 pl-1 my-0.5 font-semibold bg-gray-800 rounded-sm;
}
.optional {
@apply flex items-center justify-center h-7 w-7 border-l-2 border-gray-700;
@apply flex items-center justify-center h-7 w-7 border-l-2 border-gray-700 cursor-pointer;
}
.add-vector {
@apply flex items-center justify-center h-7 w-7 border-l-2 border-gray-700 cursor-pointer;
}
</style>
Original file line number Diff line number Diff line change
@@ -1,36 +1,32 @@
<script lang="ts">
import { propertyIsBag, ResourceProperty } from "@/lib/propertyGrid";
import {
BagResourceProperty,
propertyIsBag,
ResourceProperty,
} from "@/lib/propertyGrid";
import PropertyBag from "./PropertyBag.svelte";
import PropertyUnit from "./PropertyUnit.svelte";
export let property: ResourceProperty;
export let nextProperty: ResourceProperty | undefined;
export let parentProperty: BagResourceProperty | null = null;
export let level = 0;
/** The property path parts */
export let pathParts: string[];
let nextPropertyIsBag =
(nextProperty && propertyIsBag(nextProperty)) || false;
</script>

<div class="root">
{#if propertyIsBag(property)}
<PropertyBag
on:input
{property}
{level}
{pathParts}
withBorder={(nextProperty && !nextPropertyIsBag) || false}
/>
<PropertyBag on:input {property} {level} {pathParts} />
{:else}
<PropertyUnit
on:input
on:removeVectorProperty
{property}
{parentProperty}
{pathParts}
withBorder={(nextProperty && !nextPropertyIsBag) || false}
/>
{/if}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@
{:else if !$currentResourceData.properties.length}
<div class="italic">Resource has no properties</div>
{:else}
{#each $currentResourceData.properties as property, index (property.name)}
{#each $currentResourceData.properties as property (property.name)}
<PropertyContainer
pathParts={propertyIsGroup(property) ? [] : [property.name]}
{property}
nextProperty={$currentResourceData.properties[index + 1]}
parentProperty={null}
on:input={onInput}
/>
{/each}
Expand All @@ -75,6 +75,6 @@

<style lang="postcss">
.root {
@apply h-full px-1 overflow-y-auto;
@apply h-full px-1 py-1 overflow-y-auto;
}
</style>
178 changes: 105 additions & 73 deletions client/editor/frontend/src/components/propertyGrid/PropertyInput.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { PropertyUpdate } from "@/api";
import {
BagResourceProperty,
buildDefaultPrimitiveProperty,
extractOptionPType,
propertyIsBoolean,
Expand All @@ -25,10 +26,16 @@
import StringProperty from "./properties/StringProperty.svelte";
import Vec3Property from "./properties/Vec3Property.svelte";
const dispatch = createEventDispatcher<{ input: PropertyUpdate }>();
const dispatch = createEventDispatcher<{
input: PropertyUpdate;
// Where `string` is the property `name`
removeVectorProperty: string;
}>();
export let property: ResourceProperty;
export let parentProperty: BagResourceProperty | null;
/** The property path parts */
export let pathParts: string[];
Expand All @@ -42,6 +49,7 @@
// Option related code
// TODO: Try to extract the option input in its own component.
// It seems to fail because of the mutual recursion though.
/**
* Related to the option property, set to `null` if the property is not an option.
* Set to `true` if the option property contains a sub properties, and is therefore `Some`.
Expand Down Expand Up @@ -82,101 +90,125 @@
}
</script>

{#if propertyIsBoolean(property)}
<BooleanProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsString(property)}
<StringProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsNumber(property)}
<NumberProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsColor(property)}
<ColorProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsSpeed(property)}
<SpeedProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsVec3(property)}
<Vec3Property
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsQuat(property)}
<QuatProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsVec(property)}
{property.ptype} not implemented
{:else if propertyIsOption(property)}
{#if property.subProperties[0]}
<div class="option-property">
<svelte:self
on:input
{pathParts}
property={property.subProperties[0]}
<div class="root">
{#if propertyIsBoolean(property)}
<div class="boolean-property">
<BooleanProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
<div class="option-property-checkbox">
<Checkbox on:change={setOptionProperty} value={true} />
</div>
</div>
{:else}
<div class="option-property">
<div
class="cursor-help"
title="This property's value is optional and no value has been set yet"
>
<i>Value not set</i>
<div class="cursor-help-icon">?</div>
{:else if propertyIsString(property)}
<StringProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsNumber(property)}
<NumberProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsColor(property)}
<ColorProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsSpeed(property)}
<SpeedProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsVec3(property)}
<Vec3Property
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsQuat(property)}
<QuatProperty
on:input={({ detail }) => onInput({ value: detail })}
bind:value={property.value}
{disabled}
/>
{:else if propertyIsVec(property)}
{property.ptype} not implemented
{:else if propertyIsOption(property)}
{#if property.subProperties[0]}
<div class="option-property">
<svelte:self
on:input
on:removeVectorProperty
{pathParts}
property={property.subProperties[0]}
{disabled}
/>
<div class="option-property-checkbox">
<Checkbox on:change={setOptionProperty} value={true} />
</div>
</div>
<div class="option-property-checkbox">
<Checkbox on:change={setOptionProperty} value={false} />
{:else}
<div class="option-property">
<div
class="cursor-help"
title="This property's value is optional and no value has been set yet"
>
<div class="cursor-help-icon">?</div>
</div>
<div class="option-property-checkbox">
<Checkbox on:change={setOptionProperty} value={false} />
</div>
</div>
{/if}
{:else}
<div class="unknown-property">
Unknown property: {property.ptype}
</div>
{/if}
{#if parentProperty && propertyIsVec(parentProperty)}
<div
class="close-button"
on:click={() => dispatch("removeVectorProperty", property.name)}
>
&#215;
</div>
{/if}
{:else}
<div class="unknown-property">
Unknown property: {property.ptype}
</div>
{/if}
</div>

<style lang="postcss">
.root {
@apply flex flex-row h-full w-full items-center;
}
.boolean-property {
@apply flex flex-row w-full justify-end;
}
.unknown-property {
@apply break-all;
}
.option-property {
@apply flex flex-row;
@apply flex flex-row justify-between h-full w-full;
}
.option-property-checkbox {
@apply flex items-center flex-shrink-0 h-full pl-1;
}
.cursor-help {
@apply flex flex-row h-8 space-x-1 items-center;
@apply flex flex-row h-8 pt-1;
}
.cursor-help-icon {
@apply flex flex-row self-start justify-center items-center text-xs h-3 w-3 bg-gray-500 rounded-full;
@apply flex flex-row self-start justify-center items-center text-xs h-4 w-4 bg-gray-500 rounded-full;
}
.close-button {
@apply flex flex-row flex-shrink-0 items-center justify-center h-6 w-6 rounded-sm text-xl bg-gray-800 ml-1 cursor-pointer;
}
</style>
Loading

0 comments on commit d7bca79

Please sign in to comment.