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 "../../include/pdfwindow/PDFWindow.h" 8#include "../../include/pdfwindow/PWL_Wnd.h" 9#include "../../include/pdfwindow/PWL_ListBox.h" 10#include "../../include/pdfwindow/PWL_Utils.h" 11#include "../../include/pdfwindow/PWL_ScrollBar.h" 12#include "../../include/pdfwindow/PWL_EditCtrl.h" 13#include "../../include/pdfwindow/PWL_Edit.h" 14 15#define IsFloatZero(f) ((f) < 0.0001 && (f) > -0.0001) 16#define IsFloatBigger(fa,fb) ((fa) > (fb) && !IsFloatZero((fa) - (fb))) 17#define IsFloatSmaller(fa,fb) ((fa) < (fb) && !IsFloatZero((fa) - (fb))) 18#define IsFloatEqual(fa,fb) IsFloatZero((fa)-(fb)) 19 20/* ------------------------ CPWL_List_Notify ----------------------- */ 21 22CPWL_List_Notify::CPWL_List_Notify(CPWL_ListBox* pList) : m_pList(pList) 23{ 24 ASSERT(m_pList != NULL); 25} 26 27CPWL_List_Notify::~CPWL_List_Notify() 28{ 29} 30 31void CPWL_List_Notify::IOnSetScrollInfoY(FX_FLOAT fPlateMin, FX_FLOAT fPlateMax, 32 FX_FLOAT fContentMin, FX_FLOAT fContentMax, 33 FX_FLOAT fSmallStep, FX_FLOAT fBigStep) 34{ 35 PWL_SCROLL_INFO Info; 36 37 Info.fPlateWidth = fPlateMax - fPlateMin; 38 Info.fContentMin = fContentMin; 39 Info.fContentMax = fContentMax; 40 Info.fSmallStep = fSmallStep; 41 Info.fBigStep = fBigStep; 42 43 m_pList->OnNotify(m_pList,PNM_SETSCROLLINFO,SBT_VSCROLL,(FX_INTPTR)&Info); 44 45 if (CPWL_ScrollBar * pScroll = m_pList->GetVScrollBar()) 46 { 47 if (IsFloatBigger(Info.fPlateWidth,Info.fContentMax-Info.fContentMin) 48 || IsFloatEqual(Info.fPlateWidth,Info.fContentMax-Info.fContentMin)) 49 { 50 if (pScroll->IsVisible()) 51 { 52 pScroll->SetVisible(FALSE); 53 m_pList->RePosChildWnd(); 54 } 55 } 56 else 57 { 58 if (!pScroll->IsVisible()) 59 { 60 pScroll->SetVisible(TRUE); 61 m_pList->RePosChildWnd(); 62 } 63 } 64 } 65} 66 67void CPWL_List_Notify::IOnSetScrollPosY(FX_FLOAT fy) 68{ 69 m_pList->OnNotify(m_pList,PNM_SETSCROLLPOS,SBT_VSCROLL,(FX_INTPTR)&fy); 70} 71 72void CPWL_List_Notify::IOnInvalidateRect(CPDF_Rect * pRect) 73{ 74 m_pList->InvalidateRect(pRect); 75} 76 77/* --------------------------- CPWL_ListBox ---------------------------- */ 78 79CPWL_ListBox::CPWL_ListBox() : 80 m_pList(NULL), 81 m_pListNotify(NULL), 82 m_bMouseDown(FALSE), 83 m_bHoverSel(FALSE), 84 m_pFillerNotify(NULL) 85{ 86 m_pList = IFX_List::NewList(); 87 88 ASSERT(m_pList != NULL); 89} 90 91CPWL_ListBox::~CPWL_ListBox() 92{ 93 IFX_List::DelList(m_pList); 94 95 if (m_pListNotify) 96 { 97 delete m_pListNotify; 98 m_pListNotify = NULL; 99 } 100} 101 102CFX_ByteString CPWL_ListBox::GetClassName() const 103{ 104 return "CPWL_ListBox"; 105} 106 107void CPWL_ListBox::OnCreated() 108{ 109 if (m_pList) 110 { 111 if (m_pListNotify) delete m_pListNotify; 112 113 m_pList->SetFontMap(GetFontMap()); 114 m_pList->SetNotify(m_pListNotify = new CPWL_List_Notify(this)); 115 116 SetHoverSel(HasFlag(PLBS_HOVERSEL)); 117 m_pList->SetMultipleSel(HasFlag(PLBS_MULTIPLESEL)); 118 m_pList->SetFontSize(this->GetCreationParam().fFontSize); 119 120 m_bHoverSel = HasFlag(PLBS_HOVERSEL); 121 } 122} 123 124void CPWL_ListBox::OnDestroy() 125{ 126 if (m_pListNotify) 127 { 128 delete m_pListNotify; 129 m_pListNotify = NULL; 130 } 131} 132 133void CPWL_ListBox::GetThisAppearanceStream(CFX_ByteTextBuf & sAppStream) 134{ 135 CPWL_Wnd::GetThisAppearanceStream(sAppStream); 136 137 CFX_ByteTextBuf sListItems; 138 139 if (m_pList) 140 { 141 CPDF_Rect rcPlate = m_pList->GetPlateRect(); 142 for (FX_INT32 i=0,sz=m_pList->GetCount(); i<sz; i++) 143 { 144 CPDF_Rect rcItem = m_pList->GetItemRect(i); 145 146 if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom) continue; 147 148 CPDF_Point ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f); 149 if (m_pList->IsItemSelected(i)) 150 { 151 sListItems << CPWL_Utils::GetRectFillAppStream(rcItem,PWL_DEFAULT_SELBACKCOLOR); 152 CFX_ByteString sItem = CPWL_Utils::GetEditAppStream(m_pList->GetItemEdit(i), ptOffset); 153 if (sItem.GetLength() > 0) 154 { 155 sListItems << "BT\n" << CPWL_Utils::GetColorAppStream(PWL_DEFAULT_SELTEXTCOLOR) << sItem << "ET\n"; 156 } 157 } 158 else 159 { 160 CFX_ByteString sItem = CPWL_Utils::GetEditAppStream(m_pList->GetItemEdit(i), ptOffset); 161 if (sItem.GetLength() > 0) 162 { 163 sListItems << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()) << sItem << "ET\n"; 164 } 165 } 166 } 167 } 168 169 if (sListItems.GetLength() > 0) 170 { 171 CFX_ByteTextBuf sClip; 172 CPDF_Rect rcClient = this->GetClientRect(); 173 174 sClip << "q\n"; 175 sClip << rcClient.left << " " << rcClient.bottom << " " 176 << rcClient.right - rcClient.left << " " << rcClient.top - rcClient.bottom << " re W n\n"; 177 178 sClip << sListItems << "Q\n"; 179 180 sAppStream << "/Tx BMC\n" << sClip << "EMC\n"; 181 } 182} 183 184void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device) 185{ 186 CPWL_Wnd::DrawThisAppearance(pDevice,pUser2Device); 187 188 if (m_pList) 189 { 190 CPDF_Rect rcPlate = m_pList->GetPlateRect(); 191 CPDF_Rect rcList = GetListRect(); 192 CPDF_Rect rcClient = GetClientRect(); 193 194 for (FX_INT32 i=0,sz=m_pList->GetCount(); i<sz; i++) 195 { 196 CPDF_Rect rcItem = m_pList->GetItemRect(i); 197 if (rcItem.bottom > rcPlate.top || rcItem.top < rcPlate.bottom) continue; 198 199 CPDF_Point ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f); 200 if (IFX_Edit* pEdit = m_pList->GetItemEdit(i)) 201 { 202 CPDF_Rect rcContent = pEdit->GetContentRect(); 203 if (rcContent.Width() > rcClient.Width()) 204 rcItem.Intersect(rcList); 205 else 206 rcItem.Intersect(rcClient); 207 } 208 209 if (m_pList->IsItemSelected(i)) 210 { 211 // CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcItem, ArgbEncode(255,0,51,113)); 212 IFX_SystemHandler* pSysHandler = GetSystemHandler(); 213 if(pSysHandler && pSysHandler->IsSelectionImplemented()) 214 { 215 IFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), CPWL_Utils::PWLColorToFXColor(GetTextColor()), CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor()), 216 rcList, ptOffset, NULL,pSysHandler, m_pFormFiller); 217 pSysHandler->OutputSelectedRect(m_pFormFiller, rcItem); 218 } 219 else 220 { 221 CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rcItem, ArgbEncode(255,0,51,113)); 222 IFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), ArgbEncode(255,255,255,255), 0, 223 rcList, ptOffset, NULL, pSysHandler, m_pFormFiller); 224 } 225 } 226 else 227 { 228 IFX_SystemHandler* pSysHandler = GetSystemHandler(); 229 IFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), 230 CPWL_Utils::PWLColorToFXColor(GetTextColor()), 231 CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor()), 232 rcList, ptOffset, NULL,pSysHandler, NULL); 233 234 } 235 } 236 } 237} 238 239FX_BOOL CPWL_ListBox::OnKeyDown(FX_WORD nChar, FX_DWORD nFlag) 240{ 241 CPWL_Wnd::OnKeyDown(nChar, nFlag); 242 243 if (!m_pList) return FALSE; 244 245 switch (nChar) 246 { 247 default: 248 return FALSE; 249 case FWL_VKEY_Up: 250 case FWL_VKEY_Down: 251 case FWL_VKEY_Home: 252 case FWL_VKEY_Left: 253 case FWL_VKEY_End: 254 case FWL_VKEY_Right: 255 break; 256 } 257 258 switch (nChar) 259 { 260 case FWL_VKEY_Up: 261 m_pList->OnVK_UP(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 262 break; 263 case FWL_VKEY_Down: 264 m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 265 break; 266 case FWL_VKEY_Home: 267 m_pList->OnVK_HOME(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 268 break; 269 case FWL_VKEY_Left: 270 m_pList->OnVK_LEFT(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 271 break; 272 case FWL_VKEY_End: 273 m_pList->OnVK_END(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 274 break; 275 case FWL_VKEY_Right: 276 m_pList->OnVK_RIGHT(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 277 break; 278 case FWL_VKEY_Delete: 279 break; 280 } 281 282 FX_BOOL bExit = FALSE; 283 OnNotifySelChanged(TRUE,bExit,nFlag); 284 285 return TRUE; 286} 287 288FX_BOOL CPWL_ListBox::OnChar(FX_WORD nChar, FX_DWORD nFlag) 289{ 290 CPWL_Wnd::OnChar(nChar,nFlag); 291 292 if (!m_pList) return FALSE; 293 294 if (!m_pList->OnChar(nChar,IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag))) return FALSE; 295 296 FX_BOOL bExit = FALSE; 297 OnNotifySelChanged(TRUE,bExit, nFlag); 298 299 return TRUE; 300} 301 302FX_BOOL CPWL_ListBox::OnLButtonDown(const CPDF_Point & point, FX_DWORD nFlag) 303{ 304 CPWL_Wnd::OnLButtonDown(point,nFlag); 305 306 if (ClientHitTest(point)) 307 { 308 m_bMouseDown = TRUE; 309 SetFocus(); 310 SetCapture(); 311 312 if (m_pList) 313 m_pList->OnMouseDown(point,IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 314 } 315 316 return TRUE; 317} 318 319FX_BOOL CPWL_ListBox::OnLButtonUp(const CPDF_Point & point, FX_DWORD nFlag) 320{ 321 CPWL_Wnd::OnLButtonUp(point,nFlag); 322 323 if (m_bMouseDown) 324 { 325 ReleaseCapture(); 326 m_bMouseDown = FALSE; 327 } 328 329 FX_BOOL bExit = FALSE; 330 OnNotifySelChanged(FALSE,bExit,nFlag); 331 332 return TRUE; 333} 334 335void CPWL_ListBox::SetHoverSel(FX_BOOL bHoverSel) 336{ 337 m_bHoverSel = bHoverSel; 338} 339 340FX_BOOL CPWL_ListBox::OnMouseMove(const CPDF_Point & point, FX_DWORD nFlag) 341{ 342 CPWL_Wnd::OnMouseMove(point, nFlag); 343 344 if (m_bHoverSel && !IsCaptureMouse() && ClientHitTest(point)) 345 { 346 if (m_pList) 347 m_pList->Select(m_pList->GetItemIndex(point)); 348 } 349 350 if (m_bMouseDown) 351 { 352 if (m_pList) 353 m_pList->OnMouseMove(point,IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 354 } 355 356 return TRUE; 357} 358 359void CPWL_ListBox::OnNotify(CPWL_Wnd* pWnd, FX_DWORD msg, FX_INTPTR wParam, FX_INTPTR lParam) 360{ 361 CPWL_Wnd::OnNotify(pWnd,msg,wParam,lParam); 362 363 FX_FLOAT fPos; 364 365 switch (msg) 366 { 367 case PNM_SETSCROLLINFO: 368 switch (wParam) 369 { 370 case SBT_VSCROLL: 371 if (CPWL_Wnd * pChild = GetVScrollBar()) 372 { 373 pChild->OnNotify(pWnd,PNM_SETSCROLLINFO,wParam,lParam); 374 } 375 break; 376 } 377 break; 378 case PNM_SETSCROLLPOS: 379 switch (wParam) 380 { 381 case SBT_VSCROLL: 382 if (CPWL_Wnd * pChild = GetVScrollBar()) 383 { 384 pChild->OnNotify(pWnd,PNM_SETSCROLLPOS,wParam,lParam); 385 } 386 break; 387 } 388 break; 389 case PNM_SCROLLWINDOW: 390 fPos = *(FX_FLOAT*)lParam; 391 switch (wParam) 392 { 393 case SBT_VSCROLL: 394 if (m_pList) 395 m_pList->SetScrollPos(CPDF_Point(0,fPos)); 396 break; 397 } 398 break; 399 } 400} 401 402void CPWL_ListBox::KillFocus() 403{ 404 CPWL_Wnd::KillFocus(); 405 406 /* 407 if (this->IsMultipleSel()) 408 { 409 for(FX_INT32 i=0;i<this->GetCount();i++) 410 { 411 if (this->IsListItemSelected(i)) 412 { 413 if (!IsListItemVisible(i)) 414 this->ScrollToListItem(i); 415 break; 416 } 417 } 418 } 419 else 420 { 421 if (!IsListItemVisible(this->GetCurSel())) 422 this->ScrollToListItem(this->GetCurSel()); 423 } 424 425 SetListItemCaret(m_nCaretIndex,FALSE); 426 */ 427} 428 429void CPWL_ListBox::RePosChildWnd() 430{ 431 CPWL_Wnd::RePosChildWnd(); 432 433 if (m_pList) 434 m_pList->SetPlateRect(GetListRect()); 435} 436 437void CPWL_ListBox::OnNotifySelChanged(FX_BOOL bKeyDown, FX_BOOL & bExit, FX_DWORD nFlag) 438{ 439 if (m_pFillerNotify) 440 { 441 FX_BOOL bRC = TRUE; 442 CFX_WideString swChange = GetText(); 443 CFX_WideString strChangeEx; 444 int nSelStart = 0; 445 int nSelEnd = swChange.GetLength(); 446 m_pFillerNotify->OnBeforeKeyStroke(FALSE, GetAttachedData(), 0, swChange, strChangeEx, nSelStart, nSelEnd, bKeyDown, bRC, bExit, nFlag); 447 if (bExit) return; 448 449 m_pFillerNotify->OnAfterKeyStroke(FALSE, GetAttachedData(), bExit,nFlag); 450 } 451} 452 453CPDF_Rect CPWL_ListBox::GetFocusRect() const 454{ 455 if (m_pList && m_pList->IsMultipleSel()) 456 { 457 CPDF_Rect rcCaret = m_pList->GetItemRect(m_pList->GetCaret()); 458 rcCaret.Intersect(GetClientRect()); 459 return rcCaret; 460 } 461 462 return CPWL_Wnd::GetFocusRect(); 463} 464 465void CPWL_ListBox::AddString(FX_LPCWSTR string) 466{ 467 if (m_pList) 468 { 469 m_pList->AddString(string); 470 } 471} 472 473void CPWL_ListBox::SetText(FX_LPCWSTR csText,FX_BOOL bRefresh) 474{ 475 //return CPDF_List::SetText(csText,bRefresh); 476} 477 478CFX_WideString CPWL_ListBox::GetText() const 479{ 480 if (m_pList) 481 return m_pList->GetText(); 482 483 return L""; 484} 485 486void CPWL_ListBox::SetFontSize(FX_FLOAT fFontSize) 487{ 488 if (m_pList) 489 m_pList->SetFontSize(fFontSize); 490} 491 492FX_FLOAT CPWL_ListBox::GetFontSize() const 493{ 494 if (m_pList) 495 return m_pList->GetFontSize(); 496 return 0.0f; 497} 498 499void CPWL_ListBox::Select(FX_INT32 nItemIndex) 500{ 501 if (m_pList) 502 m_pList->Select(nItemIndex); 503} 504 505void CPWL_ListBox::SetCaret(FX_INT32 nItemIndex) 506{ 507 if (m_pList) 508 m_pList->SetCaret(nItemIndex); 509} 510 511void CPWL_ListBox::SetTopVisibleIndex(FX_INT32 nItemIndex) 512{ 513 if (m_pList) 514 m_pList->SetTopItem(nItemIndex); 515} 516 517void CPWL_ListBox::ScrollToListItem(FX_INT32 nItemIndex) 518{ 519 if (m_pList) 520 m_pList->ScrollToListItem(nItemIndex); 521} 522 523void CPWL_ListBox::ResetContent() 524{ 525 if (m_pList) 526 m_pList->Empty(); 527} 528 529void CPWL_ListBox::Reset() 530{ 531 if (m_pList) 532 m_pList->Cancel(); 533} 534 535FX_BOOL CPWL_ListBox::IsMultipleSel() const 536{ 537 if (m_pList) 538 return m_pList->IsMultipleSel(); 539 540 return FALSE; 541} 542 543FX_INT32 CPWL_ListBox::GetCaretIndex() const 544{ 545 if (m_pList) 546 return m_pList->GetCaret(); 547 548 return -1; 549} 550 551FX_INT32 CPWL_ListBox::GetCurSel() const 552{ 553 if (m_pList) 554 return m_pList->GetSelect(); 555 556 return -1; 557} 558 559FX_BOOL CPWL_ListBox::IsItemSelected(FX_INT32 nItemIndex) const 560{ 561 if (m_pList) 562 return m_pList->IsItemSelected(nItemIndex); 563 564 return FALSE; 565} 566 567FX_INT32 CPWL_ListBox::GetTopVisibleIndex() const 568{ 569 if (m_pList) 570 { 571 m_pList->ScrollToListItem(m_pList->GetFirstSelected()); 572 return m_pList->GetTopItem(); 573 } 574 575 return -1; 576} 577 578FX_INT32 CPWL_ListBox::GetCount() const 579{ 580 if (m_pList) 581 return m_pList->GetCount(); 582 583 return 0; 584} 585 586FX_INT32 CPWL_ListBox::FindNext(FX_INT32 nIndex,FX_WCHAR nChar) const 587{ 588 if (m_pList) 589 return m_pList->FindNext(nIndex,nChar); 590 591 return nIndex; 592} 593 594CPDF_Rect CPWL_ListBox::GetContentRect() const 595{ 596 if (m_pList) 597 return m_pList->GetContentRect(); 598 599 return CPDF_Rect(); 600} 601 602FX_FLOAT CPWL_ListBox::GetFirstHeight() const 603{ 604 if (m_pList) 605 return m_pList->GetFirstHeight(); 606 607 return 0.0f; 608} 609 610CPDF_Rect CPWL_ListBox::GetListRect() const 611{ 612 return CPWL_Utils::DeflateRect(GetWindowRect(),(FX_FLOAT)(GetBorderWidth()+GetInnerBorderWidth())); 613} 614 615FX_BOOL CPWL_ListBox::OnMouseWheel(short zDelta, const CPDF_Point & point, FX_DWORD nFlag) 616{ 617 if (!m_pList) return FALSE; 618 619 if (zDelta < 0) 620 { 621 m_pList->OnVK_DOWN(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 622 } 623 else 624 { 625 m_pList->OnVK_UP(IsSHIFTpressed(nFlag),IsCTRLpressed(nFlag)); 626 } 627 628 FX_BOOL bExit = FALSE; 629 OnNotifySelChanged(FALSE,bExit, nFlag); 630 return TRUE; 631} 632 633