• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()37 void ToggleButtonPattern::OnAttachToFrameNode()
38 {
39     InitParameters();
40 }
41 
InitParameters()42 void 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()62 void 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()109 void 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()138 void 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()155 void 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()184 void 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()222 void 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)237 bool 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