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->SetFlexWeight(1.0);
139 return clip;
140 }
141
BuildControlButton(InternalResource::ResourceId icon,std::function<void ()> && clickCallback,bool isFocus,bool isFloating)142 RefPtr<Component> ContainerModalComponent::BuildControlButton(
143 InternalResource::ResourceId icon, std::function<void()>&& clickCallback, bool isFocus, bool isFloating)
144 {
145 static std::unordered_map<InternalResource::ResourceId, std::pair<int32_t, std::string>> controlButtonIdMap = {
146 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_SPLIT_LEFT, { WINDOW_SPLIT_BUTTON, SPLIT_LEFT_KEY } },
147 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_SPLIT_LEFT,
148 { WINDOW_SPLIT_BUTTON, SPLIT_LEFT_KEY } },
149 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_RECOVER, { WINDOW_MAX_RECOVER_BUTTON, MAXIMIZE_KEY } },
150 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MAXIMIZE, { WINDOW_MAX_RECOVER_BUTTON, MAXIMIZE_KEY } },
151 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_RECOVER,
152 { WINDOW_MAX_RECOVER_BUTTON, MAXIMIZE_KEY } },
153 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_MAXIMIZE,
154 { WINDOW_MAX_RECOVER_BUTTON, MAXIMIZE_KEY } },
155 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MINIMIZE, { WINDOW_MINIMIZE_BUTTON, MINIMIZE_KEY } },
156 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_MINIMIZE,
157 { WINDOW_MINIMIZE_BUTTON, MINIMIZE_KEY } },
158 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_CLOSE, { WINDOW_CLOSE_BUTTON, CLOSE_KEY } },
159 { InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_CLOSE, { WINDOW_CLOSE_BUTTON, CLOSE_KEY } },
160 };
161
162 auto image = AceType::MakeRefPtr<ImageComponent>(icon);
163 image->SetWidth(TITLE_ICON_SIZE);
164 image->SetHeight(TITLE_ICON_SIZE);
165 image->SetFocusable(false);
166 std::list<RefPtr<Component>> btnChildren;
167 btnChildren.emplace_back(image);
168
169 auto button = AceType::MakeRefPtr<ButtonComponent>(btnChildren);
170 button->SetWidth(TITLE_BUTTON_SIZE);
171 button->SetHeight(TITLE_BUTTON_SIZE);
172 button->SetType(ButtonType::CIRCLE);
173 button->SetBackgroundColor(isFocus ? TITLE_BUTTON_BACKGROUND_COLOR : TITLE_BUTTON_BACKGROUND_COLOR_LOST_FOCUS);
174 button->SetClickedColor(TITLE_BUTTON_CLICKED_COLOR);
175 button->SetClickFunction(std::move(clickCallback));
176 button->SetFocusable(false);
177 std::string buttonKey = "";
178 auto iter = controlButtonIdMap.find(icon);
179 if (iter != controlButtonIdMap.end()) {
180 buttonKey = (iter->second).second;
181 }
182 button->SetInspectorKey(buttonKey.c_str());
183 if (!isDeclarative_) {
184 auto buttonId = WINDOW_BUTTON_INVALID;
185 auto iter = controlButtonIdMap.find(icon);
186 if (iter != controlButtonIdMap.end()) {
187 buttonId = isFloating ? (iter->second).first + 1 : (iter->second).first;
188 }
189 CreateAccessibilityNode(DOM_NODE_TAG_BUTTON, buttonId, isFloating ? FLOATING_TITLE_ROW : TITLE_ROW);
190 return AceType::MakeRefPtr<ComposedComponent>(std::to_string(buttonId), DOM_NODE_TAG_BUTTON, button);
191 } else {
192 return AceType::MakeRefPtr<V2::InspectorComposedComponent>(
193 V2::InspectorComposedComponent::GenerateId(), V2::BUTTON_COMPONENT_TAG, button);
194 }
195 }
196
SetPadding(const RefPtr<Component> & component,const Dimension & leftPadding,const Dimension & rightPadding)197 RefPtr<Component> ContainerModalComponent::SetPadding(
198 const RefPtr<Component>& component, const Dimension& leftPadding, const Dimension& rightPadding)
199 {
200 auto paddingComponent = AceType::MakeRefPtr<PaddingComponent>();
201 paddingComponent->SetPaddingLeft(leftPadding);
202 paddingComponent->SetPaddingRight(rightPadding);
203 paddingComponent->SetPaddingTop((CONTAINER_TITLE_HEIGHT - TITLE_BUTTON_SIZE) / 2);
204 paddingComponent->SetPaddingBottom((CONTAINER_TITLE_HEIGHT - TITLE_BUTTON_SIZE) / 2);
205 paddingComponent->SetChild(component);
206 return paddingComponent;
207 }
208
209 // Build ContainerModal FA structure
BuildInnerChild()210 void ContainerModalComponent::BuildInnerChild()
211 {
212 Border outerBorder;
213 outerBorder.SetBorderRadius(Radius(CONTAINER_OUTER_RADIUS));
214 outerBorder.SetColor(CONTAINER_BORDER_COLOR);
215 auto containerDecoration = AceType::MakeRefPtr<Decoration>();
216 containerDecoration->SetBackgroundColor(CONTAINER_BACKGROUND_COLOR);
217 containerDecoration->SetBorder(outerBorder);
218
219 auto column =
220 AceType::MakeRefPtr<ColumnComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, std::list<RefPtr<Component>>());
221 column->AppendChild(BuildTitle());
222 column->AppendChild(BuildContent());
223 std::list<RefPtr<Component>> stackChildren;
224 stackChildren.emplace_back(column);
225 stackChildren.emplace_back(BuildFloatingTitle());
226 auto stackComponent = AceType::MakeRefPtr<StackComponent>(
227 Alignment::TOP_LEFT, StackFit::INHERIT, Overflow::OBSERVABLE, stackChildren);
228
229 auto containerBox = AceType::MakeRefPtr<BoxComponent>();
230 containerBox->SetBackDecoration(containerDecoration);
231 containerBox->SetFlex(BoxFlex::FLEX_X);
232 containerBox->SetAlignment(Alignment::CENTER);
233
234 Edge padding = Edge(CONTENT_PADDING, Dimension(0.0), CONTENT_PADDING, CONTENT_PADDING);
235 containerBox->SetPadding(padding);
236 containerBox->SetChild(stackComponent);
237 SetChild(containerBox);
238 }
239
BuildTitleChildren(bool isFloating,bool isFocus,bool isFullWindow)240 std::list<RefPtr<Component>> ContainerModalComponent::BuildTitleChildren(bool isFloating, bool isFocus,
241 bool isFullWindow)
242 {
243 // title icon
244 if (!titleIcon_) {
245 titleIcon_ = AceType::MakeRefPtr<ImageComponent>();
246 titleIcon_->SetWidth(TITLE_ICON_SIZE);
247 titleIcon_->SetHeight(TITLE_ICON_SIZE);
248 titleIcon_->SetFocusable(false);
249 }
250
251 // title text
252 if (!titleLabel_) {
253 titleLabel_ = AceType::MakeRefPtr<TextComponent>("");
254 }
255 TextStyle style;
256 style.SetFontSize(TITLE_TEXT_FONT_SIZE);
257 style.SetMaxLines(1);
258 style.SetTextColor(isFocus ? TITLE_TEXT_COLOR : TITLE_TEXT_COLOR_LOST_FOCUS);
259 style.SetFontWeight(FontWeight::W500);
260 style.SetAllowScale(false);
261 style.SetTextOverflow(TextOverflow::ELLIPSIS);
262 titleLabel_->SetTextStyle(style);
263 titleLabel_->SetFlexWeight(1.0);
264
265 CreateAccessibilityNode(DOM_NODE_TAG_TEXT, isFloating ? FLOATING_TITLE_LABEL : TITLE_LABEL,
266 isFloating ? FLOATING_TITLE_ROW : TITLE_ROW);
267
268 // title control button
269 auto windowManager = context_.Upgrade()->GetWindowManager();
270 auto leftSplitButton = isFocus ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_SPLIT_LEFT
271 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_SPLIT_LEFT;
272 auto titleLeftSplitButton = BuildControlButton(leftSplitButton, [windowManager]() {
273 if (windowManager) {
274 LOGI("left split button clicked");
275 windowManager->FireWindowSplitCallBack();
276 }
277 }, isFocus, isFloating);
278 auto maxRecoverButton = isFloating && isFullWindow ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_RECOVER
279 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MAXIMIZE;
280 if (!isFocus) {
281 maxRecoverButton = isFloating && isFullWindow ?
282 InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_RECOVER :
283 InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_MAXIMIZE;
284 }
285 auto titleMaximizeRecoverButton = BuildControlButton(maxRecoverButton, [windowManager]() {
286 if (windowManager) {
287 auto mode = windowManager->GetWindowMode();
288 if (mode == WindowMode::WINDOW_MODE_FULLSCREEN) {
289 LOGI("recover button clicked");
290 windowManager->WindowRecover();
291 } else {
292 LOGI("maximize button clicked");
293 windowManager->WindowMaximize();
294 }
295 }
296 }, isFocus, isFloating);
297 auto minimizeButton = isFocus ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MINIMIZE
298 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_MINIMIZE;
299 auto titleMinimizeButton = BuildControlButton(minimizeButton, [windowManager]() {
300 if (windowManager) {
301 LOGI("minimize button clicked");
302 windowManager->WindowMinimize();
303 }
304 }, isFocus, isFloating);
305 auto closeButton = isFocus ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_CLOSE
306 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_CLOSE;
307 auto titleCloseButton = BuildControlButton(closeButton, [windowManager]() {
308 if (windowManager) {
309 LOGI("close button clicked");
310 windowManager->WindowClose();
311 }
312 }, isFocus, isFloating);
313 std::list<RefPtr<Component>> titleChildren;
314 titleChildren.emplace_back(SetPadding(titleIcon_, TITLE_PADDING_START, TITLE_ELEMENT_MARGIN_HORIZONTAL));
315 if (isDeclarative_) {
316 auto inspectorTitle = AceType::MakeRefPtr<V2::InspectorComposedComponent>(
317 V2::InspectorComposedComponent::GenerateId(), V2::TEXT_COMPONENT_TAG, titleLabel_);
318 inspectorTitle->MarkNeedUpdate();
319 titleChildren.emplace_back(inspectorTitle);
320 } else {
321 titleChildren.emplace_back(AceType::MakeRefPtr<ComposedComponent>(
322 isFloating ? std::to_string(FLOATING_TITLE_LABEL) : std::to_string(TITLE_LABEL), DOM_NODE_TAG_TEXT,
323 titleLabel_));
324 }
325 auto rightPadding = SystemProperties::GetDeviceAccess() ? TITLE_ELEMENT_MARGIN_HORIZONTAL_ACCESS_DEVICE
326 : TITLE_ELEMENT_MARGIN_HORIZONTAL;
327 if (!hideSplit_) {
328 titleChildren.emplace_back(SetPadding(titleLeftSplitButton, ZERO_PADDING_ALL, rightPadding));
329 }
330 if (!hideMaximize_) {
331 titleChildren.emplace_back(
332 SetPadding(titleMaximizeRecoverButton, ZERO_PADDING_ALL, rightPadding));
333 }
334 if (!hideMinimize_) {
335 titleChildren.emplace_back(SetPadding(titleMinimizeButton, ZERO_PADDING_ALL, rightPadding));
336 }
337 if (!hideClose_) {
338 titleChildren.emplace_back(SetPadding(titleCloseButton, ZERO_PADDING_ALL, TITLE_PADDING_END));
339 }
340 return titleChildren;
341 }
342
CreateAccessibilityNode(const std::string & tag,int32_t nodeId,int32_t parentNodeId)343 void ContainerModalComponent::CreateAccessibilityNode(const std::string& tag, int32_t nodeId, int32_t parentNodeId)
344 {
345 auto context = context_.Upgrade();
346 if (context != nullptr && !isDeclarative_) {
347 auto accessibilityManager = context->GetAccessibilityManager();
348 if (accessibilityManager) {
349 accessibilityManager->CreateAccessibilityNode(tag, nodeId, parentNodeId, -1);
350 }
351 }
352 }
353
354 } // namespace OHOS::Ace