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