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/container_modal/container_modal_component.h"
17
18 #include "base/utils/system_properties.h"
19 #include "core/components/box/box_component.h"
20 #include "core/components/button/button_component.h"
21 #include "core/components/clip/clip_component.h"
22 #include "core/components/container_modal/container_modal_constants.h"
23 #include "core/components/container_modal/container_modal_element.h"
24 #include "core/components/container_modal/render_container_modal.h"
25 #include "core/components/image/image_component.h"
26 #include "core/components/padding/padding_component.h"
27 #include "core/components/text/text_component.h"
28 #include "core/components/tween/tween_component.h"
29 #include "core/components_v2/inspector/inspector_composed_component.h"
30 #include "core/components_v2/inspector/inspector_constants.h"
31 #include "core/gestures/pan_gesture.h"
32
33 namespace OHOS::Ace {
34 namespace {
35 constexpr int32_t ROOT_DECOR_BASE = 3100000;
36 constexpr int32_t TITLE_ROW = ROOT_DECOR_BASE;
37 constexpr int32_t FLOATING_TITLE_ROW = ROOT_DECOR_BASE + 1;
38 constexpr int32_t TITLE_LABEL = ROOT_DECOR_BASE + 2;
39 constexpr int32_t FLOATING_TITLE_LABEL = ROOT_DECOR_BASE + 3;
40 constexpr int32_t WINDOW_SPLIT_BUTTON = ROOT_DECOR_BASE + 4;
41 constexpr int32_t WINDOW_MAX_RECOVER_BUTTON = ROOT_DECOR_BASE + 6;
42 constexpr int32_t WINDOW_MINIMIZE_BUTTON = ROOT_DECOR_BASE + 8;
43 constexpr int32_t WINDOW_CLOSE_BUTTON = ROOT_DECOR_BASE + 10;
44 constexpr int32_t WINDOW_BUTTON_INVALID = ROOT_DECOR_BASE + 12;
45
46 const std::string SPLIT_LEFT_KEY = "container_modal_split_left_button";
47 const std::string MAXIMIZE_KEY = "container_modal_maximize_button";
48 const std::string MINIMIZE_KEY = "container_modal_minimize_button";
49 const std::string CLOSE_KEY = "container_modal_close_button";
50 } // namespace
51
Create(const WeakPtr<PipelineContext> & context,const RefPtr<Component> & child)52 RefPtr<Component> ContainerModalComponent::Create(
53 const WeakPtr<PipelineContext>& context, const RefPtr<Component>& child)
54 {
55 auto component = AceType::MakeRefPtr<ContainerModalComponent>(context);
56 component->SetChild(child);
57 component->BuildInnerChild();
58 return component;
59 }
60
CreateElement()61 RefPtr<Element> ContainerModalComponent::CreateElement()
62 {
63 return AceType::MakeRefPtr<ContainerModalElement>();
64 }
65
CreateRenderNode()66 RefPtr<RenderNode> ContainerModalComponent::CreateRenderNode()
67 {
68 return RenderContainerModal::Create();
69 }
70
BuildTitle()71 RefPtr<Component> ContainerModalComponent::BuildTitle()
72 {
73 // build title box
74 auto titleBox = AceType::MakeRefPtr<BoxComponent>();
75 titleBox->SetHeight(CONTAINER_TITLE_HEIGHT);
76
77 // BuildTitleChildren need this
78 CreateAccessibilityNode(DOM_FLEX_ROW, TITLE_ROW, -1);
79
80 auto titleChildrenRow =
81 AceType::MakeRefPtr<RowComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, BuildTitleChildren(false));
82
83 // handle touch move and mouse move
84 PanDirection panDirection;
85 panDirection.type = PanDirection::ALL;
86 auto panGesture =
87 AceType::MakeRefPtr<PanGesture>(DEFAULT_PAN_FINGER, panDirection, DEFAULT_PAN_DISTANCE.ConvertToPx());
88 panGesture->SetOnActionStartId([contextWptr = context_](const GestureEvent&) {
89 auto context = contextWptr.Upgrade();
90 if (context) {
91 LOGI("container window start move.");
92 context->GetWindowManager()->WindowStartMove();
93 }
94 });
95 titleBox->AddGesture(GesturePriority::Low, panGesture);
96 titleBox->SetChild(titleChildrenRow);
97
98 if (isDeclarative_) {
99 return AceType::MakeRefPtr<DisplayComponent>(AceType::MakeRefPtr<V2::InspectorComposedComponent>(
100 V2::InspectorComposedComponent::GenerateId(), V2::ROW_COMPONENT_TAG, titleBox));
101 } else {
102 return AceType::MakeRefPtr<DisplayComponent>(
103 AceType::MakeRefPtr<ComposedComponent>(std::to_string(TITLE_ROW), DOM_FLEX_ROW, titleBox));
104 }
105 }
106
BuildFloatingTitle()107 RefPtr<Component> ContainerModalComponent::BuildFloatingTitle()
108 {
109 // build floating title box
110 auto titleDecoration = AceType::MakeRefPtr<Decoration>();
111 titleDecoration->SetBackgroundColor(CONTAINER_BACKGROUND_COLOR);
112
113 auto titleBox = AceType::MakeRefPtr<BoxComponent>();
114 titleBox->SetHeight(CONTAINER_TITLE_HEIGHT);
115 titleBox->SetBackDecoration(titleDecoration);
116
117 CreateAccessibilityNode(DOM_FLEX_ROW, FLOATING_TITLE_ROW, -1);
118
119 auto floatingTitleChildrenRow =
120 AceType::MakeRefPtr<RowComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, BuildTitleChildren(true));
121 titleBox->SetChild(floatingTitleChildrenRow);
122 if (isDeclarative_) {
123 return AceType::MakeRefPtr<TweenComponent>(
124 "ContainerModal", AceType::MakeRefPtr<V2::InspectorComposedComponent>(
125 V2::InspectorComposedComponent::GenerateId(), V2::ROW_COMPONENT_TAG, titleBox));
126 } else {
127 return AceType::MakeRefPtr<TweenComponent>("ContainerModal",
128 AceType::MakeRefPtr<ComposedComponent>(std::to_string(FLOATING_TITLE_ROW), DOM_FLEX_ROW, titleBox));
129 }
130 }
131
BuildContent()132 RefPtr<Component> ContainerModalComponent::BuildContent()
133 {
134 auto contentBox = AceType::MakeRefPtr<BoxComponent>();
135 contentBox->SetChild(GetChild());
136 auto contentDecoration = AceType::MakeRefPtr<Decoration>();
137 auto context = context_.Upgrade();
138 if (context) {
139 contentDecoration->SetBackgroundColor(context->GetAppBgColor());
140 }
141 contentBox->SetBackDecoration(contentDecoration);
142
143 auto clip = AceType::MakeRefPtr<ClipComponent>(contentBox);
144 clip->SetClipRadius(Radius(CONTAINER_INNER_RADIUS));
145 clip->SetFlexWeight(1.0);
146 return clip;
147 }
148
BuildControlButton(InternalResource::ResourceId icon,std::function<void ()> && clickCallback,bool isFocus,bool isFloating)149 RefPtr<Component> ContainerModalComponent::BuildControlButton(
150 InternalResource::ResourceId icon, std::function<void()>&& clickCallback, bool isFocus, bool isFloating)
151 {
152 static std::unordered_map<InternalResource::ResourceId, std::pair<int32_t, std::string>> controlButtonIdMap = {
153 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_SPLIT_LEFT, { WINDOW_SPLIT_BUTTON, SPLIT_LEFT_KEY } },
154 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_SPLIT_LEFT,
155 { WINDOW_SPLIT_BUTTON, SPLIT_LEFT_KEY } },
156 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_RECOVER, { WINDOW_MAX_RECOVER_BUTTON, MAXIMIZE_KEY } },
157 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MAXIMIZE, { WINDOW_MAX_RECOVER_BUTTON, MAXIMIZE_KEY } },
158 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_RECOVER,
159 { WINDOW_MAX_RECOVER_BUTTON, MAXIMIZE_KEY } },
160 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_MAXIMIZE,
161 { WINDOW_MAX_RECOVER_BUTTON, MAXIMIZE_KEY } },
162 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MINIMIZE, { WINDOW_MINIMIZE_BUTTON, MINIMIZE_KEY } },
163 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_MINIMIZE,
164 { WINDOW_MINIMIZE_BUTTON, MINIMIZE_KEY } },
165 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_CLOSE, { WINDOW_CLOSE_BUTTON, CLOSE_KEY } },
166 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_CLOSE, { WINDOW_CLOSE_BUTTON, CLOSE_KEY } },
167 };
168
169 auto image = AceType::MakeRefPtr<ImageComponent>(icon);
170 image->SetWidth(TITLE_ICON_SIZE);
171 image->SetHeight(TITLE_ICON_SIZE);
172 image->SetFocusable(false);
173 std::list<RefPtr<Component>> btnChildren;
174 btnChildren.emplace_back(image);
175
176 auto button = AceType::MakeRefPtr<ButtonComponent>(btnChildren);
177 button->SetWidth(TITLE_BUTTON_SIZE);
178 button->SetHeight(TITLE_BUTTON_SIZE);
179 button->SetType(ButtonType::CIRCLE);
180 button->SetBackgroundColor(isFocus ? TITLE_BUTTON_BACKGROUND_COLOR : TITLE_BUTTON_BACKGROUND_COLOR_LOST_FOCUS);
181 button->SetClickedColor(TITLE_BUTTON_CLICKED_COLOR);
182 button->SetClickFunction(std::move(clickCallback));
183 button->SetFocusable(false);
184 std::string buttonKey = "";
185 auto iter = controlButtonIdMap.find(icon);
186 if (iter != controlButtonIdMap.end()) {
187 buttonKey = (iter->second).second;
188 }
189 button->SetInspectorKey(buttonKey.c_str());
190 if (!isDeclarative_) {
191 auto buttonId = WINDOW_BUTTON_INVALID;
192 auto iter = controlButtonIdMap.find(icon);
193 if (iter != controlButtonIdMap.end()) {
194 buttonId = isFloating ? (iter->second).first + 1 : (iter->second).first;
195 }
196 CreateAccessibilityNode(DOM_NODE_TAG_BUTTON, buttonId, isFloating ? FLOATING_TITLE_ROW : TITLE_ROW);
197 return AceType::MakeRefPtr<ComposedComponent>(std::to_string(buttonId), DOM_NODE_TAG_BUTTON, button);
198 } else {
199 return AceType::MakeRefPtr<V2::InspectorComposedComponent>(
200 V2::InspectorComposedComponent::GenerateId(), V2::BUTTON_COMPONENT_TAG, button);
201 }
202 }
203
SetPadding(const RefPtr<Component> & component,const Dimension & leftPadding,const Dimension & rightPadding)204 RefPtr<Component> ContainerModalComponent::SetPadding(
205 const RefPtr<Component>& component, const Dimension& leftPadding, const Dimension& rightPadding)
206 {
207 auto paddingComponent = AceType::MakeRefPtr<PaddingComponent>();
208 paddingComponent->SetPaddingLeft(leftPadding);
209 paddingComponent->SetPaddingRight(rightPadding);
210 paddingComponent->SetPaddingTop((CONTAINER_TITLE_HEIGHT - TITLE_BUTTON_SIZE) / 2);
211 paddingComponent->SetPaddingBottom((CONTAINER_TITLE_HEIGHT - TITLE_BUTTON_SIZE) / 2);
212 paddingComponent->SetChild(component);
213 return paddingComponent;
214 }
215
216 // Build ContainerModal FA structure
BuildInnerChild()217 void ContainerModalComponent::BuildInnerChild()
218 {
219 Border outerBorder;
220 outerBorder.SetBorderRadius(Radius(CONTAINER_OUTER_RADIUS));
221 outerBorder.SetColor(CONTAINER_BORDER_COLOR);
222 outerBorder.SetWidth(CONTAINER_BORDER_WIDTH);
223 auto containerDecoration = AceType::MakeRefPtr<Decoration>();
224 containerDecoration->SetBackgroundColor(CONTAINER_BACKGROUND_COLOR);
225 containerDecoration->SetBorder(outerBorder);
226
227 auto column =
228 AceType::MakeRefPtr<ColumnComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, std::list<RefPtr<Component>>());
229 column->AppendChild(BuildTitle());
230 column->AppendChild(BuildContent());
231 std::list<RefPtr<Component>> stackChildren;
232 stackChildren.emplace_back(column);
233 stackChildren.emplace_back(BuildFloatingTitle());
234 auto stackComponent = AceType::MakeRefPtr<StackComponent>(
235 Alignment::TOP_LEFT, StackFit::INHERIT, Overflow::OBSERVABLE, stackChildren);
236
237 auto containerBox = AceType::MakeRefPtr<BoxComponent>();
238 containerBox->SetBackDecoration(containerDecoration);
239 containerBox->SetFlex(BoxFlex::FLEX_X);
240 containerBox->SetAlignment(Alignment::CENTER);
241
242 Edge padding = Edge(CONTENT_PADDING, Dimension(0.0), CONTENT_PADDING, CONTENT_PADDING);
243 containerBox->SetPadding(padding);
244 containerBox->SetChild(stackComponent);
245 SetChild(containerBox);
246 }
247
BuildTitleChildren(bool isFloating,bool isFocus,bool isFullWindow)248 std::list<RefPtr<Component>> ContainerModalComponent::BuildTitleChildren(bool isFloating, bool isFocus,
249 bool isFullWindow)
250 {
251 // title icon
252 if (!titleIcon_) {
253 titleIcon_ = AceType::MakeRefPtr<ImageComponent>();
254 titleIcon_->SetWidth(TITLE_ICON_SIZE);
255 titleIcon_->SetHeight(TITLE_ICON_SIZE);
256 titleIcon_->SetFocusable(false);
257 }
258
259 // title text
260 if (!titleLabel_) {
261 titleLabel_ = AceType::MakeRefPtr<TextComponent>("");
262 }
263 TextStyle style;
264 style.SetFontSize(TITLE_TEXT_FONT_SIZE);
265 style.SetMaxLines(1);
266 style.SetTextColor(isFocus ? TITLE_TEXT_COLOR : TITLE_TEXT_COLOR_LOST_FOCUS);
267 style.SetFontWeight(FontWeight::W500);
268 style.SetAllowScale(false);
269 style.SetTextOverflow(TextOverflow::ELLIPSIS);
270 titleLabel_->SetTextStyle(style);
271 titleLabel_->SetFlexWeight(1.0);
272
273 CreateAccessibilityNode(DOM_NODE_TAG_TEXT, isFloating ? FLOATING_TITLE_LABEL : TITLE_LABEL,
274 isFloating ? FLOATING_TITLE_ROW : TITLE_ROW);
275
276 // title control button
277 auto windowManager = context_.Upgrade()->GetWindowManager();
278 auto leftSplitButton = isFocus ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_SPLIT_LEFT
279 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_SPLIT_LEFT;
280 auto titleLeftSplitButton = BuildControlButton(leftSplitButton, [windowManager]() {
281 if (windowManager) {
282 LOGI("left split button clicked");
283 windowManager->FireWindowSplitCallBack();
284 }
285 }, isFocus, isFloating);
286 auto maxRecoverButton = isFloating && isFullWindow ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_RECOVER
287 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MAXIMIZE;
288 if (!isFocus) {
289 maxRecoverButton = isFloating && isFullWindow ?
290 InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_RECOVER :
291 InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_MAXIMIZE;
292 }
293 auto titleMaximizeRecoverButton = BuildControlButton(maxRecoverButton, [windowManager]() {
294 if (windowManager) {
295 auto mode = windowManager->GetWindowMode();
296 if (mode == WindowMode::WINDOW_MODE_FULLSCREEN) {
297 LOGI("recover button clicked");
298 windowManager->WindowRecover();
299 } else {
300 LOGI("maximize button clicked");
301 windowManager->WindowMaximize();
302 }
303 }
304 }, isFocus, isFloating);
305 auto minimizeButton = isFocus ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MINIMIZE
306 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_MINIMIZE;
307 auto titleMinimizeButton = BuildControlButton(minimizeButton, [windowManager]() {
308 if (windowManager) {
309 LOGI("minimize button clicked");
310 windowManager->WindowMinimize();
311 }
312 }, isFocus, isFloating);
313 auto closeButton = isFocus ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_CLOSE
314 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_CLOSE;
315 auto titleCloseButton = BuildControlButton(closeButton, [windowManager]() {
316 if (windowManager) {
317 LOGI("close button clicked");
318 windowManager->WindowClose();
319 }
320 }, isFocus, isFloating);
321 std::list<RefPtr<Component>> titleChildren;
322 titleChildren.emplace_back(SetPadding(titleIcon_, TITLE_PADDING_START, TITLE_ELEMENT_MARGIN_HORIZONTAL));
323 if (isDeclarative_) {
324 auto inspectorTitle = AceType::MakeRefPtr<V2::InspectorComposedComponent>(
325 V2::InspectorComposedComponent::GenerateId(), V2::TEXT_COMPONENT_TAG, titleLabel_);
326 inspectorTitle->MarkNeedUpdate();
327 titleChildren.emplace_back(inspectorTitle);
328 } else {
329 titleChildren.emplace_back(AceType::MakeRefPtr<ComposedComponent>(
330 isFloating ? std::to_string(FLOATING_TITLE_LABEL) : std::to_string(TITLE_LABEL), DOM_NODE_TAG_TEXT,
331 titleLabel_));
332 }
333 auto rightPadding = SystemProperties::GetDeviceAccess() ? TITLE_ELEMENT_MARGIN_HORIZONTAL_ACCESS_DEVICE
334 : TITLE_ELEMENT_MARGIN_HORIZONTAL;
335 if (!hideSplit_) {
336 titleChildren.emplace_back(SetPadding(titleLeftSplitButton, ZERO_PADDING, rightPadding));
337 }
338 if (!hideMaximize_) {
339 titleChildren.emplace_back(
340 SetPadding(titleMaximizeRecoverButton, ZERO_PADDING, rightPadding));
341 }
342 if (!hideMinimize_) {
343 titleChildren.emplace_back(SetPadding(titleMinimizeButton, ZERO_PADDING, rightPadding));
344 }
345 titleChildren.emplace_back(SetPadding(titleCloseButton, ZERO_PADDING, TITLE_PADDING_END));
346 return titleChildren;
347 }
348
CreateAccessibilityNode(const std::string & tag,int32_t nodeId,int32_t parentNodeId)349 void ContainerModalComponent::CreateAccessibilityNode(const std::string& tag, int32_t nodeId, int32_t parentNodeId)
350 {
351 auto context = context_.Upgrade();
352 if (context != nullptr && !isDeclarative_) {
353 auto accessibilityManager = context->GetAccessibilityManager();
354 if (accessibilityManager) {
355 accessibilityManager->CreateAccessibilityNode(tag, nodeId, parentNodeId, -1);
356 }
357 }
358 }
359
360 } // namespace OHOS::Ace