"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BUTTON_WIDTH = exports.BUTTON_HEIGHT = exports.PADDING = exports.COLLAPSED_HEIGHT = exports.COLLAPSED_WIDTH = exports.DEFAULT_STYLE = void 0;
const MAX_Z_INDEX_1 = require("../../../../../client/MAX_Z_INDEX");
const addListener_1 = require("../../../../../client/addListener");
const ANIMATION_T_S_1 = require("../../../../../client/animation/ANIMATION_T_S");
const animation_1 = require("../../../../../client/animation/animation");
const color_1 = require("../../../../../client/color");
const component_1 = require("../../../../../client/component");
const mergeStyle_1 = require("../../../../../client/component/mergeStyle");
const dragOverTimeListener_1 = require("../../../../../client/dragOverTimeListener");
const custom_1 = require("../../../../../client/event/custom");
const click_1 = require("../../../../../client/event/pointer/click");
const pointercancel_1 = require("../../../../../client/event/pointer/pointercancel");
const pointerdown_1 = require("../../../../../client/event/pointer/pointerdown");
const pointerleave_1 = require("../../../../../client/event/pointer/pointerleave");
const pointermove_1 = require("../../../../../client/event/pointer/pointermove");
const pointerup_1 = require("../../../../../client/event/pointer/pointerup");
const resize_1 = require("../../../../../client/event/resize");
const parentElement_1 = require("../../../../../client/platform/web/parentElement");
const theme_1 = require("../../../../../client/theme");
const userSelect_1 = require("../../../../../client/util/style/userSelect");
const whenInteracted_1 = require("../../../../../client/whenInteracted");
const array_1 = require("../../../../../util/array");
const callAll_1 = require("../../../../../util/call/callAll");
const id_1 = require("../../../../../util/id");
const f_1 = require("../../../../core/relation/Clamp/f");
const Component_1 = require("../../Div/Component");
const Component_2 = require("../../Icon/Component");
exports.DEFAULT_STYLE = {};
exports.COLLAPSED_WIDTH = 33;
exports.COLLAPSED_HEIGHT = 33;
exports.PADDING = 9;
exports.BUTTON_HEIGHT = 48;
exports.BUTTON_WIDTH = 24;
class GUIControl extends component_1.Component {
    constructor($props, $system) {
        super($props, $system);
        this._refresh_dock = () => {
            const { $width, $height } = this.$context;
            const screen_ratio = this._get_screen_ratio();
            if (screen_ratio < 1) {
                const height = this._get_height();
                const dy = this._y + height - $height + 3;
                if (dy >= 0) {
                    if (this._last_dy > dy) {
                        this._docking = false;
                    }
                    else {
                        this._docking = true;
                    }
                    if (this._docked && dy > 3) {
                        this._docked = false;
                        if (this._docking) {
                            //
                        }
                        else {
                            this.dispatchEvent('dock-move', {
                                dy,
                            });
                        }
                    }
                    else {
                        this._docked = true;
                        this._docked_y = true;
                        if (this._docking) {
                            this.dispatchEvent('dock-move', {
                                dy: height + 3 + 2,
                            });
                        }
                        else {
                            //
                        }
                    }
                    this._last_dy = dy;
                }
                else {
                    if (this._docked) {
                        this._docked = false;
                        this._docked_y = false;
                        this.dispatchEvent('dock-move', {
                            dy: 0,
                        });
                        this.dispatchEvent('dock-leave', {});
                    }
                }
            }
            else {
                const width = this._get_width();
                const dx = this._x - (exports.BUTTON_WIDTH + exports.PADDING);
                if (dx <= 3) {
                    if (this._last_dx < dx) {
                        this._docking = false;
                    }
                    else {
                        this._docking = true;
                    }
                    const dxb = dx;
                    if (this._docked && dxb > 2) {
                        this._docked = false;
                        if (this._docking) {
                            //
                        }
                        else {
                            this.dispatchEvent('dock-move', {
                                dx,
                            });
                        }
                    }
                    else {
                        this._docked = true;
                        this._docked_x = true;
                        if (this._docking) {
                            this.dispatchEvent('dock-move', {
                                dx: width + exports.BUTTON_WIDTH + exports.PADDING + 3,
                            });
                        }
                        else {
                            //
                        }
                    }
                    this._last_dx = dx;
                }
                else {
                    if (this._docked) {
                        this._docked = false;
                        this._docked_x = false;
                        this.dispatchEvent('dock-move', {
                            dx: 0,
                        });
                        this.dispatchEvent('dock-leave', {});
                    }
                }
            }
        };
        this._background_color = () => {
            const { $theme } = this.$context;
            const backgroundColor = (0, color_1.setAlpha)((0, theme_1.themeBackgroundColor)($theme), 0.75);
            return backgroundColor;
        };
        this._refresh_color = () => {
            if (this._collapsed) {
                const backgroundColor = this._background_color();
                (0, mergeStyle_1.mergePropStyle)(this._root, {
                    backgroundColor,
                });
            }
            else {
                (0, mergeStyle_1.mergePropStyle)(this._root, {
                    backgroundColor: theme_1.COLOR_NONE,
                });
            }
        };
        this._set_z_index = (zIndex) => {
            this._z_index = zIndex;
            (0, mergeStyle_1.mergePropStyle)(this._root, {
                zIndex: `${zIndex}`,
            });
        };
        this._z_index = MAX_Z_INDEX_1.MAX_Z_INDEX;
        this._message_id = {};
        this._clamp_x_y = () => {
            const { $width, $height } = this.$context;
            const w = this._get_width();
            const h = this._get_height();
            this._x = (0, f_1.default)({
                a: this._x,
                min: this._collapsed ? exports.PADDING : exports.BUTTON_WIDTH + exports.PADDING,
                max: $width - w - exports.PADDING,
            }).a;
            this._y = (0, f_1.default)({
                a: this._y,
                min: 0,
                max: this._collapsed ? $height : $height - h,
            }).a;
        };
        const { icon, width = 100, height = 100, style = {} } = this.$props;
        let { x = 0, y = 0, collapsed = true, _x = 0, _y = 0 } = this.$props;
        this._x = x;
        this._y = y;
        this._collapsed = collapsed;
        this._collapsed_x = this._x;
        this._collapsed_y = this._y;
        this._non_collapsed_x = this._x + exports.COLLAPSED_WIDTH + 12 + _x;
        this._non_collapsed_y = this._y + _y;
        const WR = exports.COLLAPSED_WIDTH / width;
        const HR = exports.COLLAPSED_HEIGHT / height;
        const root = new Component_1.default({
            className: 'gui-control',
            style: {
                position: 'absolute',
                left: `${x}px`,
                top: `${y}px`,
                width: this._collapsed ? `${exports.COLLAPSED_WIDTH}px` : `${width}px`,
                height: this._collapsed ? `${exports.COLLAPSED_HEIGHT}px` : `${height}px`,
                borderRadius: '3px',
                // borderRadius: this._collapsed ? '50%' : '3px',
                boxSizing: 'content-box',
                borderWidth: '1px',
                borderStyle: 'solid',
                borderColor: this._collapsed ? 'currentColor' : theme_1.COLOR_NONE,
                transition: `opacity ${ANIMATION_T_S_1.ANIMATION_T_S}s linear`,
                zIndex: `${this._z_index}`,
                opacity: this._collapsed ? `${whenInteracted_1.DIM_OPACITY}` : '0',
                touchAction: 'none',
                // contain: 'size layout style paint',
                ...style,
            },
        }, this.$system);
        const collapse = () => {
            const { api: { window: { setTimeout }, }, } = this.$system;
            if (_control_in_count === 0) {
                this._collapsed = true;
                unlisten_pointer();
                unlisten_pointer = listen_pointer(root);
                this._x = this._collapsed_x || this._x + (width - exports.COLLAPSED_WIDTH) / 2;
                this._y = this._collapsed_y || this._y + height - exports.COLLAPSED_HEIGHT;
                this._clamp_x_y();
                const backgroundColor = this._background_color();
                (0, mergeStyle_1.mergePropStyle)(root, {
                    left: `${this._x}px`,
                    top: `${this._y}px`,
                    width: `${exports.COLLAPSED_WIDTH}px`,
                    height: `${exports.COLLAPSED_HEIGHT}px`,
                    borderColor: 'currentColor',
                    backgroundColor,
                    transition: (0, animation_1.linearTransition)('left', 'top', 'width', 'height', 'border-color', 'border-radius', 'background-color'),
                });
                setTimeout(() => {
                    (0, mergeStyle_1.mergePropStyle)(root, {
                        transition: `opacity ${ANIMATION_T_S_1.ANIMATION_T_S}s linear`,
                    });
                }, animation_1.ANIMATION_T_MS);
                (0, mergeStyle_1.mergePropStyle)(container, {
                    opacity: '0',
                    transform: `scale(${WR}, ${HR})`,
                    pointerEvents: 'none',
                    ...(0, userSelect_1.userSelect)('none'),
                });
                (0, mergeStyle_1.mergePropStyle)(_icon, {
                    opacity: '1',
                    pointerEvents: 'auto',
                });
                (0, mergeStyle_1.mergePropStyle)(button, {
                    opacity: '0',
                    pointerEvents: 'none',
                });
                reset_dim();
                if (this._docked) {
                    this.dispatchEvent('dock-move', {
                        dy: 0,
                        dx: 0,
                    });
                    this.dispatchEvent('dock-leave', {});
                }
            }
            else {
                this.dispatchContextEvent('_control_back', false);
            }
            this.dispatchEvent('collapse');
        };
        const uncollapse = () => {
            const { api: { window: { setTimeout }, }, } = this.$system;
            const { width, height } = this.$props;
            this._collapsed = false;
            this._x = this._non_collapsed_x || (this._x - width + exports.COLLAPSED_WIDTH) / 2;
            this._y = this._non_collapsed_y || this._y - height + exports.COLLAPSED_HEIGHT;
            this._clamp_x_y();
            (0, mergeStyle_1.mergePropStyle)(root, {
                left: `${this._x}px`,
                top: `${this._y}px`,
                width: `${width}px`,
                height: `${height}px`,
                borderColor: theme_1.COLOR_NONE,
                backgroundColor: theme_1.COLOR_NONE,
                transition: (0, animation_1.linearTransition)('left', 'top', 'width', 'height', 'border-color', 'border-radius', 'background-color'),
            });
            (0, mergeStyle_1.mergePropStyle)(container, {
                opacity: '1',
                transform: 'scale(1, 1)',
                pointerEvents: 'auto',
                ...(0, userSelect_1.userSelect)('auto'),
            });
            (0, mergeStyle_1.mergePropStyle)(button, {
                opacity: '1',
                pointerEvents: 'auto',
            });
            setTimeout(() => {
                (0, mergeStyle_1.mergePropStyle)(root, {
                    transition: `opacity ${ANIMATION_T_S_1.ANIMATION_T_S}s linear`,
                });
                (0, mergeStyle_1.mergePropStyle)(_icon, {
                    pointerEvents: 'none',
                });
            }, animation_1.ANIMATION_T_MS);
            (0, mergeStyle_1.mergePropStyle)(_icon, {
                opacity: '0',
            });
            undim();
            this.dispatchEvent('uncollapse');
            unlisten_pointer();
            unlisten_pointer = listen_pointer(button);
            if (this._docked) {
                const height = this._get_height();
                const width = this._get_width();
                this.dispatchEvent('dock-move', {
                    dx: this._docked_x ? width + exports.BUTTON_WIDTH + exports.PADDING + 3 : 0,
                    dy: this._docked_y ? height + 3 + 2 : 0,
                });
            }
        };
        const toggle_collapse = () => {
            if (this._collapsed) {
                uncollapse();
            }
            else {
                collapse();
            }
        };
        this._docked = false;
        this._docked_x = false;
        this._docked_y = false;
        this._docking = false;
        this._last_dy = 0;
        this._last_dx = 0;
        let unlisten_pointer;
        let release;
        const listen_pointer = (component) => {
            // console.log('listen_pointer', component, release)
            return (0, callAll_1.callAll)([
                component.addEventListeners([
                    (0, click_1.makeClickListener)({
                        onClick: () => {
                            toggle_collapse();
                        },
                    }),
                    (0, pointerdown_1.makePointerDownListener)(({ pointerId, clientX, clientY }) => {
                        component.setPointerCapture(pointerId);
                        let hx = clientX - this._x;
                        let hy = clientY - this._y;
                        release = () => {
                            component.releasePointerCapture(pointerId);
                            unlisten();
                            release = undefined;
                        };
                        let unlisten = component.addEventListeners([
                            (0, pointermove_1.makePointerMoveListener)(({ clientX, clientY }) => {
                                this._x = clientX - hx;
                                this._y = clientY - hy;
                                if (this._collapsed) {
                                    this._collapsed_x = this._x;
                                    this._collapsed_y = this._y;
                                }
                                else {
                                    this._non_collapsed_x = this._x;
                                    this._non_collapsed_y = this._y;
                                }
                                this._clamp_x_y();
                                (0, mergeStyle_1.mergePropStyle)(root, {
                                    left: `${this._x}px`,
                                    top: `${this._y}px`,
                                });
                                if (!this._collapsed) {
                                    this._refresh_dock();
                                }
                            }),
                            (0, pointerup_1.makePointerUpListener)(() => {
                                release();
                            }),
                            (0, pointercancel_1.makePointerCancelListener)(() => {
                                release();
                            }),
                            (0, pointerleave_1.makePointerLeaveListener)(() => {
                                release();
                            }),
                        ]);
                    }),
                ]),
                (0, dragOverTimeListener_1.dragOverTimeListener)(component, 500, () => {
                    toggle_collapse();
                }),
                () => {
                    if (release) {
                        release();
                    }
                },
            ]);
        };
        const dim = () => {
            (0, mergeStyle_1.mergePropStyle)(root, {
                opacity: `${whenInteracted_1.DIM_OPACITY}`,
            });
        };
        const undim = () => {
            (0, mergeStyle_1.mergePropStyle)(root, {
                opacity: '1',
            });
        };
        const reset_dim = () => {
            if (this._collapsed) {
                const on_active = () => {
                    const message_id = (0, id_1.uuid)();
                    this._message_id[message_id] = true;
                    this.dispatchContextEvent('_control_foreground', {
                        message_id,
                    });
                    this._set_z_index(MAX_Z_INDEX_1.MAX_Z_INDEX);
                    if (!this._collapsed) {
                        return;
                    }
                    undim();
                };
                const on_inactive = () => {
                    if (!this._collapsed) {
                        return;
                    }
                    dim();
                };
                const unlisten_interacted = (0, whenInteracted_1.whenInteracted)(root, 3000, false, on_active, on_inactive);
            }
        };
        this._root = root;
        reset_dim();
        const container = new Component_1.default({
            style: {
                position: 'absolute',
                top: '0',
                left: '0',
                transform: `${this._collapsed ? `scale(${WR}, ${HR})` : 'scale(1, 1)'}`,
                transformOrigin: 'top left',
                borderWidth: '0px',
                borderStyle: 'solid',
                borderColor: theme_1.COLOR_NONE,
                width: `${width}px`,
                height: `${height}px`,
                opacity: this._collapsed ? '0' : '1',
                transition: `transform ${ANIMATION_T_S_1.ANIMATION_T_S}s linear, opacity ${ANIMATION_T_S_1.ANIMATION_T_S}s linear`,
            },
        }, this.$system);
        let _control_in_count = 0;
        container.addEventListeners([
            (0, custom_1.makeCustomListener)('_control_in', () => {
                _control_in_count++;
            }),
            (0, custom_1.makeCustomListener)('_control_out', () => {
                _control_in_count--;
            }),
        ]);
        const _icon = new Component_2.default({
            className: 'control-icon',
            icon,
            style: {
                position: 'absolute',
                top: '50%',
                left: '50%',
                transform: 'translate(-50%, -50%)',
                padding: '3px',
                boxSizing: 'border-box',
                width: '100%',
                height: '100%',
                opacity: this._collapsed ? '1' : '0',
                transition: `opacity ${ANIMATION_T_S_1.ANIMATION_T_S}s linear`,
                cursor: 'pointer',
                pointerEvents: this._collapsed ? 'auto' : 'none',
            },
        }, this.$system);
        _icon.preventDefault('mousedown');
        _icon.preventDefault('touchdown');
        _icon.addEventListener((0, click_1.makeClickListener)({
            onClick: uncollapse,
        }));
        _icon.$element.setAttribute('dropTarget', 'true');
        const button = new Component_1.default({
            className: 'gui-control-knob',
            style: {
                position: 'absolute',
                left: `-${exports.BUTTON_WIDTH}px`,
                opacity: this._collapsed ? '0' : '1',
                height: `${exports.BUTTON_HEIGHT}px`,
                top: '50%',
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                backgroundColor: theme_1.COLOR_NONE,
                width: `${exports.BUTTON_WIDTH}px`,
                cursor: 'pointer',
                willChange: 'opacity',
                transition: (0, animation_1.linearTransition)('opacity'),
                transform: 'translateY(-50%)',
                pointerEvents: this._collapsed ? 'none' : 'auto',
                touchAction: 'none',
                ...(0, userSelect_1.userSelect)('none'),
            },
        }, this.$system);
        button.preventDefault('mousedown');
        button.preventDefault('touchdown');
        button.preventDefault('touchstart');
        button.$element.setAttribute('dropTarget', 'true');
        const button_inner = new Component_1.default({
            style: {
                width: '8px',
                height: '16px',
                display: 'flex',
                flexWrap: 'wrap',
                gap: '3px',
                justifyContent: 'center',
                alignItems: 'center',
            },
        }, this.$system);
        button.appendChild(button_inner);
        (0, array_1.rangeArray)(6).forEach((i) => {
            const grip_circle = new Component_1.default({
                style: {
                    width: '2px',
                    height: '2px',
                    borderRadius: '50%',
                    backgroundColor: 'currentColor',
                },
            }, this.$system);
            button_inner.appendChild(grip_circle);
        });
        if (this._collapsed) {
            unlisten_pointer = listen_pointer(root);
        }
        else {
            unlisten_pointer = listen_pointer(button);
        }
        const $element = (0, parentElement_1.parentElement)($system);
        this.$element = $element;
        this.$slot = container.$slot;
        this.$primitive = true;
        this.$unbundled = false;
        container.registerParentRoot(button);
        root.registerParentRoot(container);
        root.registerParentRoot(_icon);
        this.setSubComponents({
            root,
            button,
            icon: _icon,
        });
        this.registerRoot(root);
    }
    _get_screen_ratio() {
        const { $width, $height } = this.$context;
        return $width / $height;
    }
    onPropChanged(prop, current) {
        if (prop === 'style') {
            const { width, height } = this.$props;
            this._root.setProp('style', {
                position: 'absolute',
                left: `${this._x}px`,
                top: `${this._y}px`,
                width: this._collapsed ? `${exports.COLLAPSED_WIDTH}px` : `${width}px`,
                height: this._collapsed ? `${exports.COLLAPSED_HEIGHT}px` : `${height}px`,
                borderRadius: '3px',
                // borderRadius: this._collapsed ? '50%' : '3px',
                borderWidth: '1px',
                borderStyle: 'solid',
                borderColor: this._collapsed ? 'currentColor' : theme_1.COLOR_NONE,
                transition: `opacity ${ANIMATION_T_S_1.ANIMATION_T_S}s linear`,
                zIndex: `${this._z_index}`,
                opacity: this._collapsed ? `${whenInteracted_1.DIM_OPACITY}` : '0',
                touchAction: 'none',
                // contain: 'size layout style paint',
                ...current,
            });
        }
    }
    _get_height() {
        const { height } = this.$props;
        return this._collapsed ? exports.COLLAPSED_HEIGHT : height;
    }
    _get_width() {
        const { width } = this.$props;
        return this._collapsed ? exports.COLLAPSED_WIDTH : width;
    }
    onMount() {
        this._context_unlisten = (0, addListener_1.addListeners)(this.$context, [
            (0, custom_1.makeCustomListener)('themechanged', () => {
                this._refresh_color();
            }),
            (0, resize_1.makeResizeListener)(() => {
                this._clamp_x_y();
                (0, mergeStyle_1.mergePropStyle)(this._root, {
                    left: `${this._x}px`,
                    top: `${this._y}px`,
                });
                this._refresh_dock();
            }),
            (0, custom_1.makeCustomListener)('_control_foreground', ({ message_id }) => {
                if (!this._message_id[message_id]) {
                    this._set_z_index(this._z_index - 1);
                }
                else {
                    delete this._message_id[message_id];
                }
            }),
        ]);
        this._refresh_color();
    }
    onUnmount() {
        this._context_unlisten();
    }
}
exports.default = GUIControl;
//# sourceMappingURL=Component.js.map