You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

387 lines
11 KiB

// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "xfa/fwl/cfwl_widgetmgr.h"
#include <utility>
#include "build/build_config.h"
#include "third_party/base/ptr_util.h"
#include "xfa/fwl/cfwl_app.h"
#include "xfa/fwl/cfwl_message.h"
#include "xfa/fwl/cfwl_notedriver.h"
CFWL_WidgetMgr::CFWL_WidgetMgr(AdapterIface* pAdapterNative)
: m_pAdapter(pAdapterNative) {
m_mapWidgetItem[nullptr] = pdfium::MakeUnique<Item>();
}
CFWL_WidgetMgr::~CFWL_WidgetMgr() = default;
// static
CFWL_Widget* CFWL_WidgetMgr::NextTab(CFWL_Widget* parent, CFWL_Widget* focus) {
CFWL_WidgetMgr* pMgr = parent->GetOwnerApp()->GetWidgetMgr();
CFWL_Widget* child = pMgr->GetFirstChildWidget(parent);
while (child) {
CFWL_Widget* bRet = NextTab(child, focus);
if (bRet)
return bRet;
child = pMgr->GetNextSiblingWidget(child);
}
return nullptr;
}
CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(const CFWL_Widget* pWidget) const {
Item* pItem = GetWidgetMgrItem(pWidget);
return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr;
}
CFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(const CFWL_Widget* pWidget) const {
Item* pItem = GetWidgetMgrItem(pWidget);
return pItem && pItem->pOwner ? pItem->pOwner->pWidget : nullptr;
}
CFWL_Widget* CFWL_WidgetMgr::GetFirstSiblingWidget(CFWL_Widget* pWidget) const {
Item* pItem = GetWidgetMgrItem(pWidget);
if (!pItem)
return nullptr;
pItem = pItem->pPrevious;
while (pItem && pItem->pPrevious)
pItem = pItem->pPrevious;
return pItem ? pItem->pWidget : nullptr;
}
CFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(CFWL_Widget* pWidget) const {
Item* pItem = GetWidgetMgrItem(pWidget);
return pItem && pItem->pPrevious ? pItem->pPrevious->pWidget : nullptr;
}
CFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(CFWL_Widget* pWidget) const {
Item* pItem = GetWidgetMgrItem(pWidget);
return pItem && pItem->pNext ? pItem->pNext->pWidget : nullptr;
}
CFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(CFWL_Widget* pWidget) const {
Item* pItem = GetWidgetMgrItem(pWidget);
return pItem && pItem->pChild ? pItem->pChild->pWidget : nullptr;
}
CFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(CFWL_Widget* pWidget) const {
Item* pItem = GetWidgetMgrItem(pWidget);
if (!pItem)
return nullptr;
pItem = pItem->pChild;
while (pItem && pItem->pNext)
pItem = pItem->pNext;
return pItem ? pItem->pWidget : nullptr;
}
CFWL_Widget* CFWL_WidgetMgr::GetSystemFormWidget(CFWL_Widget* pWidget) const {
Item* pItem = GetWidgetMgrItem(pWidget);
while (pItem) {
if (IsAbleNative(pItem->pWidget))
return pItem->pWidget;
pItem = pItem->pParent;
}
return nullptr;
}
void CFWL_WidgetMgr::AppendWidget(CFWL_Widget* pWidget) {
Item* pItem = GetWidgetMgrItem(pWidget);
if (!pItem)
return;
if (!pItem->pParent)
return;
Item* pChild = pItem->pParent->pChild;
int32_t i = 0;
while (pChild) {
if (pChild == pItem) {
if (pChild->pPrevious)
pChild->pPrevious->pNext = pChild->pNext;
if (pChild->pNext)
pChild->pNext->pPrevious = pChild->pPrevious;
if (pItem->pParent->pChild == pItem)
pItem->pParent->pChild = pItem->pNext;
pItem->pNext = nullptr;
pItem->pPrevious = nullptr;
break;
}
if (!pChild->pNext)
break;
pChild = pChild->pNext;
++i;
}
pChild = pItem->pParent->pChild;
if (pChild) {
while (pChild->pNext)
pChild = pChild->pNext;
pChild->pNext = pItem;
pItem->pPrevious = pChild;
} else {
pItem->pParent->pChild = pItem;
pItem->pPrevious = nullptr;
}
pItem->pNext = nullptr;
}
void CFWL_WidgetMgr::RepaintWidget(CFWL_Widget* pWidget,
const CFX_RectF& rect) {
CFWL_Widget* pNative = pWidget;
CFX_RectF transformedRect = rect;
CFWL_Widget* pOuter = pWidget->GetOuter();
while (pOuter) {
CFX_RectF rtTemp = pNative->GetWidgetRect();
transformedRect.left += rtTemp.left;
transformedRect.top += rtTemp.top;
pNative = pOuter;
pOuter = pOuter->GetOuter();
}
AddRedrawCounts(pNative);
m_pAdapter->RepaintWidget(pNative);
}
void CFWL_WidgetMgr::InsertWidget(CFWL_Widget* pParent, CFWL_Widget* pChild) {
Item* pParentItem = GetWidgetMgrItem(pParent);
if (!pParentItem) {
auto item = pdfium::MakeUnique<Item>(pParent);
pParentItem = item.get();
m_mapWidgetItem[pParent] = std::move(item);
pParentItem->pParent = GetWidgetMgrItem(nullptr);
AppendWidget(pParent);
}
Item* pItem = GetWidgetMgrItem(pChild);
if (!pItem) {
auto item = pdfium::MakeUnique<Item>(pChild);
pItem = item.get();
m_mapWidgetItem[pChild] = std::move(item);
}
if (pItem->pParent && pItem->pParent != pParentItem) {
if (pItem->pPrevious)
pItem->pPrevious->pNext = pItem->pNext;
if (pItem->pNext)
pItem->pNext->pPrevious = pItem->pPrevious;
if (pItem->pParent->pChild == pItem)
pItem->pParent->pChild = pItem->pNext;
}
pItem->pParent = pParentItem;
AppendWidget(pChild);
}
void CFWL_WidgetMgr::RemoveWidget(CFWL_Widget* pWidget) {
Item* pItem = GetWidgetMgrItem(pWidget);
if (!pItem)
return;
if (pItem->pPrevious)
pItem->pPrevious->pNext = pItem->pNext;
if (pItem->pNext)
pItem->pNext->pPrevious = pItem->pPrevious;
if (pItem->pParent && pItem->pParent->pChild == pItem)
pItem->pParent->pChild = pItem->pNext;
Item* pChild = pItem->pChild;
while (pChild) {
Item* pNext = pChild->pNext;
RemoveWidget(pChild->pWidget);
pChild = pNext;
}
m_mapWidgetItem.erase(pWidget);
}
void CFWL_WidgetMgr::SetOwner(CFWL_Widget* pOwner, CFWL_Widget* pOwned) {
Item* pParentItem = GetWidgetMgrItem(pOwner);
if (!pParentItem) {
auto item = pdfium::MakeUnique<Item>(pOwner);
pParentItem = item.get();
m_mapWidgetItem[pOwner] = std::move(item);
pParentItem->pParent = GetWidgetMgrItem(nullptr);
AppendWidget(pOwner);
}
Item* pItem = GetWidgetMgrItem(pOwned);
if (!pItem) {
auto item = pdfium::MakeUnique<Item>(pOwned);
pItem = item.get();
m_mapWidgetItem[pOwned] = std::move(item);
}
pItem->pOwner = pParentItem;
}
void CFWL_WidgetMgr::SetParent(CFWL_Widget* pParent, CFWL_Widget* pChild) {
Item* pParentItem = GetWidgetMgrItem(pParent);
Item* pItem = GetWidgetMgrItem(pChild);
if (!pItem)
return;
if (pItem->pParent && pItem->pParent != pParentItem) {
if (pItem->pPrevious)
pItem->pPrevious->pNext = pItem->pNext;
if (pItem->pNext)
pItem->pNext->pPrevious = pItem->pPrevious;
if (pItem->pParent->pChild == pItem)
pItem->pParent->pChild = pItem->pNext;
pItem->pNext = nullptr;
pItem->pPrevious = nullptr;
}
pItem->pParent = pParentItem;
AppendWidget(pChild);
}
CFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(CFWL_Widget* parent,
const CFX_PointF& point) const {
if (!parent)
return nullptr;
CFWL_Widget* child = GetLastChildWidget(parent);
while (child) {
if (child->IsVisible()) {
CFX_PointF pos = parent->GetMatrix().GetInverse().Transform(point);
CFX_RectF bounds = child->GetWidgetRect();
if (bounds.Contains(pos)) {
pos -= bounds.TopLeft();
return GetWidgetAtPoint(child, pos);
}
}
child = GetPriorSiblingWidget(child);
}
return parent;
}
CFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(CFWL_Widget* pParent) const {
if ((pParent->GetClassID() == FWL_Type::PushButton) &&
(pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
return pParent;
}
CFWL_Widget* child =
pParent->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pParent);
while (child) {
if ((child->GetClassID() == FWL_Type::PushButton) &&
(child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
return child;
}
if (CFWL_Widget* find = GetDefaultButton(child))
return find;
child = child->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(child);
}
return nullptr;
}
void CFWL_WidgetMgr::AddRedrawCounts(CFWL_Widget* pWidget) {
GetWidgetMgrItem(pWidget)->iRedrawCounter++;
}
void CFWL_WidgetMgr::ResetRedrawCounts(CFWL_Widget* pWidget) {
GetWidgetMgrItem(pWidget)->iRedrawCounter = 0;
}
CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrItem(
const CFWL_Widget* pWidget) const {
auto it = m_mapWidgetItem.find(pWidget);
return it != m_mapWidgetItem.end() ? it->second.get() : nullptr;
}
bool CFWL_WidgetMgr::IsAbleNative(CFWL_Widget* pWidget) const {
if (!pWidget || !pWidget->IsForm())
return false;
return pWidget->IsOverLapper() || pWidget->IsPopup();
}
void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget,
float fMinHeight,
float fMaxHeight,
const CFX_RectF& rtAnchor,
CFX_RectF* pPopupRect) const {
m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor,
pPopupRect);
}
void CFWL_WidgetMgr::OnProcessMessageToForm(
std::unique_ptr<CFWL_Message> pMessage) {
CFWL_Widget* pDstWidget = pMessage->GetDstTarget();
if (!pDstWidget)
return;
CFWL_NoteDriver* pNoteDriver = pDstWidget->GetOwnerApp()->GetNoteDriver();
pNoteDriver->ProcessMessage(std::move(pMessage));
}
void CFWL_WidgetMgr::OnDrawWidget(CFWL_Widget* pWidget,
CXFA_Graphics* pGraphics,
const CFX_Matrix& matrix) {
if (!pWidget || !pGraphics)
return;
CFX_RectF clipCopy(0, 0, pWidget->GetWidgetRect().Size());
CFX_RectF clipBounds;
pWidget->GetDelegate()->OnDrawWidget(pGraphics, matrix);
clipBounds = pGraphics->GetClipRect();
clipCopy = clipBounds;
if (!clipBounds.IsEmpty())
DrawChild(pWidget, clipBounds, pGraphics, &matrix);
GetWidgetMgrItem(pWidget)->iRedrawCounter = 0;
ResetRedrawCounts(pWidget);
}
void CFWL_WidgetMgr::DrawChild(CFWL_Widget* parent,
const CFX_RectF& rtClip,
CXFA_Graphics* pGraphics,
const CFX_Matrix* pMatrix) {
if (!parent)
return;
CFWL_Widget* pNextChild = GetFirstChildWidget(parent);
while (pNextChild) {
CFWL_Widget* child = pNextChild;
pNextChild = GetNextSiblingWidget(child);
if (!child->IsVisible())
continue;
CFX_RectF rtWidget = child->GetWidgetRect();
if (rtWidget.IsEmpty())
continue;
CFX_Matrix widgetMatrix;
CFX_RectF clipBounds(rtWidget);
if (pMatrix)
widgetMatrix.Concat(*pMatrix);
widgetMatrix.TranslatePrepend(rtWidget.left, rtWidget.top);
if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate())
pDelegate->OnDrawWidget(pGraphics, widgetMatrix);
DrawChild(child, clipBounds, pGraphics, &widgetMatrix);
}
}
CFWL_WidgetMgr::Item::Item() : CFWL_WidgetMgr::Item(nullptr) {}
CFWL_WidgetMgr::Item::Item(CFWL_Widget* widget)
: pParent(nullptr),
pOwner(nullptr),
pChild(nullptr),
pPrevious(nullptr),
pNext(nullptr),
pWidget(widget),
iRedrawCounter(0) {}
CFWL_WidgetMgr::Item::~Item() {}