From 9ef4e47ffcbd6693e4db5162c9c49dd0a4381f36 Mon Sep 17 00:00:00 2001 From: liuwei Date: Thu, 27 Jun 2024 11:22:20 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E3=80=90=E5=BC=A7=E5=BD=A2=E7=B4=A2?= =?UTF-8?q?=E5=BC=95=E6=9D=A1=E3=80=91=E7=BB=84=E4=BB=B6=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liuwei Change-Id: I2a696f5dd00d1631b37a860623ab71be77502731 --- build/libace.map | 1 + component_ext/BUILD.gn | 1 + component_ext/arc_alphabet_indexer/BUILD.gn | 92 ++ .../arc_alphabet_indexer_napi.cpp | 133 ++ .../arc_alphabet_indexer_napi.h | 27 + .../arkui_arcalphabetindexer.js | 261 ++++ .../jsview/models/indexer_model_impl.cpp | 2 +- .../jsview/models/indexer_model_impl.h | 2 +- .../core/components/indexer/indexer_theme.h | 6 + .../core/components_ng/pattern/BUILD.gn | 4 + .../indexer/arc_indexer_content_modifier.cpp | 91 ++ .../indexer/arc_indexer_content_modifier.h | 83 ++ .../indexer/arc_indexer_layout_algorithm.cpp | 147 +++ .../indexer/arc_indexer_layout_algorithm.h | 88 ++ .../indexer/arc_indexer_layout_property.cpp | 85 ++ .../indexer/arc_indexer_layout_property.h | 47 + .../indexer/arc_indexer_paint_method.h | 68 + .../indexer/arc_indexer_paint_property.h | 89 ++ .../pattern/indexer/arc_indexer_pattern.cpp | 1098 +++++++++++++++++ .../pattern/indexer/arc_indexer_pattern.h | 156 +++ .../indexer/indexer_layout_algorithm.h | 1 + .../indexer/indexer_layout_property.cpp | 24 +- .../pattern/indexer/indexer_layout_property.h | 3 + .../pattern/indexer/indexer_model.h | 2 +- .../pattern/indexer/indexer_model_ng.cpp | 15 +- .../pattern/indexer/indexer_model_ng.h | 4 +- .../pattern/indexer/indexer_paint_property.h | 16 + .../pattern/indexer/indexer_pattern.h | 40 +- .../pattern/indexer/indexer_theme.h | 47 + test/unittest/BUILD.gn | 4 + test/unittest/core/pattern/indexer/BUILD.gn | 1 + .../indexer/arcindexer_pattern_test_ng.cpp | 652 ++++++++++ 32 files changed, 3264 insertions(+), 26 deletions(-) create mode 100644 component_ext/arc_alphabet_indexer/BUILD.gn create mode 100644 component_ext/arc_alphabet_indexer/arc_alphabet_indexer_napi.cpp create mode 100644 component_ext/arc_alphabet_indexer/arc_alphabet_indexer_napi.h create mode 100644 component_ext/arc_alphabet_indexer/arkui_arcalphabetindexer.js create mode 100644 frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.cpp create mode 100644 frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.h create mode 100644 frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.cpp create mode 100644 frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.h create mode 100755 frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.cpp create mode 100755 frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.h create mode 100644 frameworks/core/components_ng/pattern/indexer/arc_indexer_paint_method.h create mode 100755 frameworks/core/components_ng/pattern/indexer/arc_indexer_paint_property.h create mode 100644 frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.cpp create mode 100644 frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.h create mode 100644 test/unittest/core/pattern/indexer/arcindexer_pattern_test_ng.cpp diff --git a/build/libace.map b/build/libace.map index 9036fb84db0..fdbffedfc05 100644 --- a/build/libace.map +++ b/build/libace.map @@ -364,6 +364,7 @@ vtable?for?OHOS::Ace::NG::MovingPhotoNode; vtable?for?OHOS::Ace::NG::TouchEventActuator; vtable?for?OHOS::Ace::NG::SwiperModelNG; + vtable?for?OHOS::Ace::NG::IndexerModelNG; VTT?for?OHOS::Ace::NG::AccessibilityProperty; VTT?for?OHOS::Ace::NG::BoxLayoutAlgorithm; diff --git a/component_ext/BUILD.gn b/component_ext/BUILD.gn index 159a165b5be..9912ed17c7e 100644 --- a/component_ext/BUILD.gn +++ b/component_ext/BUILD.gn @@ -13,6 +13,7 @@ group("component_ext") { deps = [ + "arc_alphabet_indexer:arcalphabetindexer", "arc_swiper:arcswiper", "movingphoto:movingphotoview", ] diff --git a/component_ext/arc_alphabet_indexer/BUILD.gn b/component_ext/arc_alphabet_indexer/BUILD.gn new file mode 100644 index 00000000000..98cf7234d50 --- /dev/null +++ b/component_ext/arc_alphabet_indexer/BUILD.gn @@ -0,0 +1,92 @@ +# Copyright (c) 2024 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("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni") +import("//build/ohos.gni") +import("//foundation/arkui/ace_engine/ace_config.gni") +import("//foundation/arkui/ace_engine/build/ace_gen_obj.gni") + +component_ext_path = "${ace_root}/component_ext" + +additional_include_dirs = [ "${ace_root}" ] + +es2abc_gen_abc("gen_arkui_arcalphabetindexer_abc") { + src_js = rebase_path("arkui_arcalphabetindexer.js") + dst_file = rebase_path(target_out_dir + "/arkui_arcalphabetindexer.abc") + in_puts = [ "arkui_arcalphabetindexer.js" ] + out_puts = [ target_out_dir + "/arkui_arcalphabetindexer.abc" ] + extra_args = [ "--module" ] +} + +gen_obj("arkui_arcalphabetindexer_js") { + input = "arkui_arcalphabetindexer.js" + output = target_out_dir + "/arkui_arcalphabetindexer.o" + snapshot_dep = [] +} + +gen_obj("arkui_arcalphabetindexer_abc") { + input = get_label_info(":gen_arkui_arcalphabetindexer_abc", + "target_out_dir") + "/arkui_arcalphabetindexer.abc" + output = target_out_dir + "arkui_arcalphabetindexer_abc.o" + snapshot_dep = [ ":gen_arkui_arcalphabetindexer_abc" ] +} + +ohos_shared_library("arcalphabetindexer") { + defines = [ "USE_ARK_ENGINE" ] + sources = [ + "${component_ext_path}/arc_alphabet_indexer/arc_alphabet_indexer_napi.cpp", + "${component_ext_path}/ext_common/ext_napi_utils.cpp", + ] + + include_dirs = [ + "${component_ext_path}/ext_common/", + "${component_ext_path}/arc_alphabet_indexer/", + "${ace_root}/frameworks", + "$root_out_dir/arkui/framework", + ] + include_dirs += additional_include_dirs + + deps = [ + ":gen_obj_src_arkui_arcalphabetindexer_abc", + ":gen_obj_src_arkui_arcalphabetindexer_js", + "$ace_root/build:libace_compatible", + "$ace_root/interfaces/inner_api/ace:ace_uicontent", + "$ace_root/interfaces/napi/kits/plugincomponent:plugincomponent", + ] + + external_deps = [ + "bounds_checking_function:libsec_static", + "ets_runtime:libark_jsruntime", + "hilog:libhilog", + "napi:ace_container_scope", + "napi:ace_napi", + ] + + ldflags = [ "-Wl,--gc-sections" ] + + cflags = [ + "-fvisibility=hidden", + "-fdata-sections", + "-ffunction-sections", + "-Os", + ] + + cflags_cc = [ + "-fvisibility-inlines-hidden", + "-Os", + ] + + relative_install_dir = "module/arkui" + subsystem_name = ace_engine_subsystem + part_name = ace_engine_part +} diff --git a/component_ext/arc_alphabet_indexer/arc_alphabet_indexer_napi.cpp b/component_ext/arc_alphabet_indexer/arc_alphabet_indexer_napi.cpp new file mode 100644 index 00000000000..d82f3786751 --- /dev/null +++ b/component_ext/arc_alphabet_indexer/arc_alphabet_indexer_napi.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024 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 "arc_alphabet_indexer_napi.h" +#include "ext_napi_utils.h" +#include "core/components_ng/pattern/indexer/indexer_model_ng.h" + +extern const char _binary_arkui_arcalphabetindexer_js_start[]; +extern const char _binary_arkui_arcalphabetindexer_abc_start[]; +#if !defined(IOS_PLATFORM) +extern const char _binary_arkui_arcalphabetindexer_js_end[]; +extern const char _binary_arkui_arcalphabetindexer_abc_end[]; +#else +extern const char* _binary_arkui_arcalphabetindexer_js_end; +extern const char* _binary_arkui_arcalphabetindexer_abc_end; +#endif + +namespace OHOS::Ace { +namespace { +static constexpr const size_t MAX_ARG_NUM = 10; +} // namespace + +std::unique_ptr IndexerModel::instance_ = nullptr; +std::mutex IndexerModel::mutex_; + +IndexerModel* IndexerModel::GetInstance() +{ + if (!instance_) { + std::lock_guard lock(mutex_); + if (!instance_) { + instance_.reset(new NG::IndexerModelNG()); + } + } + return instance_.get(); +} + +napi_value JsCreate(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARG_NUM; + napi_value argv[MAX_ARG_NUM] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + if (argc > 0 && ExtNapiUtils::CheckTypeForNapiValue(env, argv[0], napi_object)) { + napi_value jsArrayValue = ExtNapiUtils::GetNamedProperty(env, argv[0], "arrayValue"); + if (!ExtNapiUtils::IsArray(env, jsArrayValue)) { + return ExtNapiUtils::CreateNull(env); + } + uint32_t length = 0; + std::vector indexerArray; + int32_t selectedVal = 0; + napi_get_array_length(env, jsArrayValue, &length); + for (uint32_t i = 0; i < length; i++) { + napi_value elementValue; + napi_get_element(env, jsArrayValue, i, &elementValue); + std::string valueString = ExtNapiUtils::GetStringFromValueUtf8(env, elementValue); + indexerArray.emplace_back(valueString); + } + napi_value jsSelected = ExtNapiUtils::GetNamedProperty(env, argv[0], "selected"); + if (ExtNapiUtils::CheckTypeForNapiValue(env, jsSelected, napi_number)) { + selectedVal = ExtNapiUtils::GetCInt32(env, jsSelected); + } + selectedVal = selectedVal < 0 ? 0 : selectedVal; + IndexerModel::GetInstance()->Create(indexerArray, selectedVal, true); + } + return ExtNapiUtils::CreateNull(env); +} + +napi_value InitArcAlphabetIndexer(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("create", JsCreate), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} + +napi_value ExportArcAlphabetIndexer(napi_env env, napi_value exports) +{ + InitArcAlphabetIndexer(env, exports); + return exports; +} + +} // namespace OHOS::Ace + +extern "C" __attribute__((visibility("default"))) void NAPI_arkui_ArcAlphabetIndexer_GetJSCode(const char** buf, + int* bufLen) +{ + if (buf != nullptr) { + *buf = _binary_arkui_arcalphabetindexer_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_arkui_arcalphabetindexer_js_end - _binary_arkui_arcalphabetindexer_js_start; + } +} + +// arkui_arcalphabetindexer JS register +extern "C" __attribute__((visibility("default"))) void NAPI_arkui_ArcAlphabetIndexer_GetABCCode(const char** buf, + int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_arkui_arcalphabetindexer_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_arkui_arcalphabetindexer_abc_end - _binary_arkui_arcalphabetindexer_abc_start; + } +} + +static napi_module arcAlphabetIndexerModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = OHOS::Ace::ExportArcAlphabetIndexer, + .nm_modname = "arkui.ArcAlphabetIndexer", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterArcAlphabetIndexerModule() +{ + napi_module_register(&arcAlphabetIndexerModule); +} diff --git a/component_ext/arc_alphabet_indexer/arc_alphabet_indexer_napi.h b/component_ext/arc_alphabet_indexer/arc_alphabet_indexer_napi.h new file mode 100644 index 00000000000..9112c4a80c8 --- /dev/null +++ b/component_ext/arc_alphabet_indexer/arc_alphabet_indexer_napi.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 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 COMPONENT_EXT_ARC_ALPHABET_INDEXER_NAPI_H +#define COMPONENT_EXT_ARC_ALPHABET_INDEXER_NAPI_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +#include "core/components_ng/pattern/indexer/indexer_model.h" + +namespace OHOS::Ace { +napi_value JsCreate(napi_env env, napi_callback_info info); +} // namespace OHOS::Ace +#endif // COMPONENT_EXT_ARC_ALPHABET_INDEXER_NAPI_H diff --git a/component_ext/arc_alphabet_indexer/arkui_arcalphabetindexer.js b/component_ext/arc_alphabet_indexer/arkui_arcalphabetindexer.js new file mode 100644 index 00000000000..7fb6552973d --- /dev/null +++ b/component_ext/arc_alphabet_indexer/arkui_arcalphabetindexer.js @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2024 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. + */ + +const __ArcAlphabetIndexer__ = requireInternal("arkui.ArcAlphabetIndexer"); +const LengthUnit = requireNapi('arkui.node').LengthUnit; + +class ArcAlphabetIndexerColorModifier extends ModifierWithKey { + static identity = Symbol('color'); + constructor(value) { + super(value); + } + applyPeer(node, reset) { + if (reset || !this.value) { + getUINativeModule().alphabetIndexer.resetColor(node); + } + else { + getUINativeModule().alphabetIndexer.setColor(node, this.value.color); + } + } + checkObjectDiff() { + if (!this.stageValue && !this.value) { + return false; + } else if (this.stageValue && this.value) { + return this.stageValue.color !== this.value.color; + } + return true; + } +} + +class ArcAlphabetIndexerSelectedColorModifier extends ModifierWithKey { + static identity = Symbol('selectedColor'); + constructor(value) { + super(value); + } + applyPeer(node, reset) { + if (reset || !this.value) { + getUINativeModule().alphabetIndexer.resetSelectedColor(node); + } + else { + getUINativeModule().alphabetIndexer.setSelectedColor(node, this.value.color); + } + } + checkObjectDiff() { + if (!this.stageValue && !this.value) { + return false; + } else if (this.stageValue && this.value) { + return this.stageValue.color !== this.value.color; + } + return true; + } +} + +class ArcAlphabetIndexerPopupColorModifier extends ModifierWithKey { + static identity = Symbol('popupColor'); + constructor(value) { + super(value); + } + applyPeer(node, reset) { + if (reset || !this.value) { + getUINativeModule().alphabetIndexer.resetPopupColor(node); + } + else { + getUINativeModule().alphabetIndexer.setPopupColor(node, this.value.color); + } + } + checkObjectDiff() { + if (!this.stageValue && !this.value) { + return false; + } else if (this.stageValue && this.value) { + return this.stageValue.color !== this.value.color; + } + return true; + } +} + +class ArcAlphabetIndexerSelectedBackgroundColorModifier extends ModifierWithKey { + static identity = Symbol('selectedBackgroundColor'); + constructor(value) { + super(value); + } + applyPeer(node, reset) { + if (reset || !this.value) { + getUINativeModule().alphabetIndexer.resetSelectedBackgroundColor(node); + } + else { + getUINativeModule().alphabetIndexer.setSelectedBackgroundColor(node, this.value.color); + } + } + checkObjectDiff() { + if (!this.stageValue && !this.value) { + return false; + } else if (this.stageValue && this.value) { + return this.stageValue.color !== this.value.color; + } + return true; + } +} + +class ArcAlphabetIndexerPopupBackgroundModifier extends ModifierWithKey { + static identity = Symbol('popupBackground'); + constructor(value) { + super(value); + } + applyPeer(node, reset) { + if (reset || !this.value) { + getUINativeModule().alphabetIndexer.resetPopupBackground(node); + } + else { + getUINativeModule().alphabetIndexer.setPopupBackground(node, this.value.color); + } + } + checkObjectDiff() { + if (!this.stageValue && !this.value) { + return false; + } else if (this.stageValue && this.value) { + return this.stageValue.color !== this.value.color; + } + return true; + } +} + +class ArcAlphabetIndexerItemSizeModifier extends ModifierWithKey { + static identity = Symbol('itemSize'); + constructor(value) { + super(value); + } + applyPeer(node, reset) { + if (reset || !this.value) { + getUINativeModule().alphabetIndexer.resetItemSize(node); + } + else { + let size = `${this.value.value}${LengthUnit[this.value.unit]}`; + getUINativeModule().alphabetIndexer.setItemSize(node, size); + } + } + checkObjectDiff() { + if (!this.stageValue && !this.value) { + return false; + } else if (this.stageValue && this.value) { + if (this.stageValue.value !== this.value.value || + this.stageValue.unit !== this.value.unit) { + return true; + } + return false; + } + return true; + } +} + +class ArcAlphabetIndexerComponent extends ArkAlphabetIndexerComponent { + constructor(nativePtr, classType) { + super(nativePtr, classType); + } + color(color) { + modifierWithKey(this._modifiersWithKeys, ArcAlphabetIndexerColorModifier.identity, ArcAlphabetIndexerColorModifier, color); + return this; + } + selectedColor(color) { + modifierWithKey(this._modifiersWithKeys, ArcAlphabetIndexerSelectedColorModifier.identity, ArcAlphabetIndexerSelectedColorModifier, color); + return this; + } + popupColor(color) { + modifierWithKey(this._modifiersWithKeys, ArcAlphabetIndexerPopupColorModifier.identity, ArcAlphabetIndexerPopupColorModifier, color); + return this; + } + selectedBackgroundColor(color) { + modifierWithKey(this._modifiersWithKeys, ArcAlphabetIndexerSelectedBackgroundColorModifier.identity, ArcAlphabetIndexerSelectedBackgroundColorModifier, color); + return this; + } + popupBackground(color) { + modifierWithKey(this._modifiersWithKeys, ArcAlphabetIndexerPopupBackgroundModifier.identity, ArcAlphabetIndexerPopupBackgroundModifier, color); + return this; + } + itemSize(size) { + modifierWithKey(this._modifiersWithKeys, ArcAlphabetIndexerItemSizeModifier.identity, ArcAlphabetIndexerItemSizeModifier, size); + return this; + } +} + +class ArcAlphabetIndexerModifier extends ArcAlphabetIndexerComponent { + constructor(nativePtr, classType) { + super(nativePtr, classType); + this._modifiersWithKeys = new ModifierMap(); + } + applyNormalAttribute(instance) { + ModifierUtils.applySetOnChange(this); + ModifierUtils.applyAndMergeModifier(instance, this); + } +} + +class ArcAlphabetIndexer extends AlphabetIndexer { + static attributeModifier(modifier) { + attributeModifierFunc.call(this, modifier, (nativePtr) => { + return new ArcAlphabetIndexerComponent(nativePtr); + }, (nativePtr, classType, modifierJS) => { + return new modifierJS.ArcAlphabetIndexerModifier(nativePtr, classType); + }); + } + + static create(value) { + __ArcAlphabetIndexer__.create(value); + } + + static color(value) { + if (value) { + value = value.color; + } + AlphabetIndexer.color(value); + } + + static selectedColor(value) { + if (value) { + value = value.color; + } + AlphabetIndexer.selectedColor(value); + } + + static popupColor(value) { + if (value) { + value = value.color; + } + AlphabetIndexer.popupColor(value); + } + + static selectedBackgroundColor(value) { + if (value) { + value = value.color; + } + AlphabetIndexer.selectedBackgroundColor(value); + } + + static popupBackground(value) { + if (value) { + value = value.color; + } + AlphabetIndexer.popupBackground(value); + } + + static itemSize(value) { + if (value) { + value = `${value.value}${LengthUnit[value.unit]}`; + } + AlphabetIndexer.itemSize(value); + } +} + +export default { + ArcAlphabetIndexer, +}; diff --git a/frameworks/bridge/declarative_frontend/jsview/models/indexer_model_impl.cpp b/frameworks/bridge/declarative_frontend/jsview/models/indexer_model_impl.cpp index aeb590e14e0..08a36c7cba9 100644 --- a/frameworks/bridge/declarative_frontend/jsview/models/indexer_model_impl.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/models/indexer_model_impl.cpp @@ -19,7 +19,7 @@ #include "bridge/declarative_frontend/view_stack_processor.h" namespace OHOS::Ace::Framework { -void IndexerModelImpl::Create(std::vector& indexerArray, int32_t selectedVal) +void IndexerModelImpl::Create(std::vector& indexerArray, int32_t selectedVal, bool isArc) { if (static_cast(indexerArray.size()) <= 0) { return; diff --git a/frameworks/bridge/declarative_frontend/jsview/models/indexer_model_impl.h b/frameworks/bridge/declarative_frontend/jsview/models/indexer_model_impl.h index 1579e8a3da0..3b25b25a1b0 100644 --- a/frameworks/bridge/declarative_frontend/jsview/models/indexer_model_impl.h +++ b/frameworks/bridge/declarative_frontend/jsview/models/indexer_model_impl.h @@ -21,7 +21,7 @@ namespace OHOS::Ace::Framework { class IndexerModelImpl : public OHOS::Ace::IndexerModel { public: - void Create(std::vector& indexerArray, int32_t selectedVal) override; + void Create(std::vector& indexerArray, int32_t selectedVal, bool isArc = false) override; void SetSelectedColor(const std::optional& color) override; void SetColor(const std::optional& color) override; void SetPopupColor(const std::optional& color) override; diff --git a/frameworks/core/components/indexer/indexer_theme.h b/frameworks/core/components/indexer/indexer_theme.h index 2569dcd8c0b..dea3495140c 100644 --- a/frameworks/core/components/indexer/indexer_theme.h +++ b/frameworks/core/components/indexer/indexer_theme.h @@ -52,6 +52,10 @@ public: } }; + const Color& GetIndexerBackgroundColor() const + { + return indexerBackgroundColor_; + } const Color& GetDefaultTextColor() const { return defaultTextColor_; @@ -164,6 +168,7 @@ public: protected: IndexerTheme() = default; + Color indexerBackgroundColor_; Color defaultTextColor_; Color selectedTextColor_; Color popupTextColor_; @@ -199,6 +204,7 @@ private: LOGE("Pattern of indexer is null, please check!"); return; } + theme->indexerBackgroundColor_ = indexerPattern->GetAttr("indexer_bar_color", Color(0xff262626)); theme->defaultTextColor_ = indexerPattern->GetAttr("default_text_color", Color(DEFAULT_TEXT_COLOR)); theme->selectedTextColor_ = indexerPattern->GetAttr("selected_text_color", Color(SELECT_TEXT_COLOR)); diff --git a/frameworks/core/components_ng/pattern/BUILD.gn b/frameworks/core/components_ng/pattern/BUILD.gn index 5f9ec8f5cbc..6306e01e7d2 100644 --- a/frameworks/core/components_ng/pattern/BUILD.gn +++ b/frameworks/core/components_ng/pattern/BUILD.gn @@ -166,6 +166,10 @@ build_component_ng("pattern_ng") { "image/image_pattern.cpp", "image_animator/image_animator_model_ng.cpp", "image_animator/image_animator_pattern.cpp", + "indexer/arc_indexer_content_modifier.cpp", + "indexer/arc_indexer_layout_algorithm.cpp", + "indexer/arc_indexer_layout_property.cpp", + "indexer/arc_indexer_pattern.cpp", "indexer/indexer_accessibility_property.cpp", "indexer/indexer_layout_algorithm.cpp", "indexer/indexer_layout_property.cpp", diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.cpp b/frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.cpp new file mode 100644 index 00000000000..e9c13edcd32 --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024 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 "core/components_ng/pattern/indexer/arc_indexer_content_modifier.h" + +#include +#include + +#include "base/geometry/arc.h" +#include "base/geometry/ng/offset_t.h" +#include "base/utils/utils.h" +#include "core/animation/curves.h" +#include "core/components/common/properties/color.h" +#include "core/components_ng/render/drawing_prop_convertor.h" +#include "core/components_ng/render/path_painter.h" +#include "core/pipeline/pipeline_base.h" +#include "core/components_ng/base/modifier.h" +#include "core/components_ng/render/drawing.h" +#include "core/components_ng/pattern/indexer/indexer_theme.h" + +namespace OHOS::Ace::NG { +ArcIndexerContentModifier::ArcIndexerContentModifier() +{ + strokeWidth_ = AceType::MakeRefPtr(0.0); + arcRadius_ = AceType::MakeRefPtr(0.0); + arcCenter_ = AceType::MakeRefPtr(OffsetF()); + startAngle_ = AceType::MakeRefPtr(0.0); + sweepAngle_ = AceType::MakeRefPtr(0.0); + stepAngle_ = AceType::MakeRefPtr(0.0); + AttachProperty(strokeWidth_); + AttachProperty(arcRadius_); + AttachProperty(startAngle_); + AttachProperty(sweepAngle_); + AttachProperty(arcCenter_); + AttachProperty(stepAngle_); +} + +void ArcIndexerContentModifier::onDraw(DrawingContext& context) +{ + DrawArc(context); +} + +void ArcIndexerContentModifier::DrawArc(DrawingContext& context) +{ + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto indexerTheme = pipeline->GetTheme(); + CHECK_NULL_VOID(indexerTheme); + auto strokeWidth = strokeWidth_->Get(); + + auto& canvas = context.canvas; + RSPen pen; + pen.SetAntiAlias(true); + pen.SetWidth(strokeWidth); + pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND)); + pen.SetColor(ToRSColor(indexerTheme->GetIndexerBackgroundColor())); + + RSFilter filter; + filter.SetMaskFilter(RSMaskFilter::CreateBlurMaskFilter( + RSBlurType::SOLID, RSDrawing::ConvertRadiusToSigma(strokeWidth), false)); + pen.SetFilter(filter); + + auto center = arcCenter_->Get(); + auto radius = arcRadius_->Get(); + auto startAngle = startAngle_->Get(); + auto sweepAngle = sweepAngle_->Get(); + auto stepAngle = stepAngle_->Get(); + if (NearEqual(sweepAngle + stepAngle, FULL_CIRCLE_ANGLE)) { + sweepAngle = FULL_CIRCLE_ANGLE; + } + + canvas.AttachPen(pen); + canvas.DrawArc( + { center.GetX() - radius, center.GetY() - radius, center.GetX() + radius, center.GetY() + radius }, + startAngle, sweepAngle); + canvas.DetachPen(); +} + +} // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.h b/frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.h new file mode 100644 index 00000000000..d6473705a37 --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024 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 FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_ARC_INDEXER_CONTENT_MODIFIER_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_ARC_INDEXER_CONTENT_MODIFIER_H + +#include "base/memory/referenced.h" +#include "base/utils/utils.h" +#include "core/components/common/properties/animation_option.h" +#include "core/components/indexer/indexer_theme.h" +#include "core/components_ng/pattern/indexer/indexer_theme.h" +#include "core/components_ng/base/modifier.h" +#include "core/components_ng/render/animation_utils.h" +#include "core/components_ng/render/drawing.h" +#include "core/pipeline_ng/pipeline_context.h" + +namespace OHOS::Ace::NG { +class PipelineContext; + +class ArcIndexerContentModifier : public ContentModifier { + DECLARE_ACE_TYPE(ArcIndexerContentModifier, ContentModifier); + +public: + explicit ArcIndexerContentModifier(); + ~ArcIndexerContentModifier() override = default; + + void onDraw(DrawingContext& context) override; + void DrawArc(DrawingContext& context); + + void SetStrokeWidth(float strokeWidth) + { + strokeWidth_->Set(strokeWidth); + } + + void SetArcCenter(OffsetF arcCenter) + { + arcCenter_->Set(arcCenter); + } + + void SetStartAngle(float startAngle) + { + startAngle_->Set(startAngle); + } + + void SetSweepAngle(float sweepAngle) + { + sweepAngle_->Set(sweepAngle); + } + + void SetArcRadius(float arcRadius) + { + arcRadius_->Set(arcRadius); + } + + void SetStepAngle(float stepAngle) + { + stepAngle_->Set(stepAngle); + } + +private: + RefPtr strokeWidth_; + RefPtr arcCenter_; + RefPtr startAngle_; + RefPtr sweepAngle_; + RefPtr arcRadius_; + RefPtr stepAngle_; + ACE_DISALLOW_COPY_AND_MOVE(ArcIndexerContentModifier); +}; + +} // namespace OHOS::Ace::NG +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_ARC_INDEXER_CONTENT_MODIFIER_H diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.cpp b/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.cpp new file mode 100644 index 00000000000..2549a0b83cb --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2024 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 "core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.h" + +#include "base/geometry/dimension.h" +#include "base/geometry/ng/size_t.h" +#include "base/utils/utils.h" +#include "core/components/common/layout/layout_param.h" +#include "core/components_ng/base/frame_node.h" +#include "core/components_ng/base/view_stack_processor.h" +#include "core/components_ng/layout/layout_wrapper.h" +#include "core/components_ng/pattern/indexer/arc_indexer_pattern.h" +#include "core/components_ng/pattern/text/text_model.h" +#include "core/components_ng/pattern/text/text_pattern.h" +#include "core/components_ng/property/layout_constraint.h" +#include "core/components_ng/property/measure_property.h" +#include "core/components_ng/property/measure_utils.h" + +namespace OHOS::Ace::NG { + +void ArcIndexerLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper) +{ + auto layoutProperty = AceType::DynamicCast(layoutWrapper->GetLayoutProperty()); + CHECK_NULL_VOID(layoutProperty); + LayoutConstraintF layoutConstraint; + if (layoutProperty->GetLayoutConstraint().has_value()) { + layoutConstraint = layoutProperty->GetLayoutConstraint().value(); + } + auto itemSize = layoutProperty->GetItemSize().value_or(Dimension(ARC_INDEXER_ITEM_SIZE, DimensionUnit::VP)); + itemSize_ = ConvertToPx(itemSize, layoutConstraint.scaleProperty, layoutConstraint.maxSize.Height()).value(); + auto selfIdealSize = layoutConstraint.selfIdealSize; + auto actualWidth = selfIdealSize.Width().has_value() + ? selfIdealSize.Width().value() + : Dimension(ARC_INDEXER_SIZE, DimensionUnit::VP).ConvertToPx(); + auto actualHeight = selfIdealSize.Height().has_value() + ? selfIdealSize.Height().value() + : Dimension(ARC_INDEXER_SIZE, DimensionUnit::VP).ConvertToPx(); + actualSize_ = actualWidth > actualHeight ? actualHeight : actualWidth; + layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF(actualWidth, actualHeight)); + MeasureArc(layoutWrapper); + + auto childCount = layoutWrapper->GetTotalChildCount(); + if (layoutProperty->GetIsPopupValue(false)) { + MeasurePopup(layoutWrapper, childCount); + childCount--; + } + auto childLayoutConstraint = layoutProperty->CreateChildConstraint(); + for (int32_t index = 0; index < childCount; index++) { + auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(index); + CHECK_NULL_VOID(childWrapper); + childLayoutConstraint.UpdateSelfMarginSizeWithCheck(OptionalSizeF(itemSize_, itemSize_)); + childWrapper->Measure(childLayoutConstraint); + } +} + +void ArcIndexerLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper) +{ + CHECK_NULL_VOID(layoutWrapper); + auto layoutProperty = DynamicCast(layoutWrapper->GetLayoutProperty()); + CHECK_NULL_VOID(layoutProperty); + auto childCount = layoutWrapper->GetTotalChildCount(); + if (layoutProperty->GetIsPopupValue(false)) { + const auto& child = layoutWrapper->GetChildByIndex(childCount - 1); + auto offset = GetPositionOfPopupNode(layoutWrapper); + child->GetHostNode()->GetRenderContext()->UpdatePosition(offset); + child->Layout(); + childCount -= 1; + } + for (int32_t i = 0; i < childCount; i++) { + const auto& child = layoutWrapper->GetChildByIndex(i); + auto offset = CalcArcItemPosition(i); + child->GetHostNode()->GetRenderContext()->UpdatePosition(offset); + child->Layout(); + } +} + +OffsetT ArcIndexerLayoutAlgorithm::CalcArcItemPosition(int32_t index) +{ + Offset position; + float itemAngle = (startAngle_ + stepAngle_ * index) * M_PI / HALF_CIRCLE_ANGLE; + position.SetX(arcCenter_.GetX() + arcRadius_ * cos(itemAngle) - itemRadius_); + position.SetY(arcCenter_.GetY() + arcRadius_ * sin(itemAngle) - itemRadius_); + auto offset = OffsetT(Dimension(position.GetX()), Dimension(position.GetY())); + return offset; +} + +OffsetT ArcIndexerLayoutAlgorithm::GetPositionOfPopupNode( + LayoutWrapper* layoutWrapper) +{ + auto bubbleSize = Dimension(ARC_BUBBLE_BOX_SIZE, DimensionUnit::VP).ConvertToPx(); + auto positionX = layoutWrapper->GetGeometryNode()->GetFrameSize().Width() * HALF - bubbleSize * HALF; + auto positionY = Dimension(ARC_BUBBLE_POSITION_Y, DimensionUnit::VP).ConvertToPx(); + return OffsetT(Dimension(positionX), Dimension(positionY)); +} + +void ArcIndexerLayoutAlgorithm::MeasurePopup(LayoutWrapper* layoutWrapper, uint32_t childCount) +{ + auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(childCount - 1); + CHECK_NULL_VOID(childWrapper); + auto childLayoutProperty = AceType::DynamicCast(childWrapper->GetLayoutProperty()); + CHECK_NULL_VOID(childLayoutProperty); + auto layoutConstraint = childLayoutProperty->GetLayoutConstraint(); + layoutConstraint->Reset(); + childWrapper->Measure(layoutConstraint); +} + +void ArcIndexerLayoutAlgorithm::MeasureArc(LayoutWrapper* layoutWrapper) +{ + auto layoutProperty = DynamicCast(layoutWrapper->GetLayoutProperty()); + auto positionX = layoutWrapper->GetGeometryNode()->GetFrameSize().Width() * HALF; + auto positionY = layoutWrapper->GetGeometryNode()->GetFrameSize().Height() * HALF; + arcCenter_.SetX(positionX); + arcCenter_.SetY(positionY); + + itemRadius_ = itemSize_ * HALF ; + arcRadius_ = positionX < positionY ? positionX - itemRadius_: positionY - itemRadius_; + stepAngle_ = DOUBLE * atan2f(itemRadius_, arcRadius_) * HALF_CIRCLE_ANGLE / M_PI; + auto autoCollapse = layoutProperty->GetAutoCollapse().value_or(false); + if (autoCollapse && fullCount_ > ARC_INDEXER_COLLAPSE_ITEM_COUNT) { + fullCount_ += 1; + } + if (stepAngle_ * fullCount_ > FULL_CIRCLE_ANGLE) { + stepAngle_ = FULL_CIRCLE_ANGLE / fullCount_; + } + if (fullCount_ > ARC_INDEXER_COLLAPSE_ITEM_COUNT) { + startAngle_ = -stepAngle_ * ARC_INDEXER_COLLAPSE_ITEM_COUNT * HALF; + } else { + startAngle_ = -stepAngle_ * fullCount_ * HALF + stepAngle_* HALF; + } + + sweepAngle_ = stepAngle_ * (itemCount_ - 1); +} + +} // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.h b/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.h new file mode 100644 index 00000000000..36688cecbcc --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 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 FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_ARC_INDEXER_LAYOUT_ALGORITHM_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_ARC_INDEXER_LAYOUT_ALGORITHM_H + +#include "core/components_ng/pattern/indexer/indexer_layout_algorithm.h" + +namespace OHOS::Ace::NG { + +class ACE_EXPORT ArcIndexerLayoutAlgorithm : public IndexerLayoutAlgorithm { + DECLARE_ACE_TYPE(ArcIndexerLayoutAlgorithm, IndexerLayoutAlgorithm); + +public: + ArcIndexerLayoutAlgorithm() = default; + ~ArcIndexerLayoutAlgorithm() override = default; + ArcIndexerLayoutAlgorithm(int32_t itemCount, int32_t fullCount) : itemCount_(itemCount), fullCount_(fullCount) {} + + float GetArcSize() const + { + return actualSize_; + } + + OffsetF GetArcCenter() const + { + return arcCenter_; + } + + float GetStartAngle() const + { + return startAngle_; + } + + float GetSweepAngle() const + { + return sweepAngle_; + } + + float GetArcRadius() const + { + return arcRadius_; + } + + float GetstepAngle() const + { + return stepAngle_; + } + + float GetitemRadius() const + { + return itemRadius_; + } + + void Measure(LayoutWrapper* layoutWrapper) override; + + void Layout(LayoutWrapper* layoutWrapper) override; + +private: + OffsetT GetPositionOfPopupNode(LayoutWrapper* layoutWrapper); + OffsetT CalcArcItemPosition(int32_t index); + void MeasurePopup(LayoutWrapper* layoutWrapper, uint32_t childCount); + void MeasureArc(LayoutWrapper* layoutWrapper); + int32_t itemCount_ = 0; + float itemSize_ = 0.0f; + int32_t fullCount_ = 0; + float actualSize_ = 0.0f; + OffsetF arcCenter_; + float startAngle_ = 0.0f; + float sweepAngle_ = 0.0f; + float arcRadius_ = 0.0f; + float stepAngle_ = 13.5f; + float itemRadius_ = 0.0f; +}; +} // namespace OHOS::Ace::NG + +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_ARC_INDEXER_LAYOUT_ALGORITHM_H diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.cpp b/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.cpp new file mode 100755 index 00000000000..b47cef28980 --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 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 "core/components_ng/pattern/indexer/arc_indexer_layout_property.h" +#include +#include +#include "base/json/json_util.h" +#include "core/components_ng/base/inspector_filter.h" +#include "core/components_v2/inspector/utils.h" + +namespace OHOS::Ace::NG { +namespace { +const std::string DEFAULT_FAMILY = "HarmonyOS Sans"; +} +void ArcIndexerLayoutProperty::ToJsonValue(std::unique_ptr& json, const InspectorFilter& filter) const +{ + LayoutProperty::ToJsonValue(json, filter); + /* no fixed attr below, just return */ + if (filter.IsFastFilter()) { + return; + } + json->PutExtAttr("selected", std::to_string(propSelected_.value_or(0)).c_str(), filter); + json->PutExtAttr("color", propColor_.value_or(Color::WHITE).ColorToString().c_str(), filter); + json->PutExtAttr("selectedColor", propSelectedColor_.value_or(Color::WHITE).ColorToString().c_str(), filter); + json->PutExtAttr("popupColor", propPopupColor_.value_or(Color::WHITE).ColorToString().c_str(), filter); + json->PutExtAttr("usingPopup", propUsingPopup_.value_or(false) ? "true" : "false", filter); + json->PutExtAttr("itemSize", + propItemSize_.value_or(Dimension(ARC_INDEXER_ITEM_SIZE, DimensionUnit::VP)).ToString().c_str(), filter); + auto jsonArrayValue = JsonUtil::CreateArray(true); + auto arrayValue = propArrayValue_.value_or(std::vector()); + for (uint32_t i = 0; i < arrayValue.size(); i++) { + auto index = std::to_string(i); + jsonArrayValue->Put(index.c_str(), arrayValue[i].c_str()); + } + json->PutExtAttr("arrayValue", jsonArrayValue, filter); + auto fontFamily = std::vector(); + fontFamily.emplace_back(DEFAULT_FAMILY); + auto defaultFont = TextStyle(); + defaultFont.SetFontStyle(FontStyle::NORMAL); + defaultFont.SetFontSize(Dimension(ARC_INDEXER_ITEM_TEXT_SIZE, DimensionUnit::FP)); + defaultFont.SetFontWeight(FontWeight::W500); + defaultFont.SetFontFamilies(fontFamily); + auto defaultPopupFont = TextStyle(); + defaultPopupFont.SetFontStyle(FontStyle::NORMAL); + defaultPopupFont.SetFontSize(Dimension(ARC_INDEXER_POPUP_TEXT_SIZE, DimensionUnit::FP)); + defaultPopupFont.SetFontWeight(FontWeight::W500); + defaultPopupFont.SetFontFamilies(fontFamily); + json->PutExtAttr("font", ToJsonObjectValue(propFont_.value_or(defaultFont)), filter); + json->PutExtAttr("selectFont", ToJsonObjectValue(propSelectedFont_.value_or(defaultFont)), filter); + json->PutExtAttr("popupFont", ToJsonObjectValue(propPopupFont_.value_or(defaultPopupFont)), filter); + json->PutExtAttr("autoCollapse", propAutoCollapse_.value_or(false) ? "true" : "false", filter); +} + +std::unique_ptr ArcIndexerLayoutProperty::ToJsonObjectValue(const TextStyle& textStyle) +{ + auto fontJsonObject = JsonUtil::Create(true); + fontJsonObject->Put("fontSize", textStyle.GetFontSize().ToString().c_str()); + fontJsonObject->Put( + "fontStyle", textStyle.GetFontStyle() == FontStyle::NORMAL ? "FontStyle.Normal" : "FontStyle.Italic"); + fontJsonObject->Put("fontWeight", V2::ConvertWrapFontWeightToStirng(textStyle.GetFontWeight()).c_str()); + auto fontFamilyVector = textStyle.GetFontFamilies(); + std::string fontFamily; + for (uint32_t i = 0; i < fontFamilyVector.size(); i++) { + if (i == (fontFamilyVector.size() - 1)) { + fontFamily += fontFamilyVector.at(i); + break; + } + fontFamily += fontFamilyVector.at(i) + ","; + } + fontJsonObject->Put("fontFamily", fontFamily.c_str()); + return fontJsonObject; +} +} // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.h b/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.h new file mode 100755 index 00000000000..9ad07b505f9 --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 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 FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_INDEXER_ARC_INDEXER_LAYOUT_PROPERTY_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_INDEXER_ARC_INDEXER_LAYOUT_PROPERTY_H + +#include "core/components_ng/pattern/indexer/indexer_layout_property.h" + +namespace OHOS::Ace::NG { +class ACE_EXPORT ArcIndexerLayoutProperty : public IndexerLayoutProperty { + DECLARE_ACE_TYPE(ArcIndexerLayoutProperty, IndexerLayoutProperty); + +public: + ArcIndexerLayoutProperty() = default; + ~ArcIndexerLayoutProperty() override = default; + + RefPtr Clone() const override + { + auto value = MakeRefPtr(); + value->IndexerLayoutProperty::UpdateLayoutProperty(DynamicCast(this)); + return value; + } + + void Reset() override + { + IndexerLayoutProperty::Reset(); + } + + void ToJsonValue(std::unique_ptr& json, const InspectorFilter& filter) const override; +private: + static std::unique_ptr ToJsonObjectValue(const TextStyle& textStyle); +}; +} // namespace OHOS::Ace::NG + +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_INDEXER_ARC_INDEXER_LAYOUT_PROPERTY_H diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_paint_method.h b/frameworks/core/components_ng/pattern/indexer/arc_indexer_paint_method.h new file mode 100644 index 00000000000..58a26b0d27e --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_paint_method.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 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 FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_ARC_INDEXER_PAINT_METHOD_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_ARC_INDEXER_PAINT_METHOD_H + +#include "core/components_ng/pattern/indexer/arc_indexer_content_modifier.h" +#include "core/components_ng/pattern/indexer/indexer_paint_property.h" +#include "core/components_ng/pattern/indexer/indexer_theme.h" +#include "core/components_ng/render/node_paint_method.h" +#include "core/pipeline/pipeline_base.h" + +namespace OHOS::Ace::NG { +class ACE_EXPORT ArcIndexerPaintMethod : public NodePaintMethod { + DECLARE_ACE_TYPE(ArcIndexerPaintMethod, NodePaintMethod) +public: + ArcIndexerPaintMethod(float strokeWidth, OffsetF arcCenter, float startAngle, float sweepAngle, + float arcRadius, float stepAngle, RefPtr arcindexerModifier) + : strokeWidth_(strokeWidth), arcCenter_(arcCenter), startAngle_(startAngle), + sweepAngle_(sweepAngle), arcRadius_(arcRadius), stepAngle_(stepAngle), + arcindexerModifier_(arcindexerModifier) + {} + ~ArcIndexerPaintMethod() override = default; + + RefPtr GetContentModifier(PaintWrapper* paintWrapper) override + { + CHECK_NULL_RETURN(arcindexerModifier_, nullptr); + return arcindexerModifier_; + } + + void UpdateContentModifier(PaintWrapper* paintWrapper) override + { + CHECK_NULL_VOID(arcindexerModifier_); + + arcindexerModifier_->SetStrokeWidth(strokeWidth_); + arcindexerModifier_->SetArcCenter(arcCenter_); + arcindexerModifier_->SetStartAngle(startAngle_); + arcindexerModifier_->SetSweepAngle(sweepAngle_); + arcindexerModifier_->SetArcRadius(arcRadius_); + arcindexerModifier_->SetStepAngle(stepAngle_); + } + +private: + float strokeWidth_ = 0.0f; + OffsetF arcCenter_; + float startAngle_ = 0.0f; + float sweepAngle_ = 0.0f; + float arcRadius_ = 0.0f; + float stepAngle_ = 0.0f; + + RefPtr arcindexerModifier_; + ACE_DISALLOW_COPY_AND_MOVE(ArcIndexerPaintMethod); +}; +} // namespace OHOS::Ace::NG + +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_ARC_INDEXER_PAINT_METHOD_H diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_paint_property.h b/frameworks/core/components_ng/pattern/indexer/arc_indexer_paint_property.h new file mode 100755 index 00000000000..62402bc84eb --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_paint_property.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024 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 FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_INDEXER_ARC_INDEXER_PAINT_PROPERTY_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_INDEXER_ARC_INDEXER_PAINT_PROPERTY_H + +#include "core/components_ng/pattern/indexer/indexer_paint_property.h" + +namespace OHOS::Ace::NG { +class ACE_EXPORT ArcIndexerPaintProperty : public IndexerPaintProperty { + DECLARE_ACE_TYPE(ArcIndexerPaintProperty, IndexerPaintProperty); + +public: + ArcIndexerPaintProperty() = default; + + ~ArcIndexerPaintProperty() override = default; + + RefPtr Clone() const override + { + auto value = MakeRefPtr(); + value->IndexerPaintProperty::UpdateLayoutProperty(DynamicCast(this)); + return value; + } + + void Reset() override + { + IndexerPaintProperty::Reset(); + } + + void ToJsonValue(std::unique_ptr& json, const InspectorFilter& filter) const override + { + PaintProperty::ToJsonValue(json, filter); + /* no fixed attr below, just return */ + if (filter.IsFastFilter()) { + return; + } + json->PutExtAttr("selectedBackgroundColor", + propSelectedBackgroundColor_.value_or(Color(ARC_INDEXER_SELECTED_BG_COLOR)).ColorToString().c_str(), filter); + json->PutExtAttr("popupBackground", + propPopupBackground_.value_or(Color(ARC_POPUP_BG_COLOR)).ColorToString().c_str(), filter); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto indexerTheme = pipeline->GetTheme(); + CHECK_NULL_VOID(indexerTheme); + if (propPopupBorderRadius_.has_value()) { + json->PutExtAttr("popupBorderRadius", propPopupBorderRadius_.value().ToString().c_str(), filter); + } else { + json->PutExtAttr("popupBorderRadius", + Dimension(ARC_BUBBLE_BOX_RADIUS, DimensionUnit::VP).ToString().c_str(), filter); + } + if (propItemBorderRadius_.has_value()) { + json->PutExtAttr("itemBorderRadius", propItemBorderRadius_.value().ToString().c_str(), filter); + } else { + json->PutExtAttr("itemBorderRadius", + Dimension(ARC_INDEXER_DEFAULT_RADIUS, DimensionUnit::VP).ToString().c_str(), filter); + } + if (propIndexerBorderRadius_.has_value()) { + json->PutExtAttr("indexerBorderRadius", propIndexerBorderRadius_.value().ToString().c_str(), filter); + } else { + json->PutExtAttr("indexerBorderRadius", + Dimension(ARC_INDEXER_DEFAULT_RADIUS, DimensionUnit::VP).ToString().c_str(), filter); + } + BlurStyleOption blurStyleOption; + if (propPopupBackgroundBlurStyle_.has_value()) { + blurStyleOption = propPopupBackgroundBlurStyle_.value(); + } else { + blurStyleOption.blurStyle = BlurStyle::COMPONENT_REGULAR; + } + auto jsonValue = JsonUtil::Create(true); + blurStyleOption.ToJsonValue(jsonValue, filter); + json->PutExtAttr("popupBackgroundBlurStyle", + jsonValue->GetValue("backgroundBlurStyle")->GetValue("value"), filter); + } +}; +} // namespace OHOS::Ace::NG + +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_INDEXER_INDEXER_PAINT_PROPERTY_H diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.cpp b/frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.cpp new file mode 100644 index 00000000000..d4923abf51a --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.cpp @@ -0,0 +1,1098 @@ +/* + * Copyright (c) 2024 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 "core/components_ng/pattern/indexer/arc_indexer_pattern.h" + +#include "core/components_ng/pattern/stack/stack_pattern.h" +#include "core/components_ng/pattern/text/text_layout_property.h" +#include "core/components_ng/pattern/text/text_model.h" +#include "core/components_ng/pattern/text/text_pattern.h" + +namespace OHOS::Ace::NG { +namespace { +constexpr float STR_DOT_ROTATE_ANGLE = 90; +constexpr int32_t ANIMATION_DURATION_20 = 20; +} +void ArcIndexerPattern::OnModifyDone() +{ + Pattern::OnModifyDone(); + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_VOID(layoutProperty); + auto itemCountChanged = false; + bool autoCollapseModeChanged = true; + if (!isNewHeightCalculated_) { + auto autoCollapse = layoutProperty->GetAutoCollapse().value_or(false); + autoCollapseModeChanged = autoCollapse != autoCollapse_; + autoCollapse_ = autoCollapse; + + auto newArray = layoutProperty->GetArrayValue().value_or(std::vector()); + bool arrayValueChanged = newArray.size() != fullArrayValue_.size() || newArray != fullArrayValue_; + if (arrayValueChanged || autoCollapseModeChanged) { + currectCollapsingMode_ = ArcIndexerCollapsingMode::INVALID; + } + fullArrayValue_ = newArray; + } + fullCount_ = fullArrayValue_.size(); + if (fullCount_ > 0) { + if (autoCollapse_) { + sharpItemCount_ = fullArrayValue_.at(0) == StringUtils::Str16ToStr8(ARC_INDEXER_STR_SHARP) ? 1 : 0; + CollapseArrayValue(); + } else { + sharpItemCount_ = 0; + BuildFullArrayValue(); + } + itemCountChanged = (itemCount_ != static_cast(arcArrayValue_.size())); + itemCount_ = static_cast(arcArrayValue_.size()); + } else { + sharpItemCount_ = 0; + itemCountChanged = (itemCount_ != 0); + itemCount_ = 0; + arcArrayValue_.clear(); + } + BuildArrayValueItems(); + bool removeBubble = false; + auto usePopup = layoutProperty->GetUsingPopup().value_or(false); + if (isPopup_ != usePopup) { + isPopup_ = usePopup; + removeBubble = !isPopup_; + } + + // Remove bubble if auto-collapse mode switched on/off or if items count changed + bool isChange = autoCollapseModeChanged || itemCountChanged; + removeBubble |= isChange; + if (removeBubble) { + RemoveBubble(); + } + + auto propSelect = layoutProperty->GetSelected().value(); + if (propSelect < 0 || propSelect >= itemCount_) { + propSelect = 0; + layoutProperty->UpdateSelected(propSelect); + } + + if (propSelect != selected_) { + selected_ = propSelect; + selectChanged_ = true; + ResetStatus(); + } else if (!isNewHeightCalculated_) { + selectChanged_ = false; + } + isNewHeightCalculated_ = false; + auto itemSize = + layoutProperty->GetItemSize().value_or(Dimension(ARC_INDEXER_ITEM_SIZE, DimensionUnit::VP)).ConvertToPx(); + lastItemSize_ = itemSize; + auto needMarkDirty = (layoutProperty->GetPropertyChangeFlag() == PROPERTY_UPDATE_NORMAL); + ApplyIndexChanged(needMarkDirty, initialized_ && selectChanged_, false); + auto gesture = host->GetOrCreateGestureEventHub(); + if (gesture) { + InitPanEvent(gesture); + } + if (!touchListener_) { + CHECK_NULL_VOID(gesture); + auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) { + auto offset = info.GetTouches().front().GetLocalLocation(); + auto indexerPattern = weak.Upgrade(); + CHECK_NULL_VOID(indexerPattern); + if (!indexerPattern->AtArcHotArea(offset)) { + return; + } + if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) { + indexerPattern->isTouch_ = true; + indexerPattern->OnTouchDown(info); + } else if (info.GetTouches().front().GetTouchType() == TouchType::UP) { + indexerPattern->isTouch_ = false; + indexerPattern->OnTouchUp(info); + } + }; + touchListener_ = MakeRefPtr(std::move(touchCallback)); + gesture->AddTouchEvent(touchListener_); + } + SetAccessibilityAction(); +} + +bool ArcIndexerPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dirty, const DirtySwapConfig& config) +{ + if (config.skipMeasure && config.skipLayout) { + return false; + } + auto layoutAlgorithmWrapper = DynamicCast(dirty->GetLayoutAlgorithm()); + CHECK_NULL_RETURN(layoutAlgorithmWrapper, false); + auto layoutAlgorithm = DynamicCast(layoutAlgorithmWrapper->GetLayoutAlgorithm()); + CHECK_NULL_RETURN(layoutAlgorithm, false); + auto size = layoutAlgorithm->GetArcSize(); + if (arcIndexerSize_ != size && autoCollapse_) { + arcIndexerSize_ = size; + isNewHeightCalculated_ = true; + auto hostNode = dirty->GetHostNode(); + StartCollapseDelayTask(hostNode, ARC_INDEXER_COLLAPSE_WAIT_DURATION); + } + strokeWidth_ = lastItemSize_; + arcCenter_ = layoutAlgorithm->GetArcCenter(); + startAngle_ = layoutAlgorithm->GetStartAngle(); + sweepAngle_ = layoutAlgorithm->GetSweepAngle(); + arcRadius_ = layoutAlgorithm->GetArcRadius(); + stepAngle_ = layoutAlgorithm->GetstepAngle(); + itemRadius_ = layoutAlgorithm->GetitemRadius(); + return true; +} + +void ArcIndexerPattern::BuildArrayValueItems() +{ + int32_t indexerSize = static_cast(arcArrayValue_.size()); + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_VOID(layoutProperty); + auto children = host->GetChildren(); + auto lastChildCount = static_cast(children.size()); + if (layoutProperty->GetIsPopupValue(false)) { + lastChildCount -= 1; + } + if (indexerSize != lastChildCount) { + host->Clean(); + layoutProperty->UpdateIsPopup(false); + for (int32_t index = 0; index < indexerSize; index++) { + auto indexerChildNode = FrameNode::CreateFrameNode( + V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr()); + CHECK_NULL_VOID(indexerChildNode); + host->AddChild(indexerChildNode); + } + } + std::vector arrayValueStrs; + for (auto indexerItem : arcArrayValue_) { + arrayValueStrs.push_back(indexerItem.first); + } + layoutProperty->UpdateArrayValue(arrayValueStrs); +} + +void ArcIndexerPattern::BuildFullArrayValue() +{ + arcArrayValue_.clear(); + size_t indexSize = fullArrayValue_.size() > ARC_INDEXER_ITEM_MAX_COUNT-1 ? + ARC_INDEXER_ITEM_MAX_COUNT-1 : fullArrayValue_.size(); + size_t startIndex = (indexSize > 29) ? (indexSize - 29) : 0; + for (size_t i = startIndex; i < indexSize; ++i) { + arcArrayValue_.push_back(std::pair(fullArrayValue_.at(i), ArcIndexerBarState::INVALID)); + } + + if (fullCount_ + sharpItemCount_ > ARC_INDEXER_COLLAPSE_ITEM_COUNT) { + arcArrayValue_.push_back( + std::pair(StringUtils::Str16ToStr8(ARC_INDEXER_STR_COLLAPSED), ArcIndexerBarState::COLLAPSED)); + } +} + +void ArcIndexerPattern::CollapseArrayValue() +{ + if (fullCount_ <= ARC_INDEXER_COLLAPSE_ITEM_COUNT || + currectCollapsingMode_ == ArcIndexerCollapsingMode::NONE) { + BuildFullArrayValue(); + } else { + ApplyFourPlusOneMode(); + } +} + +void ArcIndexerPattern::ApplyFourPlusOneMode() +{ + arcArrayValue_.clear(); + for (int32_t groupIndex = 0; groupIndex < ARC_INDEXER_COLLAPSE_ITEM_COUNT; groupIndex++) { + arcArrayValue_.push_back(std::pair(fullArrayValue_.at(groupIndex), ArcIndexerBarState::INVALID)); + } + arcArrayValue_.push_back( + std::pair(StringUtils::Str16ToStr8(ARC_INDEXER_STR_EXPANDED), ArcIndexerBarState::EXPANDED)); +} + +void ArcIndexerPattern::InitPanEvent(const RefPtr& gestureHub) +{ + if (panEvent_) { + return; + } + auto onActionStart = [weak = WeakClaim(this)](const GestureEvent& info) { + auto pattern = weak.Upgrade(); + if (pattern) { + if (info.GetInputEventType() == InputEventType::AXIS) { + return; + } + pattern->MoveIndexByOffset(info.GetLocalLocation()); + } + }; + + auto onActionUpdate = [weak = WeakClaim(this)](const GestureEvent& info) { + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + if (info.GetInputEventType() == InputEventType::AXIS) { + if (GreatNotEqual(info.GetMainDelta(), 0.0)) { + pattern->MoveIndexByStep(-1); + } else if (LessNotEqual(info.GetMainDelta(), 0.0)) { + pattern->MoveIndexByStep(1); + } + } else { + pattern->MoveIndexByOffset(info.GetLocalLocation()); + } + }; + + PanDirection panDirection; + panDirection.type = PanDirection::VERTICAL; + panEvent_ = MakeRefPtr( + std::move(onActionStart), std::move(onActionUpdate), nullptr, nullptr); + gestureHub->AddPanEvent(panEvent_, panDirection, 1, 0.0_vp); + gestureHub->SetOnGestureJudgeNativeBegin([weak = WeakClaim(this)](const RefPtr& gestureInfo, + const std::shared_ptr& info) -> GestureJudgeResult { + auto pattern = weak.Upgrade(); + CHECK_NULL_RETURN(pattern, GestureJudgeResult::CONTINUE); + auto localLocation = info->GetFingerList().begin()->localLocation_; + if (pattern->AtArcHotArea(localLocation)) { + return GestureJudgeResult::CONTINUE; + } + return GestureJudgeResult::REJECT; + }); +} + +void ArcIndexerPattern::OnTouchDown(const TouchEventInfo& info) +{ + if (itemCount_ <= 0) { + return; + } + auto offset = info.GetTouches().front().GetLocalLocation(); + MoveIndexByOffset(offset); +} + +void ArcIndexerPattern::OnTouchUp(const TouchEventInfo& info) +{ + if (itemCount_ <= 0) { + return; + } + if (childPressIndex_ > -1) { + ArcIndexerPressOutAnimation(); + } + childPressIndex_ = -1; + ResetStatus(); + ApplyIndexChanged(true, true, true); + OnSelect(true); +} + +void ArcIndexerPattern::MoveIndexByOffset(const Offset& offset) +{ + if (itemCount_ <= 0) { + return; + } + auto nextSelectIndex = GetSelectChildIndex(offset); + if (nextSelectIndex == itemCount_) { + return; + } + if (arcArrayValue_[nextSelectIndex].second != ArcIndexerBarState::INVALID) { + isNewHeightCalculated_ = true; + if (arcArrayValue_[nextSelectIndex].second == ArcIndexerBarState::COLLAPSED && autoCollapse_) { + currectCollapsingMode_ = ArcIndexerCollapsingMode::FOUR; + lastCollapsingMode_ = ArcIndexerCollapsingMode::NONE; + ArcCollapedAnimation(ARC_INDEXER_COLLAPSE_ITEM_COUNT); + IndexNodeCollapsedAnimation(); + } else { + currectCollapsingMode_ = ArcIndexerCollapsingMode::NONE; + lastCollapsingMode_ = ArcIndexerCollapsingMode::FOUR; + ArcExpandedAnimation(fullArrayValue_.size() - 1); + auto host = GetHost(); + host->MarkModifyDone(); + host->MarkDirtyNode(); + } + return; + } + if (nextSelectIndex == childPressIndex_) { + return; + } + childPressIndex_ = nextSelectIndex; + selected_ = nextSelectIndex; + lastSelected_ = nextSelectIndex; + FireOnSelect(selected_, true); + if (childPressIndex_ >= 0) { + ArcIndexerPressInAnimation(); + } + childFocusIndex_ = -1; + ApplyIndexChanged(true, true); +} + +void ArcIndexerPattern::IndexNodeCollapsedAnimation() +{ + if (!atomicAnimateOp_) { + return; + } + atomicAnimateOp_ = false; + InitCollapsedProperty(); + AnimationOption option; + option.SetCurve(Curves::FRICTION); + option.SetDuration(ARC_INDEXER_COLLAPED_DURATION); + option.SetIteration(1); + auto total = fullArrayValue_.size(); + float from = stepAngle_ * total; + collapsedAnimateIndex_ = total; + collapsedProperty_->Set(from); + float to = stepAngle_ * (ARC_INDEXER_COLLAPSE_ITEM_COUNT + 1); + AnimationUtils::Animate( + option, + [weak = AceType::WeakClaim(this), to]() { + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + pattern->collapsedProperty_->Set(to); + }, + [id = Container::CurrentId(), weak = AceType::WeakClaim(this)]() { + ContainerScope scope(id); + auto pattern = weak.Upgrade(); + auto host = pattern->GetHost(); + host->MarkModifyDone(); + host->MarkDirtyNode(); + pattern->atomicAnimateOp_ = true; + }); + lastCollapsingMode_ = currectCollapsingMode_; +} + +void ArcIndexerPattern::IndexNodeExpandedAnimation() +{ + if (!atomicAnimateOp_) { + return; + } + atomicAnimateOp_ = false; + InitExpandedProperty(); + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto total = host->GetTotalChildCount(); + AnimationOption option; + option.SetCurve(Curves::FRICTION); + option.SetDuration(ARC_INDEXER_EXPANDED_DURATION); + option.SetIteration(1); + float from = stepAngle_ * ARC_INDEXER_COLLAPSE_ITEM_COUNT; + expandedAnimateIndex_ = ARC_INDEXER_COLLAPSE_ITEM_COUNT; + expandedProperty_->Set(from); + float to = stepAngle_ * total; + AnimationUtils::Animate( + option, + [weak = AceType::WeakClaim(this), to]() { + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + pattern->expandedProperty_->Set(to); + }, + [weak = AceType::WeakClaim(this)]() { + auto pattern = weak.Upgrade(); + pattern->atomicAnimateOp_ = true; + }); + lastCollapsingMode_ = currectCollapsingMode_; +} + +void ArcIndexerPattern::StartIndexerNodeDisappearAnimation(int32_t nodeIndex) +{ + auto host = GetHost(); + auto total = fullArrayValue_.size(); + if (nodeIndex > total) { + return; + } + auto child = host->GetChildByIndex(nodeIndex); + CHECK_NULL_VOID(child); + auto childNode = child->GetHostNode(); + CHECK_NULL_VOID(childNode); + + AnimationOption option; + option.SetCurve(Curves::FRICTION); + option.SetDuration(ANIMATION_DURATION_20); + AnimationUtils::Animate( + option, + [childNode, id = Container::CurrentId(), weak = AceType::WeakClaim(this)]() { + ContainerScope scope(id); + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + pattern->SetIndexerNodeOpacity(childNode, 0.0f); + }); +} + +int32_t ArcIndexerPattern::GetSelectChildIndex(const Offset& offset) +{ + float indexAngle = GetPositionAngle(offset); + int32_t index = 0; + for (int32_t i = 0; i < itemCount_; i++) { + auto iAngle = startAngle_ + stepAngle_ * (i - HALF); + if (GreatOrEqual(indexAngle, iAngle) && LessNotEqual(indexAngle, iAngle + stepAngle_)) { + break; + } + index++; + } + return std::clamp(index, 0, itemCount_); +} + +void ArcIndexerPattern::ResetStatus() +{ + childFocusIndex_ = -1; + childPressIndex_ = -1; +} + +void ArcIndexerPattern::OnSelect(bool changed) +{ + auto host = GetHost(); + CHECK_NULL_VOID(host); + FireOnSelect(selected_, false); + animateSelected_ = selected_; + if (animateSelected_ >= 0) { + auto selectedFrameNode = DynamicCast(host->GetChildAtIndex(animateSelected_)); + CHECK_NULL_VOID(selectedFrameNode); + ItemSelectedInAnimation(selectedFrameNode); + } + if (lastSelected_ >= 0 && lastSelected_ != animateSelected_) { + auto lastFrameNode = DynamicCast(host->GetChildAtIndex(lastSelected_)); + CHECK_NULL_VOID(lastFrameNode); + ItemSelectedOutAnimation(lastFrameNode); + } + lastSelected_ = selected_; +} + +void ArcIndexerPattern::ApplyIndexChanged(bool isTextNodeInTree, bool selectChanged, bool fromTouchUp, + bool indexerSizeChanged) +{ + initialized_ = true; + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_VOID(layoutProperty); + auto paintProperty = host->GetPaintProperty(); + CHECK_NULL_VOID(paintProperty); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto indexerTheme = pipeline->GetTheme(); + CHECK_NULL_VOID(indexerTheme); + int32_t index = 0; + auto total = host->GetTotalChildCount(); + if (layoutProperty->GetIsPopupValue(false)) { + total -= 1; + } + auto indexerRenderContext = host->GetRenderContext(); + CHECK_NULL_VOID(indexerRenderContext); + auto indexerRadius = Dimension(arcRadius_, DimensionUnit::VP); + indexerRenderContext->UpdateBorderRadius({ indexerRadius, indexerRadius, indexerRadius, indexerRadius }); + indexerRenderContext->UpdateBackgroundColor(Color::TRANSPARENT); + for (int32_t i = 0; i < total; i++) { + auto child = host->GetChildByIndex(i); + CHECK_NULL_VOID(child); + auto childNode = child->GetHostNode(); + UpdateChildBoundary(childNode); + auto nodeLayoutProperty = childNode->GetLayoutProperty(); + auto childRenderContext = childNode->GetRenderContext(); + childRenderContext->SetClipToBounds(true); + + if (arcArrayValue_[index].second != ArcIndexerBarState::INVALID) { + float itemAngle = CalcArcItemAngle(i) + STR_DOT_ROTATE_ANGLE; + childRenderContext->UpdateTransformRotate(Vector5F(0.0f, 0.0f, 1.0f, itemAngle, 0.0f)); + nodeLayoutProperty->UpdateTextColor(Color(ARC_INDEXER_STR_DOT_COLOR)); + } else { + nodeLayoutProperty->UpdateTextColor( + layoutProperty->GetColor().value_or(indexerTheme->GetDefaultTextColor())); + } + auto radiusSize = Dimension(lastItemSize_ * HALF); + childRenderContext->UpdateBorderRadius({ radiusSize, radiusSize, radiusSize, radiusSize }); + auto nodeStr = autoCollapse_ && (arcArrayValue_[index].second != ArcIndexerBarState::INVALID) ? + (arcArrayValue_[index].second == ArcIndexerBarState::COLLAPSED ? + StringUtils::Str16ToStr8(ARC_INDEXER_STR_COLLAPSED) : + StringUtils::Str16ToStr8(ARC_INDEXER_STR_EXPANDED)) : arcArrayValue_[index].first; + if (index == childPressIndex_) { + childRenderContext->UpdateBackgroundColor(indexerTheme->GetPressedBgAreaColor()); + } else if (index == childFocusIndex_ || index == selected_) { + nodeLayoutProperty->UpdateContent(nodeStr); + nodeLayoutProperty->UpdateTextAlign(TextAlign::CENTER); + nodeLayoutProperty->UpdateAlignment(Alignment::CENTER); + if (index == childFocusIndex_) { + childRenderContext->UpdateBackgroundColor( + paintProperty->GetSelectedBackgroundColor().value_or(indexerTheme->GetSeclectedBackgroundColor())); + } else { + if (!fromTouchUp || animateSelected_ == lastSelected_) { + childRenderContext->UpdateBackgroundColor(paintProperty->GetSelectedBackgroundColor().value_or( + indexerTheme->GetSeclectedBackgroundColor())); + } + childRenderContext->ResetBlendBorderColor(); + } + nodeLayoutProperty->UpdateTextColor( + layoutProperty->GetSelectedColor().value_or(indexerTheme->GetSelectedTextColor())); + auto selectedFont = layoutProperty->GetSelectedFont().value_or(indexerTheme->GetSelectTextStyle()); + nodeLayoutProperty->UpdateFontSize(selectedFont.GetFontSize()); + auto fontWeight = selectedFont.GetFontWeight(); + nodeLayoutProperty->UpdateFontWeight(fontWeight); + nodeLayoutProperty->UpdateFontFamily(selectedFont.GetFontFamilies()); + nodeLayoutProperty->UpdateItalicFontStyle(selectedFont.GetFontStyle()); + childNode->MarkModifyDone(); + if (isTextNodeInTree) { + childNode->MarkDirtyNode(); + } + index++; + AccessibilityEventType type = AccessibilityEventType::SELECTED; + host->OnAccessibilityEvent(type); + auto textAccessibilityProperty = childNode->GetAccessibilityProperty(); + if (textAccessibilityProperty) { + textAccessibilityProperty->SetSelected(true); + } + continue; + } else { + if (!fromTouchUp || animateSelected_ == lastSelected_ || index != lastSelected_) { + childRenderContext->UpdateBackgroundColor(Color::TRANSPARENT); + } + } + Dimension borderWidth; + nodeLayoutProperty->UpdateContent(nodeStr); + nodeLayoutProperty->UpdateMaxLines(1); + nodeLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS); + nodeLayoutProperty->UpdateEllipsisMode(EllipsisMode::TAIL); + nodeLayoutProperty->UpdateTextAlign(TextAlign::CENTER); + nodeLayoutProperty->UpdateAlignment(Alignment::CENTER); + nodeLayoutProperty->UpdateBorderWidth({ borderWidth, borderWidth, borderWidth, borderWidth }); + childRenderContext->ResetBlendBorderColor(); + auto defaultFont = layoutProperty->GetFont().value_or(indexerTheme->GetDefaultTextStyle()); + nodeLayoutProperty->UpdateFontSize(defaultFont.GetFontSize()); + nodeLayoutProperty->UpdateFontWeight(defaultFont.GetFontWeight()); + nodeLayoutProperty->UpdateFontFamily(defaultFont.GetFontFamilies()); + nodeLayoutProperty->UpdateItalicFontStyle(defaultFont.GetFontStyle()); + nodeLayoutProperty->UpdateTextColor(layoutProperty->GetColor().value_or(indexerTheme->GetDefaultTextColor())); + auto textAccessibilityProperty = childNode->GetAccessibilityProperty(); + if (textAccessibilityProperty) { + textAccessibilityProperty->SetSelected(false); + } + if (!fromTouchUp && currectCollapsingMode_ == ArcIndexerCollapsingMode::NONE && + currectCollapsingMode_ != lastCollapsingMode_) { + UpdateIndexerNodeOpacityByIdx(childRenderContext, index); + } + index++; + childNode->MarkModifyDone(); + if (isTextNodeInTree) childNode->MarkDirtyNode(); + } + if (!fromTouchUp && currectCollapsingMode_ == ArcIndexerCollapsingMode::NONE + && currectCollapsingMode_ != lastCollapsingMode_) { + IndexNodeExpandedAnimation(); + } + if (selectChanged) { + ShowBubble(); + } +} + +void ArcIndexerPattern::InitExpandedProperty() +{ + if (expandedProperty_) { + return; + } + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto renderContext = host->GetRenderContext(); + CHECK_NULL_VOID(renderContext); + auto expandedAngleCallback = [weak = AceType::WeakClaim(this)](float angle) { + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + int32_t index = floor(angle / pattern->stepAngle_); + for (int32_t i = pattern->expandedAnimateIndex_; i <= index; i++) { + pattern->StartIndexerNodeAppearAnimation(i); + } + pattern->expandedAnimateIndex_ = index + 1; + }; + expandedProperty_ = AceType::MakeRefPtr(0.0, std::move(expandedAngleCallback)); + renderContext->AttachNodeAnimatableProperty(expandedProperty_); +} + +void ArcIndexerPattern::InitCollapsedProperty() +{ + if (collapsedProperty_) { + return; + } + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto renderContext = host->GetRenderContext(); + CHECK_NULL_VOID(renderContext); + auto collapsedAngleCallback = [weak = AceType::WeakClaim(this)](float angle) { + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + int32_t index = floor(angle / pattern->stepAngle_); + for (int32_t i = pattern->collapsedAnimateIndex_; i >= index; i--) { + pattern->StartIndexerNodeDisappearAnimation(i); + } + pattern->collapsedAnimateIndex_ = index - 1; + }; + collapsedProperty_ = AceType::MakeRefPtr(0.0, std::move(collapsedAngleCallback)); + renderContext->AttachNodeAnimatableProperty(collapsedProperty_); +} + +void ArcIndexerPattern::UpdateIndexerNodeOpacityByIdx(RefPtr& context, int32_t index) +{ + if (index <= ARC_INDEXER_COLLAPSE_ITEM_COUNT || currectCollapsingMode_ == lastCollapsingMode_) { + return; + } + switch (currectCollapsingMode_) { + case ArcIndexerCollapsingMode::NONE: + context->UpdateOpacity(0.0f); + break; + case ArcIndexerCollapsingMode::FOUR: + case ArcIndexerCollapsingMode::INVALID: + default: + break; + } +} + +void ArcIndexerPattern::StartIndexerNodeAppearAnimation(int32_t nodeIndex) +{ + auto host = GetHost(); + auto total = fullArrayValue_.size(); + if (nodeIndex > total) { + return; + } + auto child = host->GetChildByIndex(nodeIndex); + CHECK_NULL_VOID(child); + auto childNode = child->GetHostNode(); + CHECK_NULL_VOID(childNode); + + AnimationOption option; + option.SetCurve(Curves::FRICTION); + option.SetDuration(ANIMATION_DURATION_20); + AnimationUtils::Animate( + option, + [childNode, id = Container::CurrentId(), weak = AceType::WeakClaim(this)]() { + ContainerScope scope(id); + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + pattern->SetIndexerNodeOpacity(childNode, 1.0f); + }); +} + +void ArcIndexerPattern::SetIndexerNodeOpacity(const RefPtr& itemNode, float ratio) +{ + auto rendercontext = itemNode->GetRenderContext(); + CHECK_NULL_VOID(rendercontext); + rendercontext->UpdateOpacity(ratio); +} + +void ArcIndexerPattern::ShowBubble() +{ + if (!NeedShowBubble() || itemCount_ < 1) { + return; + } + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_VOID(layoutProperty); + if (!popupNode_) { + popupNode_ = CreatePopupNode(); + UpdatePopupOpacity(0.0f); + } + if (!layoutProperty->GetIsPopupValue(false)) { + popupNode_->MountToParent(host); + layoutProperty->UpdateIsPopup(true); + } + UpdateBubbleView(); + delayTask_.Cancel(); + StartBubbleAppearAnimation(); + if (!isTouch_) { + StartDelayTask(ARC_INDEXER_BUBBLE_ENTER_DURATION + ARC_INDEXER_BUBBLE_WAIT_DURATION); + } +} + +RefPtr ArcIndexerPattern::CreatePopupNode() +{ + auto columnNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), + AceType::MakeRefPtr(true)); + CHECK_NULL_RETURN(columnNode, nullptr); + + auto letterNode = FrameNode::CreateFrameNode( + V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr()); + CHECK_NULL_RETURN(letterNode, nullptr); + auto letterStackNode = FrameNode::CreateFrameNode( + V2::STACK_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr()); + CHECK_NULL_RETURN(letterStackNode, nullptr); + letterStackNode->AddChild(letterNode); + columnNode->AddChild(letterStackNode); + return columnNode; +} + +void ArcIndexerPattern::UpdateBubbleView() +{ + CHECK_NULL_VOID(popupNode_); + auto host = GetHost(); + CHECK_NULL_VOID(host); + + auto currentListData = std::vector(); + UpdateBubbleLetterView(false, currentListData); + auto columnRenderContext = popupNode_->GetRenderContext(); + CHECK_NULL_VOID(columnRenderContext); + auto radius = Dimension(ARC_BUBBLE_RADIUS, DimensionUnit::VP); + columnRenderContext->UpdateBorderRadius({ radius, radius, radius, radius }); + columnRenderContext->UpdateBackShadow(Shadow::CreateShadow(ShadowStyle::OuterDefaultLG)); + + UpdateBubbleBackgroundView(); + columnRenderContext->SetClipToBounds(true); + popupNode_->MarkModifyDone(); + popupNode_->MarkDirtyNode(); +} + +void ArcIndexerPattern::UpdateBubbleBackgroundView() +{ + CHECK_NULL_VOID(popupNode_); + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto paintProperty = host->GetPaintProperty(); + CHECK_NULL_VOID(paintProperty); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto indexerTheme = pipeline->GetTheme(); + BlurStyleOption styleOption; + if (paintProperty->GetPopupBackgroundBlurStyle().has_value()) { + styleOption = paintProperty->GetPopupBackgroundBlurStyle().value(); + } else { + styleOption.blurStyle = BlurStyle::COMPONENT_REGULAR; + } + auto bubbleRenderContext = popupNode_->GetRenderContext(); + CHECK_NULL_VOID(bubbleRenderContext); + bubbleRenderContext->UpdateBackBlurStyle(styleOption); + bubbleRenderContext->UpdateBackgroundColor( + paintProperty->GetPopupBackground().value_or(indexerTheme->GetPopupBackgroundColor())); +} + +void ArcIndexerPattern::UpdateBubbleLetterView(bool showDivider, std::vector& currentListData) +{ + CHECK_NULL_VOID(popupNode_); + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto indexerTheme = pipeline->GetTheme(); + CHECK_NULL_VOID(indexerTheme); + auto paintProperty = host->GetPaintProperty(); + CHECK_NULL_VOID(paintProperty); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_VOID(layoutProperty); + auto letterNode = GetLetterNode(); + CHECK_NULL_VOID(letterNode); + UpdateBubbleLetterStackAndLetterTextView(); + auto letterNodeRenderContext = letterNode->GetRenderContext(); + CHECK_NULL_VOID(letterNodeRenderContext); + auto radius = Dimension(ARC_BUBBLE_RADIUS, DimensionUnit::VP); + letterNodeRenderContext->UpdateBorderRadius({ radius, radius, radius, radius }); + letterNodeRenderContext->UpdateBackgroundColor( + paintProperty->GetPopupBackground().value_or(indexerTheme->GetPopupBackgroundColor())); + auto letterStackNode = DynamicCast(popupNode_->GetFirstChild()); + CHECK_NULL_VOID(letterStackNode); + auto letterStackLayoutProperty = letterStackNode->GetLayoutProperty(); + CHECK_NULL_VOID(letterStackLayoutProperty); + auto letterStackRenderContext = letterStackNode->GetRenderContext(); + CHECK_NULL_VOID(letterStackRenderContext); + letterStackRenderContext->UpdateBorderRadius({ radius, radius, radius, radius }); + letterStackRenderContext->UpdateBackgroundColor( + paintProperty->GetPopupBackground().value_or(indexerTheme->GetPopupBackgroundColor())); + auto letterStackSize = Dimension(ARC_BUBBLE_BOX_SIZE, DimensionUnit::VP).ConvertToPx(); + letterStackLayoutProperty->UpdateUserDefinedIdealSize( + CalcSize(CalcLength(letterStackSize), CalcLength(letterStackSize))); + + letterNodeRenderContext->SetClipToBounds(true); + letterStackRenderContext->SetClipToBounds(true); + letterNode->MarkModifyDone(); + letterNode->MarkDirtyNode(); + letterStackNode->MarkModifyDone(); + letterStackNode->MarkDirtyNode(); +} + +void ArcIndexerPattern::UpdateBubbleLetterStackAndLetterTextView() +{ + CHECK_NULL_VOID(popupNode_); + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto indexerTheme = pipeline->GetTheme(); + CHECK_NULL_VOID(indexerTheme); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_VOID(layoutProperty); + auto letterNode = GetLetterNode(); + CHECK_NULL_VOID(letterNode); + auto letterLayoutProperty = letterNode->GetLayoutProperty(); + CHECK_NULL_VOID(letterLayoutProperty); + + auto contenStr = arcArrayValue_[childPressIndex_ >= 0 ? childPressIndex_ : selected_].first; + letterLayoutProperty->UpdateContent(contenStr); + auto popupTextFont = layoutProperty->GetPopupFont().value_or(indexerTheme->GetPopupTextStyle()); + letterLayoutProperty->UpdateMaxLines(ARC_INDEXER_BUBBLE_MAX_TEXT_LINE); + letterLayoutProperty->UpdateFontSize(popupTextFont.GetFontSize()); + letterLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS); + letterLayoutProperty->UpdateEllipsisMode(EllipsisMode::TAIL); + letterLayoutProperty->UpdateAdaptMaxFontSize(popupTextFont.GetFontSize()); + auto minFontSize = Dimension(popupTextFont.GetFontSize().ConvertToFp() - 3.0f, DimensionUnit::FP); + minFontSize = minFontSize < Dimension(1.0) ? Dimension(1.0) : minFontSize; + letterLayoutProperty->UpdateAdaptMinFontSize(minFontSize); + letterLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST); + letterLayoutProperty->UpdateFontWeight(popupTextFont.GetFontWeight()); + letterLayoutProperty->UpdateFontFamily(popupTextFont.GetFontFamilies()); + letterLayoutProperty->UpdateItalicFontStyle(popupTextFont.GetFontStyle()); + letterLayoutProperty->UpdateTextColor(layoutProperty->GetPopupColor().value_or(indexerTheme->GetPopupTextColor())); + letterLayoutProperty->UpdateTextAlign(TextAlign::CENTER); + letterLayoutProperty->UpdateAlignment(Alignment::CENTER); + + auto textPadding = Dimension(ARC_INDEXER_PADDING_LEFT, DimensionUnit::VP).ConvertToPx(); + letterLayoutProperty->UpdatePadding( + { CalcLength(textPadding), CalcLength(textPadding), CalcLength(textPadding), CalcLength(textPadding) }); + + auto BubbleSize = Dimension(ARC_BUBBLE_BOX_SIZE, DimensionUnit::VP).ConvertToPx(); + letterLayoutProperty->UpdateUserDefinedIdealSize( + CalcSize(CalcLength(BubbleSize), CalcLength(BubbleSize))); +} + +RefPtr ArcIndexerPattern::GetLetterNode() +{ + CHECK_NULL_RETURN(popupNode_, nullptr); + return DynamicCast(popupNode_->GetFirstChild()->GetFirstChild()); +} + +bool ArcIndexerPattern::NeedShowBubble() +{ + auto host = GetHost(); + CHECK_NULL_RETURN(host, false); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_RETURN(layoutProperty, false); + auto usePopup = layoutProperty->GetUsingPopup().value_or(false); + return usePopup && IfSelectIndexValid(); +} + +bool ArcIndexerPattern::IfSelectIndexValid() +{ + int32_t maxValidIndex = arcArrayValue_.size(); + if (maxValidIndex > ARC_INDEXER_COLLAPSE_ITEM_COUNT) { + maxValidIndex -= 1; + } + return (selected_ >= 0 && selected_ < maxValidIndex); +} + +void ArcIndexerPattern::ArcExpandedAnimation(int32_t nextIndex) +{ + AnimationOption option; + option.SetDuration(ARC_INDEXER_EXPANDED_DURATION); + option.SetCurve(Curves::FRICTION); + float nextAngle = CalcArcItemAngle(nextIndex); + nextAngle += stepAngle_ * (ARC_INDEXER_COLLAPSE_ITEM_COUNT + 1) * HALF; + if (NearEqual(nextAngle + stepAngle_, FULL_CIRCLE_ANGLE)) { + nextAngle = FULL_CIRCLE_ANGLE; + } + AnimationUtils::Animate(option, [&, nextAngle, id = Container::CurrentId()]() { + ContainerScope scope(id); + contentModifier_->SetSweepAngle(nextAngle); + }); +} + +void ArcIndexerPattern::ArcCollapedAnimation(int32_t nextIndex) +{ + AnimationOption option; + option.SetDuration(ARC_INDEXER_COLLAPED_DURATION); + option.SetCurve(Curves::FRICTION); + float nextAngle = CalcArcItemAngle(nextIndex); + nextAngle += stepAngle_ * (ARC_INDEXER_COLLAPSE_ITEM_COUNT + 1) * HALF; + AnimationUtils::Animate(option, [&, nextAngle, id = Container::CurrentId()]() { + ContainerScope scope(id); + contentModifier_->SetSweepAngle(nextAngle); + }); +} + +void ArcIndexerPattern::ArcIndexerPressInAnimation() +{ + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto renderContext = host->GetRenderContext(); + CHECK_NULL_VOID(renderContext); + AnimationOption option; + option.SetDuration(ARC_INDEXER_PRESS_IN_DURATION); + option.SetCurve(Curves::SHARP); + AnimationUtils::Animate(option, [renderContext, id = Container::CurrentId()]() { + ContainerScope scope(id); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto indexerTheme = pipeline->GetTheme(); + CHECK_NULL_VOID(indexerTheme); + renderContext->UpdateBackgroundColor(Color::TRANSPARENT); + }); +} + +void ArcIndexerPattern::ArcIndexerPressOutAnimation() +{ + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto renderContext = host->GetRenderContext(); + CHECK_NULL_VOID(renderContext); + AnimationOption option; + option.SetDuration(ARC_INDEXER_PRESS_OUT_DURATION); + option.SetCurve(Curves::SHARP); + AnimationUtils::Animate(option, [renderContext, id = Container::CurrentId()]() { + ContainerScope scope(id); + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto indexerTheme = pipeline->GetTheme(); + CHECK_NULL_VOID(indexerTheme); + renderContext->UpdateBackgroundColor(Color::TRANSPARENT); + }); +} + +void ArcIndexerPattern::StartBubbleAppearAnimation() +{ + animationId_ = GenerateAnimationId(); + UpdatePopupVisibility(VisibleType::VISIBLE); + AnimationOption option; + option.SetCurve(Curves::SHARP); + option.SetDuration(ARC_INDEXER_BUBBLE_ENTER_DURATION); + AnimationUtils::Animate( + option, + [id = Container::CurrentId(), weak = AceType::WeakClaim(this)]() { + ContainerScope scope(id); + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + pattern->UpdatePopupOpacity(1.0f); + }); +} + +void ArcIndexerPattern::StartDelayTask(uint32_t duration) +{ + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto context = host->GetContext(); + CHECK_NULL_VOID(context); + CHECK_NULL_VOID(context->GetTaskExecutor()); + delayTask_.Reset([weak = AceType::WeakClaim(this)] { + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + pattern->StartBubbleDisappearAnimation(); + }); + context->GetTaskExecutor()->PostDelayedTask( + delayTask_, TaskExecutor::TaskType::UI, duration, "ArkUIAlphabetArcIndexerBubbleDisappear"); +} + +void ArcIndexerPattern::StartBubbleDisappearAnimation() +{ + AnimationOption option; + option.SetCurve(Curves::SHARP); + option.SetDuration(ARC_INDEXER_BUBBLE_EXIT_DURATION); + AnimationUtils::Animate( + option, + [id = Container::CurrentId(), weak = AceType::WeakClaim(this)]() { + ContainerScope scope(id); + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + pattern->UpdatePopupOpacity(0.0f); + }, + [id = Container::CurrentId(), weak = AceType::WeakClaim(this)]() { + ContainerScope scope(id); + auto pattern = weak.Upgrade(); + CHECK_NULL_VOID(pattern); + CHECK_NULL_VOID(pattern->popupNode_); + auto rendercontext = pattern->popupNode_->GetRenderContext(); + CHECK_NULL_VOID(rendercontext); + if (NearZero(rendercontext->GetOpacityValue(0.0f))) { + pattern->UpdatePopupVisibility(VisibleType::GONE); + } + }); +} + +void ArcIndexerPattern::FireOnSelect(int32_t selectIndex, bool fromPress) +{ + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto indexerEventHub = host->GetEventHub(); + CHECK_NULL_VOID(indexerEventHub); + auto actualIndex = autoCollapse_ ? + selected_ > 0 ? + std::find(fullArrayValue_.begin(), fullArrayValue_.end(), + arcArrayValue_.at(selected_).first) - fullArrayValue_.begin() : + selected_ : + selectIndex; + if (fromPress || lastIndexFromPress_ == fromPress || lastFireSelectIndex_ != selectIndex) { + auto onChangeEvent = indexerEventHub->GetChangeEvent(); + if (onChangeEvent && (selected_ >= 0) && (selected_ < itemCount_)) { + onChangeEvent(selected_); + } + auto onCreatChangeEvent = indexerEventHub->GetCreatChangeEvent(); + if (onCreatChangeEvent && (selected_ >= 0) && (selected_ < itemCount_)) { + onCreatChangeEvent(selected_); + } + auto onSelected = indexerEventHub->GetOnSelected(); + if (onSelected && (selectIndex >= 0) && (selectIndex < itemCount_)) { + onSelected(actualIndex); // fire onSelected with an item's index from original array + } + } + lastFireSelectIndex_ = selectIndex; + lastIndexFromPress_ = fromPress; +} + +bool ArcIndexerPattern::IsMeasureBoundary() const +{ + auto host = GetHost(); + CHECK_NULL_RETURN(host, false); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_RETURN(layoutProperty, false); + return CheckMeasureSelfFlag(layoutProperty->GetPropertyChangeFlag()); +} + +void ArcIndexerPattern::UpdateChildBoundary(RefPtr& frameNode) +{ + auto host = GetHost(); + CHECK_NULL_VOID(host); + auto layoutProperty = host->GetLayoutProperty(); + CHECK_NULL_VOID(layoutProperty); + CHECK_NULL_VOID(frameNode); + auto pattern = DynamicCast(frameNode->GetPattern()); + CHECK_NULL_VOID(pattern); + auto isMeasureBoundary = layoutProperty->GetPropertyChangeFlag() == PROPERTY_UPDATE_NORMAL; + pattern->SetIsMeasureBoundary(isMeasureBoundary); +} + +void ArcIndexerPattern::DumpInfo() +{ + auto layoutProperty = GetLayoutProperty(); + CHECK_NULL_VOID(layoutProperty); + auto itemSize = layoutProperty->GetItemSize(); + DumpLog::GetInstance().AddDesc( + std::string("Offset: ").append(itemSize.has_value() ? itemSize.value().ToString() : "undefined")); +} + +float ArcIndexerPattern::CalcArcItemAngle(int32_t index) +{ + float itemAngle = 0.0f; + itemAngle = startAngle_ + stepAngle_ * index; + return itemAngle; +} + +float ArcIndexerPattern::GetPositionAngle(const Offset& position) +{ + float deltaY = position.GetY() - arcCenter_.GetY(); + float deltaX = position.GetX() - arcCenter_.GetX(); + float posAngle = atan2f(deltaY, deltaX) * HALF_CIRCLE_ANGLE / M_PI; + if (deltaY < 0) { + posAngle += FULL_CIRCLE_ANGLE; + } + if (posAngle < startAngle_) { + posAngle += FULL_CIRCLE_ANGLE; + } + if (posAngle > FULL_CIRCLE_ANGLE + startAngle_ - stepAngle_ * HALF) { + posAngle -= FULL_CIRCLE_ANGLE; + } + return posAngle; +} + +bool ArcIndexerPattern::AtArcHotArea(const Offset& position) +{ + float indexAngle = GetPositionAngle(position); + if (GreatNotEqual(indexAngle, sweepAngle_ + startAngle_ + stepAngle_ * HALF) || + LessNotEqual(indexAngle, startAngle_ - stepAngle_ * HALF)) { + return false; + } + + auto deltaX = position.GetX() - arcCenter_.GetX(); + auto deltaY = position.GetY() - arcCenter_.GetY(); + auto distance = sqrtf(deltaX * deltaX + deltaY * deltaY); + if (GreatOrEqual(distance, arcRadius_ - itemRadius_ * DOUBLE) && + LessOrEqual(distance, arcRadius_ + itemRadius_)) { + return true; + } + return false; +} +} // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.h b/frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.h new file mode 100644 index 00000000000..db34eaae64c --- /dev/null +++ b/frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2024 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 FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_ARC_INDEXER_PATTERN_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_ARC_INDEXER_PATTERN_H + +#include "core/components_ng/pattern/indexer/indexer_pattern.h" +#include "core/components_ng/pattern/indexer/arc_indexer_content_modifier.h" +#include "core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.h" +#include "core/components_ng/pattern/indexer/arc_indexer_paint_method.h" +#include "core/components_ng/pattern/indexer/arc_indexer_layout_property.h" +#include "core/components_ng/pattern/indexer/arc_indexer_paint_property.h" + +namespace OHOS::Ace::NG { +class ArcIndexerPattern : public IndexerPattern { + DECLARE_ACE_TYPE(ArcIndexerPattern, IndexerPattern) +public: + ArcIndexerPattern() = default; + ~ArcIndexerPattern() override = default; + + RefPtr CreateNodePaintMethod() override + { + if (!contentModifier_) { + contentModifier_ = AceType::MakeRefPtr(); + } + return MakeRefPtr( + strokeWidth_, arcCenter_, startAngle_, sweepAngle_, arcRadius_, stepAngle_, contentModifier_); + } + + RefPtr CreateEventHub() override + { + return MakeRefPtr(); + } + + RefPtr CreateLayoutProperty() override + { + return MakeRefPtr(); + } + + RefPtr CreatePaintProperty() override + { + return MakeRefPtr(); + } + + RefPtr CreateLayoutAlgorithm() override + { + auto arcindexerLayoutAlgorithm = MakeRefPtr(itemCount_, fullCount_); + return arcindexerLayoutAlgorithm; + } + + RefPtr CreateAccessibilityProperty() override + { + return MakeRefPtr(); + } + + void SetIsTouch(bool isTouch) + { + isTouch_ = isTouch; + } + + FocusPattern GetFocusPattern() const override + { + return { FocusType::NODE, true }; + } + + int32_t GetSelected() const + { + return selected_; + } + + bool IsMeasureBoundary() const override; + void UpdateChildBoundary(RefPtr& frameNode); + +private: + void OnModifyDone() override; + bool OnDirtyLayoutWrapperSwap(const RefPtr& dirty, const DirtySwapConfig& config) override; + void DumpInfo() override; + + void BuildArrayValueItems(); + void BuildFullArrayValue(); + void CollapseArrayValue(); + void ApplyFourPlusOneMode(); + + void OnTouchDown(const TouchEventInfo& info); + void OnTouchUp(const TouchEventInfo& info); + void MoveIndexByOffset(const Offset& offset); + void ApplyIndexChanged(bool isTextNodeInTree, bool refreshBubble = true, bool fromTouchUp = false, + bool indexerSizeChanged = false); + void OnSelect(bool changed = false); + void InitPanEvent(const RefPtr& gestureHub); + void ResetStatus(); + RefPtr CreatePopupNode(); + void UpdateBubbleView(); + void UpdateBubbleLetterView(bool showDivider, std::vector& currentListData); + bool NeedShowBubble(); + void ShowBubble(); + bool IfSelectIndexValid(); + int32_t GetSelectChildIndex(const Offset& offset); + void StartBubbleAppearAnimation(); + void StartDelayTask(uint32_t duration = ARC_INDEXER_BUBBLE_WAIT_DURATION); + void StartBubbleDisappearAnimation(); + void ArcExpandedAnimation(int32_t nextIndex); + void ArcCollapedAnimation(int32_t nextIndex); + void ArcIndexerPressInAnimation(); + void ArcIndexerPressOutAnimation(); + + void SetIndexerNodeOpacity(const RefPtr& itemNode, float ratio); + void UpdateIndexerNodeOpacityByIdx(RefPtr& context, int32_t index); + void StartIndexerNodeAppearAnimation(int32_t nodeIndex); + void StartIndexerNodeDisappearAnimation(int32_t nodeIndex); + void IndexNodeCollapsedAnimation(); + void IndexNodeExpandedAnimation(); + void FireOnSelect(int32_t selectIndex, bool fromPress); + void UpdateBubbleBackgroundView(); + void UpdateBubbleLetterStackAndLetterTextView(); + RefPtr GetLetterNode(); + float CalcArcItemAngle(int32_t index); + float GetPositionAngle(const Offset& position); + bool AtArcHotArea(const Offset& position); + void InitExpandedProperty(); + void InitCollapsedProperty(); + + std::vector> arcArrayValue_; + int32_t fullCount_ = 0; + float arcIndexerSize_ = 0.0f; + ArcIndexerCollapsingMode lastCollapsingMode_ = ArcIndexerCollapsingMode::INVALID; + ArcIndexerCollapsingMode currectCollapsingMode_ = ArcIndexerCollapsingMode::INVALID; + float strokeWidth_ = 24.0f; + OffsetF arcCenter_; + float startAngle_ = 0.0F; + float sweepAngle_ = 0.0f; + RefPtr expandedProperty_; + int32_t expandedAnimateIndex_ = 0; + RefPtr collapsedProperty_; + int32_t collapsedAnimateIndex_ = 0; + bool atomicAnimateOp_ = true; + float arcRadius_ = 0.0f; + float stepAngle_ = 0.0f; + float itemRadius_ = 0.0f; + RefPtr contentModifier_; +}; +} // namespace OHOS::Ace::NG + +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_ARC_INDEXER_PATTERN_H diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_layout_algorithm.h b/frameworks/core/components_ng/pattern/indexer/indexer_layout_algorithm.h index 52396b8d279..5b69374fff0 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_layout_algorithm.h +++ b/frameworks/core/components_ng/pattern/indexer/indexer_layout_algorithm.h @@ -29,6 +29,7 @@ class ACE_EXPORT IndexerLayoutAlgorithm : public LayoutAlgorithm { DECLARE_ACE_TYPE(IndexerLayoutAlgorithm, LayoutAlgorithm); public: + IndexerLayoutAlgorithm() = default; IndexerLayoutAlgorithm(int32_t itemCount_) : itemCount_(itemCount_) {} float GetItemSizeRender() const diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.cpp b/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.cpp index a62df7cbaa5..5e78f3bd2a1 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.cpp +++ b/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.cpp @@ -122,5 +122,27 @@ std::string IndexerLayoutProperty::AlignStyleToString(const AlignStyle& alignSty return alignStyleStr; } - +void IndexerLayoutProperty::UpdateLayoutProperty(const IndexerLayoutProperty* layoutProperty) +{ + propArrayValue_ = CloneArrayValue(); + propSelected_ = CloneSelected(); + propColor_ = CloneColor(); + propSelectedColor_ = CloneSelectedColor(); + propPopupColor_ = ClonePopupColor(); + propUsingPopup_ = CloneUsingPopup(); + propSelectedFont_ = CloneSelectedFont(); + propPopupFont_ = ClonePopupFont(); + propFont_ = CloneFont(); + propItemSize_ = CloneItemSize(); + propAlignStyle_ = CloneAlignStyle(); + propPopupPositionX_ = ClonePopupPositionX(); + propPopupPositionY_ = ClonePopupPositionY(); + propFontSize_ = CloneFontSize(); + propFontWeight_ = CloneFontWeight(); + propAutoCollapse_ = CloneAutoCollapse(); + propPopupHorizontalSpace_ = ClonePopupHorizontalSpace(); + propIsPopup_ = CloneIsPopup(); + propAdaptiveWidth_ = CloneAdaptiveWidth(); + propEnableHapticFeedback_ = CloneEnableHapticFeedback(); +} } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.h b/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.h index f2dcb51dfc9..72d3c1d712f 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.h +++ b/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.h @@ -114,6 +114,9 @@ public: private: static std::unique_ptr ToJsonObjectValue(const TextStyle& textStyle); static std::string AlignStyleToString(const AlignStyle& alignStyle); + +protected: + void UpdateLayoutProperty(const IndexerLayoutProperty* layoutProperty); }; } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_model.h b/frameworks/core/components_ng/pattern/indexer/indexer_model.h index b42013af8f1..bdcd88c26b4 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_model.h +++ b/frameworks/core/components_ng/pattern/indexer/indexer_model.h @@ -34,7 +34,7 @@ public: static IndexerModel* GetInstance(); virtual ~IndexerModel() = default; - virtual void Create(std::vector& indexerArray, int32_t selectedVal) = 0; + virtual void Create(std::vector& indexerArray, int32_t selectedVal, bool isArc = false) = 0; virtual void SetSelectedColor(const std::optional& color) = 0; virtual void SetColor(const std::optional& color) = 0; virtual void SetPopupColor(const std::optional& color) = 0; diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_model_ng.cpp b/frameworks/core/components_ng/pattern/indexer/indexer_model_ng.cpp index 1d758f1d7eb..0186856811a 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_model_ng.cpp +++ b/frameworks/core/components_ng/pattern/indexer/indexer_model_ng.cpp @@ -19,6 +19,7 @@ #include "core/components/indexer/indexer_theme.h" #include "core/components_ng/base/view_abstract.h" #include "core/components_ng/base/view_stack_processor.h" +#include "core/components_ng/pattern/indexer/arc_indexer_pattern.h" #include "core/components_ng/pattern/indexer/indexer_pattern.h" #include "core/components_ng/pattern/text/text_layout_property.h" #include "core/components_ng/pattern/text/text_pattern.h" @@ -26,13 +27,21 @@ #include "core/components_ng/property/property.h" namespace OHOS::Ace::NG { -void IndexerModelNG::Create(std::vector& arrayValue, int32_t selected) +void IndexerModelNG::Create(std::vector& arrayValue, int32_t selected, bool isArc) { auto* stack = ViewStackProcessor::GetInstance(); auto nodeId = stack->ClaimNodeId(); ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::INDEXER_ETS_TAG, nodeId); - auto frameNode = FrameNode::GetOrCreateFrameNode( - V2::INDEXER_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr(); }); + + RefPtr frameNode = nullptr; + if (isArc) { + frameNode = FrameNode::GetOrCreateFrameNode( + V2::INDEXER_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr(); }); + } else { + frameNode = FrameNode::GetOrCreateFrameNode( + V2::INDEXER_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr(); }); + } + stack->Push(frameNode); if (selected < 0 || selected >= static_cast(arrayValue.size())) { selected = 0; diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_model_ng.h b/frameworks/core/components_ng/pattern/indexer/indexer_model_ng.h index 6cb4f9c6c6a..041ea4afbc5 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_model_ng.h +++ b/frameworks/core/components_ng/pattern/indexer/indexer_model_ng.h @@ -20,9 +20,9 @@ #include "core/components_ng/pattern/indexer/indexer_model.h" namespace OHOS::Ace::NG { -class ACE_EXPORT IndexerModelNG : public OHOS::Ace::IndexerModel { +class ACE_FORCE_EXPORT IndexerModelNG : public OHOS::Ace::IndexerModel { public: - void Create(std::vector& indexerArray, int32_t selectedVal) override; + void Create(std::vector& indexerArray, int32_t selectedVal, bool isArc = false) override; void SetSelectedColor(const std::optional& color) override; void SetColor(const std::optional& color) override; void SetPopupColor(const std::optional& color) override; diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_paint_property.h b/frameworks/core/components_ng/pattern/indexer/indexer_paint_property.h index 25ac936c825..61373011d5b 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_paint_property.h +++ b/frameworks/core/components_ng/pattern/indexer/indexer_paint_property.h @@ -140,6 +140,22 @@ public: ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(IndexerBorderRadius, Dimension, PROPERTY_UPDATE_MEASURE); ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(PopupBackgroundBlurStyle, BlurStyleOption, PROPERTY_UPDATE_RENDER); ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(PopupTitleBackground, Color, PROPERTY_UPDATE_RENDER); + +protected: + void UpdateLayoutProperty(const IndexerPaintProperty* layoutProperty) + { + propSelectedBackgroundColor_ = CloneSelectedBackgroundColor(); + propPopupBackground_ = ClonePopupBackground(); + propPopupSelectedColor_ = ClonePopupSelectedColor(); + propPopupUnselectedColor_ = ClonePopupUnselectedColor(); + propPopupItemBackground_ = ClonePopupItemBackground(); + propPopupBorderRadius_ = ClonePopupBorderRadius(); + propPopupItemBorderRadius_ = ClonePopupItemBorderRadius(); + propItemBorderRadius_ = CloneItemBorderRadius(); + propIndexerBorderRadius_ = CloneIndexerBorderRadius(); + propPopupBackgroundBlurStyle_ = ClonePopupBackgroundBlurStyle(); + propPopupTitleBackground_ = ClonePopupTitleBackground(); + } }; } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_pattern.h b/frameworks/core/components_ng/pattern/indexer/indexer_pattern.h index f568f29b33b..54782033924 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_pattern.h +++ b/frameworks/core/components_ng/pattern/indexer/indexer_pattern.h @@ -96,7 +96,22 @@ public: bool IsMeasureBoundary() const override; void UpdateChildBoundary(RefPtr& frameNode); - +protected: + void SetAccessibilityAction(); + bool MoveIndexByStep(int32_t step); + void FireOnSelect(int32_t selectIndex, bool fromPress); + void RemoveBubble(); + void StartCollapseDelayTask(RefPtr& hostNode, uint32_t duration = INDEXER_COLLAPSE_WAIT_DURATION); + void OnSelect(bool changed = false); + int32_t GetSkipChildIndex(int32_t step); + void UpdatePopupOpacity(float ratio); + void UpdatePopupVisibility(VisibleType visible); + int32_t GenerateAnimationId(); + void UpdateBubbleBackgroundView(); + void ItemSelectedInAnimation(RefPtr& itemNode); + void ItemSelectedOutAnimation(RefPtr& itemNode); + void ShowBubble(); + private: void OnModifyDone() override; bool OnDirtyLayoutWrapperSwap(const RefPtr& dirty, const DirtySwapConfig& config) override; @@ -112,13 +127,11 @@ private: void OnTouchDown(const TouchEventInfo& info); void OnTouchUp(const TouchEventInfo& info); void MoveIndexByOffset(const Offset& offset); - bool MoveIndexByStep(int32_t step); + bool KeyIndexByStep(int32_t step); bool MoveIndexBySearch(const std::string& searchStr); void ApplyIndexChanged( bool isTextNodeInTree, bool refreshBubble = true, bool fromTouchUp = false, bool indexerSizeChanged = false); - void OnSelect(bool changed = false); - int32_t GetSkipChildIndex(int32_t step); int32_t GetFocusChildIndex(const std::string& searchStr); void InitPanEvent(const RefPtr& gestureHub); @@ -145,14 +158,12 @@ private: RefPtr CreatePopupNode(); void UpdateBubbleView(); void UpdateBubbleSize(); - void UpdateBubbleLetterView(bool showDivider, std::vector& currentListData); + void CreateBubbleListView(std::vector& currentListData); void UpdateBubbleListView(std::vector& currentListData); - void UpdatePopupOpacity(float ratio); - void UpdatePopupVisibility(VisibleType visible); bool NeedShowPopupView(); bool NeedShowBubble(); - void ShowBubble(); + bool IfSelectIndexValid(); int32_t GetSelectChildIndex(const Offset& offset); void StartBubbleAppearAnimation(); @@ -162,15 +173,10 @@ private: void IndexerHoverOutAnimation(); void IndexerPressInAnimation(); void IndexerPressOutAnimation(); - int32_t GenerateAnimationId(); - void ItemSelectedInAnimation(RefPtr& itemNode); - void ItemSelectedOutAnimation(RefPtr& itemNode); - void FireOnSelect(int32_t selectIndex, bool fromPress); - void SetAccessibilityAction(); - void RemoveBubble(); - void UpdateBubbleBackgroundView(); + CalcSize CalcBubbleListSize(int32_t popupSize, int32_t maxItemsSize); GradientColor CreatePercentGradientColor(float percent, Color color); + void UpdateBubbleLetterView(bool showDivider, std::vector& currentListData); void UpdateBubbleLetterStackAndLetterTextView(); void DrawPopupListGradient(PopupListGradientStatus gradientStatus); void UpdatePopupListGradientView(int32_t popupSize, int32_t maxItemsSize); @@ -180,8 +186,8 @@ private: void UpdateBubbleListItemContext( const RefPtr& listNode, RefPtr& indexerTheme, uint32_t pos); void UpdateBubbleListItemMarkModify(RefPtr& textNode, RefPtr& listItemNode); - void StartCollapseDelayTask(RefPtr& hostNode, uint32_t duration = INDEXER_COLLAPSE_WAIT_DURATION); - + +protected: RefPtr popupNode_; RefPtr touchListener_; RefPtr panEvent_; diff --git a/frameworks/core/components_ng/pattern/indexer/indexer_theme.h b/frameworks/core/components_ng/pattern/indexer/indexer_theme.h index 028cd4f7a49..54327e1bc9b 100644 --- a/frameworks/core/components_ng/pattern/indexer/indexer_theme.h +++ b/frameworks/core/components_ng/pattern/indexer/indexer_theme.h @@ -101,11 +101,58 @@ inline constexpr uint32_t POPUP_TITLE_BG_COLOR_SINGLE = 0x00ffffff; inline constexpr float INDEXER_ZERO_WIDTH = 0.0f; inline constexpr int32_t INDEXER_COLLAPSE_WAIT_DURATION = 1; +inline constexpr int32_t ARC_INDEXER_ITEM_MAX_COUNT = 30; // [indexer], default max count +inline const std::u16string ARC_INDEXER_STR_SHARP = StringUtils::Str8ToStr16("#"); +inline const std::u16string ARC_INDEXER_STR_EXPANDED = StringUtils::Str8ToStr16(">"); +inline const std::u16string ARC_INDEXER_STR_COLLAPSED = StringUtils::Str8ToStr16("<"); + +inline constexpr float ARC_INDEXER_SIZE = 233.0; +inline constexpr int32_t ARC_INDEXER_EXPANDED_DURATION = 470; +inline constexpr int32_t ARC_INDEXER_COLLAPED_DURATION = 470; +inline constexpr int32_t ARC_INDEXER_BUBBLE_EXIT_DURATION = 400; +inline constexpr int32_t ARC_INDEXER_BUBBLE_ENTER_DURATION = 200; +inline constexpr int32_t ARC_INDEXER_PRESS_IN_DURATION = 100; +inline constexpr int32_t ARC_INDEXER_PRESS_OUT_DURATION = 100; +inline constexpr int32_t ARC_INDEXER_BUBBLE_WAIT_DURATION = 2000; +inline constexpr int32_t ARC_INDEXER_BUBBLE_MAX_TEXT_LINE = 2; + +inline constexpr double ARC_BUBBLE_BOX_SIZE = 46.0; +inline constexpr double ARC_BUBBLE_BOX_RADIUS = 23.0; +inline constexpr double ARC_BUBBLE_POSITION_Y = 44.0; +inline constexpr double ARC_INDEXER_ITEM_SIZE = 24.0; // circle mode, item size (VP) +inline constexpr float ARC_INDEXER_ITEM_TEXT_SIZE = 13.0f; // circle, mode font size (FP) +inline constexpr float ARC_INDEXER_POPUP_TEXT_SIZE = 19.0f; // circle, mode popup font size (FP) + +inline constexpr int32_t ARC_INDEXER_COLLAPSE_ITEM_COUNT = 4; +inline constexpr float FULL_CIRCLE_ANGLE = 360.0; +inline constexpr float HALF = 0.5f; +inline constexpr double DOUBLE = 2.0; +inline constexpr float HALF_CIRCLE_ANGLE = 180.0; +inline constexpr uint32_t ARC_INDEXER_STR_DOT_COLOR = 0xA9FFFFFF; +inline constexpr uint32_t ARC_INDEXER_SELECTED_BG_COLOR = 0xFF1F71FF; +inline constexpr uint32_t ARC_POPUP_BG_COLOR = 0xD8404040; +inline constexpr float ARC_INDEXER_PADDING_LEFT = 4.0f; +inline constexpr double ARC_BUBBLE_RADIUS = 23.0; +inline constexpr double ARC_INDEXER_DEFAULT_RADIUS = 12.0; +inline constexpr int32_t ARC_INDEXER_COLLAPSE_WAIT_DURATION = 1; + enum class AlignStyle { LEFT = 0, RIGHT, START, END, }; + +enum class ArcIndexerBarState { + INVALID, + COLLAPSED, + EXPANDED +}; + +enum class ArcIndexerCollapsingMode { + INVALID, + NONE, // all array should be displayed + FOUR, // 4 + 1 collapsing mode +}; } // namespace OHOS::Ace::NG #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_INDEXER_INDEXER_THEME_H diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 11903c585cc..b9f378a4d52 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -680,6 +680,10 @@ ohos_source_set("ace_components_pattern") { "$ace_root/frameworks/core/components_ng/pattern/image/image_pattern.cpp", "$ace_root/frameworks/core/components_ng/pattern/image_animator/image_animator_model_ng.cpp", "$ace_root/frameworks/core/components_ng/pattern/image_animator/image_animator_pattern.cpp", + "$ace_root/frameworks/core/components_ng/pattern/indexer/arc_indexer_content_modifier.cpp", + "$ace_root/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.cpp", + "$ace_root/frameworks/core/components_ng/pattern/indexer/arc_indexer_layout_property.cpp", + "$ace_root/frameworks/core/components_ng/pattern/indexer/arc_indexer_pattern.cpp", "$ace_root/frameworks/core/components_ng/pattern/indexer/indexer_accessibility_property.cpp", "$ace_root/frameworks/core/components_ng/pattern/indexer/indexer_layout_algorithm.cpp", "$ace_root/frameworks/core/components_ng/pattern/indexer/indexer_layout_property.cpp", diff --git a/test/unittest/core/pattern/indexer/BUILD.gn b/test/unittest/core/pattern/indexer/BUILD.gn index 739f2022baf..62c1542be6c 100644 --- a/test/unittest/core/pattern/indexer/BUILD.gn +++ b/test/unittest/core/pattern/indexer/BUILD.gn @@ -16,6 +16,7 @@ import("//foundation/arkui/ace_engine/test/unittest/ace_unittest.gni") ace_unittest("indexer_test_ng") { type = "new" sources = [ + "arcindexer_pattern_test_ng.cpp", "indexer_model_test_ng.cpp", "indexer_pattern_test_ng.cpp", "indexer_test_ng.cpp", diff --git a/test/unittest/core/pattern/indexer/arcindexer_pattern_test_ng.cpp b/test/unittest/core/pattern/indexer/arcindexer_pattern_test_ng.cpp new file mode 100644 index 00000000000..4774da4c89e --- /dev/null +++ b/test/unittest/core/pattern/indexer/arcindexer_pattern_test_ng.cpp @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2024 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 + +#include "gtest/gtest.h" + +#include "base/geometry/dimension.h" + +#define protected public +#define private public +#include "test/mock/core/common/mock_theme_manager.h" +#include "test/mock/core/pipeline/mock_pipeline_context.h" +#include "test/mock/core/render/mock_paragraph.h" +#include "test/unittest/core/pattern/test_ng.h" + +#include "base/memory/ace_type.h" +#include "base/memory/referenced.h" +#include "core/common/container.h" +#include "core/components_ng/base/view_stack_processor.h" +#include "core/components_ng/layout/layout_property.h" +#include "core/components_ng/pattern/indexer/arc_indexer_pattern.h" +#include "core/components_ng/pattern/indexer/arc_indexer_content_modifier.h" +#include "core/components_ng/pattern/indexer/arc_indexer_layout_algorithm.h" +#include "core/components_ng/pattern/indexer/arc_indexer_paint_method.h" +#include "core/components_ng/pattern/indexer/indexer_layout_property.h" +#include "core/components_ng/pattern/indexer/indexer_model_ng.h" +#include "core/components_ng/pattern/indexer/indexer_paint_property.h" +#include "core/components_ng/pattern/indexer/indexer_pattern.h" +#include "core/components_ng/pattern/indexer/indexer_theme.h" +#include "core/components_ng/pattern/linear_layout/linear_layout_property.h" +#include "core/components_ng/pattern/list/list_pattern.h" +#include "core/components_ng/pattern/text/text_layout_property.h" +#include "core/pipeline_ng/pipeline_context.h" +#include "base/memory/memory_monitor_def.h" +using namespace testing; +using namespace testing::ext; + +namespace OHOS::Ace::NG { +namespace { +std::vector CREATE_ARRAY = { "AAAAAAAA", "BBBB", "C", "D", "E", "FFFFF", "G", "H", "I", "J", "K", "L", + "MMMMMMMM", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; +std::vector CREATE_ARRAY_1 = { "A", "B", "C", "D", "E", "F", "G", "H", "I" }; +std::vector CREATE_ARRAY_2 = { "#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L" }; +} // namespace + +class ArcindexerPatternTestNg : public TestNG { +public: + static void SetUpTestSuite(); + static void TearDownTestSuite(); + void SetUp() override; + void TearDown() override; + void GetInstance(); + + void Create(const std::function& callback = nullptr, + std::vector arrayValue = CREATE_ARRAY, int32_t selected = 0); + float GetFirstChildOffsetY(); + AssertionResult Selected(int32_t expectSelected); + void MoveIndex(GestureEvent gestureEvent); + AssertionResult Touch(TouchType touchType, float locationY, int32_t expectSelected); + + RefPtr frameNode_; + RefPtr pattern_; + RefPtr eventHub_; + RefPtr layoutProperty_; + RefPtr paintProperty_; + RefPtr accessibilityProperty_; +}; + +void ArcindexerPatternTestNg::SetUpTestSuite() +{ + TestNG::SetUpTestSuite(); + auto themeManager = AceType::MakeRefPtr(); + PipelineContext::GetCurrentContext()->SetThemeManager(themeManager); + EXPECT_CALL(*themeManager, GetTheme(_)).WillRepeatedly(Return(AceType::MakeRefPtr())); +} + +void ArcindexerPatternTestNg::TearDownTestSuite() +{ + TestNG::TearDownTestSuite(); +} + +void ArcindexerPatternTestNg::SetUp() {} + +void ArcindexerPatternTestNg::TearDown() +{ + frameNode_ = nullptr; + pattern_ = nullptr; + eventHub_ = nullptr; + layoutProperty_ = nullptr; + paintProperty_ = nullptr; + accessibilityProperty_ = nullptr; +} + +void ArcindexerPatternTestNg::GetInstance() +{ + RefPtr element = ViewStackProcessor::GetInstance()->Finish(); + frameNode_ = AceType::DynamicCast(element); + pattern_ = frameNode_->GetPattern(); + eventHub_ = frameNode_->GetEventHub(); + layoutProperty_ = frameNode_->GetLayoutProperty(); + paintProperty_ = frameNode_->GetPaintProperty(); + accessibilityProperty_ = frameNode_->GetAccessibilityProperty(); +} + +void ArcindexerPatternTestNg::Create( + const std::function& callback, std::vector arrayValue, int32_t selected) +{ + IndexerModelNG model; + model.Create(arrayValue, selected, true); + if (callback) { + callback(model); + } + GetInstance(); + FlushLayoutTask(frameNode_); +} + +float ArcindexerPatternTestNg::GetFirstChildOffsetY() +{ + if (pattern_->itemCount_ > 0) { + return GetChildRect(frameNode_, 0).GetY(); + } + return 0.f; +} + +AssertionResult ArcindexerPatternTestNg::Selected(int32_t expectSelected) +{ + return IsEqual(pattern_->GetSelected(), expectSelected); +} + +void ArcindexerPatternTestNg::MoveIndex(GestureEvent gestureEvent) +{ + auto start = pattern_->panEvent_->GetActionStartEventFunc(); + auto update = pattern_->panEvent_->GetActionUpdateEventFunc(); + start(gestureEvent); + update(gestureEvent); +} + +AssertionResult ArcindexerPatternTestNg::Touch(TouchType touchType, float locationY, int32_t expectSelected) +{ + float firstOffsetY = GetFirstChildOffsetY(); + TouchEventInfo touchEventInfo = CreateTouchEventInfo(touchType, Offset(0.f, locationY + firstOffsetY)); + auto touchFuc = pattern_->touchListener_->GetTouchEventCallback(); + touchFuc(touchEventInfo); + return Selected(expectSelected); +} + +/** + * @tc.name: ArcindexerPatternTestNg001 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg001, TestSize.Level1) +{ + /** + * @tc.steps: step1. create indexer and get frameNode. + */ + Create( + [](IndexerModelNG model) { + model.SetSelectedColor(Color(0x00000000)); + model.SetColor(Color(0x00000000)); + model.SetPopupColor(Color(0x00000000)); + model.SetSelectedBackgroundColor(Color(0x00000000)); + model.SetPopupBackground(Color(0x00000000)); + model.SetUsingPopup(true); + model.SetAlignStyle(0); + model.SetPopupHorizontalSpace(Dimension(50)); //50 is the horizontal space of popupNode + model.SetSelected(0); + model.SetPopupPositionX(Dimension(-96.f, DimensionUnit::VP)); //-96.f is the left space of popupNode + model.SetPopupPositionY(Dimension(48.f, DimensionUnit::VP)); //48.f is the top space of popupNode + model.SetPopupItemBackground(Color(0x00000000)); + model.SetPopupSelectedColor(Color(0x00000000)); + model.SetPopupUnselectedColor(Color(0x00000000)); + model.SetFontSize(Dimension(24)); //24 is the fontSize of item + model.SetFontWeight(FontWeight::MEDIUM); + model.SetAdaptiveWidth(true); + model.SetItemSize(20.0_vp); //20.0_vp is the width of item + }, + CREATE_ARRAY, 0); + + /** + * @tc.steps: step2. get layoutWrapper and indexerLayoutAlgorithm. + * @tc.expected: step2. get layoutWrapper success. + */ + pattern_->OnModifyDone(); + pattern_->isNewHeightCalculated_ = true; + pattern_->autoCollapse_ = true; + pattern_->OnModifyDone(); + + pattern_->fullCount_ = -1; + pattern_->OnModifyDone(); + + + pattern_->ApplyIndexChanged(true, true); + auto layoutWrapper = frameNode_->CreateLayoutWrapper(); + EXPECT_NE(layoutWrapper, nullptr); + auto arcindexerLayoutAlgorithm = AceType::DynamicCast(pattern_->CreateLayoutAlgorithm()); + EXPECT_NE(arcindexerLayoutAlgorithm, nullptr); + RefPtr layoutAlgorithmWrapper = + AceType::MakeRefPtr(arcindexerLayoutAlgorithm); + layoutWrapper->SetLayoutAlgorithm(layoutAlgorithmWrapper); + auto accessibilityProperty = frameNode_->GetAccessibilityProperty(); + EXPECT_EQ(arcindexerLayoutAlgorithm->GetstepAngle(), 13.5f); + + pattern_->selected_ = 5; // 5 is the index of item + EXPECT_EQ(arcindexerLayoutAlgorithm->GetstepAngle(), 13.5f); +} + +/** + * @tc.name: ArcindexerPatternTestNg002 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg002, TestSize.Level1) +{ + /** + * @tc.steps: step1. create indexer and get frameNode. + */ + Create( + [](IndexerModelNG model) { + model.SetSelectedColor(Color(0x00000000)); + model.SetColor(Color(0x00000000)); + model.SetPopupColor(Color(0x00000000)); + model.SetSelectedBackgroundColor(Color(0x00000000)); + model.SetPopupBackground(Color(0x00000000)); + model.SetUsingPopup(true); + model.SetSelected(-1); + model.SetFontSize(Dimension(24)); //24 is the fontSize of item + model.SetFontWeight(FontWeight::MEDIUM); + model.SetAdaptiveWidth(true); + model.SetItemSize(20.0_vp); //20.0_vp is the width of item + }, + CREATE_ARRAY, 0); + + /** + * @tc.steps: step2. get layoutWrapper and indexerLayoutAlgorithm. + * @tc.expected: step2. get layoutWrapper success. + */ + layoutProperty_->Clone(); + pattern_->OnModifyDone(); + pattern_->selected_ = 10; + pattern_->OnModifyDone(); + pattern_->ApplyIndexChanged(true, true); + auto layoutWrapper = frameNode_->CreateLayoutWrapper(); + EXPECT_NE(layoutWrapper, nullptr); + auto arcindexerLayoutAlgorithm = AceType::DynamicCast(pattern_->CreateLayoutAlgorithm()); + EXPECT_NE(arcindexerLayoutAlgorithm, nullptr); + RefPtr layoutAlgorithmWrapper = + AceType::MakeRefPtr(arcindexerLayoutAlgorithm); + layoutWrapper->SetLayoutAlgorithm(layoutAlgorithmWrapper); + auto accessibilityProperty = frameNode_->GetAccessibilityProperty(); + EXPECT_EQ(arcindexerLayoutAlgorithm->GetstepAngle(), 13.5f); + + pattern_->selected_ = 5; // 5 is the index of item + EXPECT_EQ(arcindexerLayoutAlgorithm->GetstepAngle(), 13.5f); +} + +/** + * @tc.name: ArcindexerPatternTestNg003 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg003, TestSize.Level1) +{ + Create(); + RefPtr layoutWrapper = frameNode_->CreateLayoutWrapper(true, true); + DirtySwapConfig config; + /** + * @tc.steps: step1. call OnDirtyLayoutWrapperSwap. + * @tc.expected: step1. func return true. + */ + pattern_->actualIndexerHeight_ = 10.0f; + pattern_->autoCollapse_ = true; + auto result1 = pattern_->OnDirtyLayoutWrapperSwap(layoutWrapper, config); + EXPECT_TRUE(result1); + + /** + * @tc.steps: step1. call OnDirtyLayoutWrapperSwap. + * @tc.expected: step1. func return false. + */ + config.skipMeasure = true; + config.skipLayout = true; + auto result = pattern_->OnDirtyLayoutWrapperSwap(layoutWrapper, config); + EXPECT_FALSE(result); +} + +/** + * @tc.name: ArcindexerPatternTestNg004 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg004, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. fullCount_ is equal 10 and call CollapseArrayValue. + */ + pattern_->lastCollapsingMode_ = ArcIndexerCollapsingMode::NONE; + EXPECT_NE(pattern_->fullCount_, INDEXER_NINE_CHARACTERS_CHECK); + pattern_->CollapseArrayValue(); + + /** + * @tc.steps: step2. fullCount_ is equal 0 and call CollapseArrayValue. + */ + pattern_->fullCount_ = 4; + pattern_->CollapseArrayValue(); + EXPECT_EQ(pattern_->fullCount_, 4); +} + +/** + * @tc.name: ArcindexerPatternTestNg005 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg005, TestSize.Level1) +{ + Create(); + + /** + * @tc.steps: step1. isHover is false and call IndexNodeCollapsedAnimation. + */ + pattern_->IndexNodeCollapsedAnimation(); + + pattern_->atomicAnimateOp_ = false; + pattern_->IndexNodeCollapsedAnimation(); +} + +/** + * @tc.name: ArcindexerPatternTestNg006 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg006, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. isHover is true and call OnHover. + */ + pattern_->IndexNodeExpandedAnimation(); +} + +/** + * @tc.name: ArcindexerPatternTestNg007 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg007, TestSize.Level1) +{ + Create(); + int32_t index = 1; + /** + * @tc.steps: step1. isInputEventRegisted_ is true and call InitInputEvent. + */ + auto renderContext = AceType::MakeRefPtr(); + pattern_->UpdateIndexerNodeOpacityByIdx(renderContext, index); +} + +/** + * @tc.name: ArcindexerPatternTestNg008 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg008, TestSize.Level1) +{ + Create(); + + /** + * @tc.steps: step1. isHover is false and call OnHover. + */ + pattern_->StartIndexerNodeDisappearAnimation(1); + pattern_->StartIndexerNodeDisappearAnimation(100); +} + +/** + * @tc.name: ArcindexerPatternTestNg009 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg009, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. isHover is true and call InitCurrentInputEvent. + */ + int32_t nodeIndex = 1; + pattern_->StartIndexerNodeAppearAnimation(nodeIndex); +} + +/** + * @tc.name: ArcindexerPatternTestNg0010 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0010, TestSize.Level1) +{ + Create( + [](IndexerModelNG model) { + model.SetSelectedColor(Color(0x00000000)); + model.SetColor(Color(0x00000000)); + model.SetPopupColor(Color(0x00000000)); + model.SetSelectedBackgroundColor(Color(0x00000000)); + model.SetPopupBackground(Color(0x00000000)); + model.SetUsingPopup(true); + model.SetSelected(-1); + model.SetFontSize(Dimension(24)); //24 is the fontSize of item + model.SetFontWeight(FontWeight::MEDIUM); + model.SetAdaptiveWidth(true); + model.SetItemSize(20.0_vp); //20.0_vp is the width of item + }, + CREATE_ARRAY, 0); + /** + * @tc.steps: step1. itemCount_ is -1 and call OnTouchDown. + */ + TouchEventInfo touchEventInfo("1"); + TouchLocationInfo locationInfo(0); + locationInfo.SetScreenLocation(Offset(200, 200)); + touchEventInfo.AddTouchLocationInfo(std::move(locationInfo)); + pattern_->OnTouchDown(touchEventInfo); + pattern_->itemCount_ = -1; + pattern_->OnTouchDown(touchEventInfo); +} + +/** + * @tc.name: ArcindexerPatternTestNg0011 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0011, TestSize.Level1) +{ + Create( + [](IndexerModelNG model) { + model.SetSelectedColor(Color(0x00000000)); + model.SetColor(Color(0x00000000)); + model.SetPopupColor(Color(0x00000000)); + model.SetSelectedBackgroundColor(Color(0x00000000)); + model.SetPopupBackground(Color(0x00000000)); + model.SetUsingPopup(true); + model.SetSelected(-1); + model.SetFontSize(Dimension(24)); //24 is the fontSize of item + model.SetFontWeight(FontWeight::MEDIUM); + model.SetAdaptiveWidth(true); + model.SetItemSize(20.0_vp); //20.0_vp is the width of item + }, + CREATE_ARRAY, 0); + /** + * @tc.steps: step1. isHover is true itemCount_is -1 and call OnTouchUp. + */ + TouchEventInfo touchEventInfo("1"); + TouchLocationInfo locationInfo(0); + locationInfo.SetScreenLocation(Offset(200, 200)); + touchEventInfo.AddTouchLocationInfo(std::move(locationInfo)); + pattern_->OnTouchUp(touchEventInfo); + pattern_->isHover_ = true; + pattern_->OnTouchUp(touchEventInfo); + pattern_->itemCount_ = -1; + pattern_->OnTouchUp(touchEventInfo); +} + +/** + * @tc.name: ArcindexerPatternTestNg0012 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0012, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call MoveIndexByOffset. + */ + pattern_->childPressIndex_ = 1; + pattern_->MoveIndexByOffset(Offset(0, 0)); + pattern_->isHover_ = true; + pattern_->childPressIndex_ = -1; + pattern_->MoveIndexByOffset(Offset(0, 0)); + pattern_->isHover_ = true; + pattern_->childPressIndex_ = 1; + pattern_->MoveIndexByOffset(Offset(0, 0)); + /** + * @tc.steps: step1. itemCount_ is -1 and call MoveIndexByOffset. + */ + pattern_->childPressIndex_ = 0; + pattern_->MoveIndexByOffset(Offset(0, 0)); + pattern_->itemCount_ = -1; + pattern_->MoveIndexByOffset(Offset(0, 0)); + pattern_->itemSizeRender_ = -1.0f; + pattern_->MoveIndexByOffset(Offset(0, 0)); +} + +/** + * @tc.name: ArcindexerPatternTestNg0013 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0013, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call GetSelectChildIndex. + * @tc.expected: step1. expect index is 0 + */ + pattern_->stepAngle_ = 720; + int32_t index = pattern_->GetSelectChildIndex(Offset(1, 1)); + EXPECT_EQ(index, 0); +} + +/** + * @tc.name: ArcindexerPatternTestNg0014 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0014, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call KeyIndexByStep. + * * @tc.expected: step1. expect status is true + */ + int32_t nextIndex = 1; + pattern_->ArcExpandedAnimation(nextIndex); +} + +/** + * @tc.name: ArcindexerPatternTestNg0015 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0015, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call MoveIndexByStep. + * @tc.expected: step1. expect status1 is true + */ + int32_t nextIndex = 1; + pattern_->ArcCollapedAnimation(nextIndex); +} + +/** + * @tc.name: ArcindexerPatternTestNg0016 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0016, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call MoveIndexBySearch. + * @tc.expected: step1. expect Search is true + */ + pattern_->StartBubbleDisappearAnimation(); +} + +/** + * @tc.name: ArcindexerPatternTestNg0017 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0017, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call OnSelect. + * @tc.expected: step1. expect resuit is true + */ + bool changed = false; + auto value = pattern_->lastSelected_ = 1; + pattern_->OnSelect(changed); + EXPECT_TRUE(value != pattern_->animateSelected_); +} + +/** + * @tc.name: ArcindexerPatternTestNg0018 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0018, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call ApplyIndexChanged set arcindex theme. + */ + pattern_->ApplyIndexChanged(false, false, false, false); +} + +/** + * @tc.name: ArcindexerPatternTestNg0019 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0019, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call ShowBubble. + */ + pattern_->ShowBubble(); + pattern_->itemCount_ = 2; + pattern_->ShowBubble(); +} + +/** + * @tc.name: ArcindexerPatternTestNg0020 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0020, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call ArcIndexerPressOutAnimation. + */ + pattern_->ArcIndexerPressOutAnimation(); + pattern_->DumpInfo(); + /** + * @tc.steps: step1. call GetPositionAngle. + * * @tc.expected: step1.expect result is same with 0.0f + */ + pattern_->startAngle_ = 360.0F; + auto result = pattern_->GetPositionAngle(Offset(0, 0)); + EXPECT_EQ(result, 585); +} + +/** + * @tc.name: ArcindexerPatternTestNg0021 + * @tc.desc: Test indexer layoutAlgorithm GetMaxItemWidth function. + * @tc.type: FUNC + */ +HWTEST_F(ArcindexerPatternTestNg, ArcindexerPatternTestNg0021, TestSize.Level1) +{ + Create(); + /** + * @tc.steps: step1. call AtArcHotArea. + * @tc.expected: step1.expect status is false + */ + bool status = pattern_->AtArcHotArea(Offset(0, 0)); + EXPECT_FALSE(status); + bool status1 = pattern_->AtArcHotArea(Offset(-360, -360)); + EXPECT_FALSE(status1); +} +} // namespace OHOS::Ace::NG -- Gitee From fb0510e6489d0e29163ef3f82e96a87e8514f8c3 Mon Sep 17 00:00:00 2001 From: liuwei Date: Sat, 6 Jul 2024 12:18:58 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E3=80=90=E5=BC=A7=E5=BD=A2=E7=B4=A2?= =?UTF-8?q?=E5=BC=95=E6=9D=A1=E3=80=91=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liuwei Change-Id: Ib7a3146fb3099ff64a2b4021e70e96d76ccb36d2 --- component_ext/arc_alphabet_indexer/BUILD.gn | 2 -- 1 file changed, 2 deletions(-) diff --git a/component_ext/arc_alphabet_indexer/BUILD.gn b/component_ext/arc_alphabet_indexer/BUILD.gn index 98cf7234d50..1f57cdd53c8 100644 --- a/component_ext/arc_alphabet_indexer/BUILD.gn +++ b/component_ext/arc_alphabet_indexer/BUILD.gn @@ -60,8 +60,6 @@ ohos_shared_library("arcalphabetindexer") { ":gen_obj_src_arkui_arcalphabetindexer_abc", ":gen_obj_src_arkui_arcalphabetindexer_js", "$ace_root/build:libace_compatible", - "$ace_root/interfaces/inner_api/ace:ace_uicontent", - "$ace_root/interfaces/napi/kits/plugincomponent:plugincomponent", ] external_deps = [ -- Gitee