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