UNPKG

@itwin/core-frontend

Version:
314 lines • 20.2 kB
/** @packageDocumentation * @module Tools */ import { CompressedId64Set, Id64Arg, Id64Array, Id64String, OrderedId64Array } from "@itwin/core-bentley"; import { Point3d, XAndY } from "@itwin/core-geometry"; import { LocateFilterStatus, LocateResponse } from "../ElementLocateManager"; import { HitDetail } from "../HitDetail"; import { IModelConnection } from "../IModelConnection"; import { SelectionSet } from "../SelectionSet"; import { DecorateContext } from "../ViewContext"; import { Viewport } from "../Viewport"; import { PrimitiveTool } from "./PrimitiveTool"; import { SelectionMethod } from "./SelectTool"; import { BeButtonEvent, BeModifierKeys, EventHandled } from "./Tool"; import { ToolAssistanceInstruction } from "./ToolAssistance"; /** Identifies the source of the elements in the agenda. * @public */ export declare enum ModifyElementSource { /** The source for the element is unknown - not caused by a modification command. */ Unknown = 0, /** The element is selected by the user. */ Selected = 1, /** The element is processed because it is in the selection set. */ SelectionSet = 2,// eslint-disable-line @typescript-eslint/no-shadow /** The element is selected by the user using drag box or crossing line selection. */ DragSelect = 3 } /** Identifies groups of elements added to agenda along with the source. * @public */ export interface GroupMark { start: number; source: ModifyElementSource; } /** The ElementAgenda class is used by [[ElementSetTool]] to hold the collection of elements it will operate on * and to manage their hilite state. * @see [[ElementSetTool]] * @public */ export declare class ElementAgenda { iModel: IModelConnection; /** The IDs of the elements in this agenda. * @note Prefer methods like [[ElementAgenda.add]] instead of modifying directly. */ readonly elements: Id64Array; /** The group source identifiers for the elements in this agenda. * @note Prefer methods like [[ElementAgenda.add]] instead of modifying directly. */ readonly groupMarks: GroupMark[]; manageHiliteState: boolean; constructor(iModel: IModelConnection); /** Get the source for the last group added to this agenda, if applicable. The "source" is merely an indication of what the collection of elements represents. */ getSource(): ModifyElementSource; /** Set the source for the last group added to this agenda. */ setSource(val: ModifyElementSource): void; get isEmpty(): boolean; get count(): number; get length(): number; /** Create [[OrderedId64Array]] from agenda. */ orderIds(): OrderedId64Array; /** Create [[CompressedId64Set]] from agenda. */ compressIds(): CompressedId64Set; /** Empties the agenda and clears hilite state when manageHiliteState is true. */ clear(): void; private setEntriesHiliteState; /** Removes the last group of elements added to this agenda. */ popGroup(): void; /** Return true if elementId is already in this agenda. */ has(id: string): boolean; /** Return true if elementId is already in this agenda. */ find(id: Id64String): boolean; /** Add elements to this agenda. */ add(arg: Id64Arg): boolean; private removeOne; remove(arg: Id64Arg): boolean; /** Add elements not currently in the agenda and remove elements currently in the agenda. */ invert(arg: Id64Arg): boolean; } /** The ElementSetTool class is a specialization of [[PrimitiveTool]] designed to unify operations on sets of elements. * Use to query or modify existing elements as well as to create new elements from existing elements. * Basic tool sequence: * - Populate [[ElementSetTool.agenda]] with the element ids to query or modify. * - Gather any additional input and if requested, enable dynamics to preview result. * - Call [[ElementSetTool.processAgenda]] to apply operation to [[ElementSetTool.agenda]]. * - Call [[ElementSetTool.onProcessComplete]] to restart or exit. * Common element sources: * - Pre-selected elements from an active [[SelectionSet]]. * - Clicking in a view to identify elements using [[ElementLocateManager]]. * - Drag box and crossing line selection. * Default behavior: * - Identify a single element with left-click. * - Immediately apply operation. * - Restart. * Sub-classes are required to opt-in to additional element sources, dynamics, AccuSnap, additional input, etc. * @public */ export declare abstract class ElementSetTool extends PrimitiveTool { private _agenda?; private _useSelectionSet; private _processDataButtonUp; /** The accept point for a selection set, drag select, or final located element. */ protected anchorPoint?: Point3d; /** The button down location that initiated box or crossing line selection. */ protected dragStartPoint?: Point3d; /** Get the [[ElementAgenda]] the tool will operate on. */ protected get agenda(): ElementAgenda; /** Convenience method to get current count from [[ElementSetTool.agenda]]. */ protected get currentElementCount(): number; /** Minimum required number of elements for tool to be able to complete. * @return number to compare with [[ElementSetTool.currentElementCount]] to determine if more elements remain to be identified. * @note A tool to subtract elements is an example where returning 2 would be necessary. */ protected get requiredElementCount(): number; /** Whether to allow element identification by drag box or crossing line selection. * @return true to allow drag select as an element source when the ctrl key is down. * @note Use ctrl+left drag for box selection. Inside/overlap is based on left/right direction (shift key inverts). * @note Use ctrl+right drag for crossing line selection. */ protected get allowDragSelect(): boolean; /** Support operations on groups/assemblies independent of selection scope. * @return true to add or remove all members of an assembly from [[ElementSetTool.agenda]] when any single member is identified. * @note Applies to [[ElementSetTool.getLocateCandidates]] only. */ protected get allowGroups(): boolean; /** Whether [[ElementSetTool.agenda]] should be populated from an active selection set. * @return true to allow selection sets as an element source. * @note A selection set must have at least [[ElementSetTool.requiredElementCount]] elements to be considered. */ protected get allowSelectionSet(): boolean; /** Whether to clear the active selection set for tools that return false for [[ElementSetTool.allowSelectionSet]]. * @return true to clear unsupported selection sets (desired default behavior). * @note It is expected that the selection set be cleared before using [[ElementLocateManager]] to identify elements. * This allows the element hilite to be a visual representation of the [[ElementSetTool.agenda]] contents. */ protected get clearSelectionSet(): boolean; /** Whether a selection set should be processed immediately upon installation or require a data button to accept. * @return false only for tools without settings or a need for confirmation. * @note A tool to delete elements is an example where returning false could be desirable. */ protected get requireAcceptForSelectionSetOperation(): boolean; /** Whether to begin dynamics for a selection set immediately or wait for a data button. * @return false for tools that can start showing dynamics without any additional input. * @note A tool to rotate elements by an active angle setting is an example where returning false could be desirable. */ protected get requireAcceptForSelectionSetDynamics(): boolean; /** Whether original source of elements being modified was the active selection set. * @return true when [[ElementSetTool.allowSelectionSet]] and active selection set count >= [[ElementSetTool.requiredElementCount]]. */ protected get isSelectionSetModify(): boolean; /** Whether drag box or crossing line selection is currently active. * @return true when [[ElementSetTool.allowDragSelect]] and corner points are currently being defined. */ protected get isSelectByPoints(): boolean; /** Whether to continue selection of additional elements by holding the ctrl key down. * @return true to continue the element identification phase beyond [[ElementSetTool.requiredElementCount]] by holding down the ctrl key. */ protected get controlKeyContinuesSelection(): boolean; /** Whether to invert selection of elements identified with the ctrl key held down. * @return true to allow ctrl to deselect already selected elements. */ protected get controlKeyInvertsSelection(): boolean; /** Whether [[ElementSetTool.setupAndPromptForNextAction]] should call [[AccuSnap.enableSnap]] for current tool phase. * @return true to enable snapping to elements. * @note A tool that just needs to identify elements and doesn't care about location should not enable snapping. */ protected get wantAccuSnap(): boolean; /** Whether to automatically start element dynamics after all required elements have been identified. * @return true if tool will implement [[InteractiveTool.onDynamicFrame]] to show element dynamics. */ protected get wantDynamics(): boolean; /** Whether tool is done identifying elements and is ready to move to the next phase. * @return true when [[ElementSetTool.requiredElementCount]] is not yet satisfied or ctrl key is being used to extend selection. */ protected get wantAdditionalElements(): boolean; /** Whether the tool has gathered enough input to call [[ElementSetTool.processAgenda]]. * Sub-classes should override to check for additional point input they collected in [[ElementSetTool.wantProcessAgenda]]. * @return true if tool does not yet have enough information to complete. * @note When [[ElementSetTool.wantDynamics]] is true an additional point is automatically required to support the dynamic preview. */ protected get wantAdditionalInput(): boolean; /** Whether the tool is ready for [[ElementSetTool.processAgenda]] to be called to complete the tool operation. * Sub-classes should override to collect additional point input before calling super or [[ElementSetTool.wantAdditionalInput]]. * @return true if tool has enough information and is ready to complete. */ protected wantProcessAgenda(_ev: BeButtonEvent): boolean; /** Whether tool should operate on an existing selection set or instead prompt user to identity elements. * Unsupported selection sets will be cleared when [[ElementSetTool.clearSelectionSet]] is true. */ protected setPreferredElementSource(): void; /** Get element ids to process from the active selection set. * Sub-classes may override to support selection scopes or apply tool specific filtering. */ protected getSelectionSetCandidates(ss: SelectionSet): Promise<Id64Arg>; /** Populate [[ElementSetTool.agenda]] from a [[SelectionSet]]. * @see [[ElementSetTool.getSelectionSetCandidates]] to filter or augment the set of elements. */ protected buildSelectionSetAgenda(ss: SelectionSet): Promise<boolean>; /** If the supplied element is part of an assembly, return all member ids. */ protected getGroupIds(id: Id64String): Promise<Id64Arg>; /** Get element id(s) to process from a [[HitDetail]] already accepted by [[ElementSetTool.isElementValidForOperation]]. * Sub-classes may override to support selection scopes. */ protected getLocateCandidates(hit: HitDetail): Promise<Id64Arg>; /** Populate [[ElementSetTool.agenda]] from a [[HitDetail]]. * @see [[ElementSetTool.getLocateCandidates]] to add additional elements. */ protected buildLocateAgenda(hit: HitDetail): Promise<boolean>; /** Get ids of spatial elements to process from a clip volume created by drag box selection. */ private static getVolumeSelectionCandidates; /** Get ids of visible elements to process from drag box or crossing line selection. */ private static getAreaSelectionCandidates; /** Get ids of elements to process from drag box or crossing line selection using either the depth buffer or clip vector... * @internal */ static getAreaOrVolumeSelectionCandidates(vp: Viewport, origin: XAndY, corner: XAndY, method: SelectionMethod, allowOverlaps: boolean, filter?: (id: Id64String) => boolean, includeDecorationsForVolume?: boolean): Promise<Set<Id64String>>; /** Get element ids to process from drag box or crossing line selection. * Sub-classes may override to support selection scopes or apply tool specific filtering. */ protected getDragSelectCandidates(vp: Viewport, origin: Point3d, corner: Point3d, method: SelectionMethod, overlap: boolean): Promise<Id64Arg>; /** Populate [[ElementSetTool.agenda]] by drag box or crossing line information. * @see [[ElementSetTool.getDragSelectCandidates]] to filter or augment the set of elements. */ protected buildDragSelectAgenda(vp: Viewport, origin: Point3d, corner: Point3d, method: SelectionMethod, overlap: boolean): Promise<boolean>; /** Quick id validity check. Sub-classes that wish to allow pickable decorations from selection sets can override. */ protected isElementIdValid(id: Id64String, source: ModifyElementSource): boolean; /** Sub-classes should override to apply tool specific filtering and to provide an explanation for rejection. */ protected isElementValidForOperation(hit: HitDetail, _out?: LocateResponse): Promise<boolean>; /** Called from [[ElementSetTool.doLocate]] as well as auto-locate to accept or reject elements under the cursor. */ filterHit(hit: HitDetail, out?: LocateResponse): Promise<LocateFilterStatus>; /** Identify an element and update the element agenda. * @param newSearch true to locate new elements, false to cycle between elements within locate tolerance from a previous locate. * @return true if [[ElementSetTool.agenda]] was changed. */ protected doLocate(ev: BeButtonEvent, newSearch: boolean): Promise<boolean>; /** Whether drag box selection only identifies elements that are wholly inside or also allows those that overlap * the selection rectangle. * @note Inside/overlap is based on left/right direction of corner points (shift key inverts check). */ protected useOverlapSelection(ev: BeButtonEvent): boolean; /** Initiate tool state for start of drag selection. */ protected selectByPointsStart(ev: BeButtonEvent): Promise<boolean>; /** Finish drag selection and update [[ElementSetTool.agenda]] with any elements that may have been identified. */ protected selectByPointsEnd(ev: BeButtonEvent): Promise<boolean>; /** Display drag box and crossing line selection graphics. */ protected selectByPointsDecorate(context: DecorateContext): void; /** Show graphics for when drag selection is active. */ decorate(context: DecorateContext): void; /** Make sure drag selection graphics are updated when mouse moves. */ onMouseMotion(ev: BeButtonEvent): Promise<void>; /** Support initiating drag selection on mouse start drag event when [[ElementSetTool.allowDragSelect]] is true. */ onMouseStartDrag(ev: BeButtonEvent): Promise<EventHandled>; /** Support completing active drag selection on mouse end drag event and update [[ElementSetTool.agenda]]. */ onMouseEndDrag(ev: BeButtonEvent): Promise<EventHandled>; /** Update prompts, cursor, graphics, etc. as appropriate on ctrl and shift key transitions. */ onModifierKeyTransition(_wentDown: boolean, modifier: BeModifierKeys, _event: KeyboardEvent): Promise<EventHandled>; /** Allow reset to cycle between elements identified for overlapping the locate circle. * Advances to next pre-located hit from [[AccuSnap.aSnapHits]] or changes last accepted hit to next hit from [[ElementLocateManger.hitList]]. * @returns EventHandled.Yes if onReinitialize was called to restart or exit tool. */ protected chooseNextHit(ev: BeButtonEvent): Promise<EventHandled>; /** Orchestrates updating the internal state of the tool on a reset button event. * @returns EventHandled.Yes if onReinitialize was called to restart or exit tool. */ protected processResetButton(ev: BeButtonEvent): Promise<EventHandled>; onResetButtonUp(ev: BeButtonEvent): Promise<EventHandled>; onResetButtonDown(ev: BeButtonEvent): Promise<EventHandled>; /** Collect element input until tool has a sufficient number to complete. */ protected gatherElements(ev: BeButtonEvent): Promise<EventHandled | undefined>; /** Collect point input until tool has a sufficient number to complete. */ protected gatherInput(ev: BeButtonEvent): Promise<EventHandled | undefined>; /** Orchestrates advancing the internal state of the tool on a data button event. * - Collect elements: Add to the element agenda until no additional elements are requested. * - Gather input: Initiates element dynamics and accepts additional points as required. * - Complete operation: Process agenda entries, restart or exit tool. * @returns EventHandled.Yes if onReinitialize was called to restart or exit tool. */ protected processDataButton(ev: BeButtonEvent): Promise<EventHandled>; onDataButtonUp(ev: BeButtonEvent): Promise<EventHandled>; onDataButtonDown(ev: BeButtonEvent): Promise<EventHandled>; protected initAgendaDynamics(): Promise<boolean>; /** Sub-classes can override to be notified of [[ElementSetTool.agenda]] changes by other methods. * @note Tools should not modify [[ElementSetTool.agenda]] in this method, it should merely serve as a convenient place * to update information, such as element graphics once dynamics has started, ex. [[ElementSetTool.chooseNextHit]]. */ protected onAgendaModified(): Promise<void>; /** Sub-classes can override to continue with current [[ElementSetTool.agenda]] or restart after processing has completed. */ protected onProcessComplete(): Promise<void>; /** Sub-classes that return false for [[ElementSetTool.requireAcceptForSelectionSetOperation]] should override to apply the tool operation to [[ElementSetTool.agenda]]. */ protected processAgendaImmediate(): Promise<void>; /** Sub-classes that require and use the accept point should override to apply the tool operation to [[ElementSetTool.agenda]]. * @note Not called for [[ElementSetTool.isSelectionSetModify]] when [[ElementSetTool.requireAcceptForSelectionSetOperation]] is false. */ protected processAgenda(_ev: BeButtonEvent): Promise<void>; /** Support either [[ElementSetTool.requireAcceptForSelectionSetOperation]] or [[ElementSetTool.requireAcceptForSelectionSetDynamics]] returning false. */ protected doProcessSelectionSetImmediate(): Promise<void>; /** Setup initial element state, prompts, check [[SelectionSet]], etc. */ onPostInstall(): Promise<void>; /** Make sure elements from [[ElementSetTool.agenda]] that aren't also from [[SelectionSet]] aren't left hilited. */ onCleanup(): Promise<void>; /** Exit and start default tool when [[ElementSetTool.isSelectionSetModify]] is true to allow [[SelectionSet]] to be modified, * or call [[PrimitiveTool.onRestartTool]] to install a new tool instance. */ onReinitialize(): Promise<void>; /** Restore tool assistance after no longer being suspended by either a [[ViewTool]] or [[InputCollector]]. */ onUnsuspend(): Promise<void>; protected get shouldEnableLocate(): boolean; protected get shouldEnableSnap(): boolean; /** Setup auto-locate, AccuSnap, AccuDraw, and supply tool assistance. */ protected setupAndPromptForNextAction(): void; /** Sub-classes should override to provide tool specific instructions. */ protected provideToolAssistance(mainInstrText?: string, additionalInstr?: ToolAssistanceInstruction[]): void; } //# sourceMappingURL=ElementSetTool.d.ts.map