You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
522 lines
17 KiB
522 lines
17 KiB
|
|
import { AbstractMesh, EventState, Scene, setAndStartTimer, Vector2 } from "@babylonjs/core"; |
|
import { Button, Container, Control, Ellipse, MultiLine, RadioButton, Rectangle, StackPanel, TextBlock, Vector2WithInfo } from "@babylonjs/gui"; |
|
import { ConfigManager } from "../controller/config-manager"; |
|
import { SceneManager } from "../controller/scene-manager"; |
|
import { UIManager } from "../controller/ui-manager"; |
|
import { UIBase } from "../view/window-base/ui-base"; |
|
import { MyInputText } from "./babylon-tool"; |
|
|
|
//babylon UI 风格 工具 |
|
export class BabylonUIStyleTool { |
|
|
|
static c_color_blue: string = "#0080FF";//普通蓝色,用于选中、确定等正面风格 |
|
static c_color_gray: string = "#E8ECF1";//普通灰色,用于取消、后退、输入背景等 |
|
static c_color_black: string = "black";//黑色 |
|
static c_color_blueBg: string = "#001121";//深蓝,用于长存界面的背景 |
|
static c_color_white: string = "white"; |
|
static c_color_green = "#439C08";//绿色按钮 |
|
static c_color_greenLight = '#00F424';//亮绿色 |
|
static c_color_red = "#C14242";//红色按钮,用于删除等危险操作 |
|
|
|
static c_color_3d_blueLight: string = "#99ECFC";//亮蓝,字 |
|
static c_color_3d_blue: string = "#47E0FF";//蓝, 框体 |
|
static c_color_3d_blueBg: string = "#122F49";//蓝黑,背景 |
|
|
|
static c_shadow_blur_button = 2;//按钮的阴影模糊 |
|
static c_shadow_blur_window = 20; //界面的阴影模糊 |
|
|
|
static readonly cornerRadius_window1 = 10;//界面圆角 |
|
static readonly cornerRadius_button = 6;//按钮圆角 |
|
|
|
static c_zIndex_gizmo = 200;//gizmo界面的z |
|
static c_zIndex_topBar = 100;//topbar界面的z |
|
|
|
static c_zIndex_buildingIcon = 50;//建筑标志的z |
|
static c_zIndex_facilityIcon = 40;//设备标志的z |
|
|
|
|
|
//#region 组件 |
|
//创建窗口根节点 |
|
static createWindoRoot(window: UIBase, name: string, width: string, height: string, isDialog: boolean) { |
|
|
|
window.root = new Rectangle(name); |
|
UIManager.Instance.uiRoot.addControl(window.root); |
|
window.root.width = width; |
|
window.root.height = height; |
|
|
|
BabylonUIStyleTool.setDefaultStyle_windowRoot(window.root, isDialog); |
|
|
|
} |
|
|
|
//创建文本输入组件 |
|
static createInputText(name: string, parent: Container, width: string, height: string, textColor: string = "black", thickness: number = 0, cornerRadius: number = 6, backgroundColor: string = "#EEF1F5", focuseColor: string = "black", focuseBgColor: string = "#EEF1F5"): MyInputText { |
|
let result = new MyInputText(name, parent, width, height); |
|
|
|
result.inputText.color = textColor; |
|
|
|
result.inputText.background = backgroundColor; |
|
result.inputText.thickness = thickness; |
|
|
|
result.inputText.focusedColor = focuseColor; |
|
result.inputText.focusedBackground = focuseBgColor; |
|
|
|
result.bg.cornerRadius = cornerRadius; |
|
result.bg.color = backgroundColor; |
|
result.bg.thickness = thickness; |
|
|
|
return result; |
|
|
|
} |
|
|
|
//创建文本 |
|
static createTextBlock(name: string, text: string, width: string, height: string, fontSize: string): TextBlock { |
|
let textBlock = new TextBlock(name, text); |
|
BabylonUIStyleTool.setStyle_size(textBlock, width, height); |
|
textBlock.fontSize = fontSize; |
|
textBlock.color = "black"; |
|
return textBlock; |
|
|
|
} |
|
|
|
//创建统一风格的确定按钮 |
|
static createBtn_OK(name: string, text: string, width: string, height: string, fontSize: string): Button { |
|
let result = BabylonUIStyleTool.createBtn(name, text, width, height, fontSize, "white", BabylonUIStyleTool.c_color_blue); |
|
BabylonUIStyleTool.setStyle_Shadow(result, undefined, 1.5); |
|
return result; |
|
} |
|
|
|
//创建统一风格的取消按钮 |
|
static createBtn_Cancel(name: string, text: string, width: string, height: string, fontSize: string): Button { |
|
let result = BabylonUIStyleTool.createBtn(name, text, width, height, fontSize, "black", BabylonUIStyleTool.c_color_gray); |
|
return result |
|
} |
|
|
|
//创建统一风格的删除按钮 |
|
static createBtn_Delete(name: string, text: string, width: string, height: string, fontSize: string,): Button { |
|
let result = BabylonUIStyleTool.createBtn(name, text, width, height, fontSize, "white", BabylonUIStyleTool.c_color_red); |
|
return result; |
|
} |
|
|
|
//创建按钮 |
|
static createBtn(name: string, text: string, width: string, height: string, fontSize: string, textColor: string = "black", bgColor: string = "white", thickness: number = 0, cornerRadius: number = 6): Button { |
|
let result = Button.CreateSimpleButton(name, text); |
|
result.background = bgColor; |
|
result.color = textColor; |
|
result.width = width; |
|
result.height = height; |
|
result.thickness = thickness; |
|
result.cornerRadius = cornerRadius; |
|
|
|
result.textBlock.color = textColor; |
|
result.fontSize = fontSize; |
|
return result; |
|
} |
|
|
|
|
|
//创建选择框 |
|
static createRadioButton(name: string, parent: Container, group: string, width: string, height: string, color: string, background: string, info?: string, infoWidth?: string, isChecked = false, callback?: (eventData: boolean, eventState: EventState) => void) { |
|
let root = new StackPanel(name + "Root"); |
|
root.isVertical = false |
|
root.width = width; |
|
root.height = height; |
|
parent.addControl(root); |
|
|
|
|
|
|
|
let radioButton = new RadioButton(name); |
|
root.addControl(radioButton); |
|
radioButton.group = group; |
|
BabylonUIStyleTool.setStyle_size(radioButton, height, height); |
|
radioButton.background = background; |
|
radioButton.color = color; |
|
if (callback) { |
|
radioButton.onIsCheckedChangedObservable.add(callback); |
|
} |
|
radioButton.isChecked = isChecked; |
|
|
|
|
|
let header = new TextBlock(name + "_info", info); |
|
root.addControl(header); |
|
header.height = height; |
|
header.width = width; |
|
header.color = "black"; |
|
header.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
|
|
|
return radioButton; |
|
} |
|
|
|
/** |
|
* 创建线性指示UI |
|
* @param key |
|
* @param mesh 跟随在此mesh 右侧 |
|
* @param size 外框的大小, 外框的左侧中点为线段起点 |
|
* @param infoSize 信息框的大小, 对齐于外框的右上角 |
|
*/ |
|
static createLineInfo(key: string, mesh: AbstractMesh, size: Vector2 = new Vector2(160, 60), infoSize: Vector2 = new Vector2(120, 20)): UI_LineInfo { |
|
|
|
|
|
if (size.x < infoSize.x) { |
|
size.x = infoSize.x; |
|
} |
|
if (size.y < infoSize.y) { |
|
size.y = infoSize.y; |
|
} |
|
|
|
let lineInfo = new UI_LineInfo(key, mesh, size, infoSize); |
|
|
|
return lineInfo; |
|
} |
|
|
|
|
|
//#endregion |
|
|
|
|
|
//#region 风格样式 |
|
//统一设置窗口根节点风格 |
|
static setDefaultStyle_windowRoot(container: Rectangle, isDialog = true, shadow: boolean = true, corner: boolean = true) { |
|
|
|
container.thickness = 0; |
|
//弹框 |
|
if (isDialog) { |
|
container.color = BabylonUIStyleTool.c_color_white; |
|
container.background = BabylonUIStyleTool.c_color_white; |
|
container.alpha = 1; |
|
container.zIndex = 100; |
|
} |
|
else//长存界面 |
|
{ |
|
|
|
container.color = BabylonUIStyleTool.c_color_blueBg; |
|
container.background = BabylonUIStyleTool.c_color_blueBg; |
|
container.alpha = 0.8; |
|
container.zIndex = 1; |
|
} |
|
|
|
|
|
//阴影 |
|
if (shadow) { |
|
BabylonUIStyleTool.setStyle_Shadow(container, BabylonUIStyleTool.c_color_black, BabylonUIStyleTool.c_shadow_blur_window); |
|
} |
|
//圆角 |
|
if (corner) { |
|
container.cornerRadius = BabylonUIStyleTool.cornerRadius_window1; |
|
} |
|
} |
|
//设置尺寸 |
|
static setStyle_size(control: Control, width: string, height: string) { |
|
control.width = width; |
|
control.height = height; |
|
} |
|
|
|
//设置文本风格 |
|
static setStyle_bodyText(text: TextBlock, fontSize: string = "20px", color: string = "#333333", alpha: number = 1) { |
|
text.fontSize = fontSize; |
|
text.color = color; |
|
text.alpha = alpha; |
|
} |
|
|
|
//设置对齐方式 |
|
//horizontal: Control.HORIZONTAL_ALIGNMENT_CENTER;Control.HORIZONTAL_ALIGNMENT_LEFT;Control.HORIZONTAL_ALIGNMENT_RIGHT; |
|
//vertical: Control.VERTICAL_ALIGNMENT_CENTER ; Control.VERTICAL_ALIGNMENT_LEFT;Control.VERTICAL_ALIGNMENT_RIGHT; |
|
// |
|
static setStyle_Alignment(control: Control, horizontal: number, vertical: number) { |
|
control.horizontalAlignment = horizontal; |
|
control.verticalAlignment = vertical; |
|
} |
|
|
|
//设置边距 |
|
static setStyle_padding(control: Control, paddingTop?: string, paddingRight?: string, paddingBottom?: string, paddingLeft?: string) { |
|
if (paddingTop != undefined) { |
|
control.paddingTop = paddingTop; |
|
} |
|
|
|
if (paddingRight != undefined) { |
|
control.paddingRight = paddingRight; |
|
} |
|
if (paddingBottom != undefined) { |
|
control.paddingBottom = paddingBottom; |
|
} |
|
|
|
if (paddingLeft != undefined) { |
|
control.paddingLeft = paddingLeft; |
|
} |
|
|
|
} |
|
|
|
|
|
//设置阴影 |
|
static setStyle_Shadow(container: Control, color: string = BabylonUIStyleTool.c_color_black, blur: number = BabylonUIStyleTool.c_shadow_blur_window) { |
|
container.shadowColor = color; |
|
container.shadowBlur = blur; |
|
|
|
} |
|
//#endregion |
|
|
|
|
|
//#region 功能封装 |
|
|
|
|
|
|
|
/** |
|
* 在按钮上增加长按事件 |
|
* @param button 按钮 |
|
* @param scene 所在的场景 |
|
* @param onEnd 正常长按 |
|
* @param onAbort 长按中端 |
|
*/ |
|
static addLongPressButtonBehave(button: Button, scene: Scene, onEnd?: () => void, onAbort?: () => void) { |
|
let pickDown = false; |
|
|
|
let size = ConfigManager.c_size_facilityIconSize; |
|
let vector2WithInfo: Vector2WithInfo; |
|
|
|
let ellipse: Ellipse; |
|
button.onPointerUpObservable.add((info) => { |
|
if (pickDown) { |
|
pickDown = false; |
|
ellipse.dispose(); |
|
console.log("onPointerUpObservable"); |
|
vector2WithInfo = info; |
|
} |
|
|
|
}); |
|
button.onPointerDownObservable.add(() => { |
|
ellipse = new Ellipse("ellipse"); |
|
ellipse.width = size + "px"; |
|
ellipse.height = size + "px"; |
|
ellipse.color = BabylonUIStyleTool.c_color_blue; |
|
button.addControl(ellipse); |
|
console.log("onPointerDownObservable"); |
|
pickDown = true; |
|
setAndStartTimer({ |
|
timeout: ConfigManager.c_time_longPress, |
|
contextObservable: scene.onBeforeRenderObservable, |
|
breakCondition: () => { |
|
return pickDown == false; |
|
}, |
|
|
|
onEnded: (data) => { |
|
if (onEnd) { |
|
onEnd(); |
|
|
|
setTimeout( |
|
function () { |
|
button.onPointerUpObservable.notifyObservers(vector2WithInfo); |
|
//此处存在问题,因为打开了前端页面,导致焦点小时,babylon无法确定鼠标抬起,则下一次的按下操作失效 |
|
}, |
|
250); |
|
|
|
|
|
} |
|
}, |
|
|
|
onAborted: () => { |
|
if (onAbort) { |
|
onAbort(); |
|
} |
|
}, |
|
|
|
onTick: (data) => { |
|
ellipse.thickness = data.completeRate * 0.5 * size * data.completeRate * data.completeRate; |
|
} |
|
}) |
|
}); |
|
} |
|
|
|
/** |
|
* 在按钮上增加双击事件 |
|
* @param button |
|
* @param scene |
|
* @param onClick 双击的回调 |
|
*/ |
|
static addDoubleClickButtonBehave(button: Button, scene: Scene, onClick: () => void) { |
|
if (BabylonUIStyleTool.s_doubleClickHelper == null) { |
|
BabylonUIStyleTool.s_doubleClickHelper = new DoubleClickHelper(scene); |
|
} |
|
button.onPointerClickObservable.add( |
|
(eventData: Vector2WithInfo, eventState: EventState) => { |
|
let buttonID = button.uniqueId.toString(); |
|
if (BabylonUIStyleTool.s_doubleClickHelper.isDoubleClick(buttonID)) { |
|
onClick(); |
|
} |
|
else { |
|
BabylonUIStyleTool.s_doubleClickHelper.setClickEvent(buttonID); |
|
} |
|
|
|
} |
|
); |
|
|
|
} |
|
|
|
static s_doubleClickHelper: DoubleClickHelper; |
|
|
|
//#endregion |
|
} |
|
|
|
/** |
|
* 双击帮助器 |
|
*/ |
|
class DoubleClickHelper { |
|
readonly c_timer: number = 200; //双击的时间间隔 |
|
scene: Scene; |
|
|
|
timer: number; |
|
buttonID: string; |
|
|
|
constructor(scene: Scene) { |
|
this.scene = scene; |
|
let instance = this; |
|
this.scene.onBeforeRenderObservable.add(() => { |
|
instance.update() |
|
}); |
|
} |
|
|
|
update() { |
|
if (this.timer > 0) { |
|
this.timer -= this.scene.deltaTime; |
|
} |
|
|
|
} |
|
|
|
/** |
|
* 判断双击 |
|
* @param buttonID 按钮id |
|
*/ |
|
isDoubleClick(buttonID: string) { |
|
if (this.buttonID == buttonID && this.timer > 0) { |
|
return true; |
|
} |
|
else { |
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
/** |
|
* 记录点击 |
|
* @param buttonID |
|
*/ |
|
setClickEvent(buttonID: string) { |
|
this.buttonID = buttonID; |
|
this.timer = this.c_timer; |
|
} |
|
|
|
|
|
} |
|
|
|
//#region 功能类 |
|
|
|
export class UI_LineInfo { |
|
key: string; |
|
mesh: AbstractMesh; |
|
|
|
root: Rectangle; |
|
root_size: Vector2; |
|
|
|
points: Ellipse[] = []; |
|
lineLength: number; |
|
|
|
infoBg: Rectangle; |
|
info: TextBlock; |
|
|
|
line: MultiLine; |
|
constructor(l_key: string, l_mesh: AbstractMesh, rootSize: Vector2, infoSize: Vector2) { |
|
this.key = l_key; |
|
this.mesh = l_mesh; |
|
|
|
this.root = new Rectangle("UI_LineRoot_" + this.key); |
|
UIManager.Instance.uiRoot.addControl(this.root); |
|
this.root.thickness = 0; |
|
|
|
|
|
this.root_size = rootSize; |
|
BabylonUIStyleTool.setStyle_size(this.root, rootSize.x + "px", rootSize.y + "px"); |
|
this.root.linkWithMesh(this.mesh); |
|
this.root.linkOffsetXInPixels = rootSize.x * 0.5; |
|
// this.root.linkOffsetYInPixels = -40; |
|
|
|
let point_start = new Ellipse("start"); |
|
point_start.width = "5px"; |
|
point_start.height = "5px"; |
|
this.root.addControl(point_start); |
|
point_start.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
|
point_start.color = BabylonUIStyleTool.c_color_3d_blue; |
|
point_start.background = BabylonUIStyleTool.c_color_3d_blue; |
|
point_start.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
|
point_start.shadowBlur = 5; |
|
this.points.push(point_start); |
|
|
|
let point_end = new Ellipse("end"); |
|
point_end.width = "1px"; |
|
point_end.height = "1px"; |
|
this.root.addControl(point_end); |
|
point_end.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
|
point_end.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
|
this.lineLength = 20; |
|
point_end.left = this.lineLength + "px"; |
|
point_end.topInPixels = infoSize.y * 0.5; |
|
this.points.push(point_end); |
|
|
|
|
|
this.infoBg = new Rectangle("infoBg"); |
|
BabylonUIStyleTool.setStyle_size(this.infoBg, infoSize.x + "px", infoSize.y + "px"); |
|
this.root.addControl(this.infoBg); |
|
this.infoBg.color = BabylonUIStyleTool.c_color_3d_blue; |
|
this.infoBg.shadowBlur = 5; |
|
this.infoBg.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
|
this.infoBg.background = BabylonUIStyleTool.c_color_3d_blueBg; |
|
this.infoBg.alpha = 0.7; |
|
this.infoBg.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT; |
|
this.infoBg.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP; |
|
|
|
this.info = new TextBlock("info", "info") |
|
this.info.fontSize = 12; |
|
this.infoBg.addControl(this.info); |
|
this.info.color = BabylonUIStyleTool.c_color_3d_blueLight; |
|
|
|
|
|
let point_infoBgLeft = new Ellipse("infoBgLeft"); |
|
this.infoBg.addControl(point_infoBgLeft); |
|
BabylonUIStyleTool.setStyle_size(point_infoBgLeft, "1px", "1px"); |
|
point_infoBgLeft.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; |
|
point_infoBgLeft.leftInPixels = -1 |
|
|
|
this.points.push(point_infoBgLeft); |
|
|
|
|
|
this.line = new MultiLine("ui_line_" + this.key); |
|
|
|
for (let i = 0; i < this.points.length; i++) { |
|
this.line.add(this.points[i]); |
|
} |
|
// this.line.add(this.mesh);//起点 |
|
// this.line.add(pointL); |
|
// this.line.add(point); |
|
this.line.lineWidth = 1.5; |
|
this.line.color = BabylonUIStyleTool.c_color_3d_blue; |
|
this.line.alpha = 0.7; |
|
this.line.shadowColor = BabylonUIStyleTool.c_color_3d_blue; |
|
this.line.shadowBlur = 5; |
|
UIManager.Instance.uiRoot.addControl(this.line); |
|
|
|
|
|
} |
|
|
|
setEnable(show: boolean) { |
|
this.root.isVisible = show; |
|
this.line.isVisible = show; |
|
} |
|
|
|
dispose() { |
|
this.root.dispose(); |
|
|
|
this.line.dispose(); |
|
} |
|
|
|
} |
|
|
|
//#endregion
|