diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..ac909da
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,160 @@
+Language: Cpp
+# BasedOnStyle: LLVM
+# 访问说明符(public、private等)的偏移
+AccessModifierOffset: -4
+# 开括号(开圆括号、开尖括号、开方括号)后的对齐
+AlignAfterOpenBracket: Align
+# 连续赋值时,等号对齐
+AlignConsecutiveAssignments: false
+# 连续赋值时,变量名对齐
+AlignConsecutiveDeclarations: false
+# 左对齐逃脱换行(使用反斜杠换行)的反斜杠
+AlignEscapedNewlinesLeft: true
+# 水平对齐二元和三元表达式的操作数
+AlignOperands: true
+# 对齐连续的尾随的注释
+AlignTrailingComments: true
+# 允许函数声明的所有参数在放在下一行
+AllowAllParametersOfDeclarationOnNextLine: false
+# 允许短的块放在同一行
+AllowShortBlocksOnASingleLine: false
+# 允许短的case标签放在同一行
+AllowShortCaseLabelsOnASingleLine: false
+# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All
+AllowShortFunctionsOnASingleLine: Empty
+# 允许短的if语句保持在同一行
+AllowShortIfStatementsOnASingleLine: false
+# 允许短的循环保持在同一行
+AllowShortLoopsOnASingleLine: false
+# 总是在定义返回类型后换行(deprecated)
+AlwaysBreakAfterDefinitionReturnType: None
+# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数),
+# AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义)
+AlwaysBreakAfterReturnType: None
+# 总是在多行string字面量前换行
+AlwaysBreakBeforeMultilineStrings: true
+# 总是在template声明后换行
+AlwaysBreakTemplateDeclarations: false
+# false表示函数实参要么都在同一行,要么都各自一行
+BinPackArguments: true
+# false表示所有形参要么都在同一行,要么都各自一行
+BinPackParameters: false
+# 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行)
+BreakBeforeBinaryOperators: None
+# 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似),
+# Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似),
+# Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom
+# 注:这里认为语句块也属于函数
+BreakBeforeBraces: Custom
+# 在三元运算符前换行
+BreakBeforeTernaryOperators: false
+# 在构造函数的初始化列表的逗号前换行
+BreakConstructorInitializersBeforeComma: false
+# 每行字符的限制,0表示没有限制
+ColumnLimit: 120
+# 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变
+CommentPragmas: "^ IWYU pragma:"
+# 构造函数的初始化列表要么都在同一行,要么都各自一行
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+# 构造函数的初始化列表的缩进宽度
+ConstructorInitializerIndentWidth: 4
+# 延续的行的缩进宽度
+ContinuationIndentWidth: 4
+# 去除C++11的列表初始化的大括号{后和}前的空格
+Cpp11BracedListStyle: true
+# 继承最常用的指针和引用的对齐方式
+DerivePointerAlignment: false
+# 关闭格式化
+DisableFormat: false
+# 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental)
+ExperimentalAutoDetectBinPacking: false
+# 需要被解读为foreach循环而不是函数调用的宏
+ForEachMacros: [foreach, Q_FOREACH, BOOST_FOREACH]
+# 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级,匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前),
+# 可以定义负数优先级从而保证某些#include永远在最前面
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ - Regex: '^(<|"(gtest|isl|json)/)'
+ Priority: 3
+ - Regex: ".*"
+ Priority: 1
+# 缩进case标签
+IndentCaseLabels: true
+# 缩进宽度
+IndentWidth: 4
+# 函数返回类型换行时,缩进函数声明或函数定义的函数名
+IndentWrappedFunctionNames: true
+# 保留在块开始处的空行
+KeepEmptyLinesAtTheStartOfBlocks: true
+# 开始一个块的宏的正则表达式
+MacroBlockBegin: ""
+# 结束一个块的宏的正则表达式
+MacroBlockEnd: ""
+# 连续空行的最大数量
+MaxEmptyLinesToKeep: 1
+# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All
+NamespaceIndentation: None
+# 使用ObjC块时缩进宽度
+ObjCBlockIndentWidth: 4
+# 在ObjC的@property后添加一个空格
+ObjCSpaceAfterProperty: false
+# 在ObjC的protocol列表前添加一个空格
+ObjCSpaceBeforeProtocolList: true
+# 在call(后对函数调用换行的penalty
+PenaltyBreakBeforeFirstCallParameter: 19
+# 在一个注释中引入换行的penalty
+PenaltyBreakComment: 300
+# 第一次在<<前换行的penalty
+PenaltyBreakFirstLessLess: 120
+# 在一个字符串字面量中引入换行的penalty
+PenaltyBreakString: 1000
+# 对于每个在行字符数限制之外的字符的penalt
+PenaltyExcessCharacter: 1000000
+# 将函数的返回类型放到它自己的行的penalty
+PenaltyReturnTypeOnItsOwnLine: 60
+# 指针和引用的对齐: Left, Right, Middle
+PointerAlignment: Left
+# 允许重新排版注释
+ReflowComments: true
+# 允许排序#include
+SortIncludes: true
+# 在C风格类型转换后添加空格
+SpaceAfterCStyleCast: false
+# 在赋值运算符之前添加空格
+SpaceBeforeAssignmentOperators: true
+# 开圆括号之前添加一个空格: Never, ControlStatements, Always
+SpaceBeforeParens: ControlStatements
+# 在空的圆括号中添加空格
+SpaceInEmptyParentheses: false
+# 在尾随的评论前添加的空格数(只适用于//)
+SpacesBeforeTrailingComments: 1
+# 在尖括号的<后和>前添加空格
+SpacesInAngles: false
+# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格
+SpacesInContainerLiterals: true
+# 在C风格类型转换的括号中添加空格
+SpacesInCStyleCastParentheses: false
+# 在圆括号的(后和)前添加空格
+SpacesInParentheses: false
+# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响
+SpacesInSquareBrackets: false
+# 标准: Cpp03, Cpp11, Auto
+Standard: Cpp11
+# tab宽度
+TabWidth: 4
+# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always
+UseTab: Never
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7ff7443
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/huawei_proprietary
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..95e0f28
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,170 @@
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build/lite/config/component/lite_component.gni")
+import("//build/lite/config/subsystem/graphic/config.gni")
+import("//build/lite/ndk/ndk.gni")
+
+lite_component("lite_ui") {
+ features = [ ":ui" ]
+ public_deps = features
+}
+
+ndk_lib("lite_ui_ndk") {
+ lib_extension = ".so"
+ deps = [ ":ui" ]
+ head_files = [ "interfaces/kits" ]
+}
+
+config("graphic_define_config") {
+ include_dirs = [
+ "interfaces/kits",
+ "interfaces/innerkits",
+ ]
+
+ defines = [
+ "ENABLE_VECTOR_FONT=1",
+ "ENABLE_SHAPING=0",
+ "ENABLE_ICU=0",
+ "ENABLE_MULTI_FONT=0",
+ ]
+
+ if (ohos_kernel_type == "linux") {
+ defines += [ "RESOURCE_DIR=\"/storage/data/\"" ]
+ } else {
+ defines += [ "RESOURCE_DIR=\"/user/data/\"" ]
+ }
+}
+
+if (enable_graphic_font) {
+ copy("utils_config") {
+ sources = [ "tools/qt/simulator/font/SourceHanSansSC-Regular.otf" ]
+ outputs = [ "$root_out_dir/data/SourceHanSansSC-Regular.otf" ]
+ }
+}
+
+shared_library("ui") {
+ sources = [
+ "frameworks/animator/animator.cpp",
+ "frameworks/animator/easing_equation.cpp",
+ "frameworks/animator/interpolation.cpp",
+ "frameworks/common/graphic_startup.cpp",
+ "frameworks/common/image.cpp",
+ "frameworks/common/input_device_manager.cpp",
+ "frameworks/common/screen.cpp",
+ "frameworks/common/screen_device_proxy.cpp",
+ "frameworks/common/task.cpp",
+ "frameworks/common/text.cpp",
+ "frameworks/common/typed_text.cpp",
+ "frameworks/common/ui_font_header.cpp",
+ "frameworks/components/root_view.cpp",
+ "frameworks/components/text_adapter.cpp",
+ "frameworks/components/ui_abstract_clock.cpp",
+ "frameworks/components/ui_abstract_progress.cpp",
+ "frameworks/components/ui_abstract_scroll.cpp",
+ "frameworks/components/ui_analog_clock.cpp",
+ "frameworks/components/ui_arc_label.cpp",
+ "frameworks/components/ui_axis.cpp",
+ "frameworks/components/ui_box_progress.cpp",
+ "frameworks/components/ui_button.cpp",
+ "frameworks/components/ui_canvas.cpp",
+ "frameworks/components/ui_chart.cpp",
+ "frameworks/components/ui_checkbox.cpp",
+ "frameworks/components/ui_circle_progress.cpp",
+ "frameworks/components/ui_dialog.cpp",
+ "frameworks/components/ui_digital_clock.cpp",
+ "frameworks/components/ui_image_animator.cpp",
+ "frameworks/components/ui_image_view.cpp",
+ "frameworks/components/ui_label.cpp",
+ "frameworks/components/ui_label_button.cpp",
+ "frameworks/components/ui_list.cpp",
+ "frameworks/components/ui_picker.cpp",
+ "frameworks/components/ui_qrcode.cpp",
+ "frameworks/components/ui_radio_button.cpp",
+ "frameworks/components/ui_repeat_button.cpp",
+ "frameworks/components/ui_scroll_view.cpp",
+ "frameworks/components/ui_slider.cpp",
+ "frameworks/components/ui_surface_view.cpp",
+ "frameworks/components/ui_swipe_view.cpp",
+ "frameworks/components/ui_texture_mapper.cpp",
+ "frameworks/components/ui_time_picker.cpp",
+ "frameworks/components/ui_toggle_button.cpp",
+ "frameworks/components/ui_video.cpp",
+ "frameworks/components/ui_view.cpp",
+ "frameworks/components/ui_view_group.cpp",
+ "frameworks/core/render_manager.cpp",
+ "frameworks/core/task_manager.cpp",
+ "frameworks/default_resource/check_box_res.cpp",
+ "frameworks/dfx/event_injector.cpp",
+ "frameworks/dfx/key_event_injector.cpp",
+ "frameworks/dfx/point_event_injector.cpp",
+ "frameworks/dfx/ui_dump_dom_tree.cpp",
+ "frameworks/dfx/ui_screenshot.cpp",
+ "frameworks/dock/input_device.cpp",
+ "frameworks/dock/key_input_device.cpp",
+ "frameworks/dock/ohos/ohos_input_device.cpp",
+ "frameworks/dock/pointer_input_device.cpp",
+ "frameworks/dock/rotate_input_device.cpp",
+ "frameworks/dock/virtual_input_device.cpp",
+ "frameworks/draw/draw_arc.cpp",
+ "frameworks/draw/draw_curve.cpp",
+ "frameworks/draw/draw_image.cpp",
+ "frameworks/draw/draw_label.cpp",
+ "frameworks/draw/draw_line.cpp",
+ "frameworks/draw/draw_rect.cpp",
+ "frameworks/draw/draw_triangle.cpp",
+ "frameworks/draw/draw_utils.cpp",
+ "frameworks/events/event.cpp",
+ "frameworks/font/base_font.cpp",
+ "frameworks/font/glyphs_manager.cpp",
+ "frameworks/font/ui_font.cpp",
+ "frameworks/font/ui_font_adaptor.cpp",
+ "frameworks/font/ui_font_allocator.cpp",
+ "frameworks/font/ui_font_cache.cpp",
+ "frameworks/font/ui_font_vector.cpp",
+ "frameworks/font/ui_line_break.cpp",
+ "frameworks/font/ui_multi_font_manager.cpp",
+ "frameworks/font/ui_text_shaping.cpp",
+ "frameworks/imgdecode/cache_manager.cpp",
+ "frameworks/imgdecode/file_img_decoder.cpp",
+ "frameworks/imgdecode/image_load.cpp",
+ "frameworks/layout/flex_layout.cpp",
+ "frameworks/layout/grid_layout.cpp",
+ "frameworks/layout/list_layout.cpp",
+ "frameworks/themes/theme.cpp",
+ "frameworks/themes/theme_manager.cpp",
+ "frameworks/window/window.cpp",
+ "frameworks/window/window_impl.cpp",
+ ]
+ include_dirs = [ "//foundation/graphic/ui/frameworks" ]
+ deps = [
+ "//build/lite/config/component/cJSON:cjson_shared",
+ "//foundation/graphic/surface:lite_surface",
+ "//foundation/graphic/utils:lite_graphic_hals",
+ "//foundation/graphic/wms:lite_wms",
+ "//foundation/multimedia/media_lite/frameworks/player_lite:player_lite",
+ "//third_party/bounds_checking_function:libsec_shared",
+ "//third_party/freetype:freetype",
+ "//third_party/giflib:libgif",
+ "//third_party/libjpeg:libjpeg",
+ "//third_party/libpng:libpng",
+ "//third_party/qrcodegen:qrcodegen",
+ ]
+
+ public_deps = [ "//foundation/graphic/utils:lite_graphic_utils" ]
+ public_configs = [ ":graphic_define_config" ]
+ cflags = [
+ "-Wall",
+ "-fno-exceptions",
+ ]
+ cflags_cc = cflags
+ ldflags = [ "-Wl,-rpath-link=$ohos_root_path/$root_out_dir" ]
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4947287
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/README.en.md b/README.en.md
deleted file mode 100644
index 25d0af2..0000000
--- a/README.en.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# graphic_ui
-
-#### Description
-{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
-
-#### Software Architecture
-Software architecture description
-
-#### Installation
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Instructions
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Contribution
-
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
-
-
-#### Gitee Feature
-
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/README.md b/README.md
index 9aad453..e75dce0 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,124 @@
-# graphic_ui
+# UI
-#### 介绍
-{**以下是 Gitee 平台说明,您可以替换此简介**
-Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
-无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
+- [Introduction](#section11660541593)
+- [Directory Structure](#section161941989596)
+- [Constraints](#section119744591305)
+- [Compilation and Building](#section137768191623)
+- [Description](#section1312121216216)
+ - [Component Description](#section66002422015)
+ - [Usage](#section129654513264)
-#### 软件架构
-软件架构说明
+- [Repositories Involved](#section1371113476307)
+
+## Introduction
+
+The graphics UI module implements a system-level graphics engine.
+
+This module provides the UIKit APIs for application development. You can use the APIs to add animations, manage layouts, transform images, process events, and operates on rich UI components.
+
+The graphics UI directly calls the HAL API or uses the client provided by the Window Manager Service \(WMS\) to interact with the hardware to complete operations such as event response and image drawing.
+
+**Figure 1** Graphics subsystem architecture
+
+
+## Directory Structure
+
+```
+/foundation/graphic/ui
+├── frameworks # Framework code
+│ ├── animator # Animator module
+│ ├── common # Common module
+│ ├── components # Components
+│ ├── core # UI main processes (such as rendering and task management)
+│ ├── default_resource
+│ ├── dfx # Maintenance and test
+│ ├── dock # Driver adaptation layer
+│ │ └── ohos # OHOS platform adaptation
+│ ├── draw # Drawing logic
+│ ├── engines # Drawing engines
+│ │ ├── dfb
+│ │ ├── general
+│ │ ├── gpu_vglite
+│ │ └── software_zlite
+│ ├── events # Events
+│ ├── font # Fonts
+│ ├── imgdecode # Image management
+│ ├── layout # Page layout
+│ ├── themes # Theme management
+│ ├── window # Window management adaptation layer
+│ └── window_manager
+│ └── dfb
+├── interfaces # APIs
+│ ├── innerkits # APIs between modules
+│ │ └── xxx # Sub-module APIs
+│ └── kits # Externel APIs
+│ │ └── xxx # Sub-module APIs
+├── test # Test code
+│ ├── framework
+│ │ ├── include # Header files for the test framework
+│ │ └── src # Source code for the test framework
+│ ├── uitest # Display effect test (The executable program is in foundation/graphic/wms/test:sample_ui.)
+│ │ └── test_xxx # Specific UI effect test
+│ └── unittest # Unit testing
+│ └── xxx # Unit testing for a specific UI component
+└── tools # Test and simulation tools (simulator projects and resource files)
+ └── qt # Qt project
+```
+
+## Constraints
+
+Platform Constraints
+
+- The Windows platform supports only Qt and OHOS IDE.
+- For the support of other platforms, see the **graphic** tag in **vender/hisilicon/\[product\_name\]/config.json**. If the **graphic** tag does not exist, it indicates that the product does not have the graphics subsystem.
+
+## Compilation and Building
+
+```
+# Generate the libui.so file in the out directory of the product folder through GN compilation.
+hb build lite_ui
+
+# To compile the Qt library, see the Qt simulator project at graphic/ui/tools/qt/simulator/simulator.pro.
+```
+
+## Description
+
+### Component Description
+
+Components are classified into basic components and container components.
+
+- Basic components: Implement only a single function, such as **Text**, **Button**, **Image**, and **List**.
+- Container components: Hold and combine child components to implement complex functions.
+
+**Figure 2** Graphics subsystem components
+
+
+### Usage
+
+For details about how to use components and APIs of graphics, see the examples provided in **foundation/graphic/ui/test/uitest**.
+
+- The Qt project can be debugged in the Windows environment.
+
+ Project file path:
+
+ ```
+ graphic/ui/tools/qt/simulator/simulator.pro
+ ```
+
+- For other debugging environments, you can run **foundation/graphic/wms/test:sample\_ui**.
+
+ ```
+ hb build lite_wms -b debug
+ ```
+
+ After the building is successful, the executable program **out/\[product\_name\]/dev\_tools/bin/sample\_ui** is obtained. You can run the program in an environment to view the display effect of a specific component.
-#### 安装教程
+## Repositories Involved
-1. xxxx
-2. xxxx
-3. xxxx
+/hmf/graphic/surface
-#### 使用说明
+/hmf/graphic/wms
-1. xxxx
-2. xxxx
-3. xxxx
+/hmf/graphic/utils
-#### 参与贡献
-
-1. Fork 本仓库
-2. 新建 Feat_xxx 分支
-3. 提交代码
-4. 新建 Pull Request
-
-
-#### 特技
-
-1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
-2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
-3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
-4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
-5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
-6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/README_zh.md b/README_zh.md
new file mode 100644
index 0000000..621bf8a
--- /dev/null
+++ b/README_zh.md
@@ -0,0 +1,124 @@
+# 图形UI组件
+
+- [简介](#section11660541593)
+- [目录](#section161941989596)
+- [约束](#section119744591305)
+- [编译构建](#section137768191623)
+- [说明](#section1312121216216)
+ - [组件说明](#section66002422015)
+ - [使用说明](#section129654513264)
+
+- [相关仓](#section1371113476307)
+
+## 简介
+
+图形UI组件实现了一套系统级的图形引擎。
+
+该组件为应用开发提供UIKit接口,包括了动画、布局、图形转换、事件处理,以及丰富的UI组件。
+
+组件内部直接调用HAL接口,或者使用WMS\(Window Manager Service\)提供的客户端与硬件交互,以完成事件响应、图像绘制等操作。
+
+**图 1** 图形子系统架构图
+
+
+## 目录
+
+```
+/foundation/graphic/ui
+├── frameworks # 框架代码
+│ ├── animator # 动画模块
+│ ├── common # 公共模块
+│ ├── components # 组件
+│ ├── core # ui主流程(渲染、任务管理等)
+│ ├── default_resource
+│ ├── dfx # 维测功能
+│ ├── dock # 驱动适配层
+│ │ └── ohos # ohos平台适配
+│ ├── draw # 绘制逻辑
+│ ├── engines # 绘制引擎
+│ │ ├── dfb
+│ │ ├── general
+│ │ ├── gpu_vglite
+│ │ └── software_zlite
+│ ├── events # 事件
+│ ├── font # 字体
+│ ├── imgdecode # 图片管理
+│ ├── layout # 页面布局
+│ ├── themes # 主题管理
+│ ├── window # 窗口管理适配层
+│ └── window_manager
+│ └── dfb
+├── interfaces # 接口
+│ ├── innerkits # 模块间接口
+│ │ └── xxx # 子模块的接口
+│ └── kits # 对外接口
+│ └── xxx # 子模块的接口
+├── test # 测试代码
+│ ├── framework
+│ │ ├── include # 测试框架头文件
+│ │ └── src # 测试框架源码
+│ ├── uitest # 显示效果测试(可执行程序在foundation/graphic/wms/test:sample_ui)
+│ │ └── test_xxx # 具体UI组件效果测试
+│ └── unittest # 单元测试
+│ └── xxx # 具体UI组件单元测试
+└── tools # 测试和模拟器工具(模拟器工程、资源文件)
+ └── qt # QT工程
+```
+
+## 约束
+
+平台约束
+
+- Windows平台仅支持QT和OHOS IDE。
+- 其他平台支持情况参考vender/hisilicon/\[product\_name\]/config.json中的graphic标签(不存在graphic标签即该产品不存在图形子系统)。
+
+## 编译构建
+
+```
+# 通过gn编译,在out目录下对应产品的文件夹中生成libui.so
+hb build lite_ui
+
+# 编译qt库可直接参考qt模拟器工程:graphic/ui/tools/qt/simulator/simulator.pro
+```
+
+## 说明
+
+### 组件说明
+
+组件分为基础组件和容器组件
+
+- 基础组件:仅实现组件自身单一功能,比如按钮、文字、图片等;
+- 容器组件:可将其他组件作为自己的子组件,通过组合实现复杂功能。
+
+**图 2** 图形组件一览
+
+
+### 使用说明
+
+foundation/graphic/ui/test/uitest中提供了图形所有组件和功能接口的使用范例。
+
+- Windows环境可运行QT工程调试
+
+ 工程文件路径:
+
+ ```
+ graphic/ui/tools/qt/simulator/simulator.pro
+ ```
+
+- 其他调试环境可以编译运行foundation/graphic/wms/test:sample\_ui
+
+ ```
+ hb build lite_wms -b debug
+ ```
+
+ 编译成功后得到可执行程序out/\[product\_name\]/dev\_tools/bin/sample\_ui,在实际环境上运行即可观察对应组件显示效果。
+
+
+## 相关仓
+
+/hmf/graphic/surface
+
+/hmf/graphic/wms
+
+/hmf/graphic/utils
+
diff --git a/figures/graphics-subsystem-architecture.png b/figures/graphics-subsystem-architecture.png
new file mode 100644
index 0000000..b848d79
Binary files /dev/null and b/figures/graphics-subsystem-architecture.png differ
diff --git a/figures/graphics-subsystem-components.png b/figures/graphics-subsystem-components.png
new file mode 100644
index 0000000..123e1d9
Binary files /dev/null and b/figures/graphics-subsystem-components.png differ
diff --git a/figures/图形子系统架构图.png b/figures/图形子系统架构图.png
new file mode 100644
index 0000000..b848d79
Binary files /dev/null and b/figures/图形子系统架构图.png differ
diff --git a/figures/图形组件一览.png b/figures/图形组件一览.png
new file mode 100644
index 0000000..123e1d9
Binary files /dev/null and b/figures/图形组件一览.png differ
diff --git a/frameworks/animator/animator.cpp b/frameworks/animator/animator.cpp
new file mode 100755
index 0000000..0629cbe
--- /dev/null
+++ b/frameworks/animator/animator.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "animator/animator.h"
+
+#include "common/task_manager.h"
+#include "hal_tick.h"
+
+namespace OHOS {
+void Animator::Start()
+{
+ SetState(START);
+ runTime_ = 0;
+ lastRunTime_ = 0;
+}
+
+void Animator::Stop()
+{
+ SetState(STOP);
+ if (callback_ != nullptr) {
+ callback_->OnStop(*view_);
+ }
+}
+
+void Animator::Pause()
+{
+ SetState(PAUSE);
+}
+
+void Animator::Resume()
+{
+ SetState(START);
+ lastRunTime_ = HALTick::GetInstance().GetTime();
+}
+
+void Animator::Run()
+{
+ if (lastRunTime_ == 0) {
+ lastRunTime_ = HALTick::GetInstance().GetTime();
+ }
+
+ uint32_t elepse = HALTick::GetInstance().GetElapseTime(lastRunTime_);
+
+ runTime_ = (UINT32_MAX - elepse > runTime_) ? (runTime_ + elepse) : time_;
+ lastRunTime_ = HALTick::GetInstance().GetTime();
+ if (callback_ != nullptr) {
+ callback_->Callback(view_);
+ }
+}
+
+void AnimatorManager::Init()
+{
+ Task::Init();
+}
+
+void AnimatorManager::Add(Animator* animator)
+{
+ if (animator == nullptr) {
+ return;
+ }
+
+ list_.PushBack(animator);
+}
+
+void AnimatorManager::Remove(const Animator* animator)
+{
+ if (animator == nullptr) {
+ return;
+ }
+ ListNode* pos = list_.Begin();
+ while (pos != list_.End()) {
+ if (pos->data_ == animator) {
+ list_.Remove(pos);
+ return;
+ }
+ pos = pos->next_;
+ }
+}
+
+void AnimatorManager::AnimatorTask()
+{
+ ListNode* pos = list_.Begin();
+ Animator* animator = nullptr;
+
+ while (pos != list_.End()) {
+ animator = pos->data_;
+ if (animator->GetState() == Animator::START) {
+ if (animator->IsRepeat() || (animator->GetRunTime() <= animator->GetTime())) {
+ animator->Run();
+ } else {
+ animator->Stop();
+ }
+ }
+
+ pos = pos->next_;
+ }
+}
+}
diff --git a/frameworks/animator/easing_equation.cpp b/frameworks/animator/easing_equation.cpp
new file mode 100755
index 0000000..9d46fb0
--- /dev/null
+++ b/frameworks/animator/easing_equation.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "animator/easing_equation.h"
+#include "graphic_math.h"
+
+namespace OHOS {
+double EasingEquation::overshoot_ = 1.7; // The empirical value commonly used in easing equation
+
+void EasingEquation::SetBackOvershoot(double overshoot)
+{
+ if ((overshoot >= OVERSHOOT_MIN) && (overshoot <= OVERSHOOT_MAX)) {
+ overshoot_ = overshoot;
+ }
+}
+
+int16_t EasingEquation::BackEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ double t = -(static_cast(curTime) / durationTime);
+ double x = -t * t * ((overshoot_ + 1) * t + overshoot_);
+ return static_cast((x * (static_cast(endPos) - startPos)) + startPos);
+ }
+
+ return endPos;
+}
+
+int16_t EasingEquation::BackEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ double t = static_cast(curTime) / durationTime;
+ t -= 1.0;
+ double x = t * t * ((overshoot_ + 1) * t + overshoot_) + 1;
+ return static_cast((x * (static_cast(endPos) - startPos)) + startPos);
+ }
+
+ return endPos;
+}
+
+int16_t EasingEquation::BackEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ uint16_t halfTime = durationTime >> 1;
+ int16_t halfStep = (endPos >> 1) + (startPos >> 1);
+ if (curTime < halfTime) {
+ return BackEaseIn(startPos, halfStep, curTime, halfTime);
+ }
+ return BackEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
+}
+
+/* 1 - sqrt(1 - t^2) */
+int16_t EasingEquation::CircEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+ uint32_t x = INTERPOLATION_RANGE - Sqrt(INTERPOLATION_RANGE_SQUARE - t * t);
+ return static_cast(((x * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+/* sqrt(1 - (1 - t)^2) */
+int16_t EasingEquation::CircEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int32_t t = INTERPOLATION_RANGE - (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+ uint32_t x = static_cast(Sqrt(INTERPOLATION_RANGE_SQUARE - t * t));
+ return static_cast(((x * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+int16_t EasingEquation::CircEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ uint16_t halfTime = durationTime >> 1;
+ int16_t halfStep = (endPos >> 1) + (startPos >> 1);
+ if (curTime < halfTime) {
+ return CircEaseIn(startPos, halfStep, curTime, halfTime);
+ }
+ return CircEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
+}
+
+/* t^3 */
+int16_t EasingEquation::CubicEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+ int16_t x = (t * t * t) >> (INTERPOLATION_RANGE_OFFSET << 1);
+ return static_cast(((x * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+/* 1 - (1 - t)^3 */
+int16_t EasingEquation::CubicEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+ t = INTERPOLATION_RANGE - t;
+ int16_t x = INTERPOLATION_RANGE - ((t * t * t) >> (INTERPOLATION_RANGE_OFFSET << 1));
+ return static_cast(((x * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+int16_t EasingEquation::CubicEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ uint16_t halfTime = durationTime >> 1;
+ int16_t halfStep = (endPos >> 1) + (startPos >> 1);
+ if (curTime < halfTime) {
+ return CubicEaseIn(startPos, halfStep, curTime, halfTime);
+ }
+ return CubicEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
+}
+
+int16_t EasingEquation::LinearEaseNone(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+ return static_cast(((t * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+/* t^2 */
+int16_t EasingEquation::QuadEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+ int16_t x = (t * t) >> INTERPOLATION_RANGE_OFFSET;
+ return static_cast(((x * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+/* 1 - (1 - t)^2 */
+int16_t EasingEquation::QuadEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int32_t t = INTERPOLATION_RANGE - (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+ int16_t x = INTERPOLATION_RANGE - ((t * t) >> INTERPOLATION_RANGE_OFFSET);
+ return static_cast(((x * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+int16_t EasingEquation::QuadEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ uint16_t halfTime = durationTime >> 1;
+ int16_t halfStep = (endPos >> 1) + (startPos >> 1);
+ if (curTime < halfTime) {
+ return QuadEaseIn(startPos, halfStep, curTime, halfTime);
+ }
+ return QuadEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
+}
+
+/* t^5 */
+int16_t EasingEquation::QuintEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int64_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+
+ /* 4: the fourth power of t */
+ int16_t x = (t * t * t * t * t) >> (INTERPOLATION_RANGE_OFFSET * 4);
+ return static_cast(((x * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+/* 1 - (1 - t)^5 */
+int16_t EasingEquation::QuintEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int64_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
+ t = INTERPOLATION_RANGE - t;
+
+ /* 4: the fourth power of t */
+ int16_t x = INTERPOLATION_RANGE - ((t * t * t * t * t) >> (INTERPOLATION_RANGE_OFFSET * 4));
+ return static_cast(((x * (static_cast(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
+ startPos);
+ }
+
+ return endPos;
+}
+
+int16_t EasingEquation::QuintEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ uint16_t halfTime = durationTime >> 1;
+ int16_t halfStep = (endPos >> 1) + (startPos >> 1);
+ if (curTime < halfTime) {
+ return QuintEaseIn(startPos, halfStep, curTime, halfTime);
+ }
+ return QuintEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
+}
+
+int16_t EasingEquation::SineEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int16_t t = (curTime * QUARTER_IN_DEGREE) / durationTime - QUARTER_IN_DEGREE;
+ float x = Sin(t) + 1;
+ return static_cast(x * (endPos - startPos)) + startPos;
+ }
+
+ return endPos;
+}
+
+int16_t EasingEquation::SineEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ if (curTime < durationTime) {
+ int16_t t = (curTime * QUARTER_IN_DEGREE) / durationTime;
+ float x = Sin(t);
+ return static_cast(x * (endPos - startPos)) + startPos;
+ }
+
+ return endPos;
+}
+
+int16_t EasingEquation::SineEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
+{
+ uint16_t halfTime = durationTime >> 1;
+ int16_t halfStep = (endPos >> 1) + (startPos >> 1);
+ if (curTime < halfTime) {
+ return SineEaseIn(startPos, halfStep, curTime, halfTime);
+ }
+ return SineEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
+}
+}
\ No newline at end of file
diff --git a/frameworks/animator/interpolation.cpp b/frameworks/animator/interpolation.cpp
new file mode 100755
index 0000000..02c8471
--- /dev/null
+++ b/frameworks/animator/interpolation.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "animator/interpolation.h"
+
+namespace OHOS {
+/* B(t) = P0*(1-t)^3 + 3*P1*t*(1-t)^2 + 3*P2*t^2*(1-t) + P3*t^3 */
+int16_t Interpolation::GetBezierInterpolation(int16_t t, int16_t u0, int16_t u1, int16_t u2, int16_t u3)
+{
+ int64_t invT = INTERPOLATION_RANGE - t;
+ int64_t invT2 = invT * invT;
+ int64_t invT3 = invT2 * invT;
+ int64_t t2 = t * t;
+ int64_t t3 = t2 * t;
+
+ int64_t ret = invT3 * u0;
+ ret += BESSEL_COEFFICIENT * invT2 * t * u1;
+ ret += BESSEL_COEFFICIENT * invT * t2 * u2;
+ ret += t3 * u3;
+ ret = ret >> CUBIC_BEZIER_CALCULATE_OFFSET;
+ return static_cast(ret);
+}
+}
diff --git a/frameworks/common/graphic_startup.cpp b/frameworks/common/graphic_startup.cpp
new file mode 100644
index 0000000..5e42e99
--- /dev/null
+++ b/frameworks/common/graphic_startup.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/graphic_startup.h"
+#include "animator/animator.h"
+#include "common/input_device_manager.h"
+#include "common/task_manager.h"
+#include "core/render_manager.h"
+#include "dfx/performance_task.h"
+#include "file.h"
+#include "font/ui_font.h"
+#if ENABLE_SHAPING
+#include "font/ui_text_shaping.h"
+#endif
+#include "graphic_log.h"
+#include "imgdecode/cache_manager.h"
+#ifdef VERSION_STANDARD
+#include "dock/ohos/ohos_input_device.h"
+#endif
+#if ENABLE_WINDOW
+#include "iwindows_manager.h"
+#endif
+#if ENABLE_GFX_ENGINES
+#include "hals/gfx_engines.h"
+#endif
+
+namespace OHOS {
+void GraphicStartUp::InitFontEngine(uintptr_t psramAddr, uint32_t psramLen, const char* dPath, const char* ttfName)
+{
+#if ENABLE_VECTOR_FONT
+ UIFont* fontEngine = UIFont::GetInstance();
+ if (fontEngine == nullptr) {
+ GRAPHIC_LOGE("Get UIFont error");
+ return;
+ }
+ fontEngine->SetPsramMemory(psramAddr, psramLen);
+ // font and glyph path
+ int8_t ret = fontEngine->SetFontPath(const_cast(dPath), nullptr);
+ if (ret == INVALID_RET_VALUE) {
+ GRAPHIC_LOGW("SetFontPath failed");
+ }
+ if (ttfName != nullptr) {
+ uint8_t ret2 = fontEngine->RegisterFontInfo(ttfName);
+ if (ret2 == INVALID_UCHAR_ID) {
+ GRAPHIC_LOGW("SetTtfName failed");
+ }
+ }
+#endif
+}
+
+void GraphicStartUp::Init()
+{
+ TaskManager::GetInstance()->SetTaskRun(true);
+ DEBUG_PERFORMANCE_TASK_INIT();
+
+ if (INDEV_READ_PERIOD > 0) {
+ InputDeviceManager::GetInstance()->Init();
+ }
+ AnimatorManager::GetInstance()->Init();
+
+ StyleDefault::Init();
+ RenderManager::GetInstance().Init();
+
+ CacheManager::GetInstance().Init(IMG_CACHE_SIZE);
+#ifdef VERSION_STANDARD
+ OHOSInputDevice* input = new OHOSInputDevice();
+ if (input == nullptr) {
+ GRAPHIC_LOGE("new OHOSInputDevice fail");
+ return;
+ }
+ InputDeviceManager::GetInstance()->Add(input);
+#endif
+
+#if ENABLE_WINDOW
+ IWindowsManager::GetInstance()->Init();
+#endif
+#if ENABLE_GFX_ENGINES
+ GfxEngines::GetInstance()->InitDriver();
+#endif
+}
+} // namespace OHOS
diff --git a/frameworks/common/image.cpp b/frameworks/common/image.cpp
new file mode 100755
index 0000000..e58af8c
--- /dev/null
+++ b/frameworks/common/image.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/image.h"
+#include "common/image_decode_ability.h"
+#include "draw/draw_image.h"
+#include "file.h"
+#include "graphic_log.h"
+#include "imgdecode/cache_manager.h"
+#if ENABLE_JPEG_AND_PNG
+#include "jpeglib.h"
+#include "png.h"
+#endif
+#include "securec.h"
+
+namespace OHOS {
+Image::Image() : imageInfo_(nullptr), path_(nullptr), srcType_(IMG_SRC_UNKNOWN), mallocFlag_(false) {}
+
+Image::~Image()
+{
+ if (srcType_ == IMG_SRC_FILE) {
+ CacheManager::GetInstance().Close(path_);
+ }
+ if (imageInfo_ != nullptr) {
+ if (mallocFlag_) {
+ if (imageInfo_->data != nullptr) {
+ UIFree(reinterpret_cast(const_cast(imageInfo_->data)));
+ }
+ mallocFlag_ = false;
+ }
+ UIFree(reinterpret_cast(const_cast(imageInfo_)));
+ imageInfo_ = nullptr;
+ }
+ if (path_ != nullptr) {
+ UIFree(reinterpret_cast(const_cast(path_)));
+ path_ = nullptr;
+ }
+ srcType_ = IMG_SRC_UNKNOWN;
+}
+
+void Image::GetHeader(ImageHeader& header) const
+{
+ if ((srcType_ == IMG_SRC_VARIABLE) && (imageInfo_ != nullptr)) {
+ header = imageInfo_->header;
+ } else if ((srcType_ == IMG_SRC_FILE) && (path_ != nullptr)) {
+ CacheManager::GetInstance().GetImageHeader(path_, header);
+ }
+}
+
+#if ENABLE_JPEG_AND_PNG
+Image::ImageType Image::CheckImgType(const char* src)
+{
+ char buf[IMG_BYTES_TO_CHECK] = {0};
+#ifdef _WIN32
+ int32_t fd = open(src, O_RDONLY | O_BINARY);
+#else
+ int32_t fd = open(src, O_RDONLY);
+#endif
+ if (fd < 0) {
+ GRAPHIC_LOGE("can't open %s\n", src);
+ return IMG_UNKNOWN;
+ }
+ if (read(fd, buf, IMG_BYTES_TO_CHECK) != IMG_BYTES_TO_CHECK) {
+ close(fd);
+ return IMG_UNKNOWN;
+ }
+ close(fd);
+ if (!png_sig_cmp(reinterpret_cast(buf), 0, IMG_BYTES_TO_CHECK)) {
+ return IMG_PNG;
+ // 0xFF 0xD8: JPEG file's header
+ } else if ((static_cast(buf[0]) == 0xFF) && (static_cast(buf[1]) == 0xD8)) {
+ return IMG_JPEG;
+ }
+ return IMG_UNKNOWN;
+}
+#endif
+
+bool Image::SetStandardSrc(const char* src)
+{
+ if (src == nullptr) {
+ return false;
+ }
+ const char* ptr = strrchr(src, '.');
+ if (ptr == nullptr) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+
+#if ENABLE_JPEG_AND_PNG
+ ImageType imageType = CheckImgType(src);
+ if (imageType == IMG_PNG) {
+ return SetPNGSrc(src);
+ } else if (imageType == IMG_JPEG) {
+ return SetJPEGSrc(src);
+ }
+#endif
+
+ size_t strLen = strlen(src) + 1;
+ char* imagePath = static_cast(UIMalloc(static_cast(strLen)));
+ if (imagePath == nullptr) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+
+ if (strcpy_s(imagePath, strLen, src) != EOK) {
+ UIFree(reinterpret_cast(imagePath));
+ imagePath = nullptr;
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ path_ = imagePath;
+ srcType_ = IMG_SRC_FILE;
+ return true;
+}
+
+bool Image::SetLiteSrc(const char* src)
+{
+ if (src == nullptr) {
+ return false;
+ }
+ const char* ptr = strrchr(src, '.');
+ if (ptr == nullptr) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+
+ size_t strLen = strlen(src) + 1;
+ char* imagePath = static_cast(UIMalloc(static_cast(strLen)));
+ if (imagePath == nullptr) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ if (IsImgValid(ptr)) {
+ const char* suffixName = "bin";
+ if (memcpy_s(imagePath, strLen, src, strLen) != EOK) {
+ UIFree(reinterpret_cast(imagePath));
+ imagePath = nullptr;
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ (ptr - src + imagePath)[1] = '\0'; // remove suffix
+ if (strcat_s(imagePath, strLen, suffixName) != EOK) {
+ UIFree(reinterpret_cast(imagePath));
+ imagePath = nullptr;
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ } else {
+ if (memcpy_s(imagePath, strLen, src, strLen) != EOK) {
+ UIFree(reinterpret_cast(imagePath));
+ imagePath = nullptr;
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ }
+ path_ = imagePath;
+ srcType_ = IMG_SRC_FILE;
+ return true;
+}
+
+bool Image::SetSrc(const char* src)
+{
+ if (path_ != nullptr) {
+ UIFree(reinterpret_cast(const_cast(path_)));
+ path_ = nullptr;
+ }
+
+ if (src != nullptr) {
+ uint32_t imageType = ImageDecodeAbility::GetInstance().GetImageDecodeAbility();
+ if (((imageType & IMG_SUPPORT_JPEG) == IMG_SUPPORT_JPEG) ||
+ ((imageType & IMG_SUPPORT_PNG) == IMG_SUPPORT_PNG)) {
+ return SetStandardSrc(src);
+ }
+ return SetLiteSrc(src);
+ } else {
+ path_ = src;
+ srcType_ = IMG_SRC_UNKNOWN;
+ }
+ return true;
+}
+
+bool Image::SetSrc(const ImageInfo* src)
+{
+ if (imageInfo_ != nullptr) {
+ if (mallocFlag_) {
+ if (imageInfo_->data != nullptr) {
+ UIFree(reinterpret_cast(const_cast(imageInfo_->data)));
+ }
+ mallocFlag_ = false;
+ }
+ UIFree(reinterpret_cast(const_cast(imageInfo_)));
+ imageInfo_ = nullptr;
+ }
+
+ if (src != nullptr) {
+ imageInfo_ = static_cast(UIMalloc(static_cast(sizeof(ImageInfo))));
+ if (imageInfo_ == nullptr) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+
+ if (memcpy_s(const_cast(imageInfo_), sizeof(ImageInfo), src, sizeof(ImageInfo)) != EOK) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+
+ srcType_ = IMG_SRC_VARIABLE;
+ } else {
+ imageInfo_ = src;
+ srcType_ = IMG_SRC_UNKNOWN;
+ }
+ return true;
+}
+
+void Image::DrawImage(const Rect& coords, const Rect& mask, const Style& style, uint8_t opaScale) const
+{
+ if (srcType_ == IMG_SRC_VARIABLE) {
+ DrawImage::DrawCommon(coords, mask, imageInfo_, style, opaScale);
+ } else if (srcType_ == IMG_SRC_FILE) {
+ DrawImage::DrawCommon(coords, mask, path_, style, opaScale);
+ } else {
+ GRAPHIC_LOGE("Image::DrawImage:: failed with error srctype!\n");
+ }
+}
+
+#if ENABLE_JPEG_AND_PNG
+bool Image::SetPNGSrc(const char* src)
+{
+ FILE* infile = nullptr;
+ png_bytep* rowPointer = nullptr;
+ png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+ if (png == nullptr) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ png_infop info = png_create_info_struct(png);
+ if (info == nullptr) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ png_destroy_read_struct(&png, &info, nullptr);
+ return false;
+ }
+ if ((infile = fopen(src, "rb")) == nullptr) {
+ GRAPHIC_LOGE("can't open %s\n", src);
+ srcType_ = IMG_SRC_UNKNOWN;
+ png_destroy_read_struct(&png, &info, nullptr);
+ return false;
+ }
+ png_init_io(png, infile);
+ png_read_info(png, info);
+
+ uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(ARGB8888) >> 3; // 3: Shift right 3 bits
+ uint16_t width = png_get_image_width(png, info);
+ uint16_t height = png_get_image_height(png, info);
+ uint8_t colorType = png_get_color_type(png, info);
+ uint8_t bitDepth = png_get_bit_depth(png, info);
+ uint32_t dataSize = height * width * pixelByteSize;
+
+ if ((colorType == PNG_COLOR_TYPE_GRAY) && (bitDepth < 8)) { // 8: Expand grayscale images to the full 8 bits
+ png_set_expand_gray_1_2_4_to_8(png);
+ }
+ if ((colorType == PNG_COLOR_TYPE_GRAY) || (colorType == PNG_COLOR_TYPE_GRAY_ALPHA)) {
+ png_set_gray_to_rgb(png);
+ }
+ if (colorType == PNG_COLOR_TYPE_PALETTE) {
+ png_set_palette_to_rgb(png);
+ }
+ if (bitDepth == 16) { // 16: Chop 16-bit depth images to 8-bit depth
+ png_set_strip_16(png);
+ }
+ if (png_get_valid(png, info, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(png);
+ }
+ if (!(colorType & PNG_COLOR_MASK_ALPHA)) {
+ png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER);
+ }
+ png_set_interlace_handling(png);
+ png_read_update_info(png, info);
+
+ rowPointer = static_cast(UIMalloc(sizeof(png_bytep) * height));
+ if (rowPointer == nullptr) {
+ srcType_ = IMG_SRC_UNKNOWN;
+ fclose(infile);
+ png_destroy_read_struct(&png, &info, nullptr);
+ return false;
+ }
+ for (uint16_t y = 0; y < height; y++) {
+ rowPointer[y] = static_cast(UIMalloc(png_get_rowbytes(png, info)));
+ if (rowPointer[y] == nullptr) {
+ for (uint16_t i = 0; i < y; i++) {
+ UIFree(rowPointer[i]);
+ rowPointer[i] = nullptr;
+ }
+ fclose(infile);
+ UIFree(rowPointer);
+ srcType_ = IMG_SRC_UNKNOWN;
+ png_destroy_read_struct(&png, &info, nullptr);
+ return false;
+ }
+ }
+ png_read_image(png, rowPointer);
+ fclose(infile);
+ png_destroy_read_struct(&png, &info, nullptr);
+ ImageInfo* imgInfo = static_cast(UIMalloc(sizeof(ImageInfo)));
+ if (imgInfo == nullptr) {
+ for (uint16_t i = 0; i < height; i++) {
+ UIFree(rowPointer[i]);
+ rowPointer[i] = nullptr;
+ }
+ UIFree(rowPointer);
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ uint8_t* srcData = static_cast(UIMalloc(dataSize));
+ if (srcData == nullptr) {
+ for (uint16_t i = 0; i < height; i++) {
+ UIFree(rowPointer[i]);
+ rowPointer[i] = nullptr;
+ }
+ UIFree(rowPointer);
+ UIFree(imgInfo);
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ uint32_t n = 0;
+ for (uint16_t y = 0; y < height; y++) {
+ png_bytep row = rowPointer[y];
+ for (uint16_t x = 0; x < width * pixelByteSize; x += pixelByteSize) {
+ srcData[n++] = row[x + 2]; // 2: B channel
+ srcData[n++] = row[x + 1]; // 1: G channel
+ srcData[n++] = row[x + 0]; // 0: R channel
+ srcData[n++] = row[x + 3]; // 3: Alpha channel
+ }
+ UIFree(row);
+ row = nullptr;
+ }
+ UIFree(rowPointer);
+
+ imgInfo->header.width = width;
+ imgInfo->header.height = height;
+ imgInfo->header.colorMode = ARGB8888;
+ imgInfo->dataSize = dataSize;
+ imgInfo->data = srcData;
+
+ if (imageInfo_ != nullptr) {
+ if (mallocFlag_) {
+ if (imageInfo_->data != nullptr) {
+ UIFree(reinterpret_cast(const_cast(imageInfo_->data)));
+ }
+ mallocFlag_ = false;
+ }
+ UIFree(reinterpret_cast(const_cast(imageInfo_)));
+ imageInfo_ = nullptr;
+ }
+ imageInfo_ = imgInfo;
+ mallocFlag_ = true;
+ srcType_ = IMG_SRC_VARIABLE;
+ return true;
+}
+
+bool Image::SetJPEGSrc(const char* src)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ FILE* infile = nullptr;
+
+ if ((infile = fopen(src, "rb")) == nullptr) {
+ GRAPHIC_LOGE("can't open %s\n", src);
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+ jpeg_stdio_src(&cinfo, infile);
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(ARGB8888) >> 3; // 3: Shift right 3 bits
+ uint16_t width = cinfo.output_width;
+ uint16_t height = cinfo.output_height;
+ uint32_t dataSize = width * height * pixelByteSize;
+ uint16_t rowStride = cinfo.output_width * pixelByteSize;
+ JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)(reinterpret_cast(&cinfo), JPOOL_IMAGE, rowStride,
+ 1); // 1: one-row-high array
+ ImageInfo* imgInfo = static_cast(UIMalloc(sizeof(ImageInfo)));
+ if (imgInfo == nullptr) {
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ uint8_t* srcData = static_cast(UIMalloc(dataSize));
+ if (srcData == nullptr) {
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+ UIFree(imgInfo);
+ srcType_ = IMG_SRC_UNKNOWN;
+ return false;
+ }
+ uint32_t n = 0;
+ while (cinfo.output_scanline < cinfo.output_height) {
+ jpeg_read_scanlines(&cinfo, buffer, 1); // 1: read one line each time
+ for (uint16_t x = 0; x < width * 3; x += 3) { // 3: color components per pixel
+ srcData[n++] = buffer[0][x + 2]; // 2: B channel
+ srcData[n++] = buffer[0][x + 1]; // 1: G channel
+ srcData[n++] = buffer[0][x + 0]; // 0: R channel
+ srcData[n++] = 255; // 255: set alpha channel
+ }
+ }
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+
+ imgInfo->header.width = width;
+ imgInfo->header.height = height;
+ imgInfo->header.colorMode = ARGB8888;
+ imgInfo->dataSize = dataSize;
+ imgInfo->data = srcData;
+
+ if (imageInfo_ != nullptr) {
+ if (mallocFlag_) {
+ if (imageInfo_->data != nullptr) {
+ UIFree(reinterpret_cast(const_cast(imageInfo_->data)));
+ }
+ mallocFlag_ = false;
+ }
+ UIFree(reinterpret_cast(const_cast(imageInfo_)));
+ imageInfo_ = nullptr;
+ }
+ imageInfo_ = imgInfo;
+ mallocFlag_ = true;
+ srcType_ = IMG_SRC_VARIABLE;
+ return true;
+}
+#endif
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/common/input_device_manager.cpp b/frameworks/common/input_device_manager.cpp
new file mode 100755
index 0000000..23923b0
--- /dev/null
+++ b/frameworks/common/input_device_manager.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/input_device_manager.h"
+#include "common/task_manager.h"
+#include "graphic_log.h"
+
+namespace OHOS {
+void InputDeviceManager::Init()
+{
+ if (INDEV_READ_PERIOD > 0) {
+ SetPeriod(INDEV_READ_PERIOD);
+ TaskManager::GetInstance()->Add(this);
+ }
+}
+
+void InputDeviceManager::Add(InputDevice* device)
+{
+ if (device == nullptr) {
+ GRAPHIC_LOGE("InputDeviceManager::Add invalid param\n");
+ return;
+ }
+ deviceList_.PushBack(device);
+}
+
+void InputDeviceManager::Remove(InputDevice* device)
+{
+ if (device == nullptr) {
+ return;
+ }
+ ListNode* node = deviceList_.Begin();
+ while (node != deviceList_.End()) {
+ if (node->data_ == device) {
+ deviceList_.Remove(node);
+ return;
+ }
+ node = node->next_;
+ }
+}
+
+void InputDeviceManager::Callback()
+{
+ ListNode* node = deviceList_.Begin();
+ while (node != deviceList_.End()) {
+ node->data_->ProcessEvent();
+ node = node->next_;
+ }
+}
+
+void InputDeviceManager::Clear()
+{
+ deviceList_.Clear();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/common/screen.cpp b/frameworks/common/screen.cpp
new file mode 100755
index 0000000..0e51e1f
--- /dev/null
+++ b/frameworks/common/screen.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/screen.h"
+#include "dock/screen_device_proxy.h"
+
+namespace OHOS {
+uint16_t Screen::GetWidth()
+{
+ return ScreenDeviceProxy::GetInstance()->GetScreenWidth();
+}
+
+uint16_t Screen::GetHeight()
+{
+ return ScreenDeviceProxy::GetInstance()->GetScreenHeight();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/common/screen_device_proxy.cpp b/frameworks/common/screen_device_proxy.cpp
new file mode 100644
index 0000000..b8d94bd
--- /dev/null
+++ b/frameworks/common/screen_device_proxy.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dock/screen_device_proxy.h"
+#include "draw/draw_utils.h"
+#include "graphic_log.h"
+#include "securec.h"
+
+namespace OHOS {
+#if ENABLE_FRAME_BUFFER
+void ScreenDeviceProxy::Flush() {}
+#else
+void ScreenDeviceProxy::Flush()
+{
+ flush_.Flushing();
+
+ if (device_ != nullptr) {
+#if ENABLE_WINDOW
+ device_->Flush(bufferRect_.GetLeft(), bufferRect_.GetTop(), bufferRect_.GetRight(), bufferRect_.GetBottom(),
+ gfxAlloc_.virAddr, ARGB8888);
+#else
+ device_->Flush(bufferRect_.GetLeft(), bufferRect_.GetTop(), bufferRect_.GetRight(), bufferRect_.GetBottom(),
+ buffer_, ARGB8888);
+#endif
+ }
+}
+#endif
+
+void ScreenDeviceProxy::OnFlushReady()
+{
+ flush_.Notify();
+}
+
+void ScreenDeviceProxy::OnRenderFinish()
+{
+ if (device_ != nullptr) {
+ device_->RenderFinish();
+ }
+}
+
+void ScreenDeviceProxy::DrawAnimatorBuffer(const Rect& invalidatedArea)
+{
+ Rect invalidRect = curViewRect_;
+ transMap_.SetTransMapRect(curViewRect_);
+ invalidRect.Join(invalidRect, transMap_.GetBoxRect());
+
+ if (invalidRect.Intersect(invalidRect, invalidatedArea)) {
+ uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(animatorImageInfo_.header.colorMode);
+ TransformDataInfo imageTranDataInfo = {animatorImageInfo_.header, animatorImageInfo_.data, pxSize, LEVEL0,
+ BILINEAR};
+ DrawUtils::GetInstance()->DrawTransform(invalidRect, {0, 0}, Color::Black(), OPA_OPAQUE, transMap_,
+ imageTranDataInfo);
+ }
+}
+
+void ScreenDeviceProxy::SetAnimatorRect(const Rect& rect)
+{
+ curViewRect_ = rect;
+ uint16_t bufferWidth = (width_ > curViewRect_.GetWidth()) ? curViewRect_.GetWidth() : width_;
+ uint16_t bufferHeight = (height_ > curViewRect_.GetHeight()) ? curViewRect_.GetHeight() : height_;
+
+ animatorImageInfo_.header.colorMode = animatorBufferMode_;
+ animatorImageInfo_.dataSize = bufferWidth * bufferHeight * DrawUtils::GetByteSizeByColorMode(animatorBufferMode_);
+ animatorImageInfo_.header.width = bufferWidth;
+ animatorImageInfo_.header.height = bufferHeight;
+ animatorImageInfo_.header.reserved = 0;
+ animatorImageInfo_.data = reinterpret_cast(GetBuffer());
+ if (animatorImageInfo_.data == nullptr) {
+ return;
+ }
+
+ SetAnimatorbufferWidth(bufferWidth);
+ if (memset_s(reinterpret_cast(const_cast(animatorImageInfo_.data)), animatorImageInfo_.dataSize, 0,
+ animatorImageInfo_.dataSize) != EOK) {
+ GRAPHIC_LOGE("animator buffer memset failed.");
+ }
+}
+
+void ScreenDeviceProxy::SetScreenSize(uint16_t width, uint16_t height)
+{
+ if ((width == 0) || (height == 0)) {
+ GRAPHIC_LOGE("screen size can not be zero.");
+ return;
+ }
+ width_ = width;
+ height_ = height;
+#if !ENABLE_WINDOW && !ENABLE_FRAME_BUFFER
+ if (buffer_ != nullptr) {
+ UIFree(buffer_);
+ }
+ uint32_t bufSize = width * height * DrawUtils::GetByteSizeByColorMode(ARGB8888);
+ buffer_ = static_cast(UIMalloc(bufSize));
+ if (buffer_ == nullptr) {
+ GRAPHIC_LOGE("screen buffer malloc failed.");
+ return;
+ }
+ if (memset_s(buffer_, bufSize, 0, bufSize) != EOK) {
+ GRAPHIC_LOGE("screen buffer memset failed.");
+ UIFree(reinterpret_cast(buffer_));
+ buffer_ = nullptr;
+ }
+#endif
+}
+
+uint8_t* ScreenDeviceProxy::GetBuffer()
+{
+ flush_.Wait();
+ if (useAnimatorBuff_) {
+ if (animatorBufferAddr_ == nullptr) {
+ GRAPHIC_LOGE("Invalid param animatorBufferAddr_.");
+ return nullptr;
+ }
+ int32_t offset = bufferRect_.GetTop() * animatorBufferWidth_ + bufferRect_.GetLeft();
+ offset *= DrawUtils::GetByteSizeByColorMode(animatorBufferMode_);
+ return animatorBufferAddr_ + offset;
+ }
+#if ENABLE_FRAME_BUFFER
+ if (frameBufferAddr_ == nullptr) {
+ GRAPHIC_LOGE("Invalid param frameBufferAddr_.");
+ return nullptr;
+ }
+ int32_t offset = bufferRect_.GetTop() * frameBufferWidth_ + bufferRect_.GetLeft();
+ offset *= DrawUtils::GetByteSizeByColorMode(frameBufferMode_);
+ return frameBufferAddr_ + offset;
+#elif ENABLE_WINDOW
+ return gfxAlloc_.virAddr;
+#else
+ return buffer_;
+#endif
+}
+
+ColorMode ScreenDeviceProxy::GetBufferMode()
+{
+ if (useAnimatorBuff_) {
+ return animatorBufferMode_;
+ }
+#if ENABLE_FRAME_BUFFER
+ return frameBufferMode_;
+#else
+ return ARGB8888;
+#endif
+}
+} // namespace OHOS
diff --git a/frameworks/common/task.cpp b/frameworks/common/task.cpp
new file mode 100755
index 0000000..a38827a
--- /dev/null
+++ b/frameworks/common/task.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "common/task.h"
+#include "common/task_manager.h"
+#include "hal_tick.h"
+
+namespace OHOS {
+void Task::TaskExecute()
+{
+ uint32_t elp = HALTick::GetInstance().GetElapseTime(lastRun_);
+ if (elp >= period_) {
+ lastRun_ = HALTick::GetInstance().GetTime();
+ Callback();
+ }
+}
+
+void Task::Init()
+{
+ SetPeriod(period_);
+ TaskManager::GetInstance()->Add(this);
+}
+}
diff --git a/frameworks/common/text.cpp b/frameworks/common/text.cpp
new file mode 100755
index 0000000..de1bb32
--- /dev/null
+++ b/frameworks/common/text.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/text.h"
+#include "common/typed_text.h"
+#include "draw/draw_label.h"
+#include "font/ui_font.h"
+#include "graphic_log.h"
+#include "securec.h"
+
+namespace OHOS {
+Text::TextLine Text::textLine_[MAX_LINE_COUNT] = {{0}};
+
+Text::Text()
+ : text_(nullptr),
+ fontId_(0),
+ fontSize_(0),
+ textSize_({0, 0}),
+ needRefresh_(false),
+ expandWidth_(false),
+ expandHeight_(false),
+ direct_(TEXT_DIRECT_LTR),
+ horizontalAlign_(TEXT_ALIGNMENT_LEFT),
+ verticalAlign_(TEXT_ALIGNMENT_TOP)
+{
+ SetFont(DEFAULT_VECTOR_FONT_FILENAME, DEFAULT_VECTOR_FONT_SIZE);
+}
+
+Text::~Text()
+{
+ if (text_ != nullptr) {
+ UIFree(text_);
+ text_ = nullptr;
+ }
+}
+
+void Text::SetText(const char* text)
+{
+ if (text == nullptr) {
+ return;
+ }
+ uint32_t textLen = static_cast(strlen(text));
+ if (textLen > MAX_TEXT_LENGTH) {
+ return;
+ }
+ if (text_ != nullptr) {
+ if (strcmp(text, text_) == 0) {
+ return;
+ }
+ UIFree(text_);
+ text_ = nullptr;
+ }
+ text_ = static_cast(UIMalloc(++textLen));
+ if (text_ == nullptr) {
+ return;
+ }
+ if (memcpy_s(text_, textLen, text, textLen) != EOK) {
+ UIFree(text_);
+ text_ = nullptr;
+ return;
+ }
+ needRefresh_ = true;
+}
+
+void Text::SetFont(const char* name, uint8_t size)
+{
+ if (name == nullptr) {
+ return;
+ }
+ if (UIFont::GetInstance()->IsVectorFont()) {
+ uint8_t fontId = UIFont::GetInstance()->GetFontId(name);
+ if ((fontId != GetTotalFontId()) && ((fontId_ != fontId) || (fontSize_ != size))) {
+ fontId_ = fontId;
+ fontSize_ = size;
+ needRefresh_ = true;
+ }
+ } else {
+ uint8_t fontId = UIFont::GetInstance()->GetFontId(name, size);
+ SetFontId(fontId);
+ }
+}
+
+void Text::SetFont(const char* name, uint8_t size, char*& destName, uint8_t& destSize)
+{
+ if (name == nullptr) {
+ return;
+ }
+ uint32_t nameLen = static_cast(strlen(name));
+ if (nameLen > MAX_TEXT_LENGTH) {
+ return;
+ }
+ if (destName != nullptr) {
+ if (strcmp(destName, name) == 0) {
+ destSize = size;
+ return;
+ }
+ UIFree(destName);
+ destName = nullptr;
+ }
+ if (nameLen != 0) {
+ /* one more to store '\0' */
+ destName = static_cast(UIMalloc(++nameLen));
+ if (destName == nullptr) {
+ return;
+ }
+ if (memcpy_s(destName, nameLen, name, nameLen) != EOK) {
+ UIFree(destName);
+ destName = nullptr;
+ return;
+ }
+ destSize = size;
+ }
+}
+
+void Text::SetFontId(uint8_t fontId)
+{
+ if ((fontId >= GetTotalFontId()) || (fontId_ == fontId)) {
+ GRAPHIC_LOGE("Text::SetFontId invalid fontId(%d)", fontId);
+ return;
+ }
+ UITextLanguageFontParam* fontParam = GetTextLangFontsTable(fontId);
+ if (fontParam == nullptr) {
+ return;
+ }
+ if (UIFont::GetInstance()->IsVectorFont()) {
+ uint8_t fontId = UIFont::GetInstance()->GetFontId(fontParam->ttfName);
+ if ((fontId != GetTotalFontId()) && ((fontId_ != fontId) || (fontSize_ != fontParam->size))) {
+ fontId_ = fontId;
+ fontSize_ = fontParam->size;
+ needRefresh_ = true;
+ }
+ } else {
+ fontId_ = fontId;
+ fontSize_ = fontParam->size;
+ needRefresh_ = true;
+ }
+}
+
+void Text::ReMeasureTextSize(const Rect& textRect, const Style& style)
+{
+ if (fontSize_ == 0) {
+ return;
+ }
+ UIFont::GetInstance()->SetCurrentFontId(fontId_, fontSize_);
+ int16_t maxWidth = (expandWidth_ ? COORD_MAX : textRect.GetWidth());
+ if (maxWidth > 0) {
+ textSize_ = TypedText::GetTextSize(text_, style.letterSpace_, style.lineSpace_, maxWidth);
+ FontHeader head;
+ if (UIFont::GetInstance()->GetCurrentFontHeader(head) != 0) {
+ return;
+ }
+ textSize_.y += fontSize_ - head.ascender;
+ }
+}
+
+void Text::OnDraw(const Rect& invalidatedArea,
+ const Rect& viewOrigRect,
+ const Rect& textRect,
+ int16_t offsetX,
+ const Style& style,
+ uint16_t ellipsisIndex,
+ OpacityType opaScale)
+{
+ if ((text_ == nullptr) || (strlen(text_) == 0) || (fontSize_ == 0)) {
+ return;
+ }
+ UIFont::GetInstance()->SetCurrentFontId(fontId_, fontSize_);
+ Rect mask = invalidatedArea;
+
+ if (mask.Intersect(mask, textRect)) {
+ Draw(mask, textRect, style, offsetX, ellipsisIndex, opaScale);
+ }
+}
+
+void Text::Draw(const Rect& mask,
+ const Rect& coords,
+ const Style& style,
+ int16_t offsetX,
+ uint16_t ellipsisIndex,
+ OpacityType opaScale)
+{
+ Point offset = {offsetX, 0};
+ int16_t lineMaxWidth = expandWidth_ ? textSize_.x : coords.GetWidth();
+ int16_t lineHeight = UIFont::GetInstance()->GetHeight() + style.lineSpace_;
+ uint16_t lineBegin = 0;
+ uint32_t maxLineBytes = 0;
+ uint16_t lineCount = GetLine(lineMaxWidth, style.letterSpace_, ellipsisIndex, maxLineBytes);
+ Point pos;
+ pos.y = TextPositionY(coords, (lineCount * lineHeight - style.lineSpace_));
+ OpacityType opa = DrawUtils::GetMixOpacity(opaScale, style.textOpa_);
+ for (int i = 0; i < lineCount; i++) {
+ if (pos.y > mask.GetBottom()) {
+ return;
+ }
+ int16_t nextLine = pos.y + lineHeight;
+ if (nextLine >= mask.GetTop()) {
+ pos.x = LineStartPos(coords, textLine_[i].linePixelWidth);
+ LabelLineInfo labelLine{pos,
+ offset,
+ mask,
+ lineHeight,
+ textLine_[i].lineBytes,
+ 0,
+ opa,
+ style,
+ &text_[lineBegin],
+ textLine_[i].lineBytes,
+ lineBegin,
+ fontId_,
+ fontSize_,
+ 0,
+ static_cast(direct_),
+ nullptr};
+ DrawLabel::DrawTextOneLine(labelLine);
+ if ((i == (lineCount - 1)) && (ellipsisIndex != TEXT_ELLIPSIS_END_INV)) {
+ labelLine.offset.x = 0;
+ labelLine.text = TEXT_ELLIPSIS;
+ labelLine.lineLength = TEXT_ELLIPSIS_DOT_NUM;
+ labelLine.length = TEXT_ELLIPSIS_DOT_NUM;
+ DrawLabel::DrawTextOneLine(labelLine);
+ }
+ }
+ lineBegin += textLine_[i].lineBytes;
+ pos.y = nextLine;
+ }
+}
+
+int16_t Text::TextPositionY(const Rect& textRect, int16_t textHeight)
+{
+ int16_t yOffset = 0;
+ if (!expandHeight_ && (verticalAlign_ != TEXT_ALIGNMENT_TOP) && (textRect.GetHeight() > textHeight)) {
+ if (verticalAlign_ == TEXT_ALIGNMENT_CENTER) {
+ yOffset = (textRect.GetHeight() - textHeight) >> 1;
+ } else if (verticalAlign_ == TEXT_ALIGNMENT_BOTTOM) {
+ yOffset = textRect.GetHeight() - textHeight;
+ }
+ }
+ return textRect.GetY() + yOffset;
+}
+
+int16_t Text::LineStartPos(const Rect& textRect, uint16_t lineWidth)
+{
+ int16_t xOffset = 0;
+ int16_t rectWidth = textRect.GetWidth();
+ if (horizontalAlign_ == TEXT_ALIGNMENT_CENTER) {
+ xOffset = (direct_ == TEXT_DIRECT_RTL) ? ((rectWidth + lineWidth + 1) >> 1) : ((rectWidth - lineWidth) >> 1);
+ } else if (horizontalAlign_ == TEXT_ALIGNMENT_RIGHT) {
+ xOffset = (direct_ == TEXT_DIRECT_RTL) ? rectWidth : (rectWidth - lineWidth);
+ } else {
+ xOffset = (direct_ == TEXT_DIRECT_RTL) ? lineWidth : 0;
+ }
+ return textRect.GetX() + xOffset;
+}
+
+uint16_t Text::GetLine(int16_t width, uint8_t letterSpace, uint16_t ellipsisIndex, uint32_t& maxLineBytes)
+{
+ if (text_ == nullptr) {
+ return 0;
+ }
+ uint16_t lineNum = 0;
+ uint32_t textLen = GetTextStrLen();
+ if ((ellipsisIndex != TEXT_ELLIPSIS_END_INV) && (ellipsisIndex < textLen)) {
+ textLen = ellipsisIndex;
+ }
+ uint32_t begin = 0;
+ while ((begin < textLen) && (text_[begin] != '\0') && (lineNum < MAX_LINE_COUNT)) {
+ begin += GetTextLine(begin, textLen, width, lineNum, letterSpace);
+ if (maxLineBytes < textLine_[lineNum].lineBytes) {
+ maxLineBytes = textLine_[lineNum].lineBytes;
+ }
+ lineNum++;
+ }
+ if ((lineNum != 0) && (ellipsisIndex != TEXT_ELLIPSIS_END_INV)) {
+ uint16_t ellipsisWidth = UIFont::GetInstance()->GetWidth('.', 0) + letterSpace;
+ textLine_[lineNum - 1].linePixelWidth += ellipsisWidth * TEXT_ELLIPSIS_DOT_NUM;
+ }
+ return lineNum;
+}
+
+uint32_t Text::GetTextStrLen()
+{
+ return strlen(text_);
+}
+
+uint32_t Text::GetTextLine(uint32_t begin, uint32_t textLen, int16_t width, uint16_t lineNum, uint8_t letterSpace)
+{
+ uint16_t nextLineBytes = TypedText::GetNextLine(&text_[begin], letterSpace, width);
+ if (nextLineBytes + begin > textLen) {
+ nextLineBytes = textLen - begin;
+ }
+ textLine_[lineNum].lineBytes = nextLineBytes;
+ textLine_[lineNum].linePixelWidth =
+ static_cast(TypedText::GetTextWidth(&text_[begin], nextLineBytes, letterSpace));
+ return nextLineBytes;
+}
+
+uint16_t Text::GetEllipsisIndex(const Rect& textRect, const Style& style)
+{
+ if ((textSize_.y <= textRect.GetHeight()) || (TypedText::GetUTF8CharacterSize(text_) <= TEXT_ELLIPSIS_DOT_NUM)) {
+ return TEXT_ELLIPSIS_END_INV;
+ }
+ UIFont* fontEngine = UIFont::GetInstance();
+ fontEngine->SetCurrentFontId(fontId_, fontSize_);
+ int16_t letterWidth = fontEngine->GetWidth('.', 0) + style.letterSpace_;
+ Point p;
+ p.x = textRect.GetWidth() - letterWidth * TEXT_ELLIPSIS_DOT_NUM;
+ p.y = textRect.GetHeight();
+ int16_t height = fontEngine->GetHeight() + style.lineSpace_;
+ if (height) {
+ p.y -= p.y % height;
+ }
+
+ p.y -= style.lineSpace_;
+ return GetLetterIndexByPosition(textRect, style, p);
+}
+
+uint16_t Text::GetLetterIndexByPosition(const Rect& textRect, const Style& style, const Point& pos)
+{
+ if (text_ == nullptr) {
+ return 0;
+ }
+ uint32_t lineStart = 0;
+ uint32_t nextLineStart = 0;
+
+ uint16_t lineHeight = UIFont::GetInstance()->GetHeight();
+ int16_t y = 0;
+ uint32_t textLen = static_cast(strlen(text_));
+ while ((lineStart < textLen) && (text_[lineStart] != '\0')) {
+ nextLineStart += TypedText::GetNextLine(&text_[lineStart], style.letterSpace_, textRect.GetWidth());
+ if (pos.y <= y + lineHeight) {
+ break;
+ }
+ y += lineHeight + style.lineSpace_;
+ lineStart = nextLineStart;
+ }
+ /* Calculate the x coordinate */
+ int16_t x = 0;
+ uint32_t i = lineStart;
+ uint32_t pre = i;
+ while (i < nextLineStart - 1) {
+ uint32_t letter = TypedText::GetUTF8Next(text_, i, i);
+ x += UIFont::GetInstance()->GetWidth(letter, 0);
+ if (pos.x < x) {
+ i = pre;
+ break;
+ }
+ x += style.letterSpace_;
+ pre = i;
+ }
+ if (i >= (GetTextStrLen() - TEXT_ELLIPSIS_DOT_NUM)) {
+ return TEXT_ELLIPSIS_END_INV;
+ } else {
+ return static_cast(i);
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/common/typed_text.cpp b/frameworks/common/typed_text.cpp
new file mode 100755
index 0000000..63e3780
--- /dev/null
+++ b/frameworks/common/typed_text.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/typed_text.h"
+#include "font/ui_font.h"
+#include "font/ui_font_adaptor.h"
+#include "graphic_log.h"
+#include "mem_api.h"
+#include "transform.h"
+
+namespace OHOS {
+#ifndef _FONT_TOOL
+Point TypedText::GetTextSize(const char* text, int16_t letterSpace, int16_t lineSpace, int16_t maxWidth)
+{
+ Point size{0, 0};
+
+ if (text == nullptr) {
+ GRAPHIC_LOGE("TypedText::GetTextSize invalid parameter");
+ return size;
+ }
+
+ uint32_t lineBegin = 0;
+ uint32_t newLineBegin = 0;
+ uint16_t letterHeight = UIFont::GetInstance()->GetHeight();
+
+ while (text[lineBegin] != '\0') {
+ int16_t lineWidth = maxWidth;
+ newLineBegin += UIFontAdaptor::GetNextLineAndWidth(&text[lineBegin], letterSpace, lineWidth);
+ if (newLineBegin == lineBegin) {
+ break;
+ }
+ size.y += letterHeight + lineSpace;
+ size.x = MATH_MAX(lineWidth, size.x);
+ lineBegin = newLineBegin;
+ }
+
+ if ((lineBegin != 0) && ((text[lineBegin - 1] == '\n') || (text[lineBegin - 1] == '\r'))) {
+ size.y += letterHeight + lineSpace;
+ }
+
+ if (size.y == 0) {
+ size.y = letterHeight;
+ } else {
+ size.y -= lineSpace;
+ }
+ return size;
+}
+
+Rect TypedText::GetArcTextRect(const char* text,
+ const Point& arcCenter,
+ int16_t letterSpace,
+ UIArcLabel::TextOrientation orientation,
+ const UIArcLabel::ArcTextInfo& arcTextInfo)
+{
+ if ((text == nullptr) || (arcTextInfo.lineStart == arcTextInfo.lineEnd) || (arcTextInfo.radius == 0)) {
+ GRAPHIC_LOGE("TypedText::GetArcTextRect invalid parameter\n");
+ return Rect();
+ }
+
+ uint16_t letterHeight = UIFont::GetInstance()->GetHeight();
+ bool xorFlag = (orientation == UIArcLabel::TextOrientation::INSIDE) ^ (arcTextInfo.direct == TEXT_DIRECT_LTR);
+ float posX = 0;
+ float posY = 0;
+ uint32_t i = arcTextInfo.lineStart;
+ float angle = arcTextInfo.startAngle;
+ Rect rect;
+ Rect rectLetter;
+ TransformMap transform;
+ while (i < arcTextInfo.lineEnd) {
+ uint32_t tmp = i;
+ uint32_t letter = GetUTF8Next(text, tmp, i);
+ if (letter == 0) {
+ continue;
+ }
+ if ((letter == '\r') || (letter == '\n')) {
+ break;
+ }
+ uint16_t letterWidth = UIFont::GetInstance()->GetWidth(letter, 0);
+ if (tmp == arcTextInfo.lineStart) {
+ angle += xorFlag ? GetAngleForArcLen(static_cast(letterWidth), letterHeight, arcTextInfo.radius,
+ arcTextInfo.direct, orientation)
+ : 0;
+ GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY);
+ rect.SetPosition(MATH_ROUND(posX), MATH_ROUND(posY));
+ }
+ rectLetter.SetPosition(MATH_ROUND(posX), MATH_ROUND(posY));
+ rectLetter.Resize(letterWidth, letterHeight);
+ transform.SetTransMapRect(rectLetter);
+
+ uint16_t arcLen = letterWidth + letterSpace;
+ if (arcLen == 0) {
+ continue;
+ }
+ float incrementAngle = GetAngleForArcLen(static_cast(arcLen), letterHeight, arcTextInfo.radius,
+ arcTextInfo.direct, orientation);
+ float rotateAngle =
+ (orientation == UIArcLabel::TextOrientation::INSIDE) ? angle : (angle - SEMICIRCLE_IN_DEGREE);
+ // 2: letterWidth's half
+ float fineTuningAngle = incrementAngle * (static_cast(letterWidth) / (2 * arcLen));
+ rotateAngle += (xorFlag ? -fineTuningAngle : fineTuningAngle);
+
+ transform.Rotate(MATH_ROUND(rotateAngle), Vector2(0, 0));
+ rect.Join(rect, transform.GetBoxRect());
+
+ angle += incrementAngle;
+ GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY);
+ }
+ return rect;
+}
+
+float TypedText::GetAngleForArcLen(float len,
+ uint16_t height,
+ uint16_t radius,
+ UITextLanguageDirect direct,
+ UIArcLabel::TextOrientation orientation)
+{
+ float realRadius =
+ static_cast((orientation == UIArcLabel::TextOrientation::OUTSIDE) ? (radius + height) : radius);
+ float angle = static_cast(len * SEMICIRCLE_IN_DEGREE) / (UI_PI * realRadius);
+ return (direct == TEXT_DIRECT_LTR) ? angle : -angle;
+}
+
+void TypedText::GetArcLetterPos(const Point& arcCenter, uint16_t radius, float angle, float& posX, float& posY)
+{
+ posX = arcCenter.x + (static_cast(radius) * Sin(MATH_ROUND(angle)));
+ posY = arcCenter.y - (static_cast(radius) * Sin(MATH_ROUND(angle + QUARTER_IN_DEGREE)));
+}
+
+uint32_t TypedText::GetNextLine(const char* text, int16_t letterSpace, int16_t maxWidth)
+{
+ uint32_t lastBreakPos = 0;
+ int16_t curW;
+ uint32_t index = 0;
+ uint32_t tmp = 0;
+ if (GetWrapPoint(text, index)) {
+ return index;
+ }
+ while (true) {
+ curW = TypedText::GetTextWidth(text, index, letterSpace);
+ if (curW > maxWidth) {
+ index = lastBreakPos;
+ if (lastBreakPos == 0) {
+ curW = 0;
+ uint32_t i = 0;
+ uint32_t letter;
+ uint16_t letterWidth;
+ while (text[i] != '\0') {
+ tmp = i;
+ letter = TypedText::GetUTF8Next(text, tmp, i);
+ letterWidth = UIFont::GetInstance()->GetWidth(letter, 0);
+ curW += letterWidth;
+ if (letterWidth > 0) {
+ curW += letterSpace;
+ }
+ if (curW > maxWidth) {
+ index = lastBreakPos;
+ return index;
+ }
+ lastBreakPos = i;
+ }
+ }
+ break;
+ }
+ if ((index > 0) && (index < strlen(text)) && ((text[index - 1] == '\r') || (text[index - 1] == '\n'))) {
+ break;
+ }
+ lastBreakPos = index;
+ if (text[index] == '\0') {
+ break;
+ }
+ if (GetWrapPoint(text + index, tmp)) {
+ return index + tmp;
+ }
+ index += tmp;
+ if (lastBreakPos == index) {
+ break;
+ }
+ }
+ return index;
+}
+
+bool TypedText::GetWrapPoint(const char* text, uint32_t& breakPoint)
+{
+ breakPoint = 0;
+ uint32_t j = 0;
+ uint32_t letter = 0;
+ if (text == nullptr) {
+ return true;
+ }
+
+ while (text[breakPoint] != '\0') {
+ letter = GetUTF8Next(text, breakPoint, j);
+ breakPoint = j;
+ if ((letter == ' ') || (letter == '.') || (letter == ',') || (letter == '!') || (letter == '=')
+ || (letter == '?')) {
+ return false;
+ }
+ if (letter == '\n') {
+ return true;
+ }
+ if ((letter == '\r') && (GetUTF8Next(text, breakPoint, j) == '\n')) {
+ breakPoint = j;
+ return true;
+ }
+ }
+ return false;
+}
+
+int16_t TypedText::GetTextWidth(const char* text, uint16_t length, int16_t letterSpace)
+{
+ if ((text == nullptr) || (length == 0) || (length > strlen(text))) {
+ GRAPHIC_LOGE("TypedText::GetTextWidth invalid parameter\n");
+ return 0;
+ }
+
+ uint32_t i = 0;
+ uint16_t width = 0;
+ uint32_t letter;
+
+ while (i < length) {
+ letter = GetUTF8Next(text, i, i);
+ if ((letter == 0) || (letter == '\n') || (letter == '\r')) {
+ continue;
+ }
+ uint16_t charWidth = UIFont::GetInstance()->GetWidth(letter, 0);
+ width += charWidth + letterSpace;
+ }
+ if (width > 0) {
+ width -= letterSpace;
+ }
+ return width;
+}
+#endif // _FONT_TOOL
+
+uint8_t TypedText::GetUTF8OneCharacterSize(const char* str)
+{
+ if ((str[0] & 0x80) == 0) {
+ return 1;
+ } else if ((str[0] & 0xE0) == 0xC0) {
+ return 2; // 2: 2 bytes
+ } else if ((str[0] & 0xF0) == 0xE0) {
+ return 3; // 3: 3 bytes
+ } else if ((str[0] & 0xF8) == 0xF0) {
+ return 4; // 4: 4 bytes
+ }
+ return 0;
+}
+
+uint32_t TypedText::GetUTF8Next(const char* text, uint32_t i, uint32_t& j)
+{
+ uint32_t unicode = 0;
+ if (text == nullptr) {
+ GRAPHIC_LOGE("text invalid parameter");
+ return 0;
+ }
+
+ j = i;
+ uint8_t lettetSize = GetUTF8OneCharacterSize(text + i);
+ switch (lettetSize) {
+ case 1:
+ unicode = text[j];
+ break;
+ case 2: // 2: letter size
+ unicode = static_cast(text[j] & 0x1F) << UTF8_TO_UNICODE_SHIFT1;
+ j++;
+ if ((text[j] & 0xC0) != 0x80) {
+ return 0;
+ }
+ unicode += (text[j] & 0x3F);
+ break;
+ case 3: // 3: letter size
+ unicode = static_cast(text[j] & 0x0F) << UTF8_TO_UNICODE_SHIFT2;
+ unicode += static_cast(text[++j] & 0x3F) << UTF8_TO_UNICODE_SHIFT1;
+ unicode += (text[++j] & 0x3F);
+ break;
+ case 4: // 4: letter size
+ unicode = static_cast(text[j] & 0x07) << UTF8_TO_UNICODE_SHIFT3;
+ unicode += static_cast(text[++j] & 0x3F) << UTF8_TO_UNICODE_SHIFT2;
+ unicode += static_cast(text[++j] & 0x3F) << UTF8_TO_UNICODE_SHIFT1;
+ unicode += text[++j] & 0x3F;
+ break;
+ default:
+ break;
+ }
+ j++;
+ return unicode;
+}
+
+uint32_t TypedText::GetByteIndexFromUTF8Id(const char* text, uint32_t utf8Id)
+{
+ if (text == nullptr) {
+ GRAPHIC_LOGE("TypedText::GetByteIndexFromUTF8Id text invalid parameter\n");
+ return 0;
+ }
+ uint32_t byteIndex = 0;
+ for (uint32_t i = 0; i < utf8Id; i++) {
+ byteIndex += GetUTF8OneCharacterSize(&text[byteIndex]);
+ }
+
+ return byteIndex;
+}
+
+uint32_t TypedText::GetUTF8CharacterSize(const char* text, uint32_t byteIndex)
+{
+ uint32_t i = 0;
+ uint32_t size = 0;
+
+ if (text == nullptr) {
+ GRAPHIC_LOGE("TypedText::GetUTF8CharacterSize text invalid parameter\n");
+ return 0;
+ }
+ while ((text[i] != '\0') && (i < byteIndex)) {
+ GetUTF8Next(text, i, i);
+ size++;
+ }
+
+ return size;
+}
+
+void TypedText::Utf8ToUtf16(const char* utf8Str, uint16_t* utf16Str, uint32_t len)
+{
+ if ((utf8Str == nullptr) || (utf16Str == nullptr)) {
+ GRAPHIC_LOGE("utf8Str or u16Str is null");
+ return;
+ }
+
+ uint32_t i = 0;
+ uint32_t cnt = 0;
+ while (utf8Str[i] != '\0') {
+ uint32_t unicode = GetUTF8Next(utf8Str, i, i);
+ if (cnt < len) {
+ if (unicode <= MAX_UINT16_LOW_SCOPE) {
+ utf16Str[cnt] = (unicode & MAX_UINT16_LOW_SCOPE);
+ } else if (unicode <= MAX_UINT16_HIGH_SCOPE) {
+ if (cnt + 1 < len) {
+ utf16Str[cnt] = static_cast(UTF16_LOW_PARAM + (unicode & UTF16_LOW_MASK)); // low
+ cnt++;
+ utf16Str[cnt] = static_cast(UTF16_HIGH_PARAM1 + (unicode >> UTF16_HIGH_SHIFT) -
+ UTF16_HIGH_PARAM2); // high
+ }
+ } else {
+ GRAPHIC_LOGE("Invalid unicode");
+ return;
+ }
+ cnt++;
+ }
+ }
+}
+
+uint32_t TypedText::GetUtf16Cnt(const char* utf8Str)
+{
+ if (utf8Str == nullptr) {
+ GRAPHIC_LOGE("text invalid parameter");
+ return 0;
+ }
+ uint32_t len = 0;
+ uint32_t i = 0;
+
+ while (utf8Str[i] != '\0') {
+ uint32_t unicode = GetUTF8Next(utf8Str, i, i);
+ if (unicode <= MAX_UINT16_LOW_SCOPE) {
+ len++;
+ } else if (unicode <= MAX_UINT16_HIGH_SCOPE) {
+ len += 2; // 2: low and high, two uint16_t numbers
+ } else {
+ GRAPHIC_LOGE("Invalid unicode");
+ return 0;
+ }
+ }
+ return len;
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/common/typed_text.h b/frameworks/common/typed_text.h
new file mode 100755
index 0000000..6dbba99
--- /dev/null
+++ b/frameworks/common/typed_text.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GRAPHIC_LITE_TYPE_TEXT_H
+#define GRAPHIC_LITE_TYPE_TEXT_H
+#include "common/text.h"
+#include "graphic_config.h"
+#ifndef _FONT_TOOL
+#include "components/ui_arc_label.h"
+#include "font/ui_font_header.h"
+#include "geometry2d.h"
+#endif
+
+namespace OHOS {
+#ifndef _FONT_TOOL
+class TypedText : public HeapBase {
+public:
+ static constexpr uint32_t MAX_UINT16_LOW_SCOPE = 0xFFFF;
+ static constexpr uint32_t MAX_UINT16_HIGH_SCOPE = 0xEFFFF;
+ static constexpr uint32_t UTF16_LOW_MASK = 0x03FF;
+ static constexpr uint32_t UTF16_LOW_PARAM = 56320;
+ static constexpr uint32_t UTF16_HIGH_PARAM1 = 55296;
+ static constexpr uint8_t UTF16_HIGH_PARAM2 = 64;
+ static constexpr uint8_t UTF16_HIGH_SHIFT = 10;
+ static constexpr uint8_t UTF8_TO_UNICODE_SHIFT1 = 6;
+ static constexpr uint8_t UTF8_TO_UNICODE_SHIFT2 = 12;
+ static constexpr uint8_t UTF8_TO_UNICODE_SHIFT3 = 18;
+
+ static Point GetTextSize(const char* text,
+ int16_t letterSpace,
+ int16_t lineSpace,
+ int16_t maxWidth);
+
+ static uint32_t GetNextLine(const char* text,
+ int16_t letterSpace,
+ int16_t maxWidth);
+
+ static int16_t GetTextWidth(const char* text,
+ uint16_t length,
+ int16_t letterSpace);
+
+ static Rect GetArcTextRect(const char* text,
+ const Point& arcCenter,
+ int16_t letterSpace,
+ UIArcLabel::TextOrientation orientation,
+ const UIArcLabel::ArcTextInfo& arcTextInfo);
+
+ static float GetAngleForArcLen(float len,
+ uint16_t height,
+ uint16_t radius,
+ UITextLanguageDirect direct,
+ UIArcLabel::TextOrientation orientation);
+
+ static void GetArcLetterPos(const Point& arcCenter, uint16_t radius, float angle, float& posX, float& posY);
+
+#else // _FONT_TOOL
+class TypedText {
+public:
+#endif // _FONT_TOOL
+ static uint32_t GetUTF8Next(const char* text, uint32_t i, uint32_t& j);
+ static uint8_t GetUTF8OneCharacterSize(const char* str);
+ static uint32_t GetByteIndexFromUTF8Id(const char* text, uint32_t utf8Id);
+ static uint32_t GetUTF8CharacterSize(const char* text, uint32_t byteIndex = UINT32_MAX);
+ static void Utf8ToUtf16(const char* utf8Str, uint16_t* utf16Str, uint32_t len);
+ static uint32_t GetUtf16Cnt(const char* utf8Str);
+
+private:
+ static bool GetWrapPoint(const char* text, uint32_t& breakPoint);
+};
+} // namespace OHOS
+#endif // GRAPHIC_LITE_TYPE_TEXT_H
diff --git a/frameworks/common/ui_font_header.cpp b/frameworks/common/ui_font_header.cpp
new file mode 100755
index 0000000..df03018
--- /dev/null
+++ b/frameworks/common/ui_font_header.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at.
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "font/ui_font.h"
+#include "font/ui_font_header.h"
+
+namespace OHOS {
+UITextLanguageFontParam* GetTextLangFontsTable(uint8_t langFontId)
+{
+ // Need to be implemented
+ return nullptr;
+}
+
+uint8_t GetTotalLangId()
+{
+ // Need to be implemented
+ return 0;
+}
+
+uint8_t GetBitmapFontIdMax()
+{
+ // Need to be implemented
+ return 0;
+}
+
+uint8_t GetTotalFontId()
+{
+ // Need to be implemented
+ return 0xFF;
+}
+
+uint16_t GetTotalTextId()
+{
+ // Need to be implemented
+ return 0;
+}
+
+LangTextParam* GetLangTextDefaultParamTable()
+{
+ // Need to be implemented
+ return nullptr;
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/root_view.cpp b/frameworks/components/root_view.cpp
new file mode 100755
index 0000000..90199a4
--- /dev/null
+++ b/frameworks/components/root_view.cpp
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/root_view.h"
+
+#include "common/screen.h"
+#include "core/render_manager.h"
+#include "dock/screen_device_proxy.h"
+#include "graphic_log.h"
+#if ENABLE_WINDOW
+#include "window/window_impl.h"
+#endif
+namespace OHOS {
+namespace {
+#if LOCAL_RENDER
+const constexpr uint8_t MAX_SPLIT_NUM = 32; // split at most 32 parts
+// view along with its parents and siblings are at most 128
+const constexpr uint8_t VIEW_STACK_DEPTH = COMPONENT_NESTING_DEPTH * 2;
+#else
+const constexpr uint8_t VIEW_STACK_DEPTH = COMPONENT_NESTING_DEPTH;
+#endif
+static Rect g_maskStack[COMPONENT_NESTING_DEPTH];
+static UIView* g_viewStack[VIEW_STACK_DEPTH];
+} // namespace
+RootView::RootView()
+{
+#if defined __linux__ || defined __LITEOS__ || defined __APPLE__
+ pthread_mutex_init(&lock_, nullptr);
+#endif
+}
+
+#if ENABLE_WINDOW
+Window* RootView::GetBoundWindow() const
+{
+ return boundWindow_;
+}
+#endif
+
+inline bool RootView::IntersectScreenRect(Rect& rect)
+{
+#if ENABLE_WINDOW
+ Rect screenRect = GetRect();
+#else
+ Rect screenRect(0, 0, Screen::GetInstance().GetWidth() - 1, Screen::GetInstance().GetHeight() - 1);
+#endif
+ return rect.Intersect(rect, screenRect);
+}
+
+#if LOCAL_RENDER
+static void DivideInvalidateRect(const Rect& originRect, Rect& leftoverRect, Vector& splitRects)
+{
+ Rect mask;
+ if (!mask.Intersect(originRect, leftoverRect)) {
+ splitRects.PushBack(leftoverRect);
+ return;
+ }
+
+ /*
+ * +---+---+---+
+ * | | A | | originRect :A+B
+ * | +---+ | leftoverRect :A->0
+ * | B | mask :A
+ * +-----------+
+ */
+ if (originRect.IsContains(leftoverRect)) {
+ return;
+ }
+
+ int16_t reserveCnt = MAX_SPLIT_NUM - splitRects.Size();
+ if (reserveCnt <= 0) {
+ splitRects.PushBack(leftoverRect);
+ return;
+ }
+
+ if (mask.GetWidth() == leftoverRect.GetWidth()) {
+ /*
+ * +---+
+ * | A | originRect :B+C
+ * +-----------+ leftoverRect :A+B->A
+ * | | B | | mask :B
+ * | +---+ |
+ * | C |
+ * +-----------+
+ */
+ if (mask.GetBottom() == leftoverRect.GetBottom()) {
+ leftoverRect.SetBottom(mask.GetTop() - 1);
+ } else if (mask.GetTop() == leftoverRect.GetTop()) {
+ leftoverRect.SetTop(mask.GetBottom() + 1);
+ } else {
+ splitRects.PushBack(leftoverRect);
+ splitRects.Back().SetBottom(mask.GetTop() - 1);
+ leftoverRect.SetTop(mask.GetBottom() + 1);
+ }
+ splitRects.PushBack(leftoverRect);
+ return;
+ }
+ if (mask.GetHeight() == leftoverRect.GetHeight()) {
+ /*
+ * +---------+ originRect :B+C
+ * +-------+ | leftoverRect :A+B->A
+ * | A | B | C | mask :B
+ * +-------+ |
+ * +---------+
+ */
+ if (mask.GetLeft() == leftoverRect.GetLeft()) {
+ leftoverRect.SetLeft(mask.GetRight() + 1);
+ } else if (mask.GetRight() == leftoverRect.GetRight()) {
+ leftoverRect.SetRight(mask.GetLeft() - 1);
+ } else {
+ splitRects.PushBack(leftoverRect);
+ splitRects.Back().SetRight(mask.GetLeft() - 1);
+ leftoverRect.SetLeft(mask.GetRight() + 1);
+ }
+ splitRects.PushBack(leftoverRect);
+ return;
+ }
+
+ Vector copyRect(splitRects);
+ if (mask.GetLeft() != leftoverRect.GetLeft()) {
+ /*
+ * |
+ * +-------+
+ * | +---+ mask :A
+ * | B | A | leftoverRect :A+B
+ * | +---+
+ * +-------+
+ * |
+ */
+ if (reserveCnt-- <= 0) {
+ splitRects.Swap(copyRect);
+ splitRects.PushBack(leftoverRect);
+ return;
+ }
+ splitRects.PushBack(leftoverRect);
+ splitRects.Back().SetRight(mask.GetLeft() - 1);
+ leftoverRect.SetLeft(mask.GetLeft());
+ }
+
+ if (mask.GetTop() != leftoverRect.GetTop()) {
+ /*
+ * +-------+
+ * | B | mask :A
+ * ---+---+--- leftoverRect :A+B
+ * | | A | |
+ * +-+---+-+
+ */
+ if (reserveCnt-- <= 0) {
+ splitRects.Swap(copyRect);
+ splitRects.PushBack(leftoverRect);
+ return;
+ }
+ splitRects.PushBack(leftoverRect);
+ splitRects.Back().SetBottom(mask.GetTop() - 1);
+ leftoverRect.SetTop(mask.GetTop());
+ }
+
+ if (mask.GetRight() != leftoverRect.GetRight()) {
+ /*
+ * |
+ * +-------+
+ * +---+ | mask :A
+ * | A | B | leftoverRect :A+B
+ * +---+ |
+ * +-------+
+ * |
+ */
+ if (reserveCnt-- <= 0) {
+ splitRects.Swap(copyRect);
+ splitRects.PushBack(leftoverRect);
+ return;
+ }
+ splitRects.PushBack(leftoverRect);
+ splitRects.Back().SetLeft(mask.GetRight() + 1);
+ leftoverRect.SetRight(mask.GetRight());
+ }
+
+ if (mask.GetBottom() != leftoverRect.GetBottom()) {
+ /*
+ * +-+---+-+
+ * | | A | | mask :A
+ * ---+---+--- leftoverRect :A+B
+ * | B |
+ * +-------+
+ */
+ if (reserveCnt-- <= 0) {
+ splitRects.Swap(copyRect);
+ splitRects.PushBack(leftoverRect);
+ return;
+ }
+ splitRects.PushBack(leftoverRect);
+ splitRects.Back().SetTop(mask.GetBottom() + 1);
+ leftoverRect.SetBottom(mask.GetBottom());
+ }
+ return;
+}
+
+static void AddRenderedRects(Rect& rect, List& renderedRects, ListNode* iter)
+{
+ /* Elements at front have larger area and more relevance */
+ for (; iter != renderedRects.End(); iter = iter->next_) {
+ Rect& curRect = iter->data_;
+ if (!curRect.IsIntersect(rect)) {
+ continue;
+ }
+
+ if (curRect.IsContains(rect)) {
+ return;
+ }
+
+ /* Merge two rects */
+ if (rect.IsContains(curRect)) {
+ } else if (((curRect.GetLeft() == rect.GetLeft()) && (curRect.GetRight() == rect.GetRight())) ||
+ ((curRect.GetTop() == rect.GetTop()) && (curRect.GetBottom() == rect.GetBottom()))) {
+ rect.Join(curRect, rect);
+ } else {
+ continue;
+ }
+ iter = renderedRects.Remove(iter)->prev_;
+ break;
+ }
+ if (iter == renderedRects.End()) { // No merge rises
+ if (renderedRects.Size() == 128) { // record 128 rendered rects at most
+ renderedRects.PopBack();
+ }
+ renderedRects.PushFront(rect);
+ } else { // merge rises, go over the rest nodes
+ AddRenderedRects(rect, renderedRects, iter);
+ }
+}
+
+void RootView::RemoveViewFromInvalidMap(UIView* view)
+{
+#if defined __linux__ || defined __LITEOS__ || defined __APPLE__
+ pthread_mutex_lock(&lock_);
+#endif
+
+ int16_t stackCount = 0;
+ do {
+ while (view != nullptr) {
+ /* delete node itself */
+ auto entry = invalidateMap_.find(view);
+ if (entry != invalidateMap_.end()) {
+ invalidateMap_.erase(entry);
+ }
+ /* delete node's children */
+ if (view->IsViewGroup() && stackCount < COMPONENT_NESTING_DEPTH) {
+ g_viewStack[stackCount++] = view;
+ view = static_cast(view)->GetChildrenHead();
+ continue;
+ }
+ /* only go to child's sibling */
+ view = view->GetNextSibling();
+ }
+ if (--stackCount >= 0) {
+ view = g_viewStack[stackCount]->GetNextSibling();
+ }
+ } while (stackCount >= 0);
+
+#if defined __linux__ || defined __LITEOS__ || defined __APPLE__
+ pthread_mutex_unlock(&lock_);
+#endif
+}
+
+void RootView::OptimizeInvalidView(UIView* curview, UIView* background, List& renderedRects)
+{
+ if (curview == nullptr) {
+ return;
+ }
+ auto mapEntry = invalidateMap_.find(curview);
+ if (mapEntry == invalidateMap_.end()) {
+ return;
+ }
+
+ Rect& invalidRect = mapEntry->second.Front();
+ /* Transparent views should draw from background */
+ if (((curview->GetStyleConst().bgOpa_ != OPA_OPAQUE) || (curview->GetOpaScale() != OPA_OPAQUE) ||
+ (!curview->IsTransInvalid())) &&
+ (curview != this)) {
+ AddInvalidateRect(invalidRect, background);
+ invalidateMap_.erase(mapEntry);
+ return;
+ }
+
+ /* Remove the rendered parts and split the origin rect into splitInvalidRects
+ * For performance reason, split numbers are strictly restrained.
+ */
+ Vector splitInvalidRects(MAX_SPLIT_NUM << 1);
+ Rect invalidRectCopy(invalidRect);
+ /* Using forward order because entries at the front are closer to the current view and have larger Size */
+ for (auto iter = renderedRects.Begin(); iter != renderedRects.End(); iter = iter->next_) {
+ for (int8_t i = 0; i < mapEntry->second.Size(); i++) {
+ DivideInvalidateRect(iter->data_, mapEntry->second[i], splitInvalidRects);
+ }
+ mapEntry->second.Swap(splitInvalidRects);
+ splitInvalidRects.Clear();
+ }
+
+ /* Add new opaque rects */
+ Rect preDrawRect(invalidRectCopy);
+ if (!curview->OnPreDraw(preDrawRect)) {
+ AddInvalidateRect(invalidRectCopy, background);
+ }
+ AddRenderedRects(preDrawRect, renderedRects, renderedRects.Begin());
+}
+
+void RootView::OptimizeInvalidMap()
+{
+ UIView* curview = this;
+ int16_t stackCount = 0;
+ int16_t opaStackCount = 0;
+ UIView* background[VIEW_STACK_DEPTH];
+ bool flags[VIEW_STACK_DEPTH]; // indicate whether stack go back from child
+ List renderedRects; // Record rendered areas to avoid rerendering
+
+ do {
+ /* push stack */
+ if (curview != nullptr) {
+ if (stackCount >= VIEW_STACK_DEPTH) {
+ return;
+ }
+ g_viewStack[stackCount] = curview;
+ flags[stackCount++] = false;
+ curview = curview->GetNextSibling();
+ continue;
+ }
+
+ curview = g_viewStack[--stackCount];
+ Rect rect(curview->GetRect());
+ if (!curview->IsVisible() || !IntersectScreenRect(rect)) {
+ curview = nullptr;
+ continue;
+ }
+ if (!flags[stackCount]) { // Back from sibling
+ if (curview->IsViewGroup()) {
+ /* Set background/topview */
+ if (((curview->GetStyleConst().bgOpa_ == OPA_OPAQUE) && (curview->GetOpaScale() == OPA_OPAQUE) &&
+ curview->IsTransInvalid()) ||
+ (curview == this)) {
+ background[opaStackCount] = curview;
+ } else {
+ background[opaStackCount] = background[opaStackCount - 1];
+ }
+ ++opaStackCount;
+ if (opaStackCount >= VIEW_STACK_DEPTH) {
+ return;
+ }
+ flags[stackCount++] = true;
+ curview = static_cast(curview)->GetChildrenHead();
+ continue;
+ }
+ } else { // Back from child
+ opaStackCount--;
+ }
+ OptimizeInvalidView(curview, background[opaStackCount - 1], renderedRects);
+ curview = nullptr;
+ } while (stackCount > 0);
+}
+
+void RootView::DrawInvalidMap(const Rect& buffRect)
+{
+ OptimizeInvalidMap();
+ Rect rect;
+ for (auto& viewEntry : invalidateMap_) {
+ Vector& viewRenderRect = viewEntry.second;
+ for (uint16_t i = 0; i < viewRenderRect.Size(); i++) {
+ rect.Intersect(viewRenderRect[i], buffRect);
+ DrawTop(viewEntry.first, rect);
+ }
+ }
+}
+#endif
+
+void RootView::AddInvalidateRect(Rect& rect, UIView* view)
+{
+ Rect commonRect(rect);
+ if (IntersectScreenRect(commonRect)) {
+#if LOCAL_RENDER
+ Vector& invalidRects = invalidateMap_[view];
+ if (invalidRects.IsEmpty()) {
+ invalidRects.PushBack(commonRect);
+ } else {
+ invalidRects[0].Join(invalidRects[0], commonRect);
+ }
+#else
+ invalidRect_.Join(invalidRect_, commonRect);
+ renderFlag_ = true;
+#endif
+ }
+}
+
+void RootView::AddInvalidateRectWithLock(Rect& rect, UIView* view)
+{
+#if defined __linux__ || defined __LITEOS__ || defined __APPLE__
+ pthread_mutex_lock(&lock_);
+#endif
+
+ AddInvalidateRect(rect, view);
+
+#if defined __linux__ || defined __LITEOS__ || defined __APPLE__
+ pthread_mutex_unlock(&lock_);
+#endif
+}
+
+void RootView::Measure()
+{
+#if LOCAL_RENDER
+ if (!invalidateMap_.empty()) {
+ MeasureView(childrenHead_);
+ }
+#else
+ if (renderFlag_) {
+ MeasureView(childrenHead_);
+ }
+#endif
+}
+
+void RootView::MeasureView(UIView* view)
+{
+ int16_t stackCount = 0;
+ UIView* curView = view;
+ while (stackCount >= 0) {
+ while (curView != nullptr) {
+ if (curView->IsVisible()) {
+ curView->ReMeasure();
+ if (curView->IsViewGroup() && stackCount < COMPONENT_NESTING_DEPTH) {
+ g_viewStack[stackCount++] = curView;
+ curView = static_cast(curView)->GetChildrenHead();
+ continue;
+ }
+ }
+ curView = curView->GetNextSibling();
+ }
+ if (--stackCount >= 0) {
+ curView = (g_viewStack[stackCount])->GetNextSibling();
+ }
+ }
+}
+
+void RootView::Render()
+{
+#if defined __linux__ || defined __LITEOS__ || defined __APPLE__
+ pthread_mutex_lock(&lock_);
+#endif
+
+#if LOCAL_RENDER
+ if (!invalidateMap_.empty()) {
+ RenderManager::RenderRect(GetRect(), this);
+ invalidateMap_.clear();
+#else
+ if (renderFlag_) {
+ RenderManager::RenderRect(invalidRect_, this);
+ invalidRect_ = {0, 0, 0, 0};
+ renderFlag_ = false;
+#endif
+
+#if ENABLE_WINDOW
+ if (boundWindow_) {
+ boundWindow_->Flush();
+ boundWindow_->Update();
+ }
+#endif
+ ScreenDeviceProxy::GetInstance()->OnRenderFinish();
+ }
+
+#if defined __linux__ || defined __LITEOS__ || defined __APPLE__
+ pthread_mutex_unlock(&lock_);
+#endif
+}
+
+void RootView::DrawTop(UIView* view, const Rect& rect)
+{
+ if (view == nullptr) {
+ return;
+ }
+
+ int16_t stackCount = 0;
+ UIView* par = view->GetParent();
+ if (par == nullptr) {
+ par = view;
+ }
+ UIView* curView = view;
+ UIView* transViewGroup = nullptr;
+ Rect curViewRect;
+ Rect mask = rect;
+ Rect OrigRect;
+ Rect RelativeRect;
+ while (par != nullptr) {
+ if (curView != nullptr) {
+ if (curView->IsVisible()) {
+ curViewRect = curView->GetMaskedRect();
+ if (curViewRect.Intersect(curViewRect, mask) || enableAnimator_) {
+ if ((curView->GetViewType() != UI_IMAGE_VIEW) && (curView->GetViewType() != UI_TEXTURE_MAPPER) &&
+ !curView->IsTransInvalid() && !enableAnimator_) {
+ OrigRect = curView->GetOrigRect();
+ RelativeRect = curView->GetRelativeRect();
+ curView->GetTransformMap().SetInvalid(true);
+ curView->SetPosition(RelativeRect.GetX() - OrigRect.GetX(),
+ RelativeRect.GetY() - OrigRect.GetY());
+ ScreenDeviceProxy::GetInstance()->EnableAnimatorBuffer(true);
+ ScreenDeviceProxy::GetInstance()->SetAnimatorRect(OrigRect);
+ ScreenDeviceProxy::GetInstance()->SetAnimatorTransMap(curView->GetTransformMap());
+ enableAnimator_ = true;
+ }
+ if (enableAnimator_) {
+ Rect invalidatedArea;
+ invalidatedArea.SetWidth(ScreenDeviceProxy::GetInstance()->GetScreenWidth());
+ invalidatedArea.SetHeight(ScreenDeviceProxy::GetInstance()->GetScreenHeight());
+ curView->OnDraw(invalidatedArea);
+ } else {
+ curView->OnDraw(curViewRect);
+ }
+
+ if ((curView->IsViewGroup()) && (stackCount < COMPONENT_NESTING_DEPTH)) {
+ if (enableAnimator_ && (transViewGroup == nullptr)) {
+ transViewGroup = curView;
+ }
+ par = curView;
+ g_viewStack[stackCount] = curView;
+ g_maskStack[stackCount] = mask;
+ stackCount++;
+ curView = static_cast(curView)->GetChildrenHead();
+ mask = par->GetContentRect();
+ mask.Intersect(mask, curViewRect);
+ continue;
+ }
+ curView->OnPostDraw(curViewRect);
+ if (enableAnimator_ && (transViewGroup == nullptr)) {
+ ScreenDeviceProxy::GetInstance()->EnableAnimatorBuffer(false);
+ ScreenDeviceProxy::GetInstance()->DrawAnimatorBuffer(mask);
+ curView->GetTransformMap().SetInvalid(false);
+ enableAnimator_ = false;
+ curView->SetPosition(RelativeRect.GetX(), RelativeRect.GetY());
+ }
+ }
+ }
+ curView = curView->GetNextSibling();
+ continue;
+ }
+ if (--stackCount >= 0) {
+ curViewRect = par->GetMaskedRect();
+ mask = g_maskStack[stackCount];
+ if (curViewRect.Intersect(curViewRect, g_maskStack[stackCount])) {
+ par->OnPostDraw(curViewRect);
+ }
+ if (enableAnimator_ && transViewGroup == g_viewStack[stackCount]) {
+ ScreenDeviceProxy::GetInstance()->EnableAnimatorBuffer(false);
+ ScreenDeviceProxy::GetInstance()->DrawAnimatorBuffer(mask);
+ transViewGroup->GetTransformMap().SetInvalid(false);
+ enableAnimator_ = false;
+ transViewGroup->SetPosition(RelativeRect.GetX(), RelativeRect.GetY());
+ transViewGroup = nullptr;
+ }
+ curView = g_viewStack[stackCount]->GetNextSibling();
+ par = par->GetParent();
+ continue;
+ }
+ stackCount = 0;
+ curView = par->GetNextSibling();
+ par = par->GetParent();
+ }
+}
+
+UIView* RootView::GetTopUIView(const Rect& rect)
+{
+ int16_t stackCount = 0;
+ UIView* currentView = this;
+ UIView* topView = currentView;
+ Rect copyRect(rect);
+ while (stackCount >= 0) {
+ while (currentView != nullptr) {
+ if (currentView->GetOrigRect().IsContains(rect) && currentView->IsVisible()) {
+ if (currentView->GetStyleConst().bgOpa_ == OPA_OPAQUE && currentView->OnPreDraw(copyRect) &&
+ currentView->GetOpaScale() == OPA_OPAQUE) {
+ topView = currentView;
+ }
+ if (currentView->IsViewGroup() && stackCount < COMPONENT_NESTING_DEPTH) {
+ g_viewStack[stackCount++] = currentView;
+ currentView = static_cast(currentView)->GetChildrenHead();
+ continue;
+ }
+ }
+ currentView = currentView->GetNextSibling();
+ }
+ if (--stackCount >= 0) {
+ currentView = (g_viewStack[stackCount])->GetNextSibling();
+ }
+ }
+ return topView;
+}
+
+bool RootView::FindSubView(const UIView& parentView, const UIView* subView)
+{
+ const UIView* root = &parentView;
+ if (root == subView) {
+ return true;
+ } else if (!root->IsViewGroup() || (subView == nullptr)) {
+ return false;
+ }
+
+ UIView* currentView = static_cast(root)->GetChildrenHead();
+ const UIView* parent = root;
+ int8_t deep = 1;
+ while (deep > 0) {
+ if (currentView == subView) {
+ return true;
+ }
+ if (currentView == nullptr) {
+ currentView = parent->GetNextSibling();
+ parent = parent->GetParent();
+ deep--;
+ } else if (currentView->IsViewGroup()) {
+ parent = currentView;
+ currentView = static_cast(currentView)->GetChildrenHead();
+ deep++;
+ } else {
+ currentView = currentView->GetNextSibling();
+ }
+ }
+ return false;
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/text_adapter.cpp b/frameworks/components/text_adapter.cpp
new file mode 100755
index 0000000..3df75ff
--- /dev/null
+++ b/frameworks/components/text_adapter.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/text_adapter.h"
+#include
+#include "securec.h"
+
+namespace OHOS {
+bool TextFormatter::Format(int16_t value, char* outText, uint16_t textLen)
+{
+ if (sprintf_s(outText, textLen, "%d", value) < 0) {
+ return false;
+ }
+ return true;
+}
+
+TextAdapter::TextAdapter()
+ : dataMode_(DYNAMIC_TEXT_MODE),
+ fontName_(nullptr),
+ fontSize_(0),
+ width_(0),
+ height_(0),
+ direct_(UITextLanguageDirect::TEXT_DIRECT_LTR),
+ lineBreakMode_(UILabel::LINE_BREAK_ADAPT),
+ integerTextStart_(0),
+ integerTextEnd_(0),
+ clickListener_(nullptr),
+ formatter_(nullptr)
+{
+ style_ = StyleDefault::GetBackgroundTransparentStyle();
+ fontId_ = style_.font_;
+}
+
+TextAdapter::~TextAdapter()
+{
+ ClearDynamicText();
+ if (fontName_ != nullptr) {
+ UIFree(fontName_);
+ fontName_ = nullptr;
+ }
+}
+
+void TextAdapter::SetFont(const char* name, uint8_t size)
+{
+ Text::SetFont(name, size, fontName_, fontSize_);
+}
+
+UIView* TextAdapter::GetView(UIView* inView, int16_t index)
+{
+ UILabel* newView = GetTextView(inView, index);
+ if (newView == nullptr) {
+ return nullptr;
+ }
+ newView->SetLineBreakMode(lineBreakMode_);
+ newView->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+ if (width_) {
+ newView->SetWidth(width_);
+ }
+ if (height_) {
+ newView->SetHeight(height_);
+ }
+ newView->SetViewIndex(index);
+ newView->UIView::SetStyle(style_);
+ newView->GetHeight();
+ if (clickListener_) {
+ newView->SetOnClickListener(clickListener_);
+ newView->SetTouchable(true);
+ }
+ return newView;
+}
+
+UILabel* TextAdapter::GetTextView(UIView* inView, int16_t index)
+{
+ switch (dataMode_) {
+ case DYNAMIC_TEXT_MODE:
+ return GetDynamicText(inView, index);
+ case CONTINUOUS_INTEGER_MODE:
+ return GetIntegerText(inView, index);
+ default:
+ return nullptr;
+ }
+}
+
+UILabel* TextAdapter::GetDynamicText(UIView* inView, int16_t index)
+{
+ if (dynamicText_.IsEmpty() || (index > dynamicText_.Size() - 1) || (index < 0)) {
+ return nullptr;
+ }
+
+ ListNode* node = dynamicText_.Begin();
+ for (int16_t i = 0; i < index; i++) {
+ node = node->next_;
+ }
+ UILabel* newView = nullptr;
+ if (inView == nullptr) {
+ newView = new UILabel();
+ } else {
+ newView = static_cast(inView);
+ }
+
+ if (newView != nullptr) {
+ newView->SetText(node->data_);
+ if (fontName_ == nullptr) {
+ newView->SetFontId(fontId_);
+ } else {
+ newView->SetFont(fontName_, fontSize_);
+ }
+ newView->SetDirect(direct_);
+ }
+ return newView;
+}
+
+UILabel* TextAdapter::GetIntegerText(UIView* inView, int16_t index)
+{
+ if ((index < 0) || ((integerTextEnd_ - integerTextStart_) < index)) {
+ return nullptr;
+ }
+ UILabel* newView = nullptr;
+ if (inView == nullptr) {
+ newView = new UILabel();
+ } else {
+ newView = static_cast(inView);
+ }
+
+ if (newView != nullptr) {
+ char buf[BUF_LEN] = {0};
+ if (formatter_ != nullptr) {
+ if (!formatter_->Format(integerTextStart_ + index, buf, BUF_LEN)) {
+ if (inView == nullptr) {
+ delete newView;
+ newView = nullptr;
+ }
+ return nullptr;
+ }
+ } else {
+ if (sprintf_s(buf, sizeof(buf), "%02d", integerTextStart_ + index) < 0) {
+ if (inView == nullptr) {
+ delete newView;
+ newView = nullptr;
+ }
+ return nullptr;
+ }
+ }
+
+ buf[BUF_LEN - 1] = '\0';
+ newView->SetText(buf);
+ if (fontName_ == nullptr) {
+ newView->SetFontId(fontId_);
+ } else {
+ newView->SetFont(fontName_, fontSize_);
+ }
+ newView->SetDirect(direct_);
+ }
+ return newView;
+}
+
+void TextAdapter::ClearDynamicText()
+{
+ ListNode* node = dynamicText_.Begin();
+ while (node != dynamicText_.End()) {
+ if (node->data_) {
+ UIFree(reinterpret_cast(const_cast(node->data_)));
+ node->data_ = nullptr;
+ }
+ node = node->next_;
+ }
+ dynamicText_.Clear();
+}
+
+void TextAdapter::SetData(List* data)
+{
+ if (data == nullptr) {
+ return;
+ }
+ if (!dynamicText_.IsEmpty()) {
+ ClearDynamicText();
+ }
+ ListNode* node = data->Begin();
+ while (node != data->End()) {
+ uint32_t len = strlen(node->data_);
+ char* stringData = static_cast(UIMalloc(len + 1));
+ if (stringData == nullptr) {
+ return;
+ }
+ if (memcpy_s(stringData, len + 1, node->data_, len) != EOK) {
+ UIFree(reinterpret_cast(stringData));
+ stringData = nullptr;
+ return;
+ }
+ stringData[len] = '\0';
+ dynamicText_.PushBack(stringData);
+ node = node->next_;
+ }
+ dataMode_ = DYNAMIC_TEXT_MODE;
+}
+
+void TextAdapter::SetData(int16_t start, int16_t end)
+{
+ if (start <= end) {
+ integerTextStart_ = start;
+ integerTextEnd_ = end;
+ dataMode_ = CONTINUOUS_INTEGER_MODE;
+ }
+}
+
+uint16_t TextAdapter::GetCount()
+{
+ switch (dataMode_) {
+ case DYNAMIC_TEXT_MODE:
+ return dynamicText_.Size();
+ case CONTINUOUS_INTEGER_MODE:
+ return (integerTextStart_ <= integerTextEnd_) ? (integerTextEnd_ - integerTextStart_ + 1) : 0;
+ default:
+ return 0;
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_abstract_clock.cpp b/frameworks/components/ui_abstract_clock.cpp
new file mode 100755
index 0000000..fa053da
--- /dev/null
+++ b/frameworks/components/ui_abstract_clock.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_abstract_clock.h"
+
+namespace OHOS {
+void UIAbstractClock::SetTime24Hour(uint8_t hour, uint8_t minute, uint8_t second)
+{
+ currentHour_ = hour % ONE_DAY_IN_HOUR;
+ currentMinute_ = minute % ONE_HOUR_IN_MINUTE;
+ currentSecond_ = second % ONE_MINUTE_IN_SECOND;
+ UpdateClock(false);
+}
+
+void UIAbstractClock::SetTime12Hour(uint8_t hour, uint8_t minute, uint8_t second, bool am)
+{
+ SetTime24Hour((hour % HALF_DAY_IN_HOUR) + (am ? 0 : HALF_DAY_IN_HOUR), minute, second);
+}
+
+void UIAbstractClock::IncOneSecond()
+{
+ currentSecond_++;
+ currentMinute_ += currentSecond_ / ONE_MINUTE_IN_SECOND;
+ currentSecond_ = currentSecond_ % ONE_MINUTE_IN_SECOND;
+
+ currentHour_ += currentMinute_ / ONE_HOUR_IN_MINUTE;
+ currentMinute_ = currentMinute_ % ONE_HOUR_IN_MINUTE;
+ currentHour_ = currentHour_ % ONE_DAY_IN_HOUR;
+
+ UpdateClock(false);
+}
+
+void UIAbstractClock::SetWorkMode(WorkMode newMode)
+{
+ if (mode_ != newMode) {
+ mode_ = newMode;
+ Invalidate();
+ }
+}
+
+void UIAbstractClock::UpdateClock(bool clockInit)
+{
+ Invalidate();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_abstract_progress.cpp b/frameworks/components/ui_abstract_progress.cpp
new file mode 100755
index 0000000..8f9e62c
--- /dev/null
+++ b/frameworks/components/ui_abstract_progress.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_abstract_progress.h"
+#include "common/image.h"
+#include "draw/draw_utils.h"
+#include "graphic_log.h"
+#include "imgdecode/cache_manager.h"
+#include "themes/theme_manager.h"
+
+namespace OHOS {
+UIAbstractProgress::UIAbstractProgress()
+ : enableBackground_(true),
+ backgroundStyleAllocFlag_(false),
+ foregroundStyleAllocFlag_(false),
+ backgroundImage_(nullptr),
+ foregroundImage_(nullptr),
+ rangeMax_(MAX_PERCENT_VALUE),
+ rangeMin_(MIN_PERCENT_VALUE),
+ curValue_(0),
+ step_(1),
+ lastValue_(0)
+{
+ style_ = &(StyleDefault::GetBackgroundTransparentStyle());
+ Theme* theme = ThemeManager::GetInstance().GetCurrent();
+ if (theme != nullptr) {
+ backgroundStyle_ = &(theme->GetProgressBackgroundStyle());
+ foregroundStyle_ = &(theme->GetProgressForegroundStyle());
+ } else {
+ backgroundStyle_ = &(StyleDefault::GetProgressBackgroundStyle());
+ foregroundStyle_ = &(StyleDefault::GetProgressForegroundStyle());
+ }
+}
+
+UIAbstractProgress::~UIAbstractProgress()
+{
+ if (backgroundImage_ != nullptr) {
+ delete backgroundImage_;
+ backgroundImage_ = nullptr;
+ }
+
+ if (foregroundImage_ != nullptr) {
+ delete foregroundImage_;
+ foregroundImage_ = nullptr;
+ }
+
+ if (backgroundStyleAllocFlag_) {
+ delete backgroundStyle_;
+ backgroundStyle_ = nullptr;
+ backgroundStyleAllocFlag_ = false;
+ }
+
+ if (foregroundStyleAllocFlag_) {
+ delete foregroundStyle_;
+ foregroundStyle_ = nullptr;
+ foregroundStyleAllocFlag_ = false;
+ }
+}
+
+void UIAbstractProgress::SetRange(int32_t rangeMax, int32_t rangeMin)
+{
+ if ((rangeMax_ == rangeMax) && (rangeMin_ == rangeMin)) {
+ return;
+ }
+
+ if (rangeMax >= rangeMin) {
+ rangeMax_ = rangeMax;
+ rangeMin_ = rangeMin;
+ lastValue_ = rangeMin;
+ SetValue(curValue_);
+ } else {
+ GRAPHIC_LOGW("UIAbstractProgress::SetRange rangeMax less than rangeMin !\n");
+ }
+};
+
+void UIAbstractProgress::SetValue(int32_t value)
+{
+ if (value < rangeMin_) {
+ curValue_ = rangeMin_;
+ } else if (value > rangeMax_) {
+ curValue_ = rangeMax_;
+ } else {
+ curValue_ = value;
+ }
+
+ if ((curValue_ != lastValue_) &&
+ ((curValue_ == rangeMin_) || (curValue_ == rangeMax_) ||
+ (MATH_ABS(curValue_ - lastValue_) >= static_cast(step_)))) {
+ Invalidate();
+ lastValue_ = curValue_;
+ }
+}
+
+int16_t UIAbstractProgress::GetCurrentPos(int16_t distance) const
+{
+ uint32_t delta = lastValue_ - rangeMin_;
+ uint32_t rangeSize = GetRangeSize();
+ if (rangeSize == 0) {
+ return distance;
+ }
+ int16_t result = static_cast(distance) * delta / rangeSize;
+ return result;
+}
+
+uint32_t UIAbstractProgress::GetRangeSize() const
+{
+ return (rangeMax_ < rangeMin_) ? 0 : (rangeMax_ - rangeMin_);
+}
+
+void UIAbstractProgress::SetImage(const char* foregroundImage, const char* backgroundImage)
+{
+ if (!InitImage()) {
+ return;
+ }
+ backgroundImage_->SetSrc(backgroundImage);
+ foregroundImage_->SetSrc(foregroundImage);
+}
+
+void UIAbstractProgress::SetImage(const ImageInfo* foregroundImage, const ImageInfo* backgroundImage)
+{
+ if (!InitImage()) {
+ return;
+ }
+ backgroundImage_->SetSrc(backgroundImage);
+ foregroundImage_->SetSrc(foregroundImage);
+}
+
+void UIAbstractProgress::SetBackgroundStyle(const Style& style)
+{
+ if (!backgroundStyleAllocFlag_) {
+ backgroundStyle_ = new Style();
+ if (backgroundStyle_ == nullptr) {
+ GRAPHIC_LOGE("new Style1 fail");
+ return;
+ }
+ backgroundStyleAllocFlag_ = true;
+ }
+ *backgroundStyle_ = style;
+}
+
+void UIAbstractProgress::SetBackgroundStyle(uint8_t key, int64_t value)
+{
+ if (!backgroundStyleAllocFlag_) {
+ backgroundStyle_ = new Style(*backgroundStyle_);
+ if (backgroundStyle_ == nullptr) {
+ GRAPHIC_LOGE("new Style1 fail");
+ return;
+ }
+ backgroundStyleAllocFlag_ = true;
+ }
+ backgroundStyle_->SetStyle(key, value);
+}
+
+const Style& UIAbstractProgress::GetBackgroundStyle() const
+{
+ return *backgroundStyle_;
+}
+
+int64_t UIAbstractProgress::GetBackgroundStyle(uint8_t key) const
+{
+ return backgroundStyle_->GetStyle(key);
+}
+
+void UIAbstractProgress::SetForegroundStyle(const Style& style)
+{
+ if (!foregroundStyleAllocFlag_) {
+ foregroundStyle_ = new Style();
+ if (foregroundStyle_ == nullptr) {
+ GRAPHIC_LOGE("new Style1 fail");
+ return;
+ }
+ foregroundStyleAllocFlag_ = true;
+ }
+ *foregroundStyle_ = style;
+}
+
+void UIAbstractProgress::SetForegroundStyle(uint8_t key, int64_t value)
+{
+ if (!foregroundStyleAllocFlag_) {
+ foregroundStyle_ = new Style(*foregroundStyle_);
+ if (foregroundStyle_ == nullptr) {
+ GRAPHIC_LOGE("new Style1 fail");
+ return;
+ }
+ foregroundStyleAllocFlag_ = true;
+ }
+ foregroundStyle_->SetStyle(key, value);
+}
+
+const Style& UIAbstractProgress::GetForegroundStyle() const
+{
+ return *foregroundStyle_;
+}
+
+int64_t UIAbstractProgress::GetForegroundStyle(uint8_t key) const
+{
+ return foregroundStyle_->GetStyle(key);
+}
+
+bool UIAbstractProgress::InitImage()
+{
+ if (backgroundImage_ == nullptr) {
+ backgroundImage_ = new Image();
+ if (backgroundImage_ == nullptr) {
+ GRAPHIC_LOGE("new Image fail");
+ return false;
+ }
+ }
+ if (foregroundImage_ == nullptr) {
+ foregroundImage_ = new Image();
+ if (foregroundImage_ == nullptr) {
+ GRAPHIC_LOGE("new Image fail");
+ return false;
+ }
+ }
+ return true;
+}
+} // namespace OHOS
diff --git a/frameworks/components/ui_abstract_scroll.cpp b/frameworks/components/ui_abstract_scroll.cpp
new file mode 100755
index 0000000..2c6d90a
--- /dev/null
+++ b/frameworks/components/ui_abstract_scroll.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_abstract_scroll.h"
+
+namespace OHOS {
+UIAbstractScroll::UIAbstractScroll()
+ : scrollBlankSize_(0),
+ reboundSize_(0),
+ maxScrollDistance_(0),
+ lastDeltaY_{0},
+ dragAccCoefficient_(DRAG_ACC_FACTOR),
+ swipeAccCoefficient_(0),
+ direction_(VERTICAL),
+ deltaYIndex_(0),
+ reserve_(0),
+ throwDrag_(false),
+ easingFunc_(EasingEquation::CubicEaseOut),
+ scrollAnimator_(&animatorCallback_, this, 0, true)
+{
+#if ENABLE_ROTATE_INPUT
+ rotateFactor_ = 1;
+ rotateThreshold_ = 1;
+#endif
+ isViewGroup_ = true;
+ touchable_ = true;
+ draggable_ = true;
+ dragParentInstead_ = false;
+ AnimatorManager::GetInstance()->Add(&scrollAnimator_);
+}
+
+UIAbstractScroll::~UIAbstractScroll()
+{
+ scrollAnimator_.Stop();
+ AnimatorManager::GetInstance()->Remove(&scrollAnimator_);
+}
+
+void UIAbstractScroll::MoveChildByOffset(int16_t offsetX, int16_t offsetY)
+{
+ if ((offsetX == 0) && (offsetY == 0)) {
+ return;
+ }
+ UIView* view = GetChildrenHead();
+ int16_t x;
+ int16_t y;
+ while (view != nullptr) {
+ x = view->GetX() + offsetX;
+ y = view->GetY() + offsetY;
+ view->SetPosition(x, y);
+ view = view->GetNextSibling();
+ }
+ Invalidate();
+}
+
+int16_t UIAbstractScroll::GetMaxDeltaY() const
+{
+ int16_t result = 0;
+ for (int16_t i = 0; i < MAX_DELTA_Y_SIZE; i++) {
+ if (result < MATH_ABS(lastDeltaY_[i])) {
+ result = MATH_ABS(lastDeltaY_[i]);
+ }
+ }
+ return result;
+}
+
+void UIAbstractScroll::StopAnimator()
+{
+ scrollAnimator_.Stop();
+ animatorCallback_.RsetCallback();
+ isDragging_ = false;
+}
+
+bool UIAbstractScroll::DragThrowAnimator(Point currentPos, Point lastPos)
+{
+ if (!throwDrag_ && (reboundSize_ == 0)) {
+ return false;
+ }
+ int16_t dragDistanceX = 0;
+ int16_t dragDistanceY = 0;
+ if (throwDrag_) {
+ CalculateDragDistance(currentPos, lastPos, dragDistanceX, dragDistanceY);
+ }
+ if (reboundSize_ != 0) {
+ CalculateReboundDistance(dragDistanceX, dragDistanceY);
+ }
+ StartAnimator(dragDistanceX, dragDistanceY);
+ return true;
+}
+
+void UIAbstractScroll::StartAnimator(int16_t dragDistanceX, int16_t dragDistanceY)
+{
+ int16_t dragTimes = MATH_MAX(MATH_ABS(dragDistanceX), MATH_ABS(dragDistanceY)) / DRAG_TIMES_COEFFICIENT;
+ if (dragTimes < MIN_DRAG_TIMES) {
+ dragTimes = MIN_DRAG_TIMES;
+ }
+ animatorCallback_.SetDragStartValue(0, 0);
+ animatorCallback_.SetDragEndValue(dragDistanceX, dragDistanceY);
+ animatorCallback_.SetDragTimes(dragTimes * DRAG_ACC_FACTOR / GetDragACCLevel());
+ scrollAnimator_.Start();
+}
+
+void UIAbstractScroll::CalculateDragDistance(Point currentPos,
+ Point lastPos,
+ int16_t& dragDistanceX,
+ int16_t& dragDistanceY)
+{
+ if ((direction_ == VERTICAL) || (direction_ == HORIZONTAL_AND_VERTICAL)) {
+ dragDistanceY = (currentPos.y - lastPos.y) * DRAG_DISTANCE_COEFFICIENT;
+ if (dragDistanceY > 0) {
+ dragDistanceY += GetMaxDeltaY() * GetSwipeACCLevel() / DRAG_ACC_FACTOR;
+ } else {
+ dragDistanceY -= GetMaxDeltaY() * GetSwipeACCLevel() / DRAG_ACC_FACTOR;
+ }
+ }
+
+ if ((direction_ == HORIZONTAL) || (direction_ == HORIZONTAL_AND_VERTICAL)) {
+ dragDistanceX = (currentPos.x - lastPos.x) * DRAG_DISTANCE_COEFFICIENT;
+ }
+
+ if (maxScrollDistance_ != 0) {
+ if (MATH_ABS(dragDistanceY) > maxScrollDistance_) {
+ int16_t calculatedValue = (dragDistanceY > 0) ? 1 : -1;
+ dragDistanceY = calculatedValue * maxScrollDistance_;
+ }
+ if (MATH_ABS(dragDistanceX) > maxScrollDistance_) {
+ int16_t calculatedValue = (dragDistanceX > 0) ? 1 : -1;
+ dragDistanceX = calculatedValue * maxScrollDistance_;
+ }
+ }
+}
+
+void UIAbstractScroll::ListAnimatorCallback::Callback(UIView* view)
+{
+ if (view == nullptr) {
+ return;
+ }
+ curtTime_++;
+
+ UIAbstractScroll* scrollView = static_cast(view);
+ scrollView->isDragging_ = true;
+
+ if (curtTime_ <= dragTimes_) {
+ bool needStopX = false;
+ bool needStopY = false;
+ if (startValueY_ != endValueY_) {
+ int16_t actY = scrollView->easingFunc_(startValueY_, endValueY_, curtTime_, dragTimes_);
+ if (!scrollView->DragYInner(actY - previousValueY_)) {
+ needStopY = true;
+ }
+ previousValueY_ = actY;
+ } else {
+ needStopY = true;
+ }
+ if (startValueX_ != endValueX_) {
+ int16_t actX = scrollView->easingFunc_(startValueX_, endValueX_, curtTime_, dragTimes_);
+ if (!scrollView->DragXInner(actX - previousValueX_)) {
+ needStopX = true;
+ }
+ previousValueX_ = actX;
+ } else {
+ needStopX = true;
+ }
+ if (needStopX && needStopY) {
+ scrollView->StopAnimator();
+ }
+ } else {
+ scrollView->StopAnimator();
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_analog_clock.cpp b/frameworks/components/ui_analog_clock.cpp
new file mode 100755
index 0000000..3780a87
--- /dev/null
+++ b/frameworks/components/ui_analog_clock.cpp
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_analog_clock.h"
+#include "components/ui_image_view.h"
+#include "draw/draw_image.h"
+#include "draw/draw_line.h"
+#include "draw/draw_rect.h"
+#include "graphic_log.h"
+#include "imgdecode/cache_manager.h"
+#include "style.h"
+#include "themes/theme.h"
+
+namespace OHOS {
+UIAnalogClock::UIAnalogClock()
+{
+ touchable_ = true;
+}
+
+void UIAnalogClock::SetHandImage(HandType type, const UIImageView& img, Point position, Point center)
+{
+ Hand *hand = nullptr;
+ if (type == HandType::HOUR_HAND) {
+ hand = &hourHand_;
+ } else if (type == HandType::MINUTE_HAND) {
+ hand = &minuteHand_;
+ } else {
+ hand = &secondHand_;
+ }
+
+ hand->center_ = center;
+ hand->position_ = position;
+ hand->initAngle_ = 0;
+ hand->preAngle_ = 0;
+ hand->nextAngle_ = 0;
+ hand->drawtype_ = DrawType::DRAW_IMAGE;
+
+ if (img.GetSrcType() == IMG_SRC_FILE) {
+ CacheEntry entry;
+ RetCode ret = CacheManager::GetInstance().Open(img.GetPath(), *style_, entry);
+ if (ret != RetCode::OK) {
+ return;
+ }
+ hand->imageInfo_ = entry.GetImageInfo();
+ } else {
+ hand->imageInfo_ = *(img.GetImageInfo());
+ }
+}
+
+void UIAnalogClock::SetHandLine(HandType type, Point position, Point center, ColorType color,
+ uint16_t width, uint16_t height, OpacityType opacity)
+{
+ Hand* hand = nullptr;
+ if (type == HandType::HOUR_HAND) {
+ hand = &hourHand_;
+ } else if (type == HandType::MINUTE_HAND) {
+ hand = &minuteHand_;
+ } else {
+ hand = &secondHand_;
+ }
+
+ hand->color_ = color;
+ hand->height_ = height;
+ hand->width_ = width;
+ hand->position_ = position;
+ hand->center_ = center;
+ hand->opacity_ = opacity;
+ hand->initAngle_ = 0;
+ hand->preAngle_ = 0;
+ hand->nextAngle_ = 0;
+ hand->drawtype_ = DrawType::DRAW_LINE;
+}
+
+Point UIAnalogClock::GetHandRotateCenter(HandType type) const
+{
+ if (type == HandType::HOUR_HAND) {
+ return hourHand_.center_;
+ } else if (type == HandType::MINUTE_HAND) {
+ return minuteHand_.center_;
+ } else {
+ return secondHand_.center_;
+ }
+}
+
+Point UIAnalogClock::GetHandPosition(HandType type) const
+{
+ if (type == HandType::HOUR_HAND) {
+ return hourHand_.position_;
+ } else if (type == HandType::MINUTE_HAND) {
+ return minuteHand_.position_;
+ } else {
+ return secondHand_.position_;
+ }
+}
+
+uint16_t UIAnalogClock::GetHandInitAngle(HandType type) const
+{
+ if (type == HandType::HOUR_HAND) {
+ return hourHand_.initAngle_;
+ } else if (type == HandType::MINUTE_HAND) {
+ return minuteHand_.initAngle_;
+ } else {
+ return secondHand_.initAngle_;
+ }
+}
+
+uint16_t UIAnalogClock::GetHandCurrentAngle(HandType type) const
+{
+ if (type == HandType::HOUR_HAND) {
+ return hourHand_.nextAngle_;
+ } else if (type == HandType::MINUTE_HAND) {
+ return minuteHand_.nextAngle_;
+ } else {
+ return secondHand_.nextAngle_;
+ }
+}
+
+void UIAnalogClock::SetInitTime24Hour(uint8_t hour, uint8_t minute, uint8_t second)
+{
+ currentHour_ = hour % ONE_DAY_IN_HOUR;
+ currentMinute_ = minute % ONE_HOUR_IN_MINUTE;
+ currentSecond_ = second % ONE_MINUTE_IN_SECOND;
+
+ hourHand_.initAngle_ = ConvertHandValueToAngle(currentHour_,
+ HALF_DAY_IN_HOUR, currentMinute_, ONE_HOUR_IN_MINUTE);
+ hourHand_.preAngle_ = hourHand_.initAngle_;
+ hourHand_.nextAngle_ = hourHand_.initAngle_;
+
+ minuteHand_.initAngle_ = ConvertHandValueToAngle(currentMinute_,
+ ONE_HOUR_IN_MINUTE, currentSecond_, ONE_MINUTE_IN_SECOND);
+ minuteHand_.preAngle_ = minuteHand_.initAngle_;
+ minuteHand_.nextAngle_ = minuteHand_.initAngle_;
+
+ secondHand_.initAngle_ = ConvertHandValueToAngle(currentSecond_, ONE_MINUTE_IN_SECOND);
+ secondHand_.preAngle_ = secondHand_.initAngle_;
+ secondHand_.nextAngle_ = secondHand_.initAngle_;
+
+ UpdateClock(true);
+}
+
+void UIAnalogClock::SetInitTime12Hour(uint8_t hour, uint8_t minute, uint8_t second, bool am)
+{
+ SetInitTime24Hour((hour % HALF_DAY_IN_HOUR) + (am ? 0 : HALF_DAY_IN_HOUR), minute, second);
+}
+
+uint16_t UIAnalogClock::ConvertHandValueToAngle(uint8_t handValue, uint8_t range,
+ uint8_t secondHandValue, uint8_t ratio) const
+{
+ if ((range == 0) || (ratio == 0)) {
+ GRAPHIC_LOGW("UIAnalogClock::ConvertHandValueToAngle Invalid range or ratio\n");
+ return 0;
+ }
+ /*
+ * Example: calculate the angle of hour hand
+ * Assume that the time is 5: 30, then range is 12, radio is 60
+ * angle is [(5 * 60 + 30) / (12 * 60)] * 360
+ */
+ uint32_t degree = (static_cast(handValue) * ratio + secondHandValue);
+ degree = static_cast(CIRCLE_IN_DEGREE * degree / (static_cast(range) * ratio));
+
+ return static_cast(degree % CIRCLE_IN_DEGREE);
+}
+
+uint16_t UIAnalogClock::ConvertHandValueToAngle(uint8_t handValue, uint8_t range) const
+{
+ if (range == 0) {
+ GRAPHIC_LOGW("UIAnalogClock::ConvertHandValueToAngle Invalid range or ratio\n");
+ return 0;
+ }
+ /*
+ * Example: calculate the angle of second hand without millisecond handle
+ * Assume that the time is 5:30:30, then range is 60
+ * angle is (30 / 60) * 360
+ */
+ return (static_cast(handValue) * CIRCLE_IN_DEGREE / range);
+}
+
+void UIAnalogClock::UpdateClock(bool clockInit)
+{
+ Invalidate();
+ hourHand_.nextAngle_ = ConvertHandValueToAngle(currentHour_,
+ HALF_DAY_IN_HOUR, currentMinute_, ONE_HOUR_IN_MINUTE);
+
+ minuteHand_.nextAngle_ = ConvertHandValueToAngle(currentMinute_,
+ ONE_HOUR_IN_MINUTE, currentSecond_, ONE_MINUTE_IN_SECOND);
+
+ secondHand_.nextAngle_ = ConvertHandValueToAngle(currentSecond_, ONE_MINUTE_IN_SECOND);
+
+ Rect rect = GetRect();
+ CalculateRedrawArea(rect, hourHand_, clockInit);
+ CalculateRedrawArea(rect, minuteHand_, clockInit);
+ if (GetWorkMode() == WorkMode::NORMAL) {
+ CalculateRedrawArea(rect, secondHand_, clockInit);
+ }
+}
+
+void UIAnalogClock::OnDraw(const Rect& invalidatedArea)
+{
+ DrawRect::Draw(GetRect(), invalidatedArea, *style_, opaScale_);
+}
+
+void UIAnalogClock::OnPostDraw(const Rect& invalidatedArea)
+{
+ Rect current = GetOrigRect();
+ DrawHand(current, invalidatedArea, hourHand_);
+ DrawHand(current, invalidatedArea, minuteHand_);
+ if (GetWorkMode() == WorkMode::NORMAL) {
+ DrawHand(current, invalidatedArea, secondHand_);
+ }
+}
+
+void UIAnalogClock::SetPosition(int16_t x, int16_t y)
+{
+ UIViewGroup::SetPosition(x, y);
+ UpdateClock(true);
+}
+
+void UIAnalogClock::SetPosition(int16_t x, int16_t y, int16_t width, int16_t height)
+{
+ UIViewGroup::SetPosition(x, y, width, height);
+ UpdateClock(true);
+}
+
+void UIAnalogClock::CalculateRedrawArea(const Rect& current, Hand& hand, bool clockInit)
+{
+ /*
+ * Use the current image as an independent rectangular area
+ * to calculate the coordinate conversion coefficient.
+ */
+ int16_t imgWidth = hand.imageInfo_.header.width;
+ int16_t imgHeight = hand.imageInfo_.header.height;
+
+ int16_t left = hand.position_.x + current.GetLeft();
+ int16_t right = left + imgWidth;
+ int16_t top = hand.position_.y + current.GetTop();
+ int16_t bottom = top + imgHeight;
+ Rect imgRect(left, top, right, bottom);
+ TransformMap backwardMap(imgRect);
+ Vector2 pivot;
+ pivot.x_ = hand.center_.x;
+ pivot.y_ = hand.center_.y;
+
+ /* Rotate the specified angle, */
+ backwardMap.Rotate(hand.nextAngle_ - hand.initAngle_, pivot);
+ Rect redraw = hand.target_;
+ hand.target_ = backwardMap.GetBoxRect();
+ hand.trans_ = backwardMap;
+ hand.preAngle_ = hand.nextAngle_;
+ if (!clockInit) {
+ /* Prevent old images from being residued */
+ redraw.Join(redraw, hand.target_);
+ InvalidateRect(redraw);
+ }
+}
+
+void UIAnalogClock::DrawHand(const Rect& current, const Rect& invalidatedArea, Hand& hand)
+{
+ if (hand.drawtype_ == DrawType::DRAW_IMAGE) {
+ DrawHandImage(current, invalidatedArea, hand);
+ } else {
+ DrawHandLine(invalidatedArea, hand);
+ }
+}
+
+void UIAnalogClock::DrawHandImage(const Rect& current, const Rect& invalidatedArea, Hand& hand)
+{
+ uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(hand.imageInfo_.header.colorMode);
+ TransformDataInfo imageTranDataInfo = {
+ hand.imageInfo_.header, hand.imageInfo_.data, pxSize,
+ BlurLevel::LEVEL0, TransformAlgorithm::BILINEAR
+ };
+ DrawUtils::GetInstance()->DrawTransform(invalidatedArea, { 0, 0 },
+ Color::Black(), opaScale_, hand.trans_, imageTranDataInfo);
+}
+
+void UIAnalogClock::DrawHandLine(const Rect& invalidatedArea, Hand& hand)
+{
+ float sinma = Sin(hand.nextAngle_);
+ float cosma = Sin(hand.nextAngle_ + THREE_QUARTER_IN_DEGREE);
+ int32_t handLength = hand.height_;
+ Rect rect = GetRect();
+ Point start;
+ Point end;
+ Point curCenter;
+ curCenter.x = hand.position_.x + hand.center_.x + rect.GetLeft();
+ curCenter.y = hand.position_.y + hand.center_.y + rect.GetTop();
+
+ int32_t startToCenterLength = hand.center_.y;
+
+ int32_t xPointLength = static_cast(startToCenterLength * sinma);
+ int32_t yPointLength = static_cast(startToCenterLength * cosma);
+
+ start.x = xPointLength + curCenter.x;
+ start.y = yPointLength + curCenter.y;
+
+ /*
+ * @ startToCenterLength: means the length between StartPoint and CenterPoint.
+ * @ handlength: means the hand height.
+ * @ xlength: means X-axis length relative to the center point
+ * @ ylength: means Y-axis length relative to the center point
+ */
+ int32_t xlength = static_cast((startToCenterLength - handLength) * sinma);
+ int32_t ylength = static_cast((startToCenterLength - handLength) * cosma);
+ end.x = xlength + curCenter.x;
+ end.y = ylength + curCenter.y;
+
+ DrawLine::Draw(start, end, invalidatedArea, hand.width_, hand.color_, hand.opacity_);
+}
+
+void UIAnalogClock::SetWorkMode(WorkMode newMode)
+{
+ WorkMode oldMode = mode_;
+
+ if (oldMode != newMode) {
+ /*
+ * After entering the alwayson mode, all child controls are no longer drawn,
+ * making the simplest analog clock.
+ */
+ isViewGroup_ = (newMode == ALWAYS_ON) ? false : true;
+ mode_ = newMode;
+ Invalidate();
+ }
+}
+} // namespace OHOS
diff --git a/frameworks/components/ui_arc_label.cpp b/frameworks/components/ui_arc_label.cpp
new file mode 100755
index 0000000..c93d148
--- /dev/null
+++ b/frameworks/components/ui_arc_label.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_arc_label.h"
+#include "common/typed_text.h"
+#include "draw/draw_label.h"
+#include "draw/draw_rect.h"
+#include "font/ui_font.h"
+#include "themes/theme_manager.h"
+
+namespace OHOS {
+UIArcLabel::UIArcLabel()
+ : arcLabelText_(nullptr),
+ needRefresh_(false),
+ textSize_({0, 0}),
+ radius_(0),
+ startAngle_(0),
+ endAngle_(0),
+ arcCenter_({0, 0}),
+ orientation_(TextOrientation::INSIDE),
+ arcTextInfo_{0}
+{
+ Theme* theme = ThemeManager::GetInstance().GetCurrent();
+ style_ = (theme != nullptr) ? &(theme->GetLabelStyle()) : &(StyleDefault::GetLabelStyle());
+}
+
+UIArcLabel::~UIArcLabel()
+{
+ if (arcLabelText_ != nullptr) {
+ delete arcLabelText_;
+ arcLabelText_ = nullptr;
+ }
+}
+
+void UIArcLabel::SetStyle(uint8_t key, int64_t value)
+{
+ UIView::SetStyle(key, value);
+ RefreshArcLabel();
+}
+
+void UIArcLabel::SetText(const char* text)
+{
+ if (text == nullptr) {
+ return;
+ }
+ InitArcLabelText();
+ arcLabelText_->SetText(text);
+ if (arcLabelText_->IsNeedRefresh()) {
+ RefreshArcLabel();
+ }
+}
+
+const char* UIArcLabel::GetText() const
+{
+ return (arcLabelText_ == nullptr) ? nullptr : arcLabelText_->GetText();
+}
+
+void UIArcLabel::SetAlign(UITextLanguageAlignment horizontalAlign)
+{
+ InitArcLabelText();
+ arcLabelText_->SetAlign(horizontalAlign, TEXT_ALIGNMENT_TOP);
+ if (arcLabelText_->IsNeedRefresh()) {
+ RefreshArcLabel();
+ }
+}
+
+UITextLanguageAlignment UIArcLabel::GetHorAlign()
+{
+ InitArcLabelText();
+ return arcLabelText_->GetHorAlign();
+}
+
+UITextLanguageDirect UIArcLabel::GetDirect()
+{
+ InitArcLabelText();
+ return arcLabelText_->GetDirect();
+}
+
+void UIArcLabel::SetFontId(uint8_t fontId)
+{
+ InitArcLabelText();
+ arcLabelText_->SetFontId(fontId);
+ if (arcLabelText_->IsNeedRefresh()) {
+ RefreshArcLabel();
+ }
+}
+
+uint8_t UIArcLabel::GetFontId()
+{
+ InitArcLabelText();
+ return arcLabelText_->GetFontId();
+}
+
+void UIArcLabel::SetFont(const char* name, uint8_t size)
+{
+ if (name == nullptr) {
+ return;
+ }
+ InitArcLabelText();
+ arcLabelText_->SetFont(name, size);
+ if (arcLabelText_->IsNeedRefresh()) {
+ RefreshArcLabel();
+ }
+}
+
+void UIArcLabel::OnDraw(const Rect& invalidatedArea)
+{
+ InitArcLabelText();
+ const char* text = arcLabelText_->GetText();
+ if ((text == nullptr) || (radius_ == 0)) {
+ return;
+ }
+ Rect trunc = invalidatedArea;
+ OpacityType opa = GetMixOpaScale();
+ DrawRect::Draw(GetRect(), trunc, *style_, opa);
+
+ Rect coords = GetContentRect();
+ if (trunc.Intersect(trunc, coords)) {
+ DrawArcText(trunc, opa);
+ }
+}
+
+void UIArcLabel::DrawArcText(const Rect& mask, OpacityType opaScale)
+{
+ Point center;
+ center.x = arcTextInfo_.arcCenter.x + GetRect().GetX();
+ center.y = arcTextInfo_.arcCenter.y + GetRect().GetY();
+ InitArcLabelText();
+ UIFont::GetInstance()->SetCurrentFontId(arcLabelText_->GetFontId(), arcLabelText_->GetFontSize());
+ DrawLabel::DrawArcText(mask, arcLabelText_->GetText(), center, arcLabelText_->GetFontId(),
+ arcTextInfo_, orientation_, *style_, opaScale);
+}
+
+void UIArcLabel::RefreshArcLabel()
+{
+ Invalidate();
+ if (!needRefresh_) {
+ needRefresh_ = true;
+ }
+}
+
+void UIArcLabel::ReMeasure()
+{
+ if (!needRefresh_) {
+ return;
+ }
+ needRefresh_ = false;
+ InitArcLabelText();
+ UIFont::GetInstance()->SetCurrentFontId(arcLabelText_->GetFontId(), arcLabelText_->GetFontSize());
+
+ MeasureArcTextInfo();
+ Rect textRect = TypedText::GetArcTextRect(arcLabelText_->GetText(),
+ arcCenter_,
+ style_->letterSpace_,
+ orientation_,
+ arcTextInfo_);
+ int16_t arcTextWidth = textRect.GetWidth();
+ int16_t arcTextHeight = textRect.GetHeight();
+
+ SetPosition(textRect.GetX(), textRect.GetY());
+ Resize(arcTextWidth, arcTextHeight);
+ arcTextInfo_.arcCenter.x = arcCenter_.x - GetX();
+ arcTextInfo_.arcCenter.y = arcCenter_.y - GetY();
+ textSize_.x = arcTextWidth;
+ textSize_.y = arcTextHeight;
+ Invalidate();
+}
+
+void UIArcLabel::MeasureArcTextInfo()
+{
+ const char* text = arcLabelText_->GetText();
+ if (text == nullptr) {
+ return;
+ }
+ uint16_t letterHeight = UIFont::GetInstance()->GetHeight();
+ arcTextInfo_.radius = ((orientation_ == TextOrientation::INSIDE) ? radius_ : (radius_ - letterHeight));
+ if (arcTextInfo_.radius == 0) {
+ return;
+ }
+
+ uint16_t arcAngle;
+ if (startAngle_ < endAngle_) {
+ arcAngle = endAngle_ - startAngle_;
+ arcTextInfo_.direct = TEXT_DIRECT_LTR; // Clockwise
+ arcLabelText_->SetDirect(TEXT_DIRECT_LTR);
+ } else {
+ arcAngle = startAngle_ - endAngle_;
+ arcTextInfo_.direct = TEXT_DIRECT_RTL; // Counterclockwise
+ arcLabelText_->SetDirect(TEXT_DIRECT_RTL);
+ }
+ // calculate max arc length
+ float maxLength = static_cast((UI_PI * radius_ * arcAngle) / SEMICIRCLE_IN_DEGREE);
+ arcTextInfo_.lineStart = 0;
+ arcTextInfo_.lineEnd = TypedText::GetNextLine(&text[arcTextInfo_.lineStart], style_->letterSpace_, maxLength);
+ arcTextInfo_.startAngle = startAngle_ % CIRCLE_IN_DEGREE;
+ int16_t actLength = TypedText::GetTextWidth(&text[arcTextInfo_.lineStart],
+ arcTextInfo_.lineEnd - arcTextInfo_.lineStart, style_->letterSpace_);
+ if ((arcLabelText_->GetHorAlign() != TEXT_ALIGNMENT_LEFT) && (actLength < maxLength)) {
+ float gapLength = maxLength - actLength;
+ if (arcLabelText_->GetHorAlign() == TEXT_ALIGNMENT_CENTER) {
+ gapLength = gapLength / 2; // 2: half
+ }
+ arcTextInfo_.startAngle += TypedText::GetAngleForArcLen(gapLength, letterHeight, arcTextInfo_.radius,
+ arcTextInfo_.direct, orientation_);
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_axis.cpp b/frameworks/components/ui_axis.cpp
new file mode 100755
index 0000000..9193eb8
--- /dev/null
+++ b/frameworks/components/ui_axis.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_axis.h"
+#include "common/screen.h"
+#include "draw/draw_line.h"
+
+namespace OHOS {
+UIAxis::UIAxis()
+ : maxRange_(0),
+ minRange_(0),
+ start_({0, 0}),
+ end_({0, 0}),
+ markInterval_(0),
+ dataPerMark_(0),
+ dataInterval_(0),
+ markDataCount_(AXIS_DEFAULT_MARK_INTERVAL),
+ enableReverse_(false)
+{
+ SetStyle(STYLE_LINE_WIDTH, 1);
+ SetStyle(STYLE_LINE_COLOR, Color::White().full);
+}
+
+void UIAxis::SetLineColor(const ColorType& color)
+{
+ SetStyle(STYLE_LINE_COLOR, color.full);
+}
+
+void UIXAxis::SetMarkNum(uint16_t count)
+{
+ if ((count == 0) || (count > Screen::GetInstance().GetWidth())) {
+ return;
+ }
+ markDataCount_ = count;
+ UpdateAxis();
+}
+
+bool UIXAxis::SetDataRange(uint16_t min, uint16_t max)
+{
+ if (max <= min) {
+ return false;
+ }
+ maxRange_ = max;
+ minRange_ = min;
+ return UpdateAxis();
+}
+
+void UIXAxis::UpdateAxisPoints()
+{
+ Rect current = GetContentRect();
+ start_.x = current.GetLeft();
+ end_.x = current.GetRight();
+ start_.y = enableReverse_ ? current.GetTop() : current.GetBottom();
+ end_.y = start_.y;
+}
+
+bool UIXAxis::UpdateAxis()
+{
+ UpdateAxisPoints();
+ int16_t xAxisLength = end_.x - start_.x + 1;
+ if (xAxisLength <= 0) {
+ return false;
+ }
+
+ if (markDataCount_ != 0) {
+ dataInterval_ = static_cast((maxRange_ - minRange_) / markDataCount_);
+ markInterval_ = static_cast(xAxisLength) / markDataCount_;
+ if (maxRange_ > minRange_) {
+ dataPerMark_ = markInterval_ / dataInterval_;
+ }
+ }
+
+ return true;
+}
+
+void UIXAxis::TranslateToPixel(int16_t& value)
+{
+ float minXStep = dataPerMark_ ? dataPerMark_ : markInterval_;
+ value = start_.x + static_cast((value - minRange_) * minXStep);
+}
+
+void UIAxis::OnDraw(const Rect& invalidatedArea)
+{
+ DrawLine::Draw(start_, end_, invalidatedArea, style_->lineWidth_, style_->lineColor_, style_->lineOpa_);
+ DrawAxisMark(invalidatedArea);
+}
+
+void UIXAxis::DrawAxisMark(const Rect& invalidatedArea)
+{
+ Point start;
+ Point end;
+ uint16_t index = 1;
+ while (index <= markDataCount_) {
+ start.y = start_.y;
+ start.x = start_.x + static_cast(index * markInterval_);
+ end.y = enableReverse_ ? (start.y + AXIS_DEFAULT_MARK_LENGTH) : (start.y - AXIS_DEFAULT_MARK_LENGTH);
+ end.x = start.x;
+
+ DrawLine::Draw(start, end, invalidatedArea, style_->lineWidth_, style_->lineColor_, style_->lineOpa_);
+ index++;
+ }
+}
+
+void UIYAxis::SetMarkNum(uint16_t count)
+{
+ if ((count == 0) || (count > Screen::GetInstance().GetHeight())) {
+ return;
+ }
+ markDataCount_ = count;
+ dataInterval_ = static_cast((maxRange_ - minRange_) / markDataCount_);
+}
+
+bool UIYAxis::SetDataRange(uint16_t min, uint16_t max)
+{
+ if (max <= min) {
+ return false;
+ }
+
+ maxRange_ = max;
+ minRange_ = min;
+ return UpdateAxis();
+}
+
+void UIYAxis::UpdateAxisPoints()
+{
+ Rect current = GetContentRect();
+ int16_t top = current.GetTop();
+ int16_t bottom = current.GetBottom();
+
+ start_.x = current.GetLeft();
+ end_.x = start_.x;
+ if (enableReverse_) {
+ start_.y = top;
+ end_.y = bottom;
+ } else {
+ start_.y = bottom;
+ end_.y = top;
+ }
+}
+
+void UIYAxis::TranslateToPixel(int16_t& value)
+{
+ float minYStep = dataPerMark_ ? dataPerMark_ : markInterval_;
+ if (enableReverse_) {
+ value = start_.y + static_cast((maxRange_ - value + minRange_) * minYStep);
+ } else {
+ value = start_.y - static_cast((value - minRange_) * minYStep);
+ }
+}
+
+bool UIYAxis::UpdateAxis()
+{
+ UpdateAxisPoints();
+ int16_t yAxisLength = enableReverse_ ? (end_.y - start_.y + 1) : (start_.y - end_.y + 1);
+ if (yAxisLength <= 0) {
+ return false;
+ }
+
+ if (markDataCount_ != 0) {
+ dataInterval_ = static_cast((maxRange_ - minRange_) / markDataCount_);
+ markInterval_ = static_cast(yAxisLength) / markDataCount_;
+ if (dataInterval_ != 0) {
+ dataPerMark_ = markInterval_ / dataInterval_;
+ }
+ }
+ return true;
+}
+
+void UIYAxis::DrawAxisMark(const Rect& invalidatedArea)
+{
+ uint16_t index = 1;
+ while (index <= markDataCount_) {
+ Point start;
+ Point end;
+ start.x = start_.x;
+ start.y = enableReverse_ ? (start_.y + static_cast(index * markInterval_))
+ : (start_.y - static_cast(index * markInterval_));
+ end.x = start.x + AXIS_DEFAULT_MARK_LENGTH;
+ end.y = start.y;
+
+ DrawLine::Draw(start, end, invalidatedArea, style_->lineWidth_, style_->lineColor_, style_->lineOpa_);
+ index++;
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_box_progress.cpp b/frameworks/components/ui_box_progress.cpp
new file mode 100755
index 0000000..27534d7
--- /dev/null
+++ b/frameworks/components/ui_box_progress.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_box_progress.h"
+#include "draw/draw_arc.h"
+#include "draw/draw_rect.h"
+#include "graphic_log.h"
+
+namespace OHOS {
+UIBoxProgress::UIBoxProgress()
+ : progressWidth_(0), progressHeight_(0), isValidWidthSet_(false), isValidHeightSet_(false)
+{
+ SetDirection(Direction::DIR_LEFT_TO_RIGHT);
+}
+
+void UIBoxProgress::DrawValidRect(const Image* image, const Rect& rect, const Rect& invalidatedArea,
+ const Style& style, uint16_t radius)
+{
+ Rect cordsTmp;
+ if ((image != nullptr) && (image->GetSrcType() != IMG_SRC_UNKNOWN)) {
+ ImageHeader header = {0};
+ image->GetHeader(header);
+
+ Rect area(rect);
+ switch (direction_) {
+ case Direction::DIR_LEFT_TO_RIGHT:
+ cordsTmp.SetPosition(area.GetLeft() - radius, area.GetTop());
+ break;
+ case Direction::DIR_TOP_TO_BOTTOM:
+ cordsTmp.SetPosition(area.GetLeft(), area.GetTop() - radius);
+ break;
+ case Direction::DIR_RIGHT_TO_LEFT:
+ cordsTmp.SetPosition(area.GetRight() + radius - header.width, area.GetTop());
+ break;
+ case Direction::DIR_BOTTOM_TO_TOP:
+ cordsTmp.SetPosition(area.GetLeft(), area.GetBottom() + radius - header.height);
+ break;
+ default:
+ GRAPHIC_LOGE("UIBoxProgress: DrawValidRect direction Err!\n");
+ break;
+ }
+ cordsTmp.SetHeight(header.height);
+ cordsTmp.SetWidth(header.width);
+ if (area.Intersect(area, invalidatedArea)) {
+ image->DrawImage(cordsTmp, area, style, opaScale_);
+ }
+ } else {
+ DrawRect::Draw(rect, invalidatedArea, style, opaScale_);
+ }
+
+ if (style.lineCap_ == CapType::CAP_ROUND) {
+ DrawRoundCap(image, {cordsTmp.GetX(), cordsTmp.GetY()}, rect, invalidatedArea, radius, style);
+ }
+}
+
+void UIBoxProgress::DrawRoundCap(const Image* image, const Point& imgPos, const Rect& rect,
+ const Rect& invalidatedArea, uint16_t radius, const Style& style)
+{
+ Point leftTop;
+ Point leftBottom;
+ Point rightTop;
+ Point rightBottom;
+
+ switch (direction_) {
+ case Direction::DIR_LEFT_TO_RIGHT:
+ case Direction::DIR_RIGHT_TO_LEFT: {
+ leftTop.x = rect.GetLeft() - 1;
+ leftTop.y = rect.GetTop() + radius - 1;
+ leftBottom.x = leftTop.x;
+ leftBottom.y = rect.GetBottom() - radius + 1;
+ rightTop.x = rect.GetRight() + 1;
+ rightTop.y = leftTop.y;
+ rightBottom.x = rightTop.x;
+ rightBottom.y = leftBottom.y;
+ break;
+ }
+
+ case Direction::DIR_TOP_TO_BOTTOM:
+ case Direction::DIR_BOTTOM_TO_TOP: {
+ leftTop.x = rect.GetLeft() + radius - 1;
+ leftTop.y = rect.GetTop() - 1;
+ rightTop.x = rect.GetRight() - radius + 1;
+ rightTop.y = leftTop.y;
+ leftBottom.x = leftTop.x;
+ leftBottom.y = rect.GetBottom() + 1;
+ rightBottom.x = rightTop.x;
+ rightBottom.y = leftBottom.y;
+ break;
+ }
+ default:
+ GRAPHIC_LOGE("UIBoxProgress: DrawRoundCap direction Err!\n");
+ break;
+ }
+
+ Style capStyle = style;
+ capStyle.lineWidth_ = radius;
+ capStyle.lineColor_ = style.bgColor_;
+ capStyle.lineOpa_ = style.bgOpa_;
+ ArcInfo arcInfo = {{0}};
+ arcInfo.radius = radius;
+ arcInfo.imgPos = imgPos;
+ arcInfo.imgSrc = image;
+
+ arcInfo.center = leftTop;
+ arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
+ arcInfo.endAngle = 0;
+ DrawArc::GetInstance()->Draw(arcInfo, invalidatedArea, capStyle, opaScale_, CapType::CAP_NONE);
+
+ arcInfo.center = leftBottom;
+ arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
+ arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
+ DrawArc::GetInstance()->Draw(arcInfo, invalidatedArea, capStyle, opaScale_, CapType::CAP_NONE);
+
+ arcInfo.center = rightTop;
+ arcInfo.startAngle = 0;
+ arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
+ DrawArc::GetInstance()->Draw(arcInfo, invalidatedArea, capStyle, opaScale_, CapType::CAP_NONE);
+
+ arcInfo.center = rightBottom;
+ arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
+ arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
+ DrawArc::GetInstance()->Draw(arcInfo, invalidatedArea, capStyle, opaScale_, CapType::CAP_NONE);
+}
+
+void UIBoxProgress::GetBackgroundParam(Point& startPoint, int16_t& width, int16_t& height, uint16_t& radius,
+ const Style& style)
+{
+ Rect rect = GetOrigRect();
+ startPoint.x = rect.GetLeft() + style_->borderWidth_ + style_->paddingLeft_;
+ startPoint.y = rect.GetTop() + style_->borderWidth_ + style_->paddingTop_;
+
+ radius = 0;
+ width = progressWidth_;
+ height = progressHeight_;
+ if (style.lineCap_ == CapType::CAP_ROUND) {
+ switch (direction_) {
+ case Direction::DIR_LEFT_TO_RIGHT:
+ case Direction::DIR_RIGHT_TO_LEFT:
+ radius = (progressHeight_ + 1) >> 1;
+ width -= radius << 1;
+ startPoint.x += radius;
+ break;
+ case Direction::DIR_TOP_TO_BOTTOM:
+ case Direction::DIR_BOTTOM_TO_TOP:
+ radius = (progressWidth_ + 1) >> 1;
+ height -= radius << 1;
+ startPoint.y += radius;
+ break;
+ default:
+ GRAPHIC_LOGE("UIBoxProgress: GetBackgroundParam direction Err!\n");
+ return;
+ }
+ }
+}
+
+void UIBoxProgress::DrawBackground(const Rect& invalidatedArea)
+{
+ Point startPoint;
+ int16_t progressWidth;
+ int16_t progressHeight;
+ uint16_t radius;
+ GetBackgroundParam(startPoint, progressWidth, progressHeight, radius, *backgroundStyle_);
+
+ Rect coords(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
+
+ DrawValidRect(backgroundImage_, coords, invalidatedArea, *backgroundStyle_, radius);
+}
+
+void UIBoxProgress::DrawForeground(const Rect& invalidatedArea, Rect& coords)
+{
+ Point startPoint;
+ int16_t progressWidth;
+ int16_t progressHeight;
+ uint16_t radius;
+ GetBackgroundParam(startPoint, progressWidth, progressHeight, radius, *foregroundStyle_);
+ int16_t length;
+
+ switch (direction_) {
+ case Direction::DIR_LEFT_TO_RIGHT: {
+ length = GetCurrentPos(progressWidth - 1);
+ coords.SetRect(startPoint.x, startPoint.y, startPoint.x + length, startPoint.y + progressHeight - 1);
+ break;
+ }
+ case Direction::DIR_RIGHT_TO_LEFT: {
+ length = GetCurrentPos(progressWidth - 1);
+ coords.SetRect(startPoint.x + progressWidth - 1 - length,
+ startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
+ break;
+ }
+ case Direction::DIR_TOP_TO_BOTTOM: {
+ length = GetCurrentPos(progressHeight - 1);
+ coords.SetRect(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + length);
+ break;
+ }
+ case Direction::DIR_BOTTOM_TO_TOP: {
+ length = GetCurrentPos(progressHeight - 1);
+ coords.SetRect(startPoint.x, startPoint.y + progressHeight - 1 - length,
+ startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
+ break;
+ }
+ default: {
+ GRAPHIC_LOGE("UIBoxProgress: DrawForeground direction Err!\n");
+ return;
+ }
+ }
+
+ DrawValidRect(foregroundImage_, coords, invalidatedArea, *foregroundStyle_, radius);
+}
+
+void UIBoxProgress::OnDraw(const Rect& invalidatedArea)
+{
+ DrawRect::Draw(GetOrigRect(), invalidatedArea, *style_, opaScale_);
+ Rect trunc(invalidatedArea);
+ if (trunc.Intersect(trunc, GetOrigRect())) {
+ if (enableBackground_) {
+ DrawBackground(trunc);
+ }
+
+ if ((lastValue_ - rangeMin_ != 0) || (foregroundStyle_->lineCap_ == CapType::CAP_ROUND)) {
+ Rect coords;
+ DrawForeground(trunc, coords);
+ }
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_button.cpp b/frameworks/components/ui_button.cpp
new file mode 100755
index 0000000..18d9d31
--- /dev/null
+++ b/frameworks/components/ui_button.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_button.h"
+#include "common/image.h"
+#include "draw/draw_image.h"
+#include "draw/draw_rect.h"
+#include "graphic_log.h"
+#include "imgdecode/cache_manager.h"
+#include "style.h"
+#include "themes/theme_manager.h"
+
+namespace OHOS {
+UIButton::UIButton()
+ : defaultImgSrc_(nullptr),
+ triggeredImgSrc_(nullptr),
+ currentImgSrc_(ButtonImageSrc::BTN_IMAGE_DEFAULT),
+ imgX_(0),
+ imgY_(0),
+ contentWidth_(0),
+ contentHeight_(0),
+ state_(RELEASED),
+ styleState_(RELEASED),
+ buttonStyleAllocFlag_(false)
+{
+ touchable_ = true;
+ SetupThemeStyles();
+}
+
+UIButton::~UIButton()
+{
+ if (defaultImgSrc_ != nullptr) {
+ delete defaultImgSrc_;
+ defaultImgSrc_ = nullptr;
+ }
+
+ if (triggeredImgSrc_ != nullptr) {
+ delete triggeredImgSrc_;
+ triggeredImgSrc_ = nullptr;
+ }
+
+ if (buttonStyleAllocFlag_) {
+ for (uint8_t i = 0; i < BTN_STATE_NUM; i++) {
+ delete buttonStyles_[i];
+ buttonStyles_[i] = nullptr;
+ }
+ buttonStyleAllocFlag_ = false;
+ }
+}
+
+void UIButton::DrawImg(const Rect& invalidatedArea, OpacityType opaScale)
+{
+ const Image* image = GetCurImageSrc();
+ if (image == nullptr) {
+ return;
+ }
+
+ ImageHeader header = {0};
+ image->GetHeader(header);
+ Rect coords;
+ Rect viewRect = GetContentRect();
+ coords.SetLeft(viewRect.GetLeft() + GetImageX());
+ coords.SetTop(viewRect.GetTop() + GetImageY());
+ coords.SetWidth(header.width);
+ coords.SetHeight(header.height);
+
+ Rect trunc(invalidatedArea);
+ if (trunc.Intersect(trunc, viewRect)) {
+ image->DrawImage(coords, trunc, *buttonStyles_[state_], opaScale);
+ }
+}
+
+void UIButton::OnDraw(const Rect& invalidatedArea)
+{
+ OpacityType opa = GetMixOpaScale();
+ DrawRect::Draw(GetOrigRect(), invalidatedArea, *buttonStyles_[state_], opa);
+ DrawImg(invalidatedArea, opa);
+}
+
+void UIButton::SetupThemeStyles()
+{
+ Theme* theme = ThemeManager::GetInstance().GetCurrent();
+
+ if (theme == nullptr) {
+ buttonStyles_[RELEASED] = &(StyleDefault::GetButtonReleasedStyle());
+ buttonStyles_[PRESSED] = &(StyleDefault::GetButtonPressedStyle());
+ buttonStyles_[INACTIVE] = &(StyleDefault::GetButtonInactiveStyle());
+ } else {
+ buttonStyles_[RELEASED] = &(theme->GetButtonStyle().released);
+ buttonStyles_[PRESSED] = &(theme->GetButtonStyle().pressed);
+ buttonStyles_[INACTIVE] = &(theme->GetButtonStyle().inactive);
+ }
+}
+
+int64_t UIButton::GetStyle(uint8_t key) const
+{
+ return GetStyleForState(key, styleState_);
+}
+
+void UIButton::SetStyle(uint8_t key, int64_t value)
+{
+ SetStyleForState(key, value, styleState_);
+}
+
+int64_t UIButton::GetStyleForState(uint8_t key, ButtonState state) const
+{
+ if (state < BTN_STATE_NUM) {
+ return (buttonStyles_[state])->GetStyle(key);
+ }
+ return 0;
+}
+
+void UIButton::SetStyleForState(uint8_t key, int64_t value, ButtonState state)
+{
+ if (state < BTN_STATE_NUM) {
+ if (!buttonStyleAllocFlag_) {
+ for (uint8_t i = 0; i < BTN_STATE_NUM; i++) {
+ Style styleSaved = *buttonStyles_[i];
+ buttonStyles_[i] = new Style;
+ if (buttonStyles_[i] == nullptr) {
+ GRAPHIC_LOGE("new Style fail");
+ return;
+ }
+ *(buttonStyles_[i]) = styleSaved;
+ }
+ buttonStyleAllocFlag_ = true;
+ }
+ int16_t width = GetWidth();
+ int16_t height = GetHeight();
+ buttonStyles_[state]->SetStyle(key, value);
+ switch (key) {
+ case STYLE_BORDER_WIDTH: {
+ SetWidth(width);
+ SetHeight(height);
+ break;
+ }
+ case STYLE_PADDING_LEFT:
+ case STYLE_PADDING_RIGHT: {
+ SetWidth(width);
+ break;
+ }
+ case STYLE_PADDING_TOP:
+ case STYLE_PADDING_BOTTOM: {
+ SetHeight(height);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+bool UIButton::OnPressEvent(const PressEvent& event)
+{
+ currentImgSrc_ = ButtonImageSrc::BTN_IMAGE_TRIGGERED;
+ SetState(PRESSED);
+ Resize(contentWidth_, contentHeight_);
+ Invalidate();
+ return UIView::OnPressEvent(event);
+}
+
+bool UIButton::OnReleaseEvent(const ReleaseEvent& event)
+{
+ currentImgSrc_ = ButtonImageSrc::BTN_IMAGE_DEFAULT;
+ SetState(RELEASED);
+ Resize(contentWidth_, contentHeight_);
+ Invalidate();
+ return UIView::OnReleaseEvent(event);
+}
+
+bool UIButton::OnCancelEvent(const CancelEvent& event)
+{
+ currentImgSrc_ = ButtonImageSrc::BTN_IMAGE_DEFAULT;
+ SetState(RELEASED);
+ Resize(contentWidth_, contentHeight_);
+ Invalidate();
+ return UIView::OnCancelEvent(event);
+}
+
+const Image* UIButton::GetCurImageSrc() const
+{
+ if (currentImgSrc_ == ButtonImageSrc::BTN_IMAGE_DEFAULT) {
+ return defaultImgSrc_;
+ } else if (currentImgSrc_ == ButtonImageSrc::BTN_IMAGE_TRIGGERED) {
+ return triggeredImgSrc_;
+ } else {
+ return nullptr;
+ }
+}
+
+void UIButton::SetImageSrc(const char* defaultImgSrc, const char* triggeredImgSrc)
+{
+ if (!InitImage()) {
+ return;
+ }
+ defaultImgSrc_->SetSrc(defaultImgSrc);
+ triggeredImgSrc_->SetSrc(triggeredImgSrc);
+}
+
+void UIButton::SetImageSrc(const ImageInfo* defaultImgSrc, const ImageInfo* triggeredImgSrc)
+{
+ if (!InitImage()) {
+ return;
+ }
+ defaultImgSrc_->SetSrc(defaultImgSrc);
+ triggeredImgSrc_->SetSrc(triggeredImgSrc);
+}
+
+void UIButton::Disable()
+{
+ SetState(INACTIVE);
+ touchable_ = false;
+}
+
+void UIButton::Enable()
+{
+ SetState(RELEASED);
+ touchable_ = true;
+}
+
+void UIButton::SetState(ButtonState state)
+{
+ state_ = state;
+ Invalidate();
+}
+
+bool UIButton::InitImage()
+{
+ if (defaultImgSrc_ == nullptr) {
+ defaultImgSrc_ = new Image();
+ if (defaultImgSrc_ == nullptr) {
+ GRAPHIC_LOGE("new Image fail");
+ return false;
+ }
+ }
+ if (triggeredImgSrc_ == nullptr) {
+ triggeredImgSrc_ = new Image();
+ if (triggeredImgSrc_ == nullptr) {
+ GRAPHIC_LOGE("new Image fail");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool UIButton::OnPreDraw(Rect& invalidatedArea) const
+{
+ Rect rect(GetRect());
+ int16_t r = buttonStyles_[styleState_]->borderRadius_;
+ if (r == COORD_MAX) {
+ return true;
+ }
+ if (r != 0) {
+ r = ((r & 0x1) == 0) ? (r >> 1) : ((r + 1) >> 1);
+ rect.SetLeft(rect.GetX() + r);
+ rect.SetWidth(rect.GetWidth() - r);
+ rect.SetTop(rect.GetY() + r);
+ rect.SetHeight(rect.GetHeight() - r);
+ }
+ if (rect.IsContains(invalidatedArea)) {
+ return true;
+ }
+ invalidatedArea.Intersect(invalidatedArea, rect);
+ return false;
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_canvas.cpp b/frameworks/components/ui_canvas.cpp
new file mode 100755
index 0000000..e7b52b8
--- /dev/null
+++ b/frameworks/components/ui_canvas.cpp
@@ -0,0 +1,807 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_canvas.h"
+#include "common/image.h"
+#include "draw/draw_arc.h"
+#include "draw/draw_curve.h"
+#include "draw/draw_image.h"
+#include "draw/draw_line.h"
+#include "draw/draw_rect.h"
+#include "graphic_log.h"
+
+namespace OHOS {
+UICanvas::UICanvasPath::~UICanvasPath()
+{
+ points_.Clear();
+ cmd_.Clear();
+ arcParam_.Clear();
+}
+
+void UICanvas::BeginPath()
+{
+ /* If the previous path is not added to the drawing linked list, it should be destroyed directly. */
+ if (path_ != nullptr && path_->strokeCount_ == 0) {
+ delete path_;
+ path_ = nullptr;
+ }
+
+ path_ = new UICanvasPath();
+ if (path_ == nullptr) {
+ GRAPHIC_LOGE("new UICanvasPath fail");
+ return;
+ }
+}
+
+void UICanvas::MoveTo(const Point& point)
+{
+ if (path_ == nullptr) {
+ return;
+ }
+
+ path_->startPos_ = point;
+ /* If the previous command is also CMD_MOVE_TO, the previous command is overwritten. */
+ if ((path_->cmd_.Size() != 0) && (path_->cmd_.Tail()->data_ == CMD_MOVE_TO)) {
+ path_->points_.Tail()->data_ = point;
+ return;
+ }
+ path_->points_.PushBack(point);
+ path_->cmd_.PushBack(CMD_MOVE_TO);
+}
+
+void UICanvas::LineTo(const Point& point)
+{
+ if (path_ == nullptr) {
+ return;
+ }
+
+ path_->points_.PushBack(point);
+ if (path_->cmd_.Size() == 0) {
+ path_->startPos_ = point;
+ path_->cmd_.PushBack(CMD_MOVE_TO);
+ } else {
+ path_->cmd_.PushBack(CMD_LINE_TO);
+ }
+}
+
+void UICanvas::ArcTo(const Point& center, uint16_t radius, int16_t startAngle, int16_t endAngle)
+{
+ if (path_ == nullptr) {
+ return;
+ }
+
+ /*
+ * If there is no command before CMD_ARC, only the arc is drawn. If there is a command in front of
+ * CMD_ARC, the start point of arc must be connected to the end point of the path.
+ */
+ float sinma = radius * Sin(startAngle);
+ float cosma = radius * Sin(QUARTER_IN_DEGREE - startAngle);
+ if (path_->cmd_.Size() != 0) {
+ path_->points_.PushBack({MATH_ROUND(center.x + sinma), MATH_ROUND(center.y - cosma)});
+ path_->cmd_.PushBack(CMD_LINE_TO);
+ } else {
+ path_->startPos_ = {MATH_ROUND(center.x + sinma), MATH_ROUND(center.y - cosma)};
+ }
+
+ /* If the ARC scan range exceeds 360 degrees, the end point of the path is the position of the start angle. */
+ if (MATH_ABS(startAngle - endAngle) < CIRCLE_IN_DEGREE) {
+ sinma = radius * Sin(endAngle);
+ cosma = radius * Sin(QUARTER_IN_DEGREE - endAngle);
+ }
+ path_->points_.PushBack({MATH_ROUND(center.x + sinma), MATH_ROUND(center.y - cosma)});
+ path_->cmd_.PushBack(CMD_ARC);
+
+ int16_t start;
+ int16_t end;
+ if (startAngle > endAngle) {
+ start = endAngle;
+ end = startAngle;
+ } else {
+ start = startAngle;
+ end = endAngle;
+ }
+
+ DrawArc::GetInstance()->GetDrawRange(start, end);
+ ArcParam param;
+ param.center = center;
+ param.radius = radius;
+ param.startAngle = start;
+ param.endAngle = end;
+ path_->arcParam_.PushBack(param);
+}
+
+void UICanvas::AddRect(const Point& point, int16_t height, int16_t width)
+{
+ if (path_ == nullptr) {
+ return;
+ }
+
+ MoveTo(point);
+ LineTo({static_cast(point.x + width), point.y});
+ LineTo({static_cast(point.x + width), static_cast(point.y + height)});
+ LineTo({point.x, static_cast(point.y + height)});
+ ClosePath();
+}
+
+void UICanvas::ClosePath()
+{
+ if ((path_ == nullptr) || (path_->cmd_.Size() == 0)) {
+ return;
+ }
+
+ path_->points_.PushBack(path_->startPos_);
+ path_->cmd_.PushBack(CMD_CLOSE);
+}
+
+UICanvas::~UICanvas()
+{
+ if ((path_ != nullptr) && (path_->strokeCount_ == 0)) {
+ delete path_;
+ path_ = nullptr;
+ }
+
+ void* param = nullptr;
+ ListNode* curDraw = drawCmdList_.Begin();
+ for (; curDraw != drawCmdList_.End(); curDraw = curDraw->next_) {
+ param = curDraw->data_.param;
+ curDraw->data_.DeleteParam(param);
+ curDraw->data_.param = nullptr;
+ }
+ drawCmdList_.Clear();
+}
+
+void UICanvas::Clear()
+{
+ if ((path_ != nullptr) && (path_->strokeCount_ == 0)) {
+ delete path_;
+ path_ = nullptr;
+ }
+
+ void* param = nullptr;
+ ListNode* curDraw = drawCmdList_.Begin();
+ for (; curDraw != drawCmdList_.End(); curDraw = curDraw->next_) {
+ param = curDraw->data_.param;
+ curDraw->data_.DeleteParam(param);
+ curDraw->data_.param = nullptr;
+ }
+ drawCmdList_.Clear();
+ Invalidate();
+}
+
+void UICanvas::DrawLine(const Point& endPoint, const Paint& paint)
+{
+ DrawLine(startPoint_, endPoint, paint);
+}
+
+void UICanvas::DrawLine(const Point& startPoint, const Point& endPoint, const Paint& paint)
+{
+ LineParam* lineParam = new LineParam;
+ if (lineParam == nullptr) {
+ GRAPHIC_LOGE("new LineParam fail");
+ return;
+ }
+ lineParam->start = startPoint;
+ lineParam->end = endPoint;
+
+ DrawCmd cmd;
+ cmd.paint = paint;
+ cmd.param = lineParam;
+ cmd.DeleteParam = DeleteLineParam;
+ cmd.DrawGraphics = DoDrawLine;
+ drawCmdList_.PushBack(cmd);
+
+ Invalidate();
+ SetStartPosition(endPoint);
+}
+
+void UICanvas::DrawCurve(const Point& control1, const Point& control2, const Point& endPoint, const Paint& paint)
+{
+ DrawCurve(startPoint_, control1, control2, endPoint, paint);
+}
+
+void UICanvas::DrawCurve(const Point& startPoint,
+ const Point& control1,
+ const Point& control2,
+ const Point& endPoint,
+ const Paint& paint)
+{
+ CurveParam* curveParam = new CurveParam;
+ if (curveParam == nullptr) {
+ GRAPHIC_LOGE("new CurveParam fail");
+ return;
+ }
+ curveParam->start = startPoint;
+ curveParam->control1 = control1;
+ curveParam->control2 = control2;
+ curveParam->end = endPoint;
+
+ DrawCmd cmd;
+ cmd.paint = paint;
+ if (paint.GetStrokeWidth() > MAX_CURVE_WIDTH) {
+ cmd.paint.SetStrokeWidth(MAX_CURVE_WIDTH);
+ }
+ cmd.param = curveParam;
+ cmd.DeleteParam = DeleteCurveParam;
+ cmd.DrawGraphics = DoDrawCurve;
+ drawCmdList_.PushBack(cmd);
+
+ Invalidate();
+ SetStartPosition(endPoint);
+}
+
+void UICanvas::DrawRect(const Point& startPoint, int16_t height, int16_t width, const Paint& paint)
+{
+ if (static_cast(paint.GetStyle()) & Paint::PaintStyle::STROKE_STYLE) {
+ RectParam* rectParam = new RectParam;
+ if (rectParam == nullptr) {
+ GRAPHIC_LOGE("new RectParam fail");
+ return;
+ }
+ rectParam->start = startPoint;
+ rectParam->height = height;
+ rectParam->width = width;
+
+ DrawCmd cmd;
+ cmd.paint = paint;
+ cmd.param = rectParam;
+ cmd.DeleteParam = DeleteRectParam;
+ cmd.DrawGraphics = DoDrawRect;
+ drawCmdList_.PushBack(cmd);
+ }
+
+ if (static_cast(paint.GetStyle()) & Paint::PaintStyle::FILL_STYLE) {
+ RectParam* rectParam = new RectParam;
+ if (rectParam == nullptr) {
+ GRAPHIC_LOGE("new RectParam fail");
+ return;
+ }
+ rectParam->start = startPoint;
+ rectParam->height = height;
+ rectParam->width = width;
+
+ DrawCmd cmd;
+ cmd.paint = paint;
+ cmd.param = rectParam;
+ cmd.DeleteParam = DeleteRectParam;
+ cmd.DrawGraphics = DoFillRect;
+ drawCmdList_.PushBack(cmd);
+ }
+
+ Invalidate();
+}
+
+void UICanvas::DrawCircle(const Point& center, uint16_t radius, const Paint& paint)
+{
+ CircleParam* circleParam = new CircleParam;
+ if (circleParam == nullptr) {
+ GRAPHIC_LOGE("new CircleParam fail");
+ return;
+ }
+ circleParam->center = center;
+ circleParam->radius = radius;
+
+ DrawCmd cmd;
+ cmd.paint = paint;
+ cmd.param = circleParam;
+ cmd.DeleteParam = DeleteCircleParam;
+ cmd.DrawGraphics = DoDrawCircle;
+ drawCmdList_.PushBack(cmd);
+
+ Invalidate();
+}
+
+void UICanvas::DrawSector(const Point& center,
+ uint16_t radius,
+ int16_t startAngle,
+ int16_t endAngle,
+ const Paint& paint)
+{
+ if (static_cast(paint.GetStyle()) & Paint::PaintStyle::FILL_STYLE) {
+ Paint innerPaint = paint;
+ innerPaint.SetStyle(Paint::PaintStyle::STROKE_STYLE);
+ innerPaint.SetStrokeWidth(radius);
+ innerPaint.SetStrokeColor(paint.GetFillColor());
+ radius >>= 1;
+ DrawArc(center, radius, startAngle, endAngle, innerPaint);
+ }
+}
+
+void UICanvas::DrawArc(const Point& center, uint16_t radius, int16_t startAngle, int16_t endAngle, const Paint& paint)
+{
+ if (static_cast(paint.GetStyle()) & Paint::PaintStyle::STROKE_STYLE) {
+ ArcParam* arcParam = new ArcParam;
+ if (arcParam == nullptr) {
+ GRAPHIC_LOGE("new ArcParam fail");
+ return;
+ }
+ arcParam->center = center;
+ arcParam->radius = radius;
+
+ int16_t start;
+ int16_t end;
+ if (startAngle > endAngle) {
+ start = endAngle;
+ end = startAngle;
+ } else {
+ start = startAngle;
+ end = endAngle;
+ }
+
+ DrawArc::GetInstance()->GetDrawRange(start, end);
+ arcParam->startAngle = start;
+ arcParam->endAngle = end;
+
+ DrawCmd cmd;
+ cmd.paint = paint;
+ cmd.param = arcParam;
+ cmd.DeleteParam = DeleteArcParam;
+ cmd.DrawGraphics = DoDrawArc;
+ drawCmdList_.PushBack(cmd);
+
+ Invalidate();
+ }
+}
+
+void UICanvas::DrawLabel(const Point& startPoint,
+ const char* text,
+ uint16_t maxWidth,
+ const FontStyle& fontStyle,
+ const Paint& paint)
+{
+ if (text == nullptr) {
+ return;
+ }
+ if (static_cast(paint.GetStyle()) & Paint::PaintStyle::FILL_STYLE) {
+ UILabel* label = new UILabel();
+ if (label == nullptr) {
+ GRAPHIC_LOGE("new UILabel fail");
+ return;
+ }
+ label->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
+ label->SetPosition(startPoint.x, startPoint.y);
+ label->SetWidth(maxWidth);
+ label->SetHeight(GetHeight());
+ label->SetText(text);
+ label->SetFont(fontStyle.fontName, fontStyle.fontSize);
+ label->SetAlign(fontStyle.align);
+ label->SetDirect(fontStyle.direct);
+ label->SetStyle(STYLE_LETTER_SPACE, fontStyle.letterSpace);
+ label->SetStyle(STYLE_TEXT_COLOR, paint.GetFillColor().full);
+ label->SetStyle(STYLE_TEXT_OPA, paint.GetOpacity());
+
+ DrawCmd cmd;
+ cmd.param = label;
+ cmd.DeleteParam = DeleteLabel;
+ cmd.DrawGraphics = DoDrawLabel;
+ drawCmdList_.PushBack(cmd);
+
+ Invalidate();
+ }
+}
+
+void UICanvas::DrawImage(const Point& startPoint, const char* image, const Paint& paint)
+{
+ if (image == nullptr) {
+ return;
+ }
+
+ ImageParam* imageParam = new ImageParam;
+ if (imageParam == nullptr) {
+ GRAPHIC_LOGE("new ImageParam fail");
+ return;
+ }
+ imageParam->image = new Image();
+ if (imageParam->image == nullptr) {
+ delete imageParam;
+ imageParam = nullptr;
+ return;
+ }
+
+ imageParam->image->SetSrc(image);
+ ImageHeader header = {0};
+ imageParam->image->GetHeader(header);
+ imageParam->start = startPoint;
+ imageParam->height = header.height;
+ imageParam->width = header.width;
+
+ DrawCmd cmd;
+ cmd.paint = paint;
+ cmd.param = imageParam;
+ cmd.DeleteParam = DeleteImageParam;
+ cmd.DrawGraphics = DoDrawImage;
+ drawCmdList_.PushBack(cmd);
+
+ Invalidate();
+}
+
+void UICanvas::DrawPath(const Paint& paint)
+{
+ if ((path_ == nullptr) || (path_->cmd_.Size() == 0)) {
+ return;
+ }
+
+ path_->strokeCount_++;
+ PathParam* param = new PathParam;
+ if (param == nullptr) {
+ GRAPHIC_LOGE("new PathParam fail");
+ return;
+ }
+ param->path = path_;
+ param->count = path_->cmd_.Size();
+
+ DrawCmd cmd;
+ cmd.paint = paint;
+ cmd.param = param;
+ cmd.DeleteParam = DeletePathParam;
+ cmd.DrawGraphics = DoDrawPath;
+ drawCmdList_.PushBack(cmd);
+ Invalidate();
+}
+
+void UICanvas::OnDraw(const Rect& invalidatedArea)
+{
+ Rect rect = GetOrigRect();
+ DrawRect::Draw(rect, invalidatedArea, *style_, opaScale_);
+
+ void* param = nullptr;
+ ListNode* curDraw = drawCmdList_.Begin();
+ Rect coords = GetOrigRect();
+ Rect trunc = invalidatedArea;
+ if (trunc.Intersect(trunc, coords)) {
+ for (; curDraw != drawCmdList_.End(); curDraw = curDraw->next_) {
+ param = curDraw->data_.param;
+ curDraw->data_.DrawGraphics(param, curDraw->data_.paint, rect, trunc, *style_);
+ }
+ }
+}
+
+void UICanvas::GetAbsolutePosition(const Point& prePoint, const Rect& rect, const Style& style, Point& point)
+{
+ point.x = prePoint.x + rect.GetLeft() + style.paddingLeft_ + style.borderWidth_;
+ point.y = prePoint.y + rect.GetTop() + style.paddingTop_ + style.borderWidth_;
+}
+
+void UICanvas::DoDrawLine(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ LineParam* lineParam = static_cast(param);
+ Point start;
+ Point end;
+ GetAbsolutePosition(lineParam->start, rect, style, start);
+ GetAbsolutePosition(lineParam->end, rect, style, end);
+
+ DrawLine::Draw(start, end, invalidatedArea, paint.GetStrokeWidth(), paint.GetStrokeColor(), paint.GetOpacity());
+}
+
+void UICanvas::DoDrawCurve(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ CurveParam* curveParam = static_cast(param);
+ Point start;
+ Point end;
+ Point control1;
+ Point control2;
+ GetAbsolutePosition(curveParam->start, rect, style, start);
+ GetAbsolutePosition(curveParam->end, rect, style, end);
+ GetAbsolutePosition(curveParam->control1, rect, style, control1);
+ GetAbsolutePosition(curveParam->control2, rect, style, control2);
+
+ DrawCurve::DrawCubicBezier(start, control1, control2, end, invalidatedArea, paint.GetStrokeWidth(),
+ paint.GetStrokeColor(), paint.GetOpacity());
+}
+
+void UICanvas::DoDrawRect(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ RectParam* rectParam = static_cast(param);
+ Style drawStyle = StyleDefault::GetDefaultStyle();
+ drawStyle.bgColor_ = paint.GetStrokeColor();
+ drawStyle.bgOpa_ = paint.GetOpacity();
+ drawStyle.borderRadius_ = 0;
+
+ int16_t lineWidth = static_cast(paint.GetStrokeWidth());
+ Point start;
+ GetAbsolutePosition(rectParam->start, rect, style, start);
+
+ int16_t x = start.x - lineWidth / 2; // 2: half
+ int16_t y = start.y - lineWidth / 2; // 2: half
+ Rect coords;
+ if ((rectParam->height <= lineWidth) || (rectParam->width <= lineWidth)) {
+ coords.SetPosition(x, y);
+ coords.SetHeight(rectParam->height + lineWidth);
+ coords.SetWidth(rectParam->width + lineWidth);
+ DrawRect::Draw(coords, invalidatedArea, drawStyle, OPA_OPAQUE);
+ return;
+ }
+
+ coords.SetPosition(x, y);
+ coords.SetHeight(lineWidth);
+ coords.SetWidth(rectParam->width);
+ DrawRect::Draw(coords, invalidatedArea, drawStyle, OPA_OPAQUE);
+
+ coords.SetPosition(x + rectParam->width, y);
+ coords.SetHeight(rectParam->height);
+ coords.SetWidth(lineWidth);
+ DrawRect::Draw(coords, invalidatedArea, drawStyle, OPA_OPAQUE);
+
+ coords.SetPosition(x, y + lineWidth);
+ coords.SetHeight(rectParam->height);
+ coords.SetWidth(lineWidth);
+ DrawRect::Draw(coords, invalidatedArea, drawStyle, OPA_OPAQUE);
+
+ coords.SetPosition(x + lineWidth, y + rectParam->height);
+ coords.SetHeight(lineWidth);
+ coords.SetWidth(rectParam->width);
+ DrawRect::Draw(coords, invalidatedArea, drawStyle, OPA_OPAQUE);
+}
+
+void UICanvas::DoFillRect(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ RectParam* rectParam = static_cast(param);
+ uint8_t enableStroke = static_cast(paint.GetStyle()) & Paint::PaintStyle::STROKE_STYLE;
+ int16_t lineWidth = enableStroke ? paint.GetStrokeWidth() : 0;
+ if ((rectParam->height <= lineWidth) || (rectParam->width <= lineWidth)) {
+ return;
+ }
+ Point start;
+ GetAbsolutePosition(rectParam->start, rect, style, start);
+
+ Rect coords;
+ coords.SetPosition(start.x + (lineWidth + 1) / 2, start.y + (lineWidth + 1) / 2); // 2: half
+ coords.SetHeight(rectParam->height - lineWidth);
+ coords.SetWidth(rectParam->width - lineWidth);
+
+ Style drawStyle = StyleDefault::GetDefaultStyle();
+ drawStyle.bgColor_ = paint.GetFillColor();
+ drawStyle.bgOpa_ = paint.GetOpacity();
+ drawStyle.borderRadius_ = 0;
+ DrawRect::Draw(coords, invalidatedArea, drawStyle, OPA_OPAQUE);
+}
+
+void UICanvas::DoDrawCircle(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ CircleParam* circleParam = static_cast(param);
+
+ Style drawStyle = StyleDefault::GetDefaultStyle();
+ drawStyle.lineOpa_ = paint.GetOpacity();
+
+ ArcInfo arcInfo = {{0}};
+ arcInfo.imgPos = Point{0, 0};
+ arcInfo.startAngle = 0;
+ arcInfo.endAngle = CIRCLE_IN_DEGREE;
+ GetAbsolutePosition(circleParam->center, rect, style, arcInfo.center);
+ uint8_t enableStroke = static_cast(paint.GetStyle()) & Paint::PaintStyle::STROKE_STYLE;
+ uint16_t halfLineWidth = enableStroke ? (paint.GetStrokeWidth() >> 1) : 0;
+ if (static_cast(paint.GetStyle()) & Paint::PaintStyle::FILL_STYLE) {
+ arcInfo.radius = circleParam->radius - halfLineWidth;
+ drawStyle.lineWidth_ = arcInfo.radius;
+ drawStyle.lineColor_ = paint.GetFillColor();
+ DrawArc::GetInstance()->Draw(arcInfo, invalidatedArea, drawStyle, OPA_OPAQUE, CapType::CAP_NONE);
+ }
+
+ if (enableStroke) {
+ arcInfo.radius = circleParam->radius + halfLineWidth - 1;
+ drawStyle.lineWidth_ = static_cast(paint.GetStrokeWidth());
+ drawStyle.lineColor_ = paint.GetStrokeColor();
+ DrawArc::GetInstance()->Draw(arcInfo, invalidatedArea, drawStyle, OPA_OPAQUE, CapType::CAP_NONE);
+ }
+}
+
+void UICanvas::DoDrawArc(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ ArcParam* arcParam = static_cast(param);
+
+ ArcInfo arcInfo = {{0}};
+ arcInfo.imgPos = Point{0, 0};
+ arcInfo.startAngle = arcParam->startAngle;
+ arcInfo.endAngle = arcParam->endAngle;
+ Style drawStyle = StyleDefault::GetDefaultStyle();
+ drawStyle.lineWidth_ = static_cast(paint.GetStrokeWidth());
+ drawStyle.lineColor_ = paint.GetStrokeColor();
+ drawStyle.lineOpa_ = paint.GetOpacity();
+ arcInfo.radius = arcParam->radius + ((paint.GetStrokeWidth() + 1) >> 1);
+
+ GetAbsolutePosition(arcParam->center, rect, style, arcInfo.center);
+ DrawArc::GetInstance()->Draw(arcInfo, invalidatedArea, drawStyle, OPA_OPAQUE, CapType::CAP_NONE);
+}
+
+void UICanvas::DoDrawImage(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ ImageParam* imageParam = static_cast(param);
+
+ if (imageParam->image == nullptr) {
+ return;
+ }
+
+ Point start;
+ GetAbsolutePosition(imageParam->start, rect, style, start);
+
+ Rect cordsTmp;
+ cordsTmp.SetPosition(start.x, start.y);
+ cordsTmp.SetHeight(imageParam->height);
+ cordsTmp.SetWidth(imageParam->width);
+ DrawImage::DrawCommon(cordsTmp, invalidatedArea, imageParam->image->GetPath(), style, paint.GetOpacity());
+}
+
+void UICanvas::DoDrawLabel(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ UILabel* label = static_cast(param);
+ Point startPos = {label->GetX(), label->GetY()};
+ Point start;
+ GetAbsolutePosition({startPos.x, startPos.y}, rect, style, start);
+ label->SetPosition(start.x, start.y);
+ label->OnDraw(invalidatedArea);
+ label->SetPosition(startPos.x, startPos.y);
+}
+
+void UICanvas::DoDrawLineJoin(const Point& center, const Rect& invalidatedArea, const Paint& paint)
+{
+ ArcInfo arcinfo = {{0}};
+ arcinfo.center = center;
+ arcinfo.imgPos = Point{0, 0};
+ arcinfo.radius = (paint.GetStrokeWidth() + 1) >> 1;
+ arcinfo.startAngle = 0;
+ arcinfo.endAngle = CIRCLE_IN_DEGREE;
+
+ Style style;
+ style.lineColor_ = paint.GetStrokeColor();
+ style.lineWidth_ = static_cast(paint.GetStrokeWidth());
+ style.lineOpa_ = OPA_OPAQUE;
+ DrawArc::GetInstance()->Draw(arcinfo, invalidatedArea, style, OPA_OPAQUE, CapType::CAP_NONE);
+}
+
+void UICanvas::DoDrawPath(void* param,
+ const Paint& paint,
+ const Rect& rect,
+ const Rect& invalidatedArea,
+ const Style& style)
+{
+ if (param == nullptr) {
+ return;
+ }
+ PathParam* pathParam = static_cast(param);
+ const UICanvasPath* path = pathParam->path;
+ if (path == nullptr) {
+ return;
+ }
+ Point pathEnd = {COORD_MIN, COORD_MIN};
+
+ ListNode* pointIter = path->points_.Begin();
+ ListNode* arcIter = path->arcParam_.Begin();
+ ListNode* iter = path->cmd_.Begin();
+ for (uint16_t i = 0; (i < pathParam->count) && (iter != path->cmd_.End()); i++, iter = iter->next_) {
+ switch (iter->data_) {
+ case CMD_MOVE_TO: {
+ pointIter = pointIter->next_;
+ break;
+ }
+ case CMD_LINE_TO: {
+ Point start = pointIter->prev_->data_;
+ Point end = pointIter->data_;
+ pointIter = pointIter->next_;
+ if ((start.x == end.x) && (start.y == end.y)) {
+ break;
+ }
+
+ GetAbsolutePosition(start, rect, style, start);
+ GetAbsolutePosition(end, rect, style, end);
+ DrawLine::Draw(start, end, invalidatedArea, paint.GetStrokeWidth(), paint.GetStrokeColor(), OPA_OPAQUE);
+ if ((pathEnd.x == start.x) && (pathEnd.y == start.y)) {
+ DoDrawLineJoin(start, invalidatedArea, paint);
+ }
+ pathEnd = end;
+ break;
+ }
+ case CMD_ARC: {
+ ArcInfo arcInfo = {{0}};
+ arcInfo.imgPos = Point{0, 0};
+ arcInfo.startAngle = arcIter->data_.startAngle;
+ arcInfo.endAngle = arcIter->data_.endAngle;
+ Style drawStyle = StyleDefault::GetDefaultStyle();
+ drawStyle.lineWidth_ = static_cast(paint.GetStrokeWidth());
+ drawStyle.lineColor_ = paint.GetStrokeColor();
+ drawStyle.lineOpa_ = OPA_OPAQUE;
+ arcInfo.radius = arcIter->data_.radius + ((paint.GetStrokeWidth() + 1) >> 1);
+
+ GetAbsolutePosition(arcIter->data_.center, rect, style, arcInfo.center);
+ DrawArc::GetInstance()->Draw(arcInfo, invalidatedArea, drawStyle, OPA_OPAQUE, CapType::CAP_NONE);
+ if (pointIter != path->points_.Begin()) {
+ DoDrawLineJoin(pathEnd, invalidatedArea, paint);
+ }
+
+ GetAbsolutePosition(pointIter->data_, rect, style, pathEnd);
+ pointIter = pointIter->next_;
+ arcIter = arcIter->next_;
+ break;
+ }
+ case CMD_CLOSE: {
+ Point start = pointIter->prev_->data_;
+ Point end = pointIter->data_;
+ GetAbsolutePosition(start, rect, style, start);
+ GetAbsolutePosition(end, rect, style, end);
+ if ((start.x != end.x) || (start.y != end.y)) {
+ DrawLine::Draw(start, end, invalidatedArea, paint.GetStrokeWidth(), paint.GetStrokeColor(),
+ OPA_OPAQUE);
+ if ((pathEnd.x == start.x) && (pathEnd.y == start.y)) {
+ DoDrawLineJoin(start, invalidatedArea, paint);
+ }
+ pathEnd = end;
+ }
+
+ if ((pathEnd.x == end.x) && (pathEnd.y == end.y)) {
+ DoDrawLineJoin(end, invalidatedArea, paint);
+ }
+ pointIter = pointIter->next_;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_chart.cpp b/frameworks/components/ui_chart.cpp
new file mode 100755
index 0000000..7542645
--- /dev/null
+++ b/frameworks/components/ui_chart.cpp
@@ -0,0 +1,832 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_chart.h"
+#include "draw/draw_arc.h"
+#include "draw/draw_line.h"
+#include "securec.h"
+
+namespace OHOS {
+UIChart::~UIChart()
+{
+ if (mixData_ != nullptr) {
+ UIFree(mixData_);
+ mixData_ = nullptr;
+ }
+ ClearDataSerial();
+ Remove(&xAxis_);
+ Remove(&yAxis_);
+}
+
+void UIChart::SetHeight(int16_t height)
+{
+ if (GetHeight() == height) {
+ return;
+ }
+
+ if (height > 0) {
+ needRefresh_ = true;
+ }
+
+ UIViewGroup::SetHeight(height);
+ xAxis_.SetHeight(height);
+ xAxis_.UpdateAxis();
+ yAxis_.SetHeight(height);
+ yAxis_.UpdateAxis();
+}
+
+void UIChart::SetWidth(int16_t width)
+{
+ UIViewGroup::SetWidth(width);
+ xAxis_.SetWidth(width);
+ yAxis_.SetWidth(width);
+ xAxis_.UpdateAxis();
+ yAxis_.UpdateAxis();
+}
+
+void UIChart::OnDraw(const Rect& invalidatedArea)
+{
+ UIViewGroup::OnDraw(invalidatedArea);
+ Rect rect = GetContentRect();
+ if (rect.Intersect(rect, invalidatedArea)) {
+ DrawDataSerials(rect);
+ }
+}
+
+bool UIChart::AddDataSerial(UIChartDataSerial* dataSerial)
+{
+ if (dataSerial == nullptr) {
+ return false;
+ }
+
+ ListNode* serialNode = list_.Head();
+ while (serialNode != list_.End()) {
+ if (serialNode->data_ == dataSerial) {
+ return false;
+ }
+ serialNode = serialNode->next_;
+ }
+ list_.PushBack(dataSerial);
+ dataSerial->BindToChart(this);
+ return true;
+}
+
+bool UIChart::DeleteDataSerial(UIChartDataSerial* dataSerial)
+{
+ if ((dataSerial == nullptr) || list_.IsEmpty()) {
+ return false;
+ }
+
+ bool findSerial = false;
+ ListNode* serialNode = list_.Head();
+ while (serialNode != list_.End()) {
+ if (serialNode->data_ == dataSerial) {
+ dataSerial->BindToChart(nullptr);
+ list_.Remove(serialNode);
+ findSerial = true;
+ break;
+ }
+ serialNode = serialNode->next_;
+ }
+
+ return findSerial;
+}
+
+void UIChart::ClearDataSerial()
+{
+ if (list_.IsEmpty()) {
+ return;
+ }
+
+ ListNode* serialNode = list_.Head();
+ while (serialNode != list_.End()) {
+ serialNode->data_->BindToChart(nullptr);
+ ListNode* tempNode = serialNode;
+ serialNode = serialNode->next_;
+ list_.Remove(tempNode);
+ }
+ list_.Clear();
+}
+
+UIChartDataSerial::UIChartDataSerial()
+ : maxCount_(0),
+ pointArray_(nullptr),
+ serialColor_(Color::White()),
+ fillColor_(Color::White()),
+ dataCount_(0),
+ peakPointIndex_(0),
+ peakData_(0),
+ valleyData_(0),
+ valleyPointIndex_(0),
+ lastPointIndex_(0),
+ latestIndex_(0),
+ hideIndex_(0),
+ hideCount_(0),
+ smooth_(false),
+ enableGradient_(false),
+ enableHeadPoint_(false),
+ enableTopPoint_(false),
+ enableBottomPoint_(false),
+ chart_(nullptr),
+ invalidateRect_(0, 0, 0, 0)
+{
+ PointStyle style;
+ style.radius = DEFAULT_POINT_RADIUS;
+ style.strokeWidth = 1;
+ style.fillColor = Color::White();
+ style.strokeColor = Color::White();
+ topPointStyle_ = style;
+ bottomPointStyle_ = style;
+ headPointStyle_ = style;
+}
+
+bool UIChartDataSerial::SetMaxDataCount(uint16_t maxCount)
+{
+ if (maxCount > MAX_POINTS_COUNT) {
+ maxCount = MAX_POINTS_COUNT;
+ }
+
+ if (maxCount == maxCount_) {
+ return true;
+ }
+
+ if (pointArray_ != nullptr) {
+ UIFree(pointArray_);
+ pointArray_ = nullptr;
+ }
+
+ maxCount_ = maxCount;
+ if (maxCount_ == 0) {
+ return true;
+ }
+
+ pointArray_ = static_cast(UIMalloc(sizeof(Point) * maxCount_));
+ if (pointArray_ == nullptr) {
+ maxCount_ = 0;
+ return false;
+ }
+ return true;
+}
+
+bool UIChartDataSerial::ModifyPoint(uint16_t index, const Point& point)
+{
+ if ((index >= maxCount_) || (pointArray_ == nullptr)) {
+ return false;
+ }
+
+ pointArray_[index].x = point.x;
+ pointArray_[index].y = point.y;
+ if (point.y > peakData_) {
+ if (enableTopPoint_) {
+ RefreshInvalidateRect(peakPointIndex_, topPointStyle_);
+ }
+ peakPointIndex_ = index;
+ peakData_ = point.y;
+ } else if (point.y < valleyData_) {
+ if (enableBottomPoint_) {
+ RefreshInvalidateRect(valleyPointIndex_, bottomPointStyle_);
+ }
+ valleyPointIndex_ = index;
+ valleyData_ = point.y;
+ } else if ((index == peakPointIndex_) || (index == valleyPointIndex_)) {
+ UpdatePeakAndValley(0, dataCount_);
+ }
+
+ latestIndex_ = index;
+ uint16_t startIndex = (index == 0) ? index : (index - 1);
+ RefreshInvalidateRect(startIndex, index + 1);
+ return true;
+}
+
+bool UIChartDataSerial::GetPoint(uint16_t index, Point& point)
+{
+ if ((index >= dataCount_) || (pointArray_ == nullptr)) {
+ return false;
+ }
+ point = pointArray_[index];
+ if (chart_ != nullptr) {
+ chart_->GetXAxis().TranslateToPixel(point.x);
+ chart_->GetYAxis().TranslateToPixel(point.y);
+ }
+ return true;
+}
+
+void UIChartDataSerial::HidePoint(uint16_t index, uint16_t count)
+{
+ hideIndex_ = index;
+ hideCount_ = count;
+ RefreshInvalidateRect(hideIndex_, hideIndex_ + hideCount_);
+}
+
+void UIChartDataSerial::RefreshInvalidateRect(uint16_t pointIndex, const PointStyle& style)
+{
+ Point point;
+ if (GetPoint(pointIndex, point)) {
+ uint16_t width = style.radius + style.strokeWidth;
+ Rect refresh(point.x - width, 0, point.x + width, 0);
+ if ((invalidateRect_.GetLeft() == 0) && (invalidateRect_.GetRight() == 0)) {
+ invalidateRect_ = refresh;
+ } else {
+ invalidateRect_.Join(invalidateRect_, refresh);
+ }
+ }
+}
+
+void UIChartDataSerial::RefreshInvalidateRect(uint16_t startIndex, uint16_t endIndex)
+{
+ Point start;
+ GetPoint(startIndex, start);
+ Point end;
+ endIndex = (endIndex >= dataCount_) ? (dataCount_ - 1) : endIndex;
+ GetPoint(endIndex, end);
+ int16_t xMin = MATH_MIN(start.x, end.x);
+ int16_t xMax = MATH_MAX(start.x, end.x);
+ Rect refresh(xMin, 0, xMax, 0);
+ if ((invalidateRect_.GetLeft() == 0) && (invalidateRect_.GetRight() == 0)) {
+ invalidateRect_ = refresh;
+ return;
+ }
+ invalidateRect_.Join(invalidateRect_, refresh);
+}
+
+bool UIChartDataSerial::UpdatePeakAndValley(uint16_t startPos, uint16_t endPos)
+{
+ if ((startPos >= endPos) || (endPos > dataCount_) || (pointArray_ == nullptr)) {
+ return false;
+ }
+
+ if (startPos == 0) {
+ peakData_ = pointArray_[startPos].y;
+ valleyData_ = pointArray_[startPos].y;
+ }
+
+ for (uint16_t i = startPos; i < endPos; i++) {
+ if (pointArray_[i].y > peakData_) {
+ if (enableTopPoint_) {
+ RefreshInvalidateRect(peakPointIndex_, topPointStyle_);
+ RefreshInvalidateRect(i, topPointStyle_);
+ }
+ peakPointIndex_ = i;
+ peakData_ = pointArray_[i].y;
+ }
+
+ if (pointArray_[i].y < valleyData_) {
+ if (enableBottomPoint_) {
+ RefreshInvalidateRect(valleyPointIndex_, bottomPointStyle_);
+ RefreshInvalidateRect(i, bottomPointStyle_);
+ }
+ valleyPointIndex_ = i;
+ valleyData_ = pointArray_[i].y;
+ }
+ }
+ return true;
+}
+
+bool UIChartDataSerial::AddPoints(const Point* data, uint16_t count)
+{
+ if ((maxCount_ <= dataCount_) || (count == 0) || (pointArray_ == nullptr) || (data == nullptr)) {
+ return false;
+ }
+
+ if (count > (maxCount_ - dataCount_)) {
+ count = maxCount_ - dataCount_;
+ }
+
+ Point* current = pointArray_ + dataCount_;
+ if (memcpy_s(current, (maxCount_ - dataCount_) * sizeof(Point), data, count * sizeof(Point)) != EOK) {
+ return false;
+ }
+ uint16_t i = dataCount_;
+ dataCount_ += count;
+ UpdatePeakAndValley(i, dataCount_);
+ latestIndex_ = dataCount_ - 1;
+ uint16_t startIndex = (i == 0) ? i : (i - 1);
+ RefreshInvalidateRect(startIndex, latestIndex_);
+ return true;
+}
+
+void UIChartDataSerial::ClearData()
+{
+ RefreshInvalidateRect(0, dataCount_ - 1);
+ if (pointArray_ != nullptr) {
+ if (memset_s(pointArray_, maxCount_ * sizeof(Point), 0, maxCount_ * sizeof(Point)) != EOK) {
+ return;
+ }
+ }
+ dataCount_ = 0;
+ valleyPointIndex_ = 0;
+ peakPointIndex_ = 0;
+ latestIndex_ = 0;
+}
+
+void UIChartDataSerial::DoDrawPoint(const Point& center, const PointStyle& style, const Rect& mask)
+{
+ Style drawStyle = StyleDefault::GetDefaultStyle();
+ drawStyle.lineOpa_ = OPA_OPAQUE;
+ drawStyle.lineColor_ = style.fillColor;
+
+ ArcInfo arcinfo = {{0}};
+ arcinfo.center = center;
+ arcinfo.imgPos = Point{0, 0};
+ arcinfo.radius = style.radius + style.strokeWidth;
+ arcinfo.startAngle = 0;
+ arcinfo.endAngle = CIRCLE_IN_DEGREE;
+
+ if (style.fillColor.full == style.strokeColor.full) {
+ drawStyle.lineWidth_ = style.radius + style.strokeWidth;
+ DrawArc::GetInstance()->Draw(arcinfo, mask, drawStyle, OPA_OPAQUE, CapType::CAP_NONE);
+ return;
+ }
+ drawStyle.lineWidth_ = style.radius;
+ arcinfo.radius = style.radius;
+ DrawArc::GetInstance()->Draw(arcinfo, mask, drawStyle, OPA_OPAQUE, CapType::CAP_NONE);
+
+ drawStyle.lineWidth_ = style.strokeWidth;
+ drawStyle.lineColor_ = style.strokeColor;
+ arcinfo.radius = style.radius + style.strokeWidth;
+ DrawArc::GetInstance()->Draw(arcinfo, mask, drawStyle, OPA_OPAQUE, CapType::CAP_NONE);
+}
+
+void UIChartDataSerial::DrawPoint(const Rect& mask)
+{
+ Point center;
+ if (enableTopPoint_) {
+ if (GetPoint(peakPointIndex_, center)) {
+ DoDrawPoint(center, topPointStyle_, mask);
+ }
+ }
+
+ if (enableBottomPoint_) {
+ if (GetPoint(valleyPointIndex_, center)) {
+ DoDrawPoint(center, bottomPointStyle_, mask);
+ }
+ }
+
+ if (enableHeadPoint_) {
+ if (GetPoint(latestIndex_, center)) {
+ DoDrawPoint(center, headPointStyle_, mask);
+ lastPointIndex_ = latestIndex_;
+ }
+ }
+}
+
+void UIChartDataSerial::Refresh()
+{
+ if (chart_ != nullptr) {
+ Rect refresh = chart_->GetContentRect();
+ refresh.SetLeft(invalidateRect_.GetLeft() - headPointStyle_.radius - headPointStyle_.strokeWidth);
+ refresh.SetRight(invalidateRect_.GetRight() + headPointStyle_.radius + headPointStyle_.strokeWidth);
+ invalidateRect_.SetRect(0, 0, 0, 0);
+ chart_->InvalidateRect(refresh);
+
+ if (enableHeadPoint_ && (lastPointIndex_ != latestIndex_)) {
+ RefreshInvalidateRect(lastPointIndex_, headPointStyle_);
+ refresh.SetLeft(invalidateRect_.GetLeft());
+ refresh.SetRight(invalidateRect_.GetRight());
+ chart_->InvalidateRect(refresh);
+ invalidateRect_.SetRect(0, 0, 0, 0);
+ }
+ }
+}
+
+void UIChartPillar::RefreshChart()
+{
+ ListNode* iter = list_.Begin();
+ Rect rect = GetContentRect();
+ for (; iter != list_.End(); iter = iter->next_) {
+ UIChartDataSerial* data = iter->data_;
+ if (data == nullptr) {
+ break;
+ }
+ uint16_t dataCount = data->GetDataCount();
+ if (dataCount <= 1) {
+ break;
+ }
+
+ uint16_t index = data->GetLastPointIndex();
+ if (index >= dataCount) {
+ break;
+ }
+
+ Point current;
+ data->GetPoint(index, current);
+ Point last;
+ data->GetPoint(dataCount - 1, last);
+ Rect refresh(current.x, rect.GetTop(), last.x, rect.GetBottom());
+ InvalidateRect(refresh);
+ data->SetLastPointIndex(dataCount - 1);
+ }
+}
+
+void UIChartPillar::DrawDataSerials(const Rect& invalidatedArea)
+{
+ xAxis_.UpdateAxisPoints();
+ yAxis_.UpdateAxisPoints();
+ uint16_t minXStep = static_cast(xAxis_.GetMarkInterval());
+ Point xStart = xAxis_.GetStartPoint();
+ uint16_t dataSerialCount = list_.Size();
+ if (dataSerialCount == 0) {
+ return;
+ }
+ uint16_t width = minXStep / dataSerialCount;
+ uint8_t dataSerialIndex = 0;
+ uint16_t barWidth = static_cast(width - DEFAULT_MARK_PERCENTAGE * (width << 1));
+
+ for (ListNode* iter = list_.Begin(); iter != list_.End(); iter = iter->next_) {
+ UIChartDataSerial* data = iter->data_;
+ uint16_t dataSerialWidth = width * dataSerialIndex;
+ int16_t x = dataSerialWidth + (width >> 1);
+ for (uint16_t index = 0; index < data->GetDataCount(); index++) {
+ Point current;
+ data->GetPoint(index, current);
+ if (current.y == xStart.y) {
+ continue;
+ }
+ current.x += x;
+ xStart.x = current.x;
+ DrawLine::Draw(current, xStart, invalidatedArea, barWidth, data->GetFillColor(), style_->lineOpa_);
+ }
+ dataSerialIndex++;
+ }
+}
+
+void UIChartPolyline::RefreshChart()
+{
+ ListNode* iter = list_.Begin();
+ for (; iter != list_.End(); iter = iter->next_) {
+ UIChartDataSerial* data = iter->data_;
+ uint16_t dataCount = data->GetDataCount();
+ if (dataCount == 1) {
+ break;
+ }
+ data->Refresh();
+ }
+}
+
+void UIChartPolyline::ReMeasure()
+{
+ if (!needRefresh_) {
+ return;
+ }
+ needRefresh_ = false;
+ int16_t height = GetHeight();
+ if (mixData_ != nullptr) {
+ UIFree(mixData_);
+ mixData_ = nullptr;
+ }
+ if (height <= 0) {
+ return;
+ }
+ if (height > COORD_MAX) {
+ height = COORD_MAX;
+ }
+ mixData_ = static_cast(UIMalloc(height));
+ if (mixData_ == nullptr) {
+ return;
+ }
+ int16_t opa = maxOpa_ - minOpa_;
+ for (int16_t y = 0; y < height; y++) {
+ mixData_[y] = static_cast(y * opa / height + minOpa_);
+ }
+}
+
+void UIChartPolyline::DrawDataSerials(const Rect& invalidatedArea)
+{
+ xAxis_.UpdateAxisPoints();
+ yAxis_.UpdateAxisPoints();
+ ListNode* iter = list_.Begin();
+ for (; iter != list_.End(); iter = iter->next_) {
+ UIChartDataSerial* data = iter->data_;
+ uint16_t dataCount = data->GetDataCount();
+ if (dataCount <= 1) {
+ continue;
+ }
+ if (data->IsGradient()) {
+ GradientColor(invalidatedArea, data);
+ }
+ if (data->GetHideCount() != 0) {
+ uint16_t hideIndex = data->GetHideIndex();
+ DrawPolyLine(0, hideIndex, invalidatedArea, data);
+ DrawPolyLine(hideIndex + data->GetHideCount(), dataCount - 1, invalidatedArea, data);
+ } else {
+ DrawPolyLine(0, dataCount - 1, invalidatedArea, data);
+ }
+
+ data->DrawPoint(invalidatedArea);
+ }
+}
+
+void UIChartPolyline::DrawSmoothPolyLine(uint16_t startIndex,
+ uint16_t endIndex,
+ const Rect& invalidatedArea,
+ UIChartDataSerial* data)
+{
+ if (data == nullptr) {
+ return;
+ }
+ Point start;
+ Point end;
+ ColorType color = data->GetLineColor();
+ Style style = *style_;
+ style.lineColor_ = color;
+ style.lineOpa_ = OPA_OPAQUE;
+
+ uint16_t slope;
+ data->GetPoint(startIndex, start);
+ data->GetPoint(startIndex + 1, end);
+ uint16_t preSlope = (start.x == end.x) ? QUARTER_IN_DEGREE : FastAtan2(end.x - start.x, end.y - start.y);
+ Point current;
+ for (uint16_t i = startIndex; i < endIndex; i++) {
+ data->GetPoint(i + 1, current);
+ if (((end.y - start.y <= 0) && (current.y - end.y <= 0)) ||
+ ((end.y - start.y >= 0) && (current.y - end.y >= 0))) {
+ slope = (current.x == start.x) ? QUARTER_IN_DEGREE : FastAtan2(current.x - start.x, current.y - start.y);
+ if (MATH_ABS(slope - preSlope) < SMOOTH_SLOPE_ANGLE) {
+ end = current;
+ continue;
+ }
+ }
+ preSlope = (current.x == end.x) ? QUARTER_IN_DEGREE : FastAtan2(current.x - end.x, current.y - end.y);
+ Rect rect;
+ rect.SetLeft(MATH_MIN(start.x, end.x) - style_->lineWidth_);
+ rect.SetRight(MATH_MAX(start.x, end.x) + style_->lineWidth_);
+ rect.SetTop(MATH_MIN(start.y, end.y) - style_->lineWidth_);
+ rect.SetBottom(MATH_MAX(start.y, end.y) + style_->lineWidth_);
+ if (!invalidatedArea.IsIntersect(rect)) {
+ start = end;
+ end = current;
+ continue;
+ }
+
+ DrawLine::Draw(start, end, invalidatedArea, style_->lineWidth_, color, OPA_OPAQUE);
+ ArcInfo arcinfo = {{0}};
+ arcinfo.center = end;
+ arcinfo.imgPos = Point{0, 0};
+ arcinfo.radius = (style_->lineWidth_ + 1) >> 1;
+ arcinfo.startAngle = 0;
+ arcinfo.endAngle = CIRCLE_IN_DEGREE;
+
+ DrawArc::GetInstance()->Draw(arcinfo, invalidatedArea, style, OPA_OPAQUE, CapType::CAP_NONE);
+
+ start = end;
+ end = current;
+ }
+ DrawLine::Draw(start, end, invalidatedArea, style_->lineWidth_, color, OPA_OPAQUE);
+}
+
+void UIChartPolyline::DrawPolyLine(uint16_t startIndex,
+ uint16_t endIndex,
+ const Rect& invalidatedArea,
+ UIChartDataSerial* data)
+{
+ if ((startIndex >= endIndex) || (data == nullptr)) {
+ return;
+ }
+
+ if (data->IsSmooth()) {
+ DrawSmoothPolyLine(startIndex, endIndex, invalidatedArea, data);
+ return;
+ }
+ Point start;
+ Point end;
+ ColorType color = data->GetLineColor();
+ Style style = *style_;
+ style.lineColor_ = color;
+ style.lineOpa_ = OPA_OPAQUE;
+ ArcInfo arcinfo = {{0}};
+ arcinfo.imgPos = Point{0, 0};
+ arcinfo.radius = (style_->lineWidth_ + 1) >> 1;
+ arcinfo.startAngle = 0;
+ arcinfo.endAngle = CIRCLE_IN_DEGREE;
+ for (uint16_t i = startIndex; i < endIndex - 1; i++) {
+ data->GetPoint(i, start);
+ data->GetPoint(i + 1, end);
+ Rect rect;
+ rect.SetLeft(MATH_MIN(start.x, end.x) - style_->lineWidth_);
+ rect.SetRight(MATH_MAX(start.x, end.x) + style_->lineWidth_);
+ rect.SetTop(MATH_MIN(start.y, end.y) - style_->lineWidth_);
+ rect.SetBottom(MATH_MAX(start.y, end.y) + style_->lineWidth_);
+ if (!invalidatedArea.IsIntersect(rect)) {
+ continue;
+ }
+
+ DrawLine::Draw(start, end, invalidatedArea, style_->lineWidth_, color, OPA_OPAQUE);
+ if (style_->lineWidth_ >= LINE_JOIN_WIDTH) {
+ arcinfo.center = end;
+ DrawArc::GetInstance()->Draw(arcinfo, invalidatedArea, style, OPA_OPAQUE, CapType::CAP_NONE);
+ }
+ }
+ data->GetPoint(endIndex - 1, start);
+ data->GetPoint(endIndex, end);
+ DrawLine::Draw(start, end, invalidatedArea, style_->lineWidth_, color, OPA_OPAQUE);
+}
+
+bool UIChartPolyline::GetLineCrossPoint(const Point& p1,
+ const Point& p2,
+ const Point& p3,
+ const Point& p4,
+ Point& cross)
+{
+ /* Rectangular ranges of line segments must intersect. */
+ if ((MATH_MIN(p1.x, p2.x) <= MATH_MAX(p3.x, p4.x)) && (MATH_MIN(p3.x, p4.x) <= MATH_MAX(p1.x, p2.x)) &&
+ (MATH_MIN(p1.y, p2.y) <= MATH_MAX(p3.y, p4.y)) && (MATH_MIN(p3.y, p4.y) <= MATH_MAX(p1.y, p2.y))) {
+ /* Check whether the lines are parallel. If the lines are collinear, there is no intersection point. */
+ if ((p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y) != 0) {
+ /*
+ * (y1 - y2)x + (x2 - x1)y = x2y1 - x1y2 -> ax + by = c
+ * (y3 - y4)x + (x4 - x3)y = x4y3 - x3y4 -> dx + ey = f
+ */
+ int64_t a = p1.y - p2.y;
+ int64_t b = p2.x - p1.x;
+ int64_t c = p2.x * p1.y - p1.x * p2.y;
+ int64_t d = p3.y - p4.y;
+ int64_t e = p4.x - p3.x;
+ int64_t f = p4.x * p3.y - p3.x * p4.y;
+ int64_t left = a * e - b * d;
+ int64_t right = c * e - b * f;
+ if (left == 0) {
+ return false;
+ }
+ cross.x = static_cast(right / left);
+ left = b * d - a * e;
+ right = c * d - a * f;
+ if (left == 0) {
+ return false;
+ }
+ cross.y = static_cast(right / left);
+ if ((cross.x >= MATH_MIN(p1.x, p2.x)) && (cross.x <= MATH_MAX(p1.x, p2.x)) &&
+ (cross.x >= MATH_MIN(p3.x, p4.x)) && (cross.x <= MATH_MAX(p3.x, p4.x))) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void UIChartPolyline::FindCrossPoints(const ChartLine& line, const ChartLine& polyLine, CrossPointSet& cross)
+{
+ if (GetLineCrossPoint(line.start, line.end, polyLine.start, polyLine.end, cross.nextFirst)) {
+ if (!cross.firstFind) {
+ /* first corss must on the line like "/" */
+ if (polyLine.start.y < polyLine.end.y) {
+ cross.first = cross.nextFirst;
+ cross.firstFind = true;
+ }
+ } else if (!cross.secondFind) {
+ /* second corss can't be same with first cross. */
+ if ((cross.first.x != cross.nextFirst.x) || (cross.first.y != cross.nextFirst.y)) {
+ cross.second = cross.nextFirst;
+ cross.secondFind = true;
+ return;
+ }
+ /* second corss must on the line like "\", otherwise skip those crosss. */
+ if (polyLine.start.y > polyLine.end.y) {
+ cross.firstFind = false;
+ }
+ }
+ }
+}
+
+void UIChartPolyline::DrawGradientColor(const Rect& invalidatedArea,
+ UIChartDataSerial* data,
+ const ChartLine& linePoints,
+ const ChartLine& limitPoints,
+ int16_t startY)
+{
+ if (data == nullptr) {
+ return;
+ }
+ Rect currentRect = GetContentRect();
+ CrossPointSet cross = {{0}};
+ ChartLine polyLine = {{0}};
+ uint16_t pointCount = data->GetDataCount() - 1;
+ int16_t y = enableReverse_ ? (linePoints.start.y + startY) : (startY - linePoints.start.y);
+ int16_t mixScale = !enableReverse_ ? (currentRect.GetBottom() - y) : (y - currentRect.GetTop());
+ if ((mixScale < 0) || (mixScale >= currentRect.GetHeight())) {
+ return;
+ }
+ bool onVerticalLine = enableReverse_ ? (y <= limitPoints.start.y) : (y >= limitPoints.start.y);
+ if (onVerticalLine) {
+ cross.first.x = limitPoints.start.x;
+ cross.first.y = enableReverse_ ? (y - startY) : (startY - y);
+ cross.firstFind = true;
+ }
+
+ Point start;
+ Point end;
+ for (uint16_t i = 0; i < pointCount; i++) {
+ data->GetPoint(i, start);
+ data->GetPoint(i + 1, end);
+ if (start.y == end.y) {
+ int16_t tmpY = enableReverse_ ? (start.y + startY) : (startY - start.y);
+ if (tmpY == linePoints.start.y) {
+ cross.firstFind = false;
+ cross.secondFind = false;
+ }
+ continue;
+ }
+ start.y = enableReverse_ ? (start.y - startY) : (startY - start.y);
+ end.y = enableReverse_ ? (end.y - startY) : (startY - end.y);
+ polyLine.start = start;
+ polyLine.end = end;
+ FindCrossPoints(linePoints, polyLine, cross);
+ if (cross.firstFind && cross.secondFind) {
+ cross.first.y = enableReverse_ ? (cross.first.y + startY) : (startY - cross.first.y);
+ cross.second.y = enableReverse_ ? (cross.second.y + startY) : (startY - cross.second.y);
+ DrawLine::Draw(cross.first, cross.second, invalidatedArea, 1, data->GetFillColor(), mixData_[mixScale]);
+ cross.firstFind = false;
+ cross.secondFind = false;
+ }
+ }
+
+ if (cross.firstFind && !cross.secondFind) {
+ cross.second.x = limitPoints.end.x;
+ cross.second.y = y;
+ cross.first.y = y;
+ DrawLine::Draw(cross.first, cross.second, invalidatedArea, 1, data->GetFillColor(), mixData_[mixScale]);
+ }
+}
+
+void UIChartPolyline::CalcVerticalInfo(int16_t top,
+ int16_t bottom,
+ int16_t start,
+ int16_t end,
+ int16_t& y,
+ int16_t& yHeight)
+{
+ if ((top < start) && (bottom > start)) {
+ y = start;
+ yHeight = top;
+ } else if ((bottom <= start) && (top >= end)) {
+ y = bottom;
+ yHeight = top;
+ } else if ((top < end) && (bottom > end)) {
+ y = bottom;
+ yHeight = end;
+ }
+}
+
+void UIChartPolyline::GradientColor(const Rect& invalidatedArea, UIChartDataSerial* data)
+{
+ if (data == nullptr) {
+ return;
+ }
+ int16_t bottom = invalidatedArea.GetBottom();
+ int16_t top = invalidatedArea.GetTop();
+ Point yStart = yAxis_.GetStartPoint();
+ yStart.y = enableReverse_ ? (yStart.y + gradientBottom_) : (yStart.y - gradientBottom_);
+ int16_t topY = enableReverse_ ? data->GetValleyData() : data->GetPeakData();
+ int16_t bottomY = enableReverse_ ? data->GetPeakData() : data->GetValleyData();
+ yAxis_.TranslateToPixel(topY);
+ yAxis_.TranslateToPixel(bottomY);
+ int16_t valleyY = enableReverse_ ? topY : bottomY;
+ int16_t startY = enableReverse_ ? topY : yStart.y;
+ int16_t endY = enableReverse_ ? yStart.y : topY;
+ if ((bottom < endY) || (top > startY)) {
+ return;
+ }
+
+ int16_t y = 0;
+ int16_t yHeight = 0;
+ CalcVerticalInfo(top, bottom, startY, endY, y, yHeight);
+
+ ChartLine limitPoints = {{0}};
+ data->GetPoint(0, limitPoints.start);
+ data->GetPoint(data->GetDataCount() - 1, limitPoints.end);
+ ChartLine linePoints = {{0}};
+ linePoints.start.x = limitPoints.start.x;
+ linePoints.end.x = limitPoints.end.x;
+ Rect currentRect = GetContentRect();
+ while (y >= yHeight) {
+ linePoints.start.y = enableReverse_ ? (y - endY) : (startY - y);
+ linePoints.end.y = linePoints.start.y;
+ if (y <= valleyY) {
+ int16_t baseY = enableReverse_ ? endY : startY;
+ DrawGradientColor(invalidatedArea, data, linePoints, limitPoints, baseY);
+ } else {
+ int16_t mixScale = enableReverse_ ? (linePoints.start.y + endY - currentRect.GetTop()) :
+ (currentRect.GetBottom() - (startY - linePoints.start.y));
+ if ((mixScale < 0) || (mixScale >= currentRect.GetHeight())) {
+ y--;
+ continue;
+ }
+ Point start = {limitPoints.start.x, y};
+ Point end = {limitPoints.end.x, y};
+ DrawLine::Draw(start, end, invalidatedArea, 1, data->GetFillColor(), mixData_[mixScale]);
+ }
+ y--;
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_checkbox.cpp b/frameworks/components/ui_checkbox.cpp
new file mode 100755
index 0000000..aed4c14
--- /dev/null
+++ b/frameworks/components/ui_checkbox.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/image.h"
+#include "components/ui_checkbox.h"
+#include "default_resource/check_box_res.h"
+#include "draw/draw_image.h"
+#include "draw/draw_rect.h"
+#include "imgdecode/cache_manager.h"
+
+namespace OHOS {
+UICheckBox::UICheckBox()
+ : state_(UNSELECTED), onStateChangeListener_(nullptr)
+{
+ touchable_ = true;
+ style_ = &(StyleDefault::GetBackgroundTransparentStyle());
+ image_[UNSELECTED].SetSrc(GetCheckBoxOffInfo());
+ image_[SELECTED].SetSrc(GetCheckBoxOnInfo());
+ ImageHeader header = { 0 };
+ image_[UNSELECTED].GetHeader(header);
+ Resize(header.width, header.height);
+}
+
+UICheckBox::~UICheckBox()
+{
+}
+
+void UICheckBox::SetState(UICheckBoxState state)
+{
+ if (state != state_) {
+ state_ = state;
+ if (onStateChangeListener_ != nullptr) {
+ onStateChangeListener_->OnChange(state);
+ }
+ Invalidate();
+ }
+}
+
+void UICheckBox::ReverseState()
+{
+ state_ = (state_ == SELECTED) ? UNSELECTED : SELECTED;
+}
+
+bool UICheckBox::OnClickEvent(const ClickEvent& event)
+{
+ ReverseState();
+ Invalidate();
+ return UIView::OnClickEvent(event);
+}
+
+void UICheckBox::SetImages(const char* selectedImageSrc, const char* unselectedImageSrc)
+{
+ image_[SELECTED].SetSrc(selectedImageSrc);
+ image_[UNSELECTED].SetSrc(unselectedImageSrc);
+}
+
+void UICheckBox::SetImages(const ImageInfo* selectedImageSrc, const ImageInfo* unselectedImageSrc)
+{
+ image_[SELECTED].SetSrc(selectedImageSrc);
+ image_[UNSELECTED].SetSrc(unselectedImageSrc);
+}
+
+void UICheckBox::OnDraw(const Rect& invalidatedArea)
+{
+ ImageHeader header = {0};
+ image_[state_].GetHeader(header);
+ int16_t imgWidth = header.width;
+ int16_t imgHeight = header.height;
+ Rect coords = GetContentRect();
+ coords.SetWidth(imgWidth);
+ coords.SetHeight(imgHeight);
+ DrawRect::Draw(GetRect(), invalidatedArea, *style_, opaScale_);
+
+ int16_t offsetLeft = (GetWidth() - imgWidth) / 2; // 2 : half
+ int16_t offsetTop = (GetHeight() - imgHeight) / 2; // 2 : half
+ coords.SetX(coords.GetX() + offsetLeft);
+ coords.SetY(coords.GetY() + offsetTop);
+ Rect trunc = invalidatedArea;
+ if (trunc.Intersect(trunc, coords)) {
+ image_[state_].DrawImage(coords, trunc, *style_, opaScale_);
+ }
+}
+} // namespace OHOS
diff --git a/frameworks/components/ui_circle_progress.cpp b/frameworks/components/ui_circle_progress.cpp
new file mode 100755
index 0000000..59a2ec0
--- /dev/null
+++ b/frameworks/components/ui_circle_progress.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_circle_progress.h"
+#include "draw/draw_arc.h"
+#include "draw/draw_line.h"
+#include "draw/draw_rect.h"
+
+namespace OHOS {
+UICircleProgress::UICircleProgress()
+ : center_({0, 0}),
+ backgroundImagePos_({0, 0}),
+ progressImagePos_({0, 0}),
+ radius_(0),
+ startAngle_(MIN_ANGLE_VALUE),
+ endAngle_(MAX_ANGLE_VALUE)
+{
+}
+
+void UICircleProgress::SetCenterPosition(int16_t x, int16_t y)
+{
+ center_.x = x;
+ center_.y = y;
+}
+
+void UICircleProgress::SetStartAngle(int16_t startAngle)
+{
+ startAngle_ = startAngle;
+}
+
+void UICircleProgress::SetEndAngle(int16_t endAngle)
+{
+ endAngle_ = endAngle;
+}
+
+void UICircleProgress::GetStartEndAngle(int16_t& start, int16_t& end) const
+{
+ if (startAngle_ > endAngle_) {
+ start = endAngle_;
+ end = startAngle_;
+ } else {
+ start = startAngle_;
+ end = endAngle_;
+ }
+}
+
+void UICircleProgress::GetAngleRange(int16_t& start, int16_t& end) const
+{
+ GetStartEndAngle(start, end);
+ DrawArc::GetInstance()->GetDrawRange(start, end);
+}
+
+void UICircleProgress::GetRedrawAngle(int16_t& start, int16_t& end) const
+{
+ GetStartEndAngle(start, end);
+
+ if (startAngle_ == endAngle_) {
+ return;
+ }
+
+ int16_t angleRange = end - start;
+ angleRange = (angleRange > CIRCLE_IN_DEGREE) ? CIRCLE_IN_DEGREE : angleRange;
+
+ int16_t angle = GetCurrentPos(angleRange);
+ if (startAngle_ > endAngle_) {
+ start = end - angle;
+ } else {
+ end = angle + start;
+ }
+ DrawArc::GetInstance()->GetDrawRange(start, end);
+}
+
+void UICircleProgress::DrawCommonCircle(const Rect& invalidatedArea)
+{
+ ArcInfo arcinfo = {{0}};
+ arcinfo.radius = radius_;
+ int16_t endAngle;
+ int16_t startAngle;
+ GetRedrawAngle(startAngle, endAngle);
+
+ int16_t start;
+ int16_t end;
+ GetAngleRange(start, end);
+ Rect rect = GetOrigRect();
+ arcinfo.center.x = center_.x + rect.GetLeft() + style_->paddingLeft_ + style_->borderWidth_;
+ arcinfo.center.y = center_.y + rect.GetTop() + style_->paddingTop_ + style_->borderWidth_;
+
+ if (enableBackground_ && ((start != end) || (backgroundStyle_->lineCap_ == CapType::CAP_ROUND))) {
+ arcinfo.imgPos.x = backgroundImagePos_.x + rect.GetLeft();
+ arcinfo.imgPos.y = backgroundImagePos_.y + rect.GetTop();
+ arcinfo.startAngle = start;
+ arcinfo.endAngle = end;
+ arcinfo.imgSrc = backgroundImage_;
+ DrawArc::GetInstance()->Draw(arcinfo, invalidatedArea, *backgroundStyle_, opaScale_,
+ backgroundStyle_->lineCap_);
+ }
+
+ if ((startAngle != endAngle) || (foregroundStyle_->lineCap_ == CapType::CAP_ROUND)) {
+ arcinfo.imgPos.x = progressImagePos_.x + rect.GetLeft();
+ arcinfo.imgPos.y = progressImagePos_.y + rect.GetTop();
+ arcinfo.startAngle = startAngle;
+ arcinfo.endAngle = endAngle;
+ arcinfo.imgSrc = foregroundImage_;
+ DrawArc::GetInstance()->Draw(arcinfo, invalidatedArea, *foregroundStyle_, opaScale_,
+ foregroundStyle_->lineCap_);
+ }
+}
+
+void UICircleProgress::OnDraw(const Rect& invalidatedArea)
+{
+ if (GetRangeSize() == 0) {
+ return;
+ }
+
+ DrawRect::Draw(GetOrigRect(), invalidatedArea, *style_, opaScale_);
+
+ Rect trunc(invalidatedArea);
+ if (trunc.Intersect(trunc, GetOrigRect())) {
+ DrawCommonCircle(trunc);
+ }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_dialog.cpp b/frameworks/components/ui_dialog.cpp
new file mode 100755
index 0000000..8bb8d5b
--- /dev/null
+++ b/frameworks/components/ui_dialog.cpp
@@ -0,0 +1,694 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_dialog.h"
+#include "common/screen.h"
+#include "common/typed_text.h"
+#if ENABLE_DEBUG
+#include "graphic_assert.h"
+#endif
+#include "graphic_log.h"
+#if ENABLE_WINDOW
+#include "window/window.h"
+#endif
+
+#if ENABLE_WINDOW
+namespace OHOS {
+class UIDialogLabelButton : public UILabelButton {
+public:
+ UIDialogLabelButton(UIDialog* dialog)
+ {
+ dialog_ = dialog;
+ }
+ virtual ~UIDialogLabelButton() {}
+ virtual bool OnClickEvent(const ClickEvent& event)
+ {
+ bool ret = true;
+ if (dialog_ != nullptr) {
+ dialog_->DestoryWindow();
+ dialog_->isShowing_ = false;
+ }
+ if (onClickListener_ != nullptr) {
+ ret = onClickListener_->OnClick(*this, event);
+ }
+ return ret;
+ }
+private:
+ UIDialog* dialog_;
+};
+
+class UIDialogClickListener : public UIView::OnClickListener {
+public:
+ UIDialogClickListener(UIDialog* dialog)
+ {
+ dialog_ = dialog;
+ }
+ virtual ~UIDialogClickListener() {}
+ bool OnClick(UIView& view, const ClickEvent& event) override
+ {
+ bool ret = true;
+ if ((dialog_ != nullptr) && (dialog_->dialogLayer_ != nullptr) &&
+ !dialog_->dialogLayer_->GetRect().IsContains(event.GetCurrentPos())) {
+ if (dialog_->enableAutoCancel_) {
+ dialog_->DestoryWindow();
+ dialog_->isShowing_ = false;
+ }
+ if (dialog_->onCancelListener_ != nullptr) {
+ ret = dialog_->onCancelListener_->OnClick(view, event);
+ }
+ }
+ return ret;
+ }
+private:
+ UIDialog* dialog_;
+};
+
+UIDialog::UIDialog()
+ : isShowing_(false),
+ enableAutoCancel_(false),
+ buttonNum_(0),
+ title_(nullptr),
+ text_(nullptr),
+ button1_(nullptr),
+ button2_(nullptr),
+ button3_(nullptr),
+ dialogLayer_(nullptr),
+ windowRootView_(nullptr),
+ onCancelListener_(nullptr),
+ dialogClickListener_(nullptr),
+ window_(nullptr),
+ line1_(nullptr),
+ line2_(nullptr),
+ titleText_(nullptr),
+ textText_(nullptr)
+{
+ uint16_t screenWidth = Screen::GetInstance().GetWidth();
+ uint16_t screenHeight = Screen::GetInstance().GetHeight();
+ // 100: calculate percentage
+ widthMax_ = screenWidth * MAX_WIDTH_PERCENT / 100;
+ // 100: calculate percentage
+ heightMax_ = screenHeight * MAX_HEIGHT_PERCENT / 100;
+ colorType1_ = Color::White();
+ colorType2_ = Color::White();
+ colorType3_ = Color::White();
+}
+
+UIDialog::~UIDialog()
+{
+ onCancelListener_ = nullptr;
+ if (dialogLayer_ != nullptr) {
+ dialogLayer_->RemoveAll();
+ delete dialogLayer_;
+ dialogLayer_ = nullptr;
+ }
+ if (title_ != nullptr) {
+ delete title_;
+ title_ = nullptr;
+ }
+ if (text_ != nullptr) {
+ delete text_;
+ text_ = nullptr;
+ }
+ if (button1_ != nullptr) {
+ delete button1_;
+ button1_ = nullptr;
+ }
+ if (button2_ != nullptr) {
+ delete button2_;
+ button2_ = nullptr;
+ }
+ if (button3_ != nullptr) {
+ delete button3_;
+ button3_ = nullptr;
+ }
+ if (line1_ != nullptr) {
+ delete line1_;
+ line1_ = nullptr;
+ }
+ if (line2_ != nullptr) {
+ delete line2_;
+ line2_ = nullptr;
+ }
+ if ((windowRootView_ != nullptr) && !RootView::DestoryWindowRootView(windowRootView_)) {
+ windowRootView_ = nullptr;
+ }
+ if (dialogClickListener_ != nullptr) {
+ delete dialogClickListener_;
+ dialogClickListener_ = nullptr;
+ }
+}
+
+void UIDialog::SetTitle(const char* title)
+{
+ if (title == nullptr) {
+ return;
+ }
+ titleText_ = title;
+}
+
+void UIDialog::SetText(const char* text)
+{
+ if (text == nullptr) {
+ return;
+ }
+ textText_ = text;
+}
+
+void UIDialog::SetButton(DialogButtonType buttonType, const char* text, UIView::OnClickListener* listener)
+{
+ switch (buttonType) {
+ case DialogButtonType::BUTTON_LEFT:
+ if (button1_ == nullptr) {
+ button1_ = new UIDialogLabelButton(this);
+ if (button1_ == nullptr) {
+ GRAPHIC_LOGE("new UIDialogLabelButton fail");
+ return;
+ }
+ button1_->SetViewId(BUTTON1_ID);
+ AddButton(buttonType, button1_, text, listener);
+ } else {
+ button1_->SetText(text);
+ button1_->SetOnClickListener(listener);
+ }
+ break;
+ case DialogButtonType::BUTTON_MID:
+ if (button2_ == nullptr) {
+ button2_ = new UIDialogLabelButton(this);
+ if (button2_ == nullptr) {
+ GRAPHIC_LOGE("new UIDialogLabelButton fail");
+ return;
+ }
+ button2_->SetViewId(BUTTON2_ID);
+ AddButton(buttonType, button2_, text, listener);
+ } else {
+ button2_->SetText(text);
+ button2_->SetOnClickListener(listener);
+ }
+ break;
+ case DialogButtonType::BUTTON_RIGHT:
+ if (button3_ == nullptr) {
+ button3_ = new UIDialogLabelButton(this);
+ if (button3_ == nullptr) {
+ GRAPHIC_LOGE("new UIDialogLabelButton fail");
+ return;
+ }
+ AddButton(buttonType, button3_, text, listener);
+ } else {
+ button3_->SetText(text);
+ button3_->SetOnClickListener(listener);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void UIDialog::AddButton(DialogButtonType buttonType,
+ UILabelButton* button,
+ const char* text,
+ UIView::OnClickListener* listener)
+{
+ buttonNum_++;
+ button->SetText(text);
+ button->SetOnClickListener(listener);
+ button->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_FONT_SIZE);
+ button->SetTextColor(Color::Blue());
+ button->SetStyleForState(STYLE_BACKGROUND_COLOR, Color::White().full, UIButton::ButtonState::RELEASED);
+ button->SetStyleForState(STYLE_BACKGROUND_COLOR, Color::Black().full, UIButton::ButtonState::PRESSED);
+ button->SetStyleForState(STYLE_BACKGROUND_OPA, BUTTON_PRESS_OPA, UIButton::ButtonState::PRESSED);
+ button->SetStyleForState(STYLE_BORDER_WIDTH, 0, UIButton::ButtonState::RELEASED);
+ button->SetStyleForState(STYLE_BORDER_WIDTH, 0, UIButton::ButtonState::PRESSED);
+ button->SetHeight(BUTTON_HEIGHT);
+}
+
+void UIDialog::Show()
+{
+ if (isShowing_) {
+ return;
+ }
+ SetTitleLabel();
+ SetTextLabel();
+ InitDialog();
+ AddComponents();
+ MeasureSize();
+ Layout();
+ CreateDialogWindow();
+ window_->Show();
+ isShowing_ = true;
+}
+
+void UIDialog::SetTitleLabel()
+{
+ if (titleText_ == nullptr) {
+ return;
+ }
+ if (title_ == nullptr) {
+ title_ = new UILabel();
+ if (title_ == nullptr) {
+ GRAPHIC_LOGE("new UILabel fail");
+ return;
+ }
+ title_->SetViewId(TITLE_ID);
+ title_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, TITLE_FONT_SIZE);
+ title_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT);
+ title_->SetStyle(STYLE_TEXT_COLOR, Color::Black().full);
+ title_->SetStyle(STYLE_TEXT_OPA, TITLE_TEXT_OPA);
+ title_->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+ }
+ title_->SetText(titleText_);
+}
+
+void UIDialog::SetTextLabel()
+{
+ if (textText_ == nullptr) {
+ return;
+ }
+ if (text_ == nullptr) {
+ text_ = new UILabel();
+ if (text_ == nullptr) {
+ GRAPHIC_LOGE("new UILabel fail");
+ return;
+ }
+ text_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, TEXT_FONT_SIZE);
+ text_->SetStyle(STYLE_TEXT_COLOR, Color::Black().full);
+ text_->SetStyle(STYLE_TEXT_OPA, TITLE_TEXT_OPA);
+ text_->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+ }
+ text_->SetText(textText_);
+}
+
+void UIDialog::InitDialog()
+{
+ if (dialogLayer_ == nullptr) {
+ dialogLayer_ = new UIViewGroup();
+ if (dialogLayer_ == nullptr) {
+ GRAPHIC_LOGE("new UIViewGroup fail");
+ return;
+ }
+ dialogLayer_->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+ }
+ if (windowRootView_ == nullptr) {
+ windowRootView_ = RootView::GetWindowRootView();
+ windowRootView_->SetWidth(Screen::GetInstance().GetWidth());
+ windowRootView_->SetHeight(Screen::GetInstance().GetHeight());
+ windowRootView_->SetTouchable(true);
+ windowRootView_->Add(dialogLayer_);
+ }
+ if (dialogClickListener_ == nullptr) {
+ dialogClickListener_ = new UIDialogClickListener(this);
+ if (dialogClickListener_ == nullptr) {
+ GRAPHIC_LOGE("new UIDialogClickListener fail");
+ return;
+ }
+ windowRootView_->SetOnClickListener(dialogClickListener_);
+ }
+}
+
+void UIDialog::AddComponents()
+{
+ if (title_ != nullptr) {
+ dialogLayer_->Add(title_);
+ }
+ if (text_ != nullptr) {
+ dialogLayer_->Add(text_);
+ }
+ if (button1_ != nullptr) {
+ dialogLayer_->Add(button1_);
+ }
+ if (button2_ != nullptr) {
+ dialogLayer_->Add(button2_);
+ }
+ if (button3_ != nullptr) {
+ dialogLayer_->Add(button3_);
+ }
+ if (buttonNum_ > 1) {
+ line1_ = new UIView();
+ if (line1_ == nullptr) {
+ GRAPHIC_LOGE("new UIView fail");
+ return;
+ }
+ line1_->SetHeight(LINE_HEIGHT);
+ line1_->SetWidth(LINE_WIDTH);
+ line1_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
+ line1_->SetStyle(STYLE_BACKGROUND_OPA, LINE_OPA);
+ dialogLayer_->Add(line1_);
+ }
+ if (buttonNum_ == 3) { // 3: three buttons
+ line2_ = new UIView();
+ if (line2_ == nullptr) {
+ GRAPHIC_LOGE("new UIView fail");
+ return;
+ }
+ line2_->SetHeight(LINE_HEIGHT);
+ line2_->SetWidth(LINE_WIDTH);
+ line2_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
+ line2_->SetStyle(STYLE_BACKGROUND_OPA, LINE_OPA);
+ dialogLayer_->Add(line2_);
+ }
+}
+
+void UIDialog::MeasureSize()
+{
+ uint16_t width = MeasureMaxWidth();
+ uint16_t height = 0;
+
+ if (buttonNum_ > 0) {
+ // 2: there are 2 paddings horizontally
+ uint16_t buttonWidth = (width - 2 * BUTTON_PADDING - (buttonNum_ - 1) * BUTTON_MID_PADDING) / buttonNum_;
+ // 2: there are 2 paddings horizontally
+ width = static_cast(buttonWidth) * buttonNum_ + (buttonNum_ - 1) * BUTTON_MID_PADDING +
+ 2 * BUTTON_PADDING;
+ height += BUTTON_TOTAL_HEIGHT;
+ height += TEXT_BUTTON_PADDING;
+ if (button1_ != nullptr) {
+ button1_->SetWidth(buttonWidth);
+ }
+ if (button2_ != nullptr) {
+ button2_->SetWidth(buttonWidth);
+ }
+ if (button3_ != nullptr) {
+ button3_->SetWidth(buttonWidth);
+ }
+ } else {
+ height += PADDING;
+ }
+
+ if (title_ != nullptr) {
+ title_->SetWidth(width - 2 * PADDING); // 2: there are 2 paddings horizontally
+ height += TITLE_TOTAL_HEIGHT;
+ } else {
+ height += PADDING;
+ }
+
+ if (text_ != nullptr) {
+ text_->SetWidth(width - 2 * PADDING); // 2: there are 2 paddings horizontally
+ uint16_t textHightMax = heightMax_ - height;
+ if (text_->GetTextHeight() < textHightMax) {
+ text_->SetHeight(text_->GetTextHeight());
+ } else {
+ text_->SetHeight(textHightMax);
+ text_->SetLineBreakMode(UILabel::LINE_BREAK_ELLIPSIS);
+ }
+ height += text_->GetHeight();
+ }
+
+ uint16_t dialogHeight = height;
+ dialogLayer_->SetHeight(dialogHeight);
+ dialogLayer_->SetWidth(width);
+}
+
+uint16_t UIDialog::MeasureMaxWidth()
+{
+ uint16_t titleWidth = 0;
+ uint16_t textWidth = 0;
+ uint16_t buttonTotalWidth = 0;
+
+ if (title_ != nullptr) {
+ titleWidth = MeasureTitleWidth();
+ titleWidth += 2 * PADDING; // 2: there are 2 paddings horizontally
+ }
+ if (text_ != nullptr) {
+ textWidth = MeasureTextWidth();
+ textWidth += 2 * PADDING; // 2: there are 2 paddings horizontally
+ }
+ if (buttonNum_ > 0) {
+ buttonTotalWidth =
+ static_cast(MeasureButtonWidth()) * buttonNum_ + (buttonNum_ - 1) * BUTTON_MID_PADDING;
+ buttonTotalWidth += 2 * BUTTON_PADDING; // 2: there are 2 paddings horizontally
+ }
+ return MATH_MAX(titleWidth, MATH_MAX(textWidth, buttonTotalWidth));
+}
+
+uint16_t UIDialog::MeasureTitleWidth()
+{
+ uint16_t titleWidth = 0;
+ uint16_t widthMaxNoPadding = widthMax_ - 2 * PADDING; // 2: there are 2 paddings horizontally
+ title_->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+ if (title_->GetTextWidth() > widthMaxNoPadding) {
+ titleWidth = widthMaxNoPadding;
+ title_->SetLineBreakMode(UILabel::LINE_BREAK_ELLIPSIS);
+ } else {
+ titleWidth = title_->GetTextWidth();
+ }
+ title_->SetHeight(title_->GetTextHeight());
+ return titleWidth;
+}
+
+uint16_t UIDialog::MeasureTextWidth()
+{
+ uint16_t textWidth = 0;
+ uint16_t widthMaxNoPadding = widthMax_ - 2 * PADDING; // 2: there are 2 paddings horizontally
+ if (title_ != nullptr) {
+ text_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT);
+ } else {
+ text_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_CENTER);
+ }
+ text_->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+ textWidth = text_->GetTextWidth();
+ if (text_->GetTextWidth() > widthMaxNoPadding) {
+ text_->SetAlign(UITextLanguageAlignment::TEXT_ALIGNMENT_LEFT);
+ textWidth = widthMaxNoPadding;
+ text_->SetLineBreakMode(UILabel::LINE_BREAK_WRAP);
+ }
+ return textWidth;
+}
+
+uint16_t UIDialog::MeasureButtonWidth()
+{
+ if (buttonNum_ == 0) {
+ return 0;
+ }
+
+ uint16_t buttonTextWidth = 0;
+ // 2: there are 2 paddings horizontally
+ uint16_t buttonMaxWidth = (widthMax_ - 2 * BUTTON_PADDING - (buttonNum_ - 1) * BUTTON_MID_PADDING) / buttonNum_;
+
+ if (button1_ != nullptr) {
+ const char* text1 = button1_->GetText();
+ buttonTextWidth = MATH_MAX(buttonTextWidth, TypedText::GetTextSize(text1,
+ button1_->GetStyleConst().letterSpace_, button1_->GetStyleConst().lineSpace_, widthMax_).x);
+ }
+ if (button2_ != nullptr) {
+ const char* text2 = button2_->GetText();
+ buttonTextWidth = MATH_MAX(buttonTextWidth, TypedText::GetTextSize(text2,
+ button2_->GetStyleConst().letterSpace_, button2_->GetStyleConst().lineSpace_, widthMax_).x);
+ }
+ if (button3_ != nullptr) {
+ const char* text3 = button3_->GetText();
+ buttonTextWidth = MATH_MAX(buttonTextWidth, TypedText::GetTextSize(text3,
+ button3_->GetStyleConst().letterSpace_, button3_->GetStyleConst().lineSpace_, widthMax_).x);
+ }
+ return (buttonTextWidth + BUTTON_HEIGHT) > buttonMaxWidth ? buttonMaxWidth : (buttonTextWidth + BUTTON_HEIGHT);
+}
+
+void UIDialog::Layout()
+{
+ if (title_ != nullptr) {
+ // 2: there are 2 paddings vertically
+ uint8_t padding = (TITLE_TOTAL_HEIGHT - title_->GetHeight()) / 2;
+ title_->LayoutLeftOfParent(PADDING);
+ title_->LayoutTopOfParent(padding);
+ if (text_ != nullptr) {
+ text_->LayoutLeftOfParent(PADDING);
+ text_->LayoutBottomToSibling(TITLE_ID, padding);
+ }
+ } else {
+ if (text_ != nullptr) {
+ text_->LayoutLeftOfParent(PADDING);
+ text_->LayoutTopOfParent(PADDING);
+ }
+ }
+ LayoutButton();
+}
+
+void UIDialog::LayoutButton()
+{
+ if (button1_ != nullptr) {
+ button1_->LayoutLeftOfParent(BUTTON_PADDING);
+ button1_->LayoutBottomOfParent(BUTTON_PADDING);
+ if (button2_ != nullptr) {
+ button2_->LayoutRightToSibling(BUTTON1_ID, BUTTON_MID_PADDING);
+ button2_->LayoutBottomOfParent(BUTTON_PADDING);
+ }
+ } else if (button2_ != nullptr) {
+ button2_->LayoutLeftOfParent(BUTTON_PADDING);
+ button2_->LayoutBottomOfParent(BUTTON_PADDING);
+ }
+ if (button3_ != nullptr) {
+ button3_->LayoutRightOfParent(BUTTON_PADDING);
+ button3_->LayoutBottomOfParent(BUTTON_PADDING);
+ }
+
+ if (buttonNum_ == 3) { // 3: three buttons
+ line1_->LayoutBottomOfParent(LINE_BOTTOM_PADDING);
+ line1_->LayoutRightToSibling(BUTTON1_ID, LINE_BUTTON_PADDING);
+ line2_->LayoutBottomOfParent(LINE_BOTTOM_PADDING);
+ line2_->LayoutRightToSibling(BUTTON2_ID, LINE_BUTTON_PADDING);
+ } else if (buttonNum_ == 2) { // 2: two buttons
+ if (button1_ != nullptr) {
+ line1_->LayoutBottomOfParent(LINE_BOTTOM_PADDING);
+ line1_->LayoutRightToSibling(BUTTON1_ID, LINE_BUTTON_PADDING);
+ } else {
+ line1_->LayoutBottomOfParent(LINE_BOTTOM_PADDING);
+ line1_->LayoutRightToSibling(BUTTON2_ID, LINE_BUTTON_PADDING);
+ }
+ }
+}
+
+void UIDialog::CreateDialogWindow()
+{
+ dialogLayer_->LayoutCenterOfParent();
+ Rect rect = dialogLayer_->GetRect();
+ int16_t offset_x = dialogLayer_->GetX();
+ int16_t offset_y = dialogLayer_->GetY();
+
+ windowRootView_->SetPosition(-offset_x, -offset_y);
+ windowRootView_->Invalidate();
+
+ WindowConfig config = {};
+ config.rect = rect;
+ config.rect.SetPosition(offset_x, offset_y);
+ config.isModal = true;
+ window_ = Window::CreateWindow(config);
+ if (window_ != nullptr) {
+ window_->BindRootView(windowRootView_);
+ } else {
+ GRAPHIC_LOGE("Create window false!");
+ }
+}
+
+void UIDialog::SetButtonColor(DialogButtonType buttonType, ColorType color)
+{
+ switch (buttonType) {
+ case DialogButtonType::BUTTON_LEFT:
+ if (button1_ != nullptr) {
+ button1_->SetStyleForState(STYLE_BACKGROUND_COLOR, color.full, UIButton::ButtonState::RELEASED);
+ button1_->SetStyleForState(STYLE_BACKGROUND_OPA, color.alpha, UIButton::ButtonState::RELEASED);
+ colorType1_ = color;
+ }
+ break;
+ case DialogButtonType::BUTTON_MID:
+ if (button2_ != nullptr) {
+ button2_->SetStyleForState(STYLE_BACKGROUND_COLOR, color.full, UIButton::ButtonState::RELEASED);
+ button2_->SetStyleForState(STYLE_BACKGROUND_OPA, color.alpha, UIButton::ButtonState::RELEASED);
+ colorType2_ = color;
+ }
+ break;
+ case DialogButtonType::BUTTON_RIGHT:
+ if (button3_ != nullptr) {
+ button3_->SetStyleForState(STYLE_BACKGROUND_COLOR, color.full, UIButton::ButtonState::RELEASED);
+ button3_->SetStyleForState(STYLE_BACKGROUND_COLOR, color.alpha, UIButton::ButtonState::RELEASED);
+ colorType3_ = color;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void UIDialog::SetOnCancelListener(UIView::OnClickListener* onCancelListener)
+{
+ if (onCancelListener == nullptr) {
+ return;
+ }
+ onCancelListener_ = onCancelListener;
+}
+
+void UIDialog::EnableAutoCancel(bool enable)
+{
+ enableAutoCancel_ = enable;
+}
+
+void UIDialog::DestoryWindow()
+{
+ if (window_ != nullptr) {
+ Window::DestoryWindow(window_);
+ window_ = nullptr;
+ }
+}
+
+#ifdef ENABLE_DEBUG
+const char* UIDialog::GetButtonText(DialogButtonType buttonType) const
+{
+ switch (buttonType) {
+ case DialogButtonType::BUTTON_LEFT:
+ if (button1_ != nullptr) {
+ return button1_->GetText();
+ }
+ return nullptr;
+ case DialogButtonType::BUTTON_MID:
+ if (button2_ != nullptr) {
+ return button2_->GetText();
+ }
+ return nullptr;
+ case DialogButtonType::BUTTON_RIGHT:
+ if (button3_ != nullptr) {
+ return button3_->GetText();
+ }
+ return nullptr;
+ default:
+ return nullptr;
+ }
+}
+
+UIView::OnClickListener* UIDialog::GetButtonListener(DialogButtonType buttonType) const
+{
+ switch (buttonType) {
+ case DialogButtonType::BUTTON_LEFT:
+ if (button1_ != nullptr) {
+ return button1_->GetOnClickListener();
+ }
+ return nullptr;
+ case DialogButtonType::BUTTON_MID:
+ if (button2_ != nullptr) {
+ return button2_->GetOnClickListener();
+ }
+ return nullptr;
+ case DialogButtonType::BUTTON_RIGHT:
+ if (button3_ != nullptr) {
+ return button3_->GetOnClickListener();
+ }
+ return nullptr;
+ default:
+ return nullptr;
+ }
+}
+
+ColorType UIDialog::GetButtonColor(DialogButtonType buttonType) const
+{
+ switch (buttonType) {
+ case DialogButtonType::BUTTON_LEFT:
+ if (button1_ != nullptr) {
+ return colorType1_;
+ }
+ break;
+ case DialogButtonType::BUTTON_MID:
+ if (button2_ != nullptr) {
+ return colorType2_;
+ }
+ break;
+ case DialogButtonType::BUTTON_RIGHT:
+ if (button3_ != nullptr) {
+ return colorType3_;
+ }
+ break;
+ default:
+ break;
+ }
+ ASSERT(0);
+}
+#endif // ENABLE_DEBUG
+} // namespace OHOS
+#endif // ENABLE_WINDOW
\ No newline at end of file
diff --git a/frameworks/components/ui_digital_clock.cpp b/frameworks/components/ui_digital_clock.cpp
new file mode 100755
index 0000000..406c5f7
--- /dev/null
+++ b/frameworks/components/ui_digital_clock.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_digital_clock.h"
+#include
+#include "components/ui_view_group.h"
+#include "font/ui_font.h"
+#include "graphic_log.h"
+#include "securec.h"
+
+namespace OHOS {
+UIDigitalClock::UIDigitalClock()
+ : timeLabels_{0},
+ displayMode_(DISPLAY_24_HOUR),
+ leadingZero_(true),
+ color_(Color::White()),
+ prevHour_(0),
+ prevMinute_(0),
+ prevSecond_(0),
+ verticalShow_(false)
+{
+ style_ = &(StyleDefault::GetBackgroundTransparentStyle());
+}
+
+void UIDigitalClock::InitTimeLabels()
+{
+ for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
+ if (timeLabels_[i] == nullptr) {
+ timeLabels_[i] = new UILabel;
+ if (timeLabels_[i] == nullptr) {
+ GRAPHIC_LOGE("new UILabel fail");
+ return;
+ }
+ timeLabels_[i]->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+ timeLabels_[i]->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
+ Add(timeLabels_[i]);
+ }
+ }
+}
+
+void UIDigitalClock::DisplayLeadingZero(bool displayLeadingZero)
+{
+ leadingZero_ = displayLeadingZero;
+ UpdateClock(false);
+}
+
+void UIDigitalClock::SetOpacity(uint8_t opacity)
+{
+ opaScale_ = opacity;
+ InitTimeLabels();
+ for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
+ timeLabels_[i]->SetStyle(STYLE_TEXT_OPA, opacity);
+ }
+ RefreshTime();
+}
+
+uint8_t UIDigitalClock::GetOpacity() const
+{
+ return opaScale_;
+}
+
+void UIDigitalClock::SetFontId(uint8_t fontId)
+{
+ SetStyle(STYLE_TEXT_FONT, fontId);
+ InitTimeLabels();
+ for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
+ timeLabels_[i]->SetFontId(fontId);
+ }
+ UpdateClock(false);
+}
+
+void UIDigitalClock::SetFont(const char* name, uint8_t size)
+{
+ InitTimeLabels();
+ for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
+ timeLabels_[i]->SetFont(name, size);
+ }
+ UpdateClock(false);
+}
+
+void UIDigitalClock::SetColor(ColorType color)
+{
+ color_ = color;
+ InitTimeLabels();
+ for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
+ timeLabels_[i]->SetStyle(STYLE_TEXT_COLOR, color.full);
+ }
+ RefreshTime();
+}
+
+void UIDigitalClock::TimeElementRefresh()
+{
+ InitTimeLabels();
+ if (currentHour_ != prevHour_) {
+ prevHour_ = currentHour_;
+ timeLabels_[HOUR_ELEMENT]->Invalidate();
+ }
+
+ if (currentMinute_ != prevMinute_) {
+ prevMinute_ = currentMinute_;
+ timeLabels_[MINUTE_ELEMENT]->Invalidate();
+ }
+
+ if (currentSecond_ != prevSecond_) {
+ prevSecond_ = currentSecond_;
+ timeLabels_[SECOND_ELEMENT]->Invalidate();
+ }
+}
+
+void UIDigitalClock::RefreshTime()
+{
+ InitTimeLabels();
+ for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
+ timeLabels_[i]->Invalidate();
+ }
+}
+
+void UIDigitalClock::UpdateClock(bool clockInit)
+{
+ char buf[TIME_ELEMENT_COUNT][BUFFER_SIZE] = {{0}};
+ const char* formatWithColon = leadingZero_ ? "%02d:" : "%d:";
+ const char* formatWithoutColon = leadingZero_ ? "%02d" : "%d";
+ const char* format = verticalShow_ ? formatWithoutColon : formatWithColon;
+ const char* formatForMinute = verticalShow_ ? "%02d" : "%02d:";
+ switch (displayMode_) {
+ case DISPLAY_24_HOUR_NO_SECONDS: {
+ if (sprintf_s(buf[HOUR_ELEMENT], BUFFER_SIZE, format, currentHour_) < 0) {
+ return;
+ }
+ if (sprintf_s(buf[MINUTE_ELEMENT], BUFFER_SIZE, "%02d", currentMinute_) < 0) {
+ return;
+ }
+ break;
+ }
+ case DISPLAY_12_HOUR_NO_SECONDS: {
+ if (sprintf_s(buf[HOUR_ELEMENT], BUFFER_SIZE, format, currentHour_ % HALF_DAY_IN_HOUR) < 0) {
+ return;
+ }
+ if (sprintf_s(buf[MINUTE_ELEMENT], BUFFER_SIZE, "%02d", currentMinute_) < 0) {
+ return;
+ }
+ break;
+ }
+ case DISPLAY_12_HOUR: {
+ if (sprintf_s(buf[HOUR_ELEMENT], BUFFER_SIZE, format, currentHour_ % HALF_DAY_IN_HOUR) < 0) {
+ return;
+ }
+ if (sprintf_s(buf[MINUTE_ELEMENT], BUFFER_SIZE, formatForMinute, currentMinute_) < 0) {
+ return;
+ }
+ if (sprintf_s(buf[SECOND_ELEMENT], BUFFER_SIZE, "%02d", currentSecond_) < 0) {
+ return;
+ }
+ break;
+ }
+ case DISPLAY_24_HOUR: {
+ if (sprintf_s(buf[HOUR_ELEMENT], BUFFER_SIZE, format, currentHour_) < 0) {
+ return;
+ }
+ if (sprintf_s(buf[MINUTE_ELEMENT], BUFFER_SIZE, formatForMinute, currentMinute_) < 0) {
+ return;
+ }
+ if (sprintf_s(buf[SECOND_ELEMENT], BUFFER_SIZE, "%02d", currentSecond_) < 0) {
+ return;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ SetTimeLabels(buf);
+}
+
+void UIDigitalClock::SetTimeLabels(const char buf[TIME_ELEMENT_COUNT][BUFFER_SIZE])
+{
+ InitTimeLabels();
+ for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
+ timeLabels_[i]->SetText(buf[i]);
+ }
+
+ SetTimeLabelsPosition();
+ TimeElementRefresh();
+}
+
+void UIDigitalClock::SetHorizontal()
+{
+ InitTimeLabels();
+ uint16_t totalWidth = timeLabels_[HOUR_ELEMENT]->GetWidth() + timeLabels_[MINUTE_ELEMENT]->GetWidth() +
+ timeLabels_[SECOND_ELEMENT]->GetWidth();
+ UITextLanguageAlignment align = timeLabels_[HOUR_ELEMENT]->GetHorAlign();
+ int16_t x = 0;
+ Rect rect = GetContentRect();
+ if (align == TEXT_ALIGNMENT_CENTER) {
+ x = (rect.GetWidth() >> 1) - (totalWidth >> 1);
+ } else if (align == TEXT_ALIGNMENT_RIGHT) {
+ x = rect.GetRight() - totalWidth;
+ }
+ timeLabels_[HOUR_ELEMENT]->SetPosition(x, 0);
+ int16_t width = timeLabels_[HOUR_ELEMENT]->GetWidth();
+ for (uint8_t i = 1; i < TIME_ELEMENT_COUNT; i++) {
+ timeLabels_[i]->SetPosition(x + width, 0);
+ width += timeLabels_[i]->GetWidth();
+ }
+}
+
+void UIDigitalClock::SetTimeLabelsPosition()
+{
+ if (verticalShow_) {
+ SetVertical();
+ } else {
+ SetHorizontal();
+ }
+}
+
+void UIDigitalClock::SetVertical()
+{
+ InitTimeLabels();
+ int16_t fontHeight = timeLabels_[HOUR_ELEMENT]->GetHeight();
+ timeLabels_[HOUR_ELEMENT]->SetPosition(0, 0);
+ int16_t y = fontHeight;
+ for (uint8_t i = 1; i < TIME_ELEMENT_COUNT; i++) {
+ timeLabels_[i]->SetPosition(0, y);
+ y += fontHeight;
+ }
+}
+
+UIDigitalClock::~UIDigitalClock()
+{
+ for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
+ if (timeLabels_[i] != nullptr) {
+ delete timeLabels_[i];
+ timeLabels_[i] = nullptr;
+ }
+ }
+}
+} // namespace OHOS
diff --git a/frameworks/components/ui_image_animator.cpp b/frameworks/components/ui_image_animator.cpp
new file mode 100755
index 0000000..2882e41
--- /dev/null
+++ b/frameworks/components/ui_image_animator.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_image_animator.h"
+
+namespace OHOS {
+UIImageAnimatorView::UIImageAnimatorView()
+ : imageSrc_(nullptr), imageNum_(0), tickOfUpdate_(1), timeOfUpdate_(DEFAULT_TASK_PERIOD),
+ timeOfPause_(0), tickOfPause_(0), repeatTimes_(1), imageAnimator_(&imageAnimatorCallback_, this, 0, true),
+ listener_(nullptr), reverse_(false), repeat_(true), sizeFixed_(false), fillMode_(true)
+{
+ AnimatorManager::GetInstance()->Add(&imageAnimator_);
+}
+
+UIImageAnimatorView::~UIImageAnimatorView()
+{
+ AnimatorManager::GetInstance()->Remove(&imageAnimator_);
+}
+
+void UIImageAnimatorView::ImageAnimatorCallback::Callback(UIView* view)
+{
+ if (view == nullptr) {
+ return;
+ }
+ UIImageAnimatorView* imageAnimatorView = static_cast(view);
+
+ imageSrc_ = imageAnimatorView->GetImageAnimatorSrc();
+ imageNum_ = imageAnimatorView->GetImageAnimatorImageNum();
+ if ((imageSrc_ == nullptr) || (imageNum_ == 0) || (imageAnimatorView->tickOfUpdate_ == 0)) {
+ return;
+ }
+
+ if (!imageAnimatorView->IsRepeat() && (repeat_ == imageAnimatorView->GetRepeatTimes())) {
+ imageAnimatorView->Stop();
+ return;
+ }
+
+ tickNum_++;
+
+ if (loop_ != imageNum_) {
+ if (tickNum_ < imageAnimatorView->tickOfUpdate_) {
+ return;
+ }
+ } else {
+ if (imageAnimatorView->tickOfPause_ != 0) {
+ if (tickNum_ < imageAnimatorView->tickOfPause_) {
+ return;
+ }
+ } else {
+ if (tickNum_ < imageAnimatorView->tickOfUpdate_) {
+ return;
+ }
+ }
+ repeat_++;
+ loop_ = 0;
+ if (!imageAnimatorView->IsRepeat() && (repeat_ == imageAnimatorView->GetRepeatTimes())) {
+ imageAnimatorView->Stop();
+ return;
+ }
+ }
+ imageAnimatorView->UpdateImage(drawingImage_, loop_);
+ tickNum_ = 0;
+}
+
+void UIImageAnimatorView::UpdateImage(uint8_t& drawingImage, uint8_t& loop)
+{
+ Invalidate();
+ drawingImage = reverse_ ? (imageNum_ - loop - 1) : loop;
+ if (drawingImage >= imageNum_) {
+ return;
+ }
+
+ ImageAnimatorInfo* imageAnimatorInfo = &(imageSrc_[drawingImage]);
+ if (imageAnimatorInfo->imageType == IMG_SRC_FILE_PATH) {
+ SetSrc(imageAnimatorInfo->imagePath);
+ } else if (imageAnimatorInfo->imageType == IMG_SRC_IMAGE_INFO) {
+ SetSrc(imageAnimatorInfo->imageInfo);
+ }
+ if (!sizeFixed_) {
+ SetPosition(imageAnimatorInfo->pos.x, imageAnimatorInfo->pos.y);
+ SetWidth(imageAnimatorInfo->width);
+ SetHeight(imageAnimatorInfo->height);
+ }
+ Invalidate();
+ loop++;
+}
+
+void UIImageAnimatorView::SetImageAnimatorSrc(const ImageAnimatorInfo imageAnimatorInfoSrc[], uint8_t imageNum)
+{
+ SetImageAnimatorSrc(imageAnimatorInfoSrc, imageNum, timeOfUpdate_);
+}
+
+void UIImageAnimatorView::SetImageAnimatorSrc(const ImageAnimatorInfo imageAnimatorInfoSrc[],
+ uint8_t imageNum, uint16_t timeOfUpdate)
+{
+ imageSrc_ = const_cast(imageAnimatorInfoSrc);
+ imageNum_ = imageNum;
+ timeOfUpdate_ = timeOfUpdate;
+ tickOfUpdate_ = GetTickByTime(timeOfUpdate);
+ return;
+}
+
+const ImageAnimatorInfo* UIImageAnimatorView::GetImageAnimatorSrc() const
+{
+ return imageSrc_;
+}
+
+uint8_t UIImageAnimatorView::GetImageAnimatorImageNum() const
+{
+ return imageNum_;
+}
+
+void UIImageAnimatorView::SetTimeOfUpdate(uint16_t timeOfUpdate)
+{
+ timeOfUpdate_ = timeOfUpdate;
+ tickOfUpdate_ = GetTickByTime(timeOfUpdate);
+}
+
+uint16_t UIImageAnimatorView::GetTimeOfUpdate() const
+{
+ return timeOfUpdate_;
+}
+
+void UIImageAnimatorView::SetTimeOfPause(uint16_t timeOfPause)
+{
+ timeOfPause_ = timeOfPause;
+ tickOfPause_ = GetTickByTime(timeOfPause);
+}
+
+uint16_t UIImageAnimatorView::GetTimeOfPause() const
+{
+ return timeOfPause_;
+}
+
+void UIImageAnimatorView::Start()
+{
+ Reset(false);
+ imageAnimator_.SetState(Animator::START);
+}
+
+void UIImageAnimatorView::Reset(bool fillMode)
+{
+ if ((imageSrc_ == nullptr) || (imageNum_ == 0)) {
+ return;
+ }
+
+ Invalidate();
+ uint8_t drawingImage;
+ if (fillMode) {
+ drawingImage = reverse_ ? 0 : (imageNum_ - 1);
+ } else {
+ drawingImage = reverse_ ? (imageNum_ - 1) : 0;
+ }
+ ImageAnimatorInfo* imageAnimatorInfo = &(imageSrc_[drawingImage]);
+ if (imageAnimatorInfo->imageType == IMG_SRC_FILE_PATH) {
+ SetSrc(imageAnimatorInfo->imagePath);
+ } else if (imageAnimatorInfo->imageType == IMG_SRC_IMAGE_INFO) {
+ SetSrc(imageAnimatorInfo->imageInfo);
+ }
+ if (!sizeFixed_) {
+ SetPosition(imageAnimatorInfo->pos.x, imageAnimatorInfo->pos.y);
+ SetWidth(imageAnimatorInfo->width);
+ SetHeight(imageAnimatorInfo->height);
+ }
+ Invalidate();
+ imageAnimatorCallback_.Reset();
+}
+
+void UIImageAnimatorView::Stop()
+{
+ if (imageAnimator_.GetState() == Animator::STOP) {
+ return;
+ }
+
+ imageAnimator_.SetState(Animator::STOP);
+ Reset(fillMode_);
+ if (listener_ != nullptr) {
+ listener_->OnAnimatorStop(*this);
+ }
+}
+
+uint8_t UIImageAnimatorView::GetTickByTime(uint16_t time) const
+{
+ uint8_t tick;
+ if ((time > 0) && (time <= DEFAULT_TASK_PERIOD)) {
+ tick = 1;
+ } else {
+ tick = time / DEFAULT_TASK_PERIOD;
+ }
+ return tick;
+}
+}
diff --git a/frameworks/components/ui_image_view.cpp b/frameworks/components/ui_image_view.cpp
new file mode 100755
index 0000000..2fdd403
--- /dev/null
+++ b/frameworks/components/ui_image_view.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_image_view.h"
+#include "common/image.h"
+#include "common/typed_text.h"
+#include "draw/draw_image.h"
+#include "draw/draw_label.h"
+#include "draw/draw_rect.h"
+#include "file.h"
+#include "image_info.h"
+#include "imgdecode/cache_manager.h"
+#include "mem_api.h"
+#ifndef VERSION_LITE
+#include "gif_lib.h"
+#endif
+
+namespace OHOS {
+#ifndef VERSION_LITE
+class GifImageAnimator : public Animator, public AnimatorCallback {
+public:
+ GifImageAnimator(UIView* view, const char* src)
+ : Animator(this, view, 0, true),
+ gifFileType_(nullptr),
+ imageIndex_(0),
+ delayTime_(0),
+ lastRunTime_(0),
+ deltaTime_(0),
+ gifDataSize_(0),
+ src_(src)
+ {
+ }
+
+ virtual ~GifImageAnimator()
+ {
+ CloseGifFile();
+ }
+
+ void Callback(UIView* view) override;
+
+ void SetGifFileType(GifFileType* gifFileType)
+ {
+ gifFileType_ = gifFileType;
+ }
+
+ uint32_t SetGifFrame(GifFileType* gifFileType, int32_t imageIndex, UIImageView* imageView) const;
+ void DealGifImageData(const GifFileType* gifFileType,
+ const GifImageDesc* gifImageDesc,
+ const SavedImage* savedImage,
+ GraphicsControlBlock gcb,
+ const ColorMapObject* colorMap) const;
+ const void OpenGifFile(const char* src);
+ void CloseGifFile();
+
+private:
+ GifFileType* GetGifFileType()
+ {
+ if (gifFileType_ == nullptr) {
+ OpenGifFile(src_);
+ }
+ return gifFileType_;
+ }
+
+ GifFileType* gifFileType_;
+ int32_t imageIndex_;
+ uint32_t delayTime_;
+ uint32_t lastRunTime_;
+ uint32_t deltaTime_;
+ uint32_t gifDataSize_;
+ uint8_t* gifImageData_ = nullptr;
+ const char* src_;
+};
+
+const void GifImageAnimator::OpenGifFile(const char* src)
+{
+ int32_t error = D_GIF_SUCCEEDED;
+ GifFileType* gifFileType = DGifOpenFileName(src, &error);
+ if (error != D_GIF_SUCCEEDED) {
+ return;
+ }
+ DGifSlurp(gifFileType);
+ /* 3 : when change single pixel to byte, the buffer should divided by 8, equal to shift right 3 bits. */
+ uint8_t pixelByteSize = DrawUtils::GetPxSizeByColorMode(ARGB8888) >> 3;
+ gifDataSize_ = gifFileType->SWidth * gifFileType->SHeight * pixelByteSize;
+ gifImageData_ = static_cast(UIMalloc(gifDataSize_));
+ if (gifImageData_ == nullptr) {
+ CloseGifFile();
+ return;
+ }
+ SetGifFileType(gifFileType);
+}
+
+void GifImageAnimator::CloseGifFile()
+{
+ GifFileType* gifFileType = GetGifFileType();
+ if (gifFileType != nullptr) {
+ DGifCloseFile(gifFileType, nullptr);
+ }
+ if (gifImageData_ != nullptr) {
+ UIFree(reinterpret_cast(const_cast(gifImageData_)));
+ gifImageData_ = nullptr;
+ }
+}
+
+void GifImageAnimator::Callback(UIView* view)
+{
+ if (view == nullptr) {
+ return;
+ }
+ UIImageView* imageView = static_cast(view);
+ uint32_t curTime = GetRunTime();
+ if (curTime != 0) {
+ if (curTime + deltaTime_ - lastRunTime_ >= delayTime_) {
+ deltaTime_ = curTime + deltaTime_ - lastRunTime_ - delayTime_;
+ lastRunTime_ = curTime;
+ } else {
+ return;
+ }
+ }
+ GifFileType* gifFileType = GetGifFileType();
+ if (gifFileType != nullptr) {
+ delayTime_ = SetGifFrame(gifFileType, imageIndex_, imageView);
+ imageIndex_ = (imageIndex_ < gifFileType->ImageCount - 1) ? (imageIndex_ + 1) : 0;
+ }
+}
+
+uint32_t GifImageAnimator::SetGifFrame(GifFileType* gifFileType, int32_t imageIndex, UIImageView* imageView) const
+{
+ SavedImage* savedImage = &(gifFileType->SavedImages[imageIndex]);
+ if (savedImage == nullptr) {
+ return 0;
+ }
+ GifImageDesc* gifImageDesc = &(savedImage->ImageDesc);
+ if (gifImageDesc == nullptr) {
+ return 0;
+ }
+ GraphicsControlBlock gcb;
+ int32_t ret = DGifSavedExtensionToGCB(gifFileType, imageIndex, &gcb);
+ if (ret != GIF_OK) {
+ return 0;
+ }
+ ColorMapObject* colorMap = nullptr;
+ if (gifImageDesc->ColorMap != nullptr) {
+ colorMap = gifImageDesc->ColorMap;
+ } else {
+ colorMap = gifFileType->SColorMap;
+ }
+
+ DealGifImageData(gifFileType, gifImageDesc, savedImage, gcb, colorMap);
+ if (gifImageData_ == nullptr) {
+ return 0;
+ }
+ imageView->gifFrameFlag_ = true;
+ ImageInfo gifFrame;
+ gifFrame.header.width = gifFileType->SWidth;
+ gifFrame.header.height = gifFileType->SHeight;
+ gifFrame.header.colorMode = ARGB8888;
+ gifFrame.dataSize = gifDataSize_;
+ gifFrame.data = gifImageData_;
+ imageView->SetSrc(&gifFrame);
+
+ if (gcb.DelayTime >= 0) {
+ return static_cast(gcb.DelayTime) * 10; // 10: change hundredths (1/100) of a second to millisecond
+ } else {
+ return 0;
+ }
+}
+
+void GifImageAnimator::DealGifImageData(const GifFileType* gifFileType,
+ const GifImageDesc* gifImageDesc,
+ const SavedImage* savedImage,
+ GraphicsControlBlock gcb,
+ const ColorMapObject* colorMap) const
+{
+ if ((gifFileType == nullptr) || (gifImageDesc == nullptr) || (savedImage == nullptr) ||
+ (savedImage->RasterBits == nullptr) || (colorMap == nullptr) || (colorMap->Colors == nullptr)) {
+ return;
+ }
+ uint8_t colorIndex = 0;
+ GifColorType* gifColorType = nullptr;
+ uint32_t index = 0;
+ bool transparentColor = true;
+ int32_t loc = 0;
+ for (int32_t x = 0; x < gifFileType->SHeight; x++) {
+ for (int32_t y = 0; y < gifFileType->SWidth; y++) {
+ transparentColor = true;
+ if ((x >= gifImageDesc->Top) && (x < gifImageDesc->Top + gifImageDesc->Height) &&
+ (y >= gifImageDesc->Left) && (y < gifImageDesc->Left + gifImageDesc->Width)) {
+ loc = (x - gifImageDesc->Top) * gifImageDesc->Width + (y - gifImageDesc->Left);
+ colorIndex = savedImage->RasterBits[loc];
+
+ if ((gcb.DisposalMode != DISPOSE_DO_NOT) || (gcb.TransparentColor == NO_TRANSPARENT_COLOR) ||
+ (colorIndex != gcb.TransparentColor)) {
+ transparentColor = false;
+ }
+ }
+ if (transparentColor) {
+ index += 4; // 4: skip color index, keep last frame color
+ } else {
+ gifColorType = &colorMap->Colors[colorIndex];
+ gifImageData_[index++] = gifColorType->Blue;
+ gifImageData_[index++] = gifColorType->Green;
+ gifImageData_[index++] = gifColorType->Red;
+ gifImageData_[index++] = OPA_OPAQUE;
+ }
+ }
+ }
+}
+#endif
+
+UIImageView::UIImageView()
+ : imageWidth_(0),
+ imageHeight_(0),
+ autoEnable_(true),
+ needRefresh_(false),
+ colorFormat_(UNKNOW),
+ blurLevel_(BlurLevel::LEVEL0),
+ algorithm_(TransformAlgorithm::BILINEAR),
+ reserve_(0)
+{
+ style_ = &(StyleDefault::GetBackgroundTransparentStyle());
+#ifndef VERSION_LITE
+ gifImageAnimator_ = nullptr;
+ gifFrameFlag_ = false;
+#endif
+}
+
+UIImageView::~UIImageView()
+{
+#ifndef VERSION_LITE
+ RemoveAndStopGifAnimator();
+#endif
+}
+
+bool UIImageView::OnPreDraw(Rect& invalidatedArea) const
+{
+ if ((image_.GetSrcType() == IMG_SRC_UNKNOWN)) {
+ return true;
+ }
+
+ if ((colorFormat_ == RGB565) || (colorFormat_ == RGB888)) {
+ if (GetRect().IsContains(invalidatedArea)) {
+ return true;
+ }
+ invalidatedArea.Intersect(invalidatedArea, GetRect());
+ }
+
+ return false;
+}
+
+void UIImageView::OnDraw(const Rect& invalidatedArea)
+{
+ OpacityType opa = GetMixOpaScale();
+ DrawRect::Draw(GetRect(), invalidatedArea, *style_, opa);
+ if ((imageHeight_ == 0) || (imageWidth_ == 0)) {
+ return;
+ }
+
+ Rect viewRect = GetContentRect();
+ Rect trunc(invalidatedArea);
+ if (trunc.Intersect(trunc, viewRect)) {
+ uint8_t srcType = image_.GetSrcType();
+ if ((srcType == IMG_SRC_FILE) || (srcType == IMG_SRC_VARIABLE)) {
+ Rect cordsTmp;
+ cordsTmp.SetTop(viewRect.GetY());
+ cordsTmp.SetBottom(viewRect.GetY() + imageHeight_ - 1);
+
+ if ((transMap_ == nullptr) || transMap_->IsInvalid()) {
+ while (cordsTmp.GetTop() <= viewRect.GetBottom()) {
+ cordsTmp.SetLeft(viewRect.GetX());
+ cordsTmp.SetRight(viewRect.GetX() + imageWidth_ - 1);
+ while (cordsTmp.GetLeft() <= viewRect.GetRight()) {
+ image_.DrawImage(cordsTmp, trunc, *style_, opa);
+ cordsTmp.SetLeft(cordsTmp.GetLeft() + imageWidth_);
+ cordsTmp.SetRight(cordsTmp.GetRight() + imageWidth_);
+ }
+ cordsTmp.SetTop(cordsTmp.GetTop() + imageHeight_);
+ cordsTmp.SetBottom(cordsTmp.GetBottom() + imageHeight_);
+ }
+ } else if ((transMap_ != nullptr) && !transMap_->IsInvalid()) {
+ ImageInfo imgInfo;
+ if (srcType == IMG_SRC_FILE) {
+ CacheEntry entry;
+ RetCode ret = CacheManager::GetInstance().Open(GetPath(), *style_, entry);
+ if (ret != RetCode::OK) {
+ return;
+ }
+ imgInfo = entry.GetImageInfo();
+ } else {
+ imgInfo = *(GetImageInfo());
+ }
+ uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(imgInfo.header.colorMode);
+ TransformDataInfo imageTranDataInfo = {imgInfo.header, imgInfo.data, pxSize,
+ static_cast(blurLevel_),
+ static_cast(algorithm_)};
+
+ Rect origRect = GetOrigRect();
+ transMap_->SetTransMapRect(origRect);
+ OpacityType opaScale = DrawUtils::GetMixOpacity(opa, style_->imageOpa_);
+ DrawUtils::GetInstance()->DrawTransform(invalidatedArea, {0, 0}, Color::Black(), opaScale, *transMap_,
+ imageTranDataInfo);
+ }
+ }
+ }
+}
+
+void UIImageView::SetSrc(const char* src)
+{
+#ifndef VERSION_LITE
+ if (src == nullptr) {
+ return;
+ }
+ const static uint8_t IMG_BYTES_TO_CHECK = 4; // 4: check 4 bytes of image file
+ char buf[IMG_BYTES_TO_CHECK] = {0};
+ int32_t fd = open(src, O_RDONLY);
+ if (fd < 0) {
+ return;
+ }
+ if (read(fd, buf, IMG_BYTES_TO_CHECK) != IMG_BYTES_TO_CHECK) {
+ close(fd);
+ return;
+ }
+ close(fd);
+ bool updated = false;
+ RemoveAndStopGifAnimator();
+ // 0x47 0x49 0x46: GIF file's header
+ if ((static_cast(buf[0]) == 0x47) && (static_cast(buf[1]) == 0x49) &&
+ (static_cast(buf[2]) == 0x46)) { // 2: array index of GIF file's header
+ if (gifImageAnimator_ == nullptr) {
+ gifImageAnimator_ = new GifImageAnimator(this, src);
+ if (gifImageAnimator_ == nullptr) {
+ GRAPHIC_LOGE("new GifImageAnimator fail");
+ return;
+ }
+ }
+ AddAndStartGifAnimator();
+ updated = true;
+ } else {
+ updated = image_.SetSrc(src);
+ }
+#else
+ bool updated = image_.SetSrc(src);
+#endif
+ if (!updated) {
+ return;
+ }
+ needRefresh_ = true;
+ if (autoEnable_) {
+ UIImageView::ReMeasure();
+ }
+ Invalidate();
+}
+
+void UIImageView::ReMeasure()
+{
+ if (!needRefresh_) {
+ return;
+ }
+ needRefresh_ = false;
+
+ ImageHeader header = {0};
+ image_.GetHeader(header);
+
+ imageWidth_ = header.width;
+ imageHeight_ = header.height;
+ colorFormat_ = header.colorMode;
+
+ if (autoEnable_) {
+ Resize(imageWidth_, imageHeight_);
+ Invalidate();
+ }
+}
+
+void UIImageView::SetSrc(const ImageInfo* src)
+{
+#ifndef VERSION_LITE
+ if (!gifFrameFlag_ && (gifImageAnimator_ != nullptr)) {
+ RemoveAndStopGifAnimator();
+ }
+ gifFrameFlag_ = false;
+#endif
+ bool updated = image_.SetSrc(src);
+ if (!updated) {
+ return;
+ }
+ needRefresh_ = true;
+ if (autoEnable_) {
+ UIImageView::ReMeasure();
+ }
+ Invalidate();
+}
+
+#ifndef VERSION_LITE
+void UIImageView::AddAndStartGifAnimator()
+{
+ if (gifImageAnimator_ != nullptr) {
+ AnimatorManager::GetInstance()->Add(gifImageAnimator_);
+ gifImageAnimator_->Start();
+ }
+}
+
+void UIImageView::RemoveAndStopGifAnimator()
+{
+ if (gifImageAnimator_ != nullptr) {
+ gifImageAnimator_->Stop();
+ AnimatorManager::GetInstance()->Remove(gifImageAnimator_);
+ delete gifImageAnimator_;
+ gifImageAnimator_ = nullptr;
+ }
+}
+#endif
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_label.cpp b/frameworks/components/ui_label.cpp
new file mode 100644
index 0000000..f56f053
--- /dev/null
+++ b/frameworks/components/ui_label.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_label.h"
+#include "font/ui_font.h"
+#include "graphic_log.h"
+#include "themes/theme_manager.h"
+
+namespace OHOS {
+class LabelAnimator : public Animator, public AnimatorCallback {
+public:
+ LabelAnimator(uint16_t textX, uint16_t labelX, int16_t startPos, UIView* view)
+ : Animator(this, view, 0, true),
+ startPos_(startPos),
+ textX_(textX),
+ labelX_(labelX),
+ offsetX_(startPos),
+ waitCount_(ANIM_WAIT_COUNT),
+ speed_(0),
+ preRunTime_(0),
+ decimal_(0)
+ {
+ AnimatorManager::GetInstance()->Add(this);
+ }
+
+ virtual ~LabelAnimator()
+ {
+ AnimatorManager::GetInstance()->Remove(this);
+ }
+
+ int16_t GetStartPos() const
+ {
+ return startPos_;
+ }
+
+ void SetStartPos(int16_t pos)
+ {
+ startPos_ = pos;
+ }
+
+ void UpdateWidth(uint16_t textWidth, uint16_t labelWidth)
+ {
+ textX_ = textWidth;
+ labelX_ = labelWidth;
+ waitCount_ = ANIM_WAIT_COUNT;
+ preRunTime_ = 0;
+ decimal_ = 0;
+ offsetX_ = startPos_;
+ static_cast(view_)->offsetX_ = offsetX_;
+ view_->Invalidate();
+ }
+
+ void Callback(UIView* view) override
+ {
+ if (view == nullptr) {
+ return;
+ }
+
+ uint32_t curTime = GetRunTime();
+ if (waitCount_ > 0) {
+ waitCount_--;
+ preRunTime_ = curTime;
+ return;
+ }
+ uint32_t time = (curTime > preRunTime_) ? (curTime - preRunTime_) : (UINT32_MAX - preRunTime_ + curTime);
+ // 1000: 1000 milliseconds is 1 second
+ float floatStep = (static_cast(time * speed_) / 1000) + decimal_;
+ uint16_t integerStep = static_cast(floatStep);
+ decimal_ = floatStep - integerStep;
+ preRunTime_ = curTime;
+
+ if (integerStep != 0) {
+ offsetX_ -= integerStep;
+ } else {
+ return;
+ }
+ offsetX_ = ((offsetX_ - labelX_) % (textX_ + labelX_)) + labelX_;
+ static_cast(view)->offsetX_ = offsetX_;
+ view->Invalidate();
+ }
+
+ void SetAnimatorSpeed(uint16_t animSpeed)
+ {
+ speed_ = animSpeed;
+ decimal_ = 0;
+ }
+
+private:
+ static constexpr uint8_t ANIM_WAIT_COUNT = 50;
+ int16_t startPos_;
+ uint16_t textX_;
+ uint16_t labelX_;
+ int16_t offsetX_;
+ uint16_t waitCount_;
+ uint16_t speed_;
+ uint32_t preRunTime_;
+ float decimal_;
+};
+
+UILabel::UILabel()
+ : labelText_(nullptr),
+ needRefresh_(false),
+ useTextColor_(false),
+ hasAnimator_(false),
+ lineBreakMode_(LINE_BREAK_ELLIPSIS),
+ ellipsisIndex_(Text::TEXT_ELLIPSIS_END_INV),
+ offsetX_(0),
+ textColor_(Color::White()),
+ animator_{nullptr}
+{
+ Theme* theme = ThemeManager::GetInstance().GetCurrent();
+ Style& style = (theme != nullptr) ? (theme->GetLabelStyle()) : (StyleDefault::GetLabelStyle());
+ UIView::SetStyle(style);
+ animator_.speed = DEFAULT_ANIMATOR_SPEED;
+}
+
+UILabel::~UILabel()
+{
+ if (hasAnimator_) {
+ animator_.animator->Stop();
+ delete animator_.animator;
+ hasAnimator_ = false;
+ }
+ if (labelText_ != nullptr) {
+ delete labelText_;
+ labelText_ = nullptr;
+ }
+}
+
+int16_t UILabel::GetWidth()
+{
+ InitLabelText();
+ if (needRefresh_ && labelText_->IsExpandWidth()) {
+ ReMeasure();
+ }
+ return UIView::GetWidth();
+}
+
+int16_t UILabel::GetHeight()
+{
+ InitLabelText();
+ if (needRefresh_ && labelText_->IsExpandHeight()) {
+ ReMeasure();
+ }
+ return UIView::GetHeight();
+}
+
+void UILabel::SetStyle(uint8_t key, int64_t value)
+{
+ UIView::SetStyle(key, value);
+ RefreshLabel();
+}
+
+void UILabel::SetText(const char* text)
+{
+ InitLabelText();
+ labelText_->SetText(text);
+ if (labelText_->IsNeedRefresh()) {
+ RefreshLabel();
+ }
+}
+
+void UILabel::SetLineBreakMode(const uint8_t lineBreakMode)
+{
+ InitLabelText();
+ if ((lineBreakMode >= LINE_BREAK_MAX) || (lineBreakMode_ == lineBreakMode)) {
+ return;
+ }
+ lineBreakMode_ = lineBreakMode;
+ if ((lineBreakMode_ == LINE_BREAK_ADAPT) || (lineBreakMode_ == LINE_BREAK_STRETCH) ||
+ (lineBreakMode_ == LINE_BREAK_MARQUEE)) {
+ labelText_->SetExpandWidth(true);
+ } else {
+ labelText_->SetExpandWidth(false);
+ }
+ if ((lineBreakMode_ == LINE_BREAK_ADAPT) || (lineBreakMode_ == LINE_BREAK_WRAP)) {
+ labelText_->SetExpandHeight(true);
+ } else {
+ labelText_->SetExpandHeight(false);
+ }
+ RefreshLabel();
+}
+
+void UILabel::SetAlign(UITextLanguageAlignment horizontalAlign, UITextLanguageAlignment verticalAlign)
+{
+ InitLabelText();
+ labelText_->SetAlign(horizontalAlign, verticalAlign);
+ if (labelText_->IsNeedRefresh()) {
+ RefreshLabel();
+ }
+}
+
+void UILabel::SetFontId(uint8_t fontId)
+{
+ InitLabelText();
+ labelText_->SetFontId(fontId);
+ if (labelText_->IsNeedRefresh()) {
+ RefreshLabel();
+ }
+}
+
+void UILabel::SetFont(const char* name, uint8_t size)
+{
+ InitLabelText();
+ labelText_->SetFont(name, size);
+ if (labelText_->IsNeedRefresh()) {
+ RefreshLabel();
+ }
+}
+
+uint16_t UILabel::GetTextWidth()
+{
+ InitLabelText();
+ if (labelText_->IsNeedRefresh()) {
+ Style style = GetStyleConst();
+ style.textColor_ = GetTextColor();
+ labelText_->ReMeasureTextSize(GetContentRect(), style);
+ }
+ return labelText_->GetTextSize().x;
+}
+
+uint16_t UILabel::GetTextHeight()
+{
+ InitLabelText();
+ if (labelText_->IsNeedRefresh()) {
+ Style style = GetStyleConst();
+ style.textColor_ = GetTextColor();
+ labelText_->ReMeasureTextSize(GetContentRect(), style);
+ }
+ return labelText_->GetTextSize().y;
+}
+
+void UILabel::SetWidth(int16_t width)
+{
+ if (GetWidth() != width) {
+ UIView::SetWidth(width);
+ RefreshLabel();
+ }
+}
+
+void UILabel::SetHeight(int16_t height)
+{
+ if (GetHeight() != height) {
+ UIView::SetHeight(height);
+ RefreshLabel();
+ }
+}
+
+void UILabel::RefreshLabel()
+{
+ Invalidate();
+ ellipsisIndex_ = Text::TEXT_ELLIPSIS_END_INV;
+ if (!needRefresh_) {
+ needRefresh_ = true;
+ }
+}
+
+void UILabel::ReMeasure()
+{
+ if (!needRefresh_) {
+ return;
+ }
+ needRefresh_ = false;
+ InitLabelText();
+ Style style = GetStyleConst();
+ style.textColor_ = GetTextColor();
+ labelText_->ReMeasureTextSize(GetContentRect(), style);
+ Point textSize = labelText_->GetTextSize();
+ switch (lineBreakMode_) {
+ case LINE_BREAK_ADAPT:
+ Resize(textSize.x, textSize.y);
+ break;
+ case LINE_BREAK_STRETCH:
+ SetWidth(textSize.x);
+ break;
+ case LINE_BREAK_WRAP:
+ SetHeight(textSize.y);
+ break;
+ case LINE_BREAK_ELLIPSIS:
+ ellipsisIndex_ = labelText_->GetEllipsisIndex(GetContentRect(), style);
+ break;
+ case LINE_BREAK_MARQUEE:
+ RemeasureForMarquee(textSize.x);
+ break;
+ default:
+ break;
+ }
+}
+
+void UILabel::RemeasureForMarquee(int16_t textWidth)
+{
+ int16_t rectWidth = GetWidth();
+ if (textWidth > rectWidth) {
+ offsetX_ = GetRollStartPos();
+ if (labelText_->GetDirect() == TEXT_DIRECT_RTL) {
+ labelText_->SetAlign(TEXT_ALIGNMENT_RIGHT);
+ } else {
+ labelText_->SetAlign(TEXT_ALIGNMENT_LEFT);
+ }
+ if (hasAnimator_) {
+ static_cast(animator_.animator)->UpdateWidth(textWidth, rectWidth);
+ } else {
+ LabelAnimator* animator = new LabelAnimator(textWidth, rectWidth, offsetX_, this);
+ if (animator == nullptr) {
+ GRAPHIC_LOGE("new LabelAnimator fail");
+ return;
+ }
+ animator->SetAnimatorSpeed(animator_.speed);
+ animator_.animator = animator;
+ hasAnimator_ = true;
+ }
+ animator_.animator->Start();
+ } else {
+ offsetX_ = 0;
+ if (hasAnimator_) {
+ animator_.animator->Stop();
+ }
+ }
+}
+
+void UILabel::SetRollStartPos(int16_t pos)
+{
+ if (hasAnimator_) {
+ static_cast(animator_.animator)->SetStartPos(pos);
+ } else {
+ animator_.pos = pos;
+ }
+}
+
+int16_t UILabel::GetRollStartPos() const
+{
+ return hasAnimator_ ? static_cast(animator_.animator)->GetStartPos() : animator_.pos;
+}
+
+void UILabel::SetRollSpeed(uint16_t speed)
+{
+ if (hasAnimator_) {
+ static_cast(animator_.animator)->SetAnimatorSpeed(speed);
+ } else {
+ animator_.speed = speed;
+ }
+}
+
+void UILabel::OnDraw(const Rect& invalidatedArea)
+{
+ InitLabelText();
+ UIView::OnDraw(invalidatedArea);
+ Style style = GetStyleConst();
+ style.textColor_ = GetTextColor();
+ OpacityType opa = GetMixOpaScale();
+ labelText_->OnDraw(invalidatedArea, GetOrigRect(), GetContentRect(), offsetX_, style, ellipsisIndex_, opa);
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/frameworks/components/ui_label_button.cpp b/frameworks/components/ui_label_button.cpp
new file mode 100755
index 0000000..2839bdc
--- /dev/null
+++ b/frameworks/components/ui_label_button.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_label_button.h"
+#include "common/typed_text.h"
+#include "draw/draw_label.h"
+#include "font/ui_font.h"
+
+namespace OHOS {
+UILabelButton::UILabelButton() : labelButtonText_(nullptr), offset_({ 0, 0 })
+{
+ labelStyle_ = StyleDefault::GetDefaultStyle();
+}
+
+void UILabelButton::OnDraw(const Rect& invalidatedArea)
+{
+ UIButton::OnDraw(invalidatedArea);
+
+ Rect textRect = GetContentRect();
+ textRect.SetLeft(textRect.GetLeft() + offset_.x);
+ textRect.SetTop(textRect.GetTop() + offset_.y);
+ InitLabelButtonText();
+ labelButtonText_->ReMeasureTextSize(textRect, labelStyle_);
+ OpacityType opa = GetMixOpaScale();
+ uint16_t ellipsisIndex = labelButtonText_->GetEllipsisIndex(textRect, labelStyle_);
+ labelButtonText_->OnDraw(invalidatedArea, GetOrigRect(), textRect, 0, labelStyle_, ellipsisIndex, opa);
+}
+
+UILabelButton::~UILabelButton()
+{
+ if (labelButtonText_ != nullptr) {
+ delete labelButtonText_;
+ labelButtonText_ = nullptr;
+ }
+}
+} // namespace OHOS
diff --git a/frameworks/components/ui_list.cpp b/frameworks/components/ui_list.cpp
new file mode 100755
index 0000000..815d435
--- /dev/null
+++ b/frameworks/components/ui_list.cpp
@@ -0,0 +1,763 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_list.h"
+
+namespace OHOS {
+UIList::Recycle::~Recycle()
+{
+ ListNode* node = scrapView_.Begin();
+ while (node != scrapView_.End()) {
+ if (node->data_) {
+ UIView* deleteView = node->data_;
+ if (deleteView != nullptr) {
+ delete deleteView;
+ deleteView = nullptr;
+ node->data_ = nullptr;
+ }
+ }
+ node = node->next_;
+ }
+ scrapView_.Clear();
+}
+
+void UIList::Recycle::InitRecycle()
+{
+ if ((adapter_ == nullptr) || (listView_ == nullptr)) {
+ return;
+ }
+ FillActiveView();
+ listView_->Invalidate();
+}
+
+UIView* UIList::Recycle::GetView(int16_t index)
+{
+ if (adapter_ == nullptr) {
+ return nullptr;
+ }
+ UIView* inView = nullptr;
+ UIView* retView = nullptr;
+
+ if (scrapView_.Size() != 0) {
+ inView = scrapView_.Back();
+ }
+
+ retView = adapter_->GetView(inView, index);
+ if (retView != nullptr) {
+ retView->SetViewIndex(index);
+ scrapView_.PopBack();
+ }
+ return retView;
+}
+
+void UIList::Recycle::FillActiveView()
+{
+ if ((adapter_ == nullptr) || (listView_ == nullptr)) {
+ return;
+ }
+ uint16_t index = listView_->GetStartIndex();
+ if (listView_->GetDirection() == UIList::VERTICAL) {
+ int16_t childBottom = 0;
+ while ((index < adapter_->GetCount()) && (childBottom < listView_->GetHeight())) {
+ UIView* view = GetView(index);
+ if (view == nullptr) {
+ break;
+ }
+ listView_->PushBack(view);
+ if (listView_->childrenTail_) {
+ childBottom =
+ listView_->childrenTail_->GetY() + listView_->childrenTail_->GetRelativeRect().GetHeight();
+ } else {
+ break;
+ }
+ index++;
+ }
+ } else {
+ int16_t childRight = 0;
+ while ((index < adapter_->GetCount()) && (childRight < listView_->GetWidth())) {
+ UIView* view = GetView(index);
+ listView_->PushBack(view);
+ if (listView_->childrenTail_) {
+ childRight = listView_->childrenTail_->GetX() + listView_->childrenTail_->GetRelativeRect().GetWidth();
+ } else {
+ break;
+ }
+ index++;
+ }
+ }
+}
+
+UIList::UIList()
+ : onSelectedView_(nullptr),
+ isLoopList_(false),
+ isReCalculateDragEnd_(true),
+ autoAlign_(false),
+ startIndex_(0),
+ topIndex_(0),
+ bottomIndex_(0),
+ selectPosition_(0),
+ onSelectedIndex_(0),
+ recycle_(this),
+ scrollListener_(nullptr)
+{
+#if ENABLE_ROTATE_INPUT
+ rotateFactor_ = 1;
+ rotateThreshold_ = 4; // 4: which means 25% of half view size
+#endif
+#if ENABLE_MOTOR
+ motorType_ = MotorType::MOTOR_TYPE_ONE;
+#endif
+ direction_ = VERTICAL;
+ touchable_ = true;
+ draggable_ = true;
+ dragParentInstead_ = false;
+}
+
+UIList::UIList(uint8_t direction)
+ : onSelectedView_(nullptr),
+ isLoopList_(false),
+ isReCalculateDragEnd_(true),
+ autoAlign_(false),
+ startIndex_(0),
+ topIndex_(0),
+ bottomIndex_(0),
+ selectPosition_(0),
+ onSelectedIndex_(0),
+ recycle_(this),
+ scrollListener_(nullptr)
+{
+#if ENABLE_ROTATE_INPUT
+ rotateFactor_ = 1;
+ rotateThreshold_ = 4; // 4: which means 25% of half view size
+#endif
+#if ENABLE_MOTOR
+ motorType_ = MotorType::MOTOR_TYPE_ONE;
+#endif
+ direction_ = direction;
+ touchable_ = true;
+ draggable_ = true;
+ dragParentInstead_ = false;
+}
+
+UIList::~UIList()
+{
+ UIView* view = GetChildrenHead();
+ while (view != nullptr) {
+ UIView* tmp = view->GetNextSibling();
+ delete view;
+ view = tmp;
+ }
+}
+
+bool UIList::OnDragEvent(const DragEvent& event)
+{
+ if (scrollAnimator_.GetState() != Animator::STOP) {
+ UIAbstractScroll::StopAnimator();
+ }
+ int16_t xDistance = event.GetDeltaX();
+ int16_t yDistance = event.GetDeltaY();
+ isReCalculateDragEnd_ = true;
+ if (direction_ == VERTICAL) {
+ RefreshDeltaY(yDistance);
+ DragYInner(yDistance);
+ } else {
+ DragXInner(xDistance);
+ }
+ return UIView::OnDragEvent(event);
+}
+
+bool UIList::OnDragEndEvent(const DragEvent& event)
+{
+ Point last = event.GetPreLastPoint();
+ Point current = event.GetLastPoint();
+ if ((last.x == current.x) && (last.y == current.y)) {
+ last = current;
+ current = event.GetCurrentPos();
+ }
+ isReCalculateDragEnd_ = false;
+ if (!DragThrowAnimator(current, last)) {
+ if (scrollListener_ && (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_MOVE)) {
+ scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
+ scrollListener_->OnScrollEnd(onSelectedIndex_, onSelectedView_);
+ }
+ }
+ return UIView::OnDragEndEvent(event);
+}
+
+bool UIList::OnPressEvent(const PressEvent& event)
+{
+ StopAnimator();
+ return UIView::OnPressEvent(event);
+}
+
+#if ENABLE_ROTATE_INPUT
+bool UIList::OnRotateEvent(const RotateEvent& event)
+{
+ int16_t tmpRotateLen = static_cast(event.GetRotate() * rotateFactor_);
+ int16_t midPointX = static_cast(GetWidth() / 2); // 2 : Get the middle point X coord of the view
+ int16_t midPointY = static_cast(GetHeight() / 2); // 2 : Get the middle point Y coord of the view
+ Point last, current;
+#if ENABLE_MOTOR
+ MotorFunc motorFunc = FocusManager::GetInstance()->GetMotorFunc();
+#endif
+
+ if (!throwDrag_ || ((MATH_ABS(tmpRotateLen) < (midPointX / rotateThreshold_)) &&
+ (MATH_ABS(tmpRotateLen) < (midPointY / rotateThreshold_)))) {
+ ScrollBy(tmpRotateLen);
+ if (event.GetRotate() == 0) {
+ isReCalculateDragEnd_ = false;
+ DragThrowAnimator(Point{0, 0}, Point{0, 0});
+ }
+ } else {
+ tmpRotateLen += tmpRotateLen;
+ last = Point{midPointX, midPointY};
+ if (direction_ == VERTICAL) {
+ current = Point{midPointX, static_cast(midPointY + tmpRotateLen)};
+ } else {
+ current = Point{static_cast(midPointX + tmpRotateLen), midPointY};
+ }
+ isReCalculateDragEnd_ = false;
+ DragThrowAnimator(current, last);
+#if ENABLE_MOTOR
+ if (motorFunc != nullptr && motorType_ == MotorType::MOTOR_TYPE_TWO) {
+ motorFunc(MotorType::MOTOR_TYPE_TWO);
+ }
+#endif
+ }
+
+#if ENABLE_MOTOR
+ if (motorFunc != nullptr && motorType_ == MotorType::MOTOR_TYPE_ONE) {
+ motorFunc(MotorType::MOTOR_TYPE_ONE);
+ }
+#endif
+
+ return UIView::OnRotateEvent(event);
+}
+#endif
+
+void UIList::ScrollBy(int16_t distance)
+{
+ if (direction_ == VERTICAL) {
+ DragYInner(distance);
+ } else {
+ DragXInner(distance);
+ }
+ if (scrollListener_ && (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_MOVE)) {
+ scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
+ scrollListener_->OnScrollEnd(onSelectedIndex_, onSelectedView_);
+ }
+}
+
+bool UIList::DragXInner(int16_t distance)
+{
+ if (IsNeedReCalculateDragEnd()) {
+ return false;
+ }
+ int16_t listWidth = GetWidth();
+ if (distance == 0) {
+ return true;
+ }
+ int16_t reboundSize = reboundSize_;
+ if (isLoopList_ || (scrollAnimator_.GetState() != Animator::STOP)) {
+ reboundSize = 0;
+ }
+ bool ret = 0;
+ do {
+ ret = MoveChildStep(distance);
+ } while (ret);
+
+ if (isLoopList_) {
+ return MoveOffset(distance);
+ }
+ if (distance > 0) {
+ if (childrenHead_ && (childrenHead_->GetX() + distance > scrollBlankSize_ + reboundSize)) {
+ distance = scrollBlankSize_ + reboundSize - childrenHead_->GetX();
+ }
+ } else {
+ if (childrenTail_) {
+ if (childrenTail_->GetRelativeRect().GetRight() <= listWidth - scrollBlankSize_ - reboundSize) {
+ distance = 0;
+ } else if (listWidth - (childrenTail_->GetX() + childrenTail_->GetRelativeRect().GetWidth() + distance) >
+ scrollBlankSize_ + reboundSize) {
+ distance = listWidth - scrollBlankSize_ - reboundSize - childrenTail_->GetX() -
+ childrenTail_->GetRelativeRect().GetWidth();
+ }
+ }
+ }
+ return MoveOffset(distance);
+}
+
+bool UIList::DragYInner(int16_t distance)
+{
+ if (IsNeedReCalculateDragEnd()) {
+ return false;
+ }
+ int16_t listHeigh = GetHeight();
+ if (distance == 0) {
+ return true;
+ }
+ int16_t reboundSize = reboundSize_;
+ if (isLoopList_ || (scrollAnimator_.GetState() != Animator::STOP)) {
+ reboundSize = 0;
+ }
+ bool ret = 0;
+ do {
+ ret = MoveChildStep(distance);
+ } while (ret);
+
+ if (isLoopList_) {
+ return MoveOffset(distance);
+ }
+ if (distance > 0) {
+ if (childrenHead_ && (childrenHead_->GetY() + distance > scrollBlankSize_ + reboundSize)) {
+ distance = scrollBlankSize_ + reboundSize - childrenHead_->GetY();
+ }
+ } else {
+ if (childrenTail_) {
+ if (childrenTail_->GetRelativeRect().GetBottom() <= listHeigh - scrollBlankSize_ - reboundSize) {
+ distance = 0;
+ } else if (listHeigh - (childrenTail_->GetY() + childrenTail_->GetRelativeRect().GetHeight() + distance) >
+ scrollBlankSize_ + reboundSize) {
+ distance = listHeigh - scrollBlankSize_ - reboundSize - childrenTail_->GetY() -
+ childrenTail_->GetRelativeRect().GetHeight();
+ }
+ }
+ }
+ return MoveOffset(distance);
+}
+
+bool UIList::MoveOffset(int16_t offset)
+{
+ if (offset == 0) {
+ return false;
+ }
+ if (direction_ == VERTICAL) {
+ MoveChildByOffset(0, offset);
+ } else {
+ MoveChildByOffset(offset, 0);
+ }
+ Invalidate();
+ if (scrollListener_ && (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_STOP)) {
+ scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_MOVE);
+ scrollListener_->OnScrollStart(onSelectedIndex_, onSelectedView_);
+ }
+
+ return true;
+}
+
+bool UIList::IsNeedReCalculateDragEnd()
+{
+ if (!autoAlign_ || isReCalculateDragEnd_ || (onSelectedView_ == nullptr)) {
+ return false;
+ }
+ int16_t animationLess = 0;
+ if (direction_ == VERTICAL) {
+ animationLess = animatorCallback_.endValueY_ - animatorCallback_.previousValueY_;
+ } else {
+ animationLess = animatorCallback_.endValueX_ - animatorCallback_.previousValueX_;
+ }
+ if (!isDragging_ || (MATH_ABS(animationLess) > RECALCULATE_DRAG_DISTANCE)) {
+ return false;
+ }
+ return true;
+}
+bool UIList::ReCalculateDragEnd()
+{
+ if ((onSelectedView_ == nullptr) || isReCalculateDragEnd_ || !autoAlign_) {
+ return false;
+ }
+
+ int16_t offsetX = 0;
+ int16_t offsetY = 0;
+ if (direction_ == VERTICAL) {
+ // 2: half
+ offsetY = selectPosition_ - (onSelectedView_->GetY() + (onSelectedView_->GetRelativeRect().GetHeight() / 2));
+ } else {
+ // 2: half
+ offsetX = selectPosition_ - (onSelectedView_->GetX() + (onSelectedView_->GetRelativeRect().GetWidth() / 2));
+ }
+ animatorCallback_.SetDragStartValue(0, 0);
+ animatorCallback_.SetDragEndValue(offsetX, offsetY);
+ animatorCallback_.SetDragTimes(RECALCULATE_DRAG_TIMES * DRAG_ACC_FACTOR / GetDragACCLevel());
+ scrollAnimator_.Start();
+ isReCalculateDragEnd_ = true;
+ return true;
+}
+
+bool UIList::MoveChildStepInner(int16_t distance,
+ int16_t (UIView::*pfnGetXOrY)() const,
+ int16_t (Rect::*pfnGetWidthOrHeight)() const)
+{
+ bool popRet = false;
+ bool pushRet = false;
+ if (distance > 0) {
+ if ((childrenHead_ == nullptr) || ((childrenHead_->*pfnGetXOrY)() + distance > 0)) {
+ uint16_t index = GetIndexDec(topIndex_);
+ if (index == topIndex_) {
+ return false;
+ }
+ UIView* newView = recycle_.GetView(index);
+ if (newView == nullptr) {
+ return false;
+ }
+ PushFront(newView);
+ pushRet = true;
+ }
+ if (childrenTail_ != nullptr &&
+ ((childrenTail_->*pfnGetXOrY)() + distance > (this->GetRelativeRect().*pfnGetWidthOrHeight)())) {
+ PopItem(childrenTail_);
+ popRet = true;
+ }
+ } else {
+ if ((childrenTail_ == nullptr) ||
+ ((childrenTail_->*pfnGetXOrY)() + (childrenTail_->GetRelativeRect().*pfnGetWidthOrHeight)() + distance <
+ (this->GetRelativeRect().*pfnGetWidthOrHeight)())) {
+ UIView* newView = recycle_.GetView(GetIndexInc(bottomIndex_));
+ if (newView == nullptr) {
+ return false;
+ }
+ PushBack(newView);
+ pushRet = true;
+ }
+ if (childrenHead_ &&
+ (childrenHead_->*pfnGetXOrY)() + distance + (childrenHead_->GetRelativeRect().*pfnGetWidthOrHeight)() < 0) {
+ PopItem(childrenHead_);
+ popRet = true;
+ }
+ }
+ return (popRet || pushRet);
+}
+
+bool UIList::MoveChildStep(int16_t distance)
+{
+ if (direction_ == VERTICAL) {
+ return MoveChildStepInner(distance, &UIView::GetY, &Rect::GetHeight);
+ } else {
+ return MoveChildStepInner(distance, &UIView::GetX, &Rect::GetWidth);
+ }
+}
+
+void UIList::SetAdapter(AbstractAdapter* adapter)
+{
+ recycle_.SetAdapter(adapter);
+ recycle_.InitRecycle();
+}
+
+UIView* UIList::GetSelectView()
+{
+ if (onSelectedView_ != nullptr) {
+ return onSelectedView_;
+ }
+ if ((childrenHead_ == nullptr) || (selectPosition_ == 0)) {
+ return nullptr;
+ }
+ UIView* child = childrenHead_;
+ while (child != nullptr) {
+ if (direction_ == VERTICAL) {
+ if ((child->GetY() <= selectPosition_) &&
+ (child->GetY() + child->GetRelativeRect().GetHeight() >= selectPosition_)) {
+ if (scrollListener_ != nullptr) {
+ scrollListener_->OnItemSelected(child->GetViewIndex(), child);
+ }
+ return child;
+ }
+ } else {
+ if ((child->GetX() <= selectPosition_) &&
+ (child->GetX() + child->GetRelativeRect().GetWidth() >= selectPosition_)) {
+ if (scrollListener_ != nullptr) {
+ scrollListener_->OnItemSelected(child->GetViewIndex(), child);
+ }
+ return child;
+ }
+ }
+ child = child->GetNextSibling();
+ }
+ return nullptr;
+}
+
+void UIList::PushBack(UIView* view)
+{
+ if (view == nullptr) {
+ return;
+ }
+ if (childrenTail_ == nullptr) {
+ SetHead(view);
+ } else {
+ if (direction_ == VERTICAL) {
+ view->SetPosition(0, childrenTail_->GetY() + childrenTail_->GetRelativeRect().GetHeight());
+ } else {
+ view->SetPosition(childrenTail_->GetX() + childrenTail_->GetRelativeRect().GetWidth(), 0);
+ }
+ bottomIndex_ = GetIndexInc(bottomIndex_);
+ }
+
+ view->SetDragParentInstead(true);
+ UIViewGroup::Add(view);
+}
+
+void UIList::PushFront(UIView* view)
+{
+ if (view == nullptr) {
+ return;
+ }
+ if (GetChildrenHead() == nullptr) {
+ SetHead(view);
+ } else {
+ if (direction_ == VERTICAL) {
+ view->SetPosition(0, GetChildrenHead()->GetY() - view->GetRelativeRect().GetHeight());
+ } else {
+ view->SetPosition(GetChildrenHead()->GetX() - view->GetRelativeRect().GetWidth(), 0);
+ }
+ topIndex_ = GetIndexDec(topIndex_);
+ }
+ view->SetDragParentInstead(true);
+ UIViewGroup::Insert(nullptr, view);
+}
+
+void UIList::PopItem(UIView* view)
+{
+ if (view == nullptr) {
+ return;
+ }
+ recycle_.AddScrapView(view);
+ if (view == GetChildrenHead()) {
+ topIndex_ = GetIndexInc(topIndex_);
+ }
+
+ if (view == childrenTail_) {
+ bottomIndex_ = GetIndexDec(bottomIndex_);
+ }
+ UIViewGroup::Remove(view);
+}
+
+void UIList::SetHead(UIView* view)
+{
+ if (view != nullptr) {
+ view->SetPosition(0, 0);
+ topIndex_ = startIndex_;
+ bottomIndex_ = startIndex_;
+ }
+}
+
+void UIList::MoveChildByOffset(int16_t xOffset, int16_t yOffset)
+{
+ UIView* view = GetChildrenHead();
+ if (view == nullptr) {
+ return;
+ }
+ int16_t x;
+ int16_t y;
+ int16_t height;
+ int16_t width;
+
+ if ((onSelectedIndex_ != NULL_SELECT_INDEX) && (selectPosition_ != 0)) {
+ if (direction_ == VERTICAL) {
+ height = view->GetRelativeRect().GetHeight();
+ if ((GetChildrenHead()->GetY() + yOffset > selectPosition_) ||
+ (childrenTail_->GetY() + height + yOffset < selectPosition_)) {
+ onSelectedIndex_ = NULL_SELECT_INDEX;
+ onSelectedView_ = nullptr;
+ if (scrollListener_ != nullptr) {
+ scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
+ }
+ }
+ } else {
+ width = view->GetRelativeRect().GetWidth();
+ if ((GetChildrenHead()->GetX() + xOffset > selectPosition_) ||
+ (childrenTail_->GetX() + width < selectPosition_)) {
+ onSelectedIndex_ = NULL_SELECT_INDEX;
+ onSelectedView_ = nullptr;
+ if (scrollListener_ != nullptr) {
+ scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
+ }
+ }
+ }
+ }
+ bool isSelectViewFind = false;
+ while (view != nullptr) {
+ x = view->GetX() + xOffset;
+ y = view->GetY() + yOffset;
+ view->SetPosition(x, y);
+ if ((selectPosition_ != 0) && !isSelectViewFind) {
+ if (direction_ == VERTICAL) {
+ height = view->GetRelativeRect().GetHeight();
+ /* Views may be the same but have different indexes because of view recycling. */
+ if ((y <= selectPosition_) && (y + height >= selectPosition_) &&
+ ((onSelectedView_ != view) || (onSelectedIndex_ != view->GetViewIndex()))) {
+ onSelectedIndex_ = view->GetViewIndex();
+ onSelectedView_ = view;
+ if (scrollListener_ != nullptr) {
+ scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
+ }
+ isSelectViewFind = true;
+ }
+ } else {
+ width = view->GetRelativeRect().GetWidth();
+ if ((x <= selectPosition_) && (x + width >= selectPosition_) &&
+ ((onSelectedView_ != view) || (onSelectedIndex_ != view->GetViewIndex()))) {
+ onSelectedIndex_ = view->GetViewIndex();
+ onSelectedView_ = view;
+ if (scrollListener_ != nullptr) {
+ scrollListener_->OnItemSelected(onSelectedIndex_, onSelectedView_);
+ }
+ isSelectViewFind = true;
+ }
+ }
+ }
+ view = view->GetNextSibling();
+ }
+}
+
+void UIList::StopAnimator()
+{
+ UIAbstractScroll::StopAnimator();
+ if (!ReCalculateDragEnd()) {
+ if ((scrollListener_ != nullptr) &&
+ (scrollListener_->GetScrollState() == ListScrollListener::SCROLL_STATE_MOVE)) {
+ scrollListener_->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
+ scrollListener_->OnScrollEnd(onSelectedIndex_, onSelectedView_);
+ }
+ }
+}
+
+uint16_t UIList::GetIndexInc(uint16_t index)
+{
+ uint16_t ret = index + 1;
+ if (isLoopList_ && (recycle_.GetAdapterItemCount() != 0)) {
+ ret = ret % recycle_.GetAdapterItemCount();
+ }
+ return ret;
+}
+
+uint16_t UIList::GetIndexDec(uint16_t index)
+{
+ if (index == 0) {
+ if (isLoopList_) {
+ return recycle_.GetAdapterItemCount() - 1;
+ } else {
+ return 0;
+ }
+ } else {
+ return index - 1;
+ }
+}
+
+void UIList::ScrollTo(uint16_t index)
+{
+ UIView* child = GetChildrenHead();
+ UIView* tmp = nullptr;
+ while (child != nullptr) {
+ tmp = child;
+ child = child->GetNextSibling();
+ PopItem(tmp);
+ }
+ onSelectedView_ = nullptr;
+ SetStartIndex(index);
+ recycle_.InitRecycle();
+}
+
+void UIList::RefreshList()
+{
+ int16_t topIndex = topIndex_;
+ UIView* child = GetChildrenHead();
+ UIView* tmp = nullptr;
+ int16_t offset = 0;
+ if (child != nullptr) {
+ if (direction_ == VERTICAL) {
+ offset = child->GetY();
+ } else {
+ offset = child->GetX();
+ }
+ }
+
+ while (child != nullptr) {
+ tmp = child;
+ child = child->GetNextSibling();
+ PopItem(tmp);
+ }
+ onSelectedView_ = nullptr;
+
+ uint16_t tmpStartIndex = startIndex_;
+ if (topIndex > recycle_.GetAdapterItemCount() - 1) {
+ startIndex_ = 0;
+ offset = 0;
+ } else {
+ startIndex_ = topIndex;
+ }
+ recycle_.InitRecycle();
+ startIndex_ = tmpStartIndex;
+
+ if (direction_ == VERTICAL) {
+ DragYInner(offset);
+ } else {
+ DragXInner(offset);
+ }
+ Invalidate();
+}
+
+void UIList::RemoveAll()
+{
+ UIViewGroup::RemoveAll();
+ recycle_.ClearScrapView();
+}
+
+void UIList::CalculateReboundDistance(int16_t& dragDistanceX, int16_t& dragDistanceY)
+{
+ if (isLoopList_) {
+ return;
+ }
+ Rect rect = GetAllChildRelativeRect();
+ int16_t top = rect.GetTop();
+ int16_t bottom = rect.GetBottom();
+ int16_t scrollHeight = GetHeight();
+ int16_t left = rect.GetLeft();
+ int16_t right = rect.GetRight();
+ int16_t scrollWidth = GetWidth();
+ if ((direction_ == VERTICAL) || (direction_ == HORIZONTAL_AND_VERTICAL)) {
+ if (top > scrollBlankSize_) {
+ if ((dragDistanceY + top) > (scrollBlankSize_ + reboundSize_)) {
+ dragDistanceY = 0;
+ }
+ dragDistanceY += scrollBlankSize_ - (top + dragDistanceY);
+ }
+ if (bottom < (scrollHeight - scrollBlankSize_ - 1)) {
+ if ((dragDistanceY + bottom) < (scrollHeight - scrollBlankSize_ - reboundSize_ - 1)) {
+ dragDistanceY = 0;
+ }
+ dragDistanceY += scrollHeight - scrollBlankSize_ - 1 - (bottom + dragDistanceY);
+ }
+ } else {
+ if (left > scrollBlankSize_) {
+ if ((dragDistanceX + left) > (scrollBlankSize_ + reboundSize_)) {
+ dragDistanceX = 0;
+ }
+ dragDistanceX += scrollBlankSize_ - (left + dragDistanceX);
+ }
+ if (right < (scrollWidth - scrollBlankSize_ - 1)) {
+ if ((dragDistanceX + right) < (scrollWidth - scrollBlankSize_ - reboundSize_ - 1)) {
+ dragDistanceX = 0;
+ }
+ dragDistanceX += scrollWidth - scrollBlankSize_ - 1 - (right + dragDistanceX);
+ }
+ }
+}
+
+#if ENABLE_MOTOR
+void UIList::SetMotorType(MotorType motorType)
+{
+ motorType_ = motorType;
+}
+#endif
+} // namespace OHOS
diff --git a/frameworks/components/ui_picker.cpp b/frameworks/components/ui_picker.cpp
new file mode 100755
index 0000000..5380931
--- /dev/null
+++ b/frameworks/components/ui_picker.cpp
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_picker.h"
+#include "draw/draw_line.h"
+#include "draw/draw_rect.h"
+#include "themes/theme_manager.h"
+
+namespace OHOS {
+class PickerListScrollListener : public ListScrollListener {
+public:
+ PickerListScrollListener(UIPicker* picker, UIList* list)
+ : listView_(list), pickerView_(picker), selectView_(nullptr), lastSelectView_(nullptr),
+ selectIndex_(0), isInitted_(false){}
+
+ virtual ~PickerListScrollListener() {}
+
+ void OnItemSelected(int16_t index, UIView* view) override
+ {
+ if (!isInitted_) {
+ return;
+ }
+
+ if ((lastSelectView_ != nullptr) && (listView_ != nullptr) && (pickerView_ != nullptr) && (view != nullptr)) {
+ lastSelectView_->SetStyle(STYLE_TEXT_COLOR, pickerView_->GetBackgroundTextColor().full);
+ if (pickerView_->backgroundFontName_ == nullptr) {
+ static_cast(lastSelectView_)->SetFontId(pickerView_->backgroundFontId_);
+ } else {
+ static_cast(lastSelectView_)
+ ->SetFont(pickerView_->backgroundFontName_, pickerView_->backgroundFontSize_);
+ }
+ view->SetStyle(STYLE_TEXT_COLOR, pickerView_->GetHighlightTextColor().full);
+ if (pickerView_->highlightFontName_ == nullptr) {
+ static_cast(view)->SetFontId(pickerView_->highlightFontId_);
+ } else {
+ static_cast(view)
+ ->SetFont(pickerView_->highlightFontName_, pickerView_->highlightFontSize_);
+ }
+ lastSelectView_ = view;
+ selectIndex_ = index;
+ listView_->Invalidate();
+ }
+ }
+
+ void OnScrollEnd(int16_t index, UIView* view) override
+ {
+ if ((view == nullptr) || (listView_ == nullptr) || (pickerView_ == nullptr)) {
+ return;
+ }
+
+ if (lastSelectView_ != nullptr) {
+ lastSelectView_->SetStyle(STYLE_TEXT_COLOR, pickerView_->GetBackgroundTextColor().full);
+ if (pickerView_->backgroundFontName_ == nullptr) {
+ static_cast(lastSelectView_)->SetFontId(pickerView_->backgroundFontId_);
+ } else {
+ static_cast(lastSelectView_)
+ ->SetFont(pickerView_->backgroundFontName_, pickerView_->backgroundFontSize_);
+ }
+ lastSelectView_ = view;
+ }
+
+ view->SetStyle(STYLE_TEXT_COLOR, pickerView_->GetHighlightTextColor().full);
+ if (pickerView_->highlightFontName_ == nullptr) {
+ static_cast(view)->SetFontId(pickerView_->highlightFontId_);
+ } else {
+ static_cast(view)
+ ->SetFont(pickerView_->highlightFontName_, pickerView_->highlightFontSize_);
+ }
+
+ listView_->Invalidate();
+ selectView_ = view;
+ selectIndex_ = index;
+
+ if (pickerView_->pickerListener_) {
+ pickerView_->pickerListener_->OnPickerStoped(*pickerView_);
+ }
+ }
+
+ void SetSelectView(UIView* view)
+ {
+ selectView_ = view;
+ lastSelectView_ = view;
+ }
+
+ const UIView* GetSelectView() const
+ {
+ return selectView_;
+ }
+
+ void SetSelectIndex(uint16_t index)
+ {
+ selectIndex_ = index;
+ }
+
+ uint16_t GetSelectIndex() const
+ {
+ return selectIndex_;
+ }
+
+ void SetInitStatus(bool status)
+ {
+ isInitted_ = status;
+ }
+
+private:
+ UIList* listView_;
+ UIPicker* pickerView_;
+ UIView* selectView_;
+ UIView* lastSelectView_;
+ uint16_t selectIndex_;
+ bool isInitted_;
+};
+
+UIPicker::UIPicker()
+ : isWidthSet_(false),
+ isHeightSet_(false),
+ textAdapter_(nullptr),
+ maxCount_(0),
+ setSelectedIndex_(0),
+ backgroundFontSize_(0),
+ highlightFontSize_(0),
+ backgroundFontName_(nullptr),
+ highlightFontName_(nullptr),
+ itemsWidth_(0),
+ itemsHeight_(0),
+ rangeValue_(nullptr),
+ rangeValueCount_(0),
+ startValue_(0),
+ endValue_(0),
+ isSetAdaptered_(false),
+ pickerListener_(nullptr)
+{
+ Theme* theme = ThemeManager::GetInstance().GetCurrent();
+ if (theme != nullptr) {
+ style_ = &(theme->GetPickerBackgroundStyle());
+ } else {
+ style_ = &(StyleDefault::GetPickerBackgroundStyle());
+ }
+ backgroundFontId_ = style_->font_;
+ backgroundColor_ = style_->textColor_;
+ direct_ = UITextLanguageDirect::TEXT_DIRECT_LTR;
+
+ if (theme != nullptr) {
+ style_ = &(theme->GetPickerHighlightStyle());
+ } else {
+ style_ = &(StyleDefault::GetPickerHighlightStyle());
+ }
+ highlightFontId_ = style_->font_;
+ highlightColor_ = style_->textColor_;
+
+ list_.SetThrowDrag(true);
+#if ENABLE_ROTATE_INPUT
+ list_.rotateFactor_ = 5; // 5: need to fit device to change
+ list_.rotateThreshold_ = 20; // 20: which means 20% of half view size
+#endif
+#if ENABLE_MOTOR
+ list_.SetMotorType(MotorType::MOTOR_TYPE_TWO);
+#endif
+ list_.SetLoopState(false);
+ list_.EnableAutoAlign(true);
+ list_.SetIntercept(false);
+ PickerListScrollListener* listener = new PickerListScrollListener(this, &list_);
+ list_.SetScrollStateListener(listener);
+ listListener_ = static_cast(listener);
+ Add(&list_);
+}
+
+UIPicker::~UIPicker()
+{
+ ClearValues();
+ Remove(&list_);
+ if (listListener_ != nullptr) {
+ delete static_cast(listListener_);
+ listListener_ = nullptr;
+ }
+
+ if (backgroundFontName_ != nullptr) {
+ UIFree(backgroundFontName_);
+ backgroundFontName_ = nullptr;
+ }
+
+ if (highlightFontName_ != nullptr) {
+ UIFree(highlightFontName_);
+ highlightFontName_ = nullptr;
+ }
+
+ if (textAdapter_ != nullptr) {
+ delete textAdapter_;
+ textAdapter_ = nullptr;
+ }
+}
+
+bool UIPicker::SetValues(int16_t start, int16_t end)
+{
+ if (start > end) {
+ return false;
+ }
+
+ startValue_ = start;
+ endValue_ = end;
+ return RefreshValues(start, end);
+}
+
+bool UIPicker::SetValues(const char* value[], uint16_t count)
+{
+ if (value == nullptr) {
+ return false;
+ }
+
+ rangeValue_ = value;
+ rangeValueCount_ = count;
+ return RefreshValues(value, count);
+}
+
+void UIPicker::Refresh()
+{
+ if (rangeValue_) {
+ RefreshValues(rangeValue_, rangeValueCount_);
+ } else if ((startValue_ != 0) || (endValue_ != 0)) {
+ RefreshValues(startValue_, endValue_);
+ }
+}
+
+bool UIPicker::RefreshValues(int16_t start, int16_t end)
+{
+ if (!isWidthSet_ || !isHeightSet_ || !itemsHeight_ || ((start == 0) && (end == 0))) {
+ return false;
+ }
+
+ ClearList();
+ InitTextAdapter();
+ textAdapter_->SetData(start, end);
+ maxCount_ = end - start + 1;
+ RefreshList();
+ if (setSelectedIndex_) {
+ RefreshSelected(setSelectedIndex_);
+ }
+ return true;
+}
+
+bool UIPicker::RefreshValues(const char* value[], uint16_t count)
+{
+ if (value == nullptr || !isWidthSet_ || !isHeightSet_ || !itemsHeight_) {
+ return false;
+ }
+
+ ClearList();
+ for (uint16_t i = 0; i < count; i++) {
+ dataList_.PushBack(value[i]);
+ }
+ InitTextAdapter();
+ textAdapter_->SetData(&dataList_);
+ maxCount_ = count;
+ RefreshList();
+ if (setSelectedIndex_) {
+ RefreshSelected(setSelectedIndex_);
+ }
+
+ return true;
+}
+
+void UIPicker::RefreshList()
+{
+ int16_t height = GetHeight();
+ itemsWidth_ = GetWidth();
+ textAdapter_->SetWidth(itemsWidth_);
+ textAdapter_->SetHeight(itemsHeight_);
+ textAdapter_->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
+ if (backgroundFontName_ == nullptr) {
+ textAdapter_->SetFontId(backgroundFontId_);
+ } else {
+ textAdapter_->SetFont(backgroundFontName_, backgroundFontSize_);
+ }
+ textAdapter_->GetStyle().textColor_ = backgroundColor_;
+ textAdapter_->SetDirect(direct_);
+ list_.SetHeight(height);
+ list_.SetWidth(itemsWidth_);
+ list_.SetPosition(GetWidth() / 2 - list_.GetWidth() / 2, 0); // 2: half
+ list_.SetScrollBlankSize((height - itemsHeight_) / 2); // 2: half
+ list_.SetSelectPosition(height / 2); // 2: half
+ list_.SetStyle(*style_);
+ list_.SetStyle(STYLE_BORDER_WIDTH, 0);
+ list_.SetStyle(STYLE_BACKGROUND_OPA, 0);
+ if (!isSetAdaptered_) {
+ list_.SetAdapter(textAdapter_);
+ isSetAdaptered_ = true;
+ }
+
+ list_.RefreshList();
+ RefreshSelected(0);
+}
+
+void UIPicker::ClearValues()
+{
+ rangeValue_ = nullptr;
+ rangeValueCount_ = 0;
+ setSelectedIndex_ = 0;
+ ClearList();
+}
+
+void UIPicker::ClearList()
+{
+ maxCount_ = 0;
+ itemsWidth_ = 0;
+ if (listListener_) {
+ PickerListScrollListener* listListener = static_cast(listListener_);
+ listListener->SetSelectView(nullptr);
+ listListener->SetSelectIndex(0);
+ listListener->SetInitStatus(false);
+ }
+ dataList_.Clear();
+}
+
+bool UIPicker::SetSelected(uint16_t index)
+{
+ setSelectedIndex_ = index;
+ return RefreshSelected(index);
+}
+
+bool UIPicker::RefreshSelected(uint16_t index)
+{
+ if (itemsHeight_ && (maxCount_ > index) && (list_.GetChildrenHead() != nullptr) && isWidthSet_ && isHeightSet_) {
+ PickerListScrollListener* listListener = static_cast(listListener_);
+ listListener->SetInitStatus(false);
+ // 2: half
+ int16_t yOffset = (list_.GetHeight() - itemsHeight_) / 2 -
+ itemsHeight_ * (index - list_.GetChildrenHead()->GetViewIndex());
+ list_.SetScrollStateListener(nullptr);
+ list_.ScrollBy(yOffset - list_.GetChildrenHead()->GetY());
+ list_.SetScrollStateListener(listListener);
+ listListener->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
+ UIView* childView = static_cast(list_.GetChildrenHead());
+ uint16_t lastSelectIndex = listListener->GetSelectIndex();
+
+ int16_t viewIndex;
+ while (childView != nullptr) {
+ viewIndex = childView->GetViewIndex();
+ if (viewIndex == lastSelectIndex) {
+ childView->SetStyle(STYLE_TEXT_COLOR, GetBackgroundTextColor().full);
+ if (backgroundFontName_ == nullptr) {
+ static_cast(childView)->SetFontId(backgroundFontId_);
+ } else {
+ static_cast(childView)->SetFont(backgroundFontName_, backgroundFontSize_);
+ }
+ }
+ if (viewIndex == index) {
+ childView->SetStyle(STYLE_TEXT_COLOR, GetHighlightTextColor().full);
+ if (highlightFontName_ == nullptr) {
+ static_cast(childView)->SetFontId(highlightFontId_);
+ } else {
+ static_cast(childView)->SetFont(highlightFontName_, highlightFontSize_);
+ }
+ listListener->SetSelectView(childView);
+ listListener->SetSelectIndex(index);
+ listListener->SetInitStatus(true);
+ }
+ childView = childView->GetNextSibling();
+ }
+ list_.Invalidate();
+ return true;
+ }
+ return false;
+}
+
+uint16_t UIPicker::GetSelected() const
+{
+ PickerListScrollListener* listListener = static_cast(listListener_);
+ return listListener->GetSelectIndex();
+}
+
+void UIPicker::SetFontId(uint8_t backgroundFontId, uint8_t highlightFontId)
+{
+ backgroundFontId_ = backgroundFontId;
+ if (backgroundFontName_ != nullptr) {
+ UIFree(backgroundFontName_);
+ backgroundFontName_ = nullptr;
+ }
+
+ highlightFontId_ = highlightFontId;
+ if (highlightFontName_ != nullptr) {
+ UIFree(highlightFontName_);
+ highlightFontName_ = nullptr;
+ }
+
+ Refresh();
+}
+
+void UIPicker::SetBackgroundFont(const char* name, uint8_t size)
+{
+ Text::SetFont(name, size, backgroundFontName_, backgroundFontSize_);
+ Refresh();
+}
+
+void UIPicker::SetHighlightFont(const char* name, uint8_t size)
+{
+ Text::SetFont(name, size, highlightFontName_, highlightFontSize_);
+ Refresh();
+}
+
+void UIPicker::SetTextColor(ColorType backgroundColor, ColorType highlightColor)
+{
+ backgroundColor_ = backgroundColor;
+ highlightColor_ = highlightColor;
+ Refresh();
+}
+
+void UIPicker::SetItemHeight(int16_t height)
+{
+ if (height > 0) {
+ itemsHeight_ = height;
+ Refresh();
+ }
+}
+
+void UIPicker::SetWidth(int16_t width)
+{
+ if (width > 0) {
+ UIView::SetWidth(width);
+ isWidthSet_ = true;
+ Refresh();
+ }
+}
+
+void UIPicker::SetHeight(int16_t height)
+{
+ if (height > 0) {
+ UIView::SetHeight(height);
+ isHeightSet_ = true;
+ Refresh();
+ }
+}
+
+void UIPicker::SetLoopState(bool state)
+{
+ list_.SetLoopState(state);
+}
+
+void UIPicker::SetDirect(UITextLanguageDirect direct)
+{
+ direct_ = direct;
+ Refresh();
+}
+
+void UIPicker::SetTextFormatter(TextFormatter* formatter)
+{
+ InitTextAdapter();
+ textAdapter_->SetTextFormatter(formatter);
+ Refresh();
+}
+}
diff --git a/frameworks/components/ui_qrcode.cpp b/frameworks/components/ui_qrcode.cpp
new file mode 100755
index 0000000..7011816
--- /dev/null
+++ b/frameworks/components/ui_qrcode.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "components/ui_qrcode.h"
+#include "QrCode.hpp"
+#include "graphic_log.h"
+#include "securec.h"
+
+using qrcodegen::QrCode;
+namespace OHOS {
+UIQrcode::UIQrcode()
+ : width_(0), needDraw_(false), backgroundColor_(Color::White()), qrColor_(Color::Black()), qrcodeVal_(nullptr)
+{
+ style_ = &(StyleDefault::GetBackgroundTransparentStyle());
+ imageInfo_ = {{0}};
+}
+
+UIQrcode::~UIQrcode()
+{
+ if (qrcodeVal_ != nullptr) {
+ UIFree(qrcodeVal_);
+ qrcodeVal_ = nullptr;
+ }
+
+ if (imageInfo_.data != nullptr) {
+ ImageCacheFree(imageInfo_);
+ imageInfo_.data = nullptr;
+ }
+}
+
+void UIQrcode::SetQrcodeInfo(const char* val, ColorType backgroundColor, ColorType qrColor)
+{
+ if (val == nullptr) {
+ GRAPHIC_LOGE("UIQrcode::SetQrcodeInfo val is null!\n");
+ return;
+ }
+ uint32_t length = static_cast(strlen(val));
+ if ((length > QRCODE_VAL_MAX) || (length == 0)) {
+ GRAPHIC_LOGE("UIQrcode::SetQrcodeInfo val length is equal 0 or greater than QRCODE_VAL_MAX!\n");
+ return;
+ }
+ backgroundColor_ = backgroundColor;
+ qrColor_ = qrColor;
+ SetQrcodeVal(val, length);
+ RefreshQrcode();
+}
+
+void UIQrcode::RefreshQrcode()
+{
+ Invalidate();
+ if (!needDraw_) {
+ needDraw_ = true;
+ }
+}
+
+void UIQrcode::SetWidth(int16_t width)
+{
+ if (GetWidth() != width) {
+ UIView::SetWidth(width);
+ RefreshQrcode();
+ }
+}
+
+void UIQrcode::SetHeight(int16_t height)
+{
+ if (GetHeight() != height) {
+ UIView::SetHeight(height);
+ RefreshQrcode();
+ }
+}
+
+void UIQrcode::ReMeasure()
+{
+ if (!needDraw_) {
+ return;
+ }
+ needDraw_ = false;
+ if (qrcodeVal_ == nullptr) {
+ GRAPHIC_LOGE("UIQrcode::ReMeasure qrcodeVal_ is null!\n");
+ return;
+ }
+ QrCode qr = QrCode::encodeText(qrcodeVal_, QrCode::Ecc::LOW);
+ SetImageInfo(qr);
+ SetSrc(&imageInfo_);
+}
+
+void UIQrcode::SetQrcodeVal(const char* qrcodeVal, uint32_t length)
+{
+ if (qrcodeVal_ != nullptr) {
+ UIFree(qrcodeVal_);
+ qrcodeVal_ = nullptr;
+ }
+
+ uint32_t len = static_cast(length + 1);
+ qrcodeVal_ = static_cast(UIMalloc(len));
+ if (qrcodeVal_ != nullptr) {
+ if (memcpy_s(qrcodeVal_, len, qrcodeVal, len) != EOK) {
+ UIFree(reinterpret_cast(qrcodeVal_));
+ qrcodeVal_ = nullptr;
+ }
+ }
+}
+
+void UIQrcode::SetImageInfo(qrcodegen::QrCode& qrcode)
+{
+ int16_t width = GetWidth();
+ int16_t height = GetHeight();
+ width_ = (width >= height) ? height : width;
+ if (width_ < qrcode.getSize()) {
+ GRAPHIC_LOGE("UIQrcode::SetImageInfo width is less than the minimum qrcode width!\n");
+ return;
+ }
+ imageInfo_.header.width = width;
+ imageInfo_.header.height = height;
+ imageInfo_.header.colorMode = ARGB8888;
+ imageInfo_.dataSize = imageInfo_.header.width * imageInfo_.header.height * QRCODE_FACTOR_NUM;
+ if (imageInfo_.data != nullptr) {
+ ImageCacheFree(imageInfo_);
+ imageInfo_.data = nullptr;
+ }
+ imageInfo_.data = reinterpret_cast(ImageCacheMalloc(imageInfo_));
+ if (imageInfo_.data == nullptr) {
+ GRAPHIC_LOGE("UIQrcode::SetImageInfo imageInfo_.data is null!\n");
+ return;
+ }
+ GenerateQrCode(qrcode);
+}
+
+void UIQrcode::GenerateQrCode(qrcodegen::QrCode& qrcode)
+{
+ FillQrCodeBackgroundColor();
+
+ FillQrCodeColor(qrcode);
+}
+
+void UIQrcode::FillQrCodeColor(qrcodegen::QrCode& qrcode)
+{
+ int32_t qrWidth = qrcode.getSize();
+ if (qrWidth <= 0) {
+ GRAPHIC_LOGE("UIQrcode::FillQrCodeColor generated qrcode size is less or equal 0!\n");
+ return;
+ }
+ int16_t width = imageInfo_.header.width;
+ int16_t height = imageInfo_.header.height;
+ uint16_t outFilePixelPrescaler = width_ / qrWidth;
+ int32_t offsetX = (width - outFilePixelPrescaler * qrWidth) / 2; // 2: half
+ int32_t offsetY = (height - outFilePixelPrescaler * qrWidth) / 2; // 2: half
+
+ uint8_t* destData = nullptr;
+ int64_t oneLinePixel = width * QRCODE_FACTOR_NUM * outFilePixelPrescaler;
+ int64_t oneLineOffsetPixel = (offsetY * width * QRCODE_FACTOR_NUM) + (offsetX * QRCODE_FACTOR_NUM);
+ for (int32_t y = 0; y < qrWidth; ++y) {
+ destData = const_cast