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