Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat (react-components): Add general option and use it to make camera speed settings #4619

Merged
merged 20 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions react-components/src/architecture/base/commands/BaseCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright 2024 Cognite AS
*/

import { type TranslateKey } from '../utilities/TranslateKey';
import { type TranslateDelegate, type TranslateKey } from '../utilities/TranslateKey';
import { clear, remove } from '../utilities/extensions/arrayExtensions';

type UpdateDelegate = (command: BaseCommand) => void;
Expand Down Expand Up @@ -44,7 +44,7 @@ export abstract class BaseCommand {
// =================================================

public get name(): string {
return this.tooltip.fallback ?? this.tooltip.key;
return this.tooltip.fallback;
}

public get shortCutKey(): string | undefined {
Expand All @@ -55,8 +55,8 @@ export abstract class BaseCommand {
return { fallback: '' };
}

public get icon(): string {
return 'Unknown';
public get icon(): string | undefined {
return undefined; // Means no icon
}

public get buttonType(): string {
Expand Down Expand Up @@ -128,4 +128,12 @@ export abstract class BaseCommand {
listener(this);
}
}

public getLabel(translate: TranslateDelegate): string {
const { key, fallback } = this.tooltip;
if (key === undefined) {
return fallback;
}
return translate(key, fallback);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*!
* Copyright 2024 Cognite AS
*/

import { type RevealRenderTarget } from '../renderTarget/RevealRenderTarget';
import { BaseCommand } from './BaseCommand';
import { RenderTargetCommand } from './RenderTargetCommand';

/**
* Base class for all command and tools. These are object that can do a
* user interaction with the system. It also have enough information to
* generate the UI for the command.
*/

export abstract class BaseOptionCommand extends BaseCommand {
private _options: BaseCommand[] | undefined = undefined;

// ==================================================
// VIRTUAL METHODS
// ==================================================

public createOptions(): BaseCommand[] {
return []; // Override this to add options
}

// ==================================================
// INSTANCE METHODS
// ==================================================

public getOptions(renderTarget: RevealRenderTarget): BaseCommand[] {
if (this._options === undefined) {
this._options = this.createOptions();
for (const option of this._options) {
if (option instanceof RenderTargetCommand) {
option.attach(renderTarget);
}
}
}
return this._options;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*!
* Copyright 2024 Cognite AS
*/

import { type BaseCommand } from '../commands/BaseCommand';
import { BaseOptionCommand } from '../commands/BaseOptionCommand';
import { RenderTargetCommand } from '../commands/RenderTargetCommand';
import { type TranslateKey } from '../utilities/TranslateKey';

const KEYBOARD_SPEED_VALUES = [0.5, 1, 2, 5, 10, 20];

export class SetKeyboardSpeedCommand extends BaseOptionCommand {
// ==================================================
// OVERRIDES
// ==================================================

public override get tooltip(): TranslateKey {
return { key: 'FLY_SPEED', fallback: 'Set fly speed on the camera' };
}

public override createOptions(): BaseCommand[] {
const options: BaseCommand[] = [];
for (const value of KEYBOARD_SPEED_VALUES) {
options.push(new OptionCommand(value));
}
return options;
}
}

// Note: This is not exported, as it is only used internally
class OptionCommand extends RenderTargetCommand {
static currentSpeed: number = 1;
private readonly _value;

public constructor(value: number) {
super();
this._value = value;
}

public override get tooltip(): TranslateKey {
return { fallback: this._value.toString() + 'x' };
}

public override get isChecked(): boolean {
return this._value === this.renderTarget.flexibleCameraManager.options.keyboardSpeed;
nilscognite marked this conversation as resolved.
Show resolved Hide resolved
}

public override invokeCore(): boolean {
this.renderTarget.flexibleCameraManager.options.keyboardSpeed = this._value;
nilscognite marked this conversation as resolved.
Show resolved Hide resolved
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,8 @@ export abstract class DomainObject {
// VIRTUAL METHODS: Others
// ==================================================

public get icon(): string {
return 'Unknown';
public get icon(): string | undefined {
return undefined;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { type BaseTool } from '../../base/commands/BaseTool';
import { ToggleMetricUnitsCommand } from '../../base/concreteCommands/ToggleMetricUnitsCommand';
import { MeasurementTool } from '../measurements/MeasurementTool';
import { ClipTool } from '../clipping/ClipTool';
import { SetSpeedOptionCommand } from '../../base/concreteCommands/SetKeyboardSpeedCommand';
nilscognite marked this conversation as resolved.
Show resolved Hide resolved

export class StoryBookConfig extends BaseRevealConfig {
// ==================================================
Expand All @@ -37,6 +38,7 @@ export class StoryBookConfig extends BaseRevealConfig {
new FitViewCommand(),
new SetAxisVisibleCommand(),
new ToggleMetricUnitsCommand(),
new SetSpeedOptionCommand(),
undefined,
new ExampleTool(),
new MeasurementTool(),
Expand Down
42 changes: 25 additions & 17 deletions react-components/src/components/Architecture/CommandButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { useTranslation } from '../i18n/I18n';
import { type BaseCommand } from '../../architecture/base/commands/BaseCommand';
import { type RevealRenderTarget } from '../../architecture/base/renderTarget/RevealRenderTarget';
import { RenderTargetCommand } from '../../architecture/base/commands/RenderTargetCommand';
import { OptionButton } from './OptionButton';
import { BaseOptionCommand } from '../../architecture/base/commands/BaseOptionCommand';
import { getButtonType, getIcon, getTooltipPlacement } from './Utilities';

export const CommandButtons = ({
commands,
Expand All @@ -27,7 +30,11 @@ export const CommandButtons = ({
};

export const CreateCommandButton = (command: BaseCommand, isHorizontal = false): ReactElement => {
return <CommandButton command={command} isHorizontal={isHorizontal} />;
if (command instanceof BaseOptionCommand) {
return <OptionButton command={command} isHorizontal={isHorizontal} />;
} else {
return <CommandButton command={command} isHorizontal={isHorizontal} />;
}
};

export const CommandButton = ({
Expand All @@ -45,15 +52,15 @@ export const CommandButton = ({
const [isEnabled, setEnabled] = useState<boolean>(true);
const [isVisible, setVisible] = useState<boolean>(true);
const [uniqueId, setUniqueId] = useState<number>(0);
const [icon, setIcon] = useState<IconType>('Copy');
const [icon, setIcon] = useState<IconType | undefined>(undefined);

useEffect(() => {
function update(command: BaseCommand): void {
setChecked(command.isChecked);
setEnabled(command.isEnabled);
setVisible(command.isVisible);
setUniqueId(command.uniqueId);
setIcon(command.icon as IconType);
setIcon(getIcon(command));
}
update(newCommand);
newCommand.addEventListener(update);
Expand All @@ -65,23 +72,18 @@ export const CommandButton = ({
if (!isVisible) {
return <></>;
}
const placement = isHorizontal ? 'top' : 'right';
const { key, fallback } = newCommand.tooltip;
// This was the only way it went through compiler: (more button types will be added in the future)
const type = newCommand.buttonType;
if (type !== 'ghost' && type !== 'ghost-destructive' && type !== 'primary') {
return <></>;
}
const text = key === undefined ? fallback : t(key, fallback);
const placement = getTooltipPlacement(isHorizontal);
const tooltip = newCommand.getLabel(t);
return (
<CogsTooltip content={text} placement={placement} appendTo={document.body}>
<CogsTooltip content={tooltip} placement={placement} appendTo={document.body}>
<Button
type={type}
type={getButtonType(newCommand)}
icon={icon}
key={uniqueId}
toggled={isChecked}
disabled={!isEnabled}
aria-label={text}
toggled={isChecked}
aria-label={tooltip}
iconPlacement="right"
onClick={() => {
newCommand.invoke();
}}
Expand All @@ -90,7 +92,10 @@ export const CommandButton = ({
);
};

function getDefaultCommand(newCommand: BaseCommand, renderTarget: RevealRenderTarget): BaseCommand {
export function getDefaultCommand(
newCommand: BaseCommand,
renderTarget: RevealRenderTarget
): BaseCommand {
// If it exists from before, return the existing command
// Otherwise, add the new command to the controller and attach the renderTarget.
if (!newCommand.hasData) {
Expand All @@ -115,5 +120,8 @@ function addCommandButton(
const direction = !isHorizontal ? 'horizontal' : 'vertical';
return <Divider key={index} weight="2px" length="24px" direction={direction} />;
}
return <CommandButton key={command.uniqueId} command={command} isHorizontal={isHorizontal} />;
if (command instanceof BaseOptionCommand)
return <OptionButton key={command.uniqueId} command={command} isHorizontal={isHorizontal} />;
else
return <CommandButton key={command.uniqueId} command={command} isHorizontal={isHorizontal} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { CommandButtons } from './Toolbar';
import { withSuppressRevealEvents } from '../../higher-order-components/withSuppressRevealEvents';
import { type TranslateDelegate } from '../../architecture/base/utilities/TranslateKey';
import { type UnitSystem } from '../../architecture/base/renderTarget/UnitSystem';
import { type DomainObject } from '../../architecture/base/domainObjects/DomainObject';

const TEXT_SIZE = 'x-small';
const HEADER_SIZE = 'small';
Expand Down Expand Up @@ -47,10 +48,8 @@ export const DomainObjectPanel = (): ReactElement => {
return <></>;
}
const unitSystem = root.unitSystem;

const icon = domainObject.icon as IconType;
const icon = getIcon(domainObject);
const header = info.header;

const commands = domainObject.getPanelToolbar();

// Set in the get string on the copy command if any
Expand All @@ -73,9 +72,11 @@ export const DomainObjectPanel = (): ReactElement => {
<table>
<tbody>
<tr>
<PaddedTh>
<Icon type={icon} />
</PaddedTh>
{icon !== undefined && (
<PaddedTh>
<Icon type={icon} />
</PaddedTh>
)}
{text !== undefined && (
<PaddedTh>
<Body size={HEADER_SIZE}>{text}</Body>
Expand Down Expand Up @@ -132,6 +133,13 @@ function toString(info: PanelInfo, translate: TranslateDelegate, unitSystem: Uni
return result;
}

export function getIcon(domainObject: DomainObject): IconType | undefined {
if (domainObject.icon === undefined) {
return undefined;
}
return domainObject.icon as IconType;
}

const NumberTh = styled.th`
text-align: right;
padding-right: 8px;
Expand Down
Loading
Loading