Skip to content

Commit

Permalink
feat(react-components): Add segmented buttons to the architecture (#4781
Browse files Browse the repository at this point in the history
)

* Add segmented button

* Set right

* Fixing toolbars

* Fixes according to review
  • Loading branch information
nilscognite authored Oct 3, 2024
1 parent 1dc99ca commit 3a5a270
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
import { type BaseCommand } from './BaseCommand';
import { RenderTargetCommand } from './RenderTargetCommand';

export enum OptionType {
Dropdown,
Segmented
}

/**
* Base class for all option like commands. Override createOptions to add options
* or use add method to add them in.
Expand All @@ -15,6 +20,7 @@ export abstract class BaseOptionCommand extends RenderTargetCommand {
// INSTANCE FIELDS/PROPERTIES
// ==================================================

public readonly optionType: OptionType;
private _children: BaseCommand[] | undefined = undefined;

public get children(): BaseCommand[] | undefined {
Expand All @@ -28,6 +34,15 @@ export abstract class BaseOptionCommand extends RenderTargetCommand {
return this._children !== undefined && this._children.length > 0;
}

// ==================================================
// CONSTRUCTOR
// ==================================================

public constructor(optionType: OptionType = OptionType.Dropdown) {
super();
this.optionType = optionType;
}

// ==================================================
// OVERRIDES
// ==================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ import { type TranslateKey } from '../utilities/TranslateKey';

export class SetFlexibleControlsTypeCommand extends RenderTargetCommand {
private readonly _controlsType: FlexibleControlsType;
private readonly _standAlone: boolean; // False if part of a group

// ==================================================
// CONSTRUCTOR
// ==================================================

public constructor(controlsType: FlexibleControlsType) {
public constructor(controlsType: FlexibleControlsType, standAlone: boolean = true) {
super();
this._controlsType = controlsType;
this._standAlone = standAlone;
}

// ==================================================
Expand All @@ -37,6 +39,9 @@ export class SetFlexibleControlsTypeCommand extends RenderTargetCommand {

public override dispose(): void {
super.dispose();
if (!this._standAlone) {
return; // Done by parent
}
const { flexibleCameraManager } = this.renderTarget;
flexibleCameraManager.removeControlsTypeChangeListener(this._controlsTypeChangeHandler);
}
Expand Down Expand Up @@ -85,6 +90,9 @@ export class SetFlexibleControlsTypeCommand extends RenderTargetCommand {

public override attach(renderTarget: RevealRenderTarget): void {
super.attach(renderTarget);
if (!this._standAlone) {
return; // Done by parent
}
const { flexibleCameraManager } = renderTarget;
flexibleCameraManager.addControlsTypeChangeListener(this._controlsTypeChangeHandler);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*!
* Copyright 2024 Cognite AS
*/

import { type RevealRenderTarget } from '../renderTarget/RevealRenderTarget';
import { FlexibleControlsType } from '@cognite/reveal';
import { type TranslateKey } from '../utilities/TranslateKey';
import { BaseOptionCommand, OptionType } from '../commands/BaseOptionCommand';
import { SetFlexibleControlsTypeCommand } from './SetFlexibleControlsTypeCommand';

