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