import { Component, ECSComponent, Property, Serializable, Serialize } from '@esengine/ecs-framework'; /** * 滑块方向 * Slider orientation */ export enum UISliderOrientation { Horizontal = 'horizontal', Vertical = 'vertical' } /** * UI 滑块组件 * UI Slider Component - Value slider with handle */ @ECSComponent('UISlider') @Serializable({ version: 1, typeId: 'UISlider' }) export class UISliderComponent extends Component { // ===== 数值 Values ===== /** * 当前值 * Current value */ @Serialize() @Property({ type: 'number', label: 'Value' }) public value: number = 0; /** * 最小值 * Minimum value */ @Serialize() @Property({ type: 'number', label: 'Min Value' }) public minValue: number = 0; /** * 最大值 * Maximum value */ @Serialize() @Property({ type: 'number', label: 'Max Value' }) public maxValue: number = 100; /** * 步进值(0 = 连续) * Step value (0 = continuous) */ @Serialize() @Property({ type: 'number', label: 'Step', min: 0 }) public step: number = 0; /** * 目标值(用于动画) * Target value (for animation) */ public targetValue: number = 0; /** * 显示值(动画插值后) * Display value (interpolated) */ public displayValue: number = 0; // ===== 方向 Orientation ===== /** * 滑块方向 * Slider orientation */ @Serialize() @Property({ type: 'enum', label: 'Orientation', options: [ { value: 'horizontal', label: 'Horizontal' }, { value: 'vertical', label: 'Vertical' } ] }) public orientation: UISliderOrientation = UISliderOrientation.Horizontal; // ===== 轨道样式 Track Style ===== /** * 轨道颜色 * Track color */ @Serialize() @Property({ type: 'color', label: 'Track Color' }) public trackColor: number = 0x444444; /** * 轨道透明度 * Track alpha */ @Serialize() @Property({ type: 'number', label: 'Track Alpha', min: 0, max: 1, step: 0.01 }) public trackAlpha: number = 1; /** * 轨道高度(水平)或宽度(垂直) * Track thickness */ @Serialize() @Property({ type: 'number', label: 'Track Thickness', min: 1 }) public trackThickness: number = 4; /** * 轨道圆角 * Track corner radius */ @Serialize() @Property({ type: 'number', label: 'Track Radius', min: 0 }) public trackRadius: number = 2; // ===== 填充样式 Fill Style ===== /** * 填充颜色(已滑过的部分) * Fill color (passed portion) */ @Serialize() @Property({ type: 'color', label: 'Fill Color' }) public fillColor: number = 0x4A90D9; /** * 填充透明度 * Fill alpha */ @Serialize() @Property({ type: 'number', label: 'Fill Alpha', min: 0, max: 1, step: 0.01 }) public fillAlpha: number = 1; // ===== 手柄样式 Handle Style ===== /** * 手柄宽度 * Handle width */ @Serialize() @Property({ type: 'number', label: 'Handle Width', min: 1 }) public handleWidth: number = 16; /** * 手柄高度 * Handle height */ @Serialize() @Property({ type: 'number', label: 'Handle Height', min: 1 }) public handleHeight: number = 16; /** * 手柄颜色 * Handle color */ @Serialize() @Property({ type: 'color', label: 'Handle Color' }) public handleColor: number = 0xFFFFFF; /** * 手柄悬停颜色 * Handle hover color */ @Serialize() @Property({ type: 'color', label: 'Handle Hover Color' }) public handleHoverColor: number = 0xE0E0E0; /** * 手柄按下颜色 * Handle pressed color */ @Serialize() @Property({ type: 'color', label: 'Handle Pressed Color' }) public handlePressedColor: number = 0xCCCCCC; /** * 手柄圆角 * Handle corner radius */ @Serialize() @Property({ type: 'number', label: 'Handle Radius', min: 0 }) public handleRadius: number = 8; /** * 手柄边框宽度 * Handle border width */ @Serialize() @Property({ type: 'number', label: 'Handle Border Width', min: 0 }) public handleBorderWidth: number = 0; /** * 手柄边框颜色 * Handle border color */ @Serialize() @Property({ type: 'color', label: 'Handle Border Color' }) public handleBorderColor: number = 0x000000; /** * 手柄阴影 * Handle shadow enabled */ @Serialize() @Property({ type: 'boolean', label: 'Handle Shadow' }) public handleShadow: boolean = true; // ===== 交互状态 Interaction State ===== /** * 手柄是否被悬停 * Whether handle is hovered */ public handleHovered: boolean = false; /** * 是否正在拖拽 * Whether currently dragging */ public dragging: boolean = false; /** * 拖拽起始值 * Drag start value */ public dragStartValue: number = 0; /** * 拖拽起始位置 * Drag start position */ public dragStartPosition: number = 0; // ===== 动画 Animation ===== /** * 过渡时长(秒) * Transition duration in seconds */ @Serialize() @Property({ type: 'number', label: 'Transition Duration', min: 0, step: 0.01 }) public transitionDuration: number = 0.1; // ===== 刻度 Ticks ===== /** * 是否显示刻度 * Whether to show ticks */ @Serialize() @Property({ type: 'boolean', label: 'Show Ticks' }) public showTicks: boolean = false; /** * 刻度数量(不包括首尾) * Number of ticks (excluding ends) */ @Serialize() @Property({ type: 'integer', label: 'Tick Count', min: 0 }) public tickCount: number = 4; /** * 刻度颜色 * Tick color */ @Serialize() @Property({ type: 'color', label: 'Tick Color' }) public tickColor: number = 0x666666; /** * 刻度大小 * Tick size */ @Serialize() @Property({ type: 'number', label: 'Tick Size', min: 1 }) public tickSize: number = 4; // ===== 文本 Text ===== /** * 是否显示值文本 * Whether to show value text */ @Serialize() @Property({ type: 'boolean', label: 'Show Value' }) public showValue: boolean = false; /** * 值文本格式 * Value text format */ @Serialize() @Property({ type: 'string', label: 'Value Format' }) public valueFormat: string = '{value}'; /** * 小数位数 * Decimal places */ @Serialize() @Property({ type: 'integer', label: 'Decimal Places', min: 0 }) public decimalPlaces: number = 0; // ===== 回调 Callbacks ===== /** * 值改变回调 * Value change callback */ public onChange?: (value: number) => void; /** * 拖拽开始回调 * Drag start callback */ public onDragStart?: (value: number) => void; /** * 拖拽结束回调 * Drag end callback */ public onDragEnd?: (value: number) => void; /** * 获取进度百分比 (0-1) * Get progress as percentage (0-1) */ public getProgress(): number { const range = this.maxValue - this.minValue; if (range <= 0) return 0; return Math.max(0, Math.min(1, (this.displayValue - this.minValue) / range)); } /** * 从百分比设置值 * Set value from percentage */ public setProgress(progress: number): this { const range = this.maxValue - this.minValue; return this.setValue(this.minValue + range * Math.max(0, Math.min(1, progress))); } /** * 设置值 * Set value */ public setValue(value: number, animate: boolean = true): this { let newValue = Math.max(this.minValue, Math.min(this.maxValue, value)); // 应用步进 if (this.step > 0) { newValue = Math.round((newValue - this.minValue) / this.step) * this.step + this.minValue; } this.targetValue = newValue; if (!animate) { this.value = newValue; this.displayValue = newValue; } return this; } /** * 获取格式化的值文本 * Get formatted value text */ public getFormattedValue(): string { const formattedValue = this.displayValue.toFixed(this.decimalPlaces); return this.valueFormat.replace('{value}', formattedValue); } /** * 计算手柄位置(归一化 0-1) * Calculate handle position (normalized 0-1) */ public getHandlePosition(): number { return this.getProgress(); } /** * 获取当前手柄颜色 * Get current handle color based on state */ public getCurrentHandleColor(): number { if (this.dragging) return this.handlePressedColor; if (this.handleHovered) return this.handleHoverColor; return this.handleColor; } }