• 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/option/option_pattern.h"
17 
18 #include "base/memory/ace_type.h"
19 #include "base/utils/utils.h"
20 #include "core/components/select/select_theme.h"
21 #include "core/components_ng/base/ui_node.h"
22 #include "core/components_ng/pattern/menu/menu_pattern.h"
23 #include "core/components_ng/pattern/option/option_paint_property.h"
24 #include "core/components_ng/pattern/text/text_layout_property.h"
25 #include "core/components_ng/property/property.h"
26 #include "core/event/touch_event.h"
27 #include "core/pipeline/pipeline_base.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29 
30 namespace OHOS::Ace::NG {
31 
OnModifyDone()32 void OptionPattern::OnModifyDone()
33 {
34     RegisterOnClick();
35     RegisterOnTouch();
36     RegisterOnHover();
37 
38     auto host = GetHost();
39     CHECK_NULL_VOID(host);
40     auto focusHub = host->GetOrCreateFocusHub();
41     CHECK_NULL_VOID(focusHub);
42     RegisterOnKeyEvent(focusHub);
43 
44     auto context = PipelineBase::GetCurrentContext();
45     CHECK_NULL_VOID(context);
46     textTheme_ = context->GetTheme<TextTheme>();
47     CHECK_NULL_VOID(textTheme_);
48     selectTheme_ = context->GetTheme<SelectTheme>();
49     CHECK_NULL_VOID(selectTheme_);
50 
51     auto eventHub = host->GetEventHub<OptionEventHub>();
52     CHECK_NULL_VOID(eventHub);
53     if (!eventHub->IsEnabled()) {
54         CHECK_NULL_VOID(text_);
55         auto textProperty = text_->GetLayoutProperty<TextLayoutProperty>();
56         CHECK_NULL_VOID(textProperty);
57         textProperty->UpdateTextColor(selectTheme_->GetDisabledMenuFontColor());
58         text_->MarkModifyDone();
59     }
60 }
61 
OnSelectProcess()62 void OptionPattern::OnSelectProcess()
63 {
64     auto host = GetHost();
65     CHECK_NULL_VOID(host);
66     auto hub = host->GetEventHub<OptionEventHub>();
67     CHECK_NULL_VOID(hub);
68     auto JsAction = hub->GetJsCallback();
69     if (JsAction) {
70         LOGI("Option's callback executing");
71         JsAction();
72     }
73     auto onSelect = hub->GetOnSelect();
74     if (onSelect) {
75         LOGI("selecting option %d", index_);
76         onSelect(index_);
77     }
78     // hide menu when option is clicked
79     auto pipeline = PipelineContext::GetCurrentContext();
80     CHECK_NULL_VOID(pipeline);
81     auto overlayManager = pipeline->GetOverlayManager();
82     CHECK_NULL_VOID(overlayManager);
83     auto menu = GetMenu().Upgrade();
84     CHECK_NULL_VOID(menu);
85     auto menuPattern = menu->GetPattern<MenuPattern>();
86     CHECK_NULL_VOID(menuPattern);
87     auto targetId = menuPattern->GetTargetId();
88     overlayManager->HideMenu(targetId);
89 }
90 
PlayBgColorAnimation(bool isHoverChange)91 void OptionPattern::PlayBgColorAnimation(bool isHoverChange)
92 {
93     AnimationOption option = AnimationOption();
94     if (isHoverChange) {
95         option.SetDuration(selectTheme_->GetHoverAnimationDuration());
96         option.SetCurve(Curves::FRICTION);
97     } else {
98         option.SetDuration(selectTheme_->GetPressAnimationDuration());
99         option.SetCurve(Curves::SHARP);
100     }
101 
102     AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
103         auto pattern = weak.Upgrade();
104         CHECK_NULL_VOID_NOLOG(pattern);
105         auto host = pattern->GetHost();
106         CHECK_NULL_VOID_NOLOG(host);
107         auto renderContext = host->GetRenderContext();
108         CHECK_NULL_VOID_NOLOG(renderContext);
109         renderContext->BlendBgColor(pattern->GetBgBlendColor());
110     });
111 }
112 
RegisterOnClick()113 void OptionPattern::RegisterOnClick()
114 {
115     auto host = GetHost();
116     CHECK_NULL_VOID(host);
117     auto hub = host->GetEventHub<OptionEventHub>();
118 
119     auto event = [weak = WeakClaim(this)](GestureEvent& /* info */) {
120         auto pattern = weak.Upgrade();
121         CHECK_NULL_VOID_NOLOG(pattern);
122         pattern->OnSelectProcess();
123     };
124     auto clickEvent = MakeRefPtr<ClickEvent>(std::move(event));
125 
126     auto gestureHub = host->GetOrCreateGestureEventHub();
127     CHECK_NULL_VOID(gestureHub);
128     gestureHub->AddClickEvent(clickEvent);
129 }
130 
RegisterOnTouch()131 void OptionPattern::RegisterOnTouch()
132 {
133     auto host = GetHost();
134     CHECK_NULL_VOID(host);
135     auto gestureHub = host->GetOrCreateGestureEventHub();
136     CHECK_NULL_VOID(gestureHub);
137 
138     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
139         auto pattern = weak.Upgrade();
140         CHECK_NULL_VOID(pattern);
141         pattern->OnPress(info);
142     };
143     auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
144     gestureHub->AddTouchEvent(touchEvent);
145 }
146 
RegisterOnHover()147 void OptionPattern::RegisterOnHover()
148 {
149     auto host = GetHost();
150     CHECK_NULL_VOID(host);
151     auto inputHub = host->GetOrCreateInputEventHub();
152     CHECK_NULL_VOID(inputHub);
153     auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
154         auto pattern = weak.Upgrade();
155         CHECK_NULL_VOID(pattern);
156         pattern->OnHover(isHover);
157     };
158     auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
159     inputHub->AddOnHoverEvent(mouseEvent);
160 }
161 
RegisterOnKeyEvent(const RefPtr<FocusHub> & focusHub)162 void OptionPattern::RegisterOnKeyEvent(const RefPtr<FocusHub>& focusHub)
163 {
164     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
165         auto pattern = wp.Upgrade();
166         CHECK_NULL_RETURN_NOLOG(pattern, false);
167         return pattern->OnKeyEvent(event);
168     };
169     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
170 }
171 
OnKeyEvent(const KeyEvent & event)172 bool OptionPattern::OnKeyEvent(const KeyEvent& event)
173 {
174     if (event.action != KeyAction::DOWN) {
175         return false;
176     }
177     if (event.code == KeyCode::KEY_ENTER || event.code == KeyCode::KEY_SPACE) {
178         OnSelectProcess();
179         return true;
180     }
181     return false;
182 }
183 
OnPress(const TouchEventInfo & info)184 void OptionPattern::OnPress(const TouchEventInfo& info)
185 {
186     auto host = GetHost();
187     CHECK_NULL_VOID(host);
188     const auto& renderContext = host->GetRenderContext();
189     CHECK_NULL_VOID(renderContext);
190     auto props = GetPaintProperty<OptionPaintProperty>();
191     CHECK_NULL_VOID(props);
192     auto touchType = info.GetTouches().front().GetTouchType();
193 
194     auto pipeline = PipelineBase::GetCurrentContext();
195     CHECK_NULL_VOID(pipeline);
196     auto theme = pipeline->GetTheme<SelectTheme>();
197     // enter press status
198     if (touchType == TouchType::DOWN) {
199         LOGD("triggers option press");
200         // change background color, update press status
201         SetBgBlendColor(theme->GetClickedColor());
202         PlayBgColorAnimation(false);
203 
204         props->UpdatePress(true);
205         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
206         // disable next option node's divider
207         UpdateNextNodeDivider(false);
208     }
209     // leave press status
210     else if (touchType == TouchType::UP) {
211         if (IsHover()) {
212             SetBgBlendColor(theme->GetHoverColor());
213         } else {
214             SetBgBlendColor(Color::TRANSPARENT);
215         }
216         PlayBgColorAnimation(false);
217 
218         props->UpdatePress(false);
219         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
220         UpdateNextNodeDivider(true);
221     }
222 }
223 
OnHover(bool isHover)224 void OptionPattern::OnHover(bool isHover)
225 {
226     SetIsHover(isHover);
227 
228     auto host = GetHost();
229     CHECK_NULL_VOID(host);
230     auto renderContext = host->GetRenderContext();
231     CHECK_NULL_VOID(renderContext);
232     auto props = GetPaintProperty<OptionPaintProperty>();
233     CHECK_NULL_VOID(props);
234     if (isHover) {
235         auto pipeline = PipelineContext::GetCurrentContext();
236         CHECK_NULL_VOID(pipeline);
237         auto theme = pipeline->GetTheme<SelectTheme>();
238         auto hoverColor = theme->GetHoverColor();
239         SetBgBlendColor(hoverColor);
240 
241         props->UpdateHover(true);
242         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
243         UpdateNextNodeDivider(false);
244     } else {
245         SetBgBlendColor(Color::TRANSPARENT);
246 
247         props->UpdateHover(false);
248         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
249         UpdateNextNodeDivider(true);
250     }
251     PlayBgColorAnimation();
252 }
253 
UpdateNextNodeDivider(bool needDivider)254 void OptionPattern::UpdateNextNodeDivider(bool needDivider)
255 {
256     auto host = GetHost();
257     // find next option node from parent menuNode
258     CHECK_NULL_VOID(host);
259     auto parent = host->GetParent();
260     CHECK_NULL_VOID(parent);
261     auto nextNode = parent->GetChildAtIndex(index_ + 1);
262     if (nextNode) {
263         if (!InstanceOf<FrameNode>(nextNode)) {
264             LOGW("next optionNode is not a frameNode! type = %{public}s", nextNode->GetTag().c_str());
265             return;
266         }
267         auto props = DynamicCast<FrameNode>(nextNode)->GetPaintProperty<OptionPaintProperty>();
268         CHECK_NULL_VOID(props);
269         props->UpdateNeedDivider(needDivider);
270         nextNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
271     }
272 }
273 
SetBgColor(const Color & color)274 void OptionPattern::SetBgColor(const Color& color)
275 {
276     auto renderContext = GetHost()->GetRenderContext();
277     CHECK_NULL_VOID(renderContext);
278     renderContext->UpdateBackgroundColor(color);
279     bgColor_ = color;
280 }
281 
SetFontSize(const Dimension & value)282 void OptionPattern::SetFontSize(const Dimension& value)
283 {
284     CHECK_NULL_VOID(text_);
285     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
286     CHECK_NULL_VOID(props);
287     text_->MarkModifyDone();
288     CHECK_NULL_VOID(selectTheme_);
289     props->UpdateFontSize(value.IsNegative() ? selectTheme_->GetMenuFontSize() : value);
290 }
291 
SetItalicFontStyle(const Ace::FontStyle & value)292 void OptionPattern::SetItalicFontStyle(const Ace::FontStyle& value)
293 {
294     CHECK_NULL_VOID(text_);
295     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
296     CHECK_NULL_VOID(props);
297     text_->MarkModifyDone();
298     props->UpdateItalicFontStyle(value);
299 }
300 
SetFontWeight(const FontWeight & value)301 void OptionPattern::SetFontWeight(const FontWeight& value)
302 {
303     CHECK_NULL_VOID(text_);
304     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
305     CHECK_NULL_VOID(props);
306     text_->MarkModifyDone();
307     props->UpdateFontWeight(value);
308 }
309 
SetFontFamily(const std::vector<std::string> & value)310 void OptionPattern::SetFontFamily(const std::vector<std::string>& value)
311 {
312     CHECK_NULL_VOID(text_);
313     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
314     CHECK_NULL_VOID(props);
315     text_->MarkModifyDone();
316     props->UpdateFontFamily(value);
317 }
318 
SetFontColor(const Color & color)319 void OptionPattern::SetFontColor(const Color& color)
320 {
321     CHECK_NULL_VOID(text_);
322     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
323     CHECK_NULL_VOID(props);
324     text_->MarkModifyDone();
325     props->UpdateTextColor(color);
326 }
327 
InspectorGetFont()328 std::string OptionPattern::InspectorGetFont()
329 {
330     CHECK_NULL_RETURN(text_, "");
331     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
332     CHECK_NULL_RETURN(props, "");
333     return props->InspectorGetTextFont();
334 }
335 
GetBgColor()336 Color OptionPattern::GetBgColor()
337 {
338     auto pipeline = PipelineContext::GetCurrentContext();
339     CHECK_NULL_RETURN(pipeline, Color());
340     auto theme = pipeline->GetTheme<SelectTheme>();
341     CHECK_NULL_RETURN(theme, Color());
342     auto bgColor = theme->GetBackgroundColor();
343     return bgColor_.value_or(bgColor);
344 }
345 
GetFontSize()346 Dimension OptionPattern::GetFontSize()
347 {
348     CHECK_NULL_RETURN(text_, Dimension());
349     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
350     CHECK_NULL_RETURN(props, Dimension());
351     CHECK_NULL_RETURN(selectTheme_, Dimension());
352     auto defaultSize = selectTheme_->GetMenuFontSize();
353     return props->GetFontSizeValue(defaultSize);
354 }
355 
GetItalicFontStyle()356 Ace::FontStyle OptionPattern::GetItalicFontStyle()
357 {
358     CHECK_NULL_RETURN(text_, Ace::FontStyle());
359     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
360     CHECK_NULL_RETURN(props, Ace::FontStyle());
361     auto defaultStyle = textTheme_->GetTextStyle().GetFontStyle();
362     return props->GetItalicFontStyleValue(defaultStyle);
363 }
364 
GetFontWeight()365 FontWeight OptionPattern::GetFontWeight()
366 {
367     CHECK_NULL_RETURN(text_, FontWeight());
368     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
369     CHECK_NULL_RETURN(props, FontWeight());
370     auto defaultWeight = textTheme_->GetTextStyle().GetFontWeight();
371     return props->GetFontWeightValue(defaultWeight);
372 }
373 
GetFontFamily()374 std::vector<std::string> OptionPattern::GetFontFamily()
375 {
376     CHECK_NULL_RETURN(text_, std::vector<std::string>());
377     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
378     CHECK_NULL_RETURN(props, std::vector<std::string>());
379     auto defaultFamily = textTheme_->GetTextStyle().GetFontFamilies();
380     return props->GetFontFamilyValue(defaultFamily);
381 }
382 
GetFontColor()383 Color OptionPattern::GetFontColor()
384 {
385     CHECK_NULL_RETURN(text_, Color::TRANSPARENT);
386     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
387     CHECK_NULL_RETURN(props, Color::TRANSPARENT);
388     auto defaultColor = selectTheme_->GetMenuFontColor();
389     return props->GetTextColorValue(defaultColor);
390 }
391 
GetText()392 const std::string& OptionPattern::GetText()
393 {
394     CHECK_NULL_RETURN(text_, std::string());
395     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
396     CHECK_NULL_RETURN(textProps, std::string());
397     return textProps->GetContentValue();
398 }
399 
400 } // namespace OHOS::Ace::NG