// 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/core/cfwl_widgetmgr.h"
|
|
#include "xfa/fwl/core/cfwl_message.h"
|
#include "xfa/fwl/core/fwl_appimp.h"
|
#include "xfa/fwl/core/fwl_noteimp.h"
|
#include "xfa/fwl/core/fwl_widgetimp.h"
|
#include "xfa/fwl/core/ifwl_app.h"
|
#include "xfa/fwl/core/ifwl_form.h"
|
#include "xfa/fxfa/app/xfa_fwladapter.h"
|
#include "xfa/fxfa/include/xfa_ffapp.h"
|
|
namespace {
|
|
const int kNeedRepaintHitPoints = 12;
|
const int kNeedRepaintHitPiece = 3;
|
|
struct FWL_NEEDREPAINTHITDATA {
|
CFX_PointF hitPoint;
|
bool bNotNeedRepaint;
|
bool bNotContainByDirty;
|
};
|
|
} // namespace
|
|
FX_BOOL FWL_UseOffscreen(IFWL_Widget* pWidget) {
|
#if (_FX_OS_ == _FX_MACOSX_)
|
return FALSE;
|
#else
|
return pWidget->GetStyles() & FWL_WGTSTYLE_Offscreen;
|
#endif
|
}
|
|
// static
|
CFWL_WidgetMgr* CFWL_WidgetMgr::GetInstance() {
|
IFWL_App* pApp = FWL_GetApp();
|
return pApp ? pApp->GetWidgetMgr() : nullptr;
|
}
|
|
CFWL_WidgetMgr::CFWL_WidgetMgr(CXFA_FFApp* pAdapterNative)
|
: m_dwCapability(0),
|
m_pDelegate(new CFWL_WidgetMgrDelegate(this)),
|
m_pAdapter(pAdapterNative->GetWidgetMgr(m_pDelegate.get())) {
|
ASSERT(m_pAdapter);
|
m_mapWidgetItem[nullptr].reset(new CFWL_WidgetMgrItem);
|
#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
|
m_rtScreen.Reset();
|
#endif
|
}
|
|
CFWL_WidgetMgr::~CFWL_WidgetMgr() {}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetParentWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
return pItem && pItem->pOwner ? pItem->pOwner->pWidget : nullptr;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetFirstSiblingWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
pItem = pItem ? pItem->pPrevious : nullptr; // Not self.
|
while (pItem && pItem->pPrevious)
|
pItem = pItem->pPrevious;
|
|
return pItem ? pItem->pWidget : nullptr;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
return pItem && pItem->pPrevious ? pItem->pPrevious->pWidget : nullptr;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
return pItem && pItem->pNext ? pItem->pNext->pWidget : nullptr;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetLastSiblingWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
pItem = pItem ? pItem->pNext : nullptr; // Not self.
|
while (pItem && pItem->pNext)
|
pItem = pItem->pNext;
|
|
return pItem ? pItem->pWidget : nullptr;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
return pItem && pItem->pChild ? pItem->pChild->pWidget : nullptr;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
pItem = pItem ? pItem->pChild : nullptr;
|
while (pItem && pItem->pNext)
|
pItem = pItem->pNext;
|
|
return pItem ? pItem->pWidget : nullptr;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetSystemFormWidget(IFWL_Widget* pWidget) const {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
while (pItem) {
|
if (IsAbleNative(pItem->pWidget))
|
return pItem->pWidget;
|
pItem = pItem->pParent;
|
}
|
return nullptr;
|
}
|
|
FX_BOOL CFWL_WidgetMgr::SetWidgetIndex(IFWL_Widget* pWidget, int32_t nIndex) {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
if (!pItem)
|
return FALSE;
|
if (!pItem->pParent)
|
return FALSE;
|
CFWL_WidgetMgrItem* pChild = pItem->pParent->pChild;
|
int32_t i = 0;
|
while (pChild) {
|
if (pChild == pItem) {
|
if (i == nIndex) {
|
return TRUE;
|
}
|
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) {
|
if (nIndex < 0) {
|
while (pChild->pNext) {
|
pChild = pChild->pNext;
|
}
|
pChild->pNext = pItem;
|
pItem->pPrevious = pChild;
|
pItem->pNext = nullptr;
|
return TRUE;
|
}
|
i = 0;
|
while (i < nIndex && pChild->pNext) {
|
pChild = pChild->pNext;
|
++i;
|
}
|
if (!pChild->pNext) {
|
pChild->pNext = pItem;
|
pItem->pPrevious = pChild;
|
pItem->pNext = nullptr;
|
return TRUE;
|
}
|
if (pChild->pPrevious) {
|
pItem->pPrevious = pChild->pPrevious;
|
pChild->pPrevious->pNext = pItem;
|
}
|
pChild->pPrevious = pItem;
|
pItem->pNext = pChild;
|
if (pItem->pParent->pChild == pChild) {
|
pItem->pParent->pChild = pItem;
|
}
|
} else {
|
pItem->pParent->pChild = pItem;
|
pItem->pPrevious = nullptr;
|
pItem->pNext = nullptr;
|
}
|
return TRUE;
|
}
|
FWL_Error CFWL_WidgetMgr::RepaintWidget(IFWL_Widget* pWidget,
|
const CFX_RectF* pRect) {
|
if (!m_pAdapter)
|
return FWL_Error::Indefinite;
|
IFWL_Widget* pNative = pWidget;
|
CFX_RectF rect(*pRect);
|
if (IsFormDisabled()) {
|
IFWL_Widget* pOuter = pWidget->GetOuter();
|
while (pOuter) {
|
CFX_RectF rtTemp;
|
pNative->GetWidgetRect(rtTemp);
|
rect.left += rtTemp.left;
|
rect.top += rtTemp.top;
|
pNative = pOuter;
|
pOuter = pOuter->GetOuter();
|
}
|
} else if (!IsAbleNative(pWidget)) {
|
pNative = GetSystemFormWidget(pWidget);
|
if (!pNative)
|
return FWL_Error::Indefinite;
|
pWidget->TransformTo(pNative, rect.left, rect.top);
|
}
|
AddRedrawCounts(pNative);
|
return m_pAdapter->RepaintWidget(pNative, &rect);
|
}
|
void CFWL_WidgetMgr::AddWidget(IFWL_Widget* pWidget) {
|
CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(nullptr);
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
if (!pItem) {
|
pItem = new CFWL_WidgetMgrItem(pWidget);
|
m_mapWidgetItem[pWidget].reset(pItem);
|
}
|
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;
|
SetWidgetIndex(pWidget, -1);
|
}
|
void CFWL_WidgetMgr::InsertWidget(IFWL_Widget* pParent,
|
IFWL_Widget* pChild,
|
int32_t nIndex) {
|
CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pParent);
|
if (!pParentItem) {
|
pParentItem = new CFWL_WidgetMgrItem(pParent);
|
m_mapWidgetItem[pParent].reset(pParentItem);
|
pParentItem->pParent = GetWidgetMgrItem(nullptr);
|
SetWidgetIndex(pParent, -1);
|
}
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pChild);
|
if (!pItem) {
|
pItem = new CFWL_WidgetMgrItem(pChild);
|
m_mapWidgetItem[pChild].reset(pItem);
|
}
|
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;
|
SetWidgetIndex(pChild, nIndex);
|
}
|
void CFWL_WidgetMgr::RemoveWidget(IFWL_Widget* pWidget) {
|
CFWL_WidgetMgrItem* 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;
|
}
|
CFWL_WidgetMgrItem* pChild = pItem->pChild;
|
while (pChild) {
|
CFWL_WidgetMgrItem* pNext = pChild->pNext;
|
RemoveWidget(pChild->pWidget);
|
pChild = pNext;
|
}
|
m_mapWidgetItem.erase(pWidget);
|
}
|
void CFWL_WidgetMgr::SetOwner(IFWL_Widget* pOwner, IFWL_Widget* pOwned) {
|
CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pOwner);
|
if (!pParentItem) {
|
pParentItem = new CFWL_WidgetMgrItem(pOwner);
|
m_mapWidgetItem[pOwner].reset(pParentItem);
|
pParentItem->pParent = GetWidgetMgrItem(nullptr);
|
SetWidgetIndex(pOwner, -1);
|
}
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pOwned);
|
if (!pItem) {
|
pItem = new CFWL_WidgetMgrItem(pOwned);
|
m_mapWidgetItem[pOwned].reset(pItem);
|
}
|
pItem->pOwner = pParentItem;
|
}
|
void CFWL_WidgetMgr::SetParent(IFWL_Widget* pParent, IFWL_Widget* pChild) {
|
CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pParent);
|
CFWL_WidgetMgrItem* 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;
|
SetWidgetIndex(pChild, -1);
|
}
|
|
FX_BOOL CFWL_WidgetMgr::IsChild(IFWL_Widget* pChild, IFWL_Widget* pParent) {
|
IFWL_Widget* pTemp = pChild;
|
do {
|
if (pTemp == pParent)
|
return TRUE;
|
pTemp = GetParentWidget(pTemp);
|
} while (pTemp);
|
return FALSE;
|
}
|
|
FWL_Error CFWL_WidgetMgr::SetWidgetRect_Native(IFWL_Widget* pWidget,
|
const CFX_RectF& rect) {
|
if (FWL_UseOffscreen(pWidget)) {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
pItem->iRedrawCounter++;
|
if (pItem->pOffscreen) {
|
CFX_RenderDevice* pDevice = pItem->pOffscreen->GetRenderDevice();
|
if (pDevice && pDevice->GetBitmap()) {
|
CFX_DIBitmap* pBitmap = pDevice->GetBitmap();
|
if (pBitmap->GetWidth() - rect.width > 1 ||
|
pBitmap->GetHeight() - rect.height > 1) {
|
pItem->pOffscreen.reset();
|
}
|
}
|
}
|
#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
|
pItem->bOutsideChanged = !m_rtScreen.Contains(rect);
|
#endif
|
}
|
return FWL_Error::Succeeded;
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(IFWL_Widget* parent,
|
FX_FLOAT x,
|
FX_FLOAT y) {
|
if (!parent)
|
return nullptr;
|
FX_FLOAT x1;
|
FX_FLOAT y1;
|
IFWL_Widget* child = GetLastChildWidget(parent);
|
while (child) {
|
if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) {
|
x1 = x;
|
y1 = y;
|
CFX_Matrix matrixOnParent;
|
child->GetMatrix(matrixOnParent);
|
CFX_Matrix m;
|
m.SetIdentity();
|
m.SetReverse(matrixOnParent);
|
m.TransformPoint(x1, y1);
|
CFX_RectF bounds;
|
child->GetWidgetRect(bounds);
|
if (bounds.Contains(x1, y1)) {
|
x1 -= bounds.left;
|
y1 -= bounds.top;
|
return GetWidgetAtPoint(child, x1, y1);
|
}
|
}
|
child = GetPriorSiblingWidget(child);
|
}
|
return parent;
|
}
|
|
void CFWL_WidgetMgr::NotifySizeChanged(IFWL_Widget* pForm,
|
FX_FLOAT fx,
|
FX_FLOAT fy) {
|
if (FWL_UseOffscreen(pForm))
|
GetWidgetMgrItem(pForm)->pOffscreen.reset();
|
}
|
|
IFWL_Widget* CFWL_WidgetMgr::nextTab(IFWL_Widget* parent,
|
IFWL_Widget* focus,
|
FX_BOOL& bFind) {
|
CFWL_WidgetMgr* pMgr = CFWL_WidgetMgr::GetInstance();
|
IFWL_Widget* child = pMgr->GetFirstChildWidget(parent);
|
while (child) {
|
if (focus == child)
|
bFind = TRUE;
|
|
if ((child->GetStyles() & FWL_WGTSTYLE_TabStop) &&
|
(!focus || (focus != child && bFind))) {
|
return child;
|
}
|
IFWL_Widget* bRet = nextTab(child, focus, bFind);
|
if (bRet)
|
return bRet;
|
|
child = pMgr->GetNextSiblingWidget(child);
|
}
|
return nullptr;
|
}
|
|
int32_t CFWL_WidgetMgr::CountRadioButtonGroup(IFWL_Widget* pFirst) {
|
int32_t iRet = 0;
|
IFWL_Widget* pChild = pFirst;
|
while (pChild) {
|
pChild = GetNextSiblingWidget(pChild);
|
++iRet;
|
}
|
return iRet;
|
}
|
IFWL_Widget* CFWL_WidgetMgr::GetSiblingRadioButton(IFWL_Widget* pWidget,
|
FX_BOOL bNext) {
|
return nullptr;
|
}
|
IFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader(
|
IFWL_Widget* pRadioButton) {
|
IFWL_Widget* pNext = pRadioButton;
|
while (pNext) {
|
if (pNext->GetStyles() & FWL_WGTSTYLE_Group)
|
return pNext;
|
pNext = GetSiblingRadioButton(pNext, FALSE);
|
}
|
pNext = GetLastSiblingWidget(pRadioButton);
|
while ((pNext = GetSiblingRadioButton(pNext, FALSE)) != nullptr &&
|
pNext != pRadioButton) {
|
if (pNext->GetStyles() & FWL_WGTSTYLE_Group)
|
return pNext;
|
}
|
pNext = GetFirstSiblingWidget(pRadioButton);
|
return GetSiblingRadioButton(pNext, TRUE);
|
}
|
void CFWL_WidgetMgr::GetSameGroupRadioButton(
|
IFWL_Widget* pRadioButton,
|
CFX_ArrayTemplate<IFWL_Widget*>& group) {
|
IFWL_Widget* pFirst = GetFirstSiblingWidget(pRadioButton);
|
if (!pFirst) {
|
pFirst = pRadioButton;
|
}
|
int32_t iGroup = CountRadioButtonGroup(pFirst);
|
if (iGroup < 2) {
|
IFWL_Widget* pNext = pFirst;
|
while ((pNext = GetSiblingRadioButton(pNext, TRUE)) != nullptr) {
|
group.Add(pNext);
|
}
|
return;
|
}
|
IFWL_Widget* pNext = GetRadioButtonGroupHeader(pRadioButton);
|
do {
|
group.Add(pNext);
|
pNext = GetSiblingRadioButton(pNext, TRUE);
|
if (!pNext)
|
pNext = GetSiblingRadioButton(pFirst, TRUE);
|
} while (pNext && ((pNext->GetStyles() & FWL_WGTSTYLE_Group) == 0));
|
}
|
IFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(IFWL_Widget* pParent) {
|
if ((pParent->GetClassID() == FWL_Type::PushButton) &&
|
(pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
|
return pParent;
|
}
|
IFWL_Widget* child =
|
CFWL_WidgetMgr::GetInstance()->GetFirstChildWidget(pParent);
|
while (child) {
|
if ((child->GetClassID() == FWL_Type::PushButton) &&
|
(child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
|
return child;
|
}
|
IFWL_Widget* find = GetDefaultButton(child);
|
if (find) {
|
return find;
|
}
|
child = CFWL_WidgetMgr::GetInstance()->GetNextSiblingWidget(child);
|
}
|
return nullptr;
|
}
|
void CFWL_WidgetMgr::AddRedrawCounts(IFWL_Widget* pWidget) {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
(pItem->iRedrawCounter)++;
|
}
|
void CFWL_WidgetMgr::ResetRedrawCounts(IFWL_Widget* pWidget) {
|
CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
|
pItem->iRedrawCounter = 0;
|
}
|
CFWL_WidgetMgrItem* CFWL_WidgetMgr::GetWidgetMgrItem(
|
IFWL_Widget* pWidget) const {
|
auto it = m_mapWidgetItem.find(pWidget);
|
return it != m_mapWidgetItem.end()
|
? static_cast<CFWL_WidgetMgrItem*>(it->second.get())
|
: nullptr;
|
}
|
int32_t CFWL_WidgetMgr::TravelWidgetMgr(CFWL_WidgetMgrItem* pParent,
|
int32_t* pIndex,
|
CFWL_WidgetMgrItem* pItem,
|
IFWL_Widget** pWidget) {
|
if (!pParent) {
|
return 0;
|
}
|
int32_t iCount = 0;
|
CFWL_WidgetMgrItem* pChild = pParent->pChild;
|
while (pChild) {
|
iCount++;
|
if (pIndex) {
|
if (*pIndex == 0) {
|
*pWidget = pChild->pWidget;
|
return iCount;
|
}
|
pIndex--;
|
}
|
if (pItem && pItem == pChild) {
|
return iCount - 1;
|
}
|
pChild = pChild->pNext;
|
}
|
if (pIndex) {
|
return 0;
|
} else if (pItem) {
|
return -1;
|
}
|
return iCount - 1;
|
}
|
|
FX_BOOL CFWL_WidgetMgr::IsAbleNative(IFWL_Widget* pWidget) const {
|
if (!pWidget)
|
return FALSE;
|
if (!pWidget->IsInstance(FX_WSTRC(FWL_CLASS_Form))) {
|
return FALSE;
|
}
|
uint32_t dwStyles = pWidget->GetStyles();
|
return ((dwStyles & FWL_WGTSTYLE_WindowTypeMask) ==
|
FWL_WGTSTYLE_OverLapper) ||
|
(dwStyles & FWL_WGTSTYLE_Popup);
|
}
|
|
bool CFWL_WidgetMgr::IsThreadEnabled() {
|
return !(m_dwCapability & FWL_WGTMGR_DisableThread);
|
}
|
|
bool CFWL_WidgetMgr::IsFormDisabled() {
|
return !!(m_dwCapability & FWL_WGTMGR_DisableForm);
|
}
|
|
FX_BOOL CFWL_WidgetMgr::GetAdapterPopupPos(IFWL_Widget* pWidget,
|
FX_FLOAT fMinHeight,
|
FX_FLOAT fMaxHeight,
|
const CFX_RectF& rtAnchor,
|
CFX_RectF& rtPopup) {
|
CXFA_FWLAdapterWidgetMgr* pSDApapter = GetAdapterWidgetMgr();
|
return pSDApapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor,
|
rtPopup);
|
}
|
CFWL_WidgetMgrDelegate::CFWL_WidgetMgrDelegate(CFWL_WidgetMgr* pWidgetMgr)
|
: m_pWidgetMgr(pWidgetMgr) {}
|
FWL_Error CFWL_WidgetMgrDelegate::OnSetCapability(uint32_t dwCapability) {
|
m_pWidgetMgr->m_dwCapability = dwCapability;
|
return FWL_Error::Succeeded;
|
}
|
|
void CFWL_WidgetMgrDelegate::OnProcessMessageToForm(CFWL_Message* pMessage) {
|
if (!pMessage)
|
return;
|
if (!pMessage->m_pDstTarget)
|
return;
|
|
IFWL_Widget* pDstWidget = pMessage->m_pDstTarget;
|
IFWL_App* pApp = pDstWidget->GetOwnerApp();
|
if (!pApp)
|
return;
|
|
CFWL_NoteDriver* pNoteDriver =
|
static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
|
if (!pNoteDriver)
|
return;
|
|
if (m_pWidgetMgr->IsThreadEnabled())
|
pMessage = static_cast<CFWL_Message*>(pMessage->Clone());
|
if (m_pWidgetMgr->IsFormDisabled())
|
pNoteDriver->ProcessMessage(pMessage);
|
else
|
pNoteDriver->QueueMessage(pMessage);
|
|
#if (_FX_OS_ == _FX_MACOSX_)
|
CFWL_NoteLoop* pTopLoop = pNoteDriver->GetTopLoop();
|
if (pTopLoop)
|
pNoteDriver->UnqueueMessage(pTopLoop);
|
#endif
|
|
if (m_pWidgetMgr->IsThreadEnabled())
|
pMessage->Release();
|
|
return;
|
}
|
|
void CFWL_WidgetMgrDelegate::OnDrawWidget(IFWL_Widget* pWidget,
|
CFX_Graphics* pGraphics,
|
const CFX_Matrix* pMatrix) {
|
if (!pWidget || !pGraphics)
|
return;
|
|
CFX_Graphics* pTemp = DrawWidgetBefore(pWidget, pGraphics, pMatrix);
|
CFX_RectF clipCopy;
|
pWidget->GetWidgetRect(clipCopy);
|
clipCopy.left = clipCopy.top = 0;
|
if (bUseOffscreenDirect(pWidget)) {
|
DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix);
|
return;
|
}
|
CFX_RectF clipBounds;
|
|
#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ || \
|
_FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_ANDROID_
|
IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(nullptr);
|
pDelegate->OnDrawWidget(pTemp, pMatrix);
|
pGraphics->GetClipRect(clipBounds);
|
clipCopy = clipBounds;
|
#elif _FX_OS_ == _FX_MACOSX_
|
if (m_pWidgetMgr->IsFormDisabled()) {
|
IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(nullptr);
|
pDelegate->OnDrawWidget(pTemp, pMatrix);
|
pGraphics->GetClipRect(clipBounds);
|
clipCopy = clipBounds;
|
} else {
|
clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d);
|
const_cast<CFX_Matrix*>(pMatrix)->SetIdentity(); // FIXME: const cast.
|
IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(nullptr);
|
pDelegate->OnDrawWidget(pTemp, pMatrix);
|
}
|
#endif // _FX_OS_ == _FX_MACOSX_
|
|
if (!m_pWidgetMgr->IsFormDisabled()) {
|
CFX_RectF rtClient;
|
pWidget->GetClientRect(rtClient);
|
clipBounds.Intersect(rtClient);
|
}
|
if (!clipBounds.IsEmpty())
|
DrawChild(pWidget, clipBounds, pTemp, pMatrix);
|
|
DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix);
|
m_pWidgetMgr->ResetRedrawCounts(pWidget);
|
}
|
|
void CFWL_WidgetMgrDelegate::DrawChild(IFWL_Widget* parent,
|
const CFX_RectF& rtClip,
|
CFX_Graphics* pGraphics,
|
const CFX_Matrix* pMatrix) {
|
if (!parent)
|
return;
|
|
FX_BOOL bFormDisable = m_pWidgetMgr->IsFormDisabled();
|
IFWL_Widget* pNextChild = m_pWidgetMgr->GetFirstChildWidget(parent);
|
while (pNextChild) {
|
IFWL_Widget* child = pNextChild;
|
pNextChild = m_pWidgetMgr->GetNextSiblingWidget(child);
|
if (child->GetStates() & FWL_WGTSTATE_Invisible)
|
continue;
|
|
CFX_RectF rtWidget;
|
child->GetWidgetRect(rtWidget);
|
if (rtWidget.IsEmpty())
|
continue;
|
|
CFX_Matrix widgetMatrix;
|
CFX_RectF clipBounds(rtWidget);
|
if (!bFormDisable)
|
child->GetMatrix(widgetMatrix, TRUE);
|
if (pMatrix)
|
widgetMatrix.Concat(*pMatrix);
|
|
if (!bFormDisable) {
|
widgetMatrix.TransformPoint(clipBounds.left, clipBounds.top);
|
clipBounds.Intersect(rtClip);
|
if (clipBounds.IsEmpty())
|
continue;
|
|
pGraphics->SaveGraphState();
|
pGraphics->SetClipRect(clipBounds);
|
}
|
widgetMatrix.Translate(rtWidget.left, rtWidget.top, TRUE);
|
IFWL_WidgetDelegate* pDelegate = child->SetDelegate(nullptr);
|
if (pDelegate) {
|
if (m_pWidgetMgr->IsFormDisabled() ||
|
IsNeedRepaint(child, &widgetMatrix, rtClip)) {
|
pDelegate->OnDrawWidget(pGraphics, &widgetMatrix);
|
}
|
}
|
if (!bFormDisable)
|
pGraphics->RestoreGraphState();
|
|
DrawChild(child, clipBounds, pGraphics,
|
bFormDisable ? &widgetMatrix : pMatrix);
|
child = m_pWidgetMgr->GetNextSiblingWidget(child);
|
}
|
}
|
|
CFX_Graphics* CFWL_WidgetMgrDelegate::DrawWidgetBefore(
|
IFWL_Widget* pWidget,
|
CFX_Graphics* pGraphics,
|
const CFX_Matrix* pMatrix) {
|
if (!FWL_UseOffscreen(pWidget))
|
return pGraphics;
|
|
CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
|
if (!pItem->pOffscreen) {
|
pItem->pOffscreen.reset(new CFX_Graphics);
|
CFX_RectF rect;
|
pWidget->GetWidgetRect(rect);
|
pItem->pOffscreen->Create((int32_t)rect.width, (int32_t)rect.height,
|
FXDIB_Argb);
|
}
|
CFX_RectF rect;
|
pGraphics->GetClipRect(rect);
|
pItem->pOffscreen->SetClipRect(rect);
|
return pItem->pOffscreen.get();
|
}
|
|
void CFWL_WidgetMgrDelegate::DrawWidgetAfter(IFWL_Widget* pWidget,
|
CFX_Graphics* pGraphics,
|
CFX_RectF& rtClip,
|
const CFX_Matrix* pMatrix) {
|
if (FWL_UseOffscreen(pWidget)) {
|
CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
|
pGraphics->Transfer(pItem->pOffscreen.get(), rtClip.left, rtClip.top,
|
rtClip, pMatrix);
|
#ifdef _WIN32
|
pItem->pOffscreen->ClearClip();
|
#endif
|
}
|
CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
|
pItem->iRedrawCounter = 0;
|
}
|
|
FX_BOOL CFWL_WidgetMgrDelegate::IsNeedRepaint(IFWL_Widget* pWidget,
|
CFX_Matrix* pMatrix,
|
const CFX_RectF& rtDirty) {
|
CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
|
if (pItem && pItem->iRedrawCounter > 0) {
|
pItem->iRedrawCounter = 0;
|
return TRUE;
|
}
|
CFX_RectF rtWidget;
|
pWidget->GetWidgetRect(rtWidget);
|
rtWidget.left = rtWidget.top = 0;
|
pMatrix->TransformRect(rtWidget);
|
if (!rtWidget.IntersectWith(rtDirty))
|
return FALSE;
|
|
IFWL_Widget* pChild =
|
CFWL_WidgetMgr::GetInstance()->GetFirstChildWidget(pWidget);
|
if (!pChild)
|
return TRUE;
|
|
CFX_RectF rtChilds;
|
rtChilds.Empty();
|
FX_BOOL bChildIntersectWithDirty = FALSE;
|
FX_BOOL bOrginPtIntersectWidthChild = FALSE;
|
FX_BOOL bOrginPtIntersectWidthDirty =
|
rtDirty.Contains(rtWidget.left, rtWidget.top);
|
static FWL_NEEDREPAINTHITDATA hitPoint[kNeedRepaintHitPoints];
|
FXSYS_memset(hitPoint, 0, sizeof(hitPoint));
|
FX_FLOAT fxPiece = rtWidget.width / kNeedRepaintHitPiece;
|
FX_FLOAT fyPiece = rtWidget.height / kNeedRepaintHitPiece;
|
hitPoint[2].hitPoint.x = hitPoint[6].hitPoint.x = rtWidget.left;
|
hitPoint[0].hitPoint.x = hitPoint[3].hitPoint.x = hitPoint[7].hitPoint.x =
|
hitPoint[10].hitPoint.x = fxPiece + rtWidget.left;
|
hitPoint[1].hitPoint.x = hitPoint[4].hitPoint.x = hitPoint[8].hitPoint.x =
|
hitPoint[11].hitPoint.x = fxPiece * 2 + rtWidget.left;
|
hitPoint[5].hitPoint.x = hitPoint[9].hitPoint.x =
|
rtWidget.width + rtWidget.left;
|
hitPoint[0].hitPoint.y = hitPoint[1].hitPoint.y = rtWidget.top;
|
hitPoint[2].hitPoint.y = hitPoint[3].hitPoint.y = hitPoint[4].hitPoint.y =
|
hitPoint[5].hitPoint.y = fyPiece + rtWidget.top;
|
hitPoint[6].hitPoint.y = hitPoint[7].hitPoint.y = hitPoint[8].hitPoint.y =
|
hitPoint[9].hitPoint.y = fyPiece * 2 + rtWidget.top;
|
hitPoint[10].hitPoint.y = hitPoint[11].hitPoint.y =
|
rtWidget.height + rtWidget.top;
|
do {
|
CFX_RectF rect;
|
pChild->GetWidgetRect(rect);
|
CFX_RectF r = rect;
|
r.left += rtWidget.left;
|
r.top += rtWidget.top;
|
if (r.IsEmpty())
|
continue;
|
if (r.Contains(rtDirty))
|
return FALSE;
|
if (!bChildIntersectWithDirty && r.IntersectWith(rtDirty))
|
bChildIntersectWithDirty = TRUE;
|
if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild)
|
bOrginPtIntersectWidthChild = rect.Contains(0, 0);
|
|
if (rtChilds.IsEmpty())
|
rtChilds = rect;
|
else if (!(pChild->GetStates() & FWL_WGTSTATE_Invisible))
|
rtChilds.Union(rect);
|
|
for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) {
|
if (hitPoint[i].bNotContainByDirty || hitPoint[i].bNotNeedRepaint)
|
continue;
|
if (!rtDirty.Contains(hitPoint[i].hitPoint)) {
|
hitPoint[i].bNotContainByDirty = true;
|
continue;
|
}
|
if (r.Contains(hitPoint[i].hitPoint))
|
hitPoint[i].bNotNeedRepaint = true;
|
}
|
pChild = CFWL_WidgetMgr::GetInstance()->GetNextSiblingWidget(pChild);
|
} while (pChild);
|
|
if (!bChildIntersectWithDirty)
|
return TRUE;
|
if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild)
|
return TRUE;
|
if (rtChilds.IsEmpty())
|
return TRUE;
|
|
int32_t repaintPoint = kNeedRepaintHitPoints;
|
for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) {
|
if (hitPoint[i].bNotNeedRepaint)
|
repaintPoint--;
|
}
|
if (repaintPoint > 0)
|
return TRUE;
|
|
pMatrix->TransformRect(rtChilds);
|
if (rtChilds.Contains(rtDirty) || rtChilds.Contains(rtWidget))
|
return FALSE;
|
return TRUE;
|
}
|
|
FX_BOOL CFWL_WidgetMgrDelegate::bUseOffscreenDirect(IFWL_Widget* pWidget) {
|
CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
|
if (!FWL_UseOffscreen(pWidget) || !(pItem->pOffscreen))
|
return FALSE;
|
|
#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
|
if (pItem->bOutsideChanged) {
|
CFX_RectF r;
|
pWidget->GetWidgetRect(r);
|
CFX_RectF temp(m_pWidgetMgr->m_rtScreen);
|
temp.Deflate(50, 50);
|
if (!temp.Contains(r))
|
return FALSE;
|
|
pItem->bOutsideChanged = FALSE;
|
}
|
#endif
|
|
return pItem->iRedrawCounter == 0;
|
}
|
|
CFWL_WidgetMgrItem::CFWL_WidgetMgrItem() : CFWL_WidgetMgrItem(nullptr) {}
|
|
CFWL_WidgetMgrItem::CFWL_WidgetMgrItem(IFWL_Widget* widget)
|
: pParent(nullptr),
|
pOwner(nullptr),
|
pChild(nullptr),
|
pPrevious(nullptr),
|
pNext(nullptr),
|
pWidget(widget),
|
iRedrawCounter(0)
|
#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
|
,
|
bOutsideChanged(FALSE)
|
#endif
|
{
|
}
|
|
CFWL_WidgetMgrItem::~CFWL_WidgetMgrItem() {}
|