1 /*
2 * Copyright (c) 2021-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/split_container/render_split_container.h"
17
18 #include "core/components/display/render_display.h"
19
20 namespace OHOS::Ace {
21
22 namespace {
23
24 constexpr int32_t DISABLE_HIDE = -1;
25
26 } // namespace
27
Update(const RefPtr<Component> & component)28 void RenderSplitContainer::Update(const RefPtr<Component>& component)
29 {
30 ResetComponentMember();
31 UpdateComponentAttr(component);
32 InitializeRecognizer();
33 MarkNeedLayout();
34 }
35
ResetComponentMember()36 void RenderSplitContainer::ResetComponentMember()
37 {
38 dragDetector_.Reset();
39 resizable_ = false;
40 layoutWidth_ = 0.0;
41 layoutHeight_ = 0.0;
42 }
43
UpdateComponentAttr(const RefPtr<Component> & component)44 void RenderSplitContainer::UpdateComponentAttr(const RefPtr<Component>& component)
45 {
46 auto splitComponent = AceType::DynamicCast<SplitContainerComponent>(component);
47 resizable_ = splitComponent->GetResizable();
48 splitType_ = splitComponent->GetSplitType();
49 }
50
InitProperties()51 void RenderSplitContainer::InitProperties()
52 {
53 magicNodes_.clear();
54 displayNodes_.clear();
55 disableHideNodes_.clear();
56 for (const auto& child : GetChildren()) {
57 MagicLayoutNode node;
58 node.node = child;
59 auto displayIndexSetted = child->GetDisplayIndexSetted();
60 auto idx = displayIndexSetted ? child->GetDisplayIndex() : DISABLE_HIDE;
61 if (idx == DISABLE_HIDE) {
62 disableHideNodes_.insert(child);
63 continue;
64 }
65
66 if (magicNodes_.find(idx) != magicNodes_.end()) {
67 magicNodes_[idx].emplace_back(node);
68 } else {
69 std::list<MagicLayoutNode> nodes;
70 nodes.emplace_back(node);
71 magicNodes_[idx] = nodes;
72 }
73 }
74 }
75
GetMainSize(const RefPtr<RenderNode> & renderNode) const76 double RenderSplitContainer::GetMainSize(const RefPtr<RenderNode>& renderNode) const
77 {
78 auto layoutSize = renderNode->GetLayoutSize();
79 if (splitType_ == SplitType::ROW_SPLIT) {
80 return layoutSize.Width();
81 } else {
82 return layoutSize.Height();
83 }
84 }
85
GetMainMinSize(const RefPtr<RenderNode> & renderNode) const86 double RenderSplitContainer::GetMainMinSize(const RefPtr<RenderNode>& renderNode) const
87 {
88 Size minSize;
89 auto flexItem = AceType::DynamicCast<RenderFlexItem>(renderNode);
90 if (flexItem) {
91 minSize = flexItem->GetNormalizedConstraints().GetMinSize();
92 }
93
94 if (splitType_ == SplitType::ROW_SPLIT) {
95 return minSize.Width();
96 } else {
97 return minSize.Height();
98 }
99 }
100
UpdateDisplayNode()101 void RenderSplitContainer::UpdateDisplayNode()
102 {
103 auto maxSize = GetLayoutParam().GetMaxSize();
104 double allocatedSize = 0.0;
105 double totalMainSize = 0.0;
106 for (const auto& node : disableHideNodes_) {
107 auto layoutSize = node->GetLayoutSize();
108 totalMainSize += splitType_ == SplitType::ROW_SPLIT ? layoutSize.Width() : layoutSize.Height();
109 }
110
111 auto maxMainSize = splitType_ == SplitType::ROW_SPLIT ? maxSize.Width() : maxSize.Height();
112 maxMainSize -= totalMainSize;
113 for (auto iter = magicNodes_.rbegin(); iter != magicNodes_.rend();) {
114 auto nodeList = (*iter).second;
115 for (const auto& node : nodeList) {
116 auto child = node.node;
117 allocatedSize += GetMainSize(child);
118 allocatedSize += DEFAULT_SPLIT_HEIGHT;
119 }
120
121 if ((allocatedSize - DEFAULT_SPLIT_HEIGHT) > maxMainSize) {
122 for (const auto& node : nodeList) {
123 auto child = node.node;
124 allocatedSize -= GetMainSize(child);
125 allocatedSize -= DEFAULT_SPLIT_HEIGHT;
126 }
127 break;
128 }
129 for (const auto& node : nodeList) {
130 auto child = node.node;
131 if (child->GetLayoutSize().IsValid()) {
132 displayNodes_.insert(child);
133 }
134 }
135 if (NearEqual(allocatedSize, maxMainSize)) {
136 break;
137 }
138 iter++;
139 }
140 }
141
PerformLayout()142 void RenderSplitContainer::PerformLayout()
143 {
144 InitProperties();
145 layoutHeight_ = 0.0;
146 layoutWidth_ = 0.0;
147 for (const auto& item : GetChildren()) {
148 item->Layout(GetLayoutParam());
149 }
150
151 UpdateDisplayNode();
152 Size maxSize = GetLayoutParam().GetMaxSize();
153 splitRects_.clear();
154 if (dragSplitOffset_.size() == 0) {
155 dragSplitOffset_ = std::vector<double>(GetChildren().size(), 0.0);
156 }
157 layoutHeight_ = splitType_ == SplitType::ROW_SPLIT ? maxSize.Height() : 0.0;
158 layoutWidth_ = splitType_ == SplitType::ROW_SPLIT ? 0.0 : maxSize.Width();
159 LayoutChildren();
160
161 if (!displayNodes_.empty() || !disableHideNodes_.empty()) {
162 if (splitType_ == SplitType::ROW_SPLIT) {
163 layoutWidth_ -= DEFAULT_SPLIT_HEIGHT;
164 } else {
165 layoutHeight_ -= DEFAULT_SPLIT_HEIGHT;
166 }
167 }
168
169 double maxHeight = GetLayoutParam().GetMaxSize().Height();
170 double maxWidth = GetLayoutParam().GetMaxSize().Width();
171 layoutHeight_ = LessNotEqual(layoutHeight_, maxHeight) ? layoutHeight_ : maxHeight;
172 layoutWidth_ = LessNotEqual(layoutWidth_, maxWidth) ? layoutWidth_ : maxWidth;
173 SetLayoutSize(Size { layoutWidth_, layoutHeight_ });
174 }
175
LayoutChildren()176 void RenderSplitContainer::LayoutChildren()
177 {
178 Size maxSize = GetLayoutParam().GetMaxSize();
179 size_t index = 0;
180 double childOffsetMain = 0.0;
181 for (const auto& item : GetChildren()) {
182 auto renderDisplay = FindChildOfClass<RenderDisplay>(item);
183 if (displayNodes_.find(item) == displayNodes_.end() &&
184 disableHideNodes_.find(item) == disableHideNodes_.end()) {
185 if (renderDisplay) {
186 renderDisplay->UpdateVisibleType(VisibleType::INVISIBLE);
187 }
188
189 item->Layout(LayoutParam(Size(), Size()));
190 index++;
191 continue;
192 }
193
194 if (renderDisplay) {
195 renderDisplay->UpdateVisibleType(VisibleType::VISIBLE);
196 }
197 Offset offset;
198 if (splitType_ == SplitType::ROW_SPLIT) {
199 offset = Offset(childOffsetMain, 0);
200 layoutWidth_ += GetMainSize(item);
201 layoutWidth_ += DEFAULT_SPLIT_HEIGHT;
202 } else {
203 offset = Offset(0, childOffsetMain);
204 layoutHeight_ += GetMainSize(item);
205 layoutHeight_ += DEFAULT_SPLIT_HEIGHT;
206 }
207 item->SetPosition(offset);
208 childOffsetMain += GetMainSize(item);
209 if (dragSplitOffset_[index] > 0.0) {
210 childOffsetMain += dragSplitOffset_[index];
211 }
212 double posMain = childOffsetMain;
213 if (splitType_ == SplitType::ROW_SPLIT) {
214 splitRects_.push_back(Rect(posMain, 0, DEFAULT_SPLIT_HEIGHT, maxSize.Height()));
215 } else {
216 splitRects_.push_back(Rect(0, posMain, maxSize.Width(), DEFAULT_SPLIT_HEIGHT));
217 }
218
219 childOffsetMain += DEFAULT_SPLIT_HEIGHT;
220
221 index++;
222 }
223 if (splitType_ == SplitType::ROW_SPLIT) {
224 layoutWidth_ = childOffsetMain > maxSize.Width() ? maxSize.Width() : childOffsetMain;
225 } else {
226 layoutHeight_ = childOffsetMain > maxSize.Height() ? maxSize.Height() : childOffsetMain;
227 }
228 }
229
InitializeRecognizer()230 void RenderSplitContainer::InitializeRecognizer()
231 {
232 if (!resizable_) {
233 return;
234 }
235 if (!dragDetector_) {
236 dragDetector_ = AceType::MakeRefPtr<VerticalDragRecognizer>();
237 dragDetector_->SetOnDragStart([weak = WeakClaim(this)](const DragStartInfo& startInfo) {
238 auto splitContainer = weak.Upgrade();
239 if (splitContainer) {
240 splitContainer->HandleDragStart(startInfo.GetLocalLocation());
241 }
242 });
243 dragDetector_->SetOnDragUpdate([weakDrag = AceType::WeakClaim(this)](const DragUpdateInfo& info) {
244 auto splitContainer = weakDrag.Upgrade();
245 if (splitContainer) {
246 splitContainer->HandleDragUpdate(info.GetLocalLocation());
247 }
248 });
249 dragDetector_->SetOnDragEnd([weakDrag = AceType::WeakClaim(this)](const DragEndInfo& info) {
250 auto splitContainer = weakDrag.Upgrade();
251 if (splitContainer) {
252 splitContainer->HandleDragEnd(info.GetLocalLocation(), info.GetMainVelocity());
253 }
254 });
255 }
256 }
257
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)258 void RenderSplitContainer::OnTouchTestHit(
259 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
260 {
261 if (dragDetector_) {
262 dragDetector_->SetCoordinateOffset(coordinateOffset);
263 result.emplace_back(dragDetector_);
264 }
265 }
266
HandleMouseEvent(const MouseEvent & event)267 bool RenderSplitContainer::HandleMouseEvent(const MouseEvent& event)
268 {
269 if (isDragedMoving_) {
270 return false;
271 }
272 MouseInfo info;
273 info.SetButton(event.button);
274 info.SetAction(event.action);
275 info.SetGlobalLocation(event.GetOffset());
276 info.SetLocalLocation(event.GetOffset() - Offset(GetCoordinatePoint().GetX(), GetCoordinatePoint().GetY()));
277 info.SetScreenLocation(event.GetScreenOffset());
278 info.SetTimeStamp(event.time);
279 if (splitType_ == SplitType::ROW_SPLIT) {
280 for (int32_t i = 0; i < static_cast<int32_t>(splitRects_.size()) - 1; i++) {
281 auto lowBound = splitRects_[i].GetOffset().GetX();
282 auto upBound = splitRects_[i].GetOffset().GetX() + DEFAULT_SPLIT_HEIGHT;
283 if (info.GetLocalLocation().GetX() >= lowBound && info.GetLocalLocation().GetX() <= upBound) {
284 isDraged_ = true;
285 break;
286 } else {
287 isDraged_ = false;
288 }
289 }
290 if (preIsDraged_ != isDraged_) {
291 preIsDraged_ = isDraged_;
292 auto mouseStyle = MouseStyle::CreateMouseStyle();
293 auto context = GetContext().Upgrade();
294 auto windowId = context->GetWindowId();
295 if (isDraged_) {
296 MouseFormat leftRightStyle = MouseFormat::WEST_EAST;
297 mouseStyle->SetPointerStyle(windowId, leftRightStyle);
298 } else {
299 MouseFormat defaultStyle = MouseFormat::DEFAULT;
300 mouseStyle->SetPointerStyle(windowId, defaultStyle);
301 }
302 }
303 } else {
304 for (int32_t i = 0; i < static_cast<int32_t>(splitRects_.size()) - 1; i++) {
305 auto lowBound = splitRects_[i].GetOffset().GetY();
306 auto upBound = splitRects_[i].GetOffset().GetY() + DEFAULT_SPLIT_HEIGHT;
307 if (info.GetLocalLocation().GetY() >= lowBound && info.GetLocalLocation().GetY() <= upBound) {
308 isDraged_ = true;
309 break;
310 } else {
311 isDraged_ = false;
312 }
313 }
314 if (preIsDraged_ != isDraged_) {
315 preIsDraged_ = isDraged_;
316 auto mouseStyle = MouseStyle::CreateMouseStyle();
317 auto context = GetContext().Upgrade();
318 auto windowId = context->GetWindowId();
319 if (isDraged_) {
320 MouseFormat upDownStyle = MouseFormat::NORTH_SOUTH;
321 mouseStyle->SetPointerStyle(windowId, upDownStyle);
322 } else {
323 MouseFormat defaultStyle = MouseFormat::DEFAULT;
324 mouseStyle->SetPointerStyle(windowId, defaultStyle);
325 }
326 }
327 }
328 return true;
329 }
330
HandleMouseHoverEvent(MouseState mouseState)331 void RenderSplitContainer::HandleMouseHoverEvent(MouseState mouseState) {}
332
333 } // namespace OHOS::Ace