import AbstractRenderer from '../rendering/renderers/AbstractRenderer';
import Viewport from '../Viewport';
import AbstractComponent from '../components/AbstractComponent';
import { Rect2 } from '@js-draw/math';
import RenderingCache from '../rendering/caching/RenderingCache';
import SerializableCommand from '../commands/SerializableCommand';
import EventDispatcher from '../EventDispatcher';
import Command from '../commands/Command';
export declare const sortLeavesByZIndex: (leaves: Array<ImageNode>) => void;
export declare enum EditorImageEventType {
    ExportViewportChanged = 0,
    AutoresizeModeChanged = 1,
    ComponentAdded = 2,
    ComponentRemoved = 3
}
interface StateChangeEvent {
    kind: EditorImageEventType.ExportViewportChanged | EditorImageEventType.AutoresizeModeChanged;
    image: EditorImage;
}
interface ComponentAddRemoveEvent {
    kind: EditorImageEventType.ComponentAdded | EditorImageEventType.ComponentRemoved;
    image: EditorImage;
    componentId: string;
}
export type EditorImageEvent = StateChangeEvent | ComponentAddRemoveEvent;
export type EditorImageNotifier = EventDispatcher<EditorImageEventType, EditorImageEvent>;
/**
 * A callback used to
 * 1. pause the render process
 * 2. observe progress through `componentsProcessed` and `totalComponents`
 * 3. stop the render process early by returning `false`.
 */
export type PreRenderComponentCallback = (component: AbstractComponent, componentsProcessed: number, totalComponents: number) => Promise<boolean>;
/**
 * Handles lookup/storage of elements in the image.
 *
 * `js-draw` images are made up of a collection of {@link AbstractComponent}s (which
 * includes {@link Stroke}s, {@link TextComponent}s, etc.). An `EditorImage`
 * is the data structure that stores these components.
 *
 * Here's how to do a few common operations:
 * - **Get all components in a {@link @js-draw/math!Rect2 | Rect2}**:
 *    {@link EditorImage.getComponentsIntersecting}.
 * - **Draw an `EditorImage` onto a canvas/SVG**: {@link EditorImage.render}.
 * - **Adding a new component**: {@link EditorImage.addComponent}.
 *
 * **Example**:
 * [[include:doc-pages/inline-examples/image-add-and-lookup.md]]
 */
