Files
esengine/packages/rendering/fairygui/src/widgets/GProgressBar.ts

229 lines
6.7 KiB
TypeScript
Raw Normal View History

feat(fairygui): FairyGUI 完整集成 (#314) * feat(fairygui): FairyGUI ECS 集成核心架构 实现 FairyGUI 的 ECS 原生集成,完全替代旧 UI 系统: 核心类: - GObject: UI 对象基类,支持变换、可见性、关联、齿轮 - GComponent: 容器组件,管理子对象和控制器 - GRoot: 根容器,管理焦点、弹窗、输入分发 - GGroup: 组容器,支持水平/垂直布局 抽象层: - DisplayObject: 显示对象基类 - EventDispatcher: 事件分发 - Timer: 计时器 - Stage: 舞台,管理输入和缩放 布局系统: - Relations: 约束关联管理 - RelationItem: 24 种关联类型 基础设施: - Controller: 状态控制器 - Transition: 过渡动画 - ScrollPane: 滚动面板 - UIPackage: 包管理 - ByteBuffer: 二进制解析 * refactor(ui): 删除旧 UI 系统,使用 FairyGUI 替代 * feat(fairygui): 实现 UI 控件 - 添加显示类:Image、TextField、Graph - 添加基础控件:GImage、GTextField、GGraph - 添加交互控件:GButton、GProgressBar、GSlider - 更新 IRenderCollector 支持 Graph 渲染 - 扩展 Controller 添加 selectedPageId - 添加 STATE_CHANGED 事件类型 * feat(fairygui): 现代化架构重构 - 增强 EventDispatcher 支持类型安全、优先级和传播控制 - 添加 PropertyBinding 响应式属性绑定系统 - 添加 ServiceContainer 依赖注入容器 - 添加 UIConfig 全局配置系统 - 添加 UIObjectFactory 对象工厂 - 实现 RenderBridge 渲染桥接层 - 实现 Canvas2DBackend 作为默认渲染后端 - 扩展 IRenderCollector 支持更多图元类型 * feat(fairygui): 九宫格渲染和资源加载修复 - 修复 FGUIUpdateSystem 支持路径和 GUID 两种加载方式 - 修复 GTextInput 同时设置 _displayObject 和 _textField - 实现九宫格渲染展开为 9 个子图元 - 添加 sourceWidth/sourceHeight 用于九宫格计算 - 添加 DOMTextRenderer 文本渲染层(临时方案) * fix(fairygui): 修复 GGraph 颜色读取 * feat(fairygui): 虚拟节点 Inspector 和文本渲染支持 * fix(fairygui): 编辑器状态刷新和遗留引用修复 - 修复切换 FGUI 包后组件列表未刷新问题 - 修复切换组件后 viewport 未清理旧内容问题 - 修复虚拟节点在包加载后未刷新问题 - 重构为事件驱动架构,移除轮询机制 - 修复 @esengine/ui 遗留引用,统一使用 @esengine/fairygui * fix: 移除 tsconfig 中的 @esengine/ui 引用
2025-12-22 10:52:54 +08:00
import { GComponent } from '../core/GComponent';
import { GObject } from '../core/GObject';
import { GImage } from './GImage';
import { EProgressTitleType, EObjectPropID, EFillMethod } from '../core/FieldTypes';
import type { ByteBuffer } from '../utils/ByteBuffer';
/**
* GProgressBar
*
* Progress bar component.
*
*
*/
export class GProgressBar extends GComponent {
private _min: number = 0;
private _max: number = 100;
private _value: number = 50;
private _titleType: EProgressTitleType = EProgressTitleType.Percent;
private _reverse: boolean = false;
private _titleObject: GObject | null = null;
private _aniObject: GObject | null = null;
private _barObjectH: GObject | null = null;
private _barObjectV: GObject | null = null;
private _barMaxWidth: number = 0;
private _barMaxHeight: number = 0;
private _barMaxWidthDelta: number = 0;
private _barMaxHeightDelta: number = 0;
private _barStartX: number = 0;
private _barStartY: number = 0;
constructor() {
super();
}
/**
* Get/set title type
* /
*/
public get titleType(): EProgressTitleType {
return this._titleType;
}
public set titleType(value: EProgressTitleType) {
if (this._titleType !== value) {
this._titleType = value;
this.update(this._value);
}
}
/**
* Get/set minimum value
* /
*/
public get min(): number {
return this._min;
}
public set min(value: number) {
if (this._min !== value) {
this._min = value;
this.update(this._value);
}
}
/**
* Get/set maximum value
* /
*/
public get max(): number {
return this._max;
}
public set max(value: number) {
if (this._max !== value) {
this._max = value;
this.update(this._value);
}
}
/**
* Get/set current value
* /
*/
public get value(): number {
return this._value;
}
public set value(value: number) {
if (this._value !== value) {
this._value = value;
this.update(value);
}
}
/**
* Update progress bar display
*
*/
public update(newValue: number): void {
let percent = this.clamp01((newValue - this._min) / (this._max - this._min));
if (this._titleObject) {
switch (this._titleType) {
case EProgressTitleType.Percent:
this._titleObject.text = Math.floor(percent * 100) + '%';
break;
case EProgressTitleType.ValueAndMax:
this._titleObject.text =
Math.floor(newValue) + '/' + Math.floor(this._max);
break;
case EProgressTitleType.Value:
this._titleObject.text = '' + Math.floor(newValue);
break;
case EProgressTitleType.Max:
this._titleObject.text = '' + Math.floor(this._max);
break;
}
}
const fullWidth = this.width - this._barMaxWidthDelta;
const fullHeight = this.height - this._barMaxHeightDelta;
if (!this._reverse) {
if (this._barObjectH) {
if (!this.setFillAmount(this._barObjectH, percent)) {
this._barObjectH.width = Math.round(fullWidth * percent);
}
}
if (this._barObjectV) {
if (!this.setFillAmount(this._barObjectV, percent)) {
this._barObjectV.height = Math.round(fullHeight * percent);
}
}
} else {
if (this._barObjectH) {
if (!this.setFillAmount(this._barObjectH, 1 - percent)) {
this._barObjectH.width = Math.round(fullWidth * percent);
this._barObjectH.x = this._barStartX + (fullWidth - this._barObjectH.width);
}
}
if (this._barObjectV) {
if (!this.setFillAmount(this._barObjectV, 1 - percent)) {
this._barObjectV.height = Math.round(fullHeight * percent);
this._barObjectV.y =
this._barStartY + (fullHeight - this._barObjectV.height);
}
}
}
if (this._aniObject) {
this._aniObject.setProp(EObjectPropID.Frame, Math.floor(percent * 100));
}
}
private setFillAmount(bar: GObject, percent: number): boolean {
if (bar instanceof GImage && bar.fillMethod !== EFillMethod.None) {
bar.fillAmount = percent;
return true;
}
return false;
}
private clamp01(value: number): number {
if (value < 0) return 0;
if (value > 1) return 1;
return value;
}
protected constructExtension(buffer: ByteBuffer): void {
buffer.seek(0, 6);
this._titleType = buffer.readByte();
this._reverse = buffer.readBool();
this._titleObject = this.getChild('title');
this._barObjectH = this.getChild('bar');
this._barObjectV = this.getChild('bar_v');
this._aniObject = this.getChild('ani');
if (this._barObjectH) {
this._barMaxWidth = this._barObjectH.width;
this._barMaxWidthDelta = this.width - this._barMaxWidth;
this._barStartX = this._barObjectH.x;
}
if (this._barObjectV) {
this._barMaxHeight = this._barObjectV.height;
this._barMaxHeightDelta = this.height - this._barMaxHeight;
this._barStartY = this._barObjectV.y;
}
}
protected handleSizeChanged(): void {
super.handleSizeChanged();
if (this._barObjectH) {
this._barMaxWidth = this.width - this._barMaxWidthDelta;
}
if (this._barObjectV) {
this._barMaxHeight = this.height - this._barMaxHeightDelta;
}
if (!this._underConstruct) {
this.update(this._value);
}
}
public setup_afterAdd(buffer: ByteBuffer, beginPos: number): void {
super.setup_afterAdd(buffer, beginPos);
if (!buffer.seek(beginPos, 6)) {
this.update(this._value);
return;
}
if (buffer.readByte() !== this.packageItem?.objectType) {
this.update(this._value);
return;
}
this._value = buffer.getInt32();
this._max = buffer.getInt32();
if (buffer.version >= 2) {
this._min = buffer.getInt32();
}
this.update(this._value);
}
}