1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_BUTTON_BUTTON_PATTERN_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_BUTTON_BUTTON_PATTERN_H 18 19 #include <optional> 20 21 #include "base/memory/referenced.h" 22 #include "base/utils/utils.h" 23 #include "core/common/container.h" 24 #include "core/components/button/button_theme.h" 25 #include "core/components/common/layout/constants.h" 26 #include "core/components_ng/base/inspector_filter.h" 27 #include "core/components_ng/event/event_hub.h" 28 #include "core/components_ng/event/focus_hub.h" 29 #include "core/components_ng/pattern/button/button_event_hub.h" 30 #include "core/components_ng/pattern/button/button_layout_algorithm.h" 31 #include "core/components_ng/pattern/button/button_layout_property.h" 32 #include "core/components_ng/pattern/button/button_model_ng.h" 33 #include "core/components_ng/pattern/pattern.h" 34 #include "core/components_ng/pattern/text/text_layout_property.h" 35 namespace OHOS::Ace::NG { 36 enum class ComponentButtonType { POPUP, BUTTON, STEPPER, NAVIGATION }; 37 class ButtonPattern : public Pattern { 38 DECLARE_ACE_TYPE(ButtonPattern, Pattern); 39 40 public: 41 ButtonPattern() = default; 42 43 ~ButtonPattern() override = default; 44 IsAtomicNode()45 bool IsAtomicNode() const override 46 { 47 return false; 48 } 49 CreateEventHub()50 RefPtr<EventHub> CreateEventHub() override 51 { 52 return MakeRefPtr<ButtonEventHub>(); 53 } 54 CreateLayoutAlgorithm()55 RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override 56 { 57 return MakeRefPtr<ButtonLayoutAlgorithm>(); 58 } 59 CreateLayoutProperty()60 RefPtr<LayoutProperty> CreateLayoutProperty() override 61 { 62 return MakeRefPtr<ButtonLayoutProperty>(); 63 } 64 GetFocusPattern()65 FocusPattern GetFocusPattern() const override 66 { 67 if (buttonType_ == ComponentButtonType::POPUP || buttonType_ == ComponentButtonType::STEPPER) { 68 FocusPaintParam focusPaintParam; 69 focusPaintParam.SetPaintColor(focusBorderColor_); 70 return { FocusType::NODE, true, FocusStyleType::INNER_BORDER, focusPaintParam }; 71 } 72 if (buttonType_ == ComponentButtonType::NAVIGATION) { 73 FocusPaintParam focusPaintParam; 74 focusPaintParam.SetPaintColor(focusBorderColor_); 75 focusPaintParam.SetPaintWidth(focusBorderWidth_); 76 return { FocusType::NODE, true, FocusStyleType::INNER_BORDER, focusPaintParam }; 77 } 78 return { FocusType::NODE, true, FocusStyleType::OUTER_BORDER }; 79 } 80 IsNeedAdjustByAspectRatio()81 bool IsNeedAdjustByAspectRatio() override 82 { 83 auto host = GetHost(); 84 CHECK_NULL_RETURN(host, false); 85 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>(); 86 CHECK_NULL_RETURN(host, false); 87 return layoutProperty->HasAspectRatio() && 88 layoutProperty->GetType().value_or(ButtonType::CAPSULE) != ButtonType::CIRCLE; 89 } 90 SetClickedColor(const Color & color)91 void SetClickedColor(const Color& color) 92 { 93 clickedColor_ = color; 94 isSetClickedColor_ = true; 95 } 96 SetBlendColor(const std::optional<Color> & blendClickColor,const std::optional<Color> & blendHoverColor)97 void SetBlendColor(const std::optional<Color>& blendClickColor, const std::optional<Color>& blendHoverColor) 98 { 99 blendClickColor_ = blendClickColor; 100 blendHoverColor_ = blendHoverColor; 101 } 102 SetFocusBorderColor(const Color & color)103 void SetFocusBorderColor(const Color& color) 104 { 105 focusBorderColor_ = color; 106 } 107 SetFocusBorderWidth(const Dimension & width)108 void SetFocusBorderWidth(const Dimension& width) 109 { 110 focusBorderWidth_ = width; 111 } 112 setComponentButtonType(const ComponentButtonType & buttonType)113 void setComponentButtonType(const ComponentButtonType& buttonType) 114 { 115 buttonType_ = buttonType; 116 } 117 ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter)118 void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const override 119 { 120 Pattern::ToJsonValue(json, filter); 121 /* no fixed attr below, just return */ 122 if (filter.IsFastFilter()) { 123 return; 124 } 125 auto host = GetHost(); 126 CHECK_NULL_VOID(host); 127 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>(); 128 CHECK_NULL_VOID(layoutProperty); 129 auto context = PipelineBase::GetCurrentContext(); 130 CHECK_NULL_VOID(context); 131 auto buttonTheme = context->GetTheme<ButtonTheme>(); 132 CHECK_NULL_VOID(buttonTheme); 133 auto textStyle = buttonTheme->GetTextStyle(); 134 json->PutExtAttr( 135 "type", host->GetTag() == "Toggle" ? "ToggleType.Button" 136 :ConvertButtonTypeToString(layoutProperty->GetType().value_or(ButtonType::CAPSULE)).c_str(), filter); 137 json->PutExtAttr("fontSize", 138 layoutProperty->GetFontSizeValue(layoutProperty->HasLabel() ? textStyle.GetFontSize() : Dimension(0)) 139 .ToString() 140 .c_str(), filter); 141 json->PutExtAttr("fontWeight", 142 V2::ConvertWrapFontWeightToStirng(layoutProperty->GetFontWeight().value_or(FontWeight::MEDIUM)).c_str(), filter); 143 json->PutExtAttr("fontColor", layoutProperty->GetFontColor() 144 .value_or(layoutProperty->HasLabel() ? textStyle.GetTextColor() : Color::BLACK) 145 .ColorToString() 146 .c_str(), filter); 147 json->PutExtAttr("fontStyle", layoutProperty->GetFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL 148 ? "FontStyle.Normal" 149 : "FontStyle.Italic", filter); 150 json->PutExtAttr("label", layoutProperty->GetLabelValue("").c_str(), filter); 151 auto eventHub = host->GetEventHub<ButtonEventHub>(); 152 CHECK_NULL_VOID(eventHub); 153 json->PutExtAttr("stateEffect", eventHub->GetStateEffect() ? "true" : "false", filter); 154 155 auto optionJson = JsonUtil::Create(true); 156 optionJson->Put( 157 "type", ConvertButtonTypeToString(layoutProperty->GetType().value_or(ButtonType::CAPSULE)).c_str()); 158 optionJson->Put("stateEffect", eventHub->GetStateEffect() ? "true" : "false"); 159 json->PutExtAttr("options", optionJson->ToString().c_str(), filter); 160 ToJsonValueAttribute(json, filter); 161 } 162 ToJsonValueAttribute(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter)163 void ToJsonValueAttribute(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const 164 { 165 auto host = GetHost(); 166 CHECK_NULL_VOID(host); 167 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>(); 168 CHECK_NULL_VOID(layoutProperty); 169 auto fontFamilyVector = 170 layoutProperty->GetFontFamily().value_or<std::vector<std::string>>({ "HarmonyOS Sans" }); 171 std::string fontFamily; 172 if (!fontFamilyVector.empty()) { 173 fontFamily = fontFamilyVector.at(0); 174 for (uint32_t i = 1; i < fontFamilyVector.size(); ++i) { 175 fontFamily += ',' + fontFamilyVector.at(i); 176 } 177 } 178 json->PutExtAttr("fontFamily", fontFamily.c_str(), filter); 179 auto fontJsValue = JsonUtil::Create(true); 180 fontJsValue->Put("size", layoutProperty->GetFontSizeValue(Dimension(0)).ToString().c_str()); 181 fontJsValue->Put("weight", 182 V2::ConvertWrapFontWeightToStirng(layoutProperty->GetFontWeight().value_or(FontWeight::MEDIUM)).c_str()); 183 fontJsValue->Put("family", fontFamily.c_str()); 184 fontJsValue->Put( 185 "style", layoutProperty->GetFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL 186 ? "FontStyle.Normal" 187 : "FontStyle.Italic"); 188 auto labelJsValue = JsonUtil::Create(true); 189 labelJsValue->Put("overflow", 190 V2::ConvertWrapTextOverflowToString(layoutProperty->GetTextOverflow().value_or(TextOverflow::CLIP)) 191 .c_str()); 192 labelJsValue->Put("maxLines", std::to_string(layoutProperty->GetMaxLines().value_or(DEFAULT_MAXLINES)).c_str()); 193 labelJsValue->Put("minFontSize", layoutProperty->GetMinFontSizeValue(Dimension(0)).ToString().c_str()); 194 labelJsValue->Put("maxFontSize", layoutProperty->GetMaxFontSizeValue(Dimension(0)).ToString().c_str()); 195 labelJsValue->Put("heightAdaptivePolicy", 196 V2::ConvertWrapTextHeightAdaptivePolicyToString( 197 layoutProperty->GetHeightAdaptivePolicy().value_or(TextHeightAdaptivePolicy::MAX_LINES_FIRST)) 198 .c_str()); 199 labelJsValue->Put("font", fontJsValue->ToString().c_str()); 200 json->PutExtAttr("labelStyle", labelJsValue->ToString().c_str(), filter); 201 202 json->PutExtAttr("buttonStyle", 203 ConvertButtonStyleToString(layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE)) 204 .c_str(), filter); 205 json->PutExtAttr("controlSize", 206 ConvertControlSizeToString(layoutProperty->GetControlSize().value_or(ControlSize::NORMAL)) 207 .c_str(), filter); 208 json->PutExtAttr( 209 "role", ConvertButtonRoleToString(layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL)) 210 .c_str(), filter); 211 } 212 ConvertButtonRoleToString(ButtonRole buttonRole)213 static std::string ConvertButtonRoleToString(ButtonRole buttonRole) 214 { 215 std::string result; 216 switch (buttonRole) { 217 case ButtonRole::NORMAL: 218 result = "ButtonRole.NORMAL"; 219 break; 220 case ButtonRole::ERROR: 221 result = "ButtonRole.ERROR"; 222 break; 223 default: 224 break; 225 } 226 return result; 227 } 228 ConvertButtonTypeToString(ButtonType buttonType)229 static std::string ConvertButtonTypeToString(ButtonType buttonType) 230 { 231 std::string result; 232 switch (buttonType) { 233 case ButtonType::NORMAL: 234 result = "ButtonType.Normal"; 235 break; 236 case ButtonType::CAPSULE: 237 result = "ButtonType.Capsule"; 238 break; 239 case ButtonType::CIRCLE: 240 result = "ButtonType.Circle"; 241 break; 242 default: 243 break; 244 } 245 return result; 246 } 247 ConvertButtonStyleToString(ButtonStyleMode buttonStyle)248 static std::string ConvertButtonStyleToString(ButtonStyleMode buttonStyle) 249 { 250 std::string result; 251 switch (buttonStyle) { 252 case ButtonStyleMode::NORMAL: 253 result = "ButtonStyleMode.NORMAL"; 254 break; 255 case ButtonStyleMode::EMPHASIZE: 256 result = "ButtonStyleMode.EMPHASIZED"; 257 break; 258 case ButtonStyleMode::TEXT: 259 result = "ButtonStyleMode.TEXTUAL"; 260 break; 261 default: 262 break; 263 } 264 return result; 265 } 266 ConvertControlSizeToString(ControlSize controlSize)267 static std::string ConvertControlSizeToString(ControlSize controlSize) 268 { 269 std::string result; 270 switch (controlSize) { 271 case ControlSize::SMALL: 272 result = "ControlSize.SMALL"; 273 break; 274 case ControlSize::NORMAL: 275 result = "ControlSize.NORMAL"; 276 break; 277 default: 278 break; 279 } 280 return result; 281 } 282 SetLocalLocation(const Offset & localLocation)283 void SetLocalLocation(const Offset& localLocation) 284 { 285 localLocation_ = localLocation; 286 } 287 GetLocalLocation()288 const Offset& GetLocalLocation() const 289 { 290 return localLocation_; 291 } 292 SetInHover(bool inHover)293 void SetInHover(bool inHover) 294 { 295 isInHover_ = inHover; 296 } 297 GetIsInHover()298 bool GetIsInHover() const 299 { 300 return isInHover_; 301 } 302 GetHoverListener()303 RefPtr<InputEvent>& GetHoverListener() 304 { 305 return hoverListener_; 306 } 307 GetTouchListener()308 RefPtr<TouchEventImpl>& GetTouchListener() 309 { 310 return touchListener_; 311 } 312 313 void SetBuilderFunc(ButtonMakeCallback&& makeFunc); 314 GetBuilderId()315 virtual int32_t GetBuilderId() const 316 { 317 return nodeId_; 318 } 319 320 void SetButtonPress(double xPos, double yPos); 321 UseContentModifier()322 virtual bool UseContentModifier() const 323 { 324 return contentModifierNode_ != nullptr; 325 } 326 327 void OnColorConfigurationUpdate() override; 328 SetSkipColorConfigurationUpdate()329 void SetSkipColorConfigurationUpdate() 330 { 331 isColorUpdateFlag_ = true; 332 } 333 SetPreFrameSize(const SizeF & frameSize)334 void SetPreFrameSize(const SizeF& frameSize) 335 { 336 preFrameSize_.SetSizeT(frameSize); 337 } 338 GetPreFrameSize()339 const SizeF& GetPreFrameSize() const 340 { 341 return preFrameSize_; 342 } 343 SetHasCustomPadding(bool hasCustomPadding)344 void SetHasCustomPadding(bool hasCustomPadding) 345 { 346 hasCustomPadding_ = hasCustomPadding; 347 } 348 GetHasCustomPadding()349 bool GetHasCustomPadding() 350 { 351 return hasCustomPadding_; 352 } 353 354 protected: IsNeedInitClickEventRecorder()355 bool IsNeedInitClickEventRecorder() const override 356 { 357 return true; 358 } 359 360 void OnModifyDone() override; 361 void OnAfterModifyDone() override; 362 void OnAttachToFrameNode() override; 363 void InitTouchEvent(); 364 void InitHoverEvent(); 365 void OnTouchDown(); 366 void OnTouchUp(); 367 void HandleHoverEvent(bool isHover); 368 void HandleBackgroundColor(); 369 void HandleEnabled(); 370 void InitButtonLabel(); 371 Color GetColorFromType(const RefPtr<ButtonTheme>& theme, const int32_t& type); 372 void AnimateTouchAndHover(RefPtr<RenderContext>& renderContext, int32_t typeFrom, int32_t typeTo, int32_t duration, 373 const RefPtr<Curve>& curve); 374 Color clickedColor_; 375 376 private: 377 static void UpdateTextLayoutProperty( 378 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty); 379 static void UpdateTextStyle( 380 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty); 381 static bool NeedAgingUpdateText(RefPtr<ButtonLayoutProperty>& layoutProperty); 382 bool IsNeedToHandleHoverOpacity(); 383 static void UpdateTextFontScale( 384 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty); 385 Color backgroundColor_; 386 Color focusBorderColor_; 387 Color themeBgColor_; 388 Color themeTextColor_; 389 bool isSetClickedColor_ = false; 390 ComponentButtonType buttonType_ = ComponentButtonType::BUTTON; 391 void FireBuilder(); 392 RefPtr<FrameNode> BuildContentModifierNode(); 393 GestureEventFunc tapEventFunc_; 394 std::optional<ButtonMakeCallback> makeFunc_; 395 RefPtr<FrameNode> contentModifierNode_; 396 std::optional<GestureEventFunc> clickEventFunc_; 397 int32_t nodeId_ = -1; 398 RefPtr<TouchEventImpl> touchListener_; 399 RefPtr<InputEvent> hoverListener_; 400 bool isHover_ = false; 401 bool isPress_ = false; 402 403 bool isInHover_ = false; 404 Offset localLocation_; 405 Dimension focusBorderWidth_; 406 407 std::optional<Color> blendClickColor_ = std::nullopt; 408 std::optional<Color> blendHoverColor_ = std::nullopt; 409 410 bool isColorUpdateFlag_ = false; 411 SizeF preFrameSize_; 412 bool hasCustomPadding_ = false; 413 ACE_DISALLOW_COPY_AND_MOVE(ButtonPattern); 414 }; 415 } // namespace OHOS::Ace::NG 416 417 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_BUTTON_BUTTON_PATTERN_H 418