/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "dock/focus_manager.h" #if ENABLE_FOCUS_MANAGER #include "components/root_view.h" #include "gfx_utils/graphic_math.h" #include "common/input_method_manager.h" namespace OHOS { FocusManager* FocusManager::GetInstance() { static FocusManager instance; return &instance; } bool FocusManager::RequestFocus(UIView* view) { if (view == nullptr || view == focusView_ || !view->IsFocusable() || !view->IsVisible()) { return false; } lastFocusView_ = focusView_; focusView_ = view; UIViewGroup* rootView = RootView::GetInstance(); if (RootView::FindSubView(*rootView, lastFocusView_)) { lastFocusView_->Blur(); } focusView_->Focus(); UIViewType viewType = focusView_->GetViewType(); // show keyboard if the view is edittable if (viewType == UI_EDIT_TEXT) { InputMethodManager::GetInstance().ShowInputMethod(focusView_); } return true; } bool FocusManager::ClearFocus() { if (focusView_ == nullptr) { return false; } lastFocusView_ = focusView_; focusView_->Blur(); focusView_ = nullptr; return true; } bool FocusManager::RequestFocusByDirection(uint8_t direction) { if (focusView_ != nullptr) { UIView* candidate = nullptr; if (GetNextFocus(focusView_, candidate, direction)) { return RequestFocus(candidate); } } return false; } bool FocusManager::CompareCandidates(UIView* focusedView, UIView*& candidate, UIView* current, uint8_t direction) { if (current == focusedView) { return false; } bool res = false; switch (direction) { case FOCUS_DIRECTION_UP: { res = CompareCandidatesByUp(focusedView, candidate, current); break; } case FOCUS_DIRECTION_DOWN: { res = CompareCandidatesByDown(focusedView, candidate, current); break; } case FOCUS_DIRECTION_LEFT: { res = CompareCandidatesByLeft(focusedView, candidate, current); break; } case FOCUS_DIRECTION_RIGHT: { res = CompareCandidatesByRight(focusedView, candidate, current); break; } default: return false; } return res; } bool FocusManager::IsAtSameCol(const Rect& rect1, const Rect& rect2) { return ((rect1.GetLeft() < rect2.GetRight()) && (rect1.GetRight() > rect2.GetLeft())); } bool FocusManager::IsAtSameRow(const Rect& rect1, const Rect& rect2) { return ((rect1.GetBottom() < rect2.GetTop()) && (rect1.GetTop() > rect2.GetBottom())); } bool FocusManager::CompareCandidatesByUp(UIView* focusedView, UIView*& candidate, UIView* current) { Rect focusedViewRect = focusedView->GetRect(); Rect currentRect = current->GetRect(); if (currentRect.GetBottom() >= focusedViewRect.GetBottom()) { return false; } if (candidate != nullptr) { Rect candidateRect = candidate->GetRect(); if (IsAtSameCol(focusedViewRect, currentRect) && IsAtSameCol(focusedViewRect, candidateRect)) { return currentRect.GetBottom() > candidateRect.GetBottom(); } return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect); } return true; } bool FocusManager::CompareCandidatesByDown(UIView* focusedView, UIView*& candidate, UIView* current) { Rect focusedViewRect = focusedView->GetRect(); Rect currentRect = current->GetRect(); if (currentRect.GetTop() <= focusedViewRect.GetTop()) { return false; } if (candidate != nullptr) { Rect candidateRect = candidate->GetRect(); if (IsAtSameCol(focusedViewRect, currentRect) && IsAtSameCol(focusedViewRect, candidateRect)) { return currentRect.GetTop() < candidateRect.GetTop(); } return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect); } return true; } bool FocusManager::CompareCandidatesByLeft(UIView* focusedView, UIView*& candidate, UIView* current) { Rect focusedViewRect = focusedView->GetRect(); Rect currentRect = current->GetRect(); if (currentRect.GetRight() >= focusedViewRect.GetRight()) { return false; } if (candidate != nullptr) { Rect candidateRect = candidate->GetRect(); if (IsAtSameRow(focusedViewRect, currentRect) && IsAtSameRow(focusedViewRect, candidateRect)) { return currentRect.GetRight() > candidateRect.GetRight(); } return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect); } return true; } bool FocusManager::CompareCandidatesByRight(UIView* focusedView, UIView*& candidate, UIView* current) { Rect focusedViewRect = focusedView->GetRect(); Rect currentRect = current->GetRect(); if (currentRect.GetLeft() <= focusedViewRect.GetLeft()) { return false; } if (candidate != nullptr) { Rect candidateRect = candidate->GetRect(); if (IsAtSameRow(focusedViewRect, currentRect) && IsAtSameRow(focusedViewRect, candidateRect)) { return currentRect.GetLeft() < candidateRect.GetLeft(); } return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect); } return true; } bool FocusManager::CompareCandidatesDistance(const Rect& focused, const Rect& candidate, const Rect& current) { uint64_t xDiff1 = focused.GetX() - candidate.GetX(); uint64_t yDiff1 = focused.GetY() - candidate.GetY(); uint64_t xDiff2 = focused.GetX() - current.GetX(); uint64_t yDiff2 = focused.GetY() - current.GetY(); uint64_t distance1 = xDiff1 * xDiff1 + yDiff1 * yDiff1; uint64_t distance2 = xDiff2 * xDiff2 + yDiff2 * yDiff2; return distance2 < distance1; } bool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, uint8_t direction) { UIView* parent = focusedView->GetParent(); if (parent == nullptr) { return false; } UIView* child = nullptr; bool isFoundBestCandidate = false; UIView* current = focusedView; while (parent != nullptr) { if (isFoundBestCandidate) { return true; } child = static_cast(parent)->GetChildrenHead(); while (child != nullptr) { if (child == current) { child = child->GetNextSibling(); continue; } if (child->IsViewGroup()) { if (GetNextFocus(focusedView, candidate, static_cast(child), direction)) { isFoundBestCandidate = true; } } else { if (GetNextFocus(focusedView, candidate, child, direction)) { isFoundBestCandidate = true; } } child = child->GetNextSibling(); } if (isFoundBestCandidate) { return true; } else { current = parent; } parent = parent->GetParent(); } return false; } bool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, UIView* view, uint8_t direction) { UIView* current = view; if (!current->IsVisible() || !current->IsFocusable()) { return false; } if (CompareCandidates(focusedView, candidate, current, direction)) { candidate = current; return true; } return false; } bool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, UIViewGroup* viewGroup, uint8_t direction) { UIViewGroup* current = viewGroup; if (!current->IsVisible() || !current->IsFocusable()) { return false; } if (current->IsInterceptFocus()) { return GetNextFocus(focusedView, candidate, static_cast(current), direction); } UIView* child = current->GetChildrenHead(); bool childFocusable = false; while (child != nullptr) { if (child == focusedView) { child = child->GetNextSibling(); continue; } if (child->IsViewGroup()) { if (GetNextFocus(focusedView, candidate, static_cast(child), direction)) { childFocusable = true; } } else if (GetNextFocus(focusedView, candidate, child, direction)) { childFocusable = true; } child = child->GetNextSibling(); } return childFocusable; } } #endif