Home | History | Annotate | Download | only in fwl
      1 // Copyright 2016 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/fwl/cfwl_combolist.h"
      8 
      9 #include <memory>
     10 #include <utility>
     11 
     12 #include "third_party/base/ptr_util.h"
     13 #include "xfa/fwl/cfwl_combobox.h"
     14 #include "xfa/fwl/cfwl_comboedit.h"
     15 #include "xfa/fwl/cfwl_listbox.h"
     16 #include "xfa/fwl/cfwl_messagekey.h"
     17 #include "xfa/fwl/cfwl_messagekillfocus.h"
     18 #include "xfa/fwl/cfwl_messagemouse.h"
     19 
     20 CFWL_ComboList::CFWL_ComboList(
     21     const CFWL_App* app,
     22     std::unique_ptr<CFWL_WidgetProperties> properties,
     23     CFWL_Widget* pOuter)
     24     : CFWL_ListBox(app, std::move(properties), pOuter), m_bNotifyOwner(true) {
     25   ASSERT(pOuter);
     26 }
     27 
     28 int32_t CFWL_ComboList::MatchItem(const CFX_WideString& wsMatch) {
     29   if (wsMatch.IsEmpty())
     30     return -1;
     31 
     32   int32_t iCount = CountItems(this);
     33   for (int32_t i = 0; i < iCount; i++) {
     34     CFWL_ListItem* hItem = GetItem(this, i);
     35     CFX_WideString wsText = hItem ? hItem->GetText() : L"";
     36     FX_STRSIZE pos = wsText.Find(wsMatch.c_str());
     37     if (!pos)
     38       return i;
     39   }
     40   return -1;
     41 }
     42 
     43 void CFWL_ComboList::ChangeSelected(int32_t iSel) {
     44   CFWL_ListItem* hItem = GetItem(this, iSel);
     45   CFWL_ListItem* hOld = GetSelItem(0);
     46   int32_t iOld = GetItemIndex(this, hOld);
     47   if (iOld == iSel)
     48     return;
     49 
     50   CFX_RectF rtInvalidate;
     51   if (iOld > -1) {
     52     if (CFWL_ListItem* hOldItem = GetItem(this, iOld))
     53       rtInvalidate = hOldItem->GetRect();
     54     SetSelItem(hOld, false);
     55   }
     56   if (hItem) {
     57     if (CFWL_ListItem* hOldItem = GetItem(this, iSel))
     58       rtInvalidate.Union(hOldItem->GetRect());
     59     CFWL_ListItem* hSel = GetItem(this, iSel);
     60     SetSelItem(hSel, true);
     61   }
     62   if (!rtInvalidate.IsEmpty())
     63     RepaintRect(rtInvalidate);
     64 }
     65 
     66 CFX_PointF CFWL_ComboList::ClientToOuter(const CFX_PointF& point) {
     67   CFX_PointF ret = point + CFX_PointF(m_pProperties->m_rtWidget.left,
     68                                       m_pProperties->m_rtWidget.top);
     69   CFWL_Widget* pOwner = GetOwner();
     70   return pOwner ? pOwner->TransformTo(m_pOuter, ret) : ret;
     71 }
     72 
     73 void CFWL_ComboList::OnProcessMessage(CFWL_Message* pMessage) {
     74   if (!pMessage)
     75     return;
     76 
     77   CFWL_Message::Type type = pMessage->GetType();
     78   bool backDefault = true;
     79   if (type == CFWL_Message::Type::SetFocus ||
     80       type == CFWL_Message::Type::KillFocus) {
     81     OnDropListFocusChanged(pMessage, type == CFWL_Message::Type::SetFocus);
     82   } else if (type == CFWL_Message::Type::Mouse) {
     83     CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
     84     CFWL_ScrollBar* vertSB = GetVertScrollBar();
     85     if (IsShowScrollBar(true) && vertSB) {
     86       CFX_RectF rect = vertSB->GetWidgetRect();
     87       if (rect.Contains(pMsg->m_pos)) {
     88         pMsg->m_pos -= rect.TopLeft();
     89         vertSB->GetDelegate()->OnProcessMessage(pMsg);
     90         return;
     91       }
     92     }
     93     switch (pMsg->m_dwCmd) {
     94       case FWL_MouseCommand::Move: {
     95         backDefault = false;
     96         OnDropListMouseMove(pMsg);
     97         break;
     98       }
     99       case FWL_MouseCommand::LeftButtonDown: {
    100         backDefault = false;
    101         OnDropListLButtonDown(pMsg);
    102         break;
    103       }
    104       case FWL_MouseCommand::LeftButtonUp: {
    105         backDefault = false;
    106         OnDropListLButtonUp(pMsg);
    107         break;
    108       }
    109       default:
    110         break;
    111     }
    112   } else if (type == CFWL_Message::Type::Key) {
    113     backDefault = !OnDropListKey(static_cast<CFWL_MessageKey*>(pMessage));
    114   }
    115   if (backDefault)
    116     CFWL_ListBox::OnProcessMessage(pMessage);
    117 }
    118 
    119 void CFWL_ComboList::OnDropListFocusChanged(CFWL_Message* pMsg, bool bSet) {
    120   if (bSet)
    121     return;
    122 
    123   CFWL_MessageKillFocus* pKill = static_cast<CFWL_MessageKillFocus*>(pMsg);
    124   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
    125   if (pKill->m_pSetFocus == m_pOuter ||
    126       pKill->m_pSetFocus == pOuter->GetComboEdit()) {
    127     pOuter->ShowDropList(false);
    128   }
    129 }
    130 
    131 void CFWL_ComboList::OnDropListMouseMove(CFWL_MessageMouse* pMsg) {
    132   if (GetRTClient().Contains(pMsg->m_pos)) {
    133     if (m_bNotifyOwner)
    134       m_bNotifyOwner = false;
    135 
    136     CFWL_ScrollBar* vertSB = GetVertScrollBar();
    137     if (IsShowScrollBar(true) && vertSB) {
    138       CFX_RectF rect = vertSB->GetWidgetRect();
    139       if (rect.Contains(pMsg->m_pos))
    140         return;
    141     }
    142 
    143     CFWL_ListItem* hItem = GetItemAtPoint(pMsg->m_pos);
    144     if (!hItem)
    145       return;
    146 
    147     ChangeSelected(GetItemIndex(this, hItem));
    148   } else if (m_bNotifyOwner) {
    149     pMsg->m_pos = ClientToOuter(pMsg->m_pos);
    150 
    151     CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
    152     pOuter->GetDelegate()->OnProcessMessage(pMsg);
    153   }
    154 }
    155 
    156 void CFWL_ComboList::OnDropListLButtonDown(CFWL_MessageMouse* pMsg) {
    157   if (GetRTClient().Contains(pMsg->m_pos))
    158     return;
    159 
    160   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
    161   pOuter->ShowDropList(false);
    162 }
    163 
    164 void CFWL_ComboList::OnDropListLButtonUp(CFWL_MessageMouse* pMsg) {
    165   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
    166   if (m_bNotifyOwner) {
    167     pMsg->m_pos = ClientToOuter(pMsg->m_pos);
    168     pOuter->GetDelegate()->OnProcessMessage(pMsg);
    169     return;
    170   }
    171 
    172   CFWL_ScrollBar* vertSB = GetVertScrollBar();
    173   if (IsShowScrollBar(true) && vertSB) {
    174     CFX_RectF rect = vertSB->GetWidgetRect();
    175     if (rect.Contains(pMsg->m_pos))
    176       return;
    177   }
    178   pOuter->ShowDropList(false);
    179 
    180   CFWL_ListItem* hItem = GetItemAtPoint(pMsg->m_pos);
    181   if (hItem)
    182     pOuter->ProcessSelChanged(true);
    183 }
    184 
    185 bool CFWL_ComboList::OnDropListKey(CFWL_MessageKey* pKey) {
    186   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
    187   bool bPropagate = false;
    188   if (pKey->m_dwCmd == FWL_KeyCommand::KeyDown) {
    189     uint32_t dwKeyCode = pKey->m_dwKeyCode;
    190     switch (dwKeyCode) {
    191       case FWL_VKEY_Return:
    192       case FWL_VKEY_Escape: {
    193         pOuter->ShowDropList(false);
    194         return true;
    195       }
    196       case FWL_VKEY_Up:
    197       case FWL_VKEY_Down: {
    198         OnDropListKeyDown(pKey);
    199         pOuter->ProcessSelChanged(false);
    200         return true;
    201       }
    202       default: {
    203         bPropagate = true;
    204         break;
    205       }
    206     }
    207   } else if (pKey->m_dwCmd == FWL_KeyCommand::Char) {
    208     bPropagate = true;
    209   }
    210   if (bPropagate) {
    211     pKey->m_pDstTarget = m_pOuter;
    212     pOuter->GetDelegate()->OnProcessMessage(pKey);
    213     return true;
    214   }
    215   return false;
    216 }
    217 
    218 void CFWL_ComboList::OnDropListKeyDown(CFWL_MessageKey* pKey) {
    219   uint32_t dwKeyCode = pKey->m_dwKeyCode;
    220   switch (dwKeyCode) {
    221     case FWL_VKEY_Up:
    222     case FWL_VKEY_Down:
    223     case FWL_VKEY_Home:
    224     case FWL_VKEY_End: {
    225       CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
    226       CFWL_ListItem* hItem = GetItem(this, pOuter->GetCurrentSelection());
    227       hItem = GetListItem(hItem, dwKeyCode);
    228       if (!hItem)
    229         break;
    230 
    231       SetSelection(hItem, hItem, true);
    232       ScrollToVisible(hItem);
    233       CFX_RectF rtInvalidate(0, 0, m_pProperties->m_rtWidget.width,
    234                              m_pProperties->m_rtWidget.height);
    235       RepaintRect(rtInvalidate);
    236       break;
    237     }
    238     default:
    239       break;
    240   }
    241 }
    242