1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "xfa/src/foxitlib.h" 8 #include "xfa/src/fwl/src/core/include/fwl_targetimp.h" 9 #include "xfa/src/fwl/src/core/include/fwl_noteimp.h" 10 #include "xfa/src/fwl/src/core/include/fwl_widgetmgrimp.h" 11 #include "xfa/src/fwl/src/core/include/fwl_threadimp.h" 12 #include "xfa/src/fwl/src/core/include/fwl_appimp.h" 13 14 FX_BOOL FWL_UseOffscreen(IFWL_Widget* pWidget) { 15 #if (_FX_OS_ == _FX_MACOSX_) 16 return FALSE; 17 #else 18 return pWidget->GetStyles() & FWL_WGTSTYLE_Offscreen; 19 #endif 20 } 21 IFWL_WidgetMgr* FWL_GetWidgetMgr() { 22 IFWL_App* pApp = FWL_GetApp(); 23 if (!pApp) 24 return NULL; 25 return pApp->GetWidgetMgr(); 26 } 27 CFWL_WidgetMgr::CFWL_WidgetMgr(IFWL_AdapterNative* pAdapterNative) 28 : m_dwCapability(0) { 29 m_pDelegate = new CFWL_WidgetMgrDelegate(this); 30 m_pAdapter = pAdapterNative->GetWidgetMgr(m_pDelegate); 31 FXSYS_assert(m_pAdapter); 32 CFWL_WidgetMgrItem* pRoot = new CFWL_WidgetMgrItem; 33 m_mapWidgetItem.SetAt(NULL, pRoot); 34 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) 35 m_rtScreen.Reset(); 36 IFWL_AdapterMonitorMgr* pMonitorMgr = pAdapterNative->GetMonitorMgr(); 37 if (pMonitorMgr) { 38 FWL_HMONITOR monitor = pMonitorMgr->GetCurrentMonitor(); 39 if (monitor) { 40 pMonitorMgr->GetMonitorSize(monitor, m_rtScreen.width, m_rtScreen.height); 41 } 42 } 43 #endif 44 } 45 CFWL_WidgetMgr::~CFWL_WidgetMgr() { 46 FX_POSITION ps = m_mapWidgetItem.GetStartPosition(); 47 while (ps) { 48 void* pWidget; 49 CFWL_WidgetMgrItem* pItem; 50 m_mapWidgetItem.GetNextAssoc(ps, pWidget, (void*&)pItem); 51 delete pItem; 52 } 53 m_mapWidgetItem.RemoveAll(); 54 if (m_pDelegate) { 55 delete m_pDelegate; 56 m_pDelegate = NULL; 57 } 58 } 59 int32_t CFWL_WidgetMgr::CountWidgets(IFWL_Widget* pParent) { 60 CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pParent); 61 return TravelWidgetMgr(pParentItem, NULL, NULL); 62 } 63 IFWL_Widget* CFWL_WidgetMgr::GetWidget(int32_t nIndex, IFWL_Widget* pParent) { 64 CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pParent); 65 IFWL_Widget* pWidget = NULL; 66 TravelWidgetMgr(pParentItem, &nIndex, NULL, &pWidget); 67 return pWidget; 68 } 69 IFWL_Widget* CFWL_WidgetMgr::GetWidget(IFWL_Widget* pWidget, 70 FWL_WGTRELATION eRelation) { 71 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget); 72 if (!pItem) { 73 return NULL; 74 } 75 IFWL_Widget* pRet = NULL; 76 switch (eRelation) { 77 case FWL_WGTRELATION_Parent: { 78 pRet = pItem->pParent ? pItem->pParent->pWidget : NULL; 79 break; 80 } 81 case FWL_WGTRELATION_Owner: { 82 pRet = pItem->pOwner ? pItem->pOwner->pWidget : NULL; 83 break; 84 } 85 case FWL_WGTRELATION_FirstSibling: { 86 pItem = pItem->pPrevious; 87 while (pItem && pItem->pPrevious) { 88 pItem = pItem->pPrevious; 89 } 90 pRet = pItem ? pItem->pWidget : NULL; 91 break; 92 } 93 case FWL_WGTRELATION_PriorSibling: { 94 pRet = pItem->pPrevious ? pItem->pPrevious->pWidget : NULL; 95 break; 96 } 97 case FWL_WGTRELATION_NextSibling: { 98 pRet = pItem->pNext ? pItem->pNext->pWidget : NULL; 99 break; 100 } 101 case FWL_WGTRELATION_LastSibling: { 102 pItem = pItem->pNext; 103 while (pItem && pItem->pNext) { 104 pItem = pItem->pNext; 105 } 106 pRet = pItem ? pItem->pWidget : NULL; 107 break; 108 } 109 case FWL_WGTRELATION_FirstChild: { 110 pRet = pItem->pChild ? pItem->pChild->pWidget : NULL; 111 break; 112 } 113 case FWL_WGTRELATION_LastChild: { 114 pItem = pItem->pChild; 115 while (pItem && pItem->pNext) { 116 pItem = pItem->pNext; 117 } 118 pRet = pItem ? pItem->pWidget : NULL; 119 break; 120 } 121 case FWL_WGTRELATION_SystemForm: { 122 while (pItem) { 123 if (IsAbleNative(pItem->pWidget)) { 124 pRet = pItem->pWidget; 125 break; 126 } 127 pItem = pItem->pParent; 128 } 129 break; 130 } 131 default: {} 132 } 133 return pRet; 134 } 135 int32_t CFWL_WidgetMgr::GetWidgetIndex(IFWL_Widget* pWidget) { 136 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget); 137 if (!pItem) 138 return -1; 139 return TravelWidgetMgr(pItem->pParent, NULL, pItem); 140 } 141 FX_BOOL CFWL_WidgetMgr::SetWidgetIndex(IFWL_Widget* pWidget, int32_t nIndex) { 142 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget); 143 if (!pItem) 144 return FALSE; 145 if (!pItem->pParent) 146 return FALSE; 147 CFWL_WidgetMgrItem* pChild = pItem->pParent->pChild; 148 int32_t i = 0; 149 while (pChild) { 150 if (pChild == pItem) { 151 if (i == nIndex) { 152 return TRUE; 153 } 154 if (pChild->pPrevious) { 155 pChild->pPrevious->pNext = pChild->pNext; 156 } 157 if (pChild->pNext) { 158 pChild->pNext->pPrevious = pChild->pPrevious; 159 } 160 if (pItem->pParent->pChild == pItem) { 161 pItem->pParent->pChild = pItem->pNext; 162 } 163 pItem->pNext = NULL; 164 pItem->pPrevious = NULL; 165 break; 166 } 167 if (!pChild->pNext) { 168 break; 169 } 170 pChild = pChild->pNext; 171 ++i; 172 } 173 pChild = pItem->pParent->pChild; 174 if (pChild) { 175 if (nIndex < 0) { 176 while (pChild->pNext) { 177 pChild = pChild->pNext; 178 } 179 pChild->pNext = pItem; 180 pItem->pPrevious = pChild; 181 pItem->pNext = NULL; 182 return TRUE; 183 } 184 i = 0; 185 while (i < nIndex && pChild->pNext) { 186 pChild = pChild->pNext; 187 ++i; 188 } 189 if (!pChild->pNext) { 190 pChild->pNext = pItem; 191 pItem->pPrevious = pChild; 192 pItem->pNext = NULL; 193 return TRUE; 194 } 195 if (pChild->pPrevious) { 196 pItem->pPrevious = pChild->pPrevious; 197 pChild->pPrevious->pNext = pItem; 198 } 199 pChild->pPrevious = pItem; 200 pItem->pNext = pChild; 201 if (pItem->pParent->pChild == pChild) { 202 pItem->pParent->pChild = pItem; 203 } 204 } else { 205 pItem->pParent->pChild = pItem; 206 pItem->pPrevious = NULL; 207 pItem->pNext = NULL; 208 } 209 return TRUE; 210 } 211 FWL_ERR CFWL_WidgetMgr::RepaintWidget(IFWL_Widget* pWidget, 212 const CFX_RectF* pRect) { 213 if (!m_pAdapter) 214 return FWL_ERR_Indefinite; 215 IFWL_Widget* pNative = pWidget; 216 CFX_RectF rect(*pRect); 217 if (IsFormDisabled()) { 218 IFWL_Widget* pOuter = pWidget->GetOuter(); 219 while (pOuter) { 220 CFX_RectF rtTemp; 221 pNative->GetWidgetRect(rtTemp); 222 rect.left += rtTemp.left; 223 rect.top += rtTemp.top; 224 pNative = pOuter; 225 pOuter = pOuter->GetOuter(); 226 } 227 } else if (!IsAbleNative(pWidget)) { 228 pNative = GetWidget(pWidget, FWL_WGTRELATION_SystemForm); 229 if (!pNative) 230 return FWL_ERR_Indefinite; 231 pWidget->TransformTo(pNative, rect.left, rect.top); 232 } 233 AddRedrawCounts(pNative); 234 return m_pAdapter->RepaintWidget(pNative, &rect); 235 } 236 void CFWL_WidgetMgr::AddWidget(IFWL_Widget* pWidget) { 237 CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(NULL); 238 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget); 239 if (!pItem) { 240 pItem = new CFWL_WidgetMgrItem; 241 pItem->pWidget = pWidget; 242 m_mapWidgetItem.SetAt(pWidget, pItem); 243 } 244 if (pItem->pParent && pItem->pParent != pParentItem) { 245 if (pItem->pPrevious) { 246 pItem->pPrevious->pNext = pItem->pNext; 247 } 248 if (pItem->pNext) { 249 pItem->pNext->pPrevious = pItem->pPrevious; 250 } 251 if (pItem->pParent->pChild == pItem) { 252 pItem->pParent->pChild = pItem->pNext; 253 } 254 } 255 pItem->pParent = pParentItem; 256 SetWidgetIndex(pWidget, -1); 257 } 258 void CFWL_WidgetMgr::InsertWidget(IFWL_Widget* pParent, 259 IFWL_Widget* pChild, 260 int32_t nIndex) { 261 CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pParent); 262 if (!pParentItem) { 263 pParentItem = new CFWL_WidgetMgrItem; 264 pParentItem->pWidget = pParent; 265 m_mapWidgetItem.SetAt(pParent, pParentItem); 266 CFWL_WidgetMgrItem* pRoot = GetWidgetMgrItem(NULL); 267 pParentItem->pParent = pRoot; 268 SetWidgetIndex(pParent, -1); 269 } 270 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pChild); 271 if (!pItem) { 272 pItem = new CFWL_WidgetMgrItem; 273 pItem->pWidget = pChild; 274 m_mapWidgetItem.SetAt(pChild, pItem); 275 } 276 if (pItem->pParent && pItem->pParent != pParentItem) { 277 if (pItem->pPrevious) { 278 pItem->pPrevious->pNext = pItem->pNext; 279 } 280 if (pItem->pNext) { 281 pItem->pNext->pPrevious = pItem->pPrevious; 282 } 283 if (pItem->pParent->pChild == pItem) { 284 pItem->pParent->pChild = pItem->pNext; 285 } 286 } 287 pItem->pParent = pParentItem; 288 SetWidgetIndex(pChild, nIndex); 289 } 290 void CFWL_WidgetMgr::RemoveWidget(IFWL_Widget* pWidget) { 291 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget); 292 if (!pItem) { 293 return; 294 } 295 if (pItem->pPrevious) { 296 pItem->pPrevious->pNext = pItem->pNext; 297 } 298 if (pItem->pNext) { 299 pItem->pNext->pPrevious = pItem->pPrevious; 300 } 301 if (pItem->pParent && pItem->pParent->pChild == pItem) { 302 pItem->pParent->pChild = pItem->pNext; 303 } 304 CFWL_WidgetMgrItem* pChild = pItem->pChild; 305 while (pChild) { 306 CFWL_WidgetMgrItem* pNext = pChild->pNext; 307 RemoveWidget(pChild->pWidget); 308 pChild = pNext; 309 } 310 m_mapWidgetItem.RemoveKey(pWidget); 311 delete pItem; 312 } 313 void CFWL_WidgetMgr::SetOwner(IFWL_Widget* pOwner, IFWL_Widget* pOwned) { 314 CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pOwner); 315 if (!pParentItem) { 316 pParentItem = new CFWL_WidgetMgrItem; 317 pParentItem->pWidget = pOwner; 318 m_mapWidgetItem.SetAt(pOwner, pParentItem); 319 CFWL_WidgetMgrItem* pRoot = GetWidgetMgrItem(NULL); 320 pParentItem->pParent = pRoot; 321 SetWidgetIndex(pOwner, -1); 322 } 323 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pOwned); 324 if (!pItem) { 325 pItem = new CFWL_WidgetMgrItem; 326 pItem->pWidget = pOwned; 327 m_mapWidgetItem.SetAt(pOwned, pItem); 328 } 329 pItem->pOwner = pParentItem; 330 } 331 void CFWL_WidgetMgr::SetParent(IFWL_Widget* pParent, IFWL_Widget* pChild) { 332 CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pParent); 333 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pChild); 334 if (!pItem) 335 return; 336 if (pItem->pParent && pItem->pParent != pParentItem) { 337 if (pItem->pPrevious) { 338 pItem->pPrevious->pNext = pItem->pNext; 339 } 340 if (pItem->pNext) { 341 pItem->pNext->pPrevious = pItem->pPrevious; 342 } 343 if (pItem->pParent->pChild == pItem) { 344 pItem->pParent->pChild = pItem->pNext; 345 } 346 pItem->pNext = NULL; 347 pItem->pPrevious = NULL; 348 } 349 pItem->pParent = pParentItem; 350 SetWidgetIndex(pChild, -1); 351 if (!m_pAdapter) 352 return; 353 m_pAdapter->SetParentWidget(pChild, pParent); 354 } 355 FX_BOOL CFWL_WidgetMgr::IsChild(IFWL_Widget* pChild, IFWL_Widget* pParent) { 356 IFWL_Widget* pTemp = pChild; 357 do { 358 if (pTemp == pParent) { 359 return TRUE; 360 } 361 pTemp = GetWidget(pTemp, FWL_WGTRELATION_Parent); 362 } while (pTemp); 363 return FALSE; 364 } 365 FWL_ERR CFWL_WidgetMgr::CreateWidget_Native(IFWL_Widget* pWidget) { 366 if (!IsAbleNative(pWidget)) { 367 return FWL_ERR_Succeeded; 368 } 369 return m_pAdapter->CreateWidget(pWidget, pWidget->GetOwner()); 370 } 371 FWL_ERR CFWL_WidgetMgr::DestroyWidget_Native(IFWL_Widget* pWidget) { 372 if (!IsAbleNative(pWidget)) { 373 return FWL_ERR_Succeeded; 374 } 375 return m_pAdapter->DestroyWidget(pWidget); 376 } 377 FWL_ERR CFWL_WidgetMgr::GetWidgetRect_Native(IFWL_Widget* pWidget, 378 CFX_RectF& rect) { 379 if (!IsAbleNative(pWidget)) { 380 return FWL_ERR_Succeeded; 381 } 382 return m_pAdapter->GetWidgetRect(pWidget, rect); 383 } 384 FWL_ERR CFWL_WidgetMgr::SetWidgetRect_Native(IFWL_Widget* pWidget, 385 const CFX_RectF& rect) { 386 if (FWL_UseOffscreen(pWidget)) { 387 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget); 388 pItem->iRedrawCounter++; 389 if (pItem->pOffscreen) { 390 CFX_RenderDevice* pDevice = pItem->pOffscreen->GetRenderDevice(); 391 if (pDevice && pDevice->GetBitmap()) { 392 CFX_DIBitmap* pBitmap = pDevice->GetBitmap(); 393 if (pBitmap->GetWidth() - rect.width > 1 || 394 pBitmap->GetHeight() - rect.height > 1) { 395 delete pItem->pOffscreen; 396 pItem->pOffscreen = NULL; 397 } 398 } 399 } 400 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) 401 pItem->bOutsideChanged = !m_rtScreen.Contains(rect); 402 #endif 403 } 404 return m_pAdapter->SetWidgetRect(pWidget, rect); 405 } 406 FWL_ERR CFWL_WidgetMgr::SetWidgetPosition_Native(IFWL_Widget* pWidget, 407 FX_FLOAT fx, 408 FX_FLOAT fy) { 409 return m_pAdapter->SetWidgetPosition(pWidget, fx, fy); 410 } 411 FWL_ERR CFWL_WidgetMgr::SetWidgetIcon_Native(IFWL_Widget* pWidget, 412 const CFX_DIBitmap* pIcon, 413 FX_BOOL bBig) { 414 return m_pAdapter->SetWidgetIcon(pWidget, pIcon, bBig); 415 } 416 FWL_ERR CFWL_WidgetMgr::SetWidgetCaption_Native( 417 IFWL_Widget* pWidget, 418 const CFX_WideStringC& wsCaption) { 419 return m_pAdapter->SetWidgetCaption(pWidget, wsCaption); 420 } 421 FWL_ERR CFWL_WidgetMgr::SetBorderRegion_Native(IFWL_Widget* pWidget, 422 CFX_Path* pPath) { 423 return m_pAdapter->SetBorderRegion(pWidget, pPath); 424 } 425 FWL_ERR CFWL_WidgetMgr::ShowWidget_Native(IFWL_Widget* pWidget) { 426 return m_pAdapter->ShowWidget(pWidget); 427 } 428 FWL_ERR CFWL_WidgetMgr::HideWidget_Native(IFWL_Widget* pWidget) { 429 return m_pAdapter->HideWidget(pWidget); 430 } 431 FWL_ERR CFWL_WidgetMgr::SetNormal_Native(IFWL_Widget* pWidget) { 432 return m_pAdapter->SetNormal(pWidget); 433 } 434 FWL_ERR CFWL_WidgetMgr::SetMaximize_Native(IFWL_Widget* pWidget) { 435 return m_pAdapter->SetMaximize(pWidget); 436 } 437 FWL_ERR CFWL_WidgetMgr::SetMinimize_Native(IFWL_Widget* pWidget) { 438 return m_pAdapter->SetMinimize(pWidget); 439 } 440 FX_BOOL CFWL_WidgetMgr::CheckMessage_Native() { 441 return m_pAdapter->CheckMessage(); 442 } 443 FWL_ERR CFWL_WidgetMgr::DispatchMessage_Native() { 444 return m_pAdapter->DispatchMessage(); 445 } 446 FX_BOOL CFWL_WidgetMgr::IsIdleMessage_Native() { 447 return m_pAdapter->IsIdleMessage(); 448 } 449 FWL_ERR CFWL_WidgetMgr::Exit_Native(int32_t iExitCode) { 450 return m_pAdapter->Exit(iExitCode); 451 } 452 FWL_ERR CFWL_WidgetMgr::CreateWidgetWithNativeId_Native(IFWL_Widget* pWidget, 453 void* vp) { 454 return m_pAdapter->CreateWidgetWithNativeId(pWidget, vp); 455 } 456 IFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(IFWL_Widget* parent, 457 FX_FLOAT x, 458 FX_FLOAT y) { 459 if (!parent) 460 return NULL; 461 FX_FLOAT x1; 462 FX_FLOAT y1; 463 IFWL_Widget* child = GetWidget(parent, FWL_WGTRELATION_LastChild); 464 while (child) { 465 if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) { 466 x1 = x; 467 y1 = y; 468 CFX_Matrix matrixOnParent; 469 child->GetMatrix(matrixOnParent); 470 CFX_Matrix m; 471 m.SetIdentity(); 472 m.SetReverse(matrixOnParent); 473 m.TransformPoint(x1, y1); 474 CFX_RectF bounds; 475 child->GetWidgetRect(bounds); 476 if (bounds.Contains(x1, y1)) { 477 x1 -= bounds.left; 478 y1 -= bounds.top; 479 return GetWidgetAtPoint(child, x1, y1); 480 } 481 } 482 child = GetWidget(child, FWL_WGTRELATION_PriorSibling); 483 } 484 return parent; 485 } 486 void CFWL_WidgetMgr::NotifySizeChanged(IFWL_Widget* pForm, 487 FX_FLOAT fx, 488 FX_FLOAT fy) { 489 if (!FWL_UseOffscreen(pForm)) { 490 return; 491 } 492 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pForm); 493 if (pItem->pOffscreen) { 494 delete pItem->pOffscreen; 495 pItem->pOffscreen = NULL; 496 } 497 } 498 IFWL_Widget* CFWL_WidgetMgr::nextTab(IFWL_Widget* parent, 499 IFWL_Widget* focus, 500 FX_BOOL& bFind) { 501 IFWL_Widget* child = 502 FWL_GetWidgetMgr()->GetWidget(parent, FWL_WGTRELATION_FirstChild); 503 while (child) { 504 if (focus == child) { 505 bFind = TRUE; 506 } 507 if ((child->GetStyles() & FWL_WGTSTYLE_TabStop) && 508 (!focus || (focus != child && bFind))) { 509 return child; 510 } 511 IFWL_Widget* bRet = nextTab(child, focus, bFind); 512 if (bRet) { 513 return bRet; 514 } 515 child = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling); 516 } 517 return NULL; 518 } 519 int32_t CFWL_WidgetMgr::CountRadioButtonGroup(IFWL_Widget* pFirst) { 520 int32_t iRet = 0; 521 IFWL_Widget* pChild = pFirst; 522 while (pChild) { 523 if ((pChild->GetStyles() & FWL_WGTSTYLE_Group) && 524 pChild->GetClassID() == 3811304691) { 525 iRet++; 526 } 527 pChild = GetWidget(pChild, FWL_WGTRELATION_NextSibling); 528 } 529 return iRet; 530 } 531 IFWL_Widget* CFWL_WidgetMgr::GetSiblingRadioButton(IFWL_Widget* pWidget, 532 FX_BOOL bNext) { 533 while ((pWidget = GetWidget(pWidget, bNext ? FWL_WGTRELATION_NextSibling 534 : FWL_WGTRELATION_PriorSibling)) != 535 NULL) { 536 if (pWidget->GetClassID() == 3811304691) { 537 return pWidget; 538 } 539 } 540 return NULL; 541 } 542 IFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader( 543 IFWL_Widget* pRadioButton) { 544 if (pRadioButton->GetStyles() & FWL_WGTSTYLE_Group) { 545 return pRadioButton; 546 } 547 IFWL_Widget* pNext = pRadioButton; 548 while ((pNext = GetSiblingRadioButton(pNext, FALSE)) != NULL) { 549 if (pNext->GetStyles() & FWL_WGTSTYLE_Group) { 550 return pNext; 551 } 552 } 553 pNext = GetWidget(pRadioButton, FWL_WGTRELATION_LastSibling); 554 if ((pNext->GetStyles() & FWL_WGTSTYLE_Group) && 555 pNext->GetClassID() == 3811304691) { 556 return pNext; 557 } 558 while ((pNext = GetSiblingRadioButton(pNext, FALSE)) && pNext && 559 pNext != pRadioButton) { 560 if (pNext->GetStyles() & FWL_WGTSTYLE_Group) { 561 return pNext; 562 } 563 } 564 pNext = GetWidget(pRadioButton, FWL_WGTRELATION_FirstSibling); 565 if (pNext && (pNext->GetStyles() == FWL_WGTSTYLE_Group) && 566 pNext->GetClassID() == 3811304691) { 567 return pNext; 568 } 569 return GetSiblingRadioButton(pNext, TRUE); 570 } 571 void CFWL_WidgetMgr::GetSameGroupRadioButton(IFWL_Widget* pRadioButton, 572 CFX_PtrArray& group) { 573 IFWL_Widget* pFirst = GetWidget(pRadioButton, FWL_WGTRELATION_FirstSibling); 574 if (!pFirst) { 575 pFirst = pRadioButton; 576 } 577 int32_t iGroup = CountRadioButtonGroup(pFirst); 578 if (iGroup < 2) { 579 if (pFirst->GetClassID() == 3811304691) { 580 group.Add(pFirst); 581 } 582 IFWL_Widget* pNext = pFirst; 583 while ((pNext = GetSiblingRadioButton(pNext, TRUE)) != NULL) { 584 group.Add(pNext); 585 } 586 return; 587 } 588 IFWL_Widget* pNext = GetRadioButtonGroupHeader(pRadioButton); 589 do { 590 group.Add(pNext); 591 pNext = GetSiblingRadioButton(pNext, TRUE); 592 if (!pNext) { 593 if (pFirst->GetClassID() == 3811304691) { 594 pNext = pFirst; 595 } else { 596 pNext = GetSiblingRadioButton(pFirst, TRUE); 597 } 598 } 599 } while (pNext && ((pNext->GetStyles() & FWL_WGTSTYLE_Group) == 0)); 600 } 601 IFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(IFWL_Widget* pParent) { 602 if ((pParent->GetClassID() == 3521614244) && 603 (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { 604 return pParent; 605 } 606 IFWL_Widget* child = 607 FWL_GetWidgetMgr()->GetWidget(pParent, FWL_WGTRELATION_FirstChild); 608 while (child) { 609 if ((child->GetClassID() == 3521614244) && 610 (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { 611 return child; 612 } 613 IFWL_Widget* find = GetDefaultButton(child); 614 if (find) { 615 return find; 616 } 617 child = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling); 618 } 619 return NULL; 620 } 621 void CFWL_WidgetMgr::AddRedrawCounts(IFWL_Widget* pWidget) { 622 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget); 623 (pItem->iRedrawCounter)++; 624 } 625 void CFWL_WidgetMgr::ResetRedrawCounts(IFWL_Widget* pWidget) { 626 CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget); 627 pItem->iRedrawCounter = 0; 628 } 629 CFWL_WidgetMgrItem* CFWL_WidgetMgr::GetWidgetMgrItem(IFWL_Widget* pWidget) { 630 return static_cast<CFWL_WidgetMgrItem*>(m_mapWidgetItem.GetValueAt(pWidget)); 631 } 632 int32_t CFWL_WidgetMgr::TravelWidgetMgr(CFWL_WidgetMgrItem* pParent, 633 int32_t* pIndex, 634 CFWL_WidgetMgrItem* pItem, 635 IFWL_Widget** pWidget) { 636 if (!pParent) { 637 return 0; 638 } 639 int32_t iCount = 0; 640 CFWL_WidgetMgrItem* pChild = pParent->pChild; 641 while (pChild) { 642 iCount++; 643 if (pIndex) { 644 if (*pIndex == 0) { 645 *pWidget = pChild->pWidget; 646 return iCount; 647 } 648 pIndex--; 649 } 650 if (pItem && pItem == pChild) { 651 return iCount - 1; 652 } 653 pChild = pChild->pNext; 654 } 655 if (pIndex) { 656 return 0; 657 } else if (pItem) { 658 return -1; 659 } 660 return iCount - 1; 661 } 662 FX_BOOL CFWL_WidgetMgr::IsAbleNative(IFWL_Widget* pWidget) { 663 if (!pWidget) 664 return FALSE; 665 if (!pWidget->IsInstance(FX_WSTRC(FWL_CLASS_Form))) { 666 return FALSE; 667 } 668 FX_DWORD dwStyles = pWidget->GetStyles(); 669 return ((dwStyles & FWL_WGTSTYLE_WindowTypeMask) == 670 FWL_WGTSTYLE_OverLapper) || 671 (dwStyles & FWL_WGTSTYLE_Popup); 672 } 673 FX_BOOL CFWL_WidgetMgr::IsThreadEnabled() { 674 return !(m_dwCapability & FWL_WGTMGR_DisableThread); 675 } 676 FX_BOOL CFWL_WidgetMgr::IsFormDisabled() { 677 return m_dwCapability & FWL_WGTMGR_DisableForm; 678 } 679 FX_BOOL CFWL_WidgetMgr::GetAdapterPopupPos(IFWL_Widget* pWidget, 680 FX_FLOAT fMinHeight, 681 FX_FLOAT fMaxHeight, 682 const CFX_RectF& rtAnchor, 683 CFX_RectF& rtPopup) { 684 IFWL_AdapterWidgetMgr* pSDApapter = GetAdapterWidgetMgr(); 685 return pSDApapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor, 686 rtPopup); 687 } 688 CFWL_WidgetMgrDelegate::CFWL_WidgetMgrDelegate(CFWL_WidgetMgr* pWidgetMgr) 689 : m_pWidgetMgr(pWidgetMgr) {} 690 FWL_ERR CFWL_WidgetMgrDelegate::OnSetCapability(FX_DWORD dwCapability) { 691 m_pWidgetMgr->m_dwCapability = dwCapability; 692 return FWL_ERR_Succeeded; 693 } 694 int32_t CFWL_WidgetMgrDelegate::OnProcessMessageToForm(CFWL_Message* pMessage) { 695 if (!pMessage) 696 return 0; 697 if (!pMessage->m_pDstTarget) 698 return 0; 699 IFWL_Widget* pDstWidget = pMessage->m_pDstTarget; 700 IFWL_NoteThread* pNoteThread = pDstWidget->GetOwnerThread(); 701 if (!pNoteThread) 702 return 0; 703 CFWL_NoteDriver* pNoteDriver = 704 static_cast<CFWL_NoteDriver*>(pNoteThread->GetNoteDriver()); 705 if (!pNoteDriver) 706 return 0; 707 if (m_pWidgetMgr->IsThreadEnabled()) { 708 pMessage = static_cast<CFWL_Message*>(pMessage->Clone()); 709 } 710 if (m_pWidgetMgr->IsFormDisabled()) { 711 pNoteDriver->ProcessMessage(pMessage); 712 } else { 713 pNoteDriver->QueueMessage(pMessage); 714 } 715 #if (_FX_OS_ == _FX_MACOSX_) 716 CFWL_NoteLoop* pTopLoop = pNoteDriver->GetTopLoop(); 717 if (pTopLoop) { 718 pNoteDriver->UnqueueMessage(pTopLoop); 719 } 720 #endif 721 if (m_pWidgetMgr->IsThreadEnabled()) { 722 pMessage->Release(); 723 } 724 return FWL_ERR_Succeeded; 725 } 726 FWL_ERR CFWL_WidgetMgrDelegate::OnDrawWidget(IFWL_Widget* pWidget, 727 CFX_Graphics* pGraphics, 728 const CFX_Matrix* pMatrix) { 729 if (!pWidget) 730 return FWL_ERR_Indefinite; 731 if (!pGraphics) 732 return FWL_ERR_Indefinite; 733 CFX_Graphics* pTemp = DrawWidgetBefore(pWidget, pGraphics, pMatrix); 734 CFX_RectF clipCopy; 735 pWidget->GetWidgetRect(clipCopy); 736 clipCopy.left = clipCopy.top = 0; 737 if (bUseOffscreenDirect(pWidget)) { 738 DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix); 739 return FWL_ERR_Succeeded; 740 } 741 CFX_RectF clipBounds; 742 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) || \ 743 (_FX_OS_ == _FX_LINUX_DESKTOP_) || (_FX_OS_ == _FX_ANDROID_) 744 IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(NULL); 745 pDelegate->OnDrawWidget(pTemp, pMatrix); 746 pGraphics->GetClipRect(clipBounds); 747 clipCopy = clipBounds; 748 #elif(_FX_OS_ == _FX_MACOSX_) 749 if (m_pWidgetMgr->IsFormDisabled()) { 750 IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(NULL); 751 pDelegate->OnDrawWidget(pTemp, pMatrix); 752 pGraphics->GetClipRect(clipBounds); 753 clipCopy = clipBounds; 754 } else { 755 clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d); 756 const_cast<CFX_Matrix*>(pMatrix)->SetIdentity(); // FIXME: const cast. 757 #ifdef FWL_UseMacSystemBorder 758 #else 759 #endif 760 { 761 IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(NULL); 762 pDelegate->OnDrawWidget(pTemp, pMatrix); 763 } 764 } 765 #endif 766 if (!m_pWidgetMgr->IsFormDisabled()) { 767 CFX_RectF rtClient; 768 pWidget->GetClientRect(rtClient); 769 clipBounds.Intersect(rtClient); 770 } 771 if (!clipBounds.IsEmpty()) { 772 DrawChild(pWidget, clipBounds, pTemp, pMatrix); 773 } 774 DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix); 775 m_pWidgetMgr->ResetRedrawCounts(pWidget); 776 return FWL_ERR_Succeeded; 777 } 778 void CFWL_WidgetMgrDelegate::DrawChild(IFWL_Widget* parent, 779 const CFX_RectF& rtClip, 780 CFX_Graphics* pGraphics, 781 const CFX_Matrix* pMatrix) { 782 if (!parent) 783 return; 784 FX_BOOL bFormDisable = m_pWidgetMgr->IsFormDisabled(); 785 IFWL_Widget* pNextChild = 786 m_pWidgetMgr->GetWidget(parent, FWL_WGTRELATION_FirstChild); 787 while (pNextChild) { 788 IFWL_Widget* child = pNextChild; 789 pNextChild = m_pWidgetMgr->GetWidget(child, FWL_WGTRELATION_NextSibling); 790 if (child->GetStates() & FWL_WGTSTATE_Invisible) { 791 continue; 792 } 793 CFX_RectF rtWidget; 794 child->GetWidgetRect(rtWidget); 795 if (rtWidget.IsEmpty()) { 796 continue; 797 } 798 CFX_Matrix widgetMatrix; 799 CFX_RectF clipBounds(rtWidget); 800 if (!bFormDisable) { 801 child->GetMatrix(widgetMatrix, TRUE); 802 } 803 if (pMatrix) { 804 widgetMatrix.Concat(*pMatrix); 805 } 806 if (!bFormDisable) { 807 widgetMatrix.TransformPoint(clipBounds.left, clipBounds.top); 808 clipBounds.Intersect(rtClip); 809 if (clipBounds.IsEmpty()) { 810 continue; 811 } 812 pGraphics->SaveGraphState(); 813 pGraphics->SetClipRect(clipBounds); 814 } 815 widgetMatrix.Translate(rtWidget.left, rtWidget.top, TRUE); 816 IFWL_WidgetDelegate* pDelegate = child->SetDelegate(NULL); 817 if (pDelegate) { 818 if (m_pWidgetMgr->IsFormDisabled() || 819 IsNeedRepaint(child, &widgetMatrix, rtClip)) { 820 pDelegate->OnDrawWidget(pGraphics, &widgetMatrix); 821 } 822 } 823 if (!bFormDisable) { 824 pGraphics->RestoreGraphState(); 825 } 826 DrawChild(child, clipBounds, pGraphics, 827 bFormDisable ? &widgetMatrix : pMatrix); 828 child = m_pWidgetMgr->GetWidget(child, FWL_WGTRELATION_NextSibling); 829 } 830 } 831 CFX_Graphics* CFWL_WidgetMgrDelegate::DrawWidgetBefore( 832 IFWL_Widget* pWidget, 833 CFX_Graphics* pGraphics, 834 const CFX_Matrix* pMatrix) { 835 if (!FWL_UseOffscreen(pWidget)) { 836 return pGraphics; 837 } 838 CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget); 839 if (!pItem->pOffscreen) { 840 pItem->pOffscreen = new CFX_Graphics; 841 CFX_RectF rect; 842 pWidget->GetWidgetRect(rect); 843 pItem->pOffscreen->Create((int32_t)rect.width, (int32_t)rect.height, 844 FXDIB_Argb); 845 } 846 CFX_RectF rect; 847 pGraphics->GetClipRect(rect); 848 pItem->pOffscreen->SetClipRect(rect); 849 return pItem->pOffscreen; 850 } 851 void CFWL_WidgetMgrDelegate::DrawWidgetAfter(IFWL_Widget* pWidget, 852 CFX_Graphics* pGraphics, 853 CFX_RectF& rtClip, 854 const CFX_Matrix* pMatrix) { 855 if (FWL_UseOffscreen(pWidget)) { 856 CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget); 857 pGraphics->Transfer(pItem->pOffscreen, rtClip.left, rtClip.top, rtClip, 858 pMatrix); 859 #ifdef _WIN32 860 pItem->pOffscreen->ClearClip(); 861 #endif 862 } 863 CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget); 864 pItem->iRedrawCounter = 0; 865 } 866 #define FWL_NEEDREPAINTHIT_Point 12 867 #define FWL_NEEDREPAINTHIT_Piece 3 868 typedef struct _FWL_NeedRepaintHitData { 869 CFX_PointF hitPoint; 870 FX_BOOL bNotNeedRepaint; 871 FX_BOOL bNotContainByDirty; 872 } FWL_NeedRepaintHitData; 873 FX_BOOL CFWL_WidgetMgrDelegate::IsNeedRepaint(IFWL_Widget* pWidget, 874 CFX_Matrix* pMatrix, 875 const CFX_RectF& rtDirty) { 876 CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget); 877 if (pItem && pItem->iRedrawCounter > 0) { 878 pItem->iRedrawCounter = 0; 879 return TRUE; 880 } 881 CFX_RectF rtWidget; 882 pWidget->GetWidgetRect(rtWidget); 883 rtWidget.left = rtWidget.top = 0; 884 pMatrix->TransformRect(rtWidget); 885 if (!rtWidget.IntersectWith(rtDirty)) { 886 return FALSE; 887 } 888 IFWL_Widget* pChild = 889 FWL_GetWidgetMgr()->GetWidget(pWidget, FWL_WGTRELATION_FirstChild); 890 if (!pChild) { 891 return TRUE; 892 } 893 if (pChild->GetClassID() == 3150298670) { 894 CFX_RectF rtTemp; 895 pChild->GetWidgetRect(rtTemp); 896 if (rtTemp.width >= rtWidget.width && rtTemp.height >= rtWidget.height) { 897 pChild = 898 FWL_GetWidgetMgr()->GetWidget(pChild, FWL_WGTRELATION_FirstChild); 899 if (!pChild) { 900 return TRUE; 901 } 902 } 903 } 904 CFX_RectF rtChilds; 905 rtChilds.Empty(); 906 FX_BOOL bChildIntersectWithDirty = FALSE; 907 FX_BOOL bOrginPtIntersectWidthChild = FALSE; 908 FX_BOOL bOrginPtIntersectWidthDirty = 909 rtDirty.Contains(rtWidget.left, rtWidget.top); 910 static FWL_NeedRepaintHitData hitPoint[FWL_NEEDREPAINTHIT_Point]; 911 static int32_t iSize = sizeof(FWL_NeedRepaintHitData); 912 FXSYS_memset(hitPoint, 0, iSize); 913 FX_FLOAT fxPiece = rtWidget.width / FWL_NEEDREPAINTHIT_Piece; 914 FX_FLOAT fyPiece = rtWidget.height / FWL_NEEDREPAINTHIT_Piece; 915 hitPoint[2].hitPoint.x = hitPoint[6].hitPoint.x = rtWidget.left; 916 hitPoint[0].hitPoint.x = hitPoint[3].hitPoint.x = hitPoint[7].hitPoint.x = 917 hitPoint[10].hitPoint.x = fxPiece + rtWidget.left; 918 hitPoint[1].hitPoint.x = hitPoint[4].hitPoint.x = hitPoint[8].hitPoint.x = 919 hitPoint[11].hitPoint.x = fxPiece * 2 + rtWidget.left; 920 hitPoint[5].hitPoint.x = hitPoint[9].hitPoint.x = 921 rtWidget.width + rtWidget.left; 922 hitPoint[0].hitPoint.y = hitPoint[1].hitPoint.y = rtWidget.top; 923 hitPoint[2].hitPoint.y = hitPoint[3].hitPoint.y = hitPoint[4].hitPoint.y = 924 hitPoint[5].hitPoint.y = fyPiece + rtWidget.top; 925 hitPoint[6].hitPoint.y = hitPoint[7].hitPoint.y = hitPoint[8].hitPoint.y = 926 hitPoint[9].hitPoint.y = fyPiece * 2 + rtWidget.top; 927 hitPoint[10].hitPoint.y = hitPoint[11].hitPoint.y = 928 rtWidget.height + rtWidget.top; 929 do { 930 CFX_RectF rect; 931 pChild->GetWidgetRect(rect); 932 CFX_RectF r = rect; 933 r.left += rtWidget.left; 934 r.top += rtWidget.top; 935 if (r.IsEmpty()) { 936 continue; 937 } 938 if (r.Contains(rtDirty)) { 939 return FALSE; 940 } 941 if (!bChildIntersectWithDirty && r.IntersectWith(rtDirty)) { 942 bChildIntersectWithDirty = TRUE; 943 } 944 if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) { 945 bOrginPtIntersectWidthChild = rect.Contains(0, 0); 946 } 947 if (rtChilds.IsEmpty()) { 948 rtChilds = rect; 949 } else if (!(pChild->GetStates() & FWL_WGTSTATE_Invisible)) { 950 rtChilds.Union(rect); 951 } 952 for (int32_t i = 0; i < FWL_NEEDREPAINTHIT_Point; i++) { 953 if (hitPoint[i].bNotContainByDirty || hitPoint[i].bNotNeedRepaint) { 954 continue; 955 } 956 if (!rtDirty.Contains(hitPoint[i].hitPoint)) { 957 hitPoint[i].bNotContainByDirty = TRUE; 958 continue; 959 } 960 if (r.Contains(hitPoint[i].hitPoint)) { 961 hitPoint[i].bNotNeedRepaint = TRUE; 962 } 963 } 964 } while ((pChild = FWL_GetWidgetMgr()->GetWidget( 965 pChild, FWL_WGTRELATION_NextSibling)) != NULL); 966 if (!bChildIntersectWithDirty) { 967 return TRUE; 968 } 969 if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) { 970 return TRUE; 971 } 972 if (rtChilds.IsEmpty()) { 973 return TRUE; 974 } 975 int32_t repaintPoint = FWL_NEEDREPAINTHIT_Point; 976 for (int32_t i = 0; i < FWL_NEEDREPAINTHIT_Point; i++) { 977 if (hitPoint[i].bNotNeedRepaint) { 978 repaintPoint--; 979 } 980 } 981 if (repaintPoint > 0) { 982 return TRUE; 983 } 984 pMatrix->TransformRect(rtChilds); 985 if (rtChilds.Contains(rtDirty) || rtChilds.Contains(rtWidget)) { 986 return FALSE; 987 } 988 return TRUE; 989 } 990 FX_BOOL CFWL_WidgetMgrDelegate::bUseOffscreenDirect(IFWL_Widget* pWidget) { 991 CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget); 992 if (!FWL_UseOffscreen(pWidget) || !(pItem->pOffscreen)) { 993 return FALSE; 994 } 995 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) 996 if (pItem->bOutsideChanged) { 997 CFX_RectF r; 998 pWidget->GetWidgetRect(r); 999 CFX_RectF temp(m_pWidgetMgr->m_rtScreen); 1000 temp.Deflate(50, 50); 1001 if (!temp.Contains(r)) { 1002 return FALSE; 1003 } 1004 pItem->bOutsideChanged = FALSE; 1005 } 1006 #endif 1007 return pItem->iRedrawCounter == 0; 1008 } 1009 static void FWL_WriteBMP(CFX_DIBitmap* pBitmap, const FX_CHAR* filename) { 1010 FILE* file = fopen(filename, "wb"); 1011 if (file == NULL) { 1012 return; 1013 } 1014 int size = 14 + 40 + pBitmap->GetPitch() * pBitmap->GetHeight(); 1015 unsigned char buffer[40]; 1016 buffer[0] = 'B'; 1017 buffer[1] = 'M'; 1018 buffer[2] = (unsigned char)size; 1019 buffer[3] = (unsigned char)(size >> 8); 1020 buffer[4] = (unsigned char)(size >> 16); 1021 buffer[5] = (unsigned char)(size >> 24); 1022 buffer[6] = buffer[7] = buffer[8] = buffer[9] = 0; 1023 buffer[10] = 54; 1024 buffer[11] = buffer[12] = buffer[13] = 0; 1025 fwrite(buffer, 14, 1, file); 1026 memset(buffer, 0, 40); 1027 buffer[0] = 40; 1028 buffer[4] = (unsigned char)pBitmap->GetWidth(); 1029 buffer[5] = (unsigned char)(pBitmap->GetWidth() >> 8); 1030 buffer[6] = (unsigned char)(pBitmap->GetWidth() >> 16); 1031 buffer[7] = (unsigned char)(pBitmap->GetWidth() >> 24); 1032 buffer[8] = (unsigned char)(-pBitmap->GetHeight()); 1033 buffer[9] = (unsigned char)((-pBitmap->GetHeight()) >> 8); 1034 buffer[10] = (unsigned char)((-pBitmap->GetHeight()) >> 16); 1035 buffer[11] = (unsigned char)((-pBitmap->GetHeight()) >> 24); 1036 buffer[12] = 1; 1037 buffer[14] = pBitmap->GetBPP(); 1038 fwrite(buffer, 40, 1, file); 1039 for (int row = 0; row < pBitmap->GetHeight(); row++) { 1040 uint8_t* scan_line = pBitmap->GetBuffer() + row * pBitmap->GetPitch(); 1041 fwrite(scan_line, pBitmap->GetPitch(), 1, file); 1042 } 1043 fclose(file); 1044 } 1045 FWL_ERR FWL_WidgetMgrSnapshot(IFWL_Widget* pWidget, 1046 const CFX_WideString* saveFile, 1047 const CFX_Matrix* pMatrix) { 1048 CFX_RectF r; 1049 pWidget->GetWidgetRect(r); 1050 CFX_Graphics gs; 1051 gs.Create((int32_t)r.width, (int32_t)r.height, FXDIB_Argb); 1052 CFWL_WidgetMgr* widgetMgr = static_cast<CFWL_WidgetMgr*>(FWL_GetWidgetMgr()); 1053 CFWL_WidgetMgrDelegate* delegate = widgetMgr->GetDelegate(); 1054 delegate->OnDrawWidget(pWidget, &gs, pMatrix); 1055 CFX_DIBitmap* dib = gs.GetRenderDevice()->GetBitmap(); 1056 FWL_WriteBMP(dib, saveFile->UTF8Encode()); 1057 return FWL_ERR_Succeeded; 1058 } 1059 FX_BOOL FWL_WidgetIsChild(IFWL_Widget* parent, IFWL_Widget* find) { 1060 if (!find) { 1061 return FALSE; 1062 } 1063 IFWL_Widget* child = 1064 FWL_GetWidgetMgr()->GetWidget(parent, FWL_WGTRELATION_FirstChild); 1065 while (child) { 1066 if (child == find) { 1067 return TRUE; 1068 } 1069 if (FWL_WidgetIsChild(child, find)) { 1070 return TRUE; 1071 } 1072 child = FWL_GetWidgetMgr()->GetWidget(child, FWL_WGTRELATION_NextSibling); 1073 } 1074 return FALSE; 1075 } 1076