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