1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16interface Frame { 17 x: number; 18 y: number; 19 width: number; 20 height: number; 21} 22 23interface Vector2 { 24 x: number 25 y: number 26} 27 28interface Vector3 { 29 x: number; 30 y: number; 31 z: number; 32} 33 34type Transform = [ 35 number, 36 number, 37 number, 38 number, 39 number, 40 number, 41 number, 42 number, 43 number, 44 number, 45 number, 46 number, 47 number, 48 number, 49 number, 50 number 51]; 52 53enum BorderStyle { 54 SOLID = 0, 55 DASHED, 56 DOTTED, 57 NONE 58} 59 60type EdgeStyles = { 61 top?: BorderStyle; 62 right?: BorderStyle; 63 bottom?: BorderStyle; 64 left?: BorderStyle; 65}; 66 67interface EdgesT<T> { 68 left: T, 69 right: T, 70 top: T, 71 bottom: T, 72} 73interface SizeT<T> { 74 width: T; 75 height: T; 76} 77 78enum LengthUnit { 79 PX = 0, 80 VP = 1, 81 FP = 2, 82 PERCENT = 3, 83 LPX = 4, 84} 85 86enum LengthMetricsUnit { 87 DEFAULT = 0, 88 PX = 1, 89} 90 91type EdgeWidths = EdgesT<Number>; 92 93type EdgeColors = EdgesT<Number>; 94 95interface Corners { 96 topLeft: number, 97 topRight: number, 98 bottomLeft: number, 99 bottomRight: number 100} 101 102type BorderRadiuses = Corners; 103 104interface Rect { 105 left: number, 106 right: number, 107 top: number, 108 bottom: number 109} 110 111interface CornerRadius { 112 topLeft: Vector2, 113 topRight: Vector2, 114 bottomLeft: Vector2, 115 bottomRight: Vector2 116} 117 118interface RoundRect { 119 rect: Rect, 120 corners: CornerRadius 121} 122 123interface Circle { 124 centerX: number, 125 centerY: number, 126 radius: number 127} 128 129interface CommandPath { 130 commands: string 131} 132 133class LengthMetrics { 134 public unit: LengthUnit; 135 public value: number; 136 constructor(value: number, unit?: LengthUnit) { 137 if (unit in LengthUnit) { 138 this.unit = unit; 139 this.value = value; 140 } else { 141 this.unit = LengthUnit.VP; 142 this.value = unit === undefined? value : 0; 143 } 144 } 145 static px(value: number) { 146 return new LengthMetrics(value, LengthUnit.PX); 147 } 148 static vp(value: number) { 149 return new LengthMetrics(value, LengthUnit.VP); 150 } 151 static fp(value: number) { 152 return new LengthMetrics(value, LengthUnit.FP); 153 } 154 static percent(value: number) { 155 return new LengthMetrics(value, LengthUnit.PERCENT); 156 } 157 static lpx(value: number) { 158 return new LengthMetrics(value, LengthUnit.LPX); 159 } 160 static resource(res: Resource) { 161 let length:Array<number> = getUINativeModule().nativeUtils.resoureToLengthMetrics(res); 162 return new LengthMetrics(length[0], length[1]); 163 } 164} 165 166declare interface Resource {} 167declare type BusinessError = any 168 169declare enum Color { 170 White, 171 Black, 172 Blue, 173 Brown, 174 Gray, 175 Green, 176 Grey, 177 Orange, 178 Pink, 179 Red, 180 Yellow, 181 Transparent, 182} 183 184declare type ResourceColor = Color | number | string | Resource; 185 186const MAX_CHANNEL_VALUE = 0xFF; 187const MAX_ALPHA_VALUE = 1; 188const ERROR_CODE_RESOURCE_GET_FAILED = 180003; 189const ERROR_CODE_COLOR_PARAMETER_INCORRECT = 401; 190 191class ColorMetrics { 192 private red_: number; 193 private green_: number; 194 private blue_: number; 195 private alpha_: number; 196 private resourceId_: number; 197 private static clamp(value: number): number { 198 return Math.min(Math.max(value, 0), MAX_CHANNEL_VALUE); 199 } 200 private constructor(red: number, green: number, blue: number, alpha: number = MAX_CHANNEL_VALUE) { 201 this.red_ = ColorMetrics.clamp(red); 202 this.green_ = ColorMetrics.clamp(green); 203 this.blue_ = ColorMetrics.clamp(blue); 204 this.alpha_ = ColorMetrics.clamp(alpha); 205 } 206 private toNumeric(): number { 207 return (this.alpha_ << 24) + (this.red_ << 16) + (this.green_ << 8) + this.blue_; 208 } 209 static numeric(value: number): ColorMetrics { 210 const red = (value >> 16) & 0x000000FF; 211 const green = (value >> 8) & 0x000000FF; 212 const blue = value & 0x000000FF; 213 const alpha = (value >> 24) & 0x000000FF; 214 if (alpha === 0) { 215 return new ColorMetrics(red, green, blue); 216 } 217 return new ColorMetrics(red, green, blue, alpha); 218 } 219 static rgba(red: number, green: number, blue: number, alpha: number = MAX_ALPHA_VALUE): ColorMetrics { 220 return new ColorMetrics(red, green, blue, alpha * MAX_CHANNEL_VALUE); 221 } 222 223 private static rgbOrRGBA(format: string): ColorMetrics { 224 const rgbPattern = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i; 225 const rgbaPattern = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+(\.\d+)?)\s*\)$/i; 226 227 const rgbMatch = rgbPattern.exec(format); 228 const rgbaMatch = rgbaPattern.exec(format); 229 230 if (rgbMatch) { 231 const [, red, green, blue] = rgbMatch; 232 return new ColorMetrics(Number.parseInt(red, 10), Number.parseInt(green, 10), Number.parseInt(blue, 10)); 233 } else if (rgbaMatch) { 234 const [, red, green, blue, alpha] = rgbaMatch; 235 return new ColorMetrics(Number.parseInt(red, 10), Number.parseInt(green, 10), Number.parseInt(blue, 10), Number.parseFloat(alpha) * MAX_CHANNEL_VALUE); 236 } else { 237 const error = new Error('Parameter error. The format of the input color string is not RGB or RGBA.') as BusinessError; 238 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 239 throw error; 240 } 241 } 242 243 static resourceColor(color: ResourceColor): ColorMetrics { 244 if (color === undefined || color === null) { 245 const error = new Error('Parameter error. The type of the input color parameter is not ResourceColor.') as BusinessError; 246 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 247 throw error; 248 } 249 let chanels: Array<number> = []; 250 if (typeof color === 'object') { 251 chanels = getUINativeModule().nativeUtils.parseResourceColor(color); 252 if (chanels === undefined) { 253 const error = new Error('Failed to obtain the color resource.') as BusinessError; 254 error.code = ERROR_CODE_RESOURCE_GET_FAILED; 255 throw error; 256 } 257 const red = chanels[0]; 258 const green = chanels[1]; 259 const blue = chanels[2]; 260 const alpha = chanels[3]; 261 const resourceId = chanels[4]; 262 const colorMetrics = new ColorMetrics(red, green, blue, alpha); 263 colorMetrics.setResourceId(resourceId); 264 return colorMetrics; 265 } else if (typeof color === 'number') { 266 return ColorMetrics.numeric(color); 267 } else if (typeof color === 'string') { 268 if (ColorMetrics.isHexFormat(color)) { 269 return ColorMetrics.hex(color); 270 } else { 271 return ColorMetrics.rgbOrRGBA(color); 272 } 273 } else { 274 const error = new Error('Parameter error. The type of the input color parameter is not ResourceColor.') as BusinessError; 275 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 276 throw error; 277 } 278 } 279 private static isHexFormat(format: string): boolean { 280 return /#(([0-9A-Fa-f]{3})|([0-9A-Fa-f]{6})|([0-9A-Fa-f]{4})|([0-9A-Fa-f]{8}))/.test(format); 281 } 282 283 private static hex(hexFormat: string): ColorMetrics { 284 let r: number = 0; 285 let g: number = 0; 286 let b: number = 0; 287 let a: number = 255; 288 if (hexFormat.length === 4) { 289 r = parseInt(hexFormat.slice(1, 2).repeat(2), 16); 290 g = parseInt(hexFormat.slice(2, 3).repeat(2), 16); 291 b = parseInt(hexFormat.slice(3).repeat(2), 16); 292 } else if (hexFormat.length === 7) { 293 r = parseInt(hexFormat.slice(1, 3), 16); 294 g = parseInt(hexFormat.slice(3, 5), 16); 295 b = parseInt(hexFormat.slice(5), 16); 296 } else if (hexFormat.length === 5) { 297 a = parseInt(hexFormat.slice(1, 2).repeat(2), 16); 298 r = parseInt(hexFormat.slice(2, 3).repeat(2), 16); 299 g = parseInt(hexFormat.slice(3, 4).repeat(2), 16); 300 b = parseInt(hexFormat.slice(4).repeat(2), 16); 301 } else if (hexFormat.length === 9) { 302 a = parseInt(hexFormat.slice(1, 3), 16); 303 r = parseInt(hexFormat.slice(3, 5), 16); 304 g = parseInt(hexFormat.slice(5, 7), 16); 305 b = parseInt(hexFormat.slice(7), 16); 306 } 307 return new ColorMetrics(r, g, b, a); 308 } 309 blendColor(overlayColor: ColorMetrics): ColorMetrics { 310 if (overlayColor === undefined || overlayColor === null) { 311 const error = new Error('Parameter error. The type of the input parameter is not ColorMetrics.') as BusinessError; 312 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 313 throw error; 314 } 315 const chanels = getUINativeModule().nativeUtils.blendColor(this.toNumeric(), overlayColor.toNumeric()); 316 if (chanels === undefined) { 317 const error = new Error('Parameter error. The type of the input parameter is not ColorMetrics.') as BusinessError; 318 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 319 throw error; 320 } 321 const red = chanels[0]; 322 const green = chanels[1]; 323 const blue = chanels[2]; 324 const alpha = chanels[3]; 325 return new ColorMetrics(red, green, blue, alpha); 326 } 327 get color(): string { 328 return `rgba(${this.red_}, ${this.green_}, ${this.blue_}, ${this.alpha_ / MAX_CHANNEL_VALUE})`; 329 } 330 get red(): number { 331 return this.red_; 332 } 333 get green(): number { 334 return this.green_; 335 } 336 get blue(): number { 337 return this.blue_; 338 } 339 get alpha(): number { 340 return this.alpha_; 341 } 342 setResourceId(resourceId: number): void { 343 this.resourceId_ = resourceId; 344 } 345 getResourceId(): number { 346 return this.resourceId_; 347 } 348} 349 350class BaseShape { 351 public rect: Rect | null = null; 352 public roundRect: RoundRect | null = null; 353 public circle: Circle | null = null; 354 public oval: Rect | null = null; 355 public path: CommandPath | null = null; 356 setRectShape(rect: Rect) { 357 this.rect = rect; 358 this.roundRect = null; 359 this.circle = null; 360 this.oval = null; 361 this.path = null; 362 } 363 setRoundRectShape(roundRect: RoundRect) { 364 this.roundRect = roundRect; 365 this.rect = null; 366 this.circle = null; 367 this.oval = null; 368 this.path = null; 369 } 370 setCircleShape(circle: Circle) { 371 this.circle = circle; 372 this.rect = null; 373 this.roundRect = null; 374 this.oval = null; 375 this.path = null; 376 } 377 setOvalShape(oval: Rect) { 378 this.oval = oval; 379 this.rect = null; 380 this.circle = null; 381 this.roundRect = null; 382 this.path = null; 383 } 384 setCommandPath(path: CommandPath) { 385 this.path = path; 386 this.oval = null; 387 this.rect = null; 388 this.circle = null; 389 this.roundRect = null; 390 } 391} 392 393class ShapeClip extends BaseShape { } 394 395class ShapeMask extends BaseShape { 396 public fillColor: number = 0XFF000000; 397 public strokeColor: number = 0XFF000000; 398 public strokeWidth: number = 0; 399} 400 401class RenderNode { 402 private childrenList: Array<RenderNode>; 403 private nodePtr: NodePtr; 404 private parentRenderNode: WeakRef<RenderNode> | null; 405 private backgroundColorValue: number; 406 private clipToFrameValue: boolean; 407 private frameValue: Frame; 408 private opacityValue: number; 409 private pivotValue: Vector2; 410 private rotationValue: Vector3; 411 private scaleValue: Vector2; 412 private shadowColorValue: number; 413 private shadowOffsetValue: Vector2; 414 private labelValue: string; 415 private shadowAlphaValue: number; 416 private shadowElevationValue: number; 417 private shadowRadiusValue: number; 418 private transformValue: Transform; 419 private translationValue: Vector2; 420 private baseNode_: BaseNode; 421 private borderStyleValue: EdgeStyles; 422 private borderWidthValue: EdgeWidths; 423 private borderColorValue: EdgeColors; 424 private borderRadiusValue: BorderRadiuses; 425 private shapeMaskValue: ShapeMask; 426 private shapeClipValue: ShapeClip; 427 private _nativeRef: NativeStrongRef; 428 private _frameNode: WeakRef<FrameNode>; 429 private lengthMetricsUnitValue: LengthMetricsUnit; 430 private markNodeGroupValue: boolean; 431 private apiTargetVersion: number; 432 433 constructor(type: string) { 434 this.nodePtr = null; 435 this.childrenList = []; 436 this.parentRenderNode = null; 437 this.backgroundColorValue = 0; 438 this.apiTargetVersion = getUINativeModule().common.getApiTargetVersion(); 439 this.clipToFrameValue = true; 440 if (this.apiTargetVersion && this.apiTargetVersion < 12) { 441 this.clipToFrameValue = false; 442 } 443 this.frameValue = { x: 0, y: 0, width: 0, height: 0 }; 444 this.opacityValue = 1.0; 445 this.pivotValue = { x: 0.5, y: 0.5 }; 446 this.rotationValue = { x: 0, y: 0, z: 0 }; 447 this.scaleValue = { x: 1.0, y: 1.0 }; 448 this.shadowColorValue = 0; 449 this.shadowOffsetValue = { x: 0, y: 0 }; 450 this.labelValue = ''; 451 this.shadowAlphaValue = 0; 452 this.shadowElevationValue = 0; 453 this.shadowRadiusValue = 0; 454 this.transformValue = [1, 0, 0, 0, 455 0, 1, 0, 0, 456 0, 0, 1, 0, 457 0, 0, 0, 1]; 458 this.translationValue = { x: 0, y: 0 }; 459 this.lengthMetricsUnitValue = LengthMetricsUnit.DEFAULT; 460 this.markNodeGroupValue = false; 461 if (type === 'BuilderRootFrameNode' || type === 'CustomFrameNode') { 462 return; 463 } 464 this._nativeRef = getUINativeModule().renderNode.createRenderNode(this); 465 this.nodePtr = this._nativeRef?.getNativeHandle(); 466 if (this.apiTargetVersion && this.apiTargetVersion < 12) { 467 this.clipToFrame = false; 468 } else { 469 this.clipToFrame = true; 470 } 471 } 472 473 set backgroundColor(color: number) { 474 this.backgroundColorValue = this.checkUndefinedOrNullWithDefaultValue<number>(color, 0); 475 getUINativeModule().renderNode.setBackgroundColor(this.nodePtr, this.backgroundColorValue); 476 } 477 set clipToFrame(useClip: boolean) { 478 this.clipToFrameValue = this.checkUndefinedOrNullWithDefaultValue<boolean>(useClip, true); 479 getUINativeModule().renderNode.setClipToFrame(this.nodePtr, this.clipToFrameValue); 480 } 481 set frame(frame: Frame) { 482 if (frame === undefined || frame === null) { 483 this.frameValue = { x: 0, y: 0, width: 0, height: 0 }; 484 } else { 485 this.size = { width: frame.width, height: frame.height }; 486 this.position = { x: frame.x, y: frame.y }; 487 } 488 } 489 set opacity(value: number) { 490 this.opacityValue = this.checkUndefinedOrNullWithDefaultValue<number>(value, 1.0); 491 getUINativeModule().common.setOpacity(this.nodePtr, this.opacityValue); 492 } 493 set pivot(pivot: Vector2) { 494 if (pivot === undefined || pivot === null) { 495 this.pivotValue = { x: 0.5, y: 0.5 }; 496 } else { 497 this.pivotValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(pivot.x, 0.5); 498 this.pivotValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(pivot.y, 0.5); 499 } 500 getUINativeModule().renderNode.setPivot(this.nodePtr, this.pivotValue.x, this.pivotValue.y); 501 } 502 set position(position: Vector2) { 503 if (position === undefined || position === null) { 504 this.frameValue.x = 0; 505 this.frameValue.y = 0; 506 } else { 507 this.frameValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(position.x, 0); 508 this.frameValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(position.y, 0); 509 } 510 getUINativeModule().renderNode.setPosition(this.nodePtr, this.frameValue.x, this.frameValue.y, this.lengthMetricsUnitValue); 511 } 512 set rotation(rotation: Vector3) { 513 if (rotation === undefined || rotation === null) { 514 this.rotationValue = { x: 0, y: 0, z: 0 }; 515 } else { 516 this.rotationValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.x, 0); 517 this.rotationValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.y, 0); 518 this.rotationValue.z = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.z, 0); 519 } 520 getUINativeModule().renderNode.setRotation(this.nodePtr, this.rotationValue.x, this.rotationValue.y, this.rotationValue.z, this.lengthMetricsUnitValue); 521 } 522 set scale(scale: Vector2) { 523 if (scale === undefined || scale === null) { 524 this.scaleValue = { x: 1.0, y: 1.0 }; 525 } else { 526 this.scaleValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(scale.x, 1.0); 527 this.scaleValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(scale.y, 1.0); 528 } 529 getUINativeModule().renderNode.setScale(this.nodePtr, this.scaleValue.x, this.scaleValue.y); 530 } 531 set shadowColor(color: number) { 532 this.shadowColorValue = this.checkUndefinedOrNullWithDefaultValue<number>(color, 0); 533 getUINativeModule().renderNode.setShadowColor(this.nodePtr, this.shadowColorValue); 534 } 535 set shadowOffset(offset: Vector2) { 536 if (offset === undefined || offset === null) { 537 this.shadowOffsetValue = { x: 0, y: 0 }; 538 } else { 539 this.shadowOffsetValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(offset.x, 0); 540 this.shadowOffsetValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(offset.y, 0); 541 } 542 getUINativeModule().renderNode.setShadowOffset(this.nodePtr, this.shadowOffsetValue.x, this.shadowOffsetValue.y, this.lengthMetricsUnitValue); 543 } 544 set label(label: string) { 545 this.labelValue = this.checkUndefinedOrNullWithDefaultValue<string>(label, ''); 546 getUINativeModule().renderNode.setLabel(this.nodePtr, this.labelValue); 547 } 548 set shadowAlpha(alpha: number) { 549 this.shadowAlphaValue = this.checkUndefinedOrNullWithDefaultValue<number>(alpha, 0); 550 getUINativeModule().renderNode.setShadowAlpha(this.nodePtr, this.shadowAlphaValue); 551 } 552 set shadowElevation(elevation: number) { 553 this.shadowElevationValue = this.checkUndefinedOrNullWithDefaultValue<number>(elevation, 0); 554 getUINativeModule().renderNode.setShadowElevation(this.nodePtr, this.shadowElevationValue); 555 } 556 set shadowRadius(radius: number) { 557 this.shadowRadiusValue = this.checkUndefinedOrNullWithDefaultValue<number>(radius, 0); 558 getUINativeModule().renderNode.setShadowRadius(this.nodePtr, this.shadowRadiusValue); 559 } 560 set size(size: Size) { 561 if (size === undefined || size === null) { 562 this.frameValue.width = 0; 563 this.frameValue.height = 0; 564 } else { 565 this.frameValue.width = this.checkUndefinedOrNullWithDefaultValue<number>(size.width, 0); 566 this.frameValue.height = this.checkUndefinedOrNullWithDefaultValue<number>(size.height, 0); 567 } 568 getUINativeModule().renderNode.setSize(this.nodePtr, this.frameValue.width, this.frameValue.height, this.lengthMetricsUnitValue); 569 } 570 set transform(transform: Transform) { 571 if (transform === undefined || transform === null) { 572 this.transformValue = [1, 0, 0, 0, 573 0, 1, 0, 0, 574 0, 0, 1, 0, 575 0, 0, 0, 1]; 576 } else { 577 let i: number = 0; 578 while (i < transform.length && i < 16) { 579 if (i % 5 === 0) { 580 this.transformValue[i] = this.checkUndefinedOrNullWithDefaultValue<number>(transform[i], 1); 581 } else { 582 this.transformValue[i] = this.checkUndefinedOrNullWithDefaultValue<number>(transform[i], 0); 583 } 584 i = i + 1; 585 } 586 } 587 getUINativeModule().common.setTransform(this.nodePtr, this.transformValue); 588 } 589 set translation(translation: Vector2) { 590 if (translation === undefined || translation === null) { 591 this.translationValue = { x: 0, y: 0 }; 592 } else { 593 this.translationValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(translation.x, 0); 594 this.translationValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(translation.y, 0); 595 } 596 getUINativeModule().renderNode.setTranslate(this.nodePtr, this.translationValue.x, this.translationValue.y, 0); 597 } 598 set lengthMetricsUnit(unit: LengthMetricsUnit) { 599 if (unit === undefined || unit == null) { 600 this.lengthMetricsUnitValue = LengthMetricsUnit.DEFAULT; 601 } else { 602 this.lengthMetricsUnitValue = unit; 603 } 604 } 605 set markNodeGroup(isNodeGroup) { 606 if (isNodeGroup === undefined || isNodeGroup === null) { 607 this.markNodeGroupValue = false; 608 } else { 609 this.markNodeGroupValue = isNodeGroup; 610 } 611 getUINativeModule().renderNode.setMarkNodeGroup(this.nodePtr, this.markNodeGroupValue); 612 } 613 get backgroundColor(): number { 614 return this.backgroundColorValue; 615 } 616 get clipToFrame(): boolean { 617 return this.clipToFrameValue; 618 } 619 get opacity(): number { 620 return this.opacityValue; 621 } 622 get frame(): Frame { 623 return this.frameValue; 624 } 625 get pivot(): Vector2 { 626 return this.pivotValue; 627 } 628 get position(): Vector2 { 629 return { x: this.frameValue.x, y: this.frameValue.y }; 630 } 631 get rotation(): Vector3 { 632 return this.rotationValue; 633 } 634 get scale(): Vector2 { 635 return this.scaleValue; 636 } 637 get shadowColor(): number { 638 return this.shadowColorValue; 639 } 640 get shadowOffset(): Vector2 { 641 return this.shadowOffsetValue; 642 } 643 get label(): string { 644 return this.labelValue; 645 } 646 get shadowAlpha(): number { 647 return this.shadowAlphaValue; 648 } 649 get shadowElevation(): number { 650 return this.shadowElevationValue; 651 } 652 get shadowRadius(): number { 653 return this.shadowRadiusValue; 654 } 655 get size(): Size { 656 return { width: this.frameValue.width, height: this.frameValue.height }; 657 } 658 get transform(): Transform { 659 return this.transformValue; 660 } 661 get translation(): Vector2 { 662 return this.translationValue; 663 } 664 get lengthMetricsUnit() { 665 return this.lengthMetricsUnitValue; 666 } 667 get markNodeGroup() { 668 return this.markNodeGroupValue; 669 } 670 checkUndefinedOrNullWithDefaultValue<T>(arg: T, defaultValue: T): T { 671 if (arg === undefined || arg === null) { 672 return defaultValue; 673 } else { 674 return arg; 675 } 676 } 677 appendChild(node: RenderNode) { 678 if (node === undefined || node === null) { 679 return; 680 } 681 if (this.childrenList.findIndex(element => element === node) !== -1) { 682 return; 683 } 684 this.childrenList.push(node); 685 node.parentRenderNode = new WeakRef(this); 686 getUINativeModule().renderNode.appendChild(this.nodePtr, node.nodePtr); 687 } 688 insertChildAfter(child: RenderNode, sibling: RenderNode | null) { 689 if (child === undefined || child === null) { 690 return; 691 } 692 let indexOfNode: number = this.childrenList.findIndex(element => element === child); 693 if (indexOfNode !== -1) { 694 return; 695 } 696 child.parentRenderNode = new WeakRef(this); 697 let indexOfSibling = this.childrenList.findIndex(element => element === sibling); 698 if (indexOfSibling === -1) { 699 sibling === null; 700 } 701 if (sibling === undefined || sibling === null) { 702 this.childrenList.splice(0, 0, child); 703 getUINativeModule().renderNode.insertChildAfter(this.nodePtr, child.nodePtr, null); 704 } else { 705 this.childrenList.splice(indexOfSibling + 1, 0, child); 706 getUINativeModule().renderNode.insertChildAfter(this.nodePtr, child.nodePtr, sibling.nodePtr); 707 } 708 } 709 removeChild(node: RenderNode) { 710 if (node === undefined || node === null) { 711 return; 712 } 713 const index = this.childrenList.findIndex(element => element === node); 714 if (index === -1) { 715 return; 716 } 717 const child = this.childrenList[index]; 718 child.parentRenderNode = null; 719 this.childrenList.splice(index, 1); 720 getUINativeModule().renderNode.removeChild(this.nodePtr, node.nodePtr); 721 } 722 clearChildren() { 723 this.childrenList = new Array<RenderNode>(); 724 getUINativeModule().renderNode.clearChildren(this.nodePtr); 725 } 726 getChild(index: number): RenderNode | null { 727 if (this.childrenList.length > index && index >= 0) { 728 return this.childrenList[index]; 729 } 730 return null; 731 } 732 getFirstChild(): RenderNode | null { 733 if (this.childrenList.length > 0) { 734 return this.childrenList[0]; 735 } 736 return null; 737 } 738 getNextSibling(): RenderNode | null { 739 if (this.parentRenderNode === undefined || this.parentRenderNode === null) { 740 return null; 741 } 742 let parent = this.parentRenderNode.deref(); 743 if (parent === undefined || parent === null) { 744 return null; 745 } 746 let siblingList = parent.childrenList; 747 const index = siblingList.findIndex(element => element === this); 748 if (index === -1) { 749 return null; 750 } 751 return parent.getChild(index + 1); 752 } 753 getPreviousSibling(): RenderNode | null { 754 if (this.parentRenderNode === undefined || this.parentRenderNode === null) { 755 return null; 756 } 757 let parent = this.parentRenderNode.deref(); 758 if (parent === undefined || parent === null) { 759 return null; 760 } 761 let siblingList = parent.childrenList; 762 const index = siblingList.findIndex(element => element === this); 763 if (index === -1) { 764 return null; 765 } 766 return parent.getChild(index - 1); 767 } 768 setFrameNode(frameNode: WeakRef<FrameNode>) { 769 this._frameNode = frameNode; 770 } 771 772 setNodePtr(nativeRef: NativeStrongRef) { 773 this._nativeRef = nativeRef; 774 this.nodePtr = this._nativeRef?.getNativeHandle(); 775 } 776 777 setBaseNode(baseNode: BaseNode | null) { 778 this.baseNode_ = baseNode; 779 } 780 resetNodePtr(): void { 781 this.nodePtr = null; 782 this._nativeRef = null; 783 } 784 dispose() { 785 this._nativeRef?.dispose(); 786 this.baseNode_?.disposeNode(); 787 this._frameNode?.deref()?.resetNodePtr(); 788 this._nativeRef = null; 789 this.nodePtr = null; 790 } 791 getNodePtr(): NodePtr { 792 return this.nodePtr; 793 } 794 795 invalidate() { 796 getUINativeModule().renderNode.invalidate(this.nodePtr); 797 } 798 set borderStyle(style: EdgeStyles) { 799 if (style === undefined || style === null) { 800 this.borderStyleValue = { left: BorderStyle.NONE, top: BorderStyle.NONE, right: BorderStyle.NONE, bottom: BorderStyle.NONE }; 801 } else { 802 this.borderStyleValue = style; 803 } 804 getUINativeModule().renderNode.setBorderStyle( 805 this.nodePtr, this.borderStyleValue.left, this.borderStyleValue.top, this.borderStyleValue.right, this.borderStyleValue.bottom); 806 } 807 get borderStyle(): EdgeStyles { 808 return this.borderStyleValue; 809 } 810 set borderWidth(width: EdgeWidths) { 811 if (width === undefined || width === null) { 812 this.borderWidthValue = { left: 0, top: 0, right: 0, bottom: 0 }; 813 } else { 814 this.borderWidthValue = width; 815 } 816 getUINativeModule().renderNode.setBorderWidth( 817 this.nodePtr, this.borderWidthValue.left, this.borderWidthValue.top, 818 this.borderWidthValue.right, this.borderWidthValue.bottom, this.lengthMetricsUnitValue); 819 } 820 get borderWidth(): EdgeWidths { 821 return this.borderWidthValue; 822 } 823 set borderColor(color: EdgeColors) { 824 if (color === undefined || color === null) { 825 this.borderColorValue = { left: 0XFF000000, top: 0XFF000000, right: 0XFF000000, bottom: 0XFF000000 }; 826 } else { 827 this.borderColorValue = color; 828 } 829 getUINativeModule().renderNode.setBorderColor( 830 this.nodePtr, this.borderColorValue.left, this.borderColorValue.top, this.borderColorValue.right, this.borderColorValue.bottom); 831 } 832 get borderColor(): EdgeColors { 833 return this.borderColorValue; 834 } 835 set borderRadius(radius: BorderRadiuses) { 836 if (radius === undefined || radius === null) { 837 this.borderRadiusValue = { topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0 }; 838 } else { 839 this.borderRadiusValue = radius; 840 } 841 getUINativeModule().renderNode.setBorderRadius( 842 this.nodePtr, this.borderRadiusValue.topLeft, this.borderRadiusValue.topRight, 843 this.borderRadiusValue.bottomLeft, this.borderRadiusValue.bottomRight, this.lengthMetricsUnitValue); 844 } 845 get borderRadius(): BorderRadiuses { 846 return this.borderRadiusValue; 847 } 848 set shapeMask(shapeMask: ShapeMask) { 849 if (shapeMask === undefined || shapeMask === null) { 850 this.shapeMaskValue = new ShapeMask(); 851 } else { 852 this.shapeMaskValue = shapeMask; 853 } 854 if (this.shapeMaskValue.rect !== null) { 855 const rectMask = this.shapeMaskValue.rect; 856 getUINativeModule().renderNode.setRectMask( 857 this.nodePtr, rectMask.left, rectMask.top, rectMask.right, rectMask.bottom, 858 this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth); 859 } else if (this.shapeMaskValue.circle !== null) { 860 const circle = this.shapeMaskValue.circle; 861 getUINativeModule().renderNode.setCircleMask( 862 this.nodePtr, circle.centerX, circle.centerY, circle.radius, 863 this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth); 864 } else if (this.shapeMaskValue.roundRect !== null) { 865 const roundRect = this.shapeMask.roundRect; 866 const corners = roundRect.corners; 867 const rect = roundRect.rect; 868 getUINativeModule().renderNode.setRoundRectMask( 869 this.nodePtr, 870 corners.topLeft.x, 871 corners.topLeft.y, 872 corners.topRight.x, 873 corners.topRight.y, 874 corners.bottomLeft.x, 875 corners.bottomLeft.y, 876 corners.bottomRight.x, 877 corners.bottomRight.y, 878 rect.left, 879 rect.top, 880 rect.right, 881 rect.bottom, 882 this.shapeMaskValue.fillColor, 883 this.shapeMaskValue.strokeColor, 884 this.shapeMaskValue.strokeWidth); 885 } else if (this.shapeMaskValue.oval !== null) { 886 const oval = this.shapeMaskValue.oval; 887 getUINativeModule().renderNode.setOvalMask( 888 this.nodePtr, oval.left, oval.top, oval.right, oval.bottom, 889 this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth); 890 } else if (this.shapeMaskValue.path !== null) { 891 const path = this.shapeMaskValue.path; 892 getUINativeModule().renderNode.setPath( 893 this.nodePtr, path.commands, this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth); 894 } 895 } 896 get shapeMask(): ShapeMask { 897 return this.shapeMaskValue; 898 } 899 set shapeClip(shapeClip: ShapeClip) { 900 if (shapeClip === undefined || shapeClip === null) { 901 this.shapeClipValue = new ShapeClip(); 902 } else { 903 this.shapeClipValue = shapeClip; 904 } 905 if (this.shapeClipValue.rect !== null) { 906 const rectClip = this.shapeClipValue.rect; 907 getUINativeModule().renderNode.setRectClip( 908 this.nodePtr, rectClip.left, rectClip.top, rectClip.right, rectClip.bottom); 909 } else if (this.shapeClipValue.circle !== null) { 910 const circle = this.shapeClipValue.circle; 911 getUINativeModule().renderNode.setCircleClip( 912 this.nodePtr, circle.centerX, circle.centerY, circle.radius); 913 } else if (this.shapeClipValue.roundRect !== null) { 914 const roundRect = this.shapeClipValue.roundRect; 915 const corners = roundRect.corners; 916 const rect = roundRect.rect; 917 getUINativeModule().renderNode.setRoundRectClip( 918 this.nodePtr, 919 corners.topLeft.x, 920 corners.topLeft.y, 921 corners.topRight.x, 922 corners.topRight.y, 923 corners.bottomLeft.x, 924 corners.bottomLeft.y, 925 corners.bottomRight.x, 926 corners.bottomRight.y, 927 rect.left, 928 rect.top, 929 rect.right, 930 rect.bottom); 931 } else if (this.shapeClipValue.oval !== null) { 932 const oval = this.shapeClipValue.oval; 933 getUINativeModule().renderNode.setOvalClip( 934 this.nodePtr, oval.left, oval.top, oval.right, oval.bottom, 935 ); 936 } else if (this.shapeClipValue.path !== null) { 937 const path = this.shapeClipValue.path; 938 getUINativeModule().renderNode.setPathClip( 939 this.nodePtr, path.commands); 940 } 941 } 942 get shapeClip(): ShapeClip { 943 this.shapeClipValue = this.shapeClipValue ? this.shapeClipValue : new ShapeClip(); 944 return this.shapeClipValue; 945 } 946} 947 948function edgeColors(all: number): EdgeColors { 949 return { left: all, top: all, right: all, bottom: all }; 950} 951 952function edgeWidths(all: number): EdgeWidths { 953 return { left: all, top: all, right: all, bottom: all }; 954} 955 956function borderStyles(all: BorderStyle): EdgeStyles { 957 return { left: all, top: all, right: all, bottom: all }; 958} 959 960function borderRadiuses(all: number): BorderRadiuses { 961 return { topLeft: all, topRight: all, bottomLeft: all, bottomRight: all }; 962} 963