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