import type { ObjectGroup } from '../../core/model/SceneObject'; import { type Button, Dropdown, Menu, TextField, ui } from '../../ui'; import { dialogSlot, FormDialog } from '../FormDialog'; const FIELD_WIDTH = 220; /** The dropdown entry that makes a group instead of joining one. */ export const NEW_GROUP = 'New group'; const slot = dialogSlot(); /** The open group name dialog, for the check scripts. */ export const currentGroupDialog = slot.current; /** Offered by the dialog that groups objects: an existing group to put them into instead. */ export interface GroupJoin { groups: readonly ObjectGroup[]; onJoin: (groupId: string) => void; /** Label of the confirming button while a group is chosen. */ confirm: string; } /** * Names a hierarchy group (#241) – a new one before it is made, or an existing one. The name is * picked up with the caret already in it, so typing replaces it straight away. Given `join`, a * dropdown above the name offers the existing groups too; picking one puts the objects into it. */ export class GroupNameDialog extends FormDialog { private readonly field: TextField; private readonly choice: Dropdown | undefined; private readonly confirmButton: Button; /** The existing group chosen in the dropdown, '' for a new one. */ private joinId = ''; constructor( title: string, name: string, confirm: string, onName: (name: string) => void, private readonly join?: GroupJoin, ) { super(320, title); const accept = () => { if (this.joinId) join?.onJoin(this.joinId); else onName(this.field.value.trim() || name); }; this.field = new TextField(name, { width: FIELD_WIDTH, onSubmit: () => { this.close(); accept(); }, }); if (join && join.groups.length > 0) { const choice = new Dropdown(NEW_GROUP, { width: FIELD_WIDTH }); choice.onClick = () => new Menu(this.choiceItems(confirm)).openBelow(choice); this.choice = choice; this.content.add(this.formRow(this.fieldLabel('Group'), choice)); } this.content.add(this.formRow(this.fieldLabel('Name'), this.field)); this.confirmButton = this.addButtons(confirm, 'primary', accept); } private choiceItems(confirm: string): { label: string; onSelect: () => void }[] { const pick = (groupId: string, label: string) => () => { this.joinId = groupId; this.choice?.setText(label); this.field.setEnabled(!groupId); this.confirmButton.setText(groupId ? (this.join?.confirm ?? confirm) : confirm); if (!groupId) ui().focus.focus(this.field); }; return [ { label: NEW_GROUP, onSelect: pick('', NEW_GROUP) }, ...(this.join?.groups ?? []).map((g) => ({ label: g.name || 'Group', onSelect: pick(g.id, g.name || 'Group'), })), ]; } /** Opens the dialog centred with the name selected. */ static open(dialog: GroupNameDialog): GroupNameDialog { slot.open(dialog); ui().focus.focus(dialog.field); return dialog; } }