// 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 "../../../foxitlib.h" #include "include/fwl_targetimp.h" #include "include/fwl_noteimp.h" #include "include/fwl_widgetmgrimp.h" #include "include/fwl_threadimp.h" #include "include/fwl_appimp.h" #define FWL_NORMALMATRIX FX_BOOL FWL_UseOffscreen(IFWL_Widget * pWidget) { #if (_FX_OS_==_FX_MACOSX_) return FALSE; #else return pWidget->GetStyles() & FWL_WGTSTYLE_Offscreen; #endif } IFWL_WidgetMgr* FWL_GetWidgetMgr() { IFWL_App *pApp = FWL_GetApp(); _FWL_RETURN_VALUE_IF_FAIL(pApp, NULL); return pApp->GetWidgetMgr(); } CFWL_WidgetMgr::CFWL_WidgetMgr(IFWL_AdapterNative *pAdapterNative) : m_dwCapability(0) { m_pDelegate = FX_NEW CFWL_WidgetMgrDelegate(this); m_pAdapter = pAdapterNative->GetWidgetMgr((IFWL_WidgetMgrDelegate*)m_pDelegate); FXSYS_assert(m_pAdapter); CFWL_WidgetMgrItem *pRoot = FX_NEW CFWL_WidgetMgrItem; m_mapWidgetItem.SetAt(NULL, pRoot); #if (_FX_OS_==_FX_WIN32_DESKTOP_) || (_FX_OS_==_FX_WIN64_) m_rtScreen.Reset(); IFWL_AdapterMonitorMgr* pMonitorMgr = pAdapterNative->GetMonitorMgr(); if (pMonitorMgr) { FWL_HMONITOR monitor = pMonitorMgr->GetCurrentMonitor(); if (monitor) { pMonitorMgr->GetMonitorSize(monitor, m_rtScreen.width, m_rtScreen.height); } } #endif } CFWL_WidgetMgr::~CFWL_WidgetMgr() { FX_POSITION ps = m_mapWidgetItem.GetStartPosition(); while (ps) { FX_LPVOID pWidget; CFWL_WidgetMgrItem *pItem; m_mapWidgetItem.GetNextAssoc(ps, pWidget, (void*&)pItem); delete pItem; } m_mapWidgetItem.RemoveAll(); if (m_pDelegate) { delete m_pDelegate; m_pDelegate = NULL; } } int32_t CFWL_WidgetMgr::CountWidgets(IFWL_Widget *pParent ) { CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pParent); return TravelWidgetMgr(pParentItem, NULL, NULL); } IFWL_Widget* CFWL_WidgetMgr::GetWidget(int32_t nIndex, IFWL_Widget *pParent ) { CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pParent); IFWL_Widget *pWidget = NULL; TravelWidgetMgr(pParentItem, &nIndex, NULL, &pWidget); return pWidget; } IFWL_Widget* CFWL_WidgetMgr::GetWidget(IFWL_Widget *pWidget, FWL_WGTRELATION eRelation) { CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget); if (!pItem) { return NULL; } IFWL_Widget *pRet = NULL; switch (eRelation) { case FWL_WGTRELATION_Parent: { pRet = pItem->pParent ? pItem->pParent->pWidget : NULL; break; } case FWL_WGTRELATION_Owner: { pRet = pItem->pOwner ? pItem->pOwner->pWidget : NULL; break; } case FWL_WGTRELATION_FirstSibling: { pItem = pItem->pPrevious; while (pItem && pItem->pPrevious) { pItem = pItem->pPrevious; } pRet = pItem ? pItem->pWidget : NULL; break; } case FWL_WGTRELATION_PriorSibling: { pRet = pItem->pPrevious ? pItem->pPrevious->pWidget : NULL; break; } case FWL_WGTRELATION_NextSibling: { pRet = pItem->pNext ? pItem->pNext->pWidget : NULL; break; } case FWL_WGTRELATION_LastSibling: { pItem = pItem->pNext; while (pItem && pItem->pNext) { pItem = pItem->pNext; } pRet = pItem ? pItem->pWidget : NULL; break; } case FWL_WGTRELATION_FirstChild: { pRet = pItem->pChild ? pItem->pChild->pWidget : NULL; break; } case FWL_WGTRELATION_LastChild: { pItem = pItem->pChild; while (pItem && pItem->pNext) { pItem = pItem->pNext; } pRet = pItem ? pItem->pWidget : NULL; break; } case FWL_WGTRELATION_SystemForm: { while (pItem) { if (IsAbleNative(pItem->pWidget)) { pRet = pItem->pWidget; break; } pItem = pItem->pParent; } break; } default: { } } return pRet; } int32_t CFWL_WidgetMgr::GetWidgetIndex(IFWL_Widget *pWidget) { CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget); _FWL_RETURN_VALUE_IF_FAIL(pItem, -1); return TravelWidgetMgr(pItem->pParent, NULL, pItem); } FX_BOOL CFWL_WidgetMgr::SetWidgetIndex(IFWL_Widget *pWidget, int32_t nIndex) { CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget); _FWL_RETURN_VALUE_IF_FAIL(pItem, FALSE); _FWL_RETURN_VALUE_IF_FAIL(pItem->pParent, 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 = NULL; pItem->pPrevious = NULL; 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 = NULL; return TRUE; } i = 0; while(i < nIndex && pChild->pNext ) { pChild = pChild->pNext; ++i; } if (!pChild->pNext) { pChild->pNext = pItem; pItem->pPrevious = pChild; pItem->pNext = NULL; 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 = NULL; pItem->pNext = NULL; } return TRUE; } FX_BOOL CFWL_WidgetMgr::IsWidget(FX_LPVOID pObj) { _FWL_RETURN_VALUE_IF_FAIL(pObj, FALSE); return GetWidgetMgrItem((IFWL_Widget*)pObj) != NULL; } FWL_ERR CFWL_WidgetMgr::RepaintWidget(IFWL_Widget *pWidget, const CFX_RectF *pRect ) { _FWL_RETURN_VALUE_IF_FAIL(m_pAdapter, FWL_ERR_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 = GetWidget(pWidget, FWL_WGTRELATION_SystemForm); _FWL_RETURN_VALUE_IF_FAIL(pNative, FWL_ERR_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(NULL); CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pWidget); if (!pItem) { pItem = FX_NEW CFWL_WidgetMgrItem; pItem->pWidget = pWidget; m_mapWidgetItem.SetAt(pWidget, 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 = FX_NEW CFWL_WidgetMgrItem; pParentItem->pWidget = pParent; m_mapWidgetItem.SetAt(pParent, pParentItem); CFWL_WidgetMgrItem *pRoot = GetWidgetMgrItem(NULL); pParentItem->pParent = pRoot; SetWidgetIndex(pParent, -1); } CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pChild); if (!pItem) { pItem = FX_NEW CFWL_WidgetMgrItem; pItem->pWidget = pChild; m_mapWidgetItem.SetAt(pChild, 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.RemoveKey(pWidget); delete pItem; } void CFWL_WidgetMgr::SetOwner(IFWL_Widget *pOwner, IFWL_Widget *pOwned) { CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pOwner); if (!pParentItem) { pParentItem = FX_NEW CFWL_WidgetMgrItem; pParentItem->pWidget = pOwner; m_mapWidgetItem.SetAt(pOwner, pParentItem); CFWL_WidgetMgrItem *pRoot = GetWidgetMgrItem(NULL); pParentItem->pParent = pRoot; SetWidgetIndex(pOwner, -1); } CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pOwned); if (!pItem) { pItem = FX_NEW CFWL_WidgetMgrItem; pItem->pWidget = pOwned; m_mapWidgetItem.SetAt(pOwned, pItem); } pItem->pOwner = pParentItem; } void CFWL_WidgetMgr::SetParent(IFWL_Widget *pParent, IFWL_Widget *pChild) { CFWL_WidgetMgrItem *pParentItem = GetWidgetMgrItem(pParent); CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pChild); _FWL_RETURN_IF_FAIL(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->pNext = NULL; pItem->pPrevious = NULL; } pItem->pParent = pParentItem; SetWidgetIndex(pChild, -1); _FWL_RETURN_IF_FAIL(m_pAdapter); m_pAdapter->SetParentWidget(pChild, pParent); } FX_BOOL CFWL_WidgetMgr::IsChild(IFWL_Widget *pChild, IFWL_Widget *pParent) { IFWL_Widget *pTemp = pChild; do { if (pTemp == pParent) { return TRUE; } pTemp = GetWidget(pTemp, FWL_WGTRELATION_Parent); } while (pTemp); return FALSE; } FWL_ERR CFWL_WidgetMgr::CreateWidget_Native(IFWL_Widget *pWidget) { if (!IsAbleNative(pWidget)) { return FWL_ERR_Succeeded; } return m_pAdapter->CreateWidget(pWidget, pWidget->GetOwner()); } FWL_ERR CFWL_WidgetMgr::DestroyWidget_Native(IFWL_Widget *pWidget) { if (!IsAbleNative(pWidget)) { return FWL_ERR_Succeeded; } return m_pAdapter->DestroyWidget(pWidget); } FWL_ERR CFWL_WidgetMgr::GetWidgetRect_Native(IFWL_Widget *pWidget, CFX_RectF &rect) { if (!IsAbleNative(pWidget)) { return FWL_ERR_Succeeded; } return m_pAdapter->GetWidgetRect(pWidget, rect); } FWL_ERR 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) { delete pItem->pOffscreen; pItem->pOffscreen = NULL; } } } #if (_FX_OS_==_FX_WIN32_DESKTOP_) || (_FX_OS_==_FX_WIN64_) pItem->bOutsideChanged = !m_rtScreen.Contains(rect); #endif } return m_pAdapter->SetWidgetRect(pWidget, rect); } FWL_ERR CFWL_WidgetMgr::SetWidgetPosition_Native(IFWL_Widget *pWidget, FX_FLOAT fx, FX_FLOAT fy) { return m_pAdapter->SetWidgetPosition(pWidget, fx, fy); } FWL_ERR CFWL_WidgetMgr::SetWidgetIcon_Native(IFWL_Widget *pWidget, const CFX_DIBitmap *pIcon, FX_BOOL bBig) { return m_pAdapter->SetWidgetIcon(pWidget, pIcon, bBig); } FWL_ERR CFWL_WidgetMgr::SetWidgetCaption_Native(IFWL_Widget *pWidget, FX_WSTR wsCaption) { return m_pAdapter->SetWidgetCaption(pWidget, wsCaption); } FWL_ERR CFWL_WidgetMgr::SetBorderRegion_Native(IFWL_Widget *pWidget, CFX_Path *pPath) { return m_pAdapter->SetBorderRegion(pWidget, pPath); } FWL_ERR CFWL_WidgetMgr::ShowWidget_Native(IFWL_Widget *pWidget) { return m_pAdapter->ShowWidget(pWidget); } FWL_ERR CFWL_WidgetMgr::HideWidget_Native(IFWL_Widget *pWidget) { return m_pAdapter->HideWidget(pWidget); } FWL_ERR CFWL_WidgetMgr::SetNormal_Native(IFWL_Widget *pWidget) { return m_pAdapter->SetNormal(pWidget); } FWL_ERR CFWL_WidgetMgr::SetMaximize_Native(IFWL_Widget *pWidget) { return m_pAdapter->SetMaximize(pWidget); } FWL_ERR CFWL_WidgetMgr::SetMinimize_Native(IFWL_Widget *pWidget) { return m_pAdapter->SetMinimize(pWidget); } FX_BOOL CFWL_WidgetMgr::CheckMessage_Native() { return m_pAdapter->CheckMessage(); } FWL_ERR CFWL_WidgetMgr::DispatchMessage_Native() { return m_pAdapter->DispatchMessage(); } FX_BOOL CFWL_WidgetMgr::IsIdleMessage_Native() { return m_pAdapter->IsIdleMessage(); } FWL_ERR CFWL_WidgetMgr::Exit_Native(int32_t iExitCode) { return m_pAdapter->Exit(iExitCode); } FWL_ERR CFWL_WidgetMgr::CreateWidgetWithNativeId_Native(IFWL_Widget *pWidget, void *vp) { return m_pAdapter->CreateWidgetWithNativeId(pWidget, vp); } IFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(IFWL_Widget * parent, FX_FLOAT x, FX_FLOAT y) { _FWL_RETURN_VALUE_IF_FAIL(parent, NULL); FX_FLOAT x1; FX_FLOAT y1; IFWL_Widget * child = GetWidget(parent, FWL_WGTRELATION_LastChild); while (child) { if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) { x1 = x; y1 = y; CFX_Matrix matrixOnParent; child->GetMatrix(matrixOnParent); CFX_Matrix m; m.Reset(); 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 = GetWidget(child, FWL_WGTRELATION_PriorSibling); } return parent; } void CFWL_WidgetMgr::NotifySizeChanged(IFWL_Widget *pForm, FX_FLOAT fx, FX_FLOAT fy) { if (!FWL_UseOffscreen(pForm)) { return; } CFWL_WidgetMgrItem *pItem = GetWidgetMgrItem(pForm); if (pItem->pOffscreen) { delete pItem->pOffscreen; pItem->pOffscreen = NULL; } } IFWL_Widget* CFWL_WidgetMgr::nextTab(IFWL_Widget *parent, IFWL_Widget *focus, FX_BOOL &bFind) { IFWL_Widget *child = FWL_GetWidgetMgr()->GetWidget(parent, FWL_WGTRELATION_FirstChild); 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 = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling); } return NULL; } int32_t CFWL_WidgetMgr::CountRadioButtonGroup(IFWL_Widget *pFirst) { int32_t iRet = 0; IFWL_Widget *pChild = pFirst; while (pChild) { if ((pChild->GetStyles() & FWL_WGTSTYLE_Group) && pChild->GetClassID() == 3811304691) { iRet ++; } pChild = GetWidget(pChild, FWL_WGTRELATION_NextSibling); } return iRet; } IFWL_Widget* CFWL_WidgetMgr::GetSiblingRadioButton(IFWL_Widget *pWidget, FX_BOOL bNext) { while ((pWidget = GetWidget(pWidget, bNext ? FWL_WGTRELATION_NextSibling : FWL_WGTRELATION_PriorSibling)) != NULL) { if (pWidget->GetClassID() == 3811304691) { return pWidget; } } return NULL; } IFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader(IFWL_Widget *pRadioButton) { if (pRadioButton->GetStyles() & FWL_WGTSTYLE_Group) { return pRadioButton; } IFWL_Widget *pNext = pRadioButton; while ((pNext = GetSiblingRadioButton(pNext, FALSE)) != NULL) { if (pNext->GetStyles() & FWL_WGTSTYLE_Group) { return pNext; } } pNext = GetWidget(pRadioButton, FWL_WGTRELATION_LastSibling); if ((pNext->GetStyles() & FWL_WGTSTYLE_Group) && pNext->GetClassID() == 3811304691) { return pNext; } while ((pNext = GetSiblingRadioButton(pNext, FALSE)) && pNext && pNext != pRadioButton) { if (pNext->GetStyles() & FWL_WGTSTYLE_Group) { return pNext; } } pNext = GetWidget(pRadioButton, FWL_WGTRELATION_FirstSibling); if (pNext && (pNext->GetStyles() == FWL_WGTSTYLE_Group) && pNext->GetClassID() == 3811304691) { return pNext; } return GetSiblingRadioButton(pNext, TRUE); } void CFWL_WidgetMgr::GetSameGroupRadioButton(IFWL_Widget *pRadioButton, CFX_PtrArray &group) { IFWL_Widget *pFirst = GetWidget(pRadioButton, FWL_WGTRELATION_FirstSibling); if (!pFirst) { pFirst = pRadioButton; } int32_t iGroup = CountRadioButtonGroup(pFirst); if (iGroup < 2) { if (pFirst->GetClassID() == 3811304691) { group.Add(pFirst); } IFWL_Widget *pNext = pFirst; while ((pNext = GetSiblingRadioButton(pNext, TRUE)) != NULL) { group.Add(pNext); } return; } IFWL_Widget *pNext = GetRadioButtonGroupHeader(pRadioButton); do { group.Add(pNext); pNext = GetSiblingRadioButton(pNext, TRUE); if (!pNext) { if (pFirst->GetClassID() == 3811304691) { pNext = pFirst; } else { pNext = GetSiblingRadioButton(pFirst, TRUE); } } } while (pNext && ((pNext->GetStyles() & FWL_WGTSTYLE_Group) == 0)); } IFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(IFWL_Widget *pParent) { if ((pParent->GetClassID() == 3521614244) && (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { return pParent; } IFWL_Widget *child = FWL_GetWidgetMgr()->GetWidget(pParent, FWL_WGTRELATION_FirstChild); while (child) { if ((child->GetClassID() == 3521614244) && (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { return child; } IFWL_Widget *find = GetDefaultButton(child); if (find) { return find; } child = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling); } return NULL; } 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) { return (CFWL_WidgetMgrItem*)m_mapWidgetItem.GetValueAt(pWidget); } 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) { _FWL_RETURN_VALUE_IF_FAIL(pWidget, FALSE); if (!pWidget->IsInstance(FX_WSTRC(FWL_CLASS_Form))) { return FALSE; } FX_DWORD dwStyles = pWidget->GetStyles(); return ((dwStyles & FWL_WGTSTYLE_WindowTypeMask) == FWL_WGTSTYLE_OverLapper) || (dwStyles & FWL_WGTSTYLE_Popup); } FX_BOOL CFWL_WidgetMgr::IsThreadEnabled() { return !(m_dwCapability & FWL_WGTMGR_DisableThread); } FX_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) { IFWL_AdapterWidgetMgr* pSDApapter = GetAdapterWidgetMgr(); return pSDApapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor, rtPopup); } CFWL_WidgetMgrDelegate::CFWL_WidgetMgrDelegate(CFWL_WidgetMgr *pWidgetMgr) : m_pWidgetMgr(pWidgetMgr) { } FWL_ERR CFWL_WidgetMgrDelegate::OnSetCapability(FX_DWORD dwCapability ) { m_pWidgetMgr->m_dwCapability = dwCapability; return FWL_ERR_Succeeded; } int32_t CFWL_WidgetMgrDelegate::OnProcessMessageToForm(CFWL_Message *pMessage) { _FWL_RETURN_VALUE_IF_FAIL(pMessage, 0); _FWL_RETURN_VALUE_IF_FAIL(pMessage->m_pDstTarget, 0); IFWL_Widget *pDstWidget = (IFWL_Widget*)pMessage->m_pDstTarget; IFWL_NoteThread *pNoteThread = pDstWidget->GetOwnerThread(); _FWL_RETURN_VALUE_IF_FAIL(pNoteThread, 0); CFWL_NoteDriver *pNoteDriver = (CFWL_NoteDriver*)pNoteThread->GetNoteDriver(); _FWL_RETURN_VALUE_IF_FAIL(pNoteDriver, 0); if (m_pWidgetMgr->IsThreadEnabled()) { pMessage = (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 FWL_ERR_Succeeded; } FWL_ERR CFWL_WidgetMgrDelegate::OnDrawWidget(IFWL_Widget * pWidget, CFX_Graphics * pGraphics, const CFX_Matrix * pMatrix ) { _FWL_RETURN_VALUE_IF_FAIL(pWidget, FWL_ERR_Indefinite); _FWL_RETURN_VALUE_IF_FAIL(pGraphics, FWL_ERR_Indefinite); 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 FWL_ERR_Succeeded; } 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(NULL); pDelegate->OnDrawWidget(pTemp, pMatrix); pGraphics->GetClipRect(clipBounds); clipCopy = clipBounds; #elif (_FX_OS_==_FX_MACOSX_) if (m_pWidgetMgr->IsFormDisabled()) { IFWL_WidgetDelegate *pDelegate = pWidget->SetDelegate(NULL); pDelegate->OnDrawWidget(pTemp, pMatrix); pGraphics->GetClipRect(clipBounds); clipCopy = clipBounds; } else { clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d); ((CFX_Matrix*)pMatrix)->Reset(); #ifdef FWL_UseMacSystemBorder #else #endif { IFWL_WidgetDelegate *pDelegate = pWidget->SetDelegate(NULL); pDelegate->OnDrawWidget(pTemp, pMatrix); } } #endif 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); return FWL_ERR_Succeeded; } void CFWL_WidgetMgrDelegate::DrawChild(IFWL_Widget* parent, const CFX_RectF& rtClip, CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix ) { _FWL_RETURN_IF_FAIL(parent); FX_BOOL bFormDisable = m_pWidgetMgr->IsFormDisabled(); IFWL_Widget* pNextChild = m_pWidgetMgr->GetWidget(parent, FWL_WGTRELATION_FirstChild); while (pNextChild) { IFWL_Widget* child = pNextChild; pNextChild = m_pWidgetMgr->GetWidget(child, FWL_WGTRELATION_NextSibling); 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(NULL); 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->GetWidget(child, FWL_WGTRELATION_NextSibling); } } 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 = FX_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; } 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, rtClip.left, rtClip.top, rtClip, (CFX_Matrix*)pMatrix); #ifdef _WIN32 pItem->pOffscreen->ClearClip(); #endif } CFWL_WidgetMgrItem *pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget); pItem->iRedrawCounter = 0; } #define FWL_NEEDREPAINTHIT_Point 12 #define FWL_NEEDREPAINTHIT_Piece 3 typedef struct _FWL_NeedRepaintHitData { CFX_PointF hitPoint; FX_BOOL bNotNeedRepaint; FX_BOOL bNotContainByDirty; } FWL_NeedRepaintHitData; 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 = FWL_GetWidgetMgr()->GetWidget(pWidget, FWL_WGTRELATION_FirstChild); if (!pChild) { return TRUE; } if (pChild->GetClassID() == 3150298670) { CFX_RectF rtTemp; pChild->GetWidgetRect(rtTemp); if (rtTemp.width >= rtWidget.width && rtTemp.height >= rtWidget.height) { pChild = FWL_GetWidgetMgr()->GetWidget(pChild, FWL_WGTRELATION_FirstChild); 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[FWL_NEEDREPAINTHIT_Point]; static int32_t iSize = sizeof(FWL_NeedRepaintHitData); FXSYS_memset(hitPoint, 0, iSize); FX_FLOAT fxPiece = rtWidget.width / FWL_NEEDREPAINTHIT_Piece; FX_FLOAT fyPiece = rtWidget.height / FWL_NEEDREPAINTHIT_Piece; 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 < FWL_NEEDREPAINTHIT_Point; 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; } } } while ((pChild = FWL_GetWidgetMgr()->GetWidget(pChild, FWL_WGTRELATION_NextSibling)) != NULL); if (!bChildIntersectWithDirty) { return TRUE; } if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) { return TRUE; } if (rtChilds.IsEmpty()) { return TRUE; } int32_t repaintPoint = FWL_NEEDREPAINTHIT_Point; for (int32_t i = 0; i < FWL_NEEDREPAINTHIT_Point; 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; } static void FWL_WriteBMP(CFX_DIBitmap* pBitmap, FX_LPCSTR filename) { FILE* file = fopen(filename, "wb"); if (file == NULL) { return; } int size = 14 + 40 + pBitmap->GetPitch() * pBitmap->GetHeight(); unsigned char buffer[40]; buffer[0] = 'B'; buffer[1] = 'M'; buffer[2] = (unsigned char)size; buffer[3] = (unsigned char)(size >> 8); buffer[4] = (unsigned char)(size >> 16); buffer[5] = (unsigned char)(size >> 24); buffer[6] = buffer[7] = buffer[8] = buffer[9] = 0; buffer[10] = 54; buffer[11] = buffer[12] = buffer[13] = 0; fwrite(buffer, 14, 1, file); memset(buffer, 0, 40); buffer[0] = 40; buffer[4] = (unsigned char)pBitmap->GetWidth(); buffer[5] = (unsigned char)(pBitmap->GetWidth() >> 8); buffer[6] = (unsigned char)(pBitmap->GetWidth() >> 16); buffer[7] = (unsigned char)(pBitmap->GetWidth() >> 24); buffer[8] = (unsigned char)(-pBitmap->GetHeight()); buffer[9] = (unsigned char)((-pBitmap->GetHeight()) >> 8); buffer[10] = (unsigned char)((-pBitmap->GetHeight()) >> 16); buffer[11] = (unsigned char)((-pBitmap->GetHeight()) >> 24); buffer[12] = 1; buffer[14] = pBitmap->GetBPP(); fwrite(buffer, 40, 1, file); for (int row = 0; row < pBitmap->GetHeight(); row ++) { FX_LPBYTE scan_line = pBitmap->GetBuffer() + row * pBitmap->GetPitch(); fwrite(scan_line, pBitmap->GetPitch(), 1, file); } fclose(file); } FWL_ERR FWL_WidgetMgrSnapshot(IFWL_Widget *pWidget, const CFX_WideString *saveFile, const CFX_Matrix *pMatrix) { CFX_RectF r; pWidget->GetWidgetRect(r); CFX_Graphics gs; gs.Create((int32_t)r.width, (int32_t)r.height, FXDIB_Argb); CFWL_WidgetMgr *widgetMgr = (CFWL_WidgetMgr*)FWL_GetWidgetMgr(); CFWL_WidgetMgrDelegate *delegate = widgetMgr->GetDelegate(); delegate->OnDrawWidget(pWidget, &gs, pMatrix); CFX_DIBitmap *dib = gs.GetRenderDevice()->GetBitmap(); FWL_WriteBMP(dib, saveFile->UTF8Encode()); return FWL_ERR_Succeeded; } FX_BOOL FWL_WidgetIsChild(IFWL_Widget *parent, IFWL_Widget *find) { if (!find) { return FALSE; } IFWL_Widget *child = FWL_GetWidgetMgr()->GetWidget(parent, FWL_WGTRELATION_FirstChild); while (child) { if (child == find) { return TRUE; } if (FWL_WidgetIsChild(child, find)) { return TRUE; } child = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling); } return FALSE; }