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 #include "core/components_ng/pattern/button/toggle_button_pattern.h" 17 18 #include "base/geometry/axis.h" 19 #include "base/memory/ace_type.h" 20 #include "base/utils/macros.h" 21 #include "base/utils/utils.h" 22 #include "core/components/button/button_theme.h" 23 #include "core/components/common/layout/constants.h" 24 #include "core/components/common/properties/color.h" 25 #include "core/components/toggle/toggle_theme.h" 26 #include "core/components_ng/base/ui_node.h" 27 #include "core/components_ng/base/view_abstract.h" 28 #include "core/components_ng/base/view_stack_processor.h" 29 #include "core/components_ng/pattern/button/toggle_button_model_ng.h" 30 #include "core/components_ng/pattern/button/toggle_button_paint_property.h" 31 #include "core/components_ng/pattern/text/text_layout_property.h" 32 #include "core/components_ng/property/property.h" 33 #include "core/pipeline/pipeline_base.h" 34 35 namespace OHOS::Ace::NG { 36 OnAttachToFrameNode()37void ToggleButtonPattern::OnAttachToFrameNode() 38 { 39 InitParameters(); 40 } 41 InitParameters()42void ToggleButtonPattern::InitParameters() 43 { 44 auto pipeline = PipelineBase::GetCurrentContext(); 45 CHECK_NULL_VOID(pipeline); 46 auto toggleTheme = pipeline->GetTheme<ToggleTheme>(); 47 CHECK_NULL_VOID(toggleTheme); 48 checkedColor_ = toggleTheme->GetCheckedColor(); 49 unCheckedColor_ = toggleTheme->GetBackgroundColor(); 50 textMargin_ = toggleTheme->GetTextMargin(); 51 buttonMargin_ = toggleTheme->GetButtonMargin(); 52 buttonHeight_ = toggleTheme->GetButtonHeight(); 53 buttonRadius_ = toggleTheme->GetButtonRadius(); 54 textFontSize_ = toggleTheme->GetTextFontSize(); 55 textColor_ = toggleTheme->GetTextColor(); 56 disabledAlpha_ = toggleTheme->GetDisabledAlpha(); 57 auto buttonTheme = pipeline->GetTheme<ButtonTheme>(); 58 CHECK_NULL_VOID(buttonTheme); 59 clickedColor_ = buttonTheme->GetClickedColor(); 60 } 61 OnModifyDone()62void ToggleButtonPattern::OnModifyDone() 63 { 64 auto host = GetHost(); 65 CHECK_NULL_VOID(host); 66 67 auto layoutProperty = host->GetLayoutProperty(); 68 CHECK_NULL_VOID(layoutProperty); 69 if (layoutProperty->GetPositionProperty()) { 70 layoutProperty->UpdateAlignment( 71 layoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER)); 72 } else { 73 layoutProperty->UpdateAlignment(Alignment::CENTER); 74 } 75 76 auto buttonPaintProperty = GetPaintProperty<ToggleButtonPaintProperty>(); 77 CHECK_NULL_VOID(buttonPaintProperty); 78 if (!isOn_.has_value()) { 79 isOn_ = buttonPaintProperty->GetIsOnValue(); 80 } 81 bool changed = false; 82 if (buttonPaintProperty->HasIsOn()) { 83 bool isOn = buttonPaintProperty->GetIsOnValue(); 84 changed = isOn ^ isOn_.value(); 85 isOn_ = isOn; 86 } 87 const auto& renderContext = host->GetRenderContext(); 88 CHECK_NULL_VOID(renderContext); 89 90 if (isOn_.value()) { 91 auto selectedColor = buttonPaintProperty->GetSelectedColor().value_or(checkedColor_); 92 renderContext->UpdateBackgroundColor(selectedColor); 93 } else { 94 auto bgColor = buttonPaintProperty->GetBackgroundColor().value_or(unCheckedColor_); 95 renderContext->UpdateBackgroundColor(bgColor); 96 } 97 98 if (changed) { 99 auto toggleButtonEventHub = GetEventHub<ToggleButtonEventHub>(); 100 CHECK_NULL_VOID(toggleButtonEventHub); 101 toggleButtonEventHub->UpdateChangeEvent(isOn_.value()); 102 } 103 InitButtonAndText(); 104 HandleEnabled(); 105 InitTouchEvent(); 106 InitOnKeyEvent(); 107 } 108 HandleEnabled()109void ToggleButtonPattern::HandleEnabled() 110 { 111 auto host = GetHost(); 112 CHECK_NULL_VOID(host); 113 auto eventHub = host->GetEventHub<EventHub>(); 114 CHECK_NULL_VOID(eventHub); 115 auto enabled = eventHub->IsEnabled(); 116 auto renderContext = host->GetRenderContext(); 117 CHECK_NULL_VOID(renderContext); 118 auto pipeline = PipelineBase::GetCurrentContext(); 119 CHECK_NULL_VOID(pipeline); 120 auto theme = pipeline->GetTheme<ToggleTheme>(); 121 CHECK_NULL_VOID(theme); 122 auto backgroundColor = renderContext->GetBackgroundColor().value_or(theme->GetCheckedColor()); 123 if (!enabled) { 124 if (host->GetFirstChild()) { 125 auto textNode = DynamicCast<FrameNode>(host->GetFirstChild()); 126 CHECK_NULL_VOID(textNode); 127 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>(); 128 CHECK_NULL_VOID(textLayoutProperty); 129 auto color = textLayoutProperty->GetTextColorValue(textColor_); 130 textLayoutProperty->UpdateTextColor(color.BlendOpacity(disabledAlpha_)); 131 } 132 renderContext->OnBackgroundColorUpdate(backgroundColor.BlendOpacity(disabledAlpha_)); 133 } else { 134 renderContext->OnBackgroundColorUpdate(backgroundColor); 135 } 136 } 137 InitClickEvent()138void ToggleButtonPattern::InitClickEvent() 139 { 140 if (clickListener_) { 141 return; 142 } 143 auto host = GetHost(); 144 CHECK_NULL_VOID(host); 145 auto gesture = host->GetOrCreateGestureEventHub(); 146 CHECK_NULL_VOID(gesture); 147 auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) { 148 auto buttonPattern = weak.Upgrade(); 149 buttonPattern->OnClick(); 150 }; 151 clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback)); 152 gesture->AddClickEvent(clickListener_); 153 } 154 OnClick()155void ToggleButtonPattern::OnClick() 156 { 157 auto host = GetHost(); 158 CHECK_NULL_VOID(host); 159 auto paintProperty = host->GetPaintProperty<ToggleButtonPaintProperty>(); 160 CHECK_NULL_VOID(paintProperty); 161 bool isLastSelected = false; 162 if (paintProperty->HasIsOn()) { 163 isLastSelected = paintProperty->GetIsOnValue(); 164 } 165 const auto& renderContext = host->GetRenderContext(); 166 CHECK_NULL_VOID(renderContext); 167 Color selectedColor; 168 auto buttonPaintProperty = host->GetPaintProperty<ToggleButtonPaintProperty>(); 169 CHECK_NULL_VOID(buttonPaintProperty); 170 if (isLastSelected) { 171 selectedColor = buttonPaintProperty->GetBackgroundColor().value_or(unCheckedColor_); 172 } else { 173 selectedColor = buttonPaintProperty->GetSelectedColor().value_or(checkedColor_); 174 } 175 paintProperty->UpdateIsOn(!isLastSelected); 176 isOn_ = !isLastSelected; 177 renderContext->UpdateBackgroundColor(selectedColor); 178 auto buttonEventHub = GetEventHub<ToggleButtonEventHub>(); 179 CHECK_NULL_VOID(buttonEventHub); 180 buttonEventHub->UpdateChangeEvent(!isLastSelected); 181 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER); 182 } 183 InitButtonAndText()184void ToggleButtonPattern::InitButtonAndText() 185 { 186 auto host = GetHost(); 187 CHECK_NULL_VOID(host); 188 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>(); 189 CHECK_NULL_VOID(layoutProperty); 190 if ((!layoutProperty->GetCalcLayoutConstraint() || 191 !layoutProperty->GetCalcLayoutConstraint()->selfIdealSize->Height().has_value())) { 192 layoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(buttonHeight_))); 193 } 194 if (!layoutProperty->HasBorderRadius()) { 195 layoutProperty->UpdateBorderRadius(buttonRadius_); 196 } 197 if (!host->GetFirstChild()) { 198 return; 199 } 200 auto textNode = DynamicCast<FrameNode>(host->GetFirstChild()); 201 CHECK_NULL_VOID(textNode); 202 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>(); 203 CHECK_NULL_VOID(textLayoutProperty); 204 if (!textLayoutProperty->HasFontSize()) { 205 textLayoutProperty->UpdateFontSize(textFontSize_); 206 } else { 207 layoutProperty->UpdateFontSize(textLayoutProperty->GetFontSizeValue(textFontSize_)); 208 } 209 layoutProperty->UpdateLabel(textLayoutProperty->GetContentValue("")); 210 textLayoutProperty->UpdateTextColor(textColor_); 211 212 if (!textLayoutProperty->GetMarginProperty()) { 213 MarginProperty margin; 214 margin.left = CalcLength(textMargin_.ConvertToPx()); 215 margin.right = CalcLength(textMargin_.ConvertToPx()); 216 textLayoutProperty->UpdateMargin(margin); 217 } 218 textNode->MarkModifyDone(); 219 textNode->MarkDirtyNode(); 220 } 221 InitOnKeyEvent()222void ToggleButtonPattern::InitOnKeyEvent() 223 { 224 auto host = GetHost(); 225 CHECK_NULL_VOID(host); 226 auto focusHub = host->GetOrCreateFocusHub(); 227 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool { 228 auto pattern = wp.Upgrade(); 229 if (!pattern) { 230 return false; 231 } 232 return pattern->OnKeyEvent(event); 233 }; 234 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent)); 235 } 236 OnKeyEvent(const KeyEvent & event)237bool ToggleButtonPattern::OnKeyEvent(const KeyEvent& event) 238 { 239 if (event.action != KeyAction::DOWN) { 240 return false; 241 } 242 if (event.code == KeyCode::KEY_SPACE || event.code == KeyCode::KEY_ENTER) { 243 OnClick(); 244 return true; 245 } 246 return false; 247 } 248 } // namespace OHOS::Ace::NG 249