Skip to content
Open
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
2 changes: 1 addition & 1 deletion configure/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "configure",
"version": "4.2.11-20260611",
"version": "4.2.12-20260702",
"homepage": "./configure/build",
"private": true,
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mmgis",
"version": "4.2.11-20260611",
"version": "4.2.12-20260702",
"description": "A web-based mapping and localization solution for science operation on planetary missions.",
"homepage": "build",
"repository": {
Expand Down
15 changes: 13 additions & 2 deletions src/essence/Basics/PanelManager_/PanelManager_.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ import { PanelPosition, PanelState, PanelLayoutType, PANEL_STATE, FLOAT_POSITION
import { PanelConfig, PanelStateObject, PanelManager as PanelManagerInterface } from './types/panel';
import { mmgisAPI } from '../../mmgisAPI/mmgisAPI';

/**
* Float panels don't require a priority (they don't compete for edge viewport
* space), so `config.priority` may be undefined. Treat missing priority as
* lowest priority (sorts last) instead of letting `undefined - undefined`
* produce NaN, which Array.prototype.sort treats as "leave order unchanged"
* and yields insertion-order-dependent, effectively unsorted results.
*/
function normalizePriority(priority: number | undefined): number {
return priority === undefined ? Infinity : priority;
}

class PanelManager implements PanelManagerInterface {
private panels: Map<string, PanelStateObject> = new Map();

Expand Down Expand Up @@ -271,7 +282,7 @@ class PanelManager implements PanelManagerInterface {
getPanelsAtPosition(position: PanelPosition): PanelStateObject[] {
return Array.from(this.panels.values())
.filter(p => p.config.position === position)
.sort((a, b) => a.config.priority - b.config.priority);
.sort((a, b) => normalizePriority(a.config.priority) - normalizePriority(b.config.priority));
}

/**
Expand All @@ -282,7 +293,7 @@ class PanelManager implements PanelManagerInterface {
*/
getAllPanelsByPriority(): PanelStateObject[] {
return Array.from(this.panels.values())
.sort((a, b) => a.config.priority - b.config.priority);
.sort((a, b) => normalizePriority(a.config.priority) - normalizePriority(b.config.priority));
}

/**
Expand Down
30 changes: 19 additions & 11 deletions src/essence/Basics/PanelManager_/types/layout.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,40 @@
/**
* Supported panel positions (regions where panels can be placed).
* Positions for edge panels (top/left/right/bottom), which claim viewport
* space and therefore require a `priority` + `layoutType`.
*/
export const PANEL_POSITION = {
const EDGE_POSITION = {
TOP: 'top',
LEFT: 'left',
RIGHT: 'right',
BOTTOM: 'bottom',
} as const
export type EdgePanelPosition = (typeof EDGE_POSITION)[keyof typeof EDGE_POSITION]

/**
* Positions for floating panels, which render as overlays inside the center
* map area and don't compete for edge viewport space.
*/
const FLOAT_POSITION = {
FLOAT_TOP_LEFT: 'float-top-left',
FLOAT_TOP_CENTER: 'float-top-center',
FLOAT_TOP_RIGHT: 'float-top-right',
FLOAT_BOTTOM_LEFT: 'float-bottom-left',
FLOAT_BOTTOM_CENTER: 'float-bottom-center',
FLOAT_BOTTOM_RIGHT: 'float-bottom-right',
} as const
export type PanelPosition = (typeof PANEL_POSITION)[keyof typeof PANEL_POSITION]
export type FloatPanelPosition = (typeof FLOAT_POSITION)[keyof typeof FLOAT_POSITION]

/**
* Supported panel positions (regions where panels can be placed).
*/
export const PANEL_POSITION = { ...EDGE_POSITION, ...FLOAT_POSITION } as const
export type PanelPosition = EdgePanelPosition | FloatPanelPosition

/**
* Set of all float positions for quick membership checks.
* Float panels render inside the center map area as overlays.
*/
export const FLOAT_POSITIONS = new Set([
PANEL_POSITION.FLOAT_TOP_LEFT,
PANEL_POSITION.FLOAT_TOP_CENTER,
PANEL_POSITION.FLOAT_TOP_RIGHT,
PANEL_POSITION.FLOAT_BOTTOM_LEFT,
PANEL_POSITION.FLOAT_BOTTOM_CENTER,
PANEL_POSITION.FLOAT_BOTTOM_RIGHT,
] as const)
export const FLOAT_POSITIONS = new Set(Object.values(FLOAT_POSITION))

/**
* Visual states of a panel:
Expand Down
80 changes: 62 additions & 18 deletions src/essence/Basics/PanelManager_/types/panel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { ToolOrientation, ToolMetadata } from '../../ToolController_/types/tool';
import { PanelPosition, PanelState, PanelLayoutType } from './layout';
import {
PanelPosition,
EdgePanelPosition,
FloatPanelPosition,
PanelState,
PanelLayoutType,
} from './layout';

/**
* Panel size configuration.
Expand Down Expand Up @@ -98,7 +104,8 @@ export interface PanelCapabilities {

/**
* Whether this panel can be resized by the user via drag handles.
* Default: false
* Default: false. Not supported on floating panels — dragging happens
* via move handles instead, so this must be false/omitted there.
*/
resizable?: boolean;

Expand All @@ -116,29 +123,16 @@ export interface PanelCapabilities {
}

/**
* Complete configuration for a panel region.
* Defines behavior, constraints, and appearance.
* Fields shared by every panel, regardless of whether it's an edge or
* floating panel.
*/
export interface PanelConfig {
interface BasePanelConfig {
/** Unique identifier for this panel */
id: string;

/** Display title for the panel */
title?: string;

/** Which region this panel occupies */
position: PanelPosition;

/**
* Layout priority for space allocation.
* Lower numbers claim viewport space first.
* Example: top=0, right=1, bottom=2, left=3
*/
priority: PanelPriority;

/** How tools are laid out when panel is in 'expanded' state */
layoutType: PanelLayoutType;

/** Which states are allowed and what the default state is */
stateConstraints: PanelStateConstraints;

Expand Down Expand Up @@ -168,6 +162,56 @@ export interface PanelConfig {
panelTools?: string[];
}

/**
* Configuration for an edge panel (top/left/right/bottom).
* Edge panels compete for viewport space, so `priority` (stacking/allocation
* order) and `layoutType` (how multiple tools are arranged) are required.
*/
export interface EdgePanelConfig extends BasePanelConfig {
/** Which edge region this panel occupies */
position: EdgePanelPosition;

/**
* Layout priority for space allocation.
* Lower numbers claim viewport space first.
* Example: top=0, right=1, bottom=2, left=3
*/
priority: PanelPriority;

/** How tools are laid out when panel is in 'expanded' state */
layoutType: PanelLayoutType;
}

/**
* Configuration for a floating panel, rendered as an overlay inside the
* center map area. Floats don't compete for edge viewport space, so
* `priority` and `layoutType` are optional, and drag-resize isn't supported.
*/
export interface FloatPanelConfig extends BasePanelConfig {
/** Which float zone this panel occupies */
position: FloatPanelPosition;

/**
* Not used for float layout/rendering, but still affects fallback tool
* assignment: ToolControllerModern_._findPanel picks the first compatible
* panel from the combined edge+float priority order, so a low priority
* here can out-rank an edge panel for an unassigned tool.
*/
priority?: PanelPriority;

/** Accepted but inert for floats — _renderFloatRegions always stacks tools regardless of this value */
layoutType?: PanelLayoutType;

/** Floats can't be drag-resized; `resizable` must be false/omitted */
capabilities?: Omit<PanelCapabilities, 'resizable'> & { resizable?: false };
}

/**
* Complete configuration for a panel region.
* Defines behavior, constraints, and appearance.
*/
export type PanelConfig = EdgePanelConfig | FloatPanelConfig;

/**
* Runtime state object for an active panel.
* Tracks current state, configuration, and associated tools.
Expand Down
Loading