• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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