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
16 #include "core/components_ng/pattern/container_modal/enhance/container_modal_view_enhance.h"
17
18 #include "core/components/theme/advanced_pattern_theme.h"
19 #include "core/components_ng/base/view_stack_processor.h"
20 #include "core/components_ng/pattern/container_modal/container_modal_utils.h"
21 #include "core/components_ng/pattern/container_modal/enhance/container_modal_pattern_enhance.h"
22 #include "core/components_ng/pattern/image/image_pattern.h"
23 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
24 #include "core/components_ng/pattern/stack/stack_pattern.h"
25 #include "core/components_v2/inspector/inspector_constants.h"
26
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr int32_t INVALID_LISTENER_ID = -1;
30 }
31
32 /**
33 * The structure of container_modal enhanced is designed as follows :
34 * |--container_modal(stack)
35 * |--column
36 * |--container_modal_custom_title(row)
37 * |--custom_node(js)
38 * |--stack
39 * |--container_modal_content(stage)
40 * |--page
41 * |--dialog(when show)
42 * |--gesture_row(row)
43 * |--container_modal_custom_floating_title(row)
44 * |--custom_node(js)
45 * |--container_modal_control_buttons(row)
46 * |--[maxRecover, minimize, close](button)
47 */
48
OnContainerModalEvent(RefPtr<PipelineContext> pipelineContext,const std::string & name,const std::string & value)49 void ContainerModalViewEnhance::OnContainerModalEvent(
50 RefPtr<PipelineContext> pipelineContext, const std::string& name, const std::string& value)
51 {
52 CHECK_NULL_VOID(pipelineContext);
53 auto rootNode = pipelineContext->GetRootElement();
54 CHECK_NULL_VOID(rootNode);
55 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode->GetFirstChild());
56 CHECK_NULL_VOID(containerNode);
57 auto containerPattern = containerNode->GetPattern<ContainerModalPattern>();
58 CHECK_NULL_VOID(containerPattern);
59 containerPattern->OnContainerModalEvent(name, value);
60 }
61
Create(RefPtr<FrameNode> & content)62 RefPtr<FrameNode> ContainerModalViewEnhance::Create(RefPtr<FrameNode>& content)
63 {
64 auto containerModalNode = FrameNode::CreateFrameNode("ContainerModal",
65 ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ContainerModalPatternEnhance>());
66 auto stack = FrameNode::CreateFrameNode(
67 V2::STACK_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<StackPattern>());
68 auto column = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
69 AceType::MakeRefPtr<LinearLayoutPattern>(true));
70 auto controlButtonsRow = FrameNode::CreateFrameNode(
71 V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<LinearLayoutPattern>(false));
72
73 column->AddChild(BuildTitle(containerModalNode));
74 stack->AddChild(content);
75 column->AddChild(stack);
76 column->AddChild(BuildGestureRow(containerModalNode));
77 auto containerPattern = containerModalNode->GetPattern<ContainerModalPatternEnhance>();
78 CHECK_NULL_RETURN(containerPattern, nullptr);
79 containerModalNode->AddChild(column);
80 containerModalNode->AddChild(BuildTitle(containerModalNode, true));
81
82 // Confirm that if it is a pure Cangjie application, the node construction is completed on the C side
83 if (customControlButtonBuilder_) {
84 WeakPtr<ContainerModalPatternEnhance> weakPattern =
85 controlButtonsRow->GetPattern<ContainerModalPatternEnhance>();
86 containerModalNode->AddChild(customControlButtonBuilder_(weakPattern, controlButtonsRow));
87 } else {
88 containerModalNode->AddChild(BuildCustomButtonRow(controlButtonsRow));
89 }
90 containerPattern->Init();
91 return containerModalNode;
92 }
93
BuildCustomButtonRow(RefPtr<FrameNode> & containerRow)94 RefPtr<FrameNode> ContainerModalViewEnhance::BuildCustomButtonRow(RefPtr<FrameNode>& containerRow)
95 {
96 TAG_LOGI(AceLogTag::ACE_APPBAR, "ContainerModalViewEnhance BuildCustomButtonRow called");
97 CHECK_NULL_RETURN(containerRow, nullptr);
98 auto isSucc = ExecuteCustomTitleAbc();
99 if (!isSucc) {
100 return nullptr;
101 }
102 auto customNode = NG::ViewStackProcessor::GetInstance()->GetCustomButtonNode();
103 containerRow->AddChild(customNode);
104 return containerRow;
105 }
106
BuildTitle(RefPtr<FrameNode> & containerNode,bool isFloatingTitle)107 RefPtr<FrameNode> ContainerModalViewEnhance::BuildTitle(RefPtr<FrameNode>& containerNode, bool isFloatingTitle)
108 {
109 TAG_LOGI(AceLogTag::ACE_APPBAR, "ContainerModalViewEnhance BuildTitle called");
110 auto titleRow = BuildTitleContainer(containerNode, isFloatingTitle);
111 CHECK_NULL_RETURN(titleRow, nullptr);
112 return titleRow;
113 }
114
AddControlButtons(RefPtr<FrameNode> & containerNode,RefPtr<FrameNode> & containerTitleRow)115 RefPtr<FrameNode> ContainerModalViewEnhance::AddControlButtons(
116 RefPtr<FrameNode>& containerNode, RefPtr<FrameNode>& containerTitleRow)
117 {
118 WeakPtr<ContainerModalPatternEnhance> weakPattern = containerNode->GetPattern<ContainerModalPatternEnhance>();
119 RefPtr<FrameNode> maximizeBtn = BuildControlButton(
120 InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MAXIMIZE, [weakPattern](GestureEvent& info) {
121 auto pattern = weakPattern.Upgrade();
122 CHECK_NULL_VOID(pattern);
123 pattern->OnMaxButtonClick(info);
124 });
125 maximizeBtn->UpdateInspectorId("EnhanceMaximizeBtn");
126
127 // add long press event
128 WeakPtr<FrameNode> weakMaximizeBtn = maximizeBtn;
129 auto longPressCallback = [weakPattern, weakMaximizeBtn](GestureEvent& info) {
130 auto pattern = weakPattern.Upgrade();
131 CHECK_NULL_VOID(pattern);
132 auto maximizeBtn = weakMaximizeBtn.Upgrade();
133 CHECK_NULL_VOID(maximizeBtn);
134 pattern->ShowMaxMenu(maximizeBtn);
135 };
136 // diable mouse left!
137 auto hub = maximizeBtn->GetOrCreateGestureEventHub();
138 auto longPressEvent = AceType::MakeRefPtr<LongPressEvent>(longPressCallback);
139 hub->SetLongPressEvent(longPressEvent, false, true);
140
141 auto eventHub = maximizeBtn->GetOrCreateInputEventHub();
142 auto hoverMoveFuc = [weakPattern](MouseInfo& info) {
143 auto pattern = weakPattern.Upgrade();
144 CHECK_NULL_VOID(pattern);
145 pattern->OnMaxBtnInputEvent(info);
146 };
147 eventHub->AddOnMouseEvent(AceType::MakeRefPtr<InputEvent>(std::move(hoverMoveFuc)));
148
149 // add hover in out event
150 auto hoverEventFuc = [weakPattern, weakMaximizeBtn](bool hover) mutable {
151 auto pattern = weakPattern.Upgrade();
152 CHECK_NULL_VOID(pattern);
153 pattern->OnMaxBtnHoverEvent(hover, weakMaximizeBtn);
154 };
155 eventHub->AddOnHoverEvent(AceType::MakeRefPtr<InputEvent>(std::move(hoverEventFuc)));
156 containerTitleRow->AddChild(maximizeBtn);
157
158 RefPtr<FrameNode> minimizeBtn = BuildControlButton(
159 InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_MINIMIZE, [weakPattern](GestureEvent& info) {
160 auto pattern = weakPattern.Upgrade();
161 CHECK_NULL_VOID(pattern);
162 pattern->OnMinButtonClick(info);
163 });
164 // minimizeBtn add empty panEvent to over fater container event
165 minimizeBtn->UpdateInspectorId("EnhanceMinimizeBtn");
166 containerTitleRow->AddChild(minimizeBtn);
167
168 RefPtr<FrameNode> closeBtn = BuildControlButton(
169 InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_CLOSE,
170 [weakPattern](GestureEvent& info) {
171 auto pattern = weakPattern.Upgrade();
172 CHECK_NULL_VOID(pattern);
173 pattern->OnCloseButtonClick(info);
174 },
175 true);
176 // closeBtn add empty panEvent to over fater container event
177 closeBtn->UpdateInspectorId("EnhanceCloseBtn");
178 containerTitleRow->AddChild(closeBtn);
179
180 return containerTitleRow;
181 }
182
BuildMenuItemIcon(InternalResource::ResourceId resourceId)183 RefPtr<FrameNode> ContainerModalViewEnhance::BuildMenuItemIcon(InternalResource::ResourceId resourceId)
184 {
185 auto icon = FrameNode::CreateFrameNode(
186 V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ImagePattern>());
187 auto iconLayoutProperty = icon->GetLayoutProperty<ImageLayoutProperty>();
188 ImageSourceInfo sourceInfo;
189 sourceInfo.SetResourceId(resourceId);
190 auto theme = PipelineContext::GetCurrentContextSafelyWithCheck()->GetTheme<AdvancedPatternTheme>();
191 if (theme) {
192 sourceInfo.SetFillColor(theme->GetPrimaryColor());
193 } else {
194 TAG_LOGI(AceLogTag::ACE_APPBAR, "BuildMenuItemIcon AdvancedPatternTheme is null");
195 }
196 iconLayoutProperty->UpdateImageSourceInfo(sourceInfo);
197 iconLayoutProperty->UpdateUserDefinedIdealSize(
198 CalcSize(CalcLength(TITLE_BUTTON_SIZE), CalcLength(TITLE_BUTTON_SIZE)));
199 icon->MarkModifyDone();
200 return icon;
201 }
202
BuildGestureRow(RefPtr<FrameNode> & containerNode)203 RefPtr<FrameNode> ContainerModalViewEnhance::BuildGestureRow(RefPtr<FrameNode>& containerNode)
204 {
205 auto pattern = containerNode->GetPattern<ContainerModalPatternEnhance>();
206 auto gestureRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
207 AceType::MakeRefPtr<LinearLayoutPattern>(false));
208 auto renderContext = gestureRow->GetRenderContext();
209 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
210 renderContext->UpdatePosition(OffsetT<Dimension>());
211 auto layoutProp = gestureRow->GetLayoutProperty();
212 layoutProp->UpdateUserDefinedIdealSize(
213 CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(CONTAINER_TITLE_HEIGHT)));
214 return gestureRow;
215 }
216
GetContainerModalComponentRect(PipelineContext * pipelineContext,RectF & floatContainerModal,RectF & floatButtons)217 bool ContainerModalViewEnhance::GetContainerModalComponentRect(
218 PipelineContext* pipelineContext, RectF& floatContainerModal, RectF& floatButtons)
219 {
220 CHECK_NULL_RETURN(pipelineContext, false);
221 auto rootNode = pipelineContext->GetRootElement();
222 CHECK_NULL_RETURN(rootNode, false);
223 auto containerMode = AceType::DynamicCast<NG::FrameNode>(rootNode->GetChildren().front());
224 CHECK_NULL_RETURN(containerMode, false);
225 auto pattern = containerMode->GetPattern<NG::ContainerModalPatternEnhance>();
226 CHECK_NULL_RETURN(pattern, false);
227 return pattern->GetContainerModalComponentRect(floatContainerModal, floatButtons);
228 }
229
SetContainerButtonStyle(RefPtr<PipelineContext> pipeline,const Ace::DecorButtonStyle & buttonStyle)230 void ContainerModalViewEnhance::SetContainerButtonStyle(RefPtr<PipelineContext> pipeline,
231 const Ace::DecorButtonStyle& buttonStyle)
232 {
233 CHECK_NULL_VOID(pipeline);
234 if (!pipeline || pipeline->GetWindowModal() != WindowModal::CONTAINER_MODAL) {
235 return;
236 }
237 auto rootNode = pipeline->GetRootElement();
238 CHECK_NULL_VOID(rootNode);
239 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode->GetChildren().front());
240 CHECK_NULL_VOID(containerNode);
241 auto containerPattern = containerNode->GetPattern<ContainerModalPatternEnhance>();
242 CHECK_NULL_VOID(containerPattern);
243 auto controlButtonsNode = containerPattern->GetCustomButtonNode();
244 CHECK_NULL_VOID(controlButtonsNode);
245 controlButtonsNode->FireCustomCallback(EVENT_NAME_BUTTON_SPACING_CHANGE,
246 std::to_string(buttonStyle.spacingBetweenButtons));
247 controlButtonsNode->FireCustomCallback(EVENT_NAME_BUTTON_SIZE_CHANGE,
248 std::to_string(buttonStyle.buttonBackgroundSize));
249 controlButtonsNode->FireCustomCallback(EVENT_NAME_COLOR_CONFIGURATION_LOCKED,
250 std::to_string(buttonStyle.colorMode));
251 if (buttonStyle.colorMode != static_cast<int32_t>(ColorMode::DARK) &&
252 buttonStyle.colorMode != static_cast<int32_t>(ColorMode::LIGHT)) {
253 containerPattern->OnColorConfigurationUpdate();
254 }
255 controlButtonsNode->FireCustomCallback(
256 EVENT_NAME_BUTTON_RIGHT_OFFSET_CHANGE, std::to_string(buttonStyle.closeButtonRightMargin));
257 controlButtonsNode->FireCustomCallback(EVENT_NAME_BUTTON_ICON_SIZE_CHANGE,
258 std::to_string(buttonStyle.buttonIconSize));
259 controlButtonsNode->FireCustomCallback(EVENT_NAME_BUTTON_BACKGROUND_CORNER_RADIUS_CHANGE,
260 std::to_string(buttonStyle.buttonBackgroundCornerRadius));
261 containerPattern->CallButtonsRectChange();
262 }
263
AddButtonsRectChangeListener(PipelineContext * context,ButtonsRectChangeListener && listener)264 int32_t ContainerModalViewEnhance::AddButtonsRectChangeListener(
265 PipelineContext* context, ButtonsRectChangeListener&& listener)
266 {
267 CHECK_NULL_RETURN(context, INVALID_LISTENER_ID);
268 auto rootNode = context->GetRootElement();
269 CHECK_NULL_RETURN(rootNode, INVALID_LISTENER_ID);
270 auto children = rootNode->GetChildren();
271 if (children.empty()) {
272 return INVALID_LISTENER_ID;
273 }
274 auto containerNode = AceType::DynamicCast<FrameNode>(children.front());
275 CHECK_NULL_RETURN(containerNode, INVALID_LISTENER_ID);
276 auto pattern = containerNode->GetPattern<ContainerModalPatternEnhance>();
277 CHECK_NULL_RETURN(pattern, INVALID_LISTENER_ID);
278 return pattern->AddButtonsRectChangeListener(std::move(listener));
279 }
280
RemoveButtonsRectChangeListener(PipelineContext * context,int32_t id)281 void ContainerModalViewEnhance::RemoveButtonsRectChangeListener(PipelineContext* context, int32_t id)
282 {
283 CHECK_NULL_VOID(context);
284 auto rootNode = context->GetRootElement();
285 CHECK_NULL_VOID(rootNode);
286 auto children = rootNode->GetChildren();
287 if (children.empty()) {
288 return;
289 }
290 auto containerNode = AceType::DynamicCast<FrameNode>(children.front());
291 CHECK_NULL_VOID(containerNode);
292 auto pattern = containerNode->GetPattern<ContainerModalPatternEnhance>();
293 CHECK_NULL_VOID(pattern);
294 pattern->RemoveButtonsRectChangeListener(id);
295 }
296
GetContainerModalTitleVisible(RefPtr<PipelineContext> pipeline,bool isImmersive)297 bool ContainerModalViewEnhance::GetContainerModalTitleVisible(RefPtr<PipelineContext> pipeline, bool isImmersive)
298 {
299 if (pipeline->GetWindowModal() != WindowModal::CONTAINER_MODAL) {
300 return false;
301 }
302 auto rootNode = pipeline->GetRootElement();
303 CHECK_NULL_RETURN(rootNode, false);
304 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode->GetFirstChild());
305 CHECK_NULL_RETURN(containerNode, false);
306 auto containerModalPattern = containerNode->GetPattern<ContainerModalPattern>();
307 CHECK_NULL_RETURN(containerModalPattern, false);
308 return containerModalPattern->GetContainerModalTitleVisible(isImmersive);
309 }
310 } // namespace OHOS::Ace::NG
311