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 auto isNeedAdjust = layoutProperty->HasAspectRatio() && 88 layoutProperty->GetType().value_or(ButtonType::CAPSULE) != ButtonType::CIRCLE; 89 90 return isNeedAdjust; 91 } 92 SetClickedColor(const Color & color)93 void SetClickedColor(const Color& color) 94 { 95 clickedColor_ = color; 96 isSetClickedColor_ = true; 97 } 98 SetBlendColor(const std::optional<Color> & blendClickColor,const std::optional<Color> & blendHoverColor)99 void SetBlendColor(const std::optional<Color>& blendClickColor, const std::optional<Color>& blendHoverColor) 100 { 101 blendClickColor_ = blendClickColor; 102 blendHoverColor_ = blendHoverColor; 103 } 104 SetFocusBorderColor(const Color & color)105 void SetFocusBorderColor(const Color& color) 106 { 107 focusBorderColor_ = color; 108 } 109 SetFocusBorderWidth(const Dimension & width)110 void SetFocusBorderWidth(const Dimension& width) 111 { 112 focusBorderWidth_ = width; 113 } 114 setComponentButtonType(const ComponentButtonType & buttonType)115 void setComponentButtonType(const ComponentButtonType& buttonType) 116 { 117 buttonType_ = buttonType; 118 } 119 ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter)120 void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const override 121 { 122 Pattern::ToJsonValue(json, filter); 123 /* no fixed attr below, just return */ 124 if (filter.IsFastFilter()) { 125 return; 126 } 127 auto host = GetHost(); 128 CHECK_NULL_VOID(host); 129 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>(); 130 CHECK_NULL_VOID(layoutProperty); 131 auto context = PipelineBase::GetCurrentContext(); 132 CHECK_NULL_VOID(context); 133 auto buttonTheme = context->GetTheme<ButtonTheme>(); 134 CHECK_NULL_VOID(buttonTheme); 135 auto textStyle = buttonTheme->GetTextStyle(); 136 auto buttonType = layoutProperty->GetType().value_or(ButtonType::CAPSULE); 137 json->PutExtAttr("type", host->GetTag() == "Toggle" ? "ToggleType.Button" : 138 ConvertButtonTypeToString(buttonType).c_str(), filter); 139 json->PutExtAttr("fontSize", 140 layoutProperty->GetFontSizeValue(layoutProperty->HasLabel() ? textStyle.GetFontSize() : Dimension(0)) 141 .ToString() 142 .c_str(), filter); 143 json->PutExtAttr("fontWeight", 144 V2::ConvertWrapFontWeightToStirng(layoutProperty->GetFontWeight().value_or(FontWeight::MEDIUM)).c_str(), filter); 145 json->PutExtAttr("fontColor", layoutProperty->GetFontColor() 146 .value_or(layoutProperty->HasLabel() ? textStyle.GetTextColor() : Color::BLACK) 147 .ColorToString() 148 .c_str(), filter); 149 json->PutExtAttr("fontStyle", layoutProperty->GetFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL 150 ? "FontStyle.Normal" 151 : "FontStyle.Italic", filter); 152 json->PutExtAttr("label", layoutProperty->GetLabelValue("").c_str(), filter); 153 auto eventHub = host->GetEventHub<ButtonEventHub>(); 154 CHECK_NULL_VOID(eventHub); 155 json->PutExtAttr("stateEffect", eventHub->GetStateEffect() ? "true" : "false", filter); 156 157 auto optionJson = JsonUtil::Create(true); 158 optionJson->Put( 159 "type", ConvertButtonTypeToString(layoutProperty->GetType().value_or(ButtonType::CAPSULE)).c_str()); 160 optionJson->Put("stateEffect", eventHub->GetStateEffect() ? "true" : "false"); 161 json->PutExtAttr("options", optionJson->ToString().c_str(), filter); 162 ToJsonValueAttribute(json, filter); 163 } 164 ToJsonValueAttribute(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter)165 void ToJsonValueAttribute(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const 166 { 167 auto host = GetHost(); 168 CHECK_NULL_VOID(host); 169 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>(); 170 CHECK_NULL_VOID(layoutProperty); 171 auto fontFamilyVector = 172 layoutProperty->GetFontFamily().value_or<std::vector<std::string>>({ "HarmonyOS Sans" }); 173 std::string fontFamily; 174 if (!fontFamilyVector.empty()) { 175 fontFamily = fontFamilyVector.at(0); 176 for (uint32_t i = 1; i < fontFamilyVector.size(); ++i) { 177 fontFamily += ',' + fontFamilyVector.at(i); 178 } 179 } 180 json->PutExtAttr("fontFamily", fontFamily.c_str(), filter); 181 auto fontJsValue = JsonUtil::Create(true); 182 fontJsValue->Put("size", layoutProperty->GetFontSizeValue(Dimension(0)).ToString().c_str()); 183 fontJsValue->Put("weight", 184 V2::ConvertWrapFontWeightToStirng(layoutProperty->GetFontWeight().value_or(FontWeight::MEDIUM)).c_str()); 185 fontJsValue->Put("family", fontFamily.c_str()); 186 fontJsValue->Put( 187 "style", layoutProperty->GetFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL 188 ? "FontStyle.Normal" 189 : "FontStyle.Italic"); 190 auto labelJsValue = JsonUtil::Create(true); 191 labelJsValue->Put("overflow", 192 V2::ConvertWrapTextOverflowToString(layoutProperty->GetTextOverflow().value_or(TextOverflow::CLIP)) 193 .c_str()); 194 labelJsValue->Put("maxLines", std::to_string(layoutProperty->GetMaxLines().value_or(DEFAULT_MAXLINES)).c_str()); 195 labelJsValue->Put("minFontSize", layoutProperty->GetMinFontSizeValue(Dimension(0)).ToString().c_str()); 196 labelJsValue->Put("maxFontSize", layoutProperty->GetMaxFontSizeValue(Dimension(0)).ToString().c_str()); 197 labelJsValue->Put("heightAdaptivePolicy", 198 V2::ConvertWrapTextHeightAdaptivePolicyToString( 199 layoutProperty->GetHeightAdaptivePolicy().value_or(TextHeightAdaptivePolicy::MAX_LINES_FIRST)) 200 .c_str()); 201 labelJsValue->Put("font", fontJsValue->ToString().c_str()); 202 json->PutExtAttr("labelStyle", labelJsValue->ToString().c_str(), filter); 203 204 json->PutExtAttr("buttonStyle", 205 ConvertButtonStyleToString(layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE)) 206 .c_str(), filter); 207 json->PutExtAttr("controlSize", 208 ConvertControlSizeToString(layoutProperty->GetControlSize().value_or(ControlSize::NORMAL)) 209 .c_str(), filter); 210 json->PutExtAttr( 211 "role", ConvertButtonRoleToString(layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL)) 212 .c_str(), filter); 213 } 214 ConvertButtonRoleToString(ButtonRole buttonRole)215 static std::string ConvertButtonRoleToString(ButtonRole buttonRole) 216 { 217 std::string result; 218 switch (buttonRole) { 219 case ButtonRole::NORMAL: 220 result = "ButtonRole.NORMAL"; 221 break; 222 case ButtonRole::ERROR: 223 result = "ButtonRole.ERROR"; 224 break; 225 default: 226 break; 227 } 228 return result; 229 } 230 ConvertButtonTypeToString(ButtonType buttonType)231 static std::string ConvertButtonTypeToString(ButtonType buttonType) 232 { 233 std::string result; 234 switch (buttonType) { 235 case ButtonType::NORMAL: 236 result = "ButtonType.Normal"; 237 break; 238 case ButtonType::CAPSULE: 239 result = "ButtonType.Capsule"; 240 break; 241 case ButtonType::CIRCLE: 242 result = "ButtonType.Circle"; 243 break; 244 case ButtonType::ROUNDED_RECTANGLE: 245 result = "ButtonType.ROUNDED_RECTANGLE"; 246 break; 247 default: 248 break; 249 } 250 return result; 251 } 252 ConvertButtonStyleToString(ButtonStyleMode buttonStyle)253 static std::string ConvertButtonStyleToString(ButtonStyleMode buttonStyle) 254 { 255 std::string result; 256 switch (buttonStyle) { 257 case ButtonStyleMode::NORMAL: 258 result = "ButtonStyleMode.NORMAL"; 259 break; 260 case ButtonStyleMode::EMPHASIZE: 261 result = "ButtonStyleMode.EMPHASIZED"; 262 break; 263 case ButtonStyleMode::TEXT: 264 result = "ButtonStyleMode.TEXTUAL"; 265 break; 266 default: 267 break; 268 } 269 return result; 270 } 271 ConvertControlSizeToString(ControlSize controlSize)272 static std::string ConvertControlSizeToString(ControlSize controlSize) 273 { 274 std::string result; 275 switch (controlSize) { 276 case ControlSize::SMALL: 277 result = "ControlSize.SMALL"; 278 break; 279 case ControlSize::NORMAL: 280 result = "ControlSize.NORMAL"; 281 break; 282 default: 283 break; 284 } 285 return result; 286 } 287 SetLocalLocation(const Offset & localLocation)288 void SetLocalLocation(const Offset& localLocation) 289 { 290 localLocation_ = localLocation; 291 } 292 GetLocalLocation()293 const Offset& GetLocalLocation() const 294 { 295 return localLocation_; 296 } 297 SetInHover(bool inHover)298 void SetInHover(bool inHover) 299 { 300 isInHover_ = inHover; 301 } 302 GetIsInHover()303 bool GetIsInHover() const 304 { 305 return isInHover_; 306 } 307 GetHoverListener()308 RefPtr<InputEvent>& GetHoverListener() 309 { 310 return hoverListener_; 311 } 312 GetTouchListener()313 RefPtr<TouchEventImpl>& GetTouchListener() 314 { 315 return touchListener_; 316 } 317 318 void SetBuilderFunc(ButtonMakeCallback&& makeFunc); 319 GetBuilderId()320 virtual int32_t GetBuilderId() const 321 { 322 return nodeId_; 323 } 324 325 void SetButtonPress(double xPos, double yPos); 326 UseContentModifier()327 virtual bool UseContentModifier() const 328 { 329 return contentModifierNode_ != nullptr; 330 } 331 332 void OnColorConfigurationUpdate() override; 333 SetSkipColorConfigurationUpdate()334 void SetSkipColorConfigurationUpdate() 335 { 336 isColorUpdateFlag_ = true; 337 } 338 SetPreFrameSize(const SizeF & frameSize)339 void SetPreFrameSize(const SizeF& frameSize) 340 { 341 preFrameSize_.SetSizeT(frameSize); 342 } 343 GetPreFrameSize()344 const SizeF& GetPreFrameSize() const 345 { 346 return preFrameSize_; 347 } 348 SetHasCustomPadding(bool hasCustomPadding)349 void SetHasCustomPadding(bool hasCustomPadding) 350 { 351 hasCustomPadding_ = hasCustomPadding; 352 } 353 GetHasCustomPadding()354 bool GetHasCustomPadding() 355 { 356 return hasCustomPadding_; 357 } 358 359 protected: IsNeedInitClickEventRecorder()360 bool IsNeedInitClickEventRecorder() const override 361 { 362 return true; 363 } 364 365 void OnModifyDone() override; 366 void OnAfterModifyDone() override; 367 void OnAttachToFrameNode() override; 368 void InitTouchEvent(); 369 void InitHoverEvent(); 370 void OnTouchDown(); 371 void OnTouchUp(); 372 void HandleHoverEvent(bool isHover); 373 void HandleBackgroundColor(); 374 void HandleEnabled(); 375 void InitButtonLabel(); 376 void CheckLocalizedBorderRadiuses(); 377 Color GetColorFromType(const RefPtr<ButtonTheme>& theme, const int32_t& type); 378 void AnimateTouchAndHover(RefPtr<RenderContext>& renderContext, int32_t typeFrom, int32_t typeTo, int32_t duration, 379 const RefPtr<Curve>& curve); 380 Color clickedColor_; 381 382 private: 383 static void UpdateTextLayoutProperty( 384 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty); 385 static void UpdateTextStyle( 386 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty); 387 static bool NeedAgingUpdateText(RefPtr<ButtonLayoutProperty>& layoutProperty); 388 bool IsNeedToHandleHoverOpacity(); 389 static void UpdateTextFontScale( 390 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty); 391 Color backgroundColor_; 392 Color focusBorderColor_; 393 Color themeBgColor_; 394 Color themeTextColor_; 395 bool isSetClickedColor_ = false; 396 ComponentButtonType buttonType_ = ComponentButtonType::BUTTON; 397 void FireBuilder(); 398 RefPtr<FrameNode> BuildContentModifierNode(); 399 GestureEventFunc tapEventFunc_; 400 std::optional<ButtonMakeCallback> makeFunc_; 401 RefPtr<FrameNode> contentModifierNode_; 402 std::optional<GestureEventFunc> clickEventFunc_; 403 int32_t nodeId_ = -1; 404 RefPtr<TouchEventImpl> touchListener_; 405 RefPtr<InputEvent> hoverListener_; 406 bool isHover_ = false; 407 bool isPress_ = false; 408 409 bool isInHover_ = false; 410 Offset localLocation_; 411 Dimension focusBorderWidth_; 412 413 std::optional<Color> blendClickColor_ = std::nullopt; 414 std::optional<Color> blendHoverColor_ = std::nullopt; 415 416 bool isColorUpdateFlag_ = false; 417 SizeF preFrameSize_; 418 bool hasCustomPadding_ = false; 419 ACE_DISALLOW_COPY_AND_MOVE(ButtonPattern); 420 }; 421 } // namespace OHOS::Ace::NG 422 423 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_BUTTON_BUTTON_PATTERN_H 424