• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The PDFium Authors
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 "core/fxcrt/check.h"
10 #include "xfa/fwl/cfwl_combobox.h"
11 #include "xfa/fwl/cfwl_comboedit.h"
12 #include "xfa/fwl/cfwl_listbox.h"
13 #include "xfa/fwl/cfwl_messagekey.h"
14 #include "xfa/fwl/cfwl_messagekillfocus.h"
15 #include "xfa/fwl/cfwl_messagemouse.h"
16 #include "xfa/fwl/fwl_widgetdef.h"
17 
18 namespace pdfium {
19 
CFWL_ComboList(CFWL_App * app,const Properties & properties,CFWL_Widget * pOuter)20 CFWL_ComboList::CFWL_ComboList(CFWL_App* app,
21                                const Properties& properties,
22                                CFWL_Widget* pOuter)
23     : CFWL_ListBox(app, properties, pOuter) {
24   DCHECK(pOuter);
25 }
26 
27 CFWL_ComboList::~CFWL_ComboList() = default;
28 
MatchItem(WideStringView wsMatch)29 int32_t CFWL_ComboList::MatchItem(WideStringView wsMatch) {
30   if (wsMatch.IsEmpty())
31     return -1;
32 
33   int32_t iCount = CountItems(this);
34   for (int32_t i = 0; i < iCount; i++) {
35     CFWL_ListBox::Item* hItem = GetItem(this, i);
36     WideString wsText = hItem ? hItem->GetText() : WideString();
37     auto pos = wsText.Find(wsMatch);
38     if (pos.has_value() && pos.value() == 0)
39       return i;
40   }
41   return -1;
42 }
43 
ChangeSelected(int32_t iSel)44 void CFWL_ComboList::ChangeSelected(int32_t iSel) {
45   CFWL_ListBox::Item* hItem = GetItem(this, iSel);
46   CFWL_ListBox::Item* hOld = GetSelItem(0);
47   int32_t iOld = GetItemIndex(this, hOld);
48   if (iOld == iSel)
49     return;
50 
51   CFX_RectF rtInvalidate;
52   if (iOld > -1) {
53     if (CFWL_ListBox::Item* hOldItem = GetItem(this, iOld))
54       rtInvalidate = hOldItem->GetRect();
55     SetSelItem(hOld, false);
56   }
57   if (hItem) {
58     if (CFWL_ListBox::Item* hOldItem = GetItem(this, iSel))
59       rtInvalidate.Union(hOldItem->GetRect());
60     CFWL_ListBox::Item* hSel = GetItem(this, iSel);
61     SetSelItem(hSel, true);
62   }
63   if (!rtInvalidate.IsEmpty())
64     RepaintRect(rtInvalidate);
65 }
66 
ClientToOuter(const CFX_PointF & point)67 CFX_PointF CFWL_ComboList::ClientToOuter(const CFX_PointF& point) {
68   return point + CFX_PointF(m_WidgetRect.left, m_WidgetRect.top);
69 }
70 
OnProcessMessage(CFWL_Message * pMessage)71 void CFWL_ComboList::OnProcessMessage(CFWL_Message* pMessage) {
72   CFWL_Message::Type type = pMessage->GetType();
73   bool backDefault = true;
74   if (type == CFWL_Message::Type::kSetFocus ||
75       type == CFWL_Message::Type::kKillFocus) {
76     OnDropListFocusChanged(pMessage, type == CFWL_Message::Type::kSetFocus);
77   } else if (type == CFWL_Message::Type::kMouse) {
78     CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
79     CFWL_ScrollBar* vertSB = GetVertScrollBar();
80     if (IsShowVertScrollBar() && vertSB) {
81       CFX_RectF rect = vertSB->GetWidgetRect();
82       if (rect.Contains(pMsg->m_pos)) {
83         pMsg->m_pos -= rect.TopLeft();
84         vertSB->GetDelegate()->OnProcessMessage(pMsg);
85         return;
86       }
87     }
88     switch (pMsg->m_dwCmd) {
89       case CFWL_MessageMouse::MouseCommand::kMove:
90         backDefault = false;
91         OnDropListMouseMove(pMsg);
92         break;
93       case CFWL_MessageMouse::MouseCommand::kLeftButtonDown:
94         backDefault = false;
95         OnDropListLButtonDown(pMsg);
96         break;
97       case CFWL_MessageMouse::MouseCommand::kLeftButtonUp:
98         backDefault = false;
99         OnDropListLButtonUp(pMsg);
100         break;
101       default:
102         break;
103     }
104   } else if (type == CFWL_Message::Type::kKey) {
105     backDefault = !OnDropListKey(static_cast<CFWL_MessageKey*>(pMessage));
106   }
107   if (backDefault)
108     CFWL_ListBox::OnProcessMessage(pMessage);
109 }
110 
OnDropListFocusChanged(CFWL_Message * pMsg,bool bSet)111 void CFWL_ComboList::OnDropListFocusChanged(CFWL_Message* pMsg, bool bSet) {
112   if (bSet)
113     return;
114 
115   CFWL_MessageKillFocus* pKill = static_cast<CFWL_MessageKillFocus*>(pMsg);
116   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(GetOuter());
117   if (pKill->IsFocusedOnWidget(pOuter) ||
118       pKill->IsFocusedOnWidget(pOuter->GetComboEdit())) {
119     pOuter->HideDropDownList();
120   }
121 }
122 
OnDropListMouseMove(CFWL_MessageMouse * pMsg)123 void CFWL_ComboList::OnDropListMouseMove(CFWL_MessageMouse* pMsg) {
124   if (GetRTClient().Contains(pMsg->m_pos)) {
125     if (m_bNotifyOwner)
126       m_bNotifyOwner = false;
127 
128     CFWL_ScrollBar* vertSB = GetVertScrollBar();
129     if (IsShowVertScrollBar() && vertSB) {
130       CFX_RectF rect = vertSB->GetWidgetRect();
131       if (rect.Contains(pMsg->m_pos))
132         return;
133     }
134 
135     CFWL_ListBox::Item* hItem = GetItemAtPoint(pMsg->m_pos);
136     if (!hItem)
137       return;
138 
139     ChangeSelected(GetItemIndex(this, hItem));
140   } else if (m_bNotifyOwner) {
141     pMsg->m_pos = ClientToOuter(pMsg->m_pos);
142 
143     CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(GetOuter());
144     pOuter->GetDelegate()->OnProcessMessage(pMsg);
145   }
146 }
147 
OnDropListLButtonDown(CFWL_MessageMouse * pMsg)148 void CFWL_ComboList::OnDropListLButtonDown(CFWL_MessageMouse* pMsg) {
149   if (GetRTClient().Contains(pMsg->m_pos))
150     return;
151 
152   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(GetOuter());
153   pOuter->HideDropDownList();
154 }
155 
OnDropListLButtonUp(CFWL_MessageMouse * pMsg)156 void CFWL_ComboList::OnDropListLButtonUp(CFWL_MessageMouse* pMsg) {
157   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(GetOuter());
158   if (m_bNotifyOwner) {
159     pMsg->m_pos = ClientToOuter(pMsg->m_pos);
160     pOuter->GetDelegate()->OnProcessMessage(pMsg);
161     return;
162   }
163 
164   CFWL_ScrollBar* vertSB = GetVertScrollBar();
165   if (IsShowVertScrollBar() && vertSB) {
166     CFX_RectF rect = vertSB->GetWidgetRect();
167     if (rect.Contains(pMsg->m_pos))
168       return;
169   }
170   pOuter->HideDropDownList();
171 
172   CFWL_ListBox::Item* hItem = GetItemAtPoint(pMsg->m_pos);
173   if (hItem)
174     pOuter->ProcessSelChanged(true);
175 }
176 
OnDropListKey(CFWL_MessageKey * pKey)177 bool CFWL_ComboList::OnDropListKey(CFWL_MessageKey* pKey) {
178   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(GetOuter());
179   bool bPropagate = false;
180   if (pKey->m_dwCmd == CFWL_MessageKey::KeyCommand::kKeyDown) {
181     uint32_t dwKeyCode = pKey->m_dwKeyCodeOrChar;
182     switch (dwKeyCode) {
183       case XFA_FWL_VKEY_Return:
184       case XFA_FWL_VKEY_Escape: {
185         pOuter->HideDropDownList();
186         return true;
187       }
188       case XFA_FWL_VKEY_Up:
189       case XFA_FWL_VKEY_Down: {
190         OnDropListKeyDown(pKey);
191         pOuter->ProcessSelChanged(false);
192         return true;
193       }
194       default: {
195         bPropagate = true;
196         break;
197       }
198     }
199   } else if (pKey->m_dwCmd == CFWL_MessageKey::KeyCommand::kChar) {
200     bPropagate = true;
201   }
202   if (bPropagate) {
203     pKey->SetDstTarget(GetOuter());
204     pOuter->GetDelegate()->OnProcessMessage(pKey);
205     return true;
206   }
207   return false;
208 }
209 
OnDropListKeyDown(CFWL_MessageKey * pKey)210 void CFWL_ComboList::OnDropListKeyDown(CFWL_MessageKey* pKey) {
211   auto dwKeyCode = static_cast<XFA_FWL_VKEYCODE>(pKey->m_dwKeyCodeOrChar);
212   switch (dwKeyCode) {
213     case XFA_FWL_VKEY_Up:
214     case XFA_FWL_VKEY_Down:
215     case XFA_FWL_VKEY_Home:
216     case XFA_FWL_VKEY_End: {
217       CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(GetOuter());
218       CFWL_ListBox::Item* hItem = GetItem(this, pOuter->GetCurrentSelection());
219       hItem = GetListItem(hItem, dwKeyCode);
220       if (!hItem)
221         break;
222 
223       SetSelection(hItem, hItem, true);
224       ScrollToVisible(hItem);
225       RepaintRect(CFX_RectF(0, 0, m_WidgetRect.width, m_WidgetRect.height));
226       break;
227     }
228     default:
229       break;
230   }
231 }
232 
233 }  // namespace pdfium
234