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: Add support for inflating flyout separators. #8592

Merged
merged 4 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
61 changes: 61 additions & 0 deletions core/flyout_separator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import type {IBoundedElement} from './interfaces/i_bounded_element.js';
import {Rect} from './utils/rect.js';

/**
* Representation of a gap between elements in a flyout.
*/
export class FlyoutSeparator implements IBoundedElement {
gonfunko marked this conversation as resolved.
Show resolved Hide resolved
gonfunko marked this conversation as resolved.
Show resolved Hide resolved
private x = 0;
private y = 0;

/**
* Creates a new separator.
*
* @param gap The amount of space this separator should occupy.
* @param axis The axis along which this separator occupies space.
*/
constructor(
private gap: number,
private axis: SeparatorAxis,
) {}

/**
* Returns the bounding box of this separator.
*
* @returns The bounding box of this separator.
*/
getBoundingRectangle(): Rect {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If someone uses a really big gap value in a vertical flyout, can it cause the flyout to become excessively wide as a result of the gap being a square instead of a rectangle? If yes, I think we should have gapX and gapY be specified separately

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes; updated it to take an axis argument and be zero-width on the non-dominant axis.

switch (this.axis) {
case SeparatorAxis.X:
return new Rect(this.y, this.y, this.x, this.x + this.gap);
case SeparatorAxis.Y:
return new Rect(this.y, this.y + this.gap, this.x, this.x);
}
}

/**
* Repositions this separator.
*
* @param dx The distance to move this separator on the X axis.
* @param dy The distance to move this separator on the Y axis.
* @param _reason The reason this move was initiated.
*/
moveBy(dx: number, dy: number, _reason?: string[]) {
this.x += dx;
this.y += dy;
}
}

/**
* Representation of an axis along which a separator occupies space.
*/
export const enum SeparatorAxis {
X = 'x',
Y = 'y',
}
69 changes: 69 additions & 0 deletions core/separator_flyout_inflater.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js';
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
import type {WorkspaceSvg} from './workspace_svg.js';
import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js';
import type {SeparatorInfo} from './utils/toolbox.js';
import * as registry from './registry.js';

/**
* Class responsible for creating separators for flyouts.
*/
export class SeparatorFlyoutInflater implements IFlyoutInflater {
/**
* Inflates a dummy flyout separator.
*
* The flyout automatically creates separators between every element with a
* size determined by calling gapForElement on the relevant inflater.
* Additionally, users can explicitly add separators in the flyout definition.
* When separators (implicitly or explicitly created) follow one another, the
* gap of the last one propagates backwards and flattens to one separator.
* This flattening is not additive; if there are initially separators of 2, 3,
* and 4 pixels, after normalization there will be one separator of 4 pixels.
* Therefore, this method returns a zero-width separator, which will be
* replaced by the one implicitly created by the flyout based on the value
* returned by gapForElement, which knows the default gap, unlike this method.
*
* @param _state A JSON representation of a flyout separator.
* @param flyoutWorkspace The workspace the separator belongs to.
* @returns A newly created FlyoutSeparator.
*/
load(_state: Object, flyoutWorkspace: WorkspaceSvg): IBoundedElement {
const flyoutAxis = flyoutWorkspace.targetWorkspace?.getFlyout()
?.horizontalLayout
? SeparatorAxis.X
: SeparatorAxis.Y;
return new FlyoutSeparator(0, flyoutAxis);
}

/**
* Returns the size of the separator. See `load` for more details.
*
* @param state A JSON representation of a flyout separator.
* @param defaultGap The default spacing for flyout items.
* @returns The desired size of the separator.
*/
gapForElement(state: Object, defaultGap: number): number {
const separatorState = state as SeparatorInfo;
const newGap = parseInt(String(separatorState['gap']));
gonfunko marked this conversation as resolved.
Show resolved Hide resolved
return newGap ?? defaultGap;
}

/**
* Disposes of the given separator. Intentional no-op.
*
* @param _element The flyout separator to dispose of.
*/
disposeElement(_element: IBoundedElement): void {}
}

registry.register(
registry.Type.FLYOUT_INFLATER,
'sep',
SeparatorFlyoutInflater,
);