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
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() {}
|