export default class EditorImage {
    private root;
    private background;
    private componentsById;
    private componentCount;
    /** Viewport for the exported/imported image. */
    private importExportViewport;
    private shouldAutoresizeExportViewport;
    readonly notifier: EditorImageNotifier;
    constructor();
    getBackgroundComponents(): AbstractComponent[];
    findParent(elem: AbstractComponent): ImageNode | null;
    queueRerenderOf(elem: AbstractComponent): void;
    /** @internal */
    renderWithCache(screenRenderer: AbstractRenderer, cache: RenderingCache, viewport: Viewport): void;
    /**
     * Renders this image to the given `renderer`.
     *
     * If `viewport` is non-null, only components that can be seen from that viewport
     * will be rendered. If `viewport` is `null`, **all** components are rendered.
     *
     * **Example**:
     * [[include:doc-pages/inline-examples/canvas-renderer.md]]
     */
    render(renderer: AbstractRenderer, viewport: Viewport | null): void;
    /**
     * Like {@link renderAll}, but can be stopped early and paused.
     *
     * **Note**: If the image is being edited during an async rendering, there is no
     * guarantee that all nodes will be rendered correctly (some may be missing).
     *
     * @internal
     */
    renderAllAsync(renderer: AbstractRenderer, preRenderComponent: PreRenderComponentCallback): Promise<boolean>;
    /**
     * Renders all nodes, even ones not within the viewport.
     *
     * This can be slow for large images
     * @internal
     */
    renderAll(renderer: AbstractRenderer): void;
    /**
     * @returns all elements in the image, sorted by z-index (low to high).
     *
     * This can be slow for large images. If you only need all elemenst in part of the image,
     * consider using {@link getComponentsIntersecting} instead.
     *
     * **Note**: The result does not include background elements. See {@link getBackgroundComponents}.
     */
    getAllComponents(): AbstractComponent[];
    /** @deprecated in favor of {@link getAllComponents} */
    getAllElements(): AbstractComponent[];
    /** Returns the number of elements added to this image. @internal */
    estimateNumElements(): number;
    /** @deprecated @see getComponentsIntersecting */
    getElementsIntersectingRegion(region: Rect2, includeBackground?: boolean): AbstractComponent[];
    /**
     * @returns a list of `AbstractComponent`s intersecting `region`, sorted by increasing z-index.
     *
     * Components in the background layer are only included if `includeBackground` is `true`.
     */
    getComponentsIntersecting(region: Rect2, includeBackground?: boolean): AbstractComponent[];
    /** Called whenever (just after) an element is completely removed. @internal */
    onDestroyElement(elem: AbstractComponent): void;
    /** Called just after an element is added. @internal */
    private onElementAdded;
    /**
     * @returns the AbstractComponent with `id`, if it exists.
     *
     * @see {@link AbstractComponent.getId}
     */
    lookupElement(id: string): AbstractComponent | null;
    private addComponentDirectly;
    private removeElementDirectly;
    /**
     * Returns a command that adds the given element to the `EditorImage`.
     * If `applyByFlattening` is true, the content of the wet ink renderer is
     * rendered onto the main rendering canvas instead of doing a full re-render.
     *
     * @see {@link Display.flatten}
     *
     * **Example**:
     *
     * [[include:doc-pages/inline-examples/adding-a-stroke.md]]
     */
    static addComponent(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
    /** @see EditorImage.addComponent */
    addComponent(component: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
    /** Alias for {@link addComponent}. @deprecated Prefer `.addComponent` */
    addElement(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
    /** Alias for {@link addComponent}. @deprecated Prefer `.addComponent`. */
    static addElement(elem: AbstractComponent, applyByFlattening?: boolean): SerializableCommand;
    private static AddComponentCommand;
    /**
     * @returns a `Viewport` for rendering the image when importing/exporting.
     */
    getImportExportViewport(): Viewport;
    /**
     * @see {@link setImportExportRect}
     */
    getImportExportRect(): Rect2;
    /**
     * Sets the import/export rectangle to the given `imageRect`. Disables
     * autoresize if it was previously enabled.
     *
     * **Note**: The import/export rectangle is the same as the size of any
     * {@link BackgroundComponent}s (and other components that auto-resize).
     */
    setImportExportRect(imageRect: Rect2): SerializableCommand;
    /** @see {@link setAutoresizeEnabled} */
    getAutoresizeEnabled(): boolean;
    /**
     * Returns a `Command` that sets whether the image should autoresize when
     * {@link AbstractComponent}s are added/removed.
     *
     * @example
     *
     * ```ts,runnable
     * import { Editor } from 'js-draw';
     *
     * const editor = new Editor(document.body);
     * const toolbar = editor.addToolbar();
     *
     * // Add a save button to demonstrate what the output looks like
     * // (it should change size to fit whatever was drawn)
     * toolbar.addSaveButton(() => {
     *   document.body.replaceChildren(editor.toSVG({ sanitize: true }));
     * });
     *
     * // Actually using setAutoresizeEnabled:
     * //
     * // To set autoresize without announcing for accessibility/making undoable
     * const addToHistory = false;
     * editor.dispatchNoAnnounce(editor.image.setAutoresizeEnabled(true), addToHistory);
     *
     * // Add to undo history **and** announce for accessibility
     * //editor.dispatch(editor.image.setAutoresizeEnabled(true), true);
     * ```
     */
    setAutoresizeEnabled(autoresize: boolean): Command;
    private setAutoresizeEnabledDirectly;
    /** Updates the size/position of the viewport */
    private autoresizeExportViewport;
    private settingExportRect;
    /**
     * Sets the import/export viewport directly, without returning a `Command`.
     * As such, this is not undoable.
     *
     * See setImportExportRect
     *
     * Returns true if changes to the viewport were made (and thus
     * ExportViewportChanged was fired.)
     */
    private setExportRectDirectly;
    private onExportViewportChanged;
    /**
     * @internal
     *
     * Enables debug mode for **all** `EditorImage`s.
     *
     * **Only use for debugging**.
     *
     * @internal
     */
    static setDebugMode(newDebugMode: boolean): void;
    private static SetImportExportRectCommand;
}
/**
 * Determines the first index in `sortedLeaves` that needs to be rendered
 * (based on occlusion -- everything before that index can be skipped and
 * produce a visually-equivalent image).
 *
 * Does nothing if visibleRect is not provided
 *
 * @internal
 */
export declare const computeFirstIndexToRender: (sortedLeaves: Array<ImageNode>, visibleRect?: Rect2) => number;
type TooSmallToRenderCheck = (rect: Rect2) => boolean;
/**
 * Part of the Editor's image. Does not handle fullscreen/invisible components.
 * @internal
 */
export declare class ImageNode {
    private parent;
    private content;
    private bbox;
    private children;
    private targetChildCount;
    private id;
    private static idCounter;
    constructor(parent?: ImageNode | null);
    getId(): number;
    onContentChange(): void;
    getContent(): AbstractComponent | null;
    getParent(): ImageNode | null;
    protected getChildrenIntersectingRegion(region: Rect2, isTooSmallFilter?: TooSmallToRenderCheck): ImageNode[];
    getChildrenOrSelfIntersectingRegion(region: Rect2, isTooSmall?: TooSmallToRenderCheck): ImageNode[];
    /**
     * Returns a list of `ImageNode`s with content (and thus no children).
     * Override getChildrenIntersectingRegion to customize how this method
     * determines whether/which children are in `region`.
     *
     * @paran region - All resultant `ImageNode`s must intersect `region`.
     * @param isTooSmall - If `isTooSmall` returns true for an image node, that node
     *                     is excluded from the output.
     *
     */
    getLeavesIntersectingRegion(region: Rect2, isTooSmall?: TooSmallToRenderCheck): ImageNode[];
    getChildWithContent(target: AbstractComponent): ImageNode | null;
    getLeaves(): ImageNode[];
    addLeaf(leaf: AbstractComponent): ImageNode;
    protected static createLeafNode(parent: ImageNode, content: AbstractComponent): ImageNode;
    getBBox(): Rect2;
    recomputeBBox(bubbleUp: boolean): void;
    private unionBBoxWith;
    private updateParents;
    private rebalance;
    protected removeChild(child: ImageNode): void;
    remove(): void;
    renderAllAsync(renderer: AbstractRenderer, preRenderComponent: PreRenderComponentCallback): Promise<boolean>;
    render(renderer: AbstractRenderer, visibleRect?: Rect2): void;
    renderDebugBoundingBoxes(renderer: AbstractRenderer, visibleRect: Rect2, depth?: number): void;
    private checkRep;
}
/** An `ImageNode` that can properly handle fullscreen/data components. @internal */
export declare class RootImageNode extends ImageNode {
    private fullscreenChildren;
    private dataComponents;
    protected getChildrenIntersectingRegion(region: Rect2, _isTooSmall?: TooSmallToRenderCheck): ImageNode[];
    getChildrenOrSelfIntersectingRegion(region: Rect2, _isTooSmall?: TooSmallToRenderCheck): ImageNode[];
    getLeaves(): ImageNode[];
    removeChild(child: ImageNode): void;
    getChildWithContent(target: AbstractComponent): ImageNode | null;
    addLeaf(leafContent: AbstractComponent): ImageNode;
}
export {};