export class SetOrbitOrFirstPersonModeCommand extends BaseOptionCommand {
// ==================================================
// CONSTRUCTOR
// ==================================================

public constructor() {
super(OptionType.Segmented);
this.add(new SetFlexibleControlsTypeCommand(FlexibleControlsType.Orbit, false));
this.add(new SetFlexibleControlsTypeCommand(FlexibleControlsType.FirstPerson, false));
}

// ==================================================
// OVERRIDES
// ==================================================

public override get tooltip(): TranslateKey {
return { key: 'CONTROLS_TYPE_TOOLTIP', fallback: 'Set Camera to Orbit or Fly mode' };
}

public override attach(renderTarget: RevealRenderTarget): void {
super.attach(renderTarget);
const { flexibleCameraManager } = renderTarget;
flexibleCameraManager.addControlsTypeChangeListener(this._controlsTypeChangeHandler);
}

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

private readonly _controlsTypeChangeHandler = (_newControlsType: FlexibleControlsType): void => {
this.update();
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ export abstract class BaseRevealConfig {
// VIRTUAL METHODS: Override these to config the viewer
// ==================================================

public createTopToolbar(): Array<BaseCommand | undefined> {
return [];
}

public createTopToolbarStyle(): PopupStyle {
return new PopupStyle({ left: 0, top: 0, horizontal: true });
}

public createMainToolbar(): Array<BaseCommand | undefined> {
return [];
}

public createMainToolbarStyle(): PopupStyle {
return new PopupStyle({ right: 0, top: 0, horizontal: false });
return new PopupStyle({ left: 0, top: 48, horizontal: false });
}

public createAxisGizmoTool(): AxisGizmoTool | undefined {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
* Copyright 2024 Cognite AS
*/

import { FlexibleControlsType } from '@cognite/reveal';
import { type BaseCommand } from '../../base/commands/BaseCommand';
import { PopupStyle } from '../../base/domainObjectsHelpers/PopupStyle';
import { SetFlexibleControlsTypeCommand } from '../../base/concreteCommands/SetFlexibleControlsTypeCommand';
import { SetTerrainVisibleCommand } from '../terrain/SetTerrainVisibleCommand';
import { UpdateTerrainCommand } from '../terrain/UpdateTerrainCommand';
import { FitViewCommand } from '../../base/concreteCommands/FitViewCommand';
Expand All @@ -25,6 +22,7 @@ import { SettingsCommand } from '../../base/concreteCommands/SettingsCommand';
import { MockSettingsCommand } from '../../base/commands/mocks/MockSettingsCommand';
import { MockFilterCommand } from '../../base/commands/mocks/MockFilterCommand';
import { ToggleAllModelsVisibleCommand } from '../../base/concreteCommands/ToggleAllModelsVisibleCommand';
import { SetOrbitOrFirstPersonModeCommand } from '../../base/concreteCommands/SetOrbitOrFirstPersonModeCommand';

export class StoryBookConfig extends BaseRevealConfig {
// ==================================================
Expand All @@ -35,16 +33,19 @@ export class StoryBookConfig extends BaseRevealConfig {
return new NavigationTool();
}

public override createMainToolbar(): Array<BaseCommand | undefined> {
public override createTopToolbar(): Array<BaseCommand | undefined> {
return [
new SetFlexibleControlsTypeCommand(FlexibleControlsType.Orbit),
new SetFlexibleControlsTypeCommand(FlexibleControlsType.FirstPerson),
undefined,
new SetOrbitOrFirstPersonModeCommand(),
new FitViewCommand(),
new SetAxisVisibleCommand(),
new KeyboardSpeedCommand()
];
}

public override createMainToolbar(): Array<BaseCommand | undefined> {
return [
new ToggleAllModelsVisibleCommand(),
new ToggleMetricUnitsCommand(),
new KeyboardSpeedCommand(),
new SettingsCommand(),
new MockSettingsCommand(),
new MockFilterCommand(),
Expand All @@ -60,10 +61,6 @@ export class StoryBookConfig extends BaseRevealConfig {
];
}

public override createMainToolbarStyle(): PopupStyle {
return new PopupStyle({ right: 0, top: 0, horizontal: false });
}

public override createAxisGizmoTool(): AxisGizmoTool | undefined {
return new AxisGizmoTool();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const CommandButton = ({
disabled={!isEnabled}
toggled={isChecked}
aria-label={label}
iconPlacement="right"
iconPlacement="left"
onClick={() => {
command.invoke();
renderTarget.domElement.focus();
Expand Down
14 changes: 11 additions & 3 deletions react-components/src/components/Architecture/CommandButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import { useMemo, type ReactElement } from 'react';
import { Divider } from '@cognite/cogs.js';
import { type BaseCommand } from '../../architecture/base/commands/BaseCommand';
import { OptionButton } from './OptionButton';
import { BaseOptionCommand } from '../../architecture/base/commands/BaseOptionCommand';
import { DropdownButton } from './DropdownButton';
import { BaseOptionCommand, OptionType } from '../../architecture/base/commands/BaseOptionCommand';
import { CommandButton } from './CommandButton';
import { SettingsButton } from './SettingsButton';
import { BaseSettingsCommand } from '../../architecture/base/commands/BaseSettingsCommand';
import { BaseFilterCommand } from '../../architecture/base/commands/BaseFilterCommand';
import { FilterButton } from './FilterButton';
import { SegmentedButtons } from './SegmentedButtons';

export function createButton(command: BaseCommand, isHorizontal = false): ReactElement {
if (command instanceof BaseFilterCommand) {
Expand All @@ -21,7 +22,14 @@ export function createButton(command: BaseCommand, isHorizontal = false): ReactE
return <SettingsButton inputCommand={command} isHorizontal={isHorizontal} />;
}
if (command instanceof BaseOptionCommand) {
return <OptionButton inputCommand={command} isHorizontal={isHorizontal} />;
switch (command.optionType) {
case OptionType.Dropdown:
return <DropdownButton inputCommand={command} isHorizontal={isHorizontal} />;
case OptionType.Segmented:
return <SegmentedButtons inputCommand={command} isHorizontal={isHorizontal} />;
default:
return <></>;
}
}
return <CommandButton inputCommand={command} isHorizontal={isHorizontal} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { type TranslateDelegate } from '../../architecture/base/utilities/Transl
import { useClickOutside } from './useClickOutside';
import { DEFAULT_PADDING, OPTION_MIN_WIDTH } from './constants';

export const OptionButton = ({
export const DropdownButton = ({
inputCommand,
isHorizontal = false,
usedInSettings = false
Expand Down Expand Up @@ -84,7 +84,7 @@ export const OptionButton = ({
}
const placement = getTooltipPlacement(isHorizontal);
const label = usedInSettings ? undefined : command.getLabel(t);
const flexDirection = getFlexDirection(isHorizontal);
const flexDirection = getFlexDirection(false); // Always vertical
const children = command.children;
const selectedLabel = command.selectedChild?.getLabel(t);

Expand Down Expand Up @@ -123,7 +123,7 @@ export const OptionButton = ({
key={uniqueId}
disabled={!isEnabled}
toggled={isOpen}
iconPlacement="right"
iconPlacement="left"
aria-label={command.getLabel(t)}
onClick={(event: MouseEvent<HTMLElement>) => {
event.stopPropagation();
Expand All @@ -148,7 +148,7 @@ export function createMenuItem(
icon={getIcon(command)}
disabled={!command.isEnabled}
toggled={command.isChecked}
iconPlacement="right"
iconPlacement="left"
onClick={() => {
command.invoke();
postAction();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export const FilterButton = ({
key={uniqueId}
disabled={!isEnabled}
toggled={isOpen}
iconPlacement="right"
iconPlacement="left"
aria-label={command.getLabel(t)}
style={{
minWidth: usedInSettings ? OPTION_MIN_WIDTH : undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ObservationsTool } from '../../architecture/concrete/observations/Obser
import { createButtonFromCommandConstructor } from './CommandButtons';
import { SettingsCommand } from '../../architecture/base/concreteCommands/SettingsCommand';
import { PointCloudFilterCommand } from '../../architecture';
import { SetOrbitOrFirstPersonModeCommand } from '../../architecture/base/concreteCommands/SetOrbitOrFirstPersonModeCommand';

export class RevealButtons {
static Settings = (): ReactElement =>
Expand All @@ -37,12 +38,15 @@ export class RevealButtons {

static Clip = (): ReactElement => createButtonFromCommandConstructor(() => new ClipTool());

static SetFlexibleControlsTypeOrbit = (): ReactElement =>
static SetOrbitOrFirstPersonMode = (): ReactElement =>
createButtonFromCommandConstructor(() => new SetOrbitOrFirstPersonModeCommand());

static SetOrbitMode = (): ReactElement =>
createButtonFromCommandConstructor(
() => new SetFlexibleControlsTypeCommand(FlexibleControlsType.Orbit)
);

static SetFlexibleControlsTypeFirstPerson = (): ReactElement =>
static SetFirstPersonMode = (): ReactElement =>
createButtonFromCommandConstructor(
() => new SetFlexibleControlsTypeCommand(FlexibleControlsType.FirstPerson)
);
Expand Down
Loading

0 comments on commit 3a5a270

Please sign in to comment.