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