• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "core/components_ng/pattern/app_bar/atomic_service_pattern.h"
16 
17 #include "base/utils/utils.h"
18 #include "core/common/container.h"
19 #include "core/components_ng/pattern/button/button_pattern.h"
20 #include "core/components_ng/pattern/divider/divider_render_property.h"
21 #include "core/components_ng/pattern/image/image_layout_property.h"
22 #include "core/components_ng/pattern/image/image_render_property.h"
23 #include "core/components_ng/pattern/text/text_layout_property.h"
24 #include "core/components_ng/property/calc_length.h"
25 #include "core/components_ng/property/measure_property.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27 
28 namespace OHOS::Ace::NG {
29 constexpr int32_t ATOMIC_SERVICE_MIN_SIZE = 2;
30 constexpr int32_t FIRST_OVERLAY_INDEX = 1;
31 
BeforeCreateLayoutWrapper()32 void AtomicServicePattern::BeforeCreateLayoutWrapper()
33 {
34     auto pipeline = PipelineContext::GetCurrentContext();
35     CHECK_NULL_VOID(pipeline);
36     auto theme = pipeline->GetTheme<AppBarTheme>();
37     CHECK_NULL_VOID(theme);
38     auto menuBar = GetMenuBar();
39     auto safeArea = pipeline->GetSafeArea();
40     auto safeAreaLeft = safeArea.left_.Length();
41     auto safeAreaRight = safeArea.right_.Length();
42     if (safeAreaLeft_ != safeAreaLeft || safeAreaRight_ != safeAreaRight) {
43         safeAreaLeft_ = safeAreaLeft;
44         safeAreaRight_ = safeAreaRight;
45         bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
46         UpdateMenuBarLayout(theme, menuBar, isRtl);
47     }
48 
49     auto host = GetHost();
50     CHECK_NULL_VOID(host);
51     auto manager = pipeline->GetSafeAreaManager();
52     CHECK_NULL_VOID(manager);
53     manager->SetIsAtomicService(true);
54     manager->AddGeoRestoreNode(host);
55     auto systemSafeArea = manager->GetSystemSafeArea();
56     float topMargin = theme->GetMenuBarTopMargin().ConvertToPx();
57     topMargin += systemSafeArea.top_.Length();
58     UpdateOverlayLayout();
59     auto menuBarRow = GetMenuBarRow();
60     CHECK_NULL_VOID(menuBarRow);
61     auto renderContext = menuBarRow->GetRenderContext();
62     renderContext->UpdatePosition(OffsetT<Dimension>(0.0_vp, Dimension(topMargin, DimensionUnit::PX)));
63     if (settedColorMode.has_value()) {
64         UpdateMenuBarColor(theme, menuBar, settedColorMode.value());
65     } else {
66         UpdateMenuBarColor(theme, menuBar, SystemProperties::GetColorMode() != ColorMode::DARK);
67     }
68     UpdateLayoutMargin();
69 }
70 
UpdateLayoutMargin()71 void AtomicServicePattern::UpdateLayoutMargin()
72 {
73     auto pipeline = PipelineContext::GetCurrentContext();
74     CHECK_NULL_VOID(pipeline);
75     auto safeArea = pipeline->GetSafeArea();
76     auto manager = pipeline->GetSafeAreaManager();
77     CHECK_NULL_VOID(manager);
78     if (manager->KeyboardSafeAreaEnabled()) {
79         safeArea.bottom_ = safeArea.bottom_.Combine(manager->GetKeyboardInset());
80     }
81     auto atom = GetHost();
82     CHECK_NULL_VOID(atom);
83     MarginProperty margin;
84     margin.left = CalcLength(safeArea.left_.Length());
85     margin.right = CalcLength(safeArea.right_.Length());
86     margin.top = CalcLength(safeArea.top_.Length());
87     margin.bottom = CalcLength(safeArea.bottom_.Length());
88     // update stage margin
89     auto stage = AceType::DynamicCast<FrameNode>(atom->GetChildAtIndex(0));
90     CHECK_NULL_VOID(stage);
91     auto layoutProperty = stage->GetLayoutProperty();
92     CHECK_NULL_VOID(layoutProperty);
93     layoutProperty->UpdateMargin(margin);
94     stage->MarkModifyDone();
95     stage->MarkDirtyNode();
96 }
97 
UpdateOverlayLayout()98 void AtomicServicePattern::UpdateOverlayLayout()
99 {
100     auto atom = GetHost();
101     CHECK_NULL_VOID(atom);
102     if (atom->GetChildren().size() <= ATOMIC_SERVICE_MIN_SIZE) {
103         return;
104     }
105     for (int index = FIRST_OVERLAY_INDEX;
106         index <= static_cast<int32_t>(atom->GetChildren().size()) - ATOMIC_SERVICE_MIN_SIZE; index++) {
107         auto overlay = AceType::DynamicCast<FrameNode>(atom->GetChildAtIndex(index));
108         CHECK_NULL_VOID(overlay);
109         auto overlayRender = overlay->GetRenderContext();
110         overlayRender->UpdatePosition(OffsetT<Dimension>());
111         overlay->MarkModifyDone();
112         overlay->MarkDirtyNode();
113     }
114 }
115 
OnAttachToFrameNode()116 void AtomicServicePattern::OnAttachToFrameNode()
117 {
118     auto host = GetHost();
119     CHECK_NULL_VOID(host);
120     host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
121     auto pipeline = PipelineContext::GetCurrentContext();
122     CHECK_NULL_VOID(pipeline);
123     host->GetRenderContext()->UpdateBackgroundColor(pipeline->GetAppBgColor());
124 }
125 
OnLanguageConfigurationUpdate()126 void AtomicServicePattern::OnLanguageConfigurationUpdate()
127 {
128     UpdateLayout();
129 }
130 
OnColorConfigurationUpdate()131 void AtomicServicePattern::OnColorConfigurationUpdate()
132 {
133     auto host = GetHost();
134     CHECK_NULL_VOID(host);
135     auto pipeline = PipelineContext::GetCurrentContext();
136     CHECK_NULL_VOID(pipeline);
137     host->GetRenderContext()->UpdateBackgroundColor(pipeline->GetAppBgColor());
138     if (settedColorMode.has_value()) {
139         UpdateColor(settedColorMode);
140     } else {
141         UpdateColor(SystemProperties::GetColorMode() != ColorMode::DARK);
142     }
143 }
144 
GetMenuBarRow()145 RefPtr<FrameNode> AtomicServicePattern::GetMenuBarRow()
146 {
147     auto atom = GetHost();
148     CHECK_NULL_RETURN(atom, nullptr);
149     auto menuBarRow = AceType::DynamicCast<FrameNode>(atom->GetChildren().back());
150     return menuBarRow;
151 }
152 
GetMenuBar()153 RefPtr<FrameNode> AtomicServicePattern::GetMenuBar()
154 {
155     auto menuBarRow = GetMenuBarRow();
156     CHECK_NULL_RETURN(menuBarRow, nullptr);
157     auto menuBar = AceType::DynamicCast<FrameNode>(menuBarRow->GetChildAtIndex(0));
158     return menuBar;
159 }
160 
GetMenuButton()161 RefPtr<FrameNode> AtomicServicePattern::GetMenuButton()
162 {
163     auto menuBar = GetMenuBar();
164     CHECK_NULL_RETURN(menuBar, nullptr);
165     auto menuButton = AceType::DynamicCast<FrameNode>(menuBar->GetChildAtIndex(0));
166     return menuButton;
167 }
168 
GetDivider()169 RefPtr<FrameNode> AtomicServicePattern::GetDivider()
170 {
171     auto menuBar = GetMenuBar();
172     CHECK_NULL_RETURN(menuBar, nullptr);
173     auto divider = AceType::DynamicCast<FrameNode>(menuBar->GetChildAtIndex(1));
174     return divider;
175 }
176 
GetCloseButton()177 RefPtr<FrameNode> AtomicServicePattern::GetCloseButton()
178 {
179     auto menuBar = GetMenuBar();
180     CHECK_NULL_RETURN(menuBar, nullptr);
181     auto closeButton = AceType::DynamicCast<FrameNode>(menuBar->GetChildAtIndex(2));
182     return closeButton;
183 }
184 
GetMenuIcon()185 RefPtr<FrameNode> AtomicServicePattern::GetMenuIcon()
186 {
187     auto menuButton = GetMenuButton();
188     CHECK_NULL_RETURN(menuButton, nullptr);
189     auto menuIcon = AceType::DynamicCast<FrameNode>(menuButton->GetChildAtIndex(0));
190     return menuIcon;
191 }
192 
GetCloseIcon()193 RefPtr<FrameNode> AtomicServicePattern::GetCloseIcon()
194 {
195     auto closeButton = GetCloseButton();
196     CHECK_NULL_RETURN(closeButton, nullptr);
197     auto closeIcon = AceType::DynamicCast<FrameNode>(closeButton->GetChildAtIndex(0));
198     return closeIcon;
199 }
200 
UpdateColor(std::optional<bool> isLight)201 void AtomicServicePattern::UpdateColor(std::optional<bool> isLight)
202 {
203     auto pipeline = PipelineContext::GetCurrentContext();
204     CHECK_NULL_VOID(pipeline);
205     auto theme = pipeline->GetTheme<AppBarTheme>();
206     if (!(isLight.has_value())) {
207         isLight = SystemProperties::GetColorMode() != ColorMode::DARK;
208     }
209     auto menuButton = GetMenuButton();
210     UpdateButtonColor(theme, menuButton, isLight.value());
211     auto divider = GetDivider();
212     UpdateDividerColor(theme, divider, isLight.value());
213     auto closeButton = GetCloseButton();
214     UpdateButtonColor(theme, closeButton, isLight.value());
215 
216     auto menuIcon = GetMenuIcon();
217     UpdateIconColor(theme, menuIcon, isLight.value());
218     auto closeIcon = GetCloseIcon();
219     UpdateIconColor(theme, closeIcon, isLight.value());
220 }
221 
UpdateMenuBarColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & menuBar,bool isLight)222 void AtomicServicePattern::UpdateMenuBarColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& menuBar, bool isLight)
223 {
224     CHECK_NULL_VOID(theme);
225     CHECK_NULL_VOID(menuBar);
226     auto renderContext = menuBar->GetRenderContext();
227     // background effect、border color
228     EffectOption option;
229     BorderColorProperty borderColor;
230     option.radius = theme->GetBlurRadius();
231     if (isLight) {
232         option.color = theme->GetBlurColorLight();
233         borderColor.SetColor(theme->GetBorderColorLight());
234     } else {
235         option.color = theme->GetBlurColorDark();
236         borderColor.SetColor(theme->GetBorderColorDark());
237     }
238     renderContext->UpdateBackgroundEffect(option);
239     renderContext->UpdateBorderColor(borderColor);
240 
241     menuBar->MarkModifyDone();
242     menuBar->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
243 }
244 
UpdateButtonColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & button,bool isLight)245 void AtomicServicePattern::UpdateButtonColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& button, bool isLight)
246 {
247     CHECK_NULL_VOID(theme);
248     CHECK_NULL_VOID(button);
249     // pressed color
250     auto buttonPattern = button->GetPattern<ButtonPattern>();
251     CHECK_NULL_VOID(buttonPattern);
252     if (isLight) {
253         buttonPattern->SetClickedColor(theme->GetClickEffectColorLight());
254     } else {
255         buttonPattern->SetClickedColor(theme->GetClickEffectColorDark());
256     }
257     // focus border color
258     if (isLight) {
259         buttonPattern->SetFocusBorderColor(theme->GetFocusedOutlineColorLight());
260     } else {
261         buttonPattern->SetFocusBorderColor(theme->GetFocusedOutlineColorDark());
262     }
263 
264     button->MarkModifyDone();
265     button->MarkDirtyNode();
266 }
267 
UpdateDividerColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & divider,bool isLight)268 void AtomicServicePattern::UpdateDividerColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& divider, bool isLight)
269 {
270     CHECK_NULL_VOID(theme);
271     CHECK_NULL_VOID(divider);
272 
273     auto renderProperty = divider->GetPaintProperty<DividerRenderProperty>();
274     if (isLight) {
275         renderProperty->UpdateDividerColor(theme->GetDividerColorLight());
276     } else {
277         renderProperty->UpdateDividerColor(theme->GetDividerColorDark());
278     }
279 
280     divider->MarkModifyDone();
281     divider->MarkDirtyNode();
282 }
283 
UpdateIconColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & icon,bool isLight)284 void AtomicServicePattern::UpdateIconColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& icon, bool isLight)
285 {
286     CHECK_NULL_VOID(theme);
287     CHECK_NULL_VOID(icon);
288     // fill color
289     auto color = isLight ? theme->GetIconColorLight() : theme->GetIconColorDark();
290     ACE_UPDATE_NODE_PAINT_PROPERTY(ImageRenderProperty, SvgFillColor, color, icon);
291     ACE_UPDATE_NODE_RENDER_CONTEXT(ForegroundColor, color, icon);
292     icon->MarkModifyDone();
293     icon->MarkDirtyNode();
294 }
295 
UpdateLayout()296 void AtomicServicePattern::UpdateLayout()
297 {
298     auto pipeline = PipelineContext::GetCurrentContext();
299     CHECK_NULL_VOID(pipeline);
300     auto theme = pipeline->GetTheme<AppBarTheme>();
301     CHECK_NULL_VOID(theme);
302     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
303 
304     auto menuBar = GetMenuBar();
305     UpdateMenuBarLayout(theme, menuBar, isRtl);
306 
307     auto menuButton = GetMenuButton();
308     UpdateButtonLayout(theme, menuButton, !isRtl);
309     auto closeButton = GetCloseButton();
310     UpdateButtonLayout(theme, closeButton, isRtl);
311 
312     auto menuIcon = GetMenuIcon();
313     UpdateIconLayout(theme, menuIcon, !isRtl);
314     auto closeIcon = GetCloseIcon();
315     UpdateIconLayout(theme, closeIcon, isRtl);
316 }
317 
UpdateMenuBarLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & menuBar,bool isRtl)318 void AtomicServicePattern::UpdateMenuBarLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& menuBar, bool isRtl)
319 {
320     CHECK_NULL_VOID(theme);
321     CHECK_NULL_VOID(menuBar);
322 
323     MarginProperty margin;
324     auto pipeline = PipelineContext::GetCurrentContext();
325     CHECK_NULL_VOID(pipeline);
326     auto safeArea = pipeline->GetSafeArea();
327 
328     Dimension safeAreaLeft(pipeline->Px2VpWithCurrentDensity(safeArea.left_.Length()), DimensionUnit::VP);
329     Dimension safeAreaRight(pipeline->Px2VpWithCurrentDensity(safeArea.right_.Length()), DimensionUnit::VP);
330 
331     if (isRtl) {
332         margin.left = CalcLength(theme->GetMenuBarRightMargin() + safeAreaLeft);
333         margin.right = CalcLength(theme->GetMenuBarLeftMargin() + safeAreaRight);
334     } else {
335         margin.left = CalcLength(theme->GetMenuBarLeftMargin() + safeAreaLeft);
336         margin.right = CalcLength(theme->GetMenuBarRightMargin() + safeAreaRight);
337     }
338     menuBar->GetLayoutProperty<LinearLayoutProperty>()->UpdateMargin(margin);
339 
340     menuBar->MarkModifyDone();
341     menuBar->MarkDirtyNode();
342 }
343 
UpdateButtonLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & button,bool isLeft)344 void AtomicServicePattern::UpdateButtonLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& button, bool isLeft)
345 {
346     CHECK_NULL_VOID(theme);
347     CHECK_NULL_VOID(button);
348 
349     auto bent = theme->GetBentRadius();
350     auto rightAngle = theme->GetRightAngle();
351     auto leftBorderRadius = BorderRadiusProperty(bent, rightAngle, rightAngle, bent);
352     auto rightBorderRadius = BorderRadiusProperty(rightAngle, bent, bent, rightAngle);
353 
354     auto layoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
355     layoutProperty->UpdateBorderRadius(isLeft ? leftBorderRadius : rightBorderRadius);
356 
357     button->MarkModifyDone();
358     button->MarkDirtyNode();
359 }
360 
UpdateIconLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & icon,bool isLeft)361 void AtomicServicePattern::UpdateIconLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& icon, bool isLeft)
362 {
363     CHECK_NULL_VOID(theme);
364     CHECK_NULL_VOID(icon);
365 
366     MarginProperty margin;
367     margin.top = CalcLength(theme->GetIconVerticalMargin());
368     margin.bottom = CalcLength(theme->GetIconVerticalMargin());
369     if (isLeft) {
370         margin.left = CalcLength(theme->GetIconOutsideMargin());
371         margin.right = CalcLength(theme->GetIconInsideMargin());
372     } else {
373         margin.left = CalcLength(theme->GetIconInsideMargin());
374         margin.right = CalcLength(theme->GetIconOutsideMargin());
375     }
376     icon->GetLayoutProperty<ImageLayoutProperty>()->UpdateMargin(margin);
377 
378     icon->MarkModifyDone();
379     icon->MarkDirtyNode();
380 }
381 } // namespace OHOS::Ace::NG
